aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarco Foco <[email protected]>2016-03-07 15:47:07 +0100
committerMarco Foco <[email protected]>2016-03-08 16:04:19 +0100
commitcd6e0492903f8a9eb5efa14263d7d9ab092517de (patch)
tree05c010b75bf777335565819dcceb140886c5a7e9 /src
downloadfaceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.tar.xz
faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.zip
FaceWorks 1.0
Diffstat (limited to 'src')
-rw-r--r--src/build/vs2013/GFSDK_FaceWorks.vcxproj263
-rw-r--r--src/build/vs2013/GFSDK_FaceWorks.vcxproj.filters38
-rw-r--r--src/build/vs2015/GFSDK_FaceWorks.vcxproj263
-rw-r--r--src/build/vs2015/GFSDK_FaceWorks.vcxproj.filters38
-rw-r--r--src/internal.h158
-rw-r--r--src/precomp.cpp843
-rw-r--r--src/runtime.cpp275
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
+// 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
+// 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
+// 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;
+}