commit
8f82f467a0
30 changed files with 2343 additions and 0 deletions
-
12.gitignore
-
BINN64E1M1.bsp
-
BINN64E2M2.bsp
-
41PS1BSP.sln
-
153PS1BSP.vcxproj
-
30PS1BSP.vcxproj.filters
-
152PS1MDL/PS1MDL.vcxproj
-
33PS1MDL/PS1MDL.vcxproj.filters
-
BINPS1MDL/h_player.mdl
-
227PS1MDL/main.c
-
93PS1MDL/mdl.h
-
BINPS1MDL/ogre.mdl
-
BINPS1MDL/palette.lmp
-
BINPS1MDL/player.mdl
-
162PS1MDL/ps1anorms.h
-
48PS1MDL/ps1mdl.h
-
BINPS1MDL/quaddama.mdl
-
BINPS1MDL/quake.pal
-
BINPS1MDL/shambler.mdl
-
BINPS1MDL/soldier.mdl
-
181anorms.h
-
98bsp.h
-
180main.cpp
-
60ps1bsp.h
-
286rectpack/best_bin_finder.h
-
70rectpack/empty_space_allocators.h
-
149rectpack/empty_spaces.h
-
155rectpack/finders_interface.h
-
135rectpack/insert_and_split.h
-
78rectpack/rect_structs.h
@ -0,0 +1,12 @@ |
|||||
|
.vs/ |
||||
|
Debug/ |
||||
|
*.raw |
||||
|
*.pcx |
||||
|
*.RoQ |
||||
|
*.wav |
||||
|
*.mkv |
||||
|
*.avi |
||||
|
*.png |
||||
|
*.tim |
||||
|
*.ps1mdl |
||||
|
*.tga |
||||
@ -0,0 +1,41 @@ |
|||||
|
|
||||
|
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
|
# Visual Studio Version 16 |
||||
|
VisualStudioVersion = 16.0.32002.261 |
||||
|
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PS1BSP", "PS1BSP.vcxproj", "{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}" |
||||
|
EndProject |
||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PS1MDL", "PS1MDL\PS1MDL.vcxproj", "{07BE9153-FB50-492F-9456-ADE90372E575}" |
||||
|
EndProject |
||||
|
Global |
||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
|
Debug|x64 = Debug|x64 |
||||
|
Debug|x86 = Debug|x86 |
||||
|
Release|x64 = Release|x64 |
||||
|
Release|x86 = Release|x86 |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Debug|x64.ActiveCfg = Debug|x64 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Debug|x64.Build.0 = Debug|x64 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Debug|x86.ActiveCfg = Debug|Win32 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Debug|x86.Build.0 = Debug|Win32 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Release|x64.ActiveCfg = Release|x64 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Release|x64.Build.0 = Release|x64 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Release|x86.ActiveCfg = Release|Win32 |
||||
|
{F5AD5AE7-32D3-48FB-AAE1-261E00418C1D}.Release|x86.Build.0 = Release|Win32 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Debug|x64.ActiveCfg = Debug|x64 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Debug|x64.Build.0 = Debug|x64 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Debug|x86.ActiveCfg = Debug|Win32 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Debug|x86.Build.0 = Debug|Win32 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Release|x64.ActiveCfg = Release|x64 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Release|x64.Build.0 = Release|x64 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Release|x86.ActiveCfg = Release|Win32 |
||||
|
{07BE9153-FB50-492F-9456-ADE90372E575}.Release|x86.Build.0 = Release|Win32 |
||||
|
EndGlobalSection |
||||
|
GlobalSection(SolutionProperties) = preSolution |
||||
|
HideSolutionNode = FALSE |
||||
|
EndGlobalSection |
||||
|
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
|
SolutionGuid = {B5C5C921-F256-48A3-AA40-AEA343FE0F08} |
||||
|
EndGlobalSection |
||||
|
EndGlobal |
||||
@ -0,0 +1,153 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<ItemGroup Label="ProjectConfigurations"> |
||||
|
<ProjectConfiguration Include="Debug|Win32"> |
||||
|
<Configuration>Debug</Configuration> |
||||
|
<Platform>Win32</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Release|Win32"> |
||||
|
<Configuration>Release</Configuration> |
||||
|
<Platform>Win32</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Debug|x64"> |
||||
|
<Configuration>Debug</Configuration> |
||||
|
<Platform>x64</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Release|x64"> |
||||
|
<Configuration>Release</Configuration> |
||||
|
<Platform>x64</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
</ItemGroup> |
||||
|
<PropertyGroup Label="Globals"> |
||||
|
<VCProjectVersion>16.0</VCProjectVersion> |
||||
|
<Keyword>Win32Proj</Keyword> |
||||
|
<ProjectGuid>{f5ad5ae7-32d3-48fb-aae1-261e00418c1d}</ProjectGuid> |
||||
|
<RootNamespace>PS1BSP</RootNamespace> |
||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>true</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>false</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>true</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>false</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
|
<ImportGroup Label="ExtensionSettings"> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="Shared"> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<PropertyGroup Label="UserMacros" /> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<LinkIncremental>true</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<LinkIncremental>false</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<LinkIncremental>true</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<LinkIncremental>false</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
<LanguageStandard>stdcpp17</LanguageStandard> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
<LanguageStandard>stdcpp17</LanguageStandard> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemGroup> |
||||
|
<ClCompile Include="main.cpp" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClInclude Include="bsp.h" /> |
||||
|
<ClInclude Include="ps1bsp.h" /> |
||||
|
</ItemGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
|
<ImportGroup Label="ExtensionTargets"> |
||||
|
</ImportGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<ItemGroup> |
||||
|
<Filter Include="Source Files"> |
||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> |
||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> |
||||
|
</Filter> |
||||
|
<Filter Include="Header Files"> |
||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> |
||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> |
||||
|
</Filter> |
||||
|
<Filter Include="Resource Files"> |
||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |
||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |
||||
|
</Filter> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClCompile Include="main.cpp"> |
||||
|
<Filter>Source Files</Filter> |
||||
|
</ClCompile> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClInclude Include="bsp.h"> |
||||
|
<Filter>Header Files</Filter> |
||||
|
</ClInclude> |
||||
|
<ClInclude Include="ps1bsp.h"> |
||||
|
<Filter>Header Files</Filter> |
||||
|
</ClInclude> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,152 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<ItemGroup Label="ProjectConfigurations"> |
||||
|
<ProjectConfiguration Include="Debug|Win32"> |
||||
|
<Configuration>Debug</Configuration> |
||||
|
<Platform>Win32</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Release|Win32"> |
||||
|
<Configuration>Release</Configuration> |
||||
|
<Platform>Win32</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Debug|x64"> |
||||
|
<Configuration>Debug</Configuration> |
||||
|
<Platform>x64</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
<ProjectConfiguration Include="Release|x64"> |
||||
|
<Configuration>Release</Configuration> |
||||
|
<Platform>x64</Platform> |
||||
|
</ProjectConfiguration> |
||||
|
</ItemGroup> |
||||
|
<PropertyGroup Label="Globals"> |
||||
|
<VCProjectVersion>16.0</VCProjectVersion> |
||||
|
<Keyword>Win32Proj</Keyword> |
||||
|
<ProjectGuid>{07be9153-fb50-492f-9456-ade90372e575}</ProjectGuid> |
||||
|
<RootNamespace>PS1MDL</RootNamespace> |
||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>true</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>false</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>true</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
||||
|
<ConfigurationType>Application</ConfigurationType> |
||||
|
<UseDebugLibraries>false</UseDebugLibraries> |
||||
|
<PlatformToolset>v142</PlatformToolset> |
||||
|
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
|
<CharacterSet>Unicode</CharacterSet> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
|
<ImportGroup Label="ExtensionSettings"> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="Shared"> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
|
</ImportGroup> |
||||
|
<PropertyGroup Label="UserMacros" /> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<LinkIncremental>true</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<LinkIncremental>false</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<LinkIncremental>true</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<LinkIncremental>false</LinkIncremental> |
||||
|
</PropertyGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
|
<ClCompile> |
||||
|
<WarningLevel>Level3</WarningLevel> |
||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
|
<SDLCheck>true</SDLCheck> |
||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
|
<ConformanceMode>true</ConformanceMode> |
||||
|
</ClCompile> |
||||
|
<Link> |
||||
|
<SubSystem>Console</SubSystem> |
||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||
|
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
|
</Link> |
||||
|
</ItemDefinitionGroup> |
||||
|
<ItemGroup> |
||||
|
<ClCompile Include="main.c" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClInclude Include="..\anorms.h" /> |
||||
|
<ClInclude Include="mdl.h" /> |
||||
|
<ClInclude Include="ps1mdl.h" /> |
||||
|
</ItemGroup> |
||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
|
<ImportGroup Label="ExtensionTargets"> |
||||
|
</ImportGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,33 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<ItemGroup> |
||||
|
<Filter Include="Source Files"> |
||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> |
||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> |
||||
|
</Filter> |
||||
|
<Filter Include="Header Files"> |
||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> |
||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> |
||||
|
</Filter> |
||||
|
<Filter Include="Resource Files"> |
||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> |
||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> |
||||
|
</Filter> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClCompile Include="main.c"> |
||||
|
<Filter>Source Files</Filter> |
||||
|
</ClCompile> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ClInclude Include="mdl.h"> |
||||
|
<Filter>Header Files</Filter> |
||||
|
</ClInclude> |
||||
|
<ClInclude Include="ps1mdl.h"> |
||||
|
<Filter>Header Files</Filter> |
||||
|
</ClInclude> |
||||
|
<ClInclude Include="..\anorms.h"> |
||||
|
<Filter>Header Files</Filter> |
||||
|
</ClInclude> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,227 @@ |
|||||
|
#include <memory.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include "mdl.h" |
||||
|
#include "ps1mdl.h" |
||||
|
|
||||
|
#define PALETTE_SIZE 256 |
||||
|
|
||||
|
#define NUMVERTEXNORMALS 162 |
||||
|
static double anorms[NUMVERTEXNORMALS][3] = { |
||||
|
#include "../anorms.h" |
||||
|
}; |
||||
|
|
||||
|
int convertPalette(const char* lmpFile) |
||||
|
{ |
||||
|
FILE* fp; |
||||
|
const short palette_size = PALETTE_SIZE; |
||||
|
unsigned char palette[PALETTE_SIZE * 3]; |
||||
|
|
||||
|
fopen_s(&fp, lmpFile, "rb"); |
||||
|
if (fp == NULL) |
||||
|
return 0; |
||||
|
|
||||
|
fread(palette, sizeof(unsigned char) * 3, PALETTE_SIZE, fp); |
||||
|
fclose(fp); |
||||
|
|
||||
|
int file_size = PALETTE_SIZE * 4 + 24, tmp; |
||||
|
|
||||
|
fopen_s(&fp, "quake.pal", "wb"); |
||||
|
if (fp == NULL) |
||||
|
return 0; |
||||
|
|
||||
|
fwrite("RIFF", sizeof(char), 4, fp); |
||||
|
tmp = file_size - 8; |
||||
|
fwrite(&tmp, sizeof(int), 1, fp); |
||||
|
fwrite("PAL data", sizeof(char), 8, fp); |
||||
|
tmp = file_size - 20; |
||||
|
fwrite(&tmp, sizeof(int), 1, fp); |
||||
|
fwrite("\000\003", sizeof(char), 2, fp); |
||||
|
fwrite(&palette_size, sizeof(short), 1, fp); |
||||
|
|
||||
|
for (int i = 0; i < PALETTE_SIZE; ++i) |
||||
|
{ |
||||
|
fwrite(palette + i * 3, 3, 1, fp); |
||||
|
fwrite("\000", sizeof(char), 1, fp); |
||||
|
} |
||||
|
|
||||
|
tmp = 1337; |
||||
|
fwrite(&tmp, sizeof(int), 1, fp); |
||||
|
fclose(fp); |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static void toFixedVector(const vec3_t inVec, int outVec[3]) |
||||
|
{ |
||||
|
const int scale = 1 << 12; |
||||
|
outVec[0] = (int)(inVec[0] * scale); |
||||
|
outVec[1] = (int)(inVec[1] * scale); |
||||
|
outVec[2] = (int)(inVec[2] * scale); |
||||
|
} |
||||
|
|
||||
|
int convertModel(const char* outFile, const mdl_header_t* inHeader, const mdl_texcoord_t* inTexCoords, const mdl_triangle_t* inTriangles, const mdl_frame_t* inFrames) |
||||
|
{ |
||||
|
FILE* fout; |
||||
|
fopen_s(&fout, outFile, "wb"); |
||||
|
if (fout == NULL) |
||||
|
return 0; |
||||
|
|
||||
|
// Header |
||||
|
ps1mdl_header_t outHeader; |
||||
|
outHeader.ident = inHeader->ident; |
||||
|
outHeader.version = inHeader->version; |
||||
|
toFixedVector(inHeader->scale, outHeader.scale); |
||||
|
toFixedVector(inHeader->translate, outHeader.translate); |
||||
|
outHeader.skinWidth = (unsigned short)inHeader->skinwidth; |
||||
|
outHeader.skinHeight = (unsigned short)inHeader->skinheight; |
||||
|
outHeader.vertexCount = (unsigned short)inHeader->num_verts; |
||||
|
outHeader.triangleCount = (unsigned short)inHeader->num_tris; |
||||
|
outHeader.frameCount = (unsigned short)inHeader->num_frames; |
||||
|
outHeader.pad = 0; |
||||
|
fwrite(&outHeader, sizeof(ps1mdl_header_t), 1, fout); |
||||
|
|
||||
|
// Texture coordinates |
||||
|
for (int i = 0; i < inHeader->num_verts; ++i) |
||||
|
{ |
||||
|
ps1mdl_texcoord_t outTexCoord; |
||||
|
outTexCoord.onSeam = (short)(inTexCoords[i].onseam != 0); |
||||
|
outTexCoord.u = (short)inTexCoords[i].s; |
||||
|
outTexCoord.v = (short)inTexCoords[i].t; |
||||
|
fwrite(&outTexCoord, sizeof(ps1mdl_texcoord_t), 1, fout); |
||||
|
} |
||||
|
|
||||
|
// Triangles |
||||
|
for (int i = 0; i < inHeader->num_tris; ++i) |
||||
|
{ |
||||
|
ps1mdl_triangle_t outTriangle; |
||||
|
outTriangle.frontFace = (short)(inTriangles[i].facesfront != 0); |
||||
|
outTriangle.vertexIndex[0] = (unsigned short)inTriangles[i].vertex[0]; |
||||
|
outTriangle.vertexIndex[1] = (unsigned short)inTriangles[i].vertex[1]; |
||||
|
outTriangle.vertexIndex[2] = (unsigned short)inTriangles[i].vertex[2]; |
||||
|
fwrite(&outTriangle, sizeof(ps1mdl_triangle_t), 1, fout); |
||||
|
} |
||||
|
|
||||
|
// Vertices |
||||
|
for (int frameIdx = 0; frameIdx < inHeader->num_frames; ++frameIdx) |
||||
|
{ |
||||
|
for (int i = 0; i < inHeader->num_verts; ++i) |
||||
|
{ |
||||
|
mdl_vertex_t* inVert = &inFrames[frameIdx].frame.verts[i]; |
||||
|
ps1mdl_vertex_t outVertex; |
||||
|
outVertex.position[0] = inVert->v[0]; |
||||
|
outVertex.position[1] = inVert->v[1]; |
||||
|
outVertex.position[2] = inVert->v[2]; |
||||
|
outVertex.normalIndex = inVert->normalIndex; |
||||
|
fwrite(&outVertex, sizeof(ps1mdl_vertex_t), 1, fout); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
fclose(fout); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
void exportNormals() |
||||
|
{ |
||||
|
FILE* fout; |
||||
|
fopen_s(&fout, "ps1anorms.h", "w"); |
||||
|
if (fout == NULL) |
||||
|
return; |
||||
|
|
||||
|
for (int i = 0; i < NUMVERTEXNORMALS; ++i) |
||||
|
{ |
||||
|
int x = (int)(anorms[i][0] * 4096); |
||||
|
int y = (int)(anorms[i][1] * 4096); |
||||
|
int z = (int)(anorms[i][2] * 4096); |
||||
|
|
||||
|
fprintf(fout, "{%d, %d, %d, 0},\n", x, y, z); |
||||
|
} |
||||
|
|
||||
|
fclose(fout); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char** argv) |
||||
|
{ |
||||
|
FILE* f; |
||||
|
mdl_header_t header; |
||||
|
char path[_MAX_PATH]; |
||||
|
|
||||
|
convertPalette(argv[1]); |
||||
|
exportNormals(); |
||||
|
|
||||
|
fopen_s(&f, argv[2], "rb"); |
||||
|
if (f == NULL) |
||||
|
return 1; |
||||
|
|
||||
|
fread(&header, sizeof(mdl_header_t), 1, f); |
||||
|
|
||||
|
printf("Header model identifier: %d, version: %d\n", header.ident, header.version); |
||||
|
|
||||
|
// Skins |
||||
|
printf("Reading %d skins of size: %dx%d\n", header.num_skins, header.skinwidth, header.skinheight); |
||||
|
|
||||
|
size_t skinSize = header.skinwidth * header.skinheight * sizeof(unsigned char); |
||||
|
unsigned char* buf = (unsigned char*)malloc(skinSize); |
||||
|
if (!buf) |
||||
|
{ |
||||
|
fclose(f); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < header.num_skins; ++i) |
||||
|
{ |
||||
|
int group; |
||||
|
fread(&group, sizeof(int), 1, f); |
||||
|
|
||||
|
if (group) |
||||
|
{ |
||||
|
int numPics; |
||||
|
fread(&numPics, sizeof(int), 1, f); |
||||
|
fseek(f, numPics * sizeof(float) + numPics * skinSize, SEEK_CUR); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
fread(buf, sizeof(unsigned char), skinSize, f); |
||||
|
|
||||
|
FILE* fout; |
||||
|
sprintf_s(path, _MAX_PATH, "skin_%d_%dx%d.raw", i, header.skinwidth, header.skinheight); |
||||
|
fopen_s(&fout, path, "wb"); |
||||
|
if (fout == NULL) |
||||
|
continue; |
||||
|
|
||||
|
fwrite(buf, sizeof(unsigned char), skinSize, fout); |
||||
|
fclose(fout); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free(buf); |
||||
|
|
||||
|
printf("Reading geometry data for %d vertices, %d triangles, %d frames\n", header.num_verts, header.num_tris, header.num_frames); |
||||
|
|
||||
|
// Texcoords & triangles (vertex indices) |
||||
|
mdl_texcoord_t* texCoords = (mdl_texcoord_t*)malloc(sizeof(mdl_texcoord_t) * header.num_verts); |
||||
|
mdl_triangle_t* triangles = (mdl_triangle_t*)malloc(sizeof(mdl_triangle_t) * header.num_tris); |
||||
|
fread(texCoords, sizeof(mdl_texcoord_t), header.num_verts, f); |
||||
|
fread(triangles, sizeof(mdl_triangle_t), header.num_tris, f); |
||||
|
|
||||
|
// Frames (vertex data) |
||||
|
mdl_frame_t* frames = (mdl_frame_t*)malloc(sizeof(mdl_frame_t) * header.num_frames); |
||||
|
for (int i = 0; i < header.num_frames; ++i) |
||||
|
{ |
||||
|
frames[i].frame.verts = (mdl_vertex_t*)malloc(sizeof(mdl_vertex_t) * header.num_verts); |
||||
|
|
||||
|
fread(&frames[i].type, sizeof(int), 1, f); |
||||
|
fread(&frames[i].frame.bboxmin, sizeof(mdl_vertex_t), 1, f); |
||||
|
fread(&frames[i].frame.bboxmax, sizeof(mdl_vertex_t), 1, f); |
||||
|
fread(frames[i].frame.name, sizeof(char), 16, f); |
||||
|
fread(frames[i].frame.verts, sizeof(mdl_vertex_t), header.num_verts, f); |
||||
|
} |
||||
|
|
||||
|
fclose(f); |
||||
|
|
||||
|
// Write simplified model file for PS1 |
||||
|
if (!convertModel(argv[3], &header, texCoords, triangles, frames)) |
||||
|
return 1; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
/* Vector */ |
||||
|
typedef float vec3_t[3]; |
||||
|
|
||||
|
/* MDL header */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int ident; /* magic number: "IDPO" */ |
||||
|
int version; /* version: 6 */ |
||||
|
|
||||
|
vec3_t scale; /* scale factor */ |
||||
|
vec3_t translate; /* translation vector */ |
||||
|
float boundingradius; |
||||
|
vec3_t eyeposition; /* eyes' position */ |
||||
|
|
||||
|
int num_skins; /* number of textures */ |
||||
|
int skinwidth; /* texture width */ |
||||
|
int skinheight; /* texture height */ |
||||
|
|
||||
|
int num_verts; /* number of vertices */ |
||||
|
int num_tris; /* number of triangles */ |
||||
|
int num_frames; /* number of frames */ |
||||
|
|
||||
|
int synctype; /* 0 = synchron, 1 = random */ |
||||
|
int flags; /* state flag */ |
||||
|
float size; |
||||
|
} mdl_header_t; |
||||
|
|
||||
|
/* Skin */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int group; /* 0 = single, 1 = group */ |
||||
|
unsigned char* data; /* texture data */ |
||||
|
} mdl_skin_t; |
||||
|
|
||||
|
/* Group of pictures */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int group; /* 1 = group */ |
||||
|
int nb; /* number of pics */ |
||||
|
float* time; /* time duration for each pic */ |
||||
|
unsigned char** data; /* texture data */ |
||||
|
} mdl_groupskin_t; |
||||
|
|
||||
|
/* Texture coords */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int onseam; |
||||
|
int s; |
||||
|
int t; |
||||
|
} mdl_texcoord_t; |
||||
|
|
||||
|
/* Triangle info */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int facesfront; /* 0 = backface, 1 = frontface */ |
||||
|
int vertex[3]; /* vertex indices */ |
||||
|
} mdl_triangle_t; |
||||
|
|
||||
|
/* Compressed vertex */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned char v[3]; |
||||
|
unsigned char normalIndex; |
||||
|
} mdl_vertex_t; |
||||
|
|
||||
|
/* Simple frame */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
mdl_vertex_t bboxmin; /* bouding box min */ |
||||
|
mdl_vertex_t bboxmax; /* bouding box max */ |
||||
|
char name[16]; |
||||
|
mdl_vertex_t* verts; /* vertex list of the frame */ |
||||
|
} mdl_simpleframe_t; |
||||
|
|
||||
|
/* Model frame */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int type; /* 0 = simple, !0 = group */ |
||||
|
mdl_simpleframe_t frame; /* this program can't read models |
||||
|
composed of group frames! */ |
||||
|
} mdl_frame_t; |
||||
|
|
||||
|
/* Group of simple frames */ |
||||
|
typedef struct |
||||
|
{ |
||||
|
int type; /* !0 = group */ |
||||
|
mdl_vertex_t min; /* min pos in all simple frames */ |
||||
|
mdl_vertex_t max; /* max pos in all simple frames */ |
||||
|
float* time; /* time duration for each frame */ |
||||
|
mdl_simpleframe_t* frames; /* simple frame list */ |
||||
|
} mdl_groupframe_t; |
||||
@ -0,0 +1,162 @@ |
|||||
|
{-2153, 0, 3484, 0}, |
||||
|
{-1813, 978, 3539, 0}, |
||||
|
{-1209, 0, 3913, 0}, |
||||
|
{-1265, 2048, 3313, 0}, |
||||
|
{-665, 1076, 3895, 0}, |
||||
|
{0, 0, 4096, 0}, |
||||
|
{0, 3484, 2153, 0}, |
||||
|
{-604, 2935, 2792, 0}, |
||||
|
{604, 2935, 2792, 0}, |
||||
|
{0, 2153, 3484, 0}, |
||||
|
{1265, 2048, 3313, 0}, |
||||
|
{2153, 0, 3484, 0}, |
||||
|
{1209, 0, 3913, 0}, |
||||
|
{1813, 978, 3539, 0}, |
||||
|
{665, 1076, 3895, 0}, |
||||
|
{-2792, 604, 2935, 0}, |
||||
|
{-3313, 1265, 2048, 0}, |
||||
|
{-2407, 1742, 2818, 0}, |
||||
|
{-3484, 2153, 0, 0}, |
||||
|
{-3539, 1813, 978, 0}, |
||||
|
{-2935, 2792, 604, 0}, |
||||
|
{-2818, 2407, 1742, 0}, |
||||
|
{-2048, 3313, 1265, 0}, |
||||
|
{-978, 3539, 1813, 0}, |
||||
|
{-1742, 2818, 2407, 0}, |
||||
|
{-2935, 2792, -604, 0}, |
||||
|
{-2048, 3313, -1265, 0}, |
||||
|
{-2153, 3484, 0, 0}, |
||||
|
{0, 3484, -2153, 0}, |
||||
|
{-978, 3539, -1813, 0}, |
||||
|
{0, 3913, -1209, 0}, |
||||
|
{-1076, 3895, -665, 0}, |
||||
|
{0, 4096, 0, 0}, |
||||
|
{0, 3913, 1209, 0}, |
||||
|
{-1076, 3895, 665, 0}, |
||||
|
{978, 3539, 1813, 0}, |
||||
|
{1076, 3895, 665, 0}, |
||||
|
{2048, 3313, 1265, 0}, |
||||
|
{978, 3539, -1813, 0}, |
||||
|
{1076, 3895, -665, 0}, |
||||
|
{2048, 3313, -1265, 0}, |
||||
|
{3484, 2153, 0, 0}, |
||||
|
{2935, 2792, 604, 0}, |
||||
|
{2935, 2792, -604, 0}, |
||||
|
{2153, 3484, 0, 0}, |
||||
|
{1742, 2818, 2407, 0}, |
||||
|
{3539, 1813, 978, 0}, |
||||
|
{2818, 2407, 1742, 0}, |
||||
|
{3313, 1265, 2048, 0}, |
||||
|
{2792, 604, 2935, 0}, |
||||
|
{2407, 1742, 2818, 0}, |
||||
|
{3913, 1209, 0, 0}, |
||||
|
{4096, 0, 0, 0}, |
||||
|
{3895, 665, 1076, 0}, |
||||
|
{3484, -2153, 0, 0}, |
||||
|
{3913, -1209, 0, 0}, |
||||
|
{3539, -1813, 978, 0}, |
||||
|
{3895, -665, 1076, 0}, |
||||
|
{3313, -1265, 2048, 0}, |
||||
|
{2792, -604, 2935, 0}, |
||||
|
{3484, 0, 2153, 0}, |
||||
|
{3539, 1813, -978, 0}, |
||||
|
{3313, 1265, -2048, 0}, |
||||
|
{3895, 665, -1076, 0}, |
||||
|
{2153, 0, -3484, 0}, |
||||
|
{2792, 604, -2935, 0}, |
||||
|
{2792, -604, -2935, 0}, |
||||
|
{3484, 0, -2153, 0}, |
||||
|
{3313, -1265, -2048, 0}, |
||||
|
{3539, -1813, -978, 0}, |
||||
|
{3895, -665, -1076, 0}, |
||||
|
{604, 2935, -2792, 0}, |
||||
|
{1265, 2048, -3313, 0}, |
||||
|
{1742, 2818, -2407, 0}, |
||||
|
{1813, 978, -3539, 0}, |
||||
|
{2407, 1742, -2818, 0}, |
||||
|
{2818, 2407, -1742, 0}, |
||||
|
{-604, 2935, -2792, 0}, |
||||
|
{-1265, 2048, -3313, 0}, |
||||
|
{0, 2153, -3484, 0}, |
||||
|
{-2153, 0, -3484, 0}, |
||||
|
{-1813, 978, -3539, 0}, |
||||
|
{-1209, 0, -3913, 0}, |
||||
|
{-665, 1076, -3895, 0}, |
||||
|
{0, 0, -4096, 0}, |
||||
|
{1209, 0, -3913, 0}, |
||||
|
{665, 1076, -3895, 0}, |
||||
|
{-1813, -978, -3539, 0}, |
||||
|
{-1265, -2048, -3313, 0}, |
||||
|
{-665, -1076, -3895, 0}, |
||||
|
{0, -3484, -2153, 0}, |
||||
|
{-604, -2935, -2792, 0}, |
||||
|
{604, -2935, -2792, 0}, |
||||
|
{0, -2153, -3484, 0}, |
||||
|
{1265, -2048, -3313, 0}, |
||||
|
{1813, -978, -3539, 0}, |
||||
|
{665, -1076, -3895, 0}, |
||||
|
{978, -3539, -1813, 0}, |
||||
|
{2048, -3313, -1265, 0}, |
||||
|
{1742, -2818, -2407, 0}, |
||||
|
{2935, -2792, -604, 0}, |
||||
|
{2818, -2407, -1742, 0}, |
||||
|
{2407, -1742, -2818, 0}, |
||||
|
{0, -3913, -1209, 0}, |
||||
|
{0, -4096, 0, 0}, |
||||
|
{1076, -3895, -665, 0}, |
||||
|
{0, -3484, 2153, 0}, |
||||
|
{0, -3913, 1209, 0}, |
||||
|
{978, -3539, 1813, 0}, |
||||
|
{1076, -3895, 665, 0}, |
||||
|
{2048, -3313, 1265, 0}, |
||||
|
{2935, -2792, 604, 0}, |
||||
|
{2153, -3484, 0, 0}, |
||||
|
{-978, -3539, -1813, 0}, |
||||
|
{-2048, -3313, -1265, 0}, |
||||
|
{-1076, -3895, -665, 0}, |
||||
|
{-3484, -2153, 0, 0}, |
||||
|
{-2935, -2792, -604, 0}, |
||||
|
{-2935, -2792, 604, 0}, |
||||
|
{-2153, -3484, 0, 0}, |
||||
|
{-2048, -3313, 1265, 0}, |
||||
|
{-978, -3539, 1813, 0}, |
||||
|
{-1076, -3895, 665, 0}, |
||||
|
{-3539, -1813, 978, 0}, |
||||
|
{-3313, -1265, 2048, 0}, |
||||
|
{-2818, -2407, 1742, 0}, |
||||
|
{-2792, -604, 2935, 0}, |
||||
|
{-1813, -978, 3539, 0}, |
||||
|
{-2407, -1742, 2818, 0}, |
||||
|
{-1265, -2048, 3313, 0}, |
||||
|
{-604, -2935, 2792, 0}, |
||||
|
{-1742, -2818, 2407, 0}, |
||||
|
{-665, -1076, 3895, 0}, |
||||
|
{1813, -978, 3539, 0}, |
||||
|
{665, -1076, 3895, 0}, |
||||
|
{1265, -2048, 3313, 0}, |
||||
|
{604, -2935, 2792, 0}, |
||||
|
{0, -2153, 3484, 0}, |
||||
|
{1742, -2818, 2407, 0}, |
||||
|
{2407, -1742, 2818, 0}, |
||||
|
{2818, -2407, 1742, 0}, |
||||
|
{-3913, 1209, 0, 0}, |
||||
|
{-3895, 665, 1076, 0}, |
||||
|
{-4096, 0, 0, 0}, |
||||
|
{-3484, 0, 2153, 0}, |
||||
|
{-3913, -1209, 0, 0}, |
||||
|
{-3895, -665, 1076, 0}, |
||||
|
{-3539, 1813, -978, 0}, |
||||
|
{-3895, 665, -1076, 0}, |
||||
|
{-3313, 1265, -2048, 0}, |
||||
|
{-3539, -1813, -978, 0}, |
||||
|
{-3895, -665, -1076, 0}, |
||||
|
{-3313, -1265, -2048, 0}, |
||||
|
{-2792, 604, -2935, 0}, |
||||
|
{-2792, -604, -2935, 0}, |
||||
|
{-3484, 0, -2153, 0}, |
||||
|
{-2818, 2407, -1742, 0}, |
||||
|
{-2407, 1742, -2818, 0}, |
||||
|
{-1742, 2818, -2407, 0}, |
||||
|
{-1742, -2818, -2407, 0}, |
||||
|
{-2407, -1742, -2818, 0}, |
||||
|
{-2818, -2407, -1742, 0}, |
||||
@ -0,0 +1,48 @@ |
|||||
|
#ifndef __PS1MDL_H__ |
||||
|
#define __PS1MDL_H__ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
int ident; |
||||
|
int version; |
||||
|
|
||||
|
int scale[3]; |
||||
|
int translate[3]; |
||||
|
|
||||
|
unsigned short skinWidth; |
||||
|
unsigned short skinHeight; |
||||
|
|
||||
|
unsigned short vertexCount; |
||||
|
unsigned short triangleCount; |
||||
|
unsigned short frameCount; |
||||
|
|
||||
|
unsigned short pad; |
||||
|
} ps1mdl_header_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
short onSeam; |
||||
|
short u, v; |
||||
|
} ps1mdl_texcoord_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
short frontFace; |
||||
|
unsigned short vertexIndex[3]; |
||||
|
} ps1mdl_triangle_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned char position[3]; |
||||
|
unsigned char normalIndex; |
||||
|
} ps1mdl_vertex_t; |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif // __PS1BSP_H__ |
||||
@ -0,0 +1,181 @@ |
|||||
|
/* |
||||
|
Copyright (C) 1996-1997 Id Software, Inc. |
||||
|
|
||||
|
This program is free software; you can redistribute it and/or |
||||
|
modify it under the terms of the GNU General Public License |
||||
|
as published by the Free Software Foundation; either version 2 |
||||
|
of the License, or (at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||||
|
|
||||
|
See the GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License |
||||
|
along with this program; if not, write to the Free Software |
||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||||
|
|
||||
|
*/ |
||||
|
{-0.525731, 0.000000, 0.850651}, |
||||
|
{-0.442863, 0.238856, 0.864188}, |
||||
|
{-0.295242, 0.000000, 0.955423}, |
||||
|
{-0.309017, 0.500000, 0.809017}, |
||||
|
{-0.162460, 0.262866, 0.951056}, |
||||
|
{0.000000, 0.000000, 1.000000}, |
||||
|
{0.000000, 0.850651, 0.525731}, |
||||
|
{-0.147621, 0.716567, 0.681718}, |
||||
|
{0.147621, 0.716567, 0.681718}, |
||||
|
{0.000000, 0.525731, 0.850651}, |
||||
|
{0.309017, 0.500000, 0.809017}, |
||||
|
{0.525731, 0.000000, 0.850651}, |
||||
|
{0.295242, 0.000000, 0.955423}, |
||||
|
{0.442863, 0.238856, 0.864188}, |
||||
|
{0.162460, 0.262866, 0.951056}, |
||||
|
{-0.681718, 0.147621, 0.716567}, |
||||
|
{-0.809017, 0.309017, 0.500000}, |
||||
|
{-0.587785, 0.425325, 0.688191}, |
||||
|
{-0.850651, 0.525731, 0.000000}, |
||||
|
{-0.864188, 0.442863, 0.238856}, |
||||
|
{-0.716567, 0.681718, 0.147621}, |
||||
|
{-0.688191, 0.587785, 0.425325}, |
||||
|
{-0.500000, 0.809017, 0.309017}, |
||||
|
{-0.238856, 0.864188, 0.442863}, |
||||
|
{-0.425325, 0.688191, 0.587785}, |
||||
|
{-0.716567, 0.681718, -0.147621}, |
||||
|
{-0.500000, 0.809017, -0.309017}, |
||||
|
{-0.525731, 0.850651, 0.000000}, |
||||
|
{0.000000, 0.850651, -0.525731}, |
||||
|
{-0.238856, 0.864188, -0.442863}, |
||||
|
{0.000000, 0.955423, -0.295242}, |
||||
|
{-0.262866, 0.951056, -0.162460}, |
||||
|
{0.000000, 1.000000, 0.000000}, |
||||
|
{0.000000, 0.955423, 0.295242}, |
||||
|
{-0.262866, 0.951056, 0.162460}, |
||||
|
{0.238856, 0.864188, 0.442863}, |
||||
|
{0.262866, 0.951056, 0.162460}, |
||||
|
{0.500000, 0.809017, 0.309017}, |
||||
|
{0.238856, 0.864188, -0.442863}, |
||||
|
{0.262866, 0.951056, -0.162460}, |
||||
|
{0.500000, 0.809017, -0.309017}, |
||||
|
{0.850651, 0.525731, 0.000000}, |
||||
|
{0.716567, 0.681718, 0.147621}, |
||||
|
{0.716567, 0.681718, -0.147621}, |
||||
|
{0.525731, 0.850651, 0.000000}, |
||||
|
{0.425325, 0.688191, 0.587785}, |
||||
|
{0.864188, 0.442863, 0.238856}, |
||||
|
{0.688191, 0.587785, 0.425325}, |
||||
|
{0.809017, 0.309017, 0.500000}, |
||||
|
{0.681718, 0.147621, 0.716567}, |
||||
|
{0.587785, 0.425325, 0.688191}, |
||||
|
{0.955423, 0.295242, 0.000000}, |
||||
|
{1.000000, 0.000000, 0.000000}, |
||||
|
{0.951056, 0.162460, 0.262866}, |
||||
|
{0.850651, -0.525731, 0.000000}, |
||||
|
{0.955423, -0.295242, 0.000000}, |
||||
|
{0.864188, -0.442863, 0.238856}, |
||||
|
{0.951056, -0.162460, 0.262866}, |
||||
|
{0.809017, -0.309017, 0.500000}, |
||||
|
{0.681718, -0.147621, 0.716567}, |
||||
|
{0.850651, 0.000000, 0.525731}, |
||||
|
{0.864188, 0.442863, -0.238856}, |
||||
|
{0.809017, 0.309017, -0.500000}, |
||||
|
{0.951056, 0.162460, -0.262866}, |
||||
|
{0.525731, 0.000000, -0.850651}, |
||||
|
{0.681718, 0.147621, -0.716567}, |
||||
|
{0.681718, -0.147621, -0.716567}, |
||||
|
{0.850651, 0.000000, -0.525731}, |
||||
|
{0.809017, -0.309017, -0.500000}, |
||||
|
{0.864188, -0.442863, -0.238856}, |
||||
|
{0.951056, -0.162460, -0.262866}, |
||||
|
{0.147621, 0.716567, -0.681718}, |
||||
|
{0.309017, 0.500000, -0.809017}, |
||||
|
{0.425325, 0.688191, -0.587785}, |
||||
|
{0.442863, 0.238856, -0.864188}, |
||||
|
{0.587785, 0.425325, -0.688191}, |
||||
|
{0.688191, 0.587785, -0.425325}, |
||||
|
{-0.147621, 0.716567, -0.681718}, |
||||
|
{-0.309017, 0.500000, -0.809017}, |
||||
|
{0.000000, 0.525731, -0.850651}, |
||||
|
{-0.525731, 0.000000, -0.850651}, |
||||
|
{-0.442863, 0.238856, -0.864188}, |
||||
|
{-0.295242, 0.000000, -0.955423}, |
||||
|
{-0.162460, 0.262866, -0.951056}, |
||||
|
{0.000000, 0.000000, -1.000000}, |
||||
|
{0.295242, 0.000000, -0.955423}, |
||||
|
{0.162460, 0.262866, -0.951056}, |
||||
|
{-0.442863, -0.238856, -0.864188}, |
||||
|
{-0.309017, -0.500000, -0.809017}, |
||||
|
{-0.162460, -0.262866, -0.951056}, |
||||
|
{0.000000, -0.850651, -0.525731}, |
||||
|
{-0.147621, -0.716567, -0.681718}, |
||||
|
{0.147621, -0.716567, -0.681718}, |
||||
|
{0.000000, -0.525731, -0.850651}, |
||||
|
{0.309017, -0.500000, -0.809017}, |
||||
|
{0.442863, -0.238856, -0.864188}, |
||||
|
{0.162460, -0.262866, -0.951056}, |
||||
|
{0.238856, -0.864188, -0.442863}, |
||||
|
{0.500000, -0.809017, -0.309017}, |
||||
|
{0.425325, -0.688191, -0.587785}, |
||||
|
{0.716567, -0.681718, -0.147621}, |
||||
|
{0.688191, -0.587785, -0.425325}, |
||||
|
{0.587785, -0.425325, -0.688191}, |
||||
|
{0.000000, -0.955423, -0.295242}, |
||||
|
{0.000000, -1.000000, 0.000000}, |
||||
|
{0.262866, -0.951056, -0.162460}, |
||||
|
{0.000000, -0.850651, 0.525731}, |
||||
|
{0.000000, -0.955423, 0.295242}, |
||||
|
{0.238856, -0.864188, 0.442863}, |
||||
|
{0.262866, -0.951056, 0.162460}, |
||||
|
{0.500000, -0.809017, 0.309017}, |
||||
|
{0.716567, -0.681718, 0.147621}, |
||||
|
{0.525731, -0.850651, 0.000000}, |
||||
|
{-0.238856, -0.864188, -0.442863}, |
||||
|
{-0.500000, -0.809017, -0.309017}, |
||||
|
{-0.262866, -0.951056, -0.162460}, |
||||
|
{-0.850651, -0.525731, 0.000000}, |
||||
|
{-0.716567, -0.681718, -0.147621}, |
||||
|
{-0.716567, -0.681718, 0.147621}, |
||||
|
{-0.525731, -0.850651, 0.000000}, |
||||
|
{-0.500000, -0.809017, 0.309017}, |
||||
|
{-0.238856, -0.864188, 0.442863}, |
||||
|
{-0.262866, -0.951056, 0.162460}, |
||||
|
{-0.864188, -0.442863, 0.238856}, |
||||
|
{-0.809017, -0.309017, 0.500000}, |
||||
|
{-0.688191, -0.587785, 0.425325}, |
||||
|
{-0.681718, -0.147621, 0.716567}, |
||||
|
{-0.442863, -0.238856, 0.864188}, |
||||
|
{-0.587785, -0.425325, 0.688191}, |
||||
|
{-0.309017, -0.500000, 0.809017}, |
||||
|
{-0.147621, -0.716567, 0.681718}, |
||||
|
{-0.425325, -0.688191, 0.587785}, |
||||
|
{-0.162460, -0.262866, 0.951056}, |
||||
|
{0.442863, -0.238856, 0.864188}, |
||||
|
{0.162460, -0.262866, 0.951056}, |
||||
|
{0.309017, -0.500000, 0.809017}, |
||||
|
{0.147621, -0.716567, 0.681718}, |
||||
|
{0.000000, -0.525731, 0.850651}, |
||||
|
{0.425325, -0.688191, 0.587785}, |
||||
|
{0.587785, -0.425325, 0.688191}, |
||||
|
{0.688191, -0.587785, 0.425325}, |
||||
|
{-0.955423, 0.295242, 0.000000}, |
||||
|
{-0.951056, 0.162460, 0.262866}, |
||||
|
{-1.000000, 0.000000, 0.000000}, |
||||
|
{-0.850651, 0.000000, 0.525731}, |
||||
|
{-0.955423, -0.295242, 0.000000}, |
||||
|
{-0.951056, -0.162460, 0.262866}, |
||||
|
{-0.864188, 0.442863, -0.238856}, |
||||
|
{-0.951056, 0.162460, -0.262866}, |
||||
|
{-0.809017, 0.309017, -0.500000}, |
||||
|
{-0.864188, -0.442863, -0.238856}, |
||||
|
{-0.951056, -0.162460, -0.262866}, |
||||
|
{-0.809017, -0.309017, -0.500000}, |
||||
|
{-0.681718, 0.147621, -0.716567}, |
||||
|
{-0.681718, -0.147621, -0.716567}, |
||||
|
{-0.850651, 0.000000, -0.525731}, |
||||
|
{-0.688191, 0.587785, -0.425325}, |
||||
|
{-0.587785, 0.425325, -0.688191}, |
||||
|
{-0.425325, 0.688191, -0.587785}, |
||||
|
{-0.425325, -0.688191, -0.587785}, |
||||
|
{-0.587785, -0.425325, -0.688191}, |
||||
|
{-0.688191, -0.587785, -0.425325}, |
||||
@ -0,0 +1,98 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
typedef struct // A Directory entry |
||||
|
{ |
||||
|
long offset; // Offset to entry, in bytes, from start of file |
||||
|
long size; // Size of entry in file, in bytes |
||||
|
} dentry_t; |
||||
|
|
||||
|
typedef struct // The BSP file header |
||||
|
{ |
||||
|
long version; // Model version, must be 0x17 (23). |
||||
|
dentry_t entities; // List of Entities. |
||||
|
dentry_t planes; // Map Planes. |
||||
|
// numplanes = size/sizeof(plane_t) |
||||
|
dentry_t miptex; // Wall Textures. |
||||
|
dentry_t vertices; // Map Vertices. |
||||
|
// numvertices = size/sizeof(vertex_t) |
||||
|
dentry_t visilist; // Leaves Visibility lists. |
||||
|
dentry_t nodes; // BSP Nodes. |
||||
|
// numnodes = size/sizeof(node_t) |
||||
|
dentry_t texinfo; // Texture Info for faces. |
||||
|
// numtexinfo = size/sizeof(texinfo_t) |
||||
|
dentry_t faces; // Faces of each surface. |
||||
|
// numfaces = size/sizeof(face_t) |
||||
|
dentry_t lightmaps; // Wall Light Maps. |
||||
|
dentry_t clipnodes; // clip nodes, for Models. |
||||
|
// numclips = size/sizeof(clipnode_t) |
||||
|
dentry_t leaves; // BSP Leaves. |
||||
|
// numlaves = size/sizeof(leaf_t) |
||||
|
dentry_t lface; // List of Faces. |
||||
|
dentry_t edges; // Edges of faces. |
||||
|
// numedges = Size/sizeof(edge_t) |
||||
|
dentry_t ledges; // List of Edges. |
||||
|
dentry_t models; // List of Models. |
||||
|
// nummodels = Size/sizeof(model_t) |
||||
|
} dheader_t; |
||||
|
|
||||
|
typedef float scalar_t; // Scalar value, |
||||
|
|
||||
|
typedef struct // Vector or Position |
||||
|
{ |
||||
|
scalar_t x; // horizontal |
||||
|
scalar_t y; // horizontal |
||||
|
scalar_t z; // vertical |
||||
|
} vec3_t; |
||||
|
|
||||
|
typedef struct // Bounding Box, Float values |
||||
|
{ |
||||
|
vec3_t min; // minimum values of X,Y,Z |
||||
|
vec3_t max; // maximum values of X,Y,Z |
||||
|
} boundbox_t; |
||||
|
|
||||
|
typedef struct // Bounding Box, Short values |
||||
|
{ |
||||
|
short min; // minimum values of X,Y,Z |
||||
|
short max; // maximum values of X,Y,Z |
||||
|
} bboxshort_t; |
||||
|
|
||||
|
typedef struct // Mip texture list header |
||||
|
{ |
||||
|
long numtex; // Number of textures in Mip Texture list |
||||
|
long *offset; // Offset to each of the individual texture |
||||
|
} mipheader_t; // from the beginning of mipheader_t |
||||
|
|
||||
|
typedef struct // Mip Texture |
||||
|
{ |
||||
|
char name[16]; // Name of the texture. |
||||
|
unsigned long width; // width of picture, must be a multiple of 8 |
||||
|
unsigned long height; // height of picture, must be a multiple of 8 |
||||
|
unsigned long offset1; // offset to u_char Pix[width * height] |
||||
|
unsigned long offset2; // offset to u_char Pix[width/2 * height/2] |
||||
|
unsigned long offset4; // offset to u_char Pix[width/4 * height/4] |
||||
|
unsigned long offset8; // offset to u_char Pix[width/8 * height/8] |
||||
|
} miptex_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
float X; // X,Y,Z coordinates of the vertex |
||||
|
float Y; // usually some integer value |
||||
|
float Z; // but coded in floating point |
||||
|
} vertex_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned short plane_id; // The plane in which the face lies |
||||
|
// must be in [0,numplanes[ |
||||
|
unsigned short side; // 0 if in front of the plane, 1 if behind the plane |
||||
|
long ledge_id; // first edge in the List of edges |
||||
|
// must be in [0,numledges[ |
||||
|
unsigned short ledge_num; // number of edges in the List of edges |
||||
|
unsigned short texinfo_id; // index of the Texture info the face is part of |
||||
|
// must be in [0,numtexinfos[ |
||||
|
unsigned char typelight; // type of lighting, for the face |
||||
|
unsigned char baselight; // from 0xFF (dark) to 0 (bright) |
||||
|
unsigned char light[2]; // two additional light models |
||||
|
long lightmap; // Pointer inside the general light map, or -1 |
||||
|
// this define the start of the face light map |
||||
|
} face_t; |
||||
@ -0,0 +1,180 @@ |
|||||
|
#include <memory.h>
|
||||
|
#include <stdlib.h>
|
||||
|
#include <stdio.h>
|
||||
|
#include "bsp.h"
|
||||
|
#include "rectpack/finders_interface.h"
|
||||
|
|
||||
|
int main(int argc, char** argv) |
||||
|
{ |
||||
|
FILE* f; |
||||
|
dheader_t header; |
||||
|
char path[_MAX_PATH]; |
||||
|
|
||||
|
fopen_s(&f, argv[1], "rb"); |
||||
|
if (f == NULL) |
||||
|
return 1; |
||||
|
|
||||
|
fread(&header, sizeof(dheader_t), 1, f); |
||||
|
|
||||
|
printf("Header model version: %d\n", header.version); |
||||
|
|
||||
|
// Test reading the entity string data
|
||||
|
fseek(f, header.entities.offset, SEEK_SET); |
||||
|
|
||||
|
char* entities = (char*)malloc((header.entities.size + 1) * sizeof(char)); |
||||
|
if (entities == NULL) |
||||
|
{ |
||||
|
fclose(f); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
memset(entities, 0, (header.entities.size + 1) * sizeof(char)); |
||||
|
fread(entities, sizeof(char), header.entities.size, f); |
||||
|
|
||||
|
printf("Entities list:\n%s\n", entities); |
||||
|
free(entities); |
||||
|
|
||||
|
// Test exporting texture data
|
||||
|
fseek(f, header.miptex.offset, SEEK_SET); |
||||
|
mipheader_t mipheader; |
||||
|
fread(&mipheader.numtex, sizeof(long), 1, f); |
||||
|
mipheader.offset = (long*)malloc(mipheader.numtex * sizeof(long)); |
||||
|
if (mipheader.offset == NULL) |
||||
|
{ |
||||
|
fclose(f); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
fread(mipheader.offset, sizeof(long), mipheader.numtex, f); |
||||
|
|
||||
|
using spaces_type = rectpack2D::empty_spaces<false>; |
||||
|
using rect_type = rectpack2D::output_rect_t<spaces_type>; |
||||
|
|
||||
|
auto report_successful = [](rect_type&) { |
||||
|
return rectpack2D::callback_result::CONTINUE_PACKING; |
||||
|
}; |
||||
|
|
||||
|
auto report_unsuccessful = [](rect_type&) { |
||||
|
return rectpack2D::callback_result::ABORT_PACKING; |
||||
|
}; |
||||
|
|
||||
|
const auto max_side = 512; // Max height of PS1 VRAM. 8-bit textures take up half the horizontal space so this is 256x512 in practice, or a quarter of the PS1's VRAM allocation.
|
||||
|
const auto discard_step = -4; |
||||
|
|
||||
|
std::vector<rect_type> rectangles; |
||||
|
|
||||
|
miptex_t miptex; |
||||
|
|
||||
|
// Try some texture packing and see if we fit inside the PS1's VRAM
|
||||
|
for (int texNum = 0; texNum < mipheader.numtex; ++texNum) |
||||
|
{ |
||||
|
unsigned long miptexOffset = header.miptex.offset + mipheader.offset[texNum]; |
||||
|
fseek(f, miptexOffset, SEEK_SET); |
||||
|
fread(&miptex, sizeof(miptex_t), 1, f); |
||||
|
|
||||
|
//printf("Texture %d (%dx%d): %.16s\n", texNum, miptex.width, miptex.height, miptex.name);
|
||||
|
|
||||
|
// Shrink the larger textures, but keep smaller ones at their original size
|
||||
|
int ps1mip = miptex.width > 64 || miptex.height > 64 ? 1 : 0; |
||||
|
|
||||
|
if (strcmp(miptex.name, "clip") && strcmp(miptex.name, "trigger")) |
||||
|
rectangles.emplace_back(rectpack2D::rect_xywh(0, 0, miptex.width >> ps1mip, miptex.height >> ps1mip)); |
||||
|
else |
||||
|
rectangles.emplace_back(rectpack2D::rect_xywh(0, 0, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
// Automatic atlas packing. Nice but it tries to make a square atlas which is not what we want. (This is solved by hacking the header itself)
|
||||
|
const auto result_size = rectpack2D::find_best_packing<spaces_type>( |
||||
|
rectangles, |
||||
|
rectpack2D::make_finder_input( |
||||
|
max_side, |
||||
|
discard_step, |
||||
|
report_successful, |
||||
|
report_unsuccessful, |
||||
|
rectpack2D::flipping_option::DISABLED |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
printf("%d textures. Packed texture atlas size: %d x %d\n", mipheader.numtex, result_size.w, result_size.h); |
||||
|
unsigned char* atlas = (unsigned char*)malloc(result_size.w * result_size.h * sizeof(unsigned char)); |
||||
|
memset(atlas, 0, result_size.w * result_size.h * sizeof(unsigned char)); |
||||
|
|
||||
|
// Try to construct the texture atlas, see what we get
|
||||
|
for (int texNum = 0; texNum < mipheader.numtex; ++texNum) |
||||
|
{ |
||||
|
unsigned long miptexOffset = header.miptex.offset + mipheader.offset[texNum]; |
||||
|
fseek(f, miptexOffset, SEEK_SET); |
||||
|
fread(&miptex, sizeof(miptex_t), 1, f); |
||||
|
|
||||
|
char* outName = miptex.name; |
||||
|
if (*outName == '*' || *outName == '+') |
||||
|
outName++; |
||||
|
|
||||
|
for (int mipLevel = 0; mipLevel < 4; ++mipLevel) |
||||
|
{ |
||||
|
unsigned long mipOffset = *(&miptex.offset1 + mipLevel); |
||||
|
fseek(f, miptexOffset + mipOffset, SEEK_SET); |
||||
|
|
||||
|
size_t numBytes = (miptex.width * miptex.height) >> mipLevel; |
||||
|
unsigned char* texBytes = (unsigned char*)malloc(sizeof(unsigned char) * numBytes); |
||||
|
fread(texBytes, sizeof(unsigned char), numBytes, f); |
||||
|
|
||||
|
FILE* fout; |
||||
|
sprintf_s(path, _MAX_PATH, "textures/%s-mip%d-%dx%d.raw", outName, mipLevel, miptex.width >> mipLevel, miptex.height >> mipLevel); |
||||
|
fopen_s(&fout, path, "wb"); |
||||
|
fwrite(texBytes, sizeof(unsigned char), numBytes, fout); |
||||
|
fclose(fout); |
||||
|
|
||||
|
const auto& rectangle = rectangles[texNum]; |
||||
|
if (miptex.width >> mipLevel == rectangle.w) // This is the mip level we've previously decided we want for our PS1 atlas
|
||||
|
{ |
||||
|
//printf("Writing texture %s mip %d to position: (%d, %d) w = %d, h = %d\n", miptex.name, mipLevel, rectangle.x, rectangle.y, rectangle.w, rectangle.h);
|
||||
|
for (int y = 0; y < rectangle.h; ++y) |
||||
|
{ |
||||
|
memcpy_s(atlas + ((rectangle.y + y) * result_size.w + rectangle.x), rectangle.w * sizeof(unsigned char), texBytes + (y * rectangle.w), rectangle.w * sizeof(unsigned char)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free(texBytes); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
FILE* fatlas; |
||||
|
sprintf_s(path, _MAX_PATH, "atlas-%dx%d.raw", result_size.w, result_size.h); |
||||
|
fopen_s(&fatlas, path, "wb"); |
||||
|
fwrite(atlas, sizeof(unsigned char), result_size.w * result_size.h, fatlas); |
||||
|
fclose(fatlas); |
||||
|
|
||||
|
free(atlas); |
||||
|
free(mipheader.offset); |
||||
|
|
||||
|
// Inspect vertex data
|
||||
|
int numVertices = header.vertices.size / sizeof(vertex_t); |
||||
|
int numFaces = header.faces.size / sizeof(face_t); |
||||
|
fseek(f, header.vertices.offset, SEEK_SET); |
||||
|
vertex_t* vertices = (vertex_t*)malloc(header.vertices.size); |
||||
|
fread(vertices, sizeof(vertex_t), numVertices, f); |
||||
|
|
||||
|
vec3_t min = { FLT_MAX, FLT_MAX, FLT_MAX }, max = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; |
||||
|
for (int vertIdx = 0; vertIdx < numVertices; ++vertIdx) |
||||
|
{ |
||||
|
vertex_t* vert = &vertices[vertIdx]; |
||||
|
if (vert->X > max.x) max.x = vert->X; |
||||
|
if (vert->Y > max.y) max.y = vert->Y; |
||||
|
if (vert->Z > max.z) max.z = vert->Z; |
||||
|
if (vert->X < min.x) min.x = vert->X; |
||||
|
if (vert->Y < min.y) min.y = vert->Y; |
||||
|
if (vert->Z < min.z) min.z = vert->Z; |
||||
|
} |
||||
|
|
||||
|
printf("%d vertices, %d faces, min = (%f, %f, %f), max = (%f, %f, %f)\n", numVertices, numFaces, min.x, min.y, min.z, max.x, max.y, max.z); |
||||
|
|
||||
|
const int fixedScale = 1 << 14; |
||||
|
int fixedMin[3] = { (int)(min.x * fixedScale), (int)(min.y * fixedScale), (int)(min.z * fixedScale) }; |
||||
|
int fixedMax[3] = { (int)(max.x * fixedScale), (int)(max.y * fixedScale), (int)(max.z * fixedScale) }; |
||||
|
printf("Fixed point min = (%d, %d, %d), max = (%d, %d, %d)\n", fixedMin[0], fixedMin[1], fixedMin[2], fixedMax[0], fixedMax[1], fixedMax[2]); |
||||
|
|
||||
|
fclose(f); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
#ifndef __PS1BSP_H__ |
||||
|
#define __PS1BSP_H__ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned char w, h; // These may be necessary for scaling UVs, especially since we use a mix of mip0 and mip1 textures |
||||
|
int tpage; // Texture page in PS1 VRAM (precalculated when generating the texture atlas) |
||||
|
short uoffs, voffs; // Texture coordinate offset within the texture page |
||||
|
unsigned short nextframe; // If non-zero, the texture is animated and this points to the next texture in the sequence |
||||
|
} ps1bsp_texture_t; |
||||
|
|
||||
|
// This matches the SVECTOR data type, using the extra padding to store vertex color data. |
||||
|
// The full range and precision required cannot be stored in just shorts, so we make use of a floating origin stored in the BSP leafs. |
||||
|
// With this the higher-order bits of each vertex position are calculated into the model-view matrix, giving good precision for polygons near the camera. |
||||
|
typedef struct |
||||
|
{ |
||||
|
short x; |
||||
|
short y; |
||||
|
short z; |
||||
|
unsigned char baseLight, finalLight; // Used for gouraud shading based on static lightmap data |
||||
|
} ps1bsp_vertex_t; |
||||
|
|
||||
|
// Instead of edges as in the original BSP format, we store triangles for easy consumption by the PS1 |
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned short vertex0; |
||||
|
unsigned short vertex1; |
||||
|
unsigned short vertex2; |
||||
|
} ps1bsp_triangle_t; |
||||
|
|
||||
|
// Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) |
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned short classtype; // Hash of the original classname |
||||
|
short angle[3]; // Can store both mangle (all axes) and just angle (Z-axis rotation only) |
||||
|
int origin[3]; // In 12-bit fixed point coordinates |
||||
|
unsigned int spawnflags; |
||||
|
unsigned short message_id; // Index into a pool of pre-defined messages |
||||
|
} ps1bsp_entity_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
unsigned char length; |
||||
|
char message[]; |
||||
|
} ps1bsp_message_t; |
||||
|
|
||||
|
typedef struct |
||||
|
{ |
||||
|
// TODO: add floating origin position, so face vertices can be moved relative to the camera position |
||||
|
} ps1bsp_leaf_t; |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif // __PS1BSP_H__ |
||||
@ -0,0 +1,286 @@ |
|||||
|
#pragma once |
||||
|
#include <variant> |
||||
|
#include <cassert> |
||||
|
#include "rect_structs.h" |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
enum class callback_result { |
||||
|
ABORT_PACKING, |
||||
|
CONTINUE_PACKING |
||||
|
}; |
||||
|
|
||||
|
template <class T> |
||||
|
auto& dereference(T& r) { |
||||
|
/* |
||||
|
This will allow us to pass orderings that consist of pointers, |
||||
|
as well as ones that are just plain objects in a vector. |
||||
|
*/ |
||||
|
|
||||
|
if constexpr(std::is_pointer_v<T>) { |
||||
|
return *r; |
||||
|
} |
||||
|
else { |
||||
|
return r; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
This function will do a binary search on viable bin sizes, |
||||
|
starting from the biggest one: starting_bin. |
||||
|
|
||||
|
The search stops when the bin was successfully inserted into, |
||||
|
AND the bin size to be tried next differs in size from the last viable one by *less* then discard_step. |
||||
|
|
||||
|
If we could not insert all input rectangles into a bin even as big as the starting_bin - the search fails. |
||||
|
In this case, we return the amount of space (total_area_type) inserted in total. |
||||
|
|
||||
|
If we've found a viable bin that is smaller or equal to starting_bin, the search succeeds. |
||||
|
In this case, we return the viable bin (rect_wh). |
||||
|
*/ |
||||
|
|
||||
|
enum class bin_dimension { |
||||
|
BOTH, |
||||
|
WIDTH, |
||||
|
HEIGHT |
||||
|
}; |
||||
|
|
||||
|
template <class empty_spaces_type, class O> |
||||
|
std::variant<total_area_type, rect_wh> best_packing_for_ordering_impl( |
||||
|
empty_spaces_type& root, |
||||
|
O ordering, |
||||
|
const rect_wh starting_bin, |
||||
|
int discard_step, |
||||
|
const bin_dimension tried_dimension |
||||
|
) { |
||||
|
auto candidate_bin = starting_bin; |
||||
|
int tries_before_discarding = 0; |
||||
|
|
||||
|
if (discard_step <= 0) |
||||
|
{ |
||||
|
tries_before_discarding = -discard_step; |
||||
|
discard_step = 1; |
||||
|
} |
||||
|
|
||||
|
//std::cout << "best_packing_for_ordering_impl dim: " << int(tried_dimension) << " w: " << starting_bin.w << " h: " << starting_bin.h << std::endl; |
||||
|
|
||||
|
int starting_step = 0; |
||||
|
|
||||
|
if (tried_dimension == bin_dimension::BOTH) { |
||||
|
candidate_bin.w /= 2; |
||||
|
candidate_bin.h /= 2; |
||||
|
|
||||
|
starting_step = candidate_bin.w / 2; |
||||
|
} |
||||
|
else if (tried_dimension == bin_dimension::WIDTH) { |
||||
|
candidate_bin.w /= 2; |
||||
|
starting_step = candidate_bin.w / 2; |
||||
|
} |
||||
|
else { |
||||
|
candidate_bin.h /= 2; |
||||
|
starting_step = candidate_bin.h / 2; |
||||
|
} |
||||
|
|
||||
|
for (int step = starting_step; ; step = std::max(1, step / 2)) { |
||||
|
//std::cout << "candidate: " << candidate_bin.w << "x" << candidate_bin.h << std::endl; |
||||
|
|
||||
|
root.reset(candidate_bin); |
||||
|
|
||||
|
int total_inserted_area = 0; |
||||
|
|
||||
|
const bool all_inserted = [&]() { |
||||
|
for (const auto& r : ordering) { |
||||
|
const auto& rect = dereference(r); |
||||
|
|
||||
|
if (root.insert(rect.get_wh())) { |
||||
|
total_inserted_area += rect.area(); |
||||
|
} |
||||
|
else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
}(); |
||||
|
|
||||
|
if (all_inserted) { |
||||
|
/* Attempt was successful. Try with a smaller bin. */ |
||||
|
|
||||
|
if (step <= discard_step) { |
||||
|
if (tries_before_discarding > 0) |
||||
|
{ |
||||
|
tries_before_discarding--; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return candidate_bin; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (tried_dimension == bin_dimension::BOTH) { |
||||
|
candidate_bin.w -= step; |
||||
|
candidate_bin.h -= step; |
||||
|
} |
||||
|
else if (tried_dimension == bin_dimension::WIDTH) { |
||||
|
candidate_bin.w -= step; |
||||
|
} |
||||
|
else { |
||||
|
candidate_bin.h -= step; |
||||
|
} |
||||
|
|
||||
|
root.reset(candidate_bin); |
||||
|
} |
||||
|
else { |
||||
|
/* Attempt ended with failure. Try with a bigger bin. */ |
||||
|
|
||||
|
if (tried_dimension == bin_dimension::BOTH) { |
||||
|
candidate_bin.w += step; |
||||
|
candidate_bin.h += step; |
||||
|
|
||||
|
if (candidate_bin.area() > starting_bin.area()) { |
||||
|
return total_inserted_area; |
||||
|
} |
||||
|
} |
||||
|
else if (tried_dimension == bin_dimension::WIDTH) { |
||||
|
candidate_bin.w += step; |
||||
|
|
||||
|
if (candidate_bin.w > starting_bin.w) { |
||||
|
return total_inserted_area; |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
candidate_bin.h += step; |
||||
|
|
||||
|
if (candidate_bin.h > starting_bin.h) { |
||||
|
return total_inserted_area; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template <class empty_spaces_type, class O> |
||||
|
std::variant<total_area_type, rect_wh> best_packing_for_ordering( |
||||
|
empty_spaces_type& root, |
||||
|
O&& ordering, |
||||
|
const rect_wh starting_bin, |
||||
|
const int discard_step |
||||
|
) { |
||||
|
const auto try_pack = [&]( |
||||
|
const bin_dimension tried_dimension, |
||||
|
const rect_wh starting_bin |
||||
|
) { |
||||
|
return best_packing_for_ordering_impl( |
||||
|
root, |
||||
|
std::forward<O>(ordering), |
||||
|
starting_bin, |
||||
|
discard_step, |
||||
|
tried_dimension |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
const auto best_result = try_pack(bin_dimension::BOTH, starting_bin); |
||||
|
|
||||
|
if (const auto failed = std::get_if<total_area_type>(&best_result)) { |
||||
|
return *failed; |
||||
|
} |
||||
|
|
||||
|
auto best_bin = std::get<rect_wh>(best_result); |
||||
|
|
||||
|
auto trial = [&](const bin_dimension tried_dimension) { |
||||
|
const auto trial = try_pack(tried_dimension, best_bin); |
||||
|
|
||||
|
if (const auto better = std::get_if<rect_wh>(&trial)) { |
||||
|
best_bin = *better; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
trial(bin_dimension::WIDTH); |
||||
|
trial(bin_dimension::HEIGHT); |
||||
|
|
||||
|
return best_bin; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
This function will try to find the best bin size among the ones generated by all provided rectangle orders. |
||||
|
Only the best order will have results written to. |
||||
|
|
||||
|
The function reports which of the rectangles did and did not fit in the end. |
||||
|
*/ |
||||
|
|
||||
|
template < |
||||
|
class empty_spaces_type, |
||||
|
class OrderType, |
||||
|
class F, |
||||
|
class I |
||||
|
> |
||||
|
rect_wh find_best_packing_impl(F for_each_order, const I input) { |
||||
|
const auto max_bin = rect_wh(input.max_bin_side << 1, input.max_bin_side >> 1); // PS1BSP: only way I've been able to make non-square output work ¯\_(ツ)_/¯ |
||||
|
|
||||
|
OrderType* best_order = nullptr; |
||||
|
|
||||
|
int best_total_inserted = -1; |
||||
|
auto best_bin = max_bin; |
||||
|
|
||||
|
/* |
||||
|
The root node is re-used on the TLS. |
||||
|
It is always reset before any packing attempt. |
||||
|
*/ |
||||
|
|
||||
|
thread_local empty_spaces_type root = rect_wh(); |
||||
|
root.flipping_mode = input.flipping_mode; |
||||
|
|
||||
|
for_each_order ([&](OrderType& current_order) { |
||||
|
const auto packing = best_packing_for_ordering( |
||||
|
root, |
||||
|
current_order, |
||||
|
max_bin, |
||||
|
input.discard_step |
||||
|
); |
||||
|
|
||||
|
if (const auto total_inserted = std::get_if<total_area_type>(&packing)) { |
||||
|
/* |
||||
|
Track which function inserts the most area in total, |
||||
|
just in case that all orders will fail to fit into the largest allowed bin. |
||||
|
*/ |
||||
|
if (best_order == nullptr) { |
||||
|
if (*total_inserted > best_total_inserted) { |
||||
|
best_order = std::addressof(current_order); |
||||
|
best_total_inserted = *total_inserted; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else if (const auto result_bin = std::get_if<rect_wh>(&packing)) { |
||||
|
/* Save the function if it performed the best. */ |
||||
|
if (result_bin->area() <= best_bin.area()) { |
||||
|
best_order = std::addressof(current_order); |
||||
|
best_bin = *result_bin; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
{ |
||||
|
assert(best_order != nullptr); |
||||
|
|
||||
|
root.reset(best_bin); |
||||
|
|
||||
|
for (auto& rr : *best_order) { |
||||
|
auto& rect = dereference(rr); |
||||
|
|
||||
|
if (const auto ret = root.insert(rect.get_wh())) { |
||||
|
rect = *ret; |
||||
|
|
||||
|
if (callback_result::ABORT_PACKING == input.handle_successful_insertion(rect)) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
if (callback_result::ABORT_PACKING == input.handle_unsuccessful_insertion(rect)) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return root.get_rects_aabb(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
#pragma once |
||||
|
#include <array> |
||||
|
#include <vector> |
||||
|
#include <type_traits> |
||||
|
|
||||
|
#include "rect_structs.h" |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
class default_empty_spaces { |
||||
|
std::vector<space_rect> empty_spaces; |
||||
|
|
||||
|
public: |
||||
|
void remove(const int i) { |
||||
|
empty_spaces[i] = empty_spaces.back(); |
||||
|
empty_spaces.pop_back(); |
||||
|
} |
||||
|
|
||||
|
bool add(const space_rect r) { |
||||
|
empty_spaces.emplace_back(r); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
auto get_count() const { |
||||
|
return empty_spaces.size(); |
||||
|
} |
||||
|
|
||||
|
void reset() { |
||||
|
empty_spaces.clear(); |
||||
|
} |
||||
|
|
||||
|
const auto& get(const int i) { |
||||
|
return empty_spaces[i]; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
template <int MAX_SPACES> |
||||
|
class static_empty_spaces { |
||||
|
int count_spaces = 0; |
||||
|
std::array<space_rect, MAX_SPACES> empty_spaces; |
||||
|
|
||||
|
public: |
||||
|
void remove(const int i) { |
||||
|
empty_spaces[i] = empty_spaces[count_spaces - 1]; |
||||
|
--count_spaces; |
||||
|
} |
||||
|
|
||||
|
bool add(const space_rect r) { |
||||
|
if (count_spaces < static_cast<int>(empty_spaces.size())) { |
||||
|
empty_spaces[count_spaces] = r; |
||||
|
++count_spaces; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
auto get_count() const { |
||||
|
return count_spaces; |
||||
|
} |
||||
|
|
||||
|
void reset() { |
||||
|
count_spaces = 0; |
||||
|
} |
||||
|
|
||||
|
const auto& get(const int i) { |
||||
|
return empty_spaces[i]; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,149 @@ |
|||||
|
#pragma once |
||||
|
#include "insert_and_split.h" |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
enum class flipping_option { |
||||
|
DISABLED, |
||||
|
ENABLED |
||||
|
}; |
||||
|
|
||||
|
class default_empty_spaces; |
||||
|
|
||||
|
template <bool allow_flip, class empty_spaces_provider = default_empty_spaces> |
||||
|
class empty_spaces { |
||||
|
rect_wh current_aabb; |
||||
|
empty_spaces_provider spaces; |
||||
|
|
||||
|
/* MSVC fix for non-conformant if constexpr implementation */ |
||||
|
|
||||
|
static auto make_output_rect(const int x, const int y, const int w, const int h) { |
||||
|
return rect_xywh(x, y, w, h); |
||||
|
} |
||||
|
|
||||
|
static auto make_output_rect(const int x, const int y, const int w, const int h, const bool flipped) { |
||||
|
return rect_xywhf(x, y, w, h, flipped); |
||||
|
} |
||||
|
|
||||
|
public: |
||||
|
using output_rect_type = std::conditional_t<allow_flip, rect_xywhf, rect_xywh>; |
||||
|
|
||||
|
flipping_option flipping_mode = flipping_option::ENABLED; |
||||
|
|
||||
|
empty_spaces(const rect_wh& r) { |
||||
|
reset(r); |
||||
|
} |
||||
|
|
||||
|
void reset(const rect_wh& r) { |
||||
|
current_aabb = {}; |
||||
|
|
||||
|
spaces.reset(); |
||||
|
spaces.add(rect_xywh(0, 0, r.w, r.h)); |
||||
|
} |
||||
|
|
||||
|
template <class F> |
||||
|
std::optional<output_rect_type> insert(const rect_wh image_rectangle, F report_candidate_empty_space) { |
||||
|
for (int i = static_cast<int>(spaces.get_count()) - 1; i >= 0; --i) { |
||||
|
const auto candidate_space = spaces.get(i); |
||||
|
|
||||
|
report_candidate_empty_space(candidate_space); |
||||
|
|
||||
|
auto accept_result = [this, i, image_rectangle, candidate_space]( |
||||
|
const created_splits& splits, |
||||
|
const bool flipping_necessary |
||||
|
) -> std::optional<output_rect_type> { |
||||
|
spaces.remove(i); |
||||
|
|
||||
|
for (int s = 0; s < splits.count; ++s) { |
||||
|
if (!spaces.add(splits.spaces[s])) { |
||||
|
return std::nullopt; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if constexpr(allow_flip) { |
||||
|
const auto result = make_output_rect( |
||||
|
candidate_space.x, |
||||
|
candidate_space.y, |
||||
|
image_rectangle.w, |
||||
|
image_rectangle.h, |
||||
|
flipping_necessary |
||||
|
); |
||||
|
|
||||
|
current_aabb.expand_with(result); |
||||
|
return result; |
||||
|
} |
||||
|
else if constexpr(!allow_flip) { |
||||
|
(void)flipping_necessary; |
||||
|
|
||||
|
const auto result = make_output_rect( |
||||
|
candidate_space.x, |
||||
|
candidate_space.y, |
||||
|
image_rectangle.w, |
||||
|
image_rectangle.h |
||||
|
); |
||||
|
|
||||
|
current_aabb.expand_with(result); |
||||
|
return result; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
auto try_to_insert = [&](const rect_wh& img) { |
||||
|
return rectpack2D::insert_and_split(img, candidate_space); |
||||
|
}; |
||||
|
|
||||
|
if constexpr(!allow_flip) { |
||||
|
if (const auto normal = try_to_insert(image_rectangle)) { |
||||
|
return accept_result(normal, false); |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
if (flipping_mode == flipping_option::ENABLED) { |
||||
|
const auto normal = try_to_insert(image_rectangle); |
||||
|
const auto flipped = try_to_insert(rect_wh(image_rectangle).flip()); |
||||
|
|
||||
|
/* |
||||
|
If both were successful, |
||||
|
prefer the one that generated less remainder spaces. |
||||
|
*/ |
||||
|
|
||||
|
if (normal && flipped) { |
||||
|
if (flipped.better_than(normal)) { |
||||
|
/* Accept the flipped result if it producues less or "better" spaces. */ |
||||
|
|
||||
|
return accept_result(flipped, true); |
||||
|
} |
||||
|
|
||||
|
return accept_result(normal, false); |
||||
|
} |
||||
|
|
||||
|
if (normal) { |
||||
|
return accept_result(normal, false); |
||||
|
} |
||||
|
|
||||
|
if (flipped) { |
||||
|
return accept_result(flipped, true); |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
if (const auto normal = try_to_insert(image_rectangle)) { |
||||
|
return accept_result(normal, false); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return std::nullopt; |
||||
|
} |
||||
|
|
||||
|
decltype(auto) insert(const rect_wh& image_rectangle) { |
||||
|
return insert(image_rectangle, [](auto&){ }); |
||||
|
} |
||||
|
|
||||
|
auto get_rects_aabb() const { |
||||
|
return current_aabb; |
||||
|
} |
||||
|
|
||||
|
const auto& get_spaces() const { |
||||
|
return spaces; |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,155 @@ |
|||||
|
#pragma once |
||||
|
#include <optional> |
||||
|
#include <vector> |
||||
|
#include <array> |
||||
|
#include <variant> |
||||
|
#include <algorithm> |
||||
|
|
||||
|
#include "insert_and_split.h" |
||||
|
#include "empty_spaces.h" |
||||
|
#include "empty_space_allocators.h" |
||||
|
|
||||
|
#include "best_bin_finder.h" |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
template <class empty_spaces_type> |
||||
|
using output_rect_t = typename empty_spaces_type::output_rect_type; |
||||
|
|
||||
|
template <class F, class G> |
||||
|
struct finder_input { |
||||
|
const int max_bin_side; |
||||
|
const int discard_step; |
||||
|
F handle_successful_insertion; |
||||
|
G handle_unsuccessful_insertion; |
||||
|
const flipping_option flipping_mode; |
||||
|
}; |
||||
|
|
||||
|
template <class F, class G> |
||||
|
auto make_finder_input( |
||||
|
const int max_bin_side, |
||||
|
const int discard_step, |
||||
|
F&& handle_successful_insertion, |
||||
|
G&& handle_unsuccessful_insertion, |
||||
|
const flipping_option flipping_mode |
||||
|
) { |
||||
|
return finder_input<F, G> { |
||||
|
max_bin_side, |
||||
|
discard_step, |
||||
|
std::forward<F>(handle_successful_insertion), |
||||
|
std::forward<G>(handle_unsuccessful_insertion), |
||||
|
flipping_mode |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
/* |
||||
|
Finds the best packing for the rectangles, |
||||
|
just in the order that they were passed. |
||||
|
*/ |
||||
|
|
||||
|
template <class empty_spaces_type, class F, class G> |
||||
|
rect_wh find_best_packing_dont_sort( |
||||
|
std::vector<output_rect_t<empty_spaces_type>>& subjects, |
||||
|
const finder_input<F, G>& input |
||||
|
) { |
||||
|
using order_type = std::remove_reference_t<decltype(subjects)>; |
||||
|
|
||||
|
return find_best_packing_impl<empty_spaces_type, order_type>( |
||||
|
[&subjects](auto callback) { callback(subjects); }, |
||||
|
input |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
Finds the best packing for the rectangles. |
||||
|
Accepts a list of predicates able to compare two input rectangles. |
||||
|
|
||||
|
The function will try to pack the rectangles in all orders generated by the predicates, |
||||
|
and will only write the x, y coordinates of the best packing found among the orders. |
||||
|
*/ |
||||
|
|
||||
|
template <class empty_spaces_type, class F, class G, class Comparator, class... Comparators> |
||||
|
rect_wh find_best_packing( |
||||
|
std::vector<output_rect_t<empty_spaces_type>>& subjects, |
||||
|
const finder_input<F, G>& input, |
||||
|
|
||||
|
Comparator comparator, |
||||
|
Comparators... comparators |
||||
|
) { |
||||
|
using rect_type = output_rect_t<empty_spaces_type>; |
||||
|
using order_type = std::vector<rect_type*>; |
||||
|
|
||||
|
constexpr auto count_orders = 1 + sizeof...(Comparators); |
||||
|
thread_local std::array<order_type, count_orders> orders; |
||||
|
|
||||
|
{ |
||||
|
/* order[0] will always exist since this overload requires at least one comparator */ |
||||
|
auto& initial_pointers = orders[0]; |
||||
|
initial_pointers.clear(); |
||||
|
|
||||
|
for (auto& s : subjects) { |
||||
|
if (s.area() > 0) { |
||||
|
initial_pointers.emplace_back(std::addressof(s)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (std::size_t i = 1; i < count_orders; ++i) { |
||||
|
orders[i] = initial_pointers; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::size_t f = 0; |
||||
|
|
||||
|
auto& orders_ref = orders; |
||||
|
|
||||
|
auto make_order = [&f, &orders_ref](auto& predicate) { |
||||
|
std::sort(orders_ref[f].begin(), orders_ref[f].end(), predicate); |
||||
|
++f; |
||||
|
}; |
||||
|
|
||||
|
make_order(comparator); |
||||
|
(make_order(comparators), ...); |
||||
|
|
||||
|
return find_best_packing_impl<empty_spaces_type, order_type>( |
||||
|
[&orders_ref](auto callback){ for (auto& o : orders_ref) { callback(o); } }, |
||||
|
input |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
Finds the best packing for the rectangles. |
||||
|
Provides a list of several sensible comparison predicates. |
||||
|
*/ |
||||
|
|
||||
|
template <class empty_spaces_type, class F, class G> |
||||
|
rect_wh find_best_packing( |
||||
|
std::vector<output_rect_t<empty_spaces_type>>& subjects, |
||||
|
const finder_input<F, G>& input |
||||
|
) { |
||||
|
using rect_type = output_rect_t<empty_spaces_type>; |
||||
|
|
||||
|
return find_best_packing<empty_spaces_type>( |
||||
|
subjects, |
||||
|
input, |
||||
|
|
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return a->area() > b->area(); |
||||
|
}, |
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return a->perimeter() > b->perimeter(); |
||||
|
}, |
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return std::max(a->w, a->h) > std::max(b->w, b->h); |
||||
|
}, |
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return a->w > b->w; |
||||
|
}, |
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return a->h > b->h; |
||||
|
}, |
||||
|
[](const rect_type* const a, const rect_type* const b) { |
||||
|
return a->get_wh().pathological_mult() > b->get_wh().pathological_mult(); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,135 @@ |
|||||
|
#pragma once |
||||
|
#include <array> |
||||
|
#include "rect_structs.h" |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
struct created_splits { |
||||
|
int count = 0; |
||||
|
std::array<space_rect, 2> spaces; |
||||
|
|
||||
|
static auto failed() { |
||||
|
created_splits result; |
||||
|
result.count = -1; |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
static auto none() { |
||||
|
return created_splits(); |
||||
|
} |
||||
|
|
||||
|
template <class... Args> |
||||
|
created_splits(Args&&... args) : spaces({ std::forward<Args>(args)... }) { |
||||
|
count = sizeof...(Args); |
||||
|
} |
||||
|
|
||||
|
bool better_than(const created_splits& b) const { |
||||
|
return count < b.count; |
||||
|
} |
||||
|
|
||||
|
explicit operator bool() const { |
||||
|
return count != -1; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
inline created_splits insert_and_split( |
||||
|
const rect_wh& im, /* Image rectangle */ |
||||
|
const space_rect& sp /* Space rectangle */ |
||||
|
) { |
||||
|
const auto free_w = sp.w - im.w; |
||||
|
const auto free_h = sp.h - im.h; |
||||
|
|
||||
|
if (free_w < 0 || free_h < 0) { |
||||
|
/* |
||||
|
Image is bigger than the candidate empty space. |
||||
|
We'll need to look further. |
||||
|
*/ |
||||
|
|
||||
|
return created_splits::failed(); |
||||
|
} |
||||
|
|
||||
|
if (free_w == 0 && free_h == 0) { |
||||
|
/* |
||||
|
If the image dimensions equal the dimensions of the candidate empty space (image fits exactly), |
||||
|
we will just delete the space and create no splits. |
||||
|
*/ |
||||
|
|
||||
|
return created_splits::none(); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
If the image fits into the candidate empty space, |
||||
|
but exactly one of the image dimensions equals the respective dimension of the candidate empty space |
||||
|
(e.g. image = 20x40, candidate space = 30x40) |
||||
|
we delete the space and create a single split. In this case a 10x40 space. |
||||
|
*/ |
||||
|
|
||||
|
if (free_w > 0 && free_h == 0) { |
||||
|
auto r = sp; |
||||
|
r.x += im.w; |
||||
|
r.w -= im.w; |
||||
|
return created_splits(r); |
||||
|
} |
||||
|
|
||||
|
if (free_w == 0 && free_h > 0) { |
||||
|
auto r = sp; |
||||
|
r.y += im.h; |
||||
|
r.h -= im.h; |
||||
|
return created_splits(r); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
Every other option has been exhausted, |
||||
|
so at this point the image must be *strictly* smaller than the empty space, |
||||
|
that is, it is smaller in both width and height. |
||||
|
|
||||
|
Thus, free_w and free_h must be positive. |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
Decide which way to split. |
||||
|
|
||||
|
Instead of having two normally-sized spaces, |
||||
|
it is better - though I have no proof of that - to have a one tiny space and a one huge space. |
||||
|
This creates better opportunity for insertion of future rectangles. |
||||
|
|
||||
|
This is why, if we had more of width remaining than we had of height, |
||||
|
we split along the vertical axis, |
||||
|
and if we had more of height remaining than we had of width, |
||||
|
we split along the horizontal axis. |
||||
|
*/ |
||||
|
|
||||
|
if (free_w > free_h) { |
||||
|
const auto bigger_split = space_rect( |
||||
|
sp.x + im.w, |
||||
|
sp.y, |
||||
|
free_w, |
||||
|
sp.h |
||||
|
); |
||||
|
|
||||
|
const auto lesser_split = space_rect( |
||||
|
sp.x, |
||||
|
sp.y + im.h, |
||||
|
im.w, |
||||
|
free_h |
||||
|
); |
||||
|
|
||||
|
return created_splits(bigger_split, lesser_split); |
||||
|
} |
||||
|
|
||||
|
const auto bigger_split = space_rect( |
||||
|
sp.x, |
||||
|
sp.y + im.h, |
||||
|
sp.w, |
||||
|
free_h |
||||
|
); |
||||
|
|
||||
|
const auto lesser_split = space_rect( |
||||
|
sp.x + im.w, |
||||
|
sp.y, |
||||
|
free_w, |
||||
|
im.h |
||||
|
); |
||||
|
|
||||
|
return created_splits(bigger_split, lesser_split); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
#pragma once |
||||
|
#include <utility> |
||||
|
|
||||
|
namespace rectpack2D { |
||||
|
using total_area_type = int; |
||||
|
|
||||
|
struct rect_wh { |
||||
|
rect_wh() : w(0), h(0) {} |
||||
|
rect_wh(const int w, const int h) : w(w), h(h) {} |
||||
|
|
||||
|
int w; |
||||
|
int h; |
||||
|
|
||||
|
auto& flip() { |
||||
|
std::swap(w, h); |
||||
|
return *this; |
||||
|
} |
||||
|
|
||||
|
int max_side() const { |
||||
|
return h > w ? h : w; |
||||
|
} |
||||
|
|
||||
|
int min_side() const { |
||||
|
return h < w ? h : w; |
||||
|
} |
||||
|
|
||||
|
int area() const { return w * h; } |
||||
|
int perimeter() const { return 2 * w + 2 * h; } |
||||
|
|
||||
|
float pathological_mult() const { |
||||
|
return float(max_side()) / min_side() * area(); |
||||
|
} |
||||
|
|
||||
|
template <class R> |
||||
|
void expand_with(const R& r) { |
||||
|
w = std::max(w, r.x + r.w); |
||||
|
h = std::max(h, r.y + r.h); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
struct rect_xywh { |
||||
|
int x; |
||||
|
int y; |
||||
|
int w; |
||||
|
int h; |
||||
|
|
||||
|
rect_xywh() : x(0), y(0), w(0), h(0) {} |
||||
|
rect_xywh(const int x, const int y, const int w, const int h) : x(x), y(y), w(w), h(h) {} |
||||
|
|
||||
|
int area() const { return w * h; } |
||||
|
int perimeter() const { return 2 * w + 2 * h; } |
||||
|
|
||||
|
auto get_wh() const { |
||||
|
return rect_wh(w, h); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
struct rect_xywhf { |
||||
|
int x; |
||||
|
int y; |
||||
|
int w; |
||||
|
int h; |
||||
|
bool flipped; |
||||
|
|
||||
|
rect_xywhf() : x(0), y(0), w(0), h(0), flipped(false) {} |
||||
|
rect_xywhf(const int x, const int y, const int w, const int h, const bool flipped) : x(x), y(y), w(flipped ? h : w), h(flipped ? w : h), flipped(flipped) {} |
||||
|
rect_xywhf(const rect_xywh& b) : rect_xywhf(b.x, b.y, b.w, b.h, false) {} |
||||
|
|
||||
|
int area() const { return w * h; } |
||||
|
int perimeter() const { return 2 * w + 2 * h; } |
||||
|
|
||||
|
auto get_wh() const { |
||||
|
return rect_wh(w, h); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
using space_rect = rect_xywh; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue