diff options
| author | Marco Foco <[email protected]> | 2016-03-07 15:47:07 +0100 |
|---|---|---|
| committer | Marco Foco <[email protected]> | 2016-03-08 16:04:19 +0100 |
| commit | cd6e0492903f8a9eb5efa14263d7d9ab092517de (patch) | |
| tree | 05c010b75bf777335565819dcceb140886c5a7e9 /src | |
| download | faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.tar.xz faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.zip | |
FaceWorks 1.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/build/vs2013/GFSDK_FaceWorks.vcxproj | 263 | ||||
| -rw-r--r-- | src/build/vs2013/GFSDK_FaceWorks.vcxproj.filters | 38 | ||||
| -rw-r--r-- | src/build/vs2015/GFSDK_FaceWorks.vcxproj | 263 | ||||
| -rw-r--r-- | src/build/vs2015/GFSDK_FaceWorks.vcxproj.filters | 38 | ||||
| -rw-r--r-- | src/internal.h | 158 | ||||
| -rw-r--r-- | src/precomp.cpp | 843 | ||||
| -rw-r--r-- | src/runtime.cpp | 275 |
7 files changed, 1878 insertions, 0 deletions
diff --git a/src/build/vs2013/GFSDK_FaceWorks.vcxproj b/src/build/vs2013/GFSDK_FaceWorks.vcxproj new file mode 100644 index 0000000..c8cba1a --- /dev/null +++ b/src/build/vs2013/GFSDK_FaceWorks.vcxproj @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.h" /> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.hlsli" /> + <ClInclude Include="..\..\internal.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\precomp.cpp" /> + <ClCompile Include="..\..\runtime.cpp" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>GFSDK_FaceWorks</ProjectName> + <ProjectGuid>{AC51FED5-AB74-4885-9873-D305444BA6D0}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>GFSDK_FaceWorks</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <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 Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <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> + <OutDir>..\..\..\redist\win32\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win32.debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>..\..\..\redist\win64\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win64.debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\redist\win32\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win32</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\redist\win64\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win64</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win32\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Gfp</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win64\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Gfp</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win32\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Qstrip_reflect /Qstrip_debug /Qstrip_priv</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win64\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Qstrip_reflect /Qstrip_debug /Qstrip_priv</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/src/build/vs2013/GFSDK_FaceWorks.vcxproj.filters b/src/build/vs2013/GFSDK_FaceWorks.vcxproj.filters new file mode 100644 index 0000000..9226a04 --- /dev/null +++ b/src/build/vs2013/GFSDK_FaceWorks.vcxproj.filters @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.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;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Public Header Files"> + <UniqueIdentifier>{22e8a8c8-36c0-4d86-8470-487ccd6ad977}</UniqueIdentifier> + </Filter> + <Filter Include="Internal Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Public Shader Files"> + <UniqueIdentifier>{d97213c0-0424-42de-82d4-873aaca1d0e0}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.h"> + <Filter>Public Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\internal.h"> + <Filter>Internal Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.hlsli"> + <Filter>Public Shader Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\precomp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\runtime.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/src/build/vs2015/GFSDK_FaceWorks.vcxproj b/src/build/vs2015/GFSDK_FaceWorks.vcxproj new file mode 100644 index 0000000..5247576 --- /dev/null +++ b/src/build/vs2015/GFSDK_FaceWorks.vcxproj @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.h" /> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.hlsli" /> + <ClInclude Include="..\..\internal.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\precomp.cpp" /> + <ClCompile Include="..\..\runtime.cpp" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>GFSDK_FaceWorks</ProjectName> + <ProjectGuid>{AC51FED5-AB74-4885-9873-D305444BA6D0}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>GFSDK_FaceWorks</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <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 Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <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> + <OutDir>..\..\..\redist\win32\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win32.debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>..\..\..\redist\win64\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win64.debug</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\redist\win32\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win32</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>..\..\..\redist\win64\</OutDir> + <IntDir>$(Platform)\$(Configuration)\</IntDir> + <TargetName>$(ProjectName).win64</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win32\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Gfp</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win64\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Gfp</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win32\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Qstrip_reflect /Qstrip_debug /Qstrip_priv</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;GFSDK_FACEWORKS_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalIncludeDirectories>..\..\..\include;generated\$(Platform)\$(Configuration)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <AdditionalOptions>/d2Zi+</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalDependencies>dxguid.lib;d3dcompiler.lib</AdditionalDependencies> + <ImportLibrary>..\..\..\lib\win64\$(TargetName).lib</ImportLibrary> + </Link> + <FxCompile> + <ShaderModel>5.0</ShaderModel> + </FxCompile> + <FxCompile> + <HeaderFileOutput>generated\$(Platform)\$(Configuration)\%(Filename).h</HeaderFileOutput> + <ObjectFileOutput /> + <VariableName>%(Filename)_bytecode</VariableName> + <TreatWarningAsError>true</TreatWarningAsError> + <AdditionalOptions>/Qstrip_reflect /Qstrip_debug /Qstrip_priv</AdditionalOptions> + </FxCompile> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <PostBuildEvent> + <Message> + </Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/src/build/vs2015/GFSDK_FaceWorks.vcxproj.filters b/src/build/vs2015/GFSDK_FaceWorks.vcxproj.filters new file mode 100644 index 0000000..63fe8fb --- /dev/null +++ b/src/build/vs2015/GFSDK_FaceWorks.vcxproj.filters @@ -0,0 +1,38 @@ +<?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;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Public Header Files"> + <UniqueIdentifier>{22e8a8c8-36c0-4d86-8470-487ccd6ad977}</UniqueIdentifier> + </Filter> + <Filter Include="Internal Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Public Shader Files"> + <UniqueIdentifier>{d97213c0-0424-42de-82d4-873aaca1d0e0}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.h"> + <Filter>Public Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\internal.h"> + <Filter>Internal Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\..\include\GFSDK_FaceWorks.hlsli"> + <Filter>Public Shader Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\precomp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\runtime.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/src/internal.h b/src/internal.h new file mode 100644 index 0000000..19dae37 --- /dev/null +++ b/src/internal.h @@ -0,0 +1,158 @@ +//---------------------------------------------------------------------------------- +// File: FaceWorks/src/internal.h +// SDK Version: v1.0 +// Email: [email protected] +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- + +#ifndef GFSDK_FACEWORKS_INTERNAL_H +#define GFSDK_FACEWORKS_INTERNAL_H + +#include <algorithm> +#include <cmath> +#include <cstdarg> +#include <memory> + +#include <GFSDK_FaceWorks.h> + +using std::min; +using std::max; + +// Get the dimension of a static array +template <typename T, int N> char (&dim_helper(T (&)[N]))[N]; +#define dim(x) (sizeof(dim_helper(x))) +#define dim_field(S, m) (dim(((S*)nullptr)->m)) + +// math fixup: log2 wasn't defined before VS2013 +#if defined(_MSC_VER) && (_MSC_VER < 1800) +inline float log2(float x) { return 1.442695041f * logf(x); } +#endif + + + +// Shared constant buffer data for SSS and deep scatter; +// matches nvsf_CBData in internal.hlsl +struct CBData +{ + // SSS constants + float m_curvatureScale, m_curvatureBias; + float m_shadowScale, m_shadowBias; + float m_minLevelForBlurredNormal; + + // Deep scatter constants + float m_deepScatterFalloff; + float m_shadowFilterRadius; + float m_decodeDepthScale, m_decodeDepthBias; +}; + + + +// Memory allocation helper functions + +inline void * FaceWorks_Malloc(size_t bytes, const gfsdk_new_delete_t & allocator) +{ + if (allocator.new_) + return allocator.new_(bytes); + else + return ::operator new(bytes); +} + +inline void FaceWorks_Free(void * p, const gfsdk_new_delete_t & allocator) +{ + if (!p) + return; + + if (allocator.delete_) + allocator.delete_(p); + else + ::operator delete(p); +} + +// STL allocator that uses the preceding functions + +template <typename T> +class FaceWorks_Allocator : public std::allocator<T> +{ +public: + gfsdk_new_delete_t m_allocator; + + explicit FaceWorks_Allocator(gfsdk_new_delete_t * pAllocator) + { + if (pAllocator) + { + m_allocator.new_ = pAllocator->new_; + m_allocator.delete_ = pAllocator->delete_; + } + else + { + m_allocator.new_ = nullptr; + m_allocator.delete_ = nullptr; + } + } + + template <typename T1> + FaceWorks_Allocator(FaceWorks_Allocator<T1> const & other) + : m_allocator(other.m_allocator) + { + } + + template <typename T1> + struct rebind + { + typedef FaceWorks_Allocator<T1> other; + }; + + pointer allocate(size_type n, const void * hint = nullptr) + { + (void)hint; + pointer p = pointer(FaceWorks_Malloc(n * sizeof(T), m_allocator)); + // Note: exceptions, yuck, but this is how you handle out-of-memory with STL... + // In FaceWorks, this is caught by the code using the STL container and converted + // to a return code; the exception should never propagate out to the caller. + if (!p) + throw std::bad_alloc(); + return p; + } + + void deallocate(pointer p, size_type n) + { + (void)n; + FaceWorks_Free(p, m_allocator); + } +}; + + + +// Error blob helper functions +void BlobPrintf(GFSDK_FaceWorks_ErrorBlob * pBlob, const char * fmt, ...); +#define ErrPrintf(...) BlobPrintf(pErrorBlobOut, "Error: " __VA_ARGS__) +#define WarnPrintf(...) BlobPrintf(pErrorBlobOut, "Warning: " __VA_ARGS__) + +#endif // GFSDK_FACEWORKS_INTERNAL_H diff --git a/src/precomp.cpp b/src/precomp.cpp new file mode 100644 index 0000000..f6396b9 --- /dev/null +++ b/src/precomp.cpp @@ -0,0 +1,843 @@ +//---------------------------------------------------------------------------------- +// File: FaceWorks/src/precomp.cpp +// SDK Version: v1.0 +// Email: [email protected] +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- + + +#include "internal.h" + +#include <cstdio> +#include <vector> + + + +// Versioning + +GFSDK_FACEWORKS_API int GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GetBinaryVersion() +{ + // Capture the header version at time of compilation + return GFSDK_FaceWorks_HeaderVersion; +} + +GFSDK_FACEWORKS_API const char * GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GetBuildInfo() +{ +#define STRINGIZE2(x) #x +#define STRINGIZE(x) STRINGIZE2(x) + + return + "GFSDK_FaceWorks_HeaderVersion: " STRINGIZE(GFSDK_FaceWorks_HeaderVersion) "\n" + "Built on: " __DATE__ " " __TIME__ "\n" + +#if defined(_MSC_VER) + "Compiler: Microsoft Visual C++\n" + "_MSC_VER: " STRINGIZE(_MSC_VER) "\n" +#else + "Compiler: unknown\n" +#endif + +#if defined(_WIN64) + "Platform: Win64\n" +#elif defined(_WIN32) + "Platform: Win32\n" +#else + "Platform: unknown\n" +#endif + +#if defined(_DEBUG) + "Configuration: Debug\n" +#else + "Configuration: Release\n" +#endif + ; + +#undef STRINGIZE +#undef STRINGIZE2 +} + +static const float pi = 3.141592654f; + +// Initialization + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_Init_Internal(int headerVersion) +{ + if (headerVersion != GFSDK_FaceWorks_GetBinaryVersion()) + return GFSDK_FaceWorks_VersionMismatch; + + return GFSDK_FaceWorks_OK; +} + + + +// Error blob helper functions + +void BlobPrintf(GFSDK_FaceWorks_ErrorBlob * pBlob, const char * fmt, ...) +{ + if (!pBlob) + return; + + // Printf the message - just use a fixed-size buffer to simplify things + char newMsg[256]; + va_list args; + va_start(args, fmt); + _vsnprintf_s(newMsg, dim(newMsg), _TRUNCATE, fmt, args); + size_t newLen = strlen(newMsg); + + // Append the message to the blob + if (pBlob->m_msg) + { + size_t curLen = strlen(pBlob->m_msg); + size_t bytes = curLen + newLen + 1; + char * concat = static_cast<char *>(FaceWorks_Malloc(bytes, pBlob->m_allocator)); + if (!concat) + { + // Out of memory while generating an error message - just give up + return; + } + memcpy(concat, pBlob->m_msg, curLen); + memcpy(concat + curLen, newMsg, newLen + 1); + FaceWorks_Free(pBlob->m_msg, pBlob->m_allocator); + pBlob->m_msg = concat; + } + else + { + size_t bytes = newLen + 1; + pBlob->m_msg = static_cast<char *>(FaceWorks_Malloc(bytes, pBlob->m_allocator)); + if (!pBlob->m_msg) + { + // Out of memory while generating an error message - just give up + return; + } + memcpy(pBlob->m_msg, newMsg, bytes); + } +} + +GFSDK_FACEWORKS_API void GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_FreeErrorBlob( + GFSDK_FaceWorks_ErrorBlob * pBlob) +{ + if (!pBlob) + return; + + FaceWorks_Free(pBlob->m_msg, pBlob->m_allocator); + pBlob->m_msg = nullptr; +} + + + +GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateCurvatureSizeBytes(int vertexCount) +{ + return sizeof(float) * max(0, vertexCount); +} + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateMeshCurvature( + int vertexCount, + const void * pPositions, + int positionStrideBytes, + const void * pNormals, + int normalStrideBytes, + int indexCount, + const int * pIndices, + int smoothingPassCount, + void * pCurvaturesOut, + int curvatureStrideBytes, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut, + gfsdk_new_delete_t * pAllocator /*= 0*/) +{ + // Validate parameters + if (vertexCount < 1) + { + ErrPrintf("vertexCount is %d; should be at least 1\n", vertexCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pPositions) + { + ErrPrintf("pPositions is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (positionStrideBytes < 3 * int(sizeof(float))) + { + ErrPrintf("positionStrideBytes is %d; should be at least %d\n", + positionStrideBytes, 3 * sizeof(float)); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pNormals) + { + ErrPrintf("pNormals is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (normalStrideBytes < 3 * int(sizeof(float))) + { + ErrPrintf("normalStrideBytes is %d; should be at least %d\n", + normalStrideBytes, 3 * sizeof(float)); + return GFSDK_FaceWorks_InvalidArgument; + } + if (indexCount < 3) + { + ErrPrintf("indexCount is %d; should be at least 3\n", indexCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pIndices) + { + ErrPrintf("pIndices is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (smoothingPassCount < 0) + { + ErrPrintf("smoothingPassCount is %d; should be at least 0\n", smoothingPassCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pCurvaturesOut) + { + ErrPrintf("pCurvaturesOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (curvatureStrideBytes < int(sizeof(float))) + { + ErrPrintf("curvatureStrideBytes is %d; should be at least %d\n", + curvatureStrideBytes, sizeof(float)); + return GFSDK_FaceWorks_InvalidArgument; + } + + // Calculate per-vertex curvature. We do this by estimating the curvature along each + // edge using the change in normals between its vertices; then we set each vertex's + // curvature to the midpoint of the minimum and maximum over all the edges touching it. + + int triCount = indexCount / 3; + + // Catch out-of-memory exceptions + try + { + FaceWorks_Allocator<float> allocFloat(pAllocator); + std::vector<float, FaceWorks_Allocator<float>> curvatureMin(vertexCount, FLT_MAX, allocFloat); + std::vector<float, FaceWorks_Allocator<float>> curvatureMax(vertexCount, 0.0f, allocFloat); + + // !!!UNDONE: SIMD-ize or GPU-ize all this math + + for (int iTri = 0; iTri < triCount; ++iTri) + { + int indices[] = + { + pIndices[3*iTri], + pIndices[3*iTri + 1], + pIndices[3*iTri + 2], + }; + + float * pos[] = + { + reinterpret_cast<float *>((char *)pPositions + indices[0] * positionStrideBytes), + reinterpret_cast<float *>((char *)pPositions + indices[1] * positionStrideBytes), + reinterpret_cast<float *>((char *)pPositions + indices[2] * positionStrideBytes), + }; + + float * normal[] = + { + reinterpret_cast<float *>((char *)pNormals + indices[0] * normalStrideBytes), + reinterpret_cast<float *>((char *)pNormals + indices[1] * normalStrideBytes), + reinterpret_cast<float *>((char *)pNormals + indices[2] * normalStrideBytes), + }; + + // Calculate each edge's curvature - most edges will be calculated twice this + // way, but it's hard to fix that while still making sure to handle boundary edges. + + float dPx = pos[1][0] - pos[0][0]; + float dPy = pos[1][1] - pos[0][1]; + float dPz = pos[1][2] - pos[0][2]; + float dNx = normal[1][0] - normal[0][0]; + float dNy = normal[1][1] - normal[0][1]; + float dNz = normal[1][2] - normal[0][2]; + float curvature = sqrtf((dNx*dNx + dNy*dNy + dNz*dNz) / (dPx*dPx + dPy*dPy + dPz*dPz)); + curvatureMin[indices[0]] = min(curvatureMin[indices[0]], curvature); + curvatureMin[indices[1]] = min(curvatureMin[indices[1]], curvature); + curvatureMax[indices[0]] = max(curvatureMax[indices[0]], curvature); + curvatureMax[indices[1]] = max(curvatureMax[indices[1]], curvature); + + dPx = pos[2][0] - pos[1][0]; + dPy = pos[2][1] - pos[1][1]; + dPz = pos[2][2] - pos[1][2]; + dNx = normal[2][0] - normal[1][0]; + dNy = normal[2][1] - normal[1][1]; + dNz = normal[2][2] - normal[1][2]; + curvature = sqrtf((dNx*dNx + dNy*dNy + dNz*dNz) / (dPx*dPx + dPy*dPy + dPz*dPz)); + curvatureMin[indices[1]] = min(curvatureMin[indices[1]], curvature); + curvatureMin[indices[2]] = min(curvatureMin[indices[2]], curvature); + curvatureMax[indices[1]] = max(curvatureMax[indices[1]], curvature); + curvatureMax[indices[2]] = max(curvatureMax[indices[2]], curvature); + + dPx = pos[0][0] - pos[2][0]; + dPy = pos[0][1] - pos[2][1]; + dPz = pos[0][2] - pos[2][2]; + dNx = normal[0][0] - normal[2][0]; + dNy = normal[0][1] - normal[2][1]; + dNz = normal[0][2] - normal[2][2]; + curvature = sqrtf((dNx*dNx + dNy*dNy + dNz*dNz) / (dPx*dPx + dPy*dPy + dPz*dPz)); + curvatureMin[indices[2]] = min(curvatureMin[indices[2]], curvature); + curvatureMin[indices[0]] = min(curvatureMin[indices[0]], curvature); + curvatureMax[indices[2]] = max(curvatureMax[indices[2]], curvature); + curvatureMax[indices[0]] = max(curvatureMax[indices[0]], curvature); + } + + for (int i = 0; i < vertexCount; ++i) + { + float * pCurvature = reinterpret_cast<float *>((char *)pCurvaturesOut + i * curvatureStrideBytes); + *pCurvature = 0.5f * (curvatureMin[i] + curvatureMax[i]); + } + } + catch (std::bad_alloc) + { + return GFSDK_FaceWorks_OutOfMemory; + } + + if (smoothingPassCount > 0) + { + // Catch out-of-memory exceptions + try + { + FaceWorks_Allocator<float> allocFloat(pAllocator); + std::vector<float, FaceWorks_Allocator<float>> curvatureSum(allocFloat); + curvatureSum.resize(vertexCount); + + FaceWorks_Allocator<int> allocInt(pAllocator); + std::vector<int, FaceWorks_Allocator<int>> curvatureCount(allocInt); + curvatureCount.resize(vertexCount); + + // Run a couple of smoothing passes, replacing each vert's curvature + // by the average of its neighbors' + + for (int iPass = 0; iPass < smoothingPassCount; ++iPass) + { + for (int i = 0; i < vertexCount; ++i) + { + curvatureSum[i] = 0.0f; + curvatureCount[i] = 0; + } + + for (int iTri = 0; iTri < triCount; ++iTri) + { + int indices[] = + { + pIndices[3*iTri], + pIndices[3*iTri + 1], + pIndices[3*iTri + 2], + }; + + float curvature0 = *reinterpret_cast<float *>((char *)pCurvaturesOut + indices[0] * curvatureStrideBytes); + float curvature1 = *reinterpret_cast<float *>((char *)pCurvaturesOut + indices[1] * curvatureStrideBytes); + float curvature2 = *reinterpret_cast<float *>((char *)pCurvaturesOut + indices[2] * curvatureStrideBytes); + + curvatureSum[indices[0]] += curvature1 + curvature2; + curvatureCount[indices[0]] += 2; + + curvatureSum[indices[1]] += curvature2 + curvature0; + curvatureCount[indices[1]] += 2; + + curvatureSum[indices[2]] += curvature0 + curvature1; + curvatureCount[indices[2]] += 2; + } + + for (int i = 0; i < vertexCount; ++i) + { + float * pCurvature = reinterpret_cast<float *>((char *)pCurvaturesOut + i * curvatureStrideBytes); + *pCurvature = curvatureSum[i] / float(max(1, curvatureCount[i])); + } + } + } + catch (std::bad_alloc) + { + return GFSDK_FaceWorks_OutOfMemory; + } + } + + return GFSDK_FaceWorks_OK; +} + + + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateMeshUVScale( + int vertexCount, + const void * pPositions, + int positionStrideBytes, + const void * pUVs, + int uvStrideBytes, + int indexCount, + const int * pIndices, + float * pAverageUVScaleOut, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + // Validate parameters + if (vertexCount < 1) + { + ErrPrintf("vertexCount is %d; should be at least 1\n", vertexCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pPositions) + { + ErrPrintf("pPositions is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (positionStrideBytes < 3 * int(sizeof(float))) + { + ErrPrintf("positionStrideBytes is %d; should be at least %d\n", + positionStrideBytes, 3 * sizeof(float)); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pUVs) + { + ErrPrintf("pUVs is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (uvStrideBytes < 2 * int(sizeof(float))) + { + ErrPrintf("uvStrideBytes is %d; should be at least %d\n", + uvStrideBytes, 2 * sizeof(float)); + return GFSDK_FaceWorks_InvalidArgument; + } + if (indexCount < 3) + { + ErrPrintf("indexCount is %d; should be at least 3\n", indexCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (indexCount % 3 != 0) + { + ErrPrintf("indexCount is %d; should be a multiple of 3\n", indexCount); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pIndices) + { + ErrPrintf("pIndices is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pAverageUVScaleOut) + { + ErrPrintf("pAverageUVScaleOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + + // Calculate average UV scale, as a geometric mean of scale for each triangle + + float logUvScaleSum = 0.0f; + int logUvScaleCount = 0; + + // !!!UNDONE: SIMD-ize or GPU-ize all this math + + for (int iIndex = 0; iIndex < indexCount; iIndex += 3) + { + int indices[] = + { + pIndices[iIndex], + pIndices[iIndex + 1], + pIndices[iIndex + 2], + }; + + float * pos[] = + { + reinterpret_cast<float *>((char *)pPositions + indices[0] * positionStrideBytes), + reinterpret_cast<float *>((char *)pPositions + indices[1] * positionStrideBytes), + reinterpret_cast<float *>((char *)pPositions + indices[2] * positionStrideBytes), + }; + + float * uv[] = + { + reinterpret_cast<float *>((char *)pUVs + indices[0] * uvStrideBytes), + reinterpret_cast<float *>((char *)pUVs + indices[1] * uvStrideBytes), + reinterpret_cast<float *>((char *)pUVs + indices[2] * uvStrideBytes), + }; + + // Find longest edge length in local space + float dP0x = pos[1][0] - pos[0][0]; + float dP0y = pos[1][1] - pos[0][1]; + float dP0z = pos[1][2] - pos[0][2]; + float dP1x = pos[2][0] - pos[1][0]; + float dP1y = pos[2][1] - pos[1][1]; + float dP1z = pos[2][2] - pos[1][2]; + float dP2x = pos[0][0] - pos[2][0]; + float dP2y = pos[0][1] - pos[2][1]; + float dP2z = pos[0][2] - pos[2][2]; + float diameter = sqrtf(max(dP0x*dP0x + dP0y*dP0y + dP0z*dP0z, + max(dP1x*dP1x + dP1y*dP1y + dP1z*dP1z, + dP2x*dP2x + dP2y*dP2y + dP2z*dP2z))); + + // Find longest edge length in UV space + float dUV0x = uv[1][0] - uv[0][0]; + float dUV0y = uv[1][1] - uv[0][1]; + float dUV1x = uv[2][0] - uv[1][0]; + float dUV1y = uv[2][1] - uv[1][1]; + float dUV2x = uv[0][0] - uv[2][0]; + float dUV2y = uv[0][1] - uv[2][1]; + float uvDiameter = sqrtf(max(dUV0x*dUV0x + dUV0y*dUV0y, + max(dUV1x*dUV1x + dUV1y*dUV1y, + dUV2x*dUV2x + dUV2y*dUV2y))); + + // Skip degenerate triangles + if (diameter < 1e-6f || uvDiameter < 1e-6f) + continue; + + float triUvScale = diameter / uvDiameter; + logUvScaleSum += logf(triUvScale); + ++logUvScaleCount; + } + + *pAverageUVScaleOut = expf(logUvScaleSum / float(logUvScaleCount)); + + return GFSDK_FaceWorks_OK; +} + + + +// Diffusion profile from GPU Gems 3 - mixture of 6 Gaussians with RGB weights +// NOTE: could switch to a LUT generated using one of the Donner and Jensen papers + +static const float diffusionSigmas[] = { 0.080f, 0.220f, 0.432f, 0.753f, 1.411f, 2.722f }; +static const float diffusionWeightsR[] = { 0.233f, 0.100f, 0.118f, 0.113f, 0.358f, 0.078f }; +static const float diffusionWeightsG[] = { 0.455f, 0.336f, 0.198f, 0.007f, 0.004f, 0.000f }; +static const float diffusionWeightsB[] = { 0.649f, 0.344f, 0.000f, 0.007f, 0.000f, 0.000f }; + + +static_assert(dim(diffusionWeightsR) == dim(diffusionSigmas), "dimension mismatch between array diffusionWeightsR and diffusionSigmas"); +static_assert(dim(diffusionWeightsG) == dim(diffusionSigmas), "dimension mismatch between array diffusionWeightsG and diffusionSigmas"); +static_assert(dim(diffusionWeightsB) == dim(diffusionSigmas), "dimension mismatch between array diffusionWeightsB and diffusionSigmas"); + +inline float Gaussian(float sigma, float x) +{ + static const float rsqrtTwoPi = 0.39894228f; + return (rsqrtTwoPi / sigma) * expf(-0.5f * (x*x) / (sigma*sigma)); +} + +static void EvaluateDiffusionProfile(float x, float rgb[3]) // x in millimeters +{ + rgb[0] = 0.0f; + rgb[1] = 0.0f; + rgb[2] = 0.0f; + + for (int i = 0; i < dim(diffusionSigmas); ++i) + { + static const float rsqrtTwoPi = 0.39894228f; + float sigma = diffusionSigmas[i]; + float gaussian = (rsqrtTwoPi / sigma) * expf(-0.5f * (x*x) / (sigma*sigma)); + + rgb[0] += diffusionWeightsR[i] * gaussian; + rgb[1] += diffusionWeightsG[i] * gaussian; + rgb[2] += diffusionWeightsB[i] * gaussian; + } +} + +GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateCurvatureLUTSizeBytes( + const GFSDK_FaceWorks_CurvatureLUTConfig * pConfig) +{ + if (!pConfig) + return 0; + + return 4 * pConfig->m_texWidth * pConfig->m_texHeight; +} + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GenerateCurvatureLUT( + const GFSDK_FaceWorks_CurvatureLUTConfig * pConfig, + void * pCurvatureLUTOut, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + // Validate parameters + if (!pConfig) + { + ErrPrintf("pConfig is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pCurvatureLUTOut) + { + ErrPrintf("pCurvatureLUTOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_diffusionRadius <= 0.0f) + { + ErrPrintf("m_diffusionRadius is %g; should be greater than 0\n", + pConfig->m_diffusionRadius); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_texWidth < 1) + { + ErrPrintf("m_texWidth is %d; should be at least 1\n", + pConfig->m_texWidth); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_texHeight < 1) + { + ErrPrintf("m_texHeight is %d; should be at least 1\n", + pConfig->m_texHeight); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_curvatureRadiusMin <= 0.0f) + { + ErrPrintf("m_curvatureRadiusMin is %g; should be greater than 0\n", + pConfig->m_curvatureRadiusMin); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_curvatureRadiusMax <= 0.0f) + { + ErrPrintf("m_curvatureRadiusMax is %g; should be greater than 0\n", + pConfig->m_curvatureRadiusMax); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_curvatureRadiusMax < pConfig->m_curvatureRadiusMin) + { + ErrPrintf("m_curvatureRadiusMin is %g and m_curvatureRadiusMax is %g; max should be greater than min\n", + pConfig->m_curvatureRadiusMin, pConfig->m_curvatureRadiusMax); + return GFSDK_FaceWorks_InvalidArgument; + } + + // The diffusion profile is built assuming a (standard human skin) radius + // of 2.7 mm, so the curvatures and shadow widths need to be scaled to generate + // a LUT for the user's desired diffusion radius. + float diffusionRadiusFactor = pConfig->m_diffusionRadius / 2.7f; + + float curvatureMin = diffusionRadiusFactor / pConfig->m_curvatureRadiusMax; + float curvatureMax = diffusionRadiusFactor / pConfig->m_curvatureRadiusMin; + float curvatureScale = (curvatureMax - curvatureMin) / float(pConfig->m_texHeight); + float curvatureBias = curvatureMin + 0.5f * curvatureScale; + + float NdotLScale = 2.0f / float(pConfig->m_texWidth); + float NdotLBias = -1.0f + 0.5f * NdotLScale; + + unsigned char * pPx = static_cast<unsigned char *>(pCurvatureLUTOut); + + // !!!UNDONE: SIMD-ize or GPU-ize all this math + + for (int iY = 0; iY < pConfig->m_texHeight; ++iY) + { + for (int iX = 0; iX < pConfig->m_texWidth; ++iX) + { + float NdotL = float(iX) * NdotLScale + NdotLBias; + float theta = acosf(NdotL); + + float curvature = float(iY) * curvatureScale + curvatureBias; + float radius = 1.0f / curvature; + + // Sample points around a ring, and Monte-Carlo-integrate the + // scattered lighting using the diffusion profile + + static const int cIter = 200; + float rgb[3] = { 0.0f, 0.0f, 0.0f }; + + // Set integration bounds in arc-length in mm on the sphere + float lowerBound = max(-pi*radius, -10.0f); + float upperBound = min(pi*radius, 10.0f); + + float iterScale = (upperBound - lowerBound) / float(cIter); + float iterBias = lowerBound + 0.5f * iterScale; + + for (int iIter = 0; iIter < cIter; ++iIter) + { + float delta = float(iIter) * iterScale + iterBias; + float rgbDiffusion[3]; + EvaluateDiffusionProfile(delta, rgbDiffusion); + + float NdotLDelta = max(0.0f, cosf(theta - delta * curvature)); + rgb[0] += NdotLDelta * rgbDiffusion[0]; + rgb[1] += NdotLDelta * rgbDiffusion[1]; + rgb[2] += NdotLDelta * rgbDiffusion[2]; + } + + // Scale sum of samples to get value of integral + float scale = (upperBound - lowerBound) / float(cIter); + rgb[0] *= scale; + rgb[1] *= scale; + rgb[2] *= scale; + + // Calculate delta from standard diffuse lighting (saturate(N.L)) to + // scattered result, remapped from [-.25, .25] to [0, 1]. + float rgbAdjust = -max(0.0f, NdotL) * 2.0f + 0.5f; + rgb[0] = rgb[0] * 2.0f + rgbAdjust; + rgb[1] = rgb[1] * 2.0f + rgbAdjust; + rgb[2] = rgb[2] * 2.0f + rgbAdjust; + + // Clamp to [0, 1] + rgb[0] = min(max(rgb[0], 0.0f), 1.0f); + rgb[1] = min(max(rgb[1], 0.0f), 1.0f); + rgb[2] = min(max(rgb[2], 0.0f), 1.0f); + + // Convert to integer format (linear RGB space) + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[0] + 0.5f); + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[1] + 0.5f); + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[2] + 0.5f); + *(pPx++) = 255; + } + } + + return GFSDK_FaceWorks_OK; +} + +GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateShadowLUTSizeBytes( + const GFSDK_FaceWorks_ShadowLUTConfig * pConfig) +{ + if (!pConfig) + return 0; + + return 4 * pConfig->m_texWidth * pConfig->m_texHeight; +} + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GenerateShadowLUT( + const GFSDK_FaceWorks_ShadowLUTConfig * pConfig, + void * pShadowLUTOut, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + if (!pConfig) + { + ErrPrintf("pConfig is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (!pShadowLUTOut) + { + ErrPrintf("pShadowLUTOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_diffusionRadius <= 0.0f) + { + ErrPrintf("m_diffusionRadius is %g; should be greater than 0\n", + pConfig->m_diffusionRadius); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_texWidth < 1) + { + ErrPrintf("m_texWidth is %d; should be at least 1\n", + pConfig->m_texWidth); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_texHeight < 1) + { + ErrPrintf("m_texHeight is %d; should be at least 1\n", + pConfig->m_texHeight); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_shadowWidthMin <= 0.0f) + { + ErrPrintf("m_shadowWidthMin is %g; should be greater than 0\n", + pConfig->m_shadowWidthMin); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_shadowWidthMax <= 0.0f) + { + ErrPrintf("m_shadowWidthMax is %g; should be greater than 0\n", + pConfig->m_shadowWidthMax); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_shadowWidthMax < pConfig->m_shadowWidthMin) + { + ErrPrintf("m_shadowWidthMin is %g and m_shadowWidthMax is %g; max should be greater than min\n", + pConfig->m_shadowWidthMin, pConfig->m_shadowWidthMax); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_shadowSharpening < 1.0f) + { + ErrPrintf("m_shadowSharpening is %g; should be at least 1.0\n", + pConfig->m_shadowSharpening); + return GFSDK_FaceWorks_InvalidArgument; + } + + // The diffusion profile is built assuming a (standard human skin) radius + // of 2.7 mm, so the curvatures and shadow widths need to be scaled to generate + // a LUT for the user's desired diffusion radius. + float diffusionRadiusFactor = pConfig->m_diffusionRadius / 2.7f; + + float shadowRcpWidthMin = diffusionRadiusFactor / pConfig->m_shadowWidthMax; + float shadowRcpWidthMax = diffusionRadiusFactor / pConfig->m_shadowWidthMin; + float shadowScale = (shadowRcpWidthMax - shadowRcpWidthMin) / float(pConfig->m_texHeight); + float shadowBias = shadowRcpWidthMin + 0.5f * shadowScale; + + unsigned char * pPx = static_cast<unsigned char *>(pShadowLUTOut); + + // !!!UNDONE: SIMD-ize or GPU-ize all this math + + for (int iY = 0; iY < pConfig->m_texHeight; ++iY) + { + for (int iX = 0; iX < pConfig->m_texWidth; ++iX) + { + // Calculate input position relative to the shadow edge, by approximately + // inverting the transfer function of a disc or Gaussian filter. + float u = (iX + 0.5f) / float(pConfig->m_texWidth); + float inputPos = (sqrtf(u) - sqrtf(1.0f - u)) * 0.5f + 0.5f; + + float rcpWidth = float(iY) * shadowScale + shadowBias; + + // Sample points along a line perpendicular to the shadow edge, and + // Monte-Carlo-integrate the scattered lighting using the diffusion profile + + static const int cIter = 200; + float rgb[3] = { 0.0f, 0.0f, 0.0f }; + + float iterScale = 20.0f / float(cIter); + float iterBias = -10.0f + 0.5f * iterScale; + + for (int iIter = 0; iIter < cIter; ++iIter) + { + float delta = float(iIter) * iterScale + iterBias; + float rgbDiffusion[3]; + EvaluateDiffusionProfile(delta, rgbDiffusion); + + // Use smoothstep as an approximation of the transfer function of a + // disc or Gaussian filter. + float newPos = (inputPos + delta * rcpWidth) * pConfig->m_shadowSharpening + + (-0.5f * pConfig->m_shadowSharpening + 0.5f); + float newPosClamped = min(max(newPos, 0.0f), 1.0f); + float newShadow = (3.0f - 2.0f * newPosClamped) * newPosClamped * newPosClamped; + + rgb[0] += newShadow * rgbDiffusion[0]; + rgb[1] += newShadow * rgbDiffusion[1]; + rgb[2] += newShadow * rgbDiffusion[2]; + } + + // Scale sum of samples to get value of integral. Also hack in a + // fade to ensure the left edge of the image goes strictly to zero. + float scale = 20.0f / float(cIter); + if (iX * 25 < pConfig->m_texWidth) + { + scale *= min(25.0f * float(iX) / float(pConfig->m_texWidth), 1.0f); + } + rgb[0] *= scale; + rgb[1] *= scale; + rgb[2] *= scale; + + // Clamp to [0, 1] + rgb[0] = min(max(rgb[0], 0.0f), 1.0f); + rgb[1] = min(max(rgb[1], 0.0f), 1.0f); + rgb[2] = min(max(rgb[2], 0.0f), 1.0f); + + // Convert linear to sRGB + rgb[0] = (rgb[0] < 0.0031308f) ? (12.92f * rgb[0]) : (1.055f * powf(rgb[0], 1.0f / 2.4f) - 0.055f); + rgb[1] = (rgb[1] < 0.0031308f) ? (12.92f * rgb[1]) : (1.055f * powf(rgb[1], 1.0f / 2.4f) - 0.055f); + rgb[2] = (rgb[2] < 0.0031308f) ? (12.92f * rgb[2]) : (1.055f * powf(rgb[2], 1.0f / 2.4f) - 0.055f); + + // Convert to integer format + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[0] + 0.5f); + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[1] + 0.5f); + *(pPx++) = static_cast<unsigned char>(255.0f * rgb[2] + 0.5f); + *(pPx++) = 255; + } + } + + return GFSDK_FaceWorks_OK; +} diff --git a/src/runtime.cpp b/src/runtime.cpp new file mode 100644 index 0000000..a220864 --- /dev/null +++ b/src/runtime.cpp @@ -0,0 +1,275 @@ +//---------------------------------------------------------------------------------- +// File: FaceWorks/src/runtime.cpp +// SDK Version: v1.0 +// Email: [email protected] +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- + +#include "internal.h" + +#include <cassert> + +// ====================================================================================== +// Runtime API for SSS +// ====================================================================================== + +GFSDK_FaceWorks_Result ValidateSSSConfig( + const GFSDK_FaceWorks_SSSConfig * pConfig, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + if (!pConfig) + { + ErrPrintf("pConfig is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + + if (pConfig->m_diffusionRadius <= 0.0f) + { + WarnPrintf( + "pConfig->m_diffusionRadius is %g; should be greater than 0.0\n", + pConfig->m_diffusionRadius); + } + if (pConfig->m_diffusionRadiusLUT <= 0.0f) + { + WarnPrintf( + "pConfig->m_diffusionRadiusLUT is %g; should be greater than 0.0\n", + pConfig->m_diffusionRadius); + } + if (pConfig->m_curvatureRadiusMinLUT <= 0.0f) + { + WarnPrintf( + "pConfig->m_curvatureRadiusMinLUT is %g; should be greater than 0.0\n", + pConfig->m_curvatureRadiusMinLUT); + } + if (pConfig->m_curvatureRadiusMaxLUT <= 0.0f) + { + WarnPrintf( + "pConfig->m_curvatureRadiusMaxLUT is %g; should be greater than 0.0\n", + pConfig->m_curvatureRadiusMaxLUT); + } + if (pConfig->m_curvatureRadiusMaxLUT < pConfig->m_curvatureRadiusMinLUT) + { + WarnPrintf( + "pConfig->m_curvatureRadiusMaxLUT (%g) is less than pConfig->m_curvatureRadiusMinLUT (%g)\n", + pConfig->m_curvatureRadiusMaxLUT, pConfig->m_curvatureRadiusMinLUT); + } + if (pConfig->m_shadowWidthMinLUT <= 0.0f) + { + WarnPrintf( + "pConfig->m_shadowWidthMinLUT is %g; should be greater than 0.0\n", + pConfig->m_shadowWidthMinLUT); + } + if (pConfig->m_shadowWidthMaxLUT <= 0.0f) + { + WarnPrintf( + "pConfig->m_shadowWidthMaxLUT is %g; should be greater than 0.0\n", + pConfig->m_shadowWidthMaxLUT); + } + if (pConfig->m_shadowWidthMaxLUT < pConfig->m_shadowWidthMinLUT) + { + WarnPrintf( + "pConfig->m_shadowWidthMaxLUT (%g) is less than pConfig->m_shadowWidthMinLUT (%g)\n", + pConfig->m_shadowWidthMaxLUT, pConfig->m_shadowWidthMinLUT); + } + if (pConfig->m_shadowFilterWidth <= 0.0f) + { + WarnPrintf( + "pConfig->m_shadowFilterWidth is %g; should be greater than 0.0\n", + pConfig->m_shadowFilterWidth); + } + if (pConfig->m_normalMapSize < 0) + { + WarnPrintf( + "pConfig->m_normalMapSize is %d; should be at least 0\n", + pConfig->m_normalMapSize); + } + if (pConfig->m_averageUVScale <= 0.0f) + { + WarnPrintf( + "pConfig->m_averageUVScale is %g; should be greater than 0.0\n", + pConfig->m_averageUVScale); + } + + return GFSDK_FaceWorks_OK; +} + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_WriteCBDataForSSS( + const GFSDK_FaceWorks_SSSConfig * pConfig, + GFSDK_FaceWorks_CBData * pCBDataOut, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + // Validate params + + GFSDK_FaceWorks_Result res = ValidateSSSConfig(pConfig, pErrorBlobOut); + if (res != GFSDK_FaceWorks_OK) + return res; + + if (!pCBDataOut) + { + ErrPrintf("GFSDK_FaceWorks_WriteCBDataForSSS: pCBDataOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + + // The LUTs are built assuming a particular scattering radius, so the + // curvatures and penumbra widths need to be scaled to match the + // scattering radius set at runtime. + float diffusionRadiusFactor = pConfig->m_diffusionRadiusLUT / + pConfig->m_diffusionRadius; + + // Set up the constant buffer + + float curvatureMin = diffusionRadiusFactor / pConfig->m_curvatureRadiusMaxLUT; + float curvatureMax = diffusionRadiusFactor / pConfig->m_curvatureRadiusMinLUT; + float curvatureScale = 1.0f / (curvatureMax - curvatureMin); + float curvatureBias = -curvatureMin * curvatureScale; + + float shadowRcpWidthMin = diffusionRadiusFactor / pConfig->m_shadowWidthMaxLUT; + float shadowRcpWidthMax = diffusionRadiusFactor / pConfig->m_shadowWidthMinLUT; + float shadowScale = 1.0f / (shadowRcpWidthMax - shadowRcpWidthMin); + float shadowBias = -shadowRcpWidthMin * shadowScale; + + float minLevelForBlurredNormal = log2(max( + pConfig->m_normalMapSize * pConfig->m_diffusionRadius, + pConfig->m_averageUVScale) + / pConfig->m_averageUVScale); + + // Output to user buffer + pCBDataOut->data[0].x = curvatureScale; + pCBDataOut->data[0].y = curvatureBias; + pCBDataOut->data[0].z = shadowScale / pConfig->m_shadowFilterWidth; + pCBDataOut->data[0].w = shadowBias; + pCBDataOut->data[1].x = minLevelForBlurredNormal; + + return GFSDK_FaceWorks_OK; +} + + + +// ====================================================================================== +// Runtime API for deep scatter +// ====================================================================================== + +GFSDK_FaceWorks_Result ValidateDeepScatterConfig( + const GFSDK_FaceWorks_DeepScatterConfig * pConfig, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + if (!pConfig) + { + ErrPrintf("pConfig is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + + if (pConfig->m_radius <= 0.0f) + { + WarnPrintf( + "pConfig->m_radius is %g; should be greater than 0.0\n", + pConfig->m_radius); + } + if (pConfig->m_shadowProjType != GFSDK_FaceWorks_NoProjection && + pConfig->m_shadowProjType != GFSDK_FaceWorks_ParallelProjection && + pConfig->m_shadowProjType != GFSDK_FaceWorks_PerspectiveProjection) + { + ErrPrintf( + "pConfig->m_shadowProjType is %d; not a valid GFSDK_FaceWorks_ProjectionType enum value\n", + pConfig->m_shadowProjType); + return GFSDK_FaceWorks_InvalidArgument; + } + if (pConfig->m_shadowProjType != GFSDK_FaceWorks_NoProjection) + { + // Error checking for shadow parameters is done only if enabled by the projection type + if (pConfig->m_shadowFilterRadius < 0.0f) + { + WarnPrintf( + "pConfig->m_shadowFilterRadius is %g; should be at least 0.0\n", + pConfig->m_shadowFilterRadius); + } + + // Should we check that m_shadowProjMatrix is of the expected form + // (e.g. has zeros in the expected places)? + } + + return GFSDK_FaceWorks_OK; +} + +GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_WriteCBDataForDeepScatter( + const GFSDK_FaceWorks_DeepScatterConfig * pConfig, + GFSDK_FaceWorks_CBData * pCBDataOut, + GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut) +{ + // Validate params + + GFSDK_FaceWorks_Result res = ValidateDeepScatterConfig(pConfig, pErrorBlobOut); + if (res != GFSDK_FaceWorks_OK) + return res; + + if (!pCBDataOut) + { + ErrPrintf("pCBDataOut is null\n"); + return GFSDK_FaceWorks_InvalidArgument; + } + + // Set up the constant buffer + + // -0.7213475f = -1 / (2 * ln(2)) - this conversion lets us write this in the shader: + // exp2(deepScatterFalloff * thickness^2) + // instead of this: + // exp(-thickness^2 / (2 * radius^2)) + float deepScatterFalloff = -0.7213475f / (pConfig->m_radius * pConfig->m_radius); + + // Calculate depth-decoding parameters from the projection matrix + float decodeDepthScale = 0.0f; + float decodeDepthBias = 0.0f; + switch (pConfig->m_shadowProjType) + { + case GFSDK_FaceWorks_NoProjection: + break; // Nothing to do + + case GFSDK_FaceWorks_ParallelProjection: + decodeDepthScale = -1.0f / pConfig->m_shadowProjMatrix._33; + break; + + case GFSDK_FaceWorks_PerspectiveProjection: + decodeDepthScale = pConfig->m_shadowProjMatrix._34 / pConfig->m_shadowProjMatrix._43; + decodeDepthBias = -pConfig->m_shadowProjMatrix._33 / pConfig->m_shadowProjMatrix._43; + break; + + default: + assert(false); + return GFSDK_FaceWorks_InvalidArgument; + } + + // Output to user buffer + pCBDataOut->data[1].y = deepScatterFalloff; + pCBDataOut->data[1].z = pConfig->m_shadowFilterRadius; + pCBDataOut->data[1].w = decodeDepthScale; + pCBDataOut->data[2].x = decodeDepthBias; + + return GFSDK_FaceWorks_OK; +} |