aboutsummaryrefslogtreecommitdiff
path: root/demo/DemoApp
diff options
context:
space:
mode:
Diffstat (limited to 'demo/DemoApp')
-rw-r--r--demo/DemoApp/DemoApp.vcxproj367
-rw-r--r--demo/DemoApp/DemoApp.vcxproj.filters166
-rw-r--r--demo/DemoApp/NvFlowInterop.h29
-rw-r--r--demo/DemoApp/NvFlowInteropLoader.cpp63
-rw-r--r--demo/DemoApp/app.manifest7
-rw-r--r--demo/DemoApp/appGraphCtx.h41
-rw-r--r--demo/DemoApp/appGraphCtxLoader.cpp92
-rw-r--r--demo/DemoApp/bitmap.cpp119
-rw-r--r--demo/DemoApp/bitmap.h39
-rw-r--r--demo/DemoApp/camera.h255
-rw-r--r--demo/DemoApp/computeContext.h103
-rw-r--r--demo/DemoApp/computeContextLoader.cpp147
-rw-r--r--demo/DemoApp/curveEditor.cpp314
-rw-r--r--demo/DemoApp/curveEditor.h59
-rw-r--r--demo/DemoApp/customEmitAllocCS.hlsl.h225
-rw-r--r--demo/DemoApp/customEmitEmit2CS.hlsl.h503
-rw-r--r--demo/DemoApp/customEmitEmitCS.hlsl.h431
-rw-r--r--demo/DemoApp/customLightingCS.hlsl.h785
-rw-r--r--demo/DemoApp/flowShaderParams.h13
-rw-r--r--demo/DemoApp/imgui.cpp697
-rw-r--r--demo/DemoApp/imgui.h108
-rw-r--r--demo/DemoApp/imguiGraph.cpp470
-rw-r--r--demo/DemoApp/imguiGraph.h63
-rw-r--r--demo/DemoApp/imguiGraphLoader.cpp125
-rw-r--r--demo/DemoApp/imguiInterop.h19
-rw-r--r--demo/DemoApp/imguiser.cpp641
-rw-r--r--demo/DemoApp/imguiser.h76
-rw-r--r--demo/DemoApp/loader.cpp38
-rw-r--r--demo/DemoApp/loader.h112
-rw-r--r--demo/DemoApp/main.cpp605
-rw-r--r--demo/DemoApp/mesh.cpp496
-rw-r--r--demo/DemoApp/mesh.h100
-rw-r--r--demo/DemoApp/meshInterop.h19
-rw-r--r--demo/DemoApp/meshLoader.cpp83
-rw-r--r--demo/DemoApp/preset0.h63
-rw-r--r--demo/DemoApp/preset1.h63
-rw-r--r--demo/DemoApp/presetFireBall.h85
-rw-r--r--demo/DemoApp/presetFlame.h85
-rw-r--r--demo/DemoApp/presetSmoke.h46
-rw-r--r--demo/DemoApp/scene.cpp1036
-rw-r--r--demo/DemoApp/scene.h838
-rw-r--r--demo/DemoApp/scene2DTextureEmitter.cpp249
-rw-r--r--demo/DemoApp/sceneCustomEmit.cpp435
-rw-r--r--demo/DemoApp/sceneFlow.cpp822
-rw-r--r--demo/DemoApp/sceneSDF.cpp522
-rw-r--r--demo/DemoApp/sceneSimpleFlame.cpp1156
-rw-r--r--demo/DemoApp/sceneSimpleSmoke.cpp399
-rw-r--r--demo/DemoApp/stb_truetype.h1839
48 files changed, 15048 insertions, 0 deletions
diff --git a/demo/DemoApp/DemoApp.vcxproj b/demo/DemoApp/DemoApp.vcxproj
new file mode 100644
index 0000000..4cae61f
--- /dev/null
+++ b/demo/DemoApp/DemoApp.vcxproj
@@ -0,0 +1,367 @@
+<?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="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Platform)'=='Win32'">
+ <PlatformName>win32</PlatformName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'=='x64'">
+ <PlatformName>win64</PlatformName>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{001BA531-503D-4407-AE6B-A42408E17BFF}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>DemoApp</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <UseOfMfc>Static</UseOfMfc>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <UseOfMfc>Static</UseOfMfc>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <UseOfMfc>Static</UseOfMfc>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <UseOfMfc>Static</UseOfMfc>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>$(SolutionDir)\include;$(SolutionDir)\NvFlow;$(SolutionDir)\NvFlowContext;$(SolutionDir)external\SDL2\include;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)lib\win32;$(SolutionDir)external\SDL2\lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86</LibraryPath>
+ <CustomBuildBeforeTargets>PostBuildEvent</CustomBuildBeforeTargets>
+ <OutDir>$(SolutionDir)bin\$(PlatformName)\</OutDir>
+ <IntDir>interm\$(Configuration)_$(PlatformName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(PlatformName)\</OutDir>
+ <IntDir>interm\$(Configuration)_$(PlatformName)\</IntDir>
+ <IncludePath>$(SolutionDir)\include;$(SolutionDir)\NvFlow;$(SolutionDir)\NvFlowContext;$(SolutionDir)external\SDL2\include;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)lib\win64;$(SolutionDir)external\SDL2\lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
+ <CustomBuildBeforeTargets>PostBuildEvent</CustomBuildBeforeTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(SolutionDir)\include;$(SolutionDir)\NvFlow;$(SolutionDir)\NvFlowContext;$(SolutionDir)external\SDL2\include;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)lib\win32;$(SolutionDir)external\SDL2\lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86</LibraryPath>
+ <CustomBuildBeforeTargets>PostBuildEvent</CustomBuildBeforeTargets>
+ <OutDir>$(SolutionDir)bin\$(PlatformName)\</OutDir>
+ <IntDir>interm\$(Configuration)_$(PlatformName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)bin\$(PlatformName)\</OutDir>
+ <IntDir>interm\$(Configuration)_$(PlatformName)\</IntDir>
+ <IncludePath>$(SolutionDir)\include;$(SolutionDir)\NvFlow;$(SolutionDir)\NvFlowContext;$(SolutionDir)external\SDL2\include;$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)lib\win64;$(SolutionDir)external\SDL2\lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
+ <CustomBuildBeforeTargets>PostBuildEvent</CustomBuildBeforeTargets>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>DLL_SUFFIX=$(Configuration)_$(PlatformName);WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>NvFlowLib$(Configuration)_$(PlatformName).lib;SDL2.lib;SDL2main.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ </Link>
+ <FxCompile>
+ <EntryPointName>%(filename)</EntryPointName>
+ <ShaderModel>5.0</ShaderModel>
+ <HeaderFileOutput>$(ProjectDir)%(Filename).hlsl.h</HeaderFileOutput>
+ <ObjectFileOutput />
+ </FxCompile>
+ <CustomBuildStep>
+ <Command>copy "$(SolutionDir)external\SDL2\lib\x86\SDL2.dll" "$(outDir)"
+copy "$(SolutionDir)Lib\$(PlatformName)\*.dll" "$(outDir)"</Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>Copying DLLs</Message>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Outputs>SDL2.dll</Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>DLL_SUFFIX=$(Configuration)_$(PlatformName);_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>NvFlowLib$(Configuration)_$(PlatformName).lib;SDL2.lib;SDL2main.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ </Link>
+ <FxCompile>
+ <EntryPointName>%(filename)</EntryPointName>
+ <ShaderModel>5.0</ShaderModel>
+ <HeaderFileOutput>$(ProjectDir)%(Filename).hlsl.h</HeaderFileOutput>
+ <ObjectFileOutput />
+ </FxCompile>
+ <CustomBuildStep>
+ <Command>copy "$(SolutionDir)external\SDL2\lib\x64\SDL2.dll" "$(outDir)"
+copy "$(SolutionDir)Lib\$(PlatformName)\*.dll" "$(outDir)"</Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>Copying DLLs</Message>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Outputs>SDL2.dll</Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>DLL_SUFFIX=$(Configuration)_$(PlatformName);WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>NvFlowLib$(Configuration)_$(PlatformName).lib;SDL2.lib;SDL2main.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ </Link>
+ <FxCompile>
+ <EntryPointName>%(filename)</EntryPointName>
+ <ShaderModel>5.0</ShaderModel>
+ <HeaderFileOutput>$(ProjectDir)%(Filename).hlsl.h</HeaderFileOutput>
+ <ObjectFileOutput />
+ </FxCompile>
+ <CustomBuildStep>
+ <Command>copy "$(SolutionDir)external\SDL2\lib\x86\SDL2.dll" "$(outDir)"
+copy "$(SolutionDir)Lib\$(PlatformName)\*.dll" "$(outDir)"</Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>Copying DLLs</Message>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Outputs>SDL2.dll</Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>DLL_SUFFIX=$(Configuration)_$(PlatformName);NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>NvFlowLib$(Configuration)_$(PlatformName).lib;SDL2.lib;SDL2main.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
+ </Link>
+ <FxCompile>
+ <EntryPointName>%(filename)</EntryPointName>
+ <ShaderModel>5.0</ShaderModel>
+ <HeaderFileOutput>$(ProjectDir)%(Filename).hlsl.h</HeaderFileOutput>
+ <ObjectFileOutput />
+ </FxCompile>
+ <CustomBuildStep>
+ <Command>copy "$(SolutionDir)external\SDL2\lib\x64\SDL2.dll" "$(outDir)"
+copy "$(SolutionDir)Lib\$(PlatformName)\*.dll" "$(outDir)"</Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>Copying DLLs</Message>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Outputs>SDL2.dll</Outputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
+ <TargetName>$(ProjectName)$(Configuration)_$(PlatformName)</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
+ <TargetName>$(ProjectName)$(Configuration)_$(PlatformName)</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
+ <TargetName>$(ProjectName)$(Configuration)_$(PlatformName)</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
+ <TargetName>$(ProjectName)$(Configuration)_$(PlatformName)</TargetName>
+ </PropertyGroup>
+ <ItemGroup>
+ <ClCompile Include="appGraphCtxLoader.cpp" />
+ <ClCompile Include="bitmap.cpp" />
+ <ClCompile Include="computeContextLoader.cpp" />
+ <ClCompile Include="curveEditor.cpp" />
+ <ClCompile Include="imgui.cpp" />
+ <ClCompile Include="imguiGraph.cpp" />
+ <ClCompile Include="imguiGraphLoader.cpp" />
+ <ClCompile Include="imguiser.cpp" />
+ <ClCompile Include="loader.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="mesh.cpp" />
+ <ClCompile Include="meshLoader.cpp" />
+ <ClCompile Include="NvFlowInteropLoader.cpp" />
+ <ClCompile Include="scene.cpp" />
+ <ClCompile Include="scene2DTextureEmitter.cpp" />
+ <ClCompile Include="sceneCustomEmit.cpp" />
+ <ClCompile Include="sceneFlow.cpp" />
+ <ClCompile Include="sceneSDF.cpp" />
+ <ClCompile Include="sceneSimpleFlame.cpp" />
+ <ClCompile Include="sceneSimpleSmoke.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Manifest Include="app.manifest" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="appGraphCtx.h" />
+ <ClInclude Include="bitmap.h" />
+ <ClInclude Include="camera.h" />
+ <ClInclude Include="computeContext.h" />
+ <ClInclude Include="curveEditor.h" />
+ <ClInclude Include="flowShaderParams.h" />
+ <ClInclude Include="imgui.h" />
+ <ClInclude Include="imguiGraph.h" />
+ <ClInclude Include="imguiInterop.h" />
+ <ClInclude Include="imguiser.h" />
+ <ClInclude Include="loader.h" />
+ <ClInclude Include="mesh.h" />
+ <ClInclude Include="meshInterop.h" />
+ <ClInclude Include="NvFlowInterop.h" />
+ <ClInclude Include="preset0.h" />
+ <ClInclude Include="preset1.h" />
+ <ClInclude Include="presetFireBall.h" />
+ <ClInclude Include="presetFlame.h" />
+ <ClInclude Include="presetSmoke.h" />
+ <ClInclude Include="scene.h" />
+ <ClInclude Include="stb_truetype.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <FxCompile Include="..\Shaders\customEmitAllocCS.hlsl">
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customEmitEmit2CS.hlsl">
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customEmitEmitCS.hlsl">
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customLightingCS.hlsl">
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)\include;$(SolutionDir)\NvFlow;</AdditionalIncludeDirectories>
+ </FxCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/demo/DemoApp/DemoApp.vcxproj.filters b/demo/DemoApp/DemoApp.vcxproj.filters
new file mode 100644
index 0000000..94b9d93
--- /dev/null
+++ b/demo/DemoApp/DemoApp.vcxproj.filters
@@ -0,0 +1,166 @@
+<?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="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Shaders">
+ <UniqueIdentifier>{12de0363-d75b-4f29-bd10-e8b9832dd449}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="imgui.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="imguiGraph.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="loader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="imguiGraphLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="NvFlowInteropLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="bitmap.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sceneSimpleFlame.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="scene2DTextureEmitter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mesh.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="meshLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="appGraphCtxLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sceneSDF.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="curveEditor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="imguiser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="scene.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="computeContextLoader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sceneSimpleSmoke.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sceneCustomEmit.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sceneFlow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Manifest Include="app.manifest">
+ <Filter>Resource Files</Filter>
+ </Manifest>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="appGraphCtx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="scene.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mesh.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="camera.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="imgui.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="imguiGraph.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stb_truetype.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="loader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="NvFlowInterop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitmap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="meshInterop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="imguiInterop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="curveEditor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="imguiser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="preset0.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="presetFlame.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="computeContext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="preset1.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="presetSmoke.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="flowShaderParams.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="presetFireBall.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <FxCompile Include="..\Shaders\customLightingCS.hlsl">
+ <Filter>Shaders</Filter>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customEmitAllocCS.hlsl">
+ <Filter>Shaders</Filter>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customEmitEmitCS.hlsl">
+ <Filter>Shaders</Filter>
+ </FxCompile>
+ <FxCompile Include="..\Shaders\customEmitEmit2CS.hlsl">
+ <Filter>Shaders</Filter>
+ </FxCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/demo/DemoApp/NvFlowInterop.h b/demo/DemoApp/NvFlowInterop.h
new file mode 100644
index 0000000..de93a24
--- /dev/null
+++ b/demo/DemoApp/NvFlowInterop.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#ifndef NV_FLOW_INTEROP_H
+#define NV_FLOW_INTEROP_H
+
+#include "appGraphCtx.h"
+#include "NvFlow.h"
+
+NV_FLOW_API NvFlowContext* NvFlowInteropCreateContext(AppGraphCtx* appctx);
+
+NV_FLOW_API NvFlowDepthStencilView* NvFlowInteropCreateDepthStencilView(AppGraphCtx* appctx, NvFlowContext* flowctx);
+
+NV_FLOW_API NvFlowRenderTargetView* NvFlowInteropCreateRenderTargetView(AppGraphCtx* appctx, NvFlowContext* flowctx);
+
+NV_FLOW_API void NvFlowInteropUpdateContext(NvFlowContext* context, AppGraphCtx* appctx);
+
+NV_FLOW_API void NvFlowInteropUpdateDepthStencilView(NvFlowDepthStencilView* view, AppGraphCtx* appctx, NvFlowContext* flowctx);
+
+NV_FLOW_API void NvFlowInteropUpdateRenderTargetView(NvFlowRenderTargetView* view, AppGraphCtx* appctx, NvFlowContext* flowctx);
+
+#endif \ No newline at end of file
diff --git a/demo/DemoApp/NvFlowInteropLoader.cpp b/demo/DemoApp/NvFlowInteropLoader.cpp
new file mode 100644
index 0000000..6224373
--- /dev/null
+++ b/demo/DemoApp/NvFlowInteropLoader.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <SDL.h>
+
+#include "loader.h"
+
+#include "NvFlowInterop.h"
+
+namespace
+{
+ ModuleLoader<16u, SDL_LoadObject, SDL_UnloadObject, SDL_LoadFunction> g_loader;
+}
+
+void loadNvFlowInterop(AppGraphCtxType type)
+{
+ const char* moduleName = demoAppDLLName(type);
+
+ g_loader.loadModule(moduleName);
+}
+
+void unloadNvFlowInterop()
+{
+ g_loader.unloadModule();
+}
+
+// Functions
+NvFlowContext* NvFlowInteropCreateContext(AppGraphCtx* appctx)
+{
+ return g_loader.function<0>(NvFlowInteropCreateContext, "NvFlowInteropCreateContext", appctx);
+}
+
+NvFlowDepthStencilView* NvFlowInteropCreateDepthStencilView(AppGraphCtx* appctx, NvFlowContext* flowctx)
+{
+ return g_loader.function<1>(NvFlowInteropCreateDepthStencilView, "NvFlowInteropCreateDepthStencilView", appctx, flowctx);
+}
+
+NvFlowRenderTargetView* NvFlowInteropCreateRenderTargetView(AppGraphCtx* appctx, NvFlowContext* flowctx)
+{
+ return g_loader.function<2>(NvFlowInteropCreateRenderTargetView, "NvFlowInteropCreateRenderTargetView", appctx, flowctx);
+}
+
+void NvFlowInteropUpdateContext(NvFlowContext* context, AppGraphCtx* appctx)
+{
+ return g_loader.function<3>(NvFlowInteropUpdateContext, "NvFlowInteropUpdateContext", context, appctx);
+}
+
+void NvFlowInteropUpdateDepthStencilView(NvFlowDepthStencilView* view, AppGraphCtx* appctx, NvFlowContext* flowctx)
+{
+ return g_loader.function<4>(NvFlowInteropUpdateDepthStencilView, "NvFlowInteropUpdateDepthStencilView", view, appctx, flowctx);
+}
+
+void NvFlowInteropUpdateRenderTargetView(NvFlowRenderTargetView* view, AppGraphCtx* appctx, NvFlowContext* flowctx)
+{
+ return g_loader.function<5>(NvFlowInteropUpdateRenderTargetView, "NvFlowInteropUpdateRenderTargetView", view, appctx, flowctx);
+} \ No newline at end of file
diff --git a/demo/DemoApp/app.manifest b/demo/DemoApp/app.manifest
new file mode 100644
index 0000000..5dea26f
--- /dev/null
+++ b/demo/DemoApp/app.manifest
@@ -0,0 +1,7 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly> \ No newline at end of file
diff --git a/demo/DemoApp/appGraphCtx.h b/demo/DemoApp/appGraphCtx.h
new file mode 100644
index 0000000..2f41c36
--- /dev/null
+++ b/demo/DemoApp/appGraphCtx.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#define APP_GRAPH_CTX_API extern "C" __declspec(dllexport)
+
+struct SDL_Window;
+
+struct AppGraphCtx;
+
+APP_GRAPH_CTX_API AppGraphCtx* AppGraphCtxCreate(int deviceID);
+
+APP_GRAPH_CTX_API bool AppGraphCtxUpdateSize(AppGraphCtx* context, SDL_Window* window, bool fullscreen);
+
+APP_GRAPH_CTX_API void AppGraphCtxReleaseRenderTarget(AppGraphCtx* context);
+
+APP_GRAPH_CTX_API void AppGraphCtxRelease(AppGraphCtx* context);
+
+APP_GRAPH_CTX_API void AppGraphCtxFrameStart(AppGraphCtx* context, float clearColor[4]);
+
+APP_GRAPH_CTX_API void AppGraphCtxFramePresent(AppGraphCtx* context, bool fullsync);
+
+APP_GRAPH_CTX_API void AppGraphCtxWaitForFrames(AppGraphCtx* context, unsigned int maxFramesInFlight);
+
+APP_GRAPH_CTX_API void AppGraphCtxProfileEnable(AppGraphCtx* context, bool enabled);
+
+APP_GRAPH_CTX_API void AppGraphCtxProfileBegin(AppGraphCtx* context, const char* label);
+
+APP_GRAPH_CTX_API void AppGraphCtxProfileEnd(AppGraphCtx* context, const char* label);
+
+APP_GRAPH_CTX_API bool AppGraphCtxProfileGet(AppGraphCtx* context, const char** plabel, float* cpuTime, float* gpuTime, int index);
+
+APP_GRAPH_CTX_API size_t AppGraphCtxDedicatedVideoMemory(AppGraphCtx* context); \ No newline at end of file
diff --git a/demo/DemoApp/appGraphCtxLoader.cpp b/demo/DemoApp/appGraphCtxLoader.cpp
new file mode 100644
index 0000000..f724a93
--- /dev/null
+++ b/demo/DemoApp/appGraphCtxLoader.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <SDL.h>
+
+#include "loader.h"
+
+#include "appGraphCtx.h"
+
+namespace
+{
+ ModuleLoader<16u, SDL_LoadObject, SDL_UnloadObject, SDL_LoadFunction> g_loader;
+}
+
+void loadAppGraphCtx(AppGraphCtxType type)
+{
+ const char* moduleName = demoAppDLLName(type);
+
+ g_loader.loadModule(moduleName);
+}
+
+void unloadAppGraphCtx()
+{
+ g_loader.unloadModule();
+}
+
+AppGraphCtx* AppGraphCtxCreate(int deviceID)
+{
+ return g_loader.function<0>(AppGraphCtxCreate, "AppGraphCtxCreate", deviceID);
+}
+
+bool AppGraphCtxUpdateSize(AppGraphCtx* context, SDL_Window* window, bool fullscreen)
+{
+ return g_loader.function<1>(AppGraphCtxUpdateSize, "AppGraphCtxUpdateSize", context, window, fullscreen);
+}
+
+void AppGraphCtxReleaseRenderTarget(AppGraphCtx* context)
+{
+ return g_loader.function<2>(AppGraphCtxReleaseRenderTarget, "AppGraphCtxReleaseRenderTarget", context);
+}
+
+void AppGraphCtxRelease(AppGraphCtx* context)
+{
+ return g_loader.function<3>(AppGraphCtxRelease, "AppGraphCtxRelease", context);
+}
+
+void AppGraphCtxFrameStart(AppGraphCtx* context, float clearColor[4])
+{
+ return g_loader.function<4>(AppGraphCtxFrameStart, "AppGraphCtxFrameStart", context, clearColor);
+}
+
+void AppGraphCtxFramePresent(AppGraphCtx* context, bool fullsync)
+{
+ return g_loader.function<5>(AppGraphCtxFramePresent, "AppGraphCtxFramePresent", context, fullsync);
+}
+
+void AppGraphCtxWaitForFrames(AppGraphCtx* context, unsigned int maxFramesInFlight)
+{
+ return g_loader.function<6>(AppGraphCtxWaitForFrames, "AppGraphCtxWaitForFrames", context, maxFramesInFlight);
+}
+
+void AppGraphCtxProfileEnable(AppGraphCtx* context, bool enabled)
+{
+ return g_loader.function<7>(AppGraphCtxProfileEnable, "AppGraphCtxProfileEnable", context, enabled);
+}
+
+void AppGraphCtxProfileBegin(AppGraphCtx* context, const char* label)
+{
+ return g_loader.function<8>(AppGraphCtxProfileBegin, "AppGraphCtxProfileBegin", context, label);
+}
+
+void AppGraphCtxProfileEnd(AppGraphCtx* context, const char* label)
+{
+ return g_loader.function<9>(AppGraphCtxProfileEnd, "AppGraphCtxProfileEnd", context, label);
+}
+
+bool AppGraphCtxProfileGet(AppGraphCtx* context, const char** plabel, float* cpuTime, float* gpuTime, int index)
+{
+ return g_loader.function<10>(AppGraphCtxProfileGet, "AppGraphCtxProfileGet", context, plabel, cpuTime, gpuTime, index);
+}
+
+size_t AppGraphCtxDedicatedVideoMemory(AppGraphCtx* context)
+{
+ return g_loader.function<11>(AppGraphCtxDedicatedVideoMemory, "AppGraphCtxDedicatedVideoMemory", context);
+} \ No newline at end of file
diff --git a/demo/DemoApp/bitmap.cpp b/demo/DemoApp/bitmap.cpp
new file mode 100644
index 0000000..e909653
--- /dev/null
+++ b/demo/DemoApp/bitmap.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdio.h>
+
+#include "bitmap.h"
+
+Bitmap::Bitmap() : data(NULL)
+{
+
+}
+
+Bitmap::~Bitmap()
+{
+ delete[] data;
+ data = NULL;
+}
+
+int Bitmap::create(int w, int h, int bpp)
+{
+ const int imagesize = w*h*(bpp / 8);
+ headerField0 = 'B';
+ headerField1 = 'M';
+ size = 54 + imagesize;
+ reserved1 = 0;
+ reserved2 = 0;
+ offset = 54;
+ headerSize = 40;
+ width = w;
+ height = h;
+ colorPlanes = 1;
+ bitsPerPixel = bpp;
+ compressionMethod = 0;
+ imageSize = imagesize;
+ hRes = 2000;
+ vRes = 2000;
+ numColors = 0;
+ numImportantColors = 0;
+ data = new unsigned char[imagesize];
+ return 0;
+}
+
+int Bitmap::write(FILE* stream)
+{
+ if (stream == NULL || data == NULL) return -1;
+ fwrite(&headerField0, 1, 1, stream);
+ fwrite(&headerField1, 1, 1, stream);
+ fwrite(&size, 4, 1, stream);
+ fwrite(&reserved1, 2, 1, stream);
+ fwrite(&reserved2, 2, 1, stream);
+ fwrite(&offset, 4, 1, stream);
+ fwrite(&headerSize, 4, 1, stream);
+ fwrite(&width, 4, 1, stream);
+ fwrite(&height, 4, 1, stream);
+ fwrite(&colorPlanes, 2, 1, stream);
+ fwrite(&bitsPerPixel, 2, 1, stream);
+ fwrite(&compressionMethod, 4, 1, stream);
+ fwrite(&imageSize, 4, 1, stream);
+ fwrite(&hRes, 4, 1, stream);
+ fwrite(&vRes, 4, 1, stream);
+ fwrite(&numColors, 4, 1, stream);
+ fwrite(&numImportantColors, 4, 1, stream);
+
+ if (compressionMethod == 0)
+ {
+ fwrite(data, 1, imageSize, stream);
+ }
+ else
+ {
+ printf("Write format not supported\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int Bitmap::read(FILE* stream)
+{
+ if (stream == NULL) return -1;
+ size_t readCount = 0;
+ readCount += fread(&headerField0, 1, 1, stream);
+ readCount += fread(&headerField1, 1, 1, stream);
+ readCount += fread(&size, 4, 1, stream);
+ readCount += fread(&reserved1, 2, 1, stream);
+ readCount += fread(&reserved2, 2, 1, stream);
+ readCount += fread(&offset, 4, 1, stream);
+ readCount += fread(&headerSize, 4, 1, stream);
+ readCount += fread(&width, 4, 1, stream);
+ readCount += fread(&height, 4, 1, stream);
+ readCount += fread(&colorPlanes, 2, 1, stream);
+ readCount += fread(&bitsPerPixel, 2, 1, stream);
+ readCount += fread(&compressionMethod, 4, 1, stream);
+ readCount += fread(&imageSize, 4, 1, stream);
+ readCount += fread(&hRes, 4, 1, stream);
+ readCount += fread(&vRes, 4, 1, stream);
+ readCount += fread(&numColors, 4, 1, stream);
+ readCount += fread(&numImportantColors, 4, 1, stream);
+
+ if (compressionMethod == 0)
+ {
+ delete[] data;
+ data = new unsigned char[imageSize];
+ readCount += fread(data, 1, imageSize, stream);
+ }
+ else
+ {
+ printf("Write format not supported\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/demo/DemoApp/bitmap.h b/demo/DemoApp/bitmap.h
new file mode 100644
index 0000000..092c4be
--- /dev/null
+++ b/demo/DemoApp/bitmap.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+struct Bitmap
+{
+ // Header Elements
+ char headerField0, headerField1;
+ unsigned int size;
+ unsigned short reserved1;
+ unsigned short reserved2;
+ unsigned int offset;
+ unsigned int headerSize;
+ unsigned int width;
+ unsigned int height;
+ unsigned short colorPlanes;
+ unsigned short bitsPerPixel;
+ unsigned int compressionMethod;
+ unsigned int imageSize;
+ unsigned int hRes;
+ unsigned int vRes;
+ unsigned int numColors;
+ unsigned int numImportantColors;
+ // Internal
+ unsigned char* data;
+
+ Bitmap();
+ ~Bitmap();
+ int create(int w, int h, int bpp);
+ int write(FILE* stream);
+ int read(FILE* stream);
+
+};
diff --git a/demo/DemoApp/camera.h b/demo/DemoApp/camera.h
new file mode 100644
index 0000000..388d52e
--- /dev/null
+++ b/demo/DemoApp/camera.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#ifndef CAMERA_H
+#define CAMERA_H
+
+#include <stdint.h>
+#include <DirectXMath.h>
+
+struct Camera
+{
+ uint32_t rotationActive;
+ uint32_t zoomActive;
+ uint32_t translateActive;
+ int mouseXprev;
+ int mouseYprev;
+
+ float defaultZoomVal;
+ float zoomVal;
+
+ DirectX::XMMATRIX pan;
+ DirectX::XMMATRIX tilt;
+ DirectX::XMMATRIX rotation;
+ DirectX::XMMATRIX zoom;
+ DirectX::XMMATRIX translate;
+ DirectX::XMMATRIX view;
+ DirectX::XMMATRIX projection;
+
+ bool isProjectionRH = false;
+
+ void getViewMatrix(DirectX::XMMATRIX& viewMatrix)
+ {
+ view =
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixMultiply(
+ translate,
+ rotation
+ ),
+ zoom
+ );
+ if (isProjectionRH)
+ {
+ view = DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixScaling(1.f, 1.f, -1.f),
+ view
+ ),
+ DirectX::XMMatrixScaling(1.f, 1.f, -1.f)
+ );
+ }
+ viewMatrix = view;
+ }
+
+ void getProjectionMatrix(DirectX::XMMATRIX& projMatrix, int winw, int winh)
+ {
+ if (isProjectionRH)
+ {
+ projection = DirectX::XMMatrixPerspectiveFovRH(DirectX::XM_PI / 4.f, float(winw) / float(winh), 0.1f, 1000.f);
+ projMatrix = projection;
+ }
+ else
+ {
+ projection = DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PI / 4.f, float(winw) / float(winh), 0.1f, 1000.f);
+ projMatrix = projection;
+ }
+ }
+
+ void rotationStart(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ rotationActive = true;
+ }
+
+ void rotationMove(int x, int y, int winw, int winh)
+ {
+ if (rotationActive)
+ {
+ int dx = -(x - mouseXprev);
+ int dy = -(y - mouseYprev);
+
+ const float gainX = 2.f * 3.14f / (winw);
+ const float gainY = 2.f * 3.14f / (winh);
+
+ float rotx = float(gainY * dy);
+ float roty = float(gainX * dx);
+ float rotMagn = sqrtf(rotx*rotx + roty*roty);
+
+ // tilt
+ {
+ DirectX::XMVECTOR rotVec = { 1.f,0.f,0.f,0.f };
+ const float angle = rotx;
+ DirectX::XMMATRIX dtilt = DirectX::XMMatrixRotationAxis(rotVec, angle);
+ tilt = DirectX::XMMatrixMultiply(dtilt, tilt);
+ }
+ // pan
+ {
+ DirectX::XMVECTOR rotVec = { 0.f,1.f,0.f,0.f };
+ const float angle = roty;
+ DirectX::XMMATRIX dpan = DirectX::XMMatrixRotationAxis(rotVec, angle);
+ pan = DirectX::XMMatrixMultiply(dpan, pan);
+ }
+ rotation = DirectX::XMMatrixMultiply(pan, tilt);
+
+ mouseXprev = x;
+ mouseYprev = y;
+ }
+ }
+
+ void rotationEnd(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ rotationActive = false;
+ }
+
+ void zoomStart(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ zoomActive = true;
+ }
+
+ void zoomMove(int x, int y, int winw, int winh)
+ {
+ if (zoomActive)
+ {
+ float dx = -float(x - mouseXprev);
+ float dy = -float(y - mouseYprev);
+
+ const float gain = 3.14f / float(winh);
+
+ //zoom = DirectX::XMMatrixMultiply(zoom, DirectX::XMMatrixScaling(1.f, 1.f, 1.f + gain*dy));
+ zoomVal *= (1.f + gain*dy);
+ zoom = DirectX::XMMatrixTranslation(0.f, 0.f, zoomVal);
+
+ mouseXprev = x;
+ mouseYprev = y;
+ }
+ }
+
+ void zoomEnd(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ zoomActive = false;
+ }
+
+ void translateStart(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ translateActive = true;
+ }
+
+ void translateMove(int x, int y, int winw, int winh)
+ {
+ if (translateActive)
+ {
+ float dx = float(x - mouseXprev);
+ float dy = -float(y - mouseYprev);
+
+ const float gainX = isProjectionRH ? -2.f / (winw) : +2.f / (winw);
+ const float gainY = isProjectionRH ? -2.f / (winh) : +2.f / (winh);
+
+ // find rotation center in screen space
+ DirectX::XMVECTOR centerScreen = { 0.f,0.f,0.f,1.f };
+ centerScreen = DirectX::XMVector4Transform(centerScreen, DirectX::XMMatrixMultiply(zoom, projection));
+ DirectX::XMFLOAT4 centerScreen4;
+ DirectX::XMStoreFloat4(&centerScreen4, centerScreen);
+
+ // produce transform for inverse project, zoom, rotate
+ DirectX::XMVECTOR det;
+ DirectX::XMMATRIX viewProjInv =
+ DirectX::XMMatrixInverse(
+ &det,
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixMultiply(
+ rotation,
+ zoom
+ ),
+ projection
+ )
+ );
+
+ // transform screen offset to world offset
+ DirectX::XMVECTOR offsetScreen = { gainX*dx, gainY*dy, centerScreen4.z / centerScreen4.w, 1.f };
+ DirectX::XMVECTOR offsetWorld =
+ DirectX::XMVector4Transform(
+ offsetScreen,
+ viewProjInv
+ );
+ DirectX::XMFLOAT4 offsetWorld4;
+ DirectX::XMStoreFloat4(&offsetWorld4, offsetWorld);
+ offsetWorld4.x /= offsetWorld4.w;
+ offsetWorld4.y /= offsetWorld4.w;
+ offsetWorld4.z /= offsetWorld4.w;
+
+ // apply offset to net world translation
+ translate =
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixTranslation(offsetWorld4.x, offsetWorld4.y, offsetWorld4.z),
+ translate
+ );
+
+ mouseXprev = x;
+ mouseYprev = y;
+ }
+ }
+
+ void translateEnd(int x, int y)
+ {
+ mouseXprev = x;
+ mouseYprev = y;
+ translateActive = false;
+ }
+
+ void init(int winw, int winh)
+ {
+ rotationActive = 0u;
+ zoomActive = 0u;
+ translateActive = 0u;
+ defaultZoomVal = 7.f;
+ zoomVal = defaultZoomVal;
+ pan = DirectX::XMMatrixIdentity();
+ {
+ //DirectX::XMVECTOR rotVec = {1.f,0.f,0.f,0.f};
+ //const float angle = -DirectX::XM_PI / 4.f;
+ //tilt = DirectX::XMMatrixRotationAxis(rotVec,angle);
+
+ DirectX::XMVECTOR rotVec = { 1.f,0.f,0.f,0.f };
+ const float angle = 0.f;
+ tilt = DirectX::XMMatrixRotationAxis(rotVec, angle);
+ }
+ rotation = DirectX::XMMatrixMultiply(pan, tilt);
+ zoom = DirectX::XMMatrixTranslation(0.f, 0.f, zoomVal);
+ translate = DirectX::XMMatrixIdentity();
+ view = DirectX::XMMatrixIdentity();
+ projection = DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PI / 4.f, float(winw) / float(winh), 0.1f, 1000.f);
+ }
+
+ Camera()
+ {
+ init(1024, 1024);
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/demo/DemoApp/computeContext.h b/demo/DemoApp/computeContext.h
new file mode 100644
index 0000000..bd55f13
--- /dev/null
+++ b/demo/DemoApp/computeContext.h
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#pragma once
+
+#define COMPUTE_API extern "C" __declspec(dllexport)
+
+struct ComputeContextDesc;
+struct ComputeContext;
+
+struct ComputeShaderDesc
+{
+ const void* cs;
+ unsigned long long cs_length;
+};
+struct ComputeShader;
+
+struct ComputeConstantBufferDesc
+{
+ unsigned int sizeInBytes;
+};
+struct ComputeConstantBuffer;
+
+struct ComputeResourceDesc;
+struct ComputeResource;
+
+struct ComputeResourceRWDesc;
+struct ComputeResourceRW;
+
+static const unsigned int ComputeDispatchMaxResources = 16u;
+static const unsigned int ComputeDispatchMaxResourcesRW = 8u;
+
+struct ComputeDispatchParams
+{
+ ComputeShader* shader;
+ unsigned int gridDim[3u];
+ ComputeConstantBuffer* constantBuffer;
+ ComputeResource* resources[ComputeDispatchMaxResources];
+ ComputeResourceRW* resourcesRW[ComputeDispatchMaxResourcesRW];
+};
+
+COMPUTE_API ComputeContext* ComputeContextCreate(ComputeContextDesc* desc);
+
+COMPUTE_API void ComputeContextUpdate(ComputeContext* context, ComputeContextDesc* desc);
+
+COMPUTE_API void ComputeContextRelease(ComputeContext* context);
+
+
+COMPUTE_API ComputeShader* ComputeShaderCreate(ComputeContext* context, const ComputeShaderDesc* desc);
+
+COMPUTE_API void ComputeShaderRelease(ComputeShader* shader);
+
+
+COMPUTE_API ComputeConstantBuffer* ComputeConstantBufferCreate(ComputeContext* context, const ComputeConstantBufferDesc* desc);
+
+COMPUTE_API void ComputeConstantBufferRelease(ComputeConstantBuffer* constantBuffer);
+
+COMPUTE_API void* ComputeConstantBufferMap(ComputeContext* context, ComputeConstantBuffer* constantBuffer);
+
+COMPUTE_API void ComputeConstantBufferUnmap(ComputeContext* context, ComputeConstantBuffer* constantBuffer);
+
+
+COMPUTE_API ComputeResource* ComputeResourceCreate(ComputeContext* context, const ComputeResourceDesc* desc);
+
+COMPUTE_API void ComputeResourceUpdate(ComputeContext* context, ComputeResource* resource, const ComputeResourceDesc* desc);
+
+COMPUTE_API void ComputeResourceRelease(ComputeResource* resource);
+
+
+COMPUTE_API ComputeResourceRW* ComputeResourceRWCreate(ComputeContext* context, const ComputeResourceRWDesc* desc);
+
+COMPUTE_API void ComputeResourceRWUpdate(ComputeContext* context, ComputeResourceRW* resourceRW, const ComputeResourceRWDesc* desc);
+
+COMPUTE_API void ComputeResourceRWRelease(ComputeResourceRW* resourceRW);
+
+COMPUTE_API ComputeResource* ComputeResourceRWGetResource(ComputeResourceRW* resourceRW);
+
+
+COMPUTE_API void ComputeContextDispatch(ComputeContext* context, const ComputeDispatchParams* params);
+
+// interoperation with NvFlow
+struct NvFlowContext;
+struct NvFlowResource;
+struct NvFlowResourceRW;
+
+COMPUTE_API ComputeContext* ComputeContextNvFlowContextCreate(NvFlowContext* flowContext);
+
+COMPUTE_API void ComputeContextNvFlowContextUpdate(ComputeContext* computeContext, NvFlowContext* flowContext);
+
+COMPUTE_API ComputeResource* ComputeResourceNvFlowCreate(ComputeContext* context, NvFlowContext* flowContext, NvFlowResource* flowResource);
+
+COMPUTE_API void ComputeResourceNvFlowUpdate(ComputeContext* context, ComputeResource* resource, NvFlowContext* flowContext, NvFlowResource* flowResource);
+
+COMPUTE_API ComputeResourceRW* ComputeResourceRWNvFlowCreate(ComputeContext* context, NvFlowContext* flowContext, NvFlowResourceRW* flowResourceRW);
+
+COMPUTE_API void ComputeResourceRWNvFlowUpdate(ComputeContext* context, ComputeResourceRW* resourceRW, NvFlowContext* flowContext, NvFlowResourceRW* flowResourceRW); \ No newline at end of file
diff --git a/demo/DemoApp/computeContextLoader.cpp b/demo/DemoApp/computeContextLoader.cpp
new file mode 100644
index 0000000..593b2ce
--- /dev/null
+++ b/demo/DemoApp/computeContextLoader.cpp
@@ -0,0 +1,147 @@
+/*
+* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include <SDL.h>
+
+#include "loader.h"
+
+#include "computeContext.h"
+
+namespace
+{
+ ModuleLoader<32u, SDL_LoadObject, SDL_UnloadObject, SDL_LoadFunction> g_loader;
+}
+
+void loadComputeContext(AppGraphCtxType type)
+{
+ const char* moduleName = demoAppDLLName(type);
+
+ g_loader.loadModule(moduleName);
+}
+
+void unloadComputeContext()
+{
+ g_loader.unloadModule();
+}
+
+ComputeContext* ComputeContextCreate(ComputeContextDesc* desc)
+{
+ return g_loader.function<0>(ComputeContextCreate, "ComputeContextCreate", desc);
+}
+
+void ComputeContextUpdate(ComputeContext* context, ComputeContextDesc* desc)
+{
+ return g_loader.function<1>(ComputeContextUpdate, "ComputeContextUpdate", context, desc);
+}
+
+void ComputeContextRelease(ComputeContext* context)
+{
+ return g_loader.function<2>(ComputeContextRelease, "ComputeContextRelease", context);
+}
+
+ComputeShader* ComputeShaderCreate(ComputeContext* context, const ComputeShaderDesc* desc)
+{
+ return g_loader.function<3>(ComputeShaderCreate, "ComputeShaderCreate", context, desc);
+}
+
+void ComputeShaderRelease(ComputeShader* shader)
+{
+ return g_loader.function<4>(ComputeShaderRelease, "ComputeShaderRelease", shader);
+}
+
+ComputeConstantBuffer* ComputeConstantBufferCreate(ComputeContext* context, const ComputeConstantBufferDesc* desc)
+{
+ return g_loader.function<5>(ComputeConstantBufferCreate, "ComputeConstantBufferCreate", context, desc);
+}
+
+void ComputeConstantBufferRelease(ComputeConstantBuffer* constantBuffer)
+{
+ return g_loader.function<6>(ComputeConstantBufferRelease, "ComputeConstantBufferRelease", constantBuffer);
+}
+
+void* ComputeConstantBufferMap(ComputeContext* context, ComputeConstantBuffer* constantBuffer)
+{
+ return g_loader.function<7>(ComputeConstantBufferMap, "ComputeConstantBufferMap", context, constantBuffer);
+}
+
+void ComputeConstantBufferUnmap(ComputeContext* context, ComputeConstantBuffer* constantBuffer)
+{
+ return g_loader.function<8>(ComputeConstantBufferUnmap, "ComputeConstantBufferUnmap", context, constantBuffer);
+}
+
+ComputeResource* ComputeResourceCreate(ComputeContext* context, const ComputeResourceDesc* desc)
+{
+ return g_loader.function<9>(ComputeResourceCreate, "ComputeResourceCreate", context, desc);
+}
+
+void ComputeResourceUpdate(ComputeContext* context, ComputeResource* resource, const ComputeResourceDesc* desc)
+{
+ return g_loader.function<10>(ComputeResourceUpdate, "ComputeResourceUpdate", context, resource, desc);
+}
+
+void ComputeResourceRelease(ComputeResource* resource)
+{
+ return g_loader.function<11>(ComputeResourceRelease, "ComputeResourceRelease", resource);
+}
+
+ComputeResourceRW* ComputeResourceRWCreate(ComputeContext* context, const ComputeResourceRWDesc* desc)
+{
+ return g_loader.function<12>(ComputeResourceRWCreate, "ComputeResourceRWCreate", context, desc);
+}
+
+void ComputeResourceRWUpdate(ComputeContext* context, ComputeResourceRW* resourceRW, const ComputeResourceRWDesc* desc)
+{
+ return g_loader.function<13>(ComputeResourceRWUpdate, "ComputeResourceRWUpdate", context, resourceRW, desc);
+}
+
+void ComputeResourceRWRelease(ComputeResourceRW* resourceRW)
+{
+ return g_loader.function<14>(ComputeResourceRWRelease, "ComputeResourceRWRelease", resourceRW);
+}
+
+void ComputeContextDispatch(ComputeContext* context, const ComputeDispatchParams* params)
+{
+ return g_loader.function<15>(ComputeContextDispatch, "ComputeContextDispatch", context, params);
+}
+
+ComputeContext* ComputeContextNvFlowContextCreate(NvFlowContext* flowContext)
+{
+ return g_loader.function<16>(ComputeContextNvFlowContextCreate, "ComputeContextNvFlowContextCreate", flowContext);
+}
+
+void ComputeContextNvFlowContextUpdate(ComputeContext* computeContext, NvFlowContext* flowContext)
+{
+ return g_loader.function<17>(ComputeContextNvFlowContextUpdate, "ComputeContextNvFlowContextUpdate", computeContext, flowContext);
+}
+
+ComputeResource* ComputeResourceNvFlowCreate(ComputeContext* context, NvFlowContext* flowContext, NvFlowResource* flowResource)
+{
+ return g_loader.function<18>(ComputeResourceNvFlowCreate, "ComputeResourceNvFlowCreate", context, flowContext, flowResource);
+}
+
+void ComputeResourceNvFlowUpdate(ComputeContext* context, ComputeResource* resource, NvFlowContext* flowContext, NvFlowResource* flowResource)
+{
+ return g_loader.function<19>(ComputeResourceNvFlowUpdate, "ComputeResourceNvFlowUpdate", context, resource, flowContext, flowResource);
+}
+
+ComputeResourceRW* ComputeResourceRWNvFlowCreate(ComputeContext* context, NvFlowContext* flowContext, NvFlowResourceRW* flowResourceRW)
+{
+ return g_loader.function<20>(ComputeResourceRWNvFlowCreate, "ComputeResourceRWNvFlowCreate", context, flowContext, flowResourceRW);
+}
+
+void ComputeResourceRWNvFlowUpdate(ComputeContext* context, ComputeResourceRW* resourceRW, NvFlowContext* flowContext, NvFlowResourceRW* flowResourceRW)
+{
+ return g_loader.function<21>(ComputeResourceRWNvFlowUpdate, "ComputeResourceRWNvFlowUpdate", context, resourceRW, flowContext, flowResourceRW);
+}
+
+ComputeResource* ComputeResourceRWGetResource(ComputeResourceRW* resourceRW)
+{
+ return g_loader.function<22>(ComputeResourceRWGetResource, "ComputeResourceRWGetResource", resourceRW);
+} \ No newline at end of file
diff --git a/demo/DemoApp/curveEditor.cpp b/demo/DemoApp/curveEditor.cpp
new file mode 100644
index 0000000..095ca17
--- /dev/null
+++ b/demo/DemoApp/curveEditor.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "imgui.h"
+
+#include "curveEditor.h"
+
+namespace
+{
+ unsigned char colorInByte(float v)
+ {
+ const float cScale = 255.f;
+ v *= cScale;
+ if (v < 0.f) v = 0.f;
+ if (v > 255.f) v = 255.f;
+ return (unsigned char) v;
+ }
+
+ unsigned int colorInBytes(float r, float g, float b, float a)
+ {
+ return imguiRGBA(colorInByte(r), colorInByte(g), colorInByte(b), colorInByte(a));
+ }
+};
+
+bool curveEditor(CurveEditState* editState, const CurveEditParams* params)
+{
+ const float sliderWidth = 256u;
+
+ const float border = 20;
+ const float ptSize0 = 12.f;
+ const float ptOffset0 = -6.f;
+ const float ptSize1 = 9.f;
+ const float ptOffset1 = -4.5f;
+
+ float graphx = params->editorBounds.x + border;
+ float graphy = params->editorBounds.y + border;
+ float graphw = float(params->editorBounds.w - 2 * border) - sliderWidth - border;
+ float graphh = float(params->editorBounds.h - 2 * border);
+
+ float xscale = graphw / (params->rangeMax.x - params->rangeMin.x);
+ float ascale = graphh / (params->rangeMax.a - params->rangeMin.a);
+ float xoffset = -xscale * params->rangeMin.x + graphx;
+ float aoffset = -ascale * params->rangeMin.a + graphy;
+
+ bool isMouseOverPoint = false;
+ int mousePointIdx = 0;
+ int mx = params->mouseState.x;
+ int my = params->mouseState.y;
+
+ bool modified = false;
+ {
+ // make a copy of the active point, in case it is modified
+ editState->point = params->points[editState->activePointIndex];
+ }
+
+ // draw graph backgroud
+ {
+ imguiDrawRoundedRect(
+ (float)params->editorBounds.x,
+ (float)params->editorBounds.y,
+ (float)params->editorBounds.w - sliderWidth - border,
+ (float)params->editorBounds.h,
+ 6.f,
+ imguiRGBA(0, 0, 0, 192)
+ );
+ }
+
+ // draw border
+ {
+ float pts[4][2] = {
+ { graphx, graphy },
+ { graphx + graphw, graphy },
+ { graphx + graphw, graphy + graphh },
+ { graphx, graphy + graphh }
+ };
+ imguiDrawLine(pts[0][0], pts[0][1], pts[1][0], pts[1][1], 2.f, 0xCFCFCFCF);
+ imguiDrawLine(pts[1][0], pts[1][1], pts[2][0], pts[2][1], 2.f, 0xCFCFCFCF);
+ imguiDrawLine(pts[2][0], pts[2][1], pts[3][0], pts[3][1], 2.f, 0xCFCFCFCF);
+ imguiDrawLine(pts[3][0], pts[3][1], pts[0][0], pts[0][1], 2.f, 0xCFCFCFCF);
+ }
+
+ // process mouse input
+ {
+ // check if mouse is still active
+ if ((params->mouseState.but & IMGUI_MBUT_LEFT) == 0)
+ {
+ editState->pointMoveActive = false;
+ }
+ // check for overlap
+ if (!editState->pointMoveActive)
+ {
+ for (unsigned int i = 0; i < params->numPoints; i++)
+ {
+ CurvePoint& pt = params->points[i];
+
+ float x = xscale * pt.x + xoffset;
+ float a = ascale * pt.a + aoffset;
+
+ // check if mouse overlaps point
+ if (float(mx) >= x + ptOffset0 && float(mx) <= x - ptOffset0 &&
+ float(my) >= a + ptOffset0 && float(my) <= a - ptOffset0)
+ {
+ isMouseOverPoint = true;
+ mousePointIdx = i;
+ }
+ }
+ }
+ // support dragging points
+ if (isMouseOverPoint)
+ {
+ if (params->mouseState.but & IMGUI_MBUT_LEFT)
+ {
+ if (editState->activePointIndex != mousePointIdx)
+ {
+ editState->activePointIndex = mousePointIdx;
+ editState->point = params->points[editState->activePointIndex];
+ }
+ if (!editState->pointMoveActive)
+ {
+ editState->pointMoveActive = true;
+ editState->pointMoveX = mx;
+ editState->pointMoveY = my;
+ }
+ }
+ }
+ if (editState->pointMoveActive)
+ {
+ CurvePoint& pt = params->points[editState->activePointIndex];
+
+ int dmx = mx - editState->pointMoveX;
+ int dmy = my - editState->pointMoveY;
+ editState->pointMoveX = mx;
+ editState->pointMoveY = my;
+
+ // inverse transform
+ float dx = dmx / xscale;
+ float da = dmy / ascale;
+
+ auto& point = editState->point;
+ point = pt;
+ point.x += dx;
+ point.a += da;
+
+ modified = true;
+ }
+ }
+
+ // draw lines and points
+ {
+ float x0, a0, x1, a1;
+ {
+ CurvePoint& pt = params->points[0];
+
+ x0 = xscale * pt.x + xoffset;
+ a0 = ascale * pt.a + aoffset;
+ }
+ for (unsigned int i = 1; i < params->numPoints; i++)
+ {
+ CurvePoint& pt = params->points[i];
+
+ // scale based on min max
+ x1 = xscale * pt.x + xoffset;
+ a1 = ascale * pt.a + aoffset;
+
+ imguiDrawLine(x0, a0, x1, a1, 2.f, 0xFFFFFFFF);
+
+ x0 = x1;
+ a0 = a1;
+ }
+
+ int activeIdx = editState->activePointIndex;
+ unsigned int activeColor = imguiRGBA(255, 196, 0, 255);
+ for (unsigned int i = 0; i < params->numPoints; i++)
+ {
+ CurvePoint& pt = params->points[i];
+
+ float x = xscale * pt.x + xoffset;
+ float a = ascale * pt.a + aoffset;
+
+ imguiDrawRect(x + ptOffset0, a + ptOffset0, ptSize0, ptSize0, (i == activeIdx) ? activeColor : 0xFFFFFFFF);
+ imguiDrawRect(x + ptOffset1, a + ptOffset1, ptSize1, ptSize1, colorInBytes(pt.r, pt.g, pt.b, 1.f));
+ }
+ // highlight mouse point as needed
+ if (isMouseOverPoint)
+ {
+ unsigned int mouseColor = imguiRGBA(255, 196, 0, 128);
+
+ CurvePoint& pt = params->points[mousePointIdx];
+
+ float x = xscale * pt.x + xoffset;
+ float a = ascale * pt.a + aoffset;
+
+ imguiDrawRect(x + ptOffset0, a + ptOffset0, ptSize0, ptSize0, mouseColor);
+ }
+ }
+
+ // sliders
+ {
+ static int scroll = 0;
+
+ imguiBeginScrollArea("Curve Editor",
+ int(graphx + graphw + 2 * border), int(params->editorBounds.y),
+ int(params->editorBounds.w - graphw - 3*border), int(params->editorBounds.h),
+ &scroll);
+
+ // keep active index valid
+ if (editState->activePointIndex >= (int)params->numPoints)
+ {
+ editState->activePointIndex = params->numPoints - 1;
+ if (editState->activePointIndex < 0) editState->activePointIndex = 0;
+ }
+
+ float val = float(editState->activePointIndex);
+ if(imguiSlider("Active Point ID", &val, 0.f, float(params->numPoints) - 1.f, 1.f, true))
+ {
+ editState->activePointIndex = int(val);
+ editState->point = params->points[editState->activePointIndex];
+ }
+
+ imguiSeparatorLine();
+
+ // get active point data
+ auto& point = editState->point;
+
+ if (imguiSlider("x", &point.x, params->rangeMin.x, params->rangeMax.x, 0.01f, true)) modified = true;
+ if (imguiSlider("r", &point.r, params->rangeMin.r, params->rangeMax.r, 0.01f, true)) modified = true;
+ if (imguiSlider("g", &point.g, params->rangeMin.g, params->rangeMax.g, 0.01f, true)) modified = true;
+ if (imguiSlider("b", &point.b, params->rangeMin.b, params->rangeMax.b, 0.01f, true)) modified = true;
+ if (imguiSlider("a", &point.a, params->rangeMin.a, params->rangeMax.a, 0.01f, true)) modified = true;
+
+ // enforce constraints
+ {
+ int activeIdx = editState->activePointIndex;
+
+ // do not allow points to cross with their neighbors
+ if (activeIdx > 0)
+ {
+ float xmin = params->points[activeIdx - 1].x;
+ if (point.x < xmin)
+ {
+ point.x = xmin;
+ modified = true;
+ }
+ }
+ if (activeIdx + 1 < (int)params->numPoints)
+ {
+ float xmax = params->points[activeIdx + 1].x;
+ if (point.x > xmax)
+ {
+ point.x = xmax;
+ modified = true;
+ }
+ }
+
+ // enforce that curve must span x range
+ {
+ if (activeIdx == 0)
+ {
+ point.x = params->rangeMin.x;
+ modified = true;
+ }
+ if (activeIdx == params->numPoints - 1)
+ {
+ point.x = params->rangeMax.x;
+ modified = true;
+ }
+ }
+ }
+
+ editState->action = modified ? CURVE_POINT_MODIFY : CURVE_POINT_NO_ACTION;
+
+ if (imguiButton("Add Point", true))
+ {
+ editState->action = CURVE_POINT_INSERT;
+ // generate interpolated new point
+ int bidx = editState->activePointIndex + 1;
+ if (bidx >= (int)params->numPoints)
+ {
+ bidx = editState->activePointIndex;
+ }
+ else
+ {
+ editState->activePointIndex++;
+ }
+
+ const auto ptb = params->points[bidx];
+ point.x = 0.5f * point.x + 0.5f * ptb.x;
+ point.r = 0.5f * point.r + 0.5f * ptb.r;
+ point.g = 0.5f * point.g + 0.5f * ptb.g;
+ point.b = 0.5f * point.b + 0.5f * ptb.b;
+ point.a = 0.5f * point.a + 0.5f * ptb.a;
+ }
+
+ if (imguiButton("Remove Point", true))
+ {
+ // ignore if 2 or less
+ if (params->numPoints > 2)
+ {
+ editState->action = CURVE_POINT_REMOVE;
+ }
+ }
+
+ imguiEndScrollArea();
+ }
+
+ return (editState->action != CURVE_POINT_NO_ACTION);
+} \ No newline at end of file
diff --git a/demo/DemoApp/curveEditor.h b/demo/DemoApp/curveEditor.h
new file mode 100644
index 0000000..f20fb5b
--- /dev/null
+++ b/demo/DemoApp/curveEditor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+struct CurveMouseState
+{
+ int x;
+ int y;
+ unsigned char but;
+};
+
+struct CurveEditorBounds
+{
+ int x, y, w, h;
+};
+
+struct CurvePoint
+{
+ float x;
+ float r, g, b, a;
+};
+
+enum CurvePointAction
+{
+ CURVE_POINT_NO_ACTION,
+ CURVE_POINT_MODIFY,
+ CURVE_POINT_INSERT,
+ CURVE_POINT_REMOVE,
+};
+
+struct CurveEditParams
+{
+ CurveMouseState mouseState;
+ CurveEditorBounds editorBounds;
+ CurvePoint rangeMin;
+ CurvePoint rangeMax;
+ CurvePoint* points;
+ unsigned int numPoints;
+};
+
+struct CurveEditState
+{
+ int activePointIndex;
+ int action;
+ bool pointMoveActive;
+ int pointMoveX;
+ int pointMoveY;
+ CurvePoint point;
+};
+
+bool curveEditor(CurveEditState* editState, const CurveEditParams* params); \ No newline at end of file
diff --git a/demo/DemoApp/customEmitAllocCS.hlsl.h b/demo/DemoApp/customEmitAllocCS.hlsl.h
new file mode 100644
index 0000000..64e7d9e
--- /dev/null
+++ b/demo/DemoApp/customEmitAllocCS.hlsl.h
@@ -0,0 +1,225 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer params
+// {
+//
+// uint4 minMaskIdx; // Offset: 0 Size: 16
+// uint4 maxMaskIdx; // Offset: 16 Size: 16
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// maskUAV UAV uint 3d u0 1
+// params cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Input
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Output
+cs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[2], immediateIndexed
+dcl_uav_typed_texture3d (uint,uint,uint,uint) u0
+dcl_input vThreadID.xyz
+dcl_temps 2
+dcl_thread_group 8, 8, 8
+iadd r0.xyzw, vThreadID.xyzz, cb0[0].xyzz
+ige r1.xyz, r0.xywx, cb0[0].xyzx
+and r1.x, r1.y, r1.x
+and r1.x, r1.z, r1.x
+ilt r1.yzw, r0.xxyw, cb0[1].xxyz
+and r1.y, r1.z, r1.y
+and r1.y, r1.w, r1.y
+and r1.x, r1.y, r1.x
+if_nz r1.x
+ store_uav_typed u0.xyzw, r0.xyzw, l(1,1,1,1)
+endif
+ret
+// Approximately 12 instruction slots used
+#endif
+
+const BYTE g_customEmitAllocCS[] =
+{
+ 68, 88, 66, 67, 40, 49,
+ 206, 141, 171, 96, 209, 139,
+ 236, 95, 146, 56, 48, 52,
+ 47, 50, 1, 0, 0, 0,
+ 212, 3, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 160, 1, 0, 0, 176, 1,
+ 0, 0, 192, 1, 0, 0,
+ 56, 3, 0, 0, 82, 68,
+ 69, 70, 100, 1, 0, 0,
+ 1, 0, 0, 0, 140, 0,
+ 0, 0, 2, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 83, 67, 0, 1, 0, 0,
+ 59, 1, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 124, 0, 0, 0, 4, 0,
+ 0, 0, 4, 0, 0, 0,
+ 8, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 132, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 109, 97,
+ 115, 107, 85, 65, 86, 0,
+ 112, 97, 114, 97, 109, 115,
+ 0, 171, 132, 0, 0, 0,
+ 2, 0, 0, 0, 164, 0,
+ 0, 0, 32, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 244, 0, 0, 0,
+ 0, 0, 0, 0, 16, 0,
+ 0, 0, 2, 0, 0, 0,
+ 12, 1, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 48, 1, 0, 0, 16, 0,
+ 0, 0, 16, 0, 0, 0,
+ 2, 0, 0, 0, 12, 1,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 109, 105,
+ 110, 77, 97, 115, 107, 73,
+ 100, 120, 0, 78, 118, 70,
+ 108, 111, 119, 85, 105, 110,
+ 116, 52, 0, 171, 1, 0,
+ 19, 0, 1, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 255, 0, 0, 0, 109, 97,
+ 120, 77, 97, 115, 107, 73,
+ 100, 120, 0, 77, 105, 99,
+ 114, 111, 115, 111, 102, 116,
+ 32, 40, 82, 41, 32, 72,
+ 76, 83, 76, 32, 83, 104,
+ 97, 100, 101, 114, 32, 67,
+ 111, 109, 112, 105, 108, 101,
+ 114, 32, 49, 48, 46, 49,
+ 0, 171, 73, 83, 71, 78,
+ 8, 0, 0, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 79, 83, 71, 78, 8, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 83, 72,
+ 69, 88, 112, 1, 0, 0,
+ 80, 0, 5, 0, 92, 0,
+ 0, 0, 106, 8, 0, 1,
+ 89, 0, 0, 4, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 156, 40,
+ 0, 4, 0, 224, 17, 0,
+ 0, 0, 0, 0, 68, 68,
+ 0, 0, 95, 0, 0, 2,
+ 114, 0, 2, 0, 104, 0,
+ 0, 2, 2, 0, 0, 0,
+ 155, 0, 0, 4, 8, 0,
+ 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 30, 0,
+ 0, 7, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 10,
+ 2, 0, 70, 138, 32, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 8,
+ 114, 0, 16, 0, 1, 0,
+ 0, 0, 70, 3, 16, 0,
+ 0, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 1, 0, 0, 7,
+ 18, 0, 16, 0, 1, 0,
+ 0, 0, 42, 0, 16, 0,
+ 1, 0, 0, 0, 10, 0,
+ 16, 0, 1, 0, 0, 0,
+ 34, 0, 0, 8, 226, 0,
+ 16, 0, 1, 0, 0, 0,
+ 6, 13, 16, 0, 0, 0,
+ 0, 0, 6, 137, 32, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 7,
+ 34, 0, 16, 0, 1, 0,
+ 0, 0, 42, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 1, 0, 0, 7, 34, 0,
+ 16, 0, 1, 0, 0, 0,
+ 58, 0, 16, 0, 1, 0,
+ 0, 0, 26, 0, 16, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 31, 0, 4, 3,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 164, 0, 0, 10,
+ 242, 224, 17, 0, 0, 0,
+ 0, 0, 70, 14, 16, 0,
+ 0, 0, 0, 0, 2, 64,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 21, 0, 0, 1, 62, 0,
+ 0, 1, 83, 84, 65, 84,
+ 148, 0, 0, 0, 12, 0,
+ 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 5, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0
+};
diff --git a/demo/DemoApp/customEmitEmit2CS.hlsl.h b/demo/DemoApp/customEmitEmit2CS.hlsl.h
new file mode 100644
index 0000000..7bbd512
--- /dev/null
+++ b/demo/DemoApp/customEmitEmit2CS.hlsl.h
@@ -0,0 +1,503 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer params
+// {
+//
+// struct NvFlowShaderPointParams
+// {
+//
+// uint4 isVTR; // Offset: 0
+// uint4 blockDim; // Offset: 16
+// uint4 blockDimBits; // Offset: 32
+// uint4 poolGridDim; // Offset: 48
+// uint4 gridDim; // Offset: 64
+//
+// } customEmitParams; // Offset: 0 Size: 80
+// uint4 minVidx; // Offset: 80 Size: 16
+// uint4 maxVidx; // Offset: 96 Size: 16
+// float4 targetValue; // Offset: 112 Size: 16
+// float4 blendRate; // Offset: 128 Size: 16
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// blockList texture uint buf t0 1
+// blockTable texture uint 3d t1 1
+// dataSRV texture float4 3d t2 1
+// dataUAV UAV float4 3d u0 1
+// params cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Input
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Output
+cs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[9], immediateIndexed
+dcl_resource_buffer (uint,uint,uint,uint) t0
+dcl_resource_texture3d (uint,uint,uint,uint) t1
+dcl_resource_texture3d (float,float,float,float) t2
+dcl_uav_typed_texture3d (float,float,float,float) u0
+dcl_input vThreadID.xyz
+dcl_temps 6
+dcl_thread_group 8, 8, 8
+ushr r0.x, vThreadID.x, cb0[2].x
+ld_indexable(buffer)(uint,uint,uint,uint) r0.x, r0.xxxx, t0.xyzw
+not r0.x, r0.x
+and r1.x, r0.x, l(1023)
+ubfe r1.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r0.xxxx
+ishl r0.xyz, r1.xyzx, cb0[2].xyzx
+iadd r1.xyz, cb0[1].xyzx, l(-1, -1, -1, 0)
+and r2.xyz, r1.xyzx, vThreadID.xyzx
+or r0.xyz, r0.xyzx, r2.xyzx
+if_nz cb0[0].x
+ mov r2.xyz, r0.xyzx
+else
+ ishr r3.xyz, r0.xyzx, cb0[2].xyzx
+ mov r3.w, l(0)
+ ld_indexable(texture3d)(uint,uint,uint,uint) r0.w, r3.xyzw, t1.yzwx
+ not r0.w, r0.w
+ and r3.x, r0.w, l(1023)
+ ubfe r3.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r0.wwww
+ ishl r3.xyz, r3.xyzx, cb0[2].xyzx
+ and r1.xyz, r1.xyzx, r0.xyzx
+ or r2.xyz, r1.xyzx, r3.xyzx
+endif
+mov r2.w, l(0)
+ld_indexable(texture3d)(float,float,float,float) r1.xyzw, r2.xyzw, t2.xyzw
+ige r3.xyz, r0.xyzx, cb0[5].xyzx
+and r0.w, r3.y, r3.x
+and r0.w, r3.z, r0.w
+ilt r0.xyz, r0.xyzx, cb0[6].xyzx
+and r0.x, r0.y, r0.x
+and r0.x, r0.z, r0.x
+and r0.x, r0.x, r0.w
+add r3.xyzw, -cb0[8].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000)
+mul r4.xyzw, cb0[7].xyzw, cb0[8].xyzw
+mad r5.xyzw, r3.xyzw, r1.xyzw, r4.xyzw
+mad r3.xyzw, r3.xyzw, r5.xyzw, r4.xyzw
+movc r0.xyzw, r0.xxxx, r3.xyzw, r1.xyzw
+store_uav_typed u0.xyzw, r2.xyzz, r0.xyzw
+ret
+// Approximately 38 instruction slots used
+#endif
+
+const BYTE g_customEmitEmit2CS[] =
+{
+ 68, 88, 66, 67, 63, 249,
+ 53, 68, 110, 243, 167, 44,
+ 138, 46, 81, 217, 135, 232,
+ 162, 70, 1, 0, 0, 0,
+ 80, 9, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 184, 3, 0, 0, 200, 3,
+ 0, 0, 216, 3, 0, 0,
+ 180, 8, 0, 0, 82, 68,
+ 69, 70, 124, 3, 0, 0,
+ 1, 0, 0, 0, 8, 1,
+ 0, 0, 5, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 83, 67, 0, 1, 0, 0,
+ 82, 3, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 220, 0, 0, 0, 2, 0,
+ 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 230, 0, 0, 0,
+ 2, 0, 0, 0, 4, 0,
+ 0, 0, 8, 0, 0, 0,
+ 255, 255, 255, 255, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 241, 0,
+ 0, 0, 2, 0, 0, 0,
+ 5, 0, 0, 0, 8, 0,
+ 0, 0, 255, 255, 255, 255,
+ 2, 0, 0, 0, 1, 0,
+ 0, 0, 13, 0, 0, 0,
+ 249, 0, 0, 0, 4, 0,
+ 0, 0, 5, 0, 0, 0,
+ 8, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 13, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 98, 108,
+ 111, 99, 107, 76, 105, 115,
+ 116, 0, 98, 108, 111, 99,
+ 107, 84, 97, 98, 108, 101,
+ 0, 100, 97, 116, 97, 83,
+ 82, 86, 0, 100, 97, 116,
+ 97, 85, 65, 86, 0, 112,
+ 97, 114, 97, 109, 115, 0,
+ 1, 1, 0, 0, 5, 0,
+ 0, 0, 32, 1, 0, 0,
+ 144, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 232, 1, 0, 0, 0, 0,
+ 0, 0, 80, 0, 0, 0,
+ 2, 0, 0, 0, 176, 2,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 212, 2,
+ 0, 0, 80, 0, 0, 0,
+ 16, 0, 0, 0, 2, 0,
+ 0, 0, 220, 2, 0, 0,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 0, 3, 0, 0,
+ 96, 0, 0, 0, 16, 0,
+ 0, 0, 2, 0, 0, 0,
+ 220, 2, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 8, 3, 0, 0, 112, 0,
+ 0, 0, 16, 0, 0, 0,
+ 2, 0, 0, 0, 36, 3,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 72, 3,
+ 0, 0, 128, 0, 0, 0,
+ 16, 0, 0, 0, 2, 0,
+ 0, 0, 36, 3, 0, 0,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 99, 117, 115, 116,
+ 111, 109, 69, 109, 105, 116,
+ 80, 97, 114, 97, 109, 115,
+ 0, 78, 118, 70, 108, 111,
+ 119, 83, 104, 97, 100, 101,
+ 114, 80, 111, 105, 110, 116,
+ 80, 97, 114, 97, 109, 115,
+ 0, 105, 115, 86, 84, 82,
+ 0, 78, 118, 70, 108, 111,
+ 119, 85, 105, 110, 116, 52,
+ 0, 171, 1, 0, 19, 0,
+ 1, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 23, 2,
+ 0, 0, 98, 108, 111, 99,
+ 107, 68, 105, 109, 0, 98,
+ 108, 111, 99, 107, 68, 105,
+ 109, 66, 105, 116, 115, 0,
+ 112, 111, 111, 108, 71, 114,
+ 105, 100, 68, 105, 109, 0,
+ 103, 114, 105, 100, 68, 105,
+ 109, 0, 171, 171, 17, 2,
+ 0, 0, 36, 2, 0, 0,
+ 0, 0, 0, 0, 72, 2,
+ 0, 0, 36, 2, 0, 0,
+ 16, 0, 0, 0, 81, 2,
+ 0, 0, 36, 2, 0, 0,
+ 32, 0, 0, 0, 94, 2,
+ 0, 0, 36, 2, 0, 0,
+ 48, 0, 0, 0, 106, 2,
+ 0, 0, 36, 2, 0, 0,
+ 64, 0, 0, 0, 5, 0,
+ 0, 0, 1, 0, 20, 0,
+ 0, 0, 5, 0, 116, 2,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 249, 1, 0, 0, 109, 105,
+ 110, 86, 105, 100, 120, 0,
+ 1, 0, 19, 0, 1, 0,
+ 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 23, 2, 0, 0,
+ 109, 97, 120, 86, 105, 100,
+ 120, 0, 116, 97, 114, 103,
+ 101, 116, 86, 97, 108, 117,
+ 101, 0, 78, 118, 70, 108,
+ 111, 119, 70, 108, 111, 97,
+ 116, 52, 0, 171, 171, 171,
+ 1, 0, 3, 0, 1, 0,
+ 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 20, 3, 0, 0,
+ 98, 108, 101, 110, 100, 82,
+ 97, 116, 101, 0, 77, 105,
+ 99, 114, 111, 115, 111, 102,
+ 116, 32, 40, 82, 41, 32,
+ 72, 76, 83, 76, 32, 83,
+ 104, 97, 100, 101, 114, 32,
+ 67, 111, 109, 112, 105, 108,
+ 101, 114, 32, 49, 48, 46,
+ 49, 0, 171, 171, 73, 83,
+ 71, 78, 8, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0,
+ 0, 0, 79, 83, 71, 78,
+ 8, 0, 0, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 83, 72, 69, 88, 212, 4,
+ 0, 0, 80, 0, 5, 0,
+ 53, 1, 0, 0, 106, 8,
+ 0, 1, 89, 0, 0, 4,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 9, 0, 0, 0,
+ 88, 8, 0, 4, 0, 112,
+ 16, 0, 0, 0, 0, 0,
+ 68, 68, 0, 0, 88, 40,
+ 0, 4, 0, 112, 16, 0,
+ 1, 0, 0, 0, 68, 68,
+ 0, 0, 88, 40, 0, 4,
+ 0, 112, 16, 0, 2, 0,
+ 0, 0, 85, 85, 0, 0,
+ 156, 40, 0, 4, 0, 224,
+ 17, 0, 0, 0, 0, 0,
+ 85, 85, 0, 0, 95, 0,
+ 0, 2, 114, 0, 2, 0,
+ 104, 0, 0, 2, 6, 0,
+ 0, 0, 155, 0, 0, 4,
+ 8, 0, 0, 0, 8, 0,
+ 0, 0, 8, 0, 0, 0,
+ 85, 0, 0, 7, 18, 0,
+ 16, 0, 0, 0, 0, 0,
+ 10, 0, 2, 0, 10, 128,
+ 32, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 45, 0,
+ 0, 137, 66, 0, 0, 128,
+ 3, 17, 17, 0, 18, 0,
+ 16, 0, 0, 0, 0, 0,
+ 6, 0, 16, 0, 0, 0,
+ 0, 0, 70, 126, 16, 0,
+ 0, 0, 0, 0, 59, 0,
+ 0, 5, 18, 0, 16, 0,
+ 0, 0, 0, 0, 10, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 0, 0, 7, 18, 0,
+ 16, 0, 1, 0, 0, 0,
+ 10, 0, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 255, 3, 0, 0, 138, 0,
+ 0, 15, 98, 0, 16, 0,
+ 1, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0,
+ 20, 0, 0, 0, 0, 0,
+ 0, 0, 6, 0, 16, 0,
+ 0, 0, 0, 0, 41, 0,
+ 0, 8, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 1, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 30, 0, 0, 11, 114, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 2, 64, 0, 0, 255, 255,
+ 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 1, 0, 0, 6,
+ 114, 0, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 0,
+ 1, 0, 0, 0, 70, 2,
+ 2, 0, 60, 0, 0, 7,
+ 114, 0, 16, 0, 0, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 2, 0, 0, 0,
+ 31, 0, 4, 4, 10, 128,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 5, 114, 0, 16, 0,
+ 2, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 18, 0, 0, 1, 42, 0,
+ 0, 8, 114, 0, 16, 0,
+ 3, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 54, 0, 0, 5, 130, 0,
+ 16, 0, 3, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 0, 0, 45, 0, 0, 137,
+ 66, 1, 0, 128, 3, 17,
+ 17, 0, 130, 0, 16, 0,
+ 0, 0, 0, 0, 70, 14,
+ 16, 0, 3, 0, 0, 0,
+ 150, 115, 16, 0, 1, 0,
+ 0, 0, 59, 0, 0, 5,
+ 130, 0, 16, 0, 0, 0,
+ 0, 0, 58, 0, 16, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 3, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 64, 0, 0, 255, 3,
+ 0, 0, 138, 0, 0, 15,
+ 98, 0, 16, 0, 3, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 0, 0, 10, 0,
+ 0, 0, 10, 0, 0, 0,
+ 0, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 20, 0,
+ 0, 0, 0, 0, 0, 0,
+ 246, 15, 16, 0, 0, 0,
+ 0, 0, 41, 0, 0, 8,
+ 114, 0, 16, 0, 3, 0,
+ 0, 0, 70, 2, 16, 0,
+ 3, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 1, 0,
+ 0, 7, 114, 0, 16, 0,
+ 1, 0, 0, 0, 70, 2,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 60, 0, 0, 7,
+ 114, 0, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 0,
+ 1, 0, 0, 0, 70, 2,
+ 16, 0, 3, 0, 0, 0,
+ 21, 0, 0, 1, 54, 0,
+ 0, 5, 130, 0, 16, 0,
+ 2, 0, 0, 0, 1, 64,
+ 0, 0, 0, 0, 0, 0,
+ 45, 0, 0, 137, 66, 1,
+ 0, 128, 67, 85, 21, 0,
+ 242, 0, 16, 0, 1, 0,
+ 0, 0, 70, 14, 16, 0,
+ 2, 0, 0, 0, 70, 126,
+ 16, 0, 2, 0, 0, 0,
+ 33, 0, 0, 8, 114, 0,
+ 16, 0, 3, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 5, 0,
+ 0, 0, 1, 0, 0, 7,
+ 130, 0, 16, 0, 0, 0,
+ 0, 0, 26, 0, 16, 0,
+ 3, 0, 0, 0, 10, 0,
+ 16, 0, 3, 0, 0, 0,
+ 1, 0, 0, 7, 130, 0,
+ 16, 0, 0, 0, 0, 0,
+ 42, 0, 16, 0, 3, 0,
+ 0, 0, 58, 0, 16, 0,
+ 0, 0, 0, 0, 34, 0,
+ 0, 8, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 6, 0, 0, 0,
+ 1, 0, 0, 7, 18, 0,
+ 16, 0, 0, 0, 0, 0,
+ 26, 0, 16, 0, 0, 0,
+ 0, 0, 10, 0, 16, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 0, 0, 0, 0, 42, 0,
+ 16, 0, 0, 0, 0, 0,
+ 10, 0, 16, 0, 0, 0,
+ 0, 0, 1, 0, 0, 7,
+ 18, 0, 16, 0, 0, 0,
+ 0, 0, 10, 0, 16, 0,
+ 0, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 12, 242, 0,
+ 16, 0, 3, 0, 0, 0,
+ 70, 142, 32, 128, 65, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 128, 63,
+ 0, 0, 128, 63, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 56, 0, 0, 9, 242, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 7, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 50, 0, 0, 9, 242, 0,
+ 16, 0, 5, 0, 0, 0,
+ 70, 14, 16, 0, 3, 0,
+ 0, 0, 70, 14, 16, 0,
+ 1, 0, 0, 0, 70, 14,
+ 16, 0, 4, 0, 0, 0,
+ 50, 0, 0, 9, 242, 0,
+ 16, 0, 3, 0, 0, 0,
+ 70, 14, 16, 0, 3, 0,
+ 0, 0, 70, 14, 16, 0,
+ 5, 0, 0, 0, 70, 14,
+ 16, 0, 4, 0, 0, 0,
+ 55, 0, 0, 9, 242, 0,
+ 16, 0, 0, 0, 0, 0,
+ 6, 0, 16, 0, 0, 0,
+ 0, 0, 70, 14, 16, 0,
+ 3, 0, 0, 0, 70, 14,
+ 16, 0, 1, 0, 0, 0,
+ 164, 0, 0, 7, 242, 224,
+ 17, 0, 0, 0, 0, 0,
+ 70, 10, 16, 0, 2, 0,
+ 0, 0, 70, 14, 16, 0,
+ 0, 0, 0, 0, 62, 0,
+ 0, 1, 83, 84, 65, 84,
+ 148, 0, 0, 0, 38, 0,
+ 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 4, 0, 0, 0,
+ 6, 0, 0, 0, 14, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0
+};
diff --git a/demo/DemoApp/customEmitEmitCS.hlsl.h b/demo/DemoApp/customEmitEmitCS.hlsl.h
new file mode 100644
index 0000000..aad9db6
--- /dev/null
+++ b/demo/DemoApp/customEmitEmitCS.hlsl.h
@@ -0,0 +1,431 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer params
+// {
+//
+// struct NvFlowShaderPointParams
+// {
+//
+// uint4 isVTR; // Offset: 0
+// uint4 blockDim; // Offset: 16
+// uint4 blockDimBits; // Offset: 32
+// uint4 poolGridDim; // Offset: 48
+// uint4 gridDim; // Offset: 64
+//
+// } customEmitParams; // Offset: 0 Size: 80
+// uint4 minVidx; // Offset: 80 Size: 16
+// uint4 maxVidx; // Offset: 96 Size: 16
+// float4 targetValue; // Offset: 112 Size: 16
+// float4 blendRate; // Offset: 128 Size: 16
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// blockTable texture uint 3d t1 1
+// dataSRV texture float4 3d t2 1
+// dataUAV UAV float4 3d u0 1
+// params cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Input
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Output
+cs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[9], immediateIndexed
+dcl_resource_texture3d (uint,uint,uint,uint) t1
+dcl_resource_texture3d (float,float,float,float) t2
+dcl_uav_typed_texture3d (float,float,float,float) u0
+dcl_input vThreadID.xyz
+dcl_temps 4
+dcl_thread_group 8, 8, 8
+iadd r0.xyz, vThreadID.xyzx, cb0[5].xyzx
+ige r1.xyz, r0.xyzx, cb0[5].xyzx
+and r1.x, r1.y, r1.x
+and r1.x, r1.z, r1.x
+ilt r1.yzw, r0.xxyz, cb0[6].xxyz
+and r1.y, r1.z, r1.y
+and r1.y, r1.w, r1.y
+and r1.x, r1.y, r1.x
+if_nz r1.x
+ if_z cb0[0].x
+ ishr r1.xyz, r0.xyzx, cb0[2].xyzx
+ mov r1.w, l(0)
+ ld_indexable(texture3d)(uint,uint,uint,uint) r1.x, r1.xyzw, t1.xyzw
+ not r1.x, r1.x
+ and r2.x, r1.x, l(1023)
+ ubfe r2.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r1.xxxx
+ ishl r1.xyz, r2.xyzx, cb0[2].xyzx
+ iadd r2.xyz, cb0[1].xyzx, l(-1, -1, -1, 0)
+ and r2.xyz, r0.xyzx, r2.xyzx
+ or r0.xyz, r1.xyzx, r2.xyzx
+ endif
+ mov r0.w, l(0)
+ ld_indexable(texture3d)(float,float,float,float) r1.xyzw, r0.xyzw, t2.xyzw
+ add r2.xyzw, -cb0[8].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000)
+ mul r3.xyzw, cb0[7].xyzw, cb0[8].xyzw
+ mad r1.xyzw, r2.xyzw, r1.xyzw, r3.xyzw
+ store_uav_typed u0.xyzw, r0.xyzz, r1.xyzw
+endif
+ret
+// Approximately 29 instruction slots used
+#endif
+
+const BYTE g_customEmitEmitCS[] =
+{
+ 68, 88, 66, 67, 185, 132,
+ 145, 219, 25, 247, 37, 83,
+ 81, 8, 147, 1, 228, 138,
+ 141, 6, 1, 0, 0, 0,
+ 228, 7, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 144, 3, 0, 0, 160, 3,
+ 0, 0, 176, 3, 0, 0,
+ 72, 7, 0, 0, 82, 68,
+ 69, 70, 84, 3, 0, 0,
+ 1, 0, 0, 0, 224, 0,
+ 0, 0, 4, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 83, 67, 0, 1, 0, 0,
+ 42, 3, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 188, 0, 0, 0, 2, 0,
+ 0, 0, 4, 0, 0, 0,
+ 8, 0, 0, 0, 255, 255,
+ 255, 255, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 199, 0, 0, 0,
+ 2, 0, 0, 0, 5, 0,
+ 0, 0, 8, 0, 0, 0,
+ 255, 255, 255, 255, 2, 0,
+ 0, 0, 1, 0, 0, 0,
+ 13, 0, 0, 0, 207, 0,
+ 0, 0, 4, 0, 0, 0,
+ 5, 0, 0, 0, 8, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 13, 0, 0, 0,
+ 215, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 98, 108, 111, 99,
+ 107, 84, 97, 98, 108, 101,
+ 0, 100, 97, 116, 97, 83,
+ 82, 86, 0, 100, 97, 116,
+ 97, 85, 65, 86, 0, 112,
+ 97, 114, 97, 109, 115, 0,
+ 171, 171, 215, 0, 0, 0,
+ 5, 0, 0, 0, 248, 0,
+ 0, 0, 144, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 192, 1, 0, 0,
+ 0, 0, 0, 0, 80, 0,
+ 0, 0, 2, 0, 0, 0,
+ 136, 2, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 172, 2, 0, 0, 80, 0,
+ 0, 0, 16, 0, 0, 0,
+ 2, 0, 0, 0, 180, 2,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 216, 2,
+ 0, 0, 96, 0, 0, 0,
+ 16, 0, 0, 0, 2, 0,
+ 0, 0, 180, 2, 0, 0,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 224, 2, 0, 0,
+ 112, 0, 0, 0, 16, 0,
+ 0, 0, 2, 0, 0, 0,
+ 252, 2, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 32, 3, 0, 0, 128, 0,
+ 0, 0, 16, 0, 0, 0,
+ 2, 0, 0, 0, 252, 2,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 99, 117,
+ 115, 116, 111, 109, 69, 109,
+ 105, 116, 80, 97, 114, 97,
+ 109, 115, 0, 78, 118, 70,
+ 108, 111, 119, 83, 104, 97,
+ 100, 101, 114, 80, 111, 105,
+ 110, 116, 80, 97, 114, 97,
+ 109, 115, 0, 105, 115, 86,
+ 84, 82, 0, 78, 118, 70,
+ 108, 111, 119, 85, 105, 110,
+ 116, 52, 0, 171, 1, 0,
+ 19, 0, 1, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 239, 1, 0, 0, 98, 108,
+ 111, 99, 107, 68, 105, 109,
+ 0, 98, 108, 111, 99, 107,
+ 68, 105, 109, 66, 105, 116,
+ 115, 0, 112, 111, 111, 108,
+ 71, 114, 105, 100, 68, 105,
+ 109, 0, 103, 114, 105, 100,
+ 68, 105, 109, 0, 171, 171,
+ 233, 1, 0, 0, 252, 1,
+ 0, 0, 0, 0, 0, 0,
+ 32, 2, 0, 0, 252, 1,
+ 0, 0, 16, 0, 0, 0,
+ 41, 2, 0, 0, 252, 1,
+ 0, 0, 32, 0, 0, 0,
+ 54, 2, 0, 0, 252, 1,
+ 0, 0, 48, 0, 0, 0,
+ 66, 2, 0, 0, 252, 1,
+ 0, 0, 64, 0, 0, 0,
+ 5, 0, 0, 0, 1, 0,
+ 20, 0, 0, 0, 5, 0,
+ 76, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 209, 1, 0, 0,
+ 109, 105, 110, 86, 105, 100,
+ 120, 0, 1, 0, 19, 0,
+ 1, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 239, 1,
+ 0, 0, 109, 97, 120, 86,
+ 105, 100, 120, 0, 116, 97,
+ 114, 103, 101, 116, 86, 97,
+ 108, 117, 101, 0, 78, 118,
+ 70, 108, 111, 119, 70, 108,
+ 111, 97, 116, 52, 0, 171,
+ 171, 171, 1, 0, 3, 0,
+ 1, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 236, 2,
+ 0, 0, 98, 108, 101, 110,
+ 100, 82, 97, 116, 101, 0,
+ 77, 105, 99, 114, 111, 115,
+ 111, 102, 116, 32, 40, 82,
+ 41, 32, 72, 76, 83, 76,
+ 32, 83, 104, 97, 100, 101,
+ 114, 32, 67, 111, 109, 112,
+ 105, 108, 101, 114, 32, 49,
+ 48, 46, 49, 0, 171, 171,
+ 73, 83, 71, 78, 8, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 79, 83,
+ 71, 78, 8, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0,
+ 0, 0, 83, 72, 69, 88,
+ 144, 3, 0, 0, 80, 0,
+ 5, 0, 228, 0, 0, 0,
+ 106, 8, 0, 1, 89, 0,
+ 0, 4, 70, 142, 32, 0,
+ 0, 0, 0, 0, 9, 0,
+ 0, 0, 88, 40, 0, 4,
+ 0, 112, 16, 0, 1, 0,
+ 0, 0, 68, 68, 0, 0,
+ 88, 40, 0, 4, 0, 112,
+ 16, 0, 2, 0, 0, 0,
+ 85, 85, 0, 0, 156, 40,
+ 0, 4, 0, 224, 17, 0,
+ 0, 0, 0, 0, 85, 85,
+ 0, 0, 95, 0, 0, 2,
+ 114, 0, 2, 0, 104, 0,
+ 0, 2, 4, 0, 0, 0,
+ 155, 0, 0, 4, 8, 0,
+ 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 30, 0,
+ 0, 7, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 2, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 5, 0,
+ 0, 0, 33, 0, 0, 8,
+ 114, 0, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 1, 0, 0, 7,
+ 18, 0, 16, 0, 1, 0,
+ 0, 0, 42, 0, 16, 0,
+ 1, 0, 0, 0, 10, 0,
+ 16, 0, 1, 0, 0, 0,
+ 34, 0, 0, 8, 226, 0,
+ 16, 0, 1, 0, 0, 0,
+ 6, 9, 16, 0, 0, 0,
+ 0, 0, 6, 137, 32, 0,
+ 0, 0, 0, 0, 6, 0,
+ 0, 0, 1, 0, 0, 7,
+ 34, 0, 16, 0, 1, 0,
+ 0, 0, 42, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 1, 0, 0, 7, 34, 0,
+ 16, 0, 1, 0, 0, 0,
+ 58, 0, 16, 0, 1, 0,
+ 0, 0, 26, 0, 16, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 7, 18, 0, 16, 0,
+ 1, 0, 0, 0, 26, 0,
+ 16, 0, 1, 0, 0, 0,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 31, 0, 4, 3,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 31, 0, 0, 4,
+ 10, 128, 32, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 42, 0, 0, 8, 114, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 2, 0,
+ 0, 0, 54, 0, 0, 5,
+ 130, 0, 16, 0, 1, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 0, 0, 45, 0,
+ 0, 137, 66, 1, 0, 128,
+ 3, 17, 17, 0, 18, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 14, 16, 0, 1, 0,
+ 0, 0, 70, 126, 16, 0,
+ 1, 0, 0, 0, 59, 0,
+ 0, 5, 18, 0, 16, 0,
+ 1, 0, 0, 0, 10, 0,
+ 16, 0, 1, 0, 0, 0,
+ 1, 0, 0, 7, 18, 0,
+ 16, 0, 2, 0, 0, 0,
+ 10, 0, 16, 0, 1, 0,
+ 0, 0, 1, 64, 0, 0,
+ 255, 3, 0, 0, 138, 0,
+ 0, 15, 98, 0, 16, 0,
+ 2, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0,
+ 20, 0, 0, 0, 0, 0,
+ 0, 0, 6, 0, 16, 0,
+ 1, 0, 0, 0, 41, 0,
+ 0, 8, 114, 0, 16, 0,
+ 1, 0, 0, 0, 70, 2,
+ 16, 0, 2, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 30, 0, 0, 11, 114, 0,
+ 16, 0, 2, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 2, 64, 0, 0, 255, 255,
+ 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 1, 0, 0, 7,
+ 114, 0, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 2, 0, 0, 0,
+ 60, 0, 0, 7, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 2, 0, 0, 0, 21, 0,
+ 0, 1, 54, 0, 0, 5,
+ 130, 0, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 0, 0, 45, 0,
+ 0, 137, 66, 1, 0, 128,
+ 67, 85, 21, 0, 242, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 14, 16, 0, 0, 0,
+ 0, 0, 70, 126, 16, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 12, 242, 0, 16, 0,
+ 2, 0, 0, 0, 70, 142,
+ 32, 128, 65, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 128, 63, 0, 0,
+ 128, 63, 0, 0, 128, 63,
+ 0, 0, 128, 63, 56, 0,
+ 0, 9, 242, 0, 16, 0,
+ 3, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 50, 0,
+ 0, 9, 242, 0, 16, 0,
+ 1, 0, 0, 0, 70, 14,
+ 16, 0, 2, 0, 0, 0,
+ 70, 14, 16, 0, 1, 0,
+ 0, 0, 70, 14, 16, 0,
+ 3, 0, 0, 0, 164, 0,
+ 0, 7, 242, 224, 17, 0,
+ 0, 0, 0, 0, 70, 10,
+ 16, 0, 0, 0, 0, 0,
+ 70, 14, 16, 0, 1, 0,
+ 0, 0, 21, 0, 0, 1,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 148, 0, 0, 0,
+ 29, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0,
+ 0, 0, 6, 0, 0, 0,
+ 9, 0, 0, 0, 2, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0
+};
diff --git a/demo/DemoApp/customLightingCS.hlsl.h b/demo/DemoApp/customLightingCS.hlsl.h
new file mode 100644
index 0000000..538d193
--- /dev/null
+++ b/demo/DemoApp/customLightingCS.hlsl.h
@@ -0,0 +1,785 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer params
+// {
+//
+// struct NvFlowShaderLinearParams
+// {
+//
+// uint4 isVTR; // Offset: 0
+// uint4 blockDim; // Offset: 16
+// uint4 blockDimBits; // Offset: 32
+// uint4 poolGridDim; // Offset: 48
+// uint4 gridDim; // Offset: 64
+// float4 blockDimInv; // Offset: 80
+// uint4 linearBlockDim; // Offset: 96
+// uint4 linearBlockOffset; // Offset: 112
+// float4 dimInv; // Offset: 128
+// float4 vdim; // Offset: 144
+// float4 vdimInv; // Offset: 160
+//
+// } exportParams; // Offset: 0 Size: 176
+//
+// struct NvFlowShaderLinearParams
+// {
+//
+// uint4 isVTR; // Offset: 176
+// uint4 blockDim; // Offset: 192
+// uint4 blockDimBits; // Offset: 208
+// uint4 poolGridDim; // Offset: 224
+// uint4 gridDim; // Offset: 240
+// float4 blockDimInv; // Offset: 256
+// uint4 linearBlockDim; // Offset: 272
+// uint4 linearBlockOffset; // Offset: 288
+// float4 dimInv; // Offset: 304
+// float4 vdim; // Offset: 320
+// float4 vdimInv; // Offset: 336
+//
+// } importParams; // Offset: 176 Size: 176
+//
+// struct Light
+// {
+//
+// float4 location; // Offset: 352
+// float4 intensity; // Offset: 368
+// float4 bias; // Offset: 384
+// float4 falloff; // Offset: 400
+//
+// } light[3]; // Offset: 352 Size: 192
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// borderSampler sampler NA NA s0 1
+// exportBlockTable texture uint 3d t1 1
+// exportData texture float4 3d t2 1
+// importBlockList texture uint buf t3 1
+// importBlockTable texture uint 3d t4 1
+// importDataRW UAV float4 3d u0 1
+// params cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Input
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Output
+cs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[34], immediateIndexed
+dcl_sampler s0, mode_default
+dcl_resource_texture3d (uint,uint,uint,uint) t1
+dcl_resource_texture3d (float,float,float,float) t2
+dcl_resource_buffer (uint,uint,uint,uint) t3
+dcl_resource_texture3d (uint,uint,uint,uint) t4
+dcl_uav_typed_texture3d (float,float,float,float) u0
+dcl_input vThreadID.xyz
+dcl_temps 7
+dcl_thread_group 8, 8, 8
+ushr r0.x, vThreadID.x, cb0[13].x
+ld_indexable(buffer)(uint,uint,uint,uint) r0.x, r0.xxxx, t3.xyzw
+not r0.x, r0.x
+and r1.x, r0.x, l(1023)
+ubfe r1.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r0.xxxx
+ishl r0.xyz, r1.xyzx, cb0[13].xyzx
+iadd r1.xyz, cb0[12].xyzx, l(-1, -1, -1, 0)
+and r2.xyz, r1.xyzx, vThreadID.xyzx
+or r0.xyz, r0.xyzx, r2.xyzx
+itof r2.xyz, r0.xyzx
+add r2.xyz, r2.xyzx, l(0.500000, 0.500000, 0.500000, 0.000000)
+mul r3.xyz, r2.xyzx, cb0[10].xyzx
+mad r3.xyz, r3.xyzx, l(2.000000, 2.000000, 2.000000, 0.000000), l(-1.000000, -1.000000, -1.000000, 0.000000)
+if_z cb0[0].x
+ mul r4.xyz, r2.xyzx, cb0[5].xyzx
+ round_ni r4.xyz, r4.xyzx
+ ftoi r5.xyz, r4.xyzx
+ mov r5.w, l(0)
+ ld_indexable(texture3d)(uint,uint,uint,uint) r0.w, r5.xyzw, t1.yzwx
+ not r0.w, r0.w
+ and r5.x, r0.w, l(1023)
+ ubfe r5.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r0.wwww
+ imul null, r5.xyz, r5.xyzx, cb0[6].xyzx
+ utof r5.xyz, r5.xyzx
+ utof r6.xyz, cb0[1].xyzx
+ mad r4.xyz, cb0[5].xyzx, r2.xyzx, -r4.xyzx
+ mad r4.xyz, r6.xyzx, r4.xyzx, r5.xyzx
+ utof r5.xyz, cb0[7].xyzx
+ add r2.xyz, r4.xyzx, r5.xyzx
+endif
+mul r2.xyz, r2.xyzx, cb0[8].xyzx
+sample_l_indexable(texture3d)(float,float,float,float) r0.w, r2.xyzx, t2.yzwx, s0, l(0.000000)
+mul r2.xyz, r0.wwww, l(0.100000, 0.100000, 0.100000, 0.000000)
+add r4.xyz, r3.xyzx, -cb0[22].xyzx
+dp3 r1.w, r4.xyzx, r4.xyzx
+mul r4.xyzw, cb0[23].xyzw, cb0[24].xyzw
+mad r5.xyzw, cb0[25].xyzw, r1.wwww, cb0[24].xyzw
+div r4.xyzw, r4.xyzw, r5.xyzw
+mov r2.w, l(0.250000)
+add r2.xyzw, r2.xyzw, r4.xyzw
+add r4.xyz, r3.xyzx, -cb0[26].xyzx
+dp3 r1.w, r4.xyzx, r4.xyzx
+mul r4.xyzw, cb0[27].xyzw, cb0[28].xyzw
+mad r5.xyzw, cb0[29].xyzw, r1.wwww, cb0[28].xyzw
+div r4.xyzw, r4.xyzw, r5.xyzw
+add r2.xyzw, r2.xyzw, r4.xyzw
+add r3.xyz, r3.xyzx, -cb0[30].xyzx
+dp3 r1.w, r3.xyzx, r3.xyzx
+mul r3.xyzw, cb0[31].xyzw, cb0[32].xyzw
+mad r4.xyzw, cb0[33].xyzw, r1.wwww, cb0[32].xyzw
+div r3.xyzw, r3.xyzw, r4.xyzw
+add r2.xyzw, r2.xyzw, r3.xyzw
+add r0.w, r0.w, l(-0.250000)
+max r0.w, r0.w, l(0.000000)
+mul r0.w, r0.w, r2.w
+mul r2.w, r0.w, l(0.250000)
+if_z cb0[11].x
+ ishr r3.xyz, r0.xyzx, cb0[13].xyzx
+ mov r3.w, l(0)
+ ld_indexable(texture3d)(uint,uint,uint,uint) r0.w, r3.xyzw, t4.yzwx
+ not r0.w, r0.w
+ and r3.x, r0.w, l(1023)
+ ubfe r3.yz, l(0, 10, 10, 0), l(0, 10, 20, 0), r0.wwww
+ ishl r3.xyz, r3.xyzx, cb0[13].xyzx
+ and r1.xyz, r1.xyzx, r0.xyzx
+ or r0.xyz, r1.xyzx, r3.xyzx
+endif
+store_uav_typed u0.xyzw, r0.xyzz, r2.xyzw
+ret
+// Approximately 69 instruction slots used
+#endif
+
+const BYTE g_customLightingCS[] =
+{
+ 68, 88, 66, 67, 81, 60,
+ 238, 114, 184, 37, 48, 25,
+ 88, 28, 231, 151, 12, 178,
+ 59, 182, 1, 0, 0, 0,
+ 108, 14, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 208, 4, 0, 0, 224, 4,
+ 0, 0, 240, 4, 0, 0,
+ 208, 13, 0, 0, 82, 68,
+ 69, 70, 148, 4, 0, 0,
+ 1, 0, 0, 0, 124, 1,
+ 0, 0, 7, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 83, 67, 0, 1, 0, 0,
+ 108, 4, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 28, 1, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 42, 1, 0, 0,
+ 2, 0, 0, 0, 4, 0,
+ 0, 0, 8, 0, 0, 0,
+ 255, 255, 255, 255, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 59, 1,
+ 0, 0, 2, 0, 0, 0,
+ 5, 0, 0, 0, 8, 0,
+ 0, 0, 255, 255, 255, 255,
+ 2, 0, 0, 0, 1, 0,
+ 0, 0, 13, 0, 0, 0,
+ 70, 1, 0, 0, 2, 0,
+ 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 255, 255,
+ 255, 255, 3, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 86, 1, 0, 0,
+ 2, 0, 0, 0, 4, 0,
+ 0, 0, 8, 0, 0, 0,
+ 255, 255, 255, 255, 4, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 103, 1,
+ 0, 0, 4, 0, 0, 0,
+ 5, 0, 0, 0, 8, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 13, 0, 0, 0,
+ 116, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 98, 111, 114, 100,
+ 101, 114, 83, 97, 109, 112,
+ 108, 101, 114, 0, 101, 120,
+ 112, 111, 114, 116, 66, 108,
+ 111, 99, 107, 84, 97, 98,
+ 108, 101, 0, 101, 120, 112,
+ 111, 114, 116, 68, 97, 116,
+ 97, 0, 105, 109, 112, 111,
+ 114, 116, 66, 108, 111, 99,
+ 107, 76, 105, 115, 116, 0,
+ 105, 109, 112, 111, 114, 116,
+ 66, 108, 111, 99, 107, 84,
+ 97, 98, 108, 101, 0, 105,
+ 109, 112, 111, 114, 116, 68,
+ 97, 116, 97, 82, 87, 0,
+ 112, 97, 114, 97, 109, 115,
+ 0, 171, 116, 1, 0, 0,
+ 3, 0, 0, 0, 148, 1,
+ 0, 0, 32, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 12, 2, 0, 0,
+ 0, 0, 0, 0, 176, 0,
+ 0, 0, 2, 0, 0, 0,
+ 140, 3, 0, 0, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 176, 3, 0, 0, 176, 0,
+ 0, 0, 176, 0, 0, 0,
+ 2, 0, 0, 0, 140, 3,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 189, 3,
+ 0, 0, 96, 1, 0, 0,
+ 192, 0, 0, 0, 2, 0,
+ 0, 0, 72, 4, 0, 0,
+ 0, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 101, 120, 112, 111,
+ 114, 116, 80, 97, 114, 97,
+ 109, 115, 0, 78, 118, 70,
+ 108, 111, 119, 83, 104, 97,
+ 100, 101, 114, 76, 105, 110,
+ 101, 97, 114, 80, 97, 114,
+ 97, 109, 115, 0, 105, 115,
+ 86, 84, 82, 0, 78, 118,
+ 70, 108, 111, 119, 85, 105,
+ 110, 116, 52, 0, 1, 0,
+ 19, 0, 1, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 56, 2, 0, 0, 98, 108,
+ 111, 99, 107, 68, 105, 109,
+ 0, 98, 108, 111, 99, 107,
+ 68, 105, 109, 66, 105, 116,
+ 115, 0, 112, 111, 111, 108,
+ 71, 114, 105, 100, 68, 105,
+ 109, 0, 103, 114, 105, 100,
+ 68, 105, 109, 0, 98, 108,
+ 111, 99, 107, 68, 105, 109,
+ 73, 110, 118, 0, 78, 118,
+ 70, 108, 111, 119, 70, 108,
+ 111, 97, 116, 52, 0, 171,
+ 1, 0, 3, 0, 1, 0,
+ 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 158, 2, 0, 0,
+ 108, 105, 110, 101, 97, 114,
+ 66, 108, 111, 99, 107, 68,
+ 105, 109, 0, 108, 105, 110,
+ 101, 97, 114, 66, 108, 111,
+ 99, 107, 79, 102, 102, 115,
+ 101, 116, 0, 100, 105, 109,
+ 73, 110, 118, 0, 118, 100,
+ 105, 109, 0, 118, 100, 105,
+ 109, 73, 110, 118, 0, 171,
+ 171, 171, 50, 2, 0, 0,
+ 68, 2, 0, 0, 0, 0,
+ 0, 0, 104, 2, 0, 0,
+ 68, 2, 0, 0, 16, 0,
+ 0, 0, 113, 2, 0, 0,
+ 68, 2, 0, 0, 32, 0,
+ 0, 0, 126, 2, 0, 0,
+ 68, 2, 0, 0, 48, 0,
+ 0, 0, 138, 2, 0, 0,
+ 68, 2, 0, 0, 64, 0,
+ 0, 0, 146, 2, 0, 0,
+ 172, 2, 0, 0, 80, 0,
+ 0, 0, 208, 2, 0, 0,
+ 68, 2, 0, 0, 96, 0,
+ 0, 0, 223, 2, 0, 0,
+ 68, 2, 0, 0, 112, 0,
+ 0, 0, 241, 2, 0, 0,
+ 172, 2, 0, 0, 128, 0,
+ 0, 0, 248, 2, 0, 0,
+ 172, 2, 0, 0, 144, 0,
+ 0, 0, 253, 2, 0, 0,
+ 172, 2, 0, 0, 160, 0,
+ 0, 0, 5, 0, 0, 0,
+ 1, 0, 44, 0, 0, 0,
+ 11, 0, 8, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 25, 2,
+ 0, 0, 105, 109, 112, 111,
+ 114, 116, 80, 97, 114, 97,
+ 109, 115, 0, 108, 105, 103,
+ 104, 116, 0, 76, 105, 103,
+ 104, 116, 0, 108, 111, 99,
+ 97, 116, 105, 111, 110, 0,
+ 102, 108, 111, 97, 116, 52,
+ 0, 171, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 210, 3, 0, 0, 105, 110,
+ 116, 101, 110, 115, 105, 116,
+ 121, 0, 98, 105, 97, 115,
+ 0, 102, 97, 108, 108, 111,
+ 102, 102, 0, 171, 201, 3,
+ 0, 0, 220, 3, 0, 0,
+ 0, 0, 0, 0, 0, 4,
+ 0, 0, 220, 3, 0, 0,
+ 16, 0, 0, 0, 10, 4,
+ 0, 0, 220, 3, 0, 0,
+ 32, 0, 0, 0, 15, 4,
+ 0, 0, 220, 3, 0, 0,
+ 48, 0, 0, 0, 5, 0,
+ 0, 0, 1, 0, 16, 0,
+ 3, 0, 4, 0, 24, 4,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 195, 3, 0, 0, 77, 105,
+ 99, 114, 111, 115, 111, 102,
+ 116, 32, 40, 82, 41, 32,
+ 72, 76, 83, 76, 32, 83,
+ 104, 97, 100, 101, 114, 32,
+ 67, 111, 109, 112, 105, 108,
+ 101, 114, 32, 49, 48, 46,
+ 49, 0, 73, 83, 71, 78,
+ 8, 0, 0, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 79, 83, 71, 78, 8, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 83, 72,
+ 69, 88, 216, 8, 0, 0,
+ 80, 0, 5, 0, 54, 2,
+ 0, 0, 106, 8, 0, 1,
+ 89, 0, 0, 4, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 40,
+ 0, 4, 0, 112, 16, 0,
+ 1, 0, 0, 0, 68, 68,
+ 0, 0, 88, 40, 0, 4,
+ 0, 112, 16, 0, 2, 0,
+ 0, 0, 85, 85, 0, 0,
+ 88, 8, 0, 4, 0, 112,
+ 16, 0, 3, 0, 0, 0,
+ 68, 68, 0, 0, 88, 40,
+ 0, 4, 0, 112, 16, 0,
+ 4, 0, 0, 0, 68, 68,
+ 0, 0, 156, 40, 0, 4,
+ 0, 224, 17, 0, 0, 0,
+ 0, 0, 85, 85, 0, 0,
+ 95, 0, 0, 2, 114, 0,
+ 2, 0, 104, 0, 0, 2,
+ 7, 0, 0, 0, 155, 0,
+ 0, 4, 8, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0,
+ 0, 0, 85, 0, 0, 7,
+ 18, 0, 16, 0, 0, 0,
+ 0, 0, 10, 0, 2, 0,
+ 10, 128, 32, 0, 0, 0,
+ 0, 0, 13, 0, 0, 0,
+ 45, 0, 0, 137, 66, 0,
+ 0, 128, 3, 17, 17, 0,
+ 18, 0, 16, 0, 0, 0,
+ 0, 0, 6, 0, 16, 0,
+ 0, 0, 0, 0, 70, 126,
+ 16, 0, 3, 0, 0, 0,
+ 59, 0, 0, 5, 18, 0,
+ 16, 0, 0, 0, 0, 0,
+ 10, 0, 16, 0, 0, 0,
+ 0, 0, 1, 0, 0, 7,
+ 18, 0, 16, 0, 1, 0,
+ 0, 0, 10, 0, 16, 0,
+ 0, 0, 0, 0, 1, 64,
+ 0, 0, 255, 3, 0, 0,
+ 138, 0, 0, 15, 98, 0,
+ 16, 0, 1, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0,
+ 10, 0, 0, 0, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 0, 0, 10, 0,
+ 0, 0, 20, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0,
+ 16, 0, 0, 0, 0, 0,
+ 41, 0, 0, 8, 114, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 1, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 13, 0,
+ 0, 0, 30, 0, 0, 11,
+ 114, 0, 16, 0, 1, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 12, 0,
+ 0, 0, 2, 64, 0, 0,
+ 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255,
+ 0, 0, 0, 0, 1, 0,
+ 0, 6, 114, 0, 16, 0,
+ 2, 0, 0, 0, 70, 2,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 2, 0, 60, 0,
+ 0, 7, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 70, 2, 16, 0, 2, 0,
+ 0, 0, 43, 0, 0, 5,
+ 114, 0, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 10, 114, 0, 16, 0,
+ 2, 0, 0, 0, 70, 2,
+ 16, 0, 2, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 63, 0, 0, 0, 63,
+ 0, 0, 0, 63, 0, 0,
+ 0, 0, 56, 0, 0, 8,
+ 114, 0, 16, 0, 3, 0,
+ 0, 0, 70, 2, 16, 0,
+ 2, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 50, 0,
+ 0, 15, 114, 0, 16, 0,
+ 3, 0, 0, 0, 70, 2,
+ 16, 0, 3, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 64, 0, 0, 0, 64,
+ 0, 0, 0, 64, 0, 0,
+ 0, 0, 2, 64, 0, 0,
+ 0, 0, 128, 191, 0, 0,
+ 128, 191, 0, 0, 128, 191,
+ 0, 0, 0, 0, 31, 0,
+ 0, 4, 10, 128, 32, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 56, 0, 0, 8,
+ 114, 0, 16, 0, 4, 0,
+ 0, 0, 70, 2, 16, 0,
+ 2, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 65, 0,
+ 0, 5, 114, 0, 16, 0,
+ 4, 0, 0, 0, 70, 2,
+ 16, 0, 4, 0, 0, 0,
+ 27, 0, 0, 5, 114, 0,
+ 16, 0, 5, 0, 0, 0,
+ 70, 2, 16, 0, 4, 0,
+ 0, 0, 54, 0, 0, 5,
+ 130, 0, 16, 0, 5, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 0, 0, 45, 0,
+ 0, 137, 66, 1, 0, 128,
+ 3, 17, 17, 0, 130, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 14, 16, 0, 5, 0,
+ 0, 0, 150, 115, 16, 0,
+ 1, 0, 0, 0, 59, 0,
+ 0, 5, 130, 0, 16, 0,
+ 0, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 0, 0, 7, 18, 0,
+ 16, 0, 5, 0, 0, 0,
+ 58, 0, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 255, 3, 0, 0, 138, 0,
+ 0, 15, 98, 0, 16, 0,
+ 5, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0,
+ 20, 0, 0, 0, 0, 0,
+ 0, 0, 246, 15, 16, 0,
+ 0, 0, 0, 0, 38, 0,
+ 0, 9, 0, 208, 0, 0,
+ 114, 0, 16, 0, 5, 0,
+ 0, 0, 70, 2, 16, 0,
+ 5, 0, 0, 0, 70, 130,
+ 32, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 86, 0,
+ 0, 5, 114, 0, 16, 0,
+ 5, 0, 0, 0, 70, 2,
+ 16, 0, 5, 0, 0, 0,
+ 86, 0, 0, 6, 114, 0,
+ 16, 0, 6, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 50, 0, 0, 11, 114, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 5, 0, 0, 0,
+ 70, 2, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 128,
+ 65, 0, 0, 0, 4, 0,
+ 0, 0, 50, 0, 0, 9,
+ 114, 0, 16, 0, 4, 0,
+ 0, 0, 70, 2, 16, 0,
+ 6, 0, 0, 0, 70, 2,
+ 16, 0, 4, 0, 0, 0,
+ 70, 2, 16, 0, 5, 0,
+ 0, 0, 86, 0, 0, 6,
+ 114, 0, 16, 0, 5, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 7, 0,
+ 0, 0, 0, 0, 0, 7,
+ 114, 0, 16, 0, 2, 0,
+ 0, 0, 70, 2, 16, 0,
+ 4, 0, 0, 0, 70, 2,
+ 16, 0, 5, 0, 0, 0,
+ 21, 0, 0, 1, 56, 0,
+ 0, 8, 114, 0, 16, 0,
+ 2, 0, 0, 0, 70, 2,
+ 16, 0, 2, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 72, 0, 0, 141, 66, 1,
+ 0, 128, 67, 85, 21, 0,
+ 130, 0, 16, 0, 0, 0,
+ 0, 0, 70, 2, 16, 0,
+ 2, 0, 0, 0, 150, 115,
+ 16, 0, 2, 0, 0, 0,
+ 0, 96, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 0, 0, 56, 0,
+ 0, 10, 114, 0, 16, 0,
+ 2, 0, 0, 0, 246, 15,
+ 16, 0, 0, 0, 0, 0,
+ 2, 64, 0, 0, 205, 204,
+ 204, 61, 205, 204, 204, 61,
+ 205, 204, 204, 61, 0, 0,
+ 0, 0, 0, 0, 0, 9,
+ 114, 0, 16, 0, 4, 0,
+ 0, 0, 70, 2, 16, 0,
+ 3, 0, 0, 0, 70, 130,
+ 32, 128, 65, 0, 0, 0,
+ 0, 0, 0, 0, 22, 0,
+ 0, 0, 16, 0, 0, 7,
+ 130, 0, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 4, 0, 0, 0, 70, 2,
+ 16, 0, 4, 0, 0, 0,
+ 56, 0, 0, 9, 242, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 23, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 24, 0, 0, 0,
+ 50, 0, 0, 11, 242, 0,
+ 16, 0, 5, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 25, 0, 0, 0,
+ 246, 15, 16, 0, 1, 0,
+ 0, 0, 70, 142, 32, 0,
+ 0, 0, 0, 0, 24, 0,
+ 0, 0, 14, 0, 0, 7,
+ 242, 0, 16, 0, 4, 0,
+ 0, 0, 70, 14, 16, 0,
+ 4, 0, 0, 0, 70, 14,
+ 16, 0, 5, 0, 0, 0,
+ 54, 0, 0, 5, 130, 0,
+ 16, 0, 2, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 128, 62, 0, 0, 0, 7,
+ 242, 0, 16, 0, 2, 0,
+ 0, 0, 70, 14, 16, 0,
+ 2, 0, 0, 0, 70, 14,
+ 16, 0, 4, 0, 0, 0,
+ 0, 0, 0, 9, 114, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 2, 16, 0, 3, 0,
+ 0, 0, 70, 130, 32, 128,
+ 65, 0, 0, 0, 0, 0,
+ 0, 0, 26, 0, 0, 0,
+ 16, 0, 0, 7, 130, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 4, 0,
+ 0, 0, 70, 2, 16, 0,
+ 4, 0, 0, 0, 56, 0,
+ 0, 9, 242, 0, 16, 0,
+ 4, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 27, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 50, 0,
+ 0, 11, 242, 0, 16, 0,
+ 5, 0, 0, 0, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 29, 0, 0, 0, 246, 15,
+ 16, 0, 1, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 28, 0, 0, 0,
+ 14, 0, 0, 7, 242, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 14, 16, 0, 4, 0,
+ 0, 0, 70, 14, 16, 0,
+ 5, 0, 0, 0, 0, 0,
+ 0, 7, 242, 0, 16, 0,
+ 2, 0, 0, 0, 70, 14,
+ 16, 0, 2, 0, 0, 0,
+ 70, 14, 16, 0, 4, 0,
+ 0, 0, 0, 0, 0, 9,
+ 114, 0, 16, 0, 3, 0,
+ 0, 0, 70, 2, 16, 0,
+ 3, 0, 0, 0, 70, 130,
+ 32, 128, 65, 0, 0, 0,
+ 0, 0, 0, 0, 30, 0,
+ 0, 0, 16, 0, 0, 7,
+ 130, 0, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 3, 0, 0, 0, 70, 2,
+ 16, 0, 3, 0, 0, 0,
+ 56, 0, 0, 9, 242, 0,
+ 16, 0, 3, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 31, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 32, 0, 0, 0,
+ 50, 0, 0, 11, 242, 0,
+ 16, 0, 4, 0, 0, 0,
+ 70, 142, 32, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0,
+ 246, 15, 16, 0, 1, 0,
+ 0, 0, 70, 142, 32, 0,
+ 0, 0, 0, 0, 32, 0,
+ 0, 0, 14, 0, 0, 7,
+ 242, 0, 16, 0, 3, 0,
+ 0, 0, 70, 14, 16, 0,
+ 3, 0, 0, 0, 70, 14,
+ 16, 0, 4, 0, 0, 0,
+ 0, 0, 0, 7, 242, 0,
+ 16, 0, 2, 0, 0, 0,
+ 70, 14, 16, 0, 2, 0,
+ 0, 0, 70, 14, 16, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 7, 130, 0, 16, 0,
+ 0, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 128, 190, 52, 0, 0, 7,
+ 130, 0, 16, 0, 0, 0,
+ 0, 0, 58, 0, 16, 0,
+ 0, 0, 0, 0, 1, 64,
+ 0, 0, 0, 0, 0, 0,
+ 56, 0, 0, 7, 130, 0,
+ 16, 0, 0, 0, 0, 0,
+ 58, 0, 16, 0, 0, 0,
+ 0, 0, 58, 0, 16, 0,
+ 2, 0, 0, 0, 56, 0,
+ 0, 7, 130, 0, 16, 0,
+ 2, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 128, 62, 31, 0, 0, 4,
+ 10, 128, 32, 0, 0, 0,
+ 0, 0, 11, 0, 0, 0,
+ 42, 0, 0, 8, 114, 0,
+ 16, 0, 3, 0, 0, 0,
+ 70, 2, 16, 0, 0, 0,
+ 0, 0, 70, 130, 32, 0,
+ 0, 0, 0, 0, 13, 0,
+ 0, 0, 54, 0, 0, 5,
+ 130, 0, 16, 0, 3, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 0, 0, 45, 0,
+ 0, 137, 66, 1, 0, 128,
+ 3, 17, 17, 0, 130, 0,
+ 16, 0, 0, 0, 0, 0,
+ 70, 14, 16, 0, 3, 0,
+ 0, 0, 150, 115, 16, 0,
+ 4, 0, 0, 0, 59, 0,
+ 0, 5, 130, 0, 16, 0,
+ 0, 0, 0, 0, 58, 0,
+ 16, 0, 0, 0, 0, 0,
+ 1, 0, 0, 7, 18, 0,
+ 16, 0, 3, 0, 0, 0,
+ 58, 0, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 255, 3, 0, 0, 138, 0,
+ 0, 15, 98, 0, 16, 0,
+ 3, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 10, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 64, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0,
+ 20, 0, 0, 0, 0, 0,
+ 0, 0, 246, 15, 16, 0,
+ 0, 0, 0, 0, 41, 0,
+ 0, 8, 114, 0, 16, 0,
+ 3, 0, 0, 0, 70, 2,
+ 16, 0, 3, 0, 0, 0,
+ 70, 130, 32, 0, 0, 0,
+ 0, 0, 13, 0, 0, 0,
+ 1, 0, 0, 7, 114, 0,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 1, 0,
+ 0, 0, 70, 2, 16, 0,
+ 0, 0, 0, 0, 60, 0,
+ 0, 7, 114, 0, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 1, 0, 0, 0,
+ 70, 2, 16, 0, 3, 0,
+ 0, 0, 21, 0, 0, 1,
+ 164, 0, 0, 7, 242, 224,
+ 17, 0, 0, 0, 0, 0,
+ 70, 10, 16, 0, 0, 0,
+ 0, 0, 70, 14, 16, 0,
+ 2, 0, 0, 0, 62, 0,
+ 0, 1, 83, 84, 65, 84,
+ 148, 0, 0, 0, 69, 0,
+ 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 32, 0, 0, 0,
+ 5, 0, 0, 0, 11, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0
+};
diff --git a/demo/DemoApp/flowShaderParams.h b/demo/DemoApp/flowShaderParams.h
new file mode 100644
index 0000000..1c769ef
--- /dev/null
+++ b/demo/DemoApp/flowShaderParams.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#define NV_FLOW_SHADER_UTILS 1
+
+#include "NvFlowShader.h" \ No newline at end of file
diff --git a/demo/DemoApp/imgui.cpp b/demo/DemoApp/imgui.cpp
new file mode 100644
index 0000000..cccaf3f
--- /dev/null
+++ b/demo/DemoApp/imgui.cpp
@@ -0,0 +1,697 @@
+//
+// Copyright (c) 2009-2010 Mikko Mononen [email protected]
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+//
+
+#include <stdio.h>
+#include <string.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include "imgui.h"
+
+#ifdef WIN32
+# define snprintf _snprintf
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static const unsigned TEXT_POOL_SIZE = 8000;
+static char g_textPool[TEXT_POOL_SIZE];
+static unsigned g_textPoolSize = 0;
+static const char* allocText(const char* text)
+{
+ int len = (int)(strlen(text) + 1);
+ if (g_textPoolSize + len >= TEXT_POOL_SIZE)
+ return 0;
+ char* dst = &g_textPool[g_textPoolSize];
+ memcpy(dst, text, len);
+ g_textPoolSize += len;
+ return dst;
+}
+
+static const unsigned GFXCMD_QUEUE_SIZE = 5000;
+static imguiGfxCmd g_gfxCmdQueue[GFXCMD_QUEUE_SIZE];
+static unsigned g_gfxCmdQueueSize = 0;
+
+static void resetGfxCmdQueue()
+{
+ g_gfxCmdQueueSize = 0;
+ g_textPoolSize = 0;
+}
+
+static void addGfxCmdScissor(int x, int y, int w, int h)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_SCISSOR;
+ cmd.flags = x < 0 ? 0 : 1; // on/off flag.
+ cmd.col = 0;
+ cmd.rect.x = (short)x;
+ cmd.rect.y = (short)y;
+ cmd.rect.w = (short)w;
+ cmd.rect.h = (short)h;
+}
+
+static void addGfxCmdRect(float x, float y, float w, float h, unsigned int color)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_RECT;
+ cmd.flags = 0;
+ cmd.col = color;
+ cmd.rect.x = (short)(x*8.0f);
+ cmd.rect.y = (short)(y*8.0f);
+ cmd.rect.w = (short)(w*8.0f);
+ cmd.rect.h = (short)(h*8.0f);
+ cmd.rect.r = 0;
+}
+
+static void addGfxCmdLine(float x0, float y0, float x1, float y1, float r, unsigned int color)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_LINE;
+ cmd.flags = 0;
+ cmd.col = color;
+ cmd.line.x0 = (short)(x0*8.0f);
+ cmd.line.y0 = (short)(y0*8.0f);
+ cmd.line.x1 = (short)(x1*8.0f);
+ cmd.line.y1 = (short)(y1*8.0f);
+ cmd.line.r = (short)(r*8.0f);
+}
+
+static void addGfxCmdRoundedRect(float x, float y, float w, float h, float r, unsigned int color)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_RECT;
+ cmd.flags = 0;
+ cmd.col = color;
+ cmd.rect.x = (short)(x*8.0f);
+ cmd.rect.y = (short)(y*8.0f);
+ cmd.rect.w = (short)(w*8.0f);
+ cmd.rect.h = (short)(h*8.0f);
+ cmd.rect.r = (short)(r*8.0f);
+}
+
+static void addGfxCmdTriangle(int x, int y, int w, int h, int flags, unsigned int color)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_TRIANGLE;
+ cmd.flags = (char)flags;
+ cmd.col = color;
+ cmd.rect.x = (short)(x*8.0f);
+ cmd.rect.y = (short)(y*8.0f);
+ cmd.rect.w = (short)(w*8.0f);
+ cmd.rect.h = (short)(h*8.0f);
+}
+
+static void addGfxCmdText(int x, int y, int align, const char* text, unsigned int color)
+{
+ if (g_gfxCmdQueueSize >= GFXCMD_QUEUE_SIZE)
+ return;
+ imguiGfxCmd& cmd = g_gfxCmdQueue[g_gfxCmdQueueSize++];
+ cmd.type = IMGUI_GFXCMD_TEXT;
+ cmd.flags = 0;
+ cmd.col = color;
+ cmd.text.x = (short)x;
+ cmd.text.y = (short)y;
+ cmd.text.align = (short)align;
+ cmd.text.text = allocText(text);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+struct GuiState
+{
+ GuiState() :
+ left(false), leftPressed(false), leftReleased(false),
+ mx(-1), my(-1), scroll(0),
+ active(0), hot(0), hotToBe(0), isHot(false), isActive(false), wentActive(false),
+ dragX(0), dragY(0), dragOrig(0), widgetX(0), widgetY(0), widgetW(100),
+ insideCurrentScroll(false), areaId(0), widgetId(0)
+ {
+ }
+
+ bool left;
+ bool leftPressed, leftReleased;
+ int mx, my;
+ int scroll;
+ unsigned int active;
+ unsigned int hot;
+ unsigned int hotToBe;
+ bool isHot;
+ bool isActive;
+ bool wentActive;
+ int dragX, dragY;
+ float dragOrig;
+ int widgetX, widgetY, widgetW;
+ bool insideCurrentScroll;
+
+ unsigned int areaId;
+ unsigned int widgetId;
+};
+
+static GuiState g_state;
+
+// Begin Add Android Support
+#ifdef ANDROID
+void setStateLeft(bool bLeftDown)
+{
+ g_state.left = bLeftDown;
+}
+#endif
+// End Add Android Support
+
+inline bool anyActive()
+{
+ return g_state.active != 0;
+}
+
+inline bool isActive(unsigned int id)
+{
+ return g_state.active == id;
+}
+
+inline bool isHot(unsigned int id)
+{
+ return g_state.hot == id;
+}
+
+inline bool inRect(int x, int y, int w, int h, bool checkScroll = true)
+{
+ return (!checkScroll || g_state.insideCurrentScroll) && g_state.mx >= x && g_state.mx <= x + w && g_state.my >= y && g_state.my <= y + h;
+}
+
+inline void clearInput()
+{
+ g_state.leftPressed = false;
+ g_state.leftReleased = false;
+ g_state.scroll = 0;
+}
+
+inline void clearActive()
+{
+ g_state.active = 0;
+ // mark all UI for this frame as processed
+ clearInput();
+}
+
+inline void setActive(unsigned int id)
+{
+ g_state.active = id;
+ g_state.wentActive = true;
+}
+
+inline void setHot(unsigned int id)
+{
+ g_state.hotToBe = id;
+ // Begin Add Android Support
+#ifdef ANDROID
+ g_state.hot = id;
+#endif
+ // End Add Android Support
+}
+
+
+static bool buttonLogic(unsigned int id, bool over)
+{
+ bool res = false;
+ // process down
+ if (!anyActive())
+ {
+ if (over)
+ setHot(id);
+ // Begin Add Android Support
+#ifdef ANDROID
+ if (isHot(id) && g_state.leftPressed && over)
+ setActive(id);
+#else
+ if (isHot(id) && g_state.leftPressed)
+ setActive(id);
+#endif
+ // End Add Android Support
+ }
+
+ // if button is active, then react on left up
+ if (isActive(id))
+ {
+ g_state.isActive = true;
+ if (over)
+ setHot(id);
+ if (g_state.leftReleased)
+ {
+ if (isHot(id))
+ res = true;
+ clearActive();
+ }
+ }
+
+ if (isHot(id))
+ g_state.isHot = true;
+
+ return res;
+}
+
+static void updateInput(int mx, int my, unsigned char mbut, int scroll)
+{
+ bool left = (mbut & IMGUI_MBUT_LEFT) != 0;
+
+ g_state.mx = mx;
+ g_state.my = my;
+ g_state.leftPressed = !g_state.left && left;
+ g_state.leftReleased = g_state.left && !left;
+ g_state.left = left;
+
+ g_state.scroll = scroll;
+}
+
+void imguiBeginFrame(int mx, int my, unsigned char mbut, int scroll)
+{
+ updateInput(mx, my, mbut, scroll);
+
+ g_state.hot = g_state.hotToBe;
+ g_state.hotToBe = 0;
+
+ g_state.wentActive = false;
+ g_state.isActive = false;
+ g_state.isHot = false;
+
+ g_state.widgetX = 0;
+ g_state.widgetY = 0;
+ g_state.widgetW = 0;
+
+ g_state.areaId = 1;
+ g_state.widgetId = 1;
+
+ resetGfxCmdQueue();
+}
+
+void imguiEndFrame()
+{
+ clearInput();
+}
+
+const imguiGfxCmd* imguiGetRenderQueue()
+{
+ return g_gfxCmdQueue;
+}
+
+int imguiGetRenderQueueSize()
+{
+ return g_gfxCmdQueueSize;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static const int BUTTON_HEIGHT = 20;
+static const int SLIDER_HEIGHT = 20;
+static const int SLIDER_MARKER_WIDTH = 10;
+static const int CHECK_SIZE = 8;
+static const int DEFAULT_SPACING = 4;
+static const int TEXT_HEIGHT = 8;
+static const int SCROLL_AREA_PADDING = 6;
+static const int INDENT_SIZE = 16;
+static const int AREA_HEADER = 28;
+
+static int g_scrollTop = 0;
+static int g_scrollBottom = 0;
+static int g_scrollRight = 0;
+static int g_scrollAreaTop = 0;
+static int* g_scrollVal = 0;
+static int g_focusTop = 0;
+static int g_focusBottom = 0;
+static unsigned int g_scrollId = 0;
+static bool g_insideScrollArea = false;
+
+bool imguiBeginScrollArea(const char* name, int x, int y, int w, int h, int* scroll)
+{
+ g_state.areaId++;
+ g_state.widgetId = 0;
+ g_scrollId = (g_state.areaId << 16) | g_state.widgetId;
+
+ g_state.widgetX = x + SCROLL_AREA_PADDING;
+ g_state.widgetY = y + h - AREA_HEADER + (*scroll);
+ g_state.widgetW = w - SCROLL_AREA_PADDING * 4;
+ g_scrollTop = y - AREA_HEADER + h;
+ g_scrollBottom = y + SCROLL_AREA_PADDING;
+ g_scrollRight = x + w - SCROLL_AREA_PADDING * 3;
+ g_scrollVal = scroll;
+
+ g_scrollAreaTop = g_state.widgetY;
+
+ g_focusTop = y - AREA_HEADER;
+ g_focusBottom = y - AREA_HEADER + h;
+
+ g_insideScrollArea = inRect(x, y, w, h, false);
+ g_state.insideCurrentScroll = g_insideScrollArea;
+
+ addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 6, imguiRGBA(0, 0, 0, 192));
+
+ addGfxCmdText(x + AREA_HEADER / 2, y + h - AREA_HEADER / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, name, imguiRGBA(255, 255, 255, 128));
+
+ addGfxCmdScissor(x + SCROLL_AREA_PADDING, y + SCROLL_AREA_PADDING, w - SCROLL_AREA_PADDING * 4, h - AREA_HEADER - SCROLL_AREA_PADDING);
+
+ return g_insideScrollArea;
+}
+
+void imguiEndScrollArea()
+{
+ // Disable scissoring.
+ addGfxCmdScissor(-1, -1, -1, -1);
+
+ // Draw scroll bar
+ int x = g_scrollRight + SCROLL_AREA_PADDING / 2;
+ int y = g_scrollBottom;
+ int w = SCROLL_AREA_PADDING * 2;
+ int h = g_scrollTop - g_scrollBottom;
+
+ int stop = g_scrollAreaTop;
+ int sbot = g_state.widgetY;
+ int sh = stop - sbot; // The scrollable area height.
+
+ float barHeight = (float)h / (float)sh;
+
+ if (barHeight < 1)
+ {
+ float barY = (float)(y - sbot) / (float)sh;
+ if (barY < 0) barY = 0;
+ if (barY > 1) barY = 1;
+
+ // Handle scroll bar logic.
+ unsigned int hid = g_scrollId;
+ int hx = x;
+ int hy = y + (int)(barY*h);
+ int hw = w;
+ int hh = (int)(barHeight*h);
+
+ const int range = h - (hh - 1);
+ bool over = inRect(hx, hy, hw, hh);
+ buttonLogic(hid, over);
+ if (isActive(hid))
+ {
+ float u = (float)(hy - y) / (float)range;
+ if (g_state.wentActive)
+ {
+ g_state.dragY = g_state.my;
+ g_state.dragOrig = u;
+ }
+ if (g_state.dragY != g_state.my)
+ {
+ u = g_state.dragOrig + (g_state.my - g_state.dragY) / (float)range;
+ if (u < 0) u = 0;
+ if (u > 1) u = 1;
+ *g_scrollVal = (int)((1 - u) * (sh - h));
+ }
+ }
+
+ // BG
+ addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, (float)w / 2 - 1, imguiRGBA(0, 0, 0, 196));
+ // Bar
+ if (isActive(hid))
+ addGfxCmdRoundedRect((float)hx, (float)hy, (float)hw, (float)hh, (float)w / 2 - 1, imguiRGBA(255, 196, 0, 196));
+ else
+ addGfxCmdRoundedRect((float)hx, (float)hy, (float)hw, (float)hh, (float)w / 2 - 1, isHot(hid) ? imguiRGBA(255, 196, 0, 96) : imguiRGBA(255, 255, 255, 64));
+
+ // Handle mouse scrolling.
+ if (g_insideScrollArea) // && !anyActive())
+ {
+ if (g_state.scroll)
+ {
+ *g_scrollVal += 20 * g_state.scroll;
+ if (*g_scrollVal < 0) *g_scrollVal = 0;
+ if (*g_scrollVal >(sh - h)) *g_scrollVal = (sh - h);
+ }
+ }
+ }
+ g_state.insideCurrentScroll = false;
+}
+
+bool imguiButton(const char* text, bool enabled)
+{
+ g_state.widgetId++;
+ unsigned int id = (g_state.areaId << 16) | g_state.widgetId;
+
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ int w = g_state.widgetW;
+ int h = BUTTON_HEIGHT;
+ g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
+
+ bool over = enabled && inRect(x, y, w, h);
+ bool res = buttonLogic(id, over);
+
+ addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, (float)BUTTON_HEIGHT / 2 - 1, imguiRGBA(128, 128, 128, isActive(id) ? 196 : 96));
+ if (enabled)
+ addGfxCmdText(x + BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200));
+ else
+ addGfxCmdText(x + BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128, 128, 128, 200));
+
+ return res;
+}
+
+bool imguiItem(const char* text, bool enabled, unsigned int color)
+{
+ g_state.widgetId++;
+ unsigned int id = (g_state.areaId << 16) | g_state.widgetId;
+
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ int w = g_state.widgetW;
+ int h = BUTTON_HEIGHT;
+ g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
+
+ bool over = enabled && inRect(x, y, w, h);
+ bool res = buttonLogic(id, over);
+
+ if (isHot(id))
+ addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 2.0f, imguiRGBA(255, 196, 0, isActive(id) ? 196 : 96));
+
+ if (enabled)
+ addGfxCmdText(x + BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, color);
+ else
+ addGfxCmdText(x + BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, color);
+
+ return res;
+}
+
+bool imguiCheck(const char* text, bool checked, bool enabled)
+{
+ g_state.widgetId++;
+ unsigned int id = (g_state.areaId << 16) | g_state.widgetId;
+
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ int w = g_state.widgetW;
+ int h = BUTTON_HEIGHT;
+ g_state.widgetY -= BUTTON_HEIGHT + DEFAULT_SPACING;
+
+ bool over = enabled && inRect(x, y, w, h);
+ bool res = buttonLogic(id, over);
+
+ const int cx = x + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
+ const int cy = y + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
+ addGfxCmdRoundedRect((float)cx - 3, (float)cy - 3, (float)CHECK_SIZE + 6, (float)CHECK_SIZE + 6, 4, imguiRGBA(128, 128, 128, isActive(id) ? 196 : 96));
+ if (checked)
+ {
+ if (enabled)
+ addGfxCmdRoundedRect((float)cx, (float)cy, (float)CHECK_SIZE, (float)CHECK_SIZE, (float)CHECK_SIZE / 2 - 1, imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200));
+ else
+ addGfxCmdRoundedRect((float)cx, (float)cy, (float)CHECK_SIZE, (float)CHECK_SIZE, (float)CHECK_SIZE / 2 - 1, imguiRGBA(128, 128, 128, 200));
+ }
+
+ if (enabled)
+ addGfxCmdText(x + BUTTON_HEIGHT, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200));
+ else
+ addGfxCmdText(x + BUTTON_HEIGHT, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128, 128, 128, 200));
+
+ return res;
+}
+
+bool imguiCollapse(const char* text, const char* subtext, bool checked, bool enabled)
+{
+ g_state.widgetId++;
+ unsigned int id = (g_state.areaId << 16) | g_state.widgetId;
+
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ int w = g_state.widgetW;
+ int h = BUTTON_HEIGHT;
+ g_state.widgetY -= BUTTON_HEIGHT; // + DEFAULT_SPACING;
+
+ const int cx = x + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
+ const int cy = y + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
+
+ bool over = enabled && inRect(x, y, w, h);
+ bool res = buttonLogic(id, over);
+
+ if (checked)
+ addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 2, imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200));
+ else
+ addGfxCmdTriangle(cx, cy, CHECK_SIZE, CHECK_SIZE, 1, imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200));
+
+ if (enabled)
+ addGfxCmdText(x + BUTTON_HEIGHT, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200));
+ else
+ addGfxCmdText(x + BUTTON_HEIGHT, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128, 128, 128, 200));
+
+ if (subtext)
+ addGfxCmdText(x + w - BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_RIGHT, subtext, imguiRGBA(255, 255, 255, 128));
+
+ return res;
+}
+
+void imguiLabel(const char* text)
+{
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ g_state.widgetY -= BUTTON_HEIGHT;
+ addGfxCmdText(x, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, imguiRGBA(255, 255, 255, 255));
+}
+
+void imguiValue(const char* text)
+{
+ const int x = g_state.widgetX;
+ const int y = g_state.widgetY - BUTTON_HEIGHT;
+ const int w = g_state.widgetW;
+ g_state.widgetY -= BUTTON_HEIGHT;
+
+ addGfxCmdText(x + w - BUTTON_HEIGHT / 2, y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_RIGHT, text, imguiRGBA(255, 255, 255, 200));
+}
+
+bool imguiSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled)
+{
+ g_state.widgetId++;
+ unsigned int id = (g_state.areaId << 16) | g_state.widgetId;
+
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - BUTTON_HEIGHT;
+ int w = g_state.widgetW;
+ int h = SLIDER_HEIGHT;
+ g_state.widgetY -= SLIDER_HEIGHT + DEFAULT_SPACING;
+
+ addGfxCmdRoundedRect((float)x, (float)y, (float)w, (float)h, 4.0f, imguiRGBA(0, 0, 0, 128));
+
+ const int range = w - SLIDER_MARKER_WIDTH;
+
+ float u = (*val - vmin) / (vmax - vmin);
+ if (u < 0) u = 0;
+ if (u > 1) u = 1;
+ int m = (int)(u * range);
+
+ bool over = enabled && inRect(x + m, y, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT);
+ bool res = buttonLogic(id, over);
+ bool valChanged = false;
+
+ if (isActive(id))
+ {
+ if (g_state.wentActive)
+ {
+ g_state.dragX = g_state.mx;
+ g_state.dragOrig = u;
+ }
+ if (g_state.dragX != g_state.mx)
+ {
+ u = g_state.dragOrig + (float)(g_state.mx - g_state.dragX) / (float)range;
+ if (u < 0) u = 0;
+ if (u > 1) u = 1;
+ *val = vmin + u*(vmax - vmin);
+ *val = floorf(*val / vinc + 0.5f)*vinc; // Snap to vinc
+ m = (int)(u * range);
+ valChanged = true;
+ }
+ }
+
+ if (isActive(id))
+ addGfxCmdRoundedRect((float)(x + m), (float)y, (float)SLIDER_MARKER_WIDTH, (float)SLIDER_HEIGHT, 4.0f, imguiRGBA(255, 255, 255, 255));
+ else
+ addGfxCmdRoundedRect((float)(x + m), (float)y, (float)SLIDER_MARKER_WIDTH, (float)SLIDER_HEIGHT, 4.0f, isHot(id) ? imguiRGBA(255, 196, 0, 128) : imguiRGBA(255, 255, 255, 64));
+
+ // TODO: fix this, take a look at 'nicenum'.
+ int digits = (int)(ceilf(log10f(vinc)));
+ char fmt[16];
+ snprintf(fmt, 16, "%%.%df", digits >= 0 ? 0 : -digits);
+ char msg[128];
+ snprintf(msg, 128, fmt, *val);
+
+ if (enabled)
+ {
+ addGfxCmdText(x + SLIDER_HEIGHT / 2, y + SLIDER_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200));
+ addGfxCmdText(x + w - SLIDER_HEIGHT / 2, y + SLIDER_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_RIGHT, msg, isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200));
+ }
+ else
+ {
+ addGfxCmdText(x + SLIDER_HEIGHT / 2, y + SLIDER_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_LEFT, text, imguiRGBA(128, 128, 128, 200));
+ addGfxCmdText(x + w - SLIDER_HEIGHT / 2, y + SLIDER_HEIGHT / 2 - TEXT_HEIGHT / 2, IMGUI_ALIGN_RIGHT, msg, imguiRGBA(128, 128, 128, 200));
+ }
+
+ return res || valChanged;
+}
+
+
+void imguiIndent()
+{
+ g_state.widgetX += INDENT_SIZE;
+ g_state.widgetW -= INDENT_SIZE;
+}
+
+void imguiUnindent()
+{
+ g_state.widgetX -= INDENT_SIZE;
+ g_state.widgetW += INDENT_SIZE;
+}
+
+void imguiSeparator()
+{
+ g_state.widgetY -= DEFAULT_SPACING * 3;
+}
+
+void imguiSeparatorLine()
+{
+ int x = g_state.widgetX;
+ int y = g_state.widgetY - DEFAULT_SPACING * 2;
+ int w = g_state.widgetW;
+ int h = 1;
+ g_state.widgetY -= DEFAULT_SPACING * 4;
+
+ addGfxCmdRect((float)x, (float)y, (float)w, (float)h, imguiRGBA(255, 255, 255, 32));
+}
+
+void imguiDrawText(int x, int y, int align, const char* text, unsigned int color)
+{
+ addGfxCmdText(x, y, align, text, color);
+}
+
+void imguiDrawLine(float x0, float y0, float x1, float y1, float r, unsigned int color)
+{
+ addGfxCmdLine(x0, y0, x1, y1, r, color);
+}
+
+void imguiDrawRect(float x, float y, float w, float h, unsigned int color)
+{
+ addGfxCmdRect(x, y, w, h, color);
+}
+
+void imguiDrawRoundedRect(float x, float y, float w, float h, float r, unsigned int color)
+{
+ addGfxCmdRoundedRect(x, y, w, h, r, color);
+}
+
diff --git a/demo/DemoApp/imgui.h b/demo/DemoApp/imgui.h
new file mode 100644
index 0000000..e01f374
--- /dev/null
+++ b/demo/DemoApp/imgui.h
@@ -0,0 +1,108 @@
+//
+// Copyright (c) 2009-2010 Mikko Mononen [email protected]
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+//
+
+#ifndef IMGUI_H
+#define IMGUI_H
+
+enum imguiMouseButton
+{
+ IMGUI_MBUT_LEFT = 0x01,
+ IMGUI_MBUT_RIGHT = 0x02,
+};
+
+enum imguiTextAlign
+{
+ IMGUI_ALIGN_LEFT,
+ IMGUI_ALIGN_CENTER,
+ IMGUI_ALIGN_RIGHT,
+};
+
+inline unsigned int imguiRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255)
+{
+ return (r) | (g << 8) | (b << 16) | (a << 24);
+}
+
+void imguiBeginFrame(int mx, int my, unsigned char mbut, int scroll);
+void imguiEndFrame();
+
+bool imguiBeginScrollArea(const char* name, int x, int y, int w, int h, int* scroll);
+void imguiEndScrollArea();
+
+void imguiIndent();
+void imguiUnindent();
+void imguiSeparator();
+void imguiSeparatorLine();
+
+bool imguiButton(const char* text, bool enabled = true);
+bool imguiItem(const char* text, bool enabled = true, unsigned int color = imguiRGBA(255, 255, 255, 200));
+bool imguiCheck(const char* text, bool checked, bool enabled = true);
+bool imguiCollapse(const char* text, const char* subtext, bool checked, bool enabled = true);
+void imguiLabel(const char* text);
+void imguiValue(const char* text);
+bool imguiSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled = true);
+
+void imguiDrawText(int x, int y, int align, const char* text, unsigned int color);
+void imguiDrawLine(float x0, float y0, float x1, float y1, float r, unsigned int color);
+void imguiDrawRoundedRect(float x, float y, float w, float h, float r, unsigned int color);
+void imguiDrawRect(float x, float y, float w, float h, unsigned int color);
+
+// Pull render interface.
+enum imguiGfxCmdType
+{
+ IMGUI_GFXCMD_RECT,
+ IMGUI_GFXCMD_TRIANGLE,
+ IMGUI_GFXCMD_LINE,
+ IMGUI_GFXCMD_TEXT,
+ IMGUI_GFXCMD_SCISSOR,
+};
+
+struct imguiGfxRect
+{
+ short x, y, w, h, r;
+};
+
+struct imguiGfxText
+{
+ short x, y, align;
+ const char* text;
+};
+
+struct imguiGfxLine
+{
+ short x0, y0, x1, y1, r;
+};
+
+struct imguiGfxCmd
+{
+ char type;
+ char flags;
+ char pad[2];
+ unsigned int col;
+ union
+ {
+ imguiGfxLine line;
+ imguiGfxRect rect;
+ imguiGfxText text;
+ };
+};
+
+const imguiGfxCmd* imguiGetRenderQueue();
+int imguiGetRenderQueueSize();
+
+
+#endif // IMGUI_H \ No newline at end of file
diff --git a/demo/DemoApp/imguiGraph.cpp b/demo/DemoApp/imguiGraph.cpp
new file mode 100644
index 0000000..345b74a
--- /dev/null
+++ b/demo/DemoApp/imguiGraph.cpp
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include "imgui.h"
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "imguiGraph.h"
+
+// Some math headers don't have PI defined.
+static const float PI = 3.14159265f;
+
+void imguifree(void* ptr, void* userptr);
+void* imguimalloc(size_t size, void* userptr);
+
+#define STBTT_malloc(x,y) imguimalloc(x,y)
+#define STBTT_free(x,y) imguifree(x,y)
+#define STB_TRUETYPE_IMPLEMENTATION
+#include "stb_truetype.h"
+
+void imguifree(void* ptr, void* /*userptr*/)
+{
+ free(ptr);
+}
+
+void* imguimalloc(size_t size, void* /*userptr*/)
+{
+ return malloc(size);
+}
+
+static const unsigned TEMP_COORD_COUNT = 100;
+static float g_tempCoords[TEMP_COORD_COUNT * 2];
+static float g_tempNormals[TEMP_COORD_COUNT * 2];
+
+static const int CIRCLE_VERTS = 8 * 4;
+static float g_circleVerts[CIRCLE_VERTS * 2];
+
+static stbtt_bakedchar g_cdata[96]; // ASCII 32..126 is 95 glyphs
+
+inline unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ return (r) | (g << 8) | (b << 16) | (a << 24);
+}
+
+static void drawPolygon(const float* coords, unsigned numCoords, float r, unsigned int col)
+{
+ if (numCoords > TEMP_COORD_COUNT) numCoords = TEMP_COORD_COUNT;
+
+ for (unsigned i = 0, j = numCoords - 1; i < numCoords; j = i++)
+ {
+ const float* v0 = &coords[j * 2];
+ const float* v1 = &coords[i * 2];
+ float dx = v1[0] - v0[0];
+ float dy = v1[1] - v0[1];
+ float d = sqrtf(dx*dx + dy*dy);
+ if (d > 0)
+ {
+ d = 1.0f / d;
+ dx *= d;
+ dy *= d;
+ }
+ g_tempNormals[j * 2 + 0] = dy;
+ g_tempNormals[j * 2 + 1] = -dx;
+ }
+
+ for (unsigned i = 0, j = numCoords - 1; i < numCoords; j = i++)
+ {
+ float dlx0 = g_tempNormals[j * 2 + 0];
+ float dly0 = g_tempNormals[j * 2 + 1];
+ float dlx1 = g_tempNormals[i * 2 + 0];
+ float dly1 = g_tempNormals[i * 2 + 1];
+ float dmx = (dlx0 + dlx1) * 0.5f;
+ float dmy = (dly0 + dly1) * 0.5f;
+ float dmr2 = dmx*dmx + dmy*dmy;
+ if (dmr2 > 0.000001f)
+ {
+ float scale = 1.0f / dmr2;
+ if (scale > 10.0f) scale = 10.0f;
+ dmx *= scale;
+ dmy *= scale;
+ }
+ g_tempCoords[i * 2 + 0] = coords[i * 2 + 0] + dmx*r;
+ g_tempCoords[i * 2 + 1] = coords[i * 2 + 1] + dmy*r;
+ }
+
+ unsigned int colTrans = RGBA(col & 0xff, (col >> 8) & 0xff, (col >> 16) & 0xff, 0);
+
+ imguiGraphColor4ubv((uint8_t*)&col);
+
+ for (unsigned i = 0, j = numCoords - 1; i < numCoords; j = i++)
+ {
+ imguiGraphVertex2fv(&coords[i * 2]);
+ imguiGraphVertex2fv(&coords[j * 2]);
+ imguiGraphColor4ubv((uint8_t*)&colTrans);
+ imguiGraphVertex2fv(&g_tempCoords[j * 2]);
+
+ imguiGraphVertex2fv(&g_tempCoords[j * 2]);
+ imguiGraphVertex2fv(&g_tempCoords[i * 2]);
+
+ imguiGraphColor4ubv((uint8_t*)&col);
+ imguiGraphVertex2fv(&coords[i * 2]);
+ }
+
+ imguiGraphColor4ubv((uint8_t*)&col);
+ for (unsigned i = 2; i < numCoords; ++i)
+ {
+ imguiGraphVertex2fv(&coords[0]);
+ imguiGraphVertex2fv(&coords[(i - 1) * 2]);
+ imguiGraphVertex2fv(&coords[i * 2]);
+ }
+}
+
+static void drawRect(float x, float y, float w, float h, float fth, unsigned int col)
+{
+ float verts[4 * 2] =
+ {
+ x + 0.5f, y + 0.5f,
+ x + w - 0.5f, y + 0.5f,
+ x + w - 0.5f, y + h - 0.5f,
+ x + 0.5f, y + h - 0.5f,
+ };
+ drawPolygon(verts, 4, fth, col);
+}
+
+/*
+static void drawEllipse(float x, float y, float w, float h, float fth, unsigned int col)
+{
+float verts[CIRCLE_VERTS*2];
+const float* cverts = g_circleVerts;
+float* v = verts;
+
+for (int i = 0; i < CIRCLE_VERTS; ++i)
+{
+*v++ = x + cverts[i*2]*w;
+*v++ = y + cverts[i*2+1]*h;
+}
+
+drawPolygon(verts, CIRCLE_VERTS, fth, col);
+}
+*/
+
+static void drawRoundedRect(float x, float y, float w, float h, float r, float fth, unsigned int col)
+{
+ const unsigned n = CIRCLE_VERTS / 4;
+ float verts[(n + 1) * 4 * 2];
+ const float* cverts = g_circleVerts;
+ float* v = verts;
+
+ for (unsigned i = 0; i <= n; ++i)
+ {
+ *v++ = x + w - r + cverts[i * 2] * r;
+ *v++ = y + h - r + cverts[i * 2 + 1] * r;
+ }
+
+ for (unsigned i = n; i <= n * 2; ++i)
+ {
+ *v++ = x + r + cverts[i * 2] * r;
+ *v++ = y + h - r + cverts[i * 2 + 1] * r;
+ }
+
+ for (unsigned i = n * 2; i <= n * 3; ++i)
+ {
+ *v++ = x + r + cverts[i * 2] * r;
+ *v++ = y + r + cverts[i * 2 + 1] * r;
+ }
+
+ for (unsigned i = n * 3; i < n * 4; ++i)
+ {
+ *v++ = x + w - r + cverts[i * 2] * r;
+ *v++ = y + r + cverts[i * 2 + 1] * r;
+ }
+ *v++ = x + w - r + cverts[0] * r;
+ *v++ = y + r + cverts[1] * r;
+
+ drawPolygon(verts, (n + 1) * 4, fth, col);
+}
+
+
+static void drawLine(float x0, float y0, float x1, float y1, float r, float fth, unsigned int col)
+{
+ float dx = x1 - x0;
+ float dy = y1 - y0;
+ float d = sqrtf(dx*dx + dy*dy);
+ if (d > 0.0001f)
+ {
+ d = 1.0f / d;
+ dx *= d;
+ dy *= d;
+ }
+ float nx = dy;
+ float ny = -dx;
+ float verts[4 * 2];
+ r -= fth;
+ r *= 0.5f;
+ if (r < 0.01f) r = 0.01f;
+ dx *= r;
+ dy *= r;
+ nx *= r;
+ ny *= r;
+
+ verts[0] = x0 - dx - nx;
+ verts[1] = y0 - dy - ny;
+
+ verts[2] = x0 - dx + nx;
+ verts[3] = y0 - dy + ny;
+
+ verts[4] = x1 + dx + nx;
+ verts[5] = y1 + dy + ny;
+
+ verts[6] = x1 + dx - nx;
+ verts[7] = y1 + dy - ny;
+
+ drawPolygon(verts, 4, fth, col);
+}
+
+
+bool imguiGraphInit(const char* fontpath, const ImguiGraphDesc* desc)
+{
+ imguiGraphContextInit(desc);
+
+ for (int i = 0; i < CIRCLE_VERTS; ++i)
+ {
+ float a = (float)i / (float)CIRCLE_VERTS * PI * 2;
+ g_circleVerts[i * 2 + 0] = cosf(a);
+ g_circleVerts[i * 2 + 1] = sinf(a);
+ }
+
+ // Load font.
+ FILE* fp = fopen(fontpath, "rb");
+ if (!fp) return false;
+ fseek(fp, 0, SEEK_END);
+ int size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ unsigned char* ttfBuffer = (unsigned char*)malloc(size);
+ if (!ttfBuffer)
+ {
+ fclose(fp);
+ return false;
+ }
+
+ size_t len = fread(ttfBuffer, 1, size, fp);
+ (void)len;
+
+ fclose(fp);
+ fp = 0;
+
+ unsigned char* bmap = (unsigned char*)malloc(512 * 512);
+ if (!bmap)
+ {
+ free(ttfBuffer);
+ return false;
+ }
+
+ stbtt_BakeFontBitmap(ttfBuffer, 0, 15.0f, bmap, 512, 512, 32, 96, g_cdata);
+
+ // can free ttf_buffer at this point
+ imguiGraphFontTextureInit(bmap);
+
+ free(ttfBuffer);
+ free(bmap);
+
+ return true;
+}
+
+void imguiGraphUpdate(const ImguiGraphDesc* desc)
+{
+ imguiGraphContextUpdate(desc);
+}
+
+void imguiGraphDestroy()
+{
+ imguiGraphFontTextureRelease();
+
+ imguiGraphContextDestroy();
+}
+
+static void getBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index,
+ float *xpos, float *ypos, stbtt_aligned_quad *q)
+{
+ stbtt_bakedchar *b = chardata + char_index;
+ int round_x = STBTT_ifloor(*xpos + b->xoff);
+ int round_y = STBTT_ifloor(*ypos - b->yoff);
+
+ q->x0 = (float)round_x;
+ q->y0 = (float)round_y;
+ q->x1 = (float)round_x + b->x1 - b->x0;
+ q->y1 = (float)round_y - b->y1 + b->y0;
+
+ q->s0 = b->x0 / (float)pw;
+ q->t0 = b->y0 / (float)pw;
+ q->s1 = b->x1 / (float)ph;
+ q->t1 = b->y1 / (float)ph;
+
+ *xpos += b->xadvance;
+}
+
+static const float g_tabStops[4] = { 150, 210, 270, 330 };
+
+static float getTextLength(stbtt_bakedchar *chardata, const char* text)
+{
+ float xpos = 0;
+ float len = 0;
+ while (*text)
+ {
+ int c = (unsigned char)*text;
+ if (c == '\t')
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (xpos < g_tabStops[i])
+ {
+ xpos = g_tabStops[i];
+ break;
+ }
+ }
+ }
+ else if (c >= 32 && c < 128)
+ {
+ stbtt_bakedchar *b = chardata + c - 32;
+ int round_x = STBTT_ifloor((xpos + b->xoff) + 0.5);
+ len = round_x + b->x1 - b->x0 + 0.5f;
+ xpos += b->xadvance;
+ }
+ ++text;
+ }
+ return len;
+}
+
+static void drawText(float x, float y, const char *text, int align, unsigned int col)
+{
+ if (!text) return;
+
+ if (align == IMGUI_ALIGN_CENTER)
+ x -= getTextLength(g_cdata, text) / 2;
+ else if (align == IMGUI_ALIGN_RIGHT)
+ x -= getTextLength(g_cdata, text);
+
+ imguiGraphColor4ub(col & 0xff, (col >> 8) & 0xff, (col >> 16) & 0xff, (col >> 24) & 0xff);
+
+ imguiGraphFontTextureEnable();
+
+ // assume orthographic projection with units = screen pixels, origin at top left
+ const float ox = x;
+
+ while (*text)
+ {
+ int c = (unsigned char)*text;
+ if (c == '\t')
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (x < g_tabStops[i] + ox)
+ {
+ x = g_tabStops[i] + ox;
+ break;
+ }
+ }
+ }
+ else if (c >= 32 && c < 128)
+ {
+ stbtt_aligned_quad q;
+ getBakedQuad(g_cdata, 512, 512, c - 32, &x, &y, &q);
+
+ imguiGraphTexCoord2f(q.s0, q.t0);
+ imguiGraphVertex2f(q.x0, q.y0);
+ imguiGraphTexCoord2f(q.s1, q.t1);
+ imguiGraphVertex2f(q.x1, q.y1);
+ imguiGraphTexCoord2f(q.s1, q.t0);
+ imguiGraphVertex2f(q.x1, q.y0);
+
+ imguiGraphTexCoord2f(q.s0, q.t0);
+ imguiGraphVertex2f(q.x0, q.y0);
+ imguiGraphTexCoord2f(q.s0, q.t1);
+ imguiGraphVertex2f(q.x0, q.y1);
+ imguiGraphTexCoord2f(q.s1, q.t1);
+ imguiGraphVertex2f(q.x1, q.y1);
+ }
+ ++text;
+ }
+
+ imguiGraphFontTextureDisable();
+}
+
+
+void imguiGraphDraw()
+{
+ const imguiGfxCmd* q = imguiGetRenderQueue();
+ int nq = imguiGetRenderQueueSize();
+
+ const float s = 1.0f / 8.0f;
+
+ imguiGraphRecordBegin();
+
+ imguiGraphDisableScissor();
+ for (int i = 0; i < nq; ++i)
+ {
+ const imguiGfxCmd& cmd = q[i];
+ if (cmd.type == IMGUI_GFXCMD_RECT)
+ {
+ if (cmd.rect.r == 0)
+ {
+ drawRect((float)cmd.rect.x*s + 0.5f, (float)cmd.rect.y*s + 0.5f,
+ (float)cmd.rect.w*s - 1, (float)cmd.rect.h*s - 1,
+ 1.0f, cmd.col);
+ }
+ else
+ {
+ drawRoundedRect((float)cmd.rect.x*s + 0.5f, (float)cmd.rect.y*s + 0.5f,
+ (float)cmd.rect.w*s - 1, (float)cmd.rect.h*s - 1,
+ (float)cmd.rect.r*s, 1.0f, cmd.col);
+ }
+ }
+ else if (cmd.type == IMGUI_GFXCMD_LINE)
+ {
+ drawLine(cmd.line.x0*s, cmd.line.y0*s, cmd.line.x1*s, cmd.line.y1*s, cmd.line.r*s, 1.0f, cmd.col);
+ }
+ else if (cmd.type == IMGUI_GFXCMD_TRIANGLE)
+ {
+ if (cmd.flags == 1)
+ {
+ const float verts[3 * 2] =
+ {
+ (float)cmd.rect.x*s + 0.5f, (float)cmd.rect.y*s + 0.5f,
+ (float)cmd.rect.x*s + 0.5f + (float)cmd.rect.w*s - 1, (float)cmd.rect.y*s + 0.5f + (float)cmd.rect.h*s / 2 - 0.5f,
+ (float)cmd.rect.x*s + 0.5f, (float)cmd.rect.y*s + 0.5f + (float)cmd.rect.h*s - 1,
+ };
+ drawPolygon(verts, 3, 1.0f, cmd.col);
+ }
+ if (cmd.flags == 2)
+ {
+ const float verts[3 * 2] =
+ {
+ (float)cmd.rect.x*s + 0.5f, (float)cmd.rect.y*s + 0.5f + (float)cmd.rect.h*s - 1,
+ (float)cmd.rect.x*s + 0.5f + (float)cmd.rect.w*s / 2 - 0.5f, (float)cmd.rect.y*s + 0.5f,
+ (float)cmd.rect.x*s + 0.5f + (float)cmd.rect.w*s - 1, (float)cmd.rect.y*s + 0.5f + (float)cmd.rect.h*s - 1,
+ };
+ drawPolygon(verts, 3, 1.0f, cmd.col);
+ }
+ }
+ else if (cmd.type == IMGUI_GFXCMD_TEXT)
+ {
+ drawText(cmd.text.x, cmd.text.y, cmd.text.text, cmd.text.align, cmd.col);
+ }
+ else if (cmd.type == IMGUI_GFXCMD_SCISSOR)
+ {
+ if (cmd.flags)
+ {
+ imguiGraphEnableScissor(cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h);
+ }
+ else
+ {
+ imguiGraphDisableScissor();
+ }
+ }
+ }
+ imguiGraphDisableScissor();
+
+ imguiGraphRecordEnd();
+}
diff --git a/demo/DemoApp/imguiGraph.h b/demo/DemoApp/imguiGraph.h
new file mode 100644
index 0000000..0d64aa7
--- /dev/null
+++ b/demo/DemoApp/imguiGraph.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#define IMGUI_GRAPH_API extern "C" __declspec(dllexport)
+
+struct ImguiGraphDesc;
+
+typedef bool (*imguiGraphInit_t)(const char* fontpath, const ImguiGraphDesc* desc);
+
+typedef void (*imguiGraphUpdate_t)(const ImguiGraphDesc* desc);
+
+bool imguiGraphInit(const char* fontpath, const ImguiGraphDesc* desc);
+
+void imguiGraphUpdate(const ImguiGraphDesc* desc);
+
+void imguiGraphDestroy();
+
+void imguiGraphDraw();
+
+// Below are the functions that must be implemented per graphics API
+
+IMGUI_GRAPH_API void imguiGraphContextInit(const ImguiGraphDesc* desc);
+
+IMGUI_GRAPH_API void imguiGraphContextUpdate(const ImguiGraphDesc* desc);
+
+IMGUI_GRAPH_API void imguiGraphContextDestroy();
+
+IMGUI_GRAPH_API void imguiGraphRecordBegin();
+
+IMGUI_GRAPH_API void imguiGraphRecordEnd();
+
+IMGUI_GRAPH_API void imguiGraphVertex2f(float x, float y);
+
+IMGUI_GRAPH_API void imguiGraphVertex2fv(const float* v);
+
+IMGUI_GRAPH_API void imguiGraphTexCoord2f(float u, float v);
+
+IMGUI_GRAPH_API void imguiGraphColor4ub(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha);
+
+IMGUI_GRAPH_API void imguiGraphColor4ubv(const uint8_t* v);
+
+IMGUI_GRAPH_API void imguiGraphFontTextureEnable();
+
+IMGUI_GRAPH_API void imguiGraphFontTextureDisable();
+
+IMGUI_GRAPH_API void imguiGraphEnableScissor(int x, int y, int width, int height);
+
+IMGUI_GRAPH_API void imguiGraphDisableScissor();
+
+IMGUI_GRAPH_API void imguiGraphFontTextureInit(unsigned char* data);
+
+IMGUI_GRAPH_API void imguiGraphFontTextureRelease(); \ No newline at end of file
diff --git a/demo/DemoApp/imguiGraphLoader.cpp b/demo/DemoApp/imguiGraphLoader.cpp
new file mode 100644
index 0000000..155e9f3
--- /dev/null
+++ b/demo/DemoApp/imguiGraphLoader.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <SDL.h>
+
+#include "loader.h"
+
+#include "imguiGraph.h"
+#include "imguiInterop.h"
+
+namespace
+{
+ ModuleLoader<24u, SDL_LoadObject, SDL_UnloadObject, SDL_LoadFunction> g_loader;
+}
+
+void loadImgui(AppGraphCtxType type)
+{
+ const char* moduleName = demoAppDLLName(type);
+
+ g_loader.loadModule(moduleName);
+}
+
+void unloadImgui()
+{
+ g_loader.unloadModule();
+}
+
+// Below are the functions that must be implemented per graphics API
+
+void imguiGraphContextInit(const ImguiGraphDesc* desc)
+{
+ return g_loader.function<0>(imguiGraphContextInit, "imguiGraphContextInit", desc);
+}
+
+void imguiGraphContextUpdate(const ImguiGraphDesc* desc)
+{
+ return g_loader.function<1>(imguiGraphContextUpdate, "imguiGraphContextUpdate", desc);
+}
+
+void imguiGraphContextDestroy()
+{
+ return g_loader.function<2>(imguiGraphContextDestroy, "imguiGraphContextDestroy");
+}
+
+void imguiGraphRecordBegin()
+{
+ return g_loader.function<3>(imguiGraphRecordBegin, "imguiGraphRecordBegin");
+}
+
+void imguiGraphRecordEnd()
+{
+ return g_loader.function<4>(imguiGraphRecordEnd, "imguiGraphRecordEnd");
+}
+
+void imguiGraphVertex2f(float x, float y)
+{
+ return g_loader.function<5>(imguiGraphVertex2f, "imguiGraphVertex2f", x, y);
+}
+
+void imguiGraphVertex2fv(const float* v)
+{
+ return g_loader.function<6>(imguiGraphVertex2fv, "imguiGraphVertex2fv", v);
+}
+
+void imguiGraphTexCoord2f(float u, float v)
+{
+ return g_loader.function<7>(imguiGraphTexCoord2f, "imguiGraphTexCoord2f", u, v);
+}
+
+void imguiGraphColor4ub(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
+{
+ return g_loader.function<8>(imguiGraphColor4ub, "imguiGraphColor4ub", red, green, blue, alpha);
+}
+
+void imguiGraphColor4ubv(const uint8_t* v)
+{
+ return g_loader.function<9>(imguiGraphColor4ubv, "imguiGraphColor4ubv", v);
+}
+
+void imguiGraphFontTextureEnable()
+{
+ return g_loader.function<10>(imguiGraphFontTextureEnable, "imguiGraphFontTextureEnable");
+}
+
+void imguiGraphFontTextureDisable()
+{
+ return g_loader.function<11>(imguiGraphFontTextureDisable, "imguiGraphFontTextureDisable");
+}
+
+void imguiGraphEnableScissor(int x, int y, int width, int height)
+{
+ return g_loader.function<12>(imguiGraphEnableScissor, "imguiGraphEnableScissor", x, y, width, height);
+}
+
+void imguiGraphDisableScissor()
+{
+ return g_loader.function<13>(imguiGraphDisableScissor, "imguiGraphDisableScissor");
+}
+
+void imguiGraphFontTextureInit(unsigned char* data)
+{
+ return g_loader.function<14>(imguiGraphFontTextureInit, "imguiGraphFontTextureInit",data);
+}
+
+void imguiGraphFontTextureRelease()
+{
+ return g_loader.function<15>(imguiGraphFontTextureRelease, "imguiGraphFontTextureRelease");
+}
+
+bool imguiInteropGraphInit(imguiGraphInit_t func, const char* fontpath, AppGraphCtx* appctx)
+{
+ return g_loader.function<16>(imguiInteropGraphInit, "imguiInteropGraphInit", func, fontpath, appctx);
+}
+
+void imguiInteropGraphUpdate(imguiGraphUpdate_t func, AppGraphCtx* appctx)
+{
+ return g_loader.function<17>(imguiInteropGraphUpdate, "imguiInteropGraphUpdate", func, appctx);
+} \ No newline at end of file
diff --git a/demo/DemoApp/imguiInterop.h b/demo/DemoApp/imguiInterop.h
new file mode 100644
index 0000000..3cbbe96
--- /dev/null
+++ b/demo/DemoApp/imguiInterop.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#include "imguiGraph.h"
+
+#include "appGraphCtx.h"
+
+IMGUI_GRAPH_API bool imguiInteropGraphInit(imguiGraphInit_t func, const char* fontpath, AppGraphCtx* appctx);
+
+IMGUI_GRAPH_API void imguiInteropGraphUpdate(imguiGraphUpdate_t func, AppGraphCtx* appctx); \ No newline at end of file
diff --git a/demo/DemoApp/imguiser.cpp b/demo/DemoApp/imguiser.cpp
new file mode 100644
index 0000000..64018d0
--- /dev/null
+++ b/demo/DemoApp/imguiser.cpp
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "imguiser.h"
+
+#include <stdio.h>
+
+#include <vector>
+
+namespace
+{
+ std::vector<ImserNode> g_nodes;
+
+ bool g_shouldSave = false;
+ bool g_shouldLoad = false;
+ bool g_shouldLoadC = false;
+ bool g_saveProcessActive = false;
+ bool g_loadProcessActive = false;
+
+ char g_saveFilename[256u];
+ char g_loadFilename[256u];
+ const ImserNode* g_loadC_nodes = nullptr;
+ unsigned int g_loadC_sizeInBytes = 0;
+
+ const int TEXT_POOL_CAP = 16u * 1024u;
+ char g_textPool[TEXT_POOL_CAP];
+ int g_textPoolIdx = 0;
+
+ char* allocText(const char* text)
+ {
+ if (text == nullptr)
+ {
+ return nullptr;
+ }
+ int len = (int)(strlen(text) + 1);
+ if (g_textPoolIdx + len < TEXT_POOL_CAP)
+ {
+ char* dst = &g_textPool[g_textPoolIdx];
+ memcpy(dst, text, len);
+ g_textPoolIdx += len;
+ return dst;
+ }
+ return nullptr;
+ }
+
+ struct TreeNode
+ {
+ int node;
+ int parent;
+ int childStart;
+ int childEnd;
+ int next;
+ int childCount;
+ };
+
+ std::vector<TreeNode> g_treeNodes;
+ int g_treeNodeIdxScope = 0;
+ int g_treeNodeIdxSearch = 0;
+ int g_treeNoMatchGroupRef = 0;
+
+ bool treeSearch(const char* name)
+ {
+ if (g_treeNoMatchGroupRef != 0)
+ {
+ return false;
+ }
+ if (name != nullptr)
+ {
+ if (g_treeNodes[g_treeNodeIdxSearch].parent != g_treeNodeIdxScope)
+ {
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxScope].childStart;
+ }
+ int startIdx = g_treeNodeIdxSearch;
+ do
+ {
+ int nodeIdx = g_treeNodes[g_treeNodeIdxSearch].node;
+ if (nodeIdx != -1 && strcmp(g_nodes[nodeIdx].name, name) == 0)
+ {
+ return true;
+ }
+ // increment seach with wrap
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxSearch].next;
+ if (g_treeNodeIdxSearch == -1)
+ {
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxScope].childStart;
+ }
+ } while (startIdx != g_treeNodeIdxSearch);
+ }
+ else
+ {
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxSearch].next;
+ if (g_treeNodeIdxSearch == -1)
+ {
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxScope].childStart;
+ }
+ }
+ return false;
+ }
+}
+
+static void imguiserDoSave(const char* filename);
+static void imguiserDoLoad(const char* filename);
+static void imguiserDoLoadC(const ImserNode* nodes, unsigned int sizeInBytes);
+
+void imguiserInit()
+{
+ g_nodes.reserve(4096u);
+ g_treeNodes.reserve(4096u);
+
+ g_shouldSave = false;
+ g_shouldLoad = false;
+ g_shouldLoadC = false;
+ g_saveProcessActive = false;
+ g_loadProcessActive = false;
+ g_saveFilename[0] = '\0';
+ g_loadFilename[0] = '\0';
+ g_loadC_nodes = nullptr;
+ g_loadC_sizeInBytes = 0;
+}
+
+void imguiserUpdate()
+{
+ if (g_saveProcessActive)
+ {
+ imguiserDoSave(g_saveFilename);
+ g_saveProcessActive = false;
+ }
+ if (g_loadProcessActive)
+ {
+ g_loadProcessActive = false;
+ }
+ if (g_shouldSave)
+ {
+ g_saveProcessActive = true;
+ g_shouldSave = false;
+ }
+ if (g_shouldLoad)
+ {
+ imguiserDoLoad(g_loadFilename);
+ if(g_shouldLoad) g_loadProcessActive = true;
+ g_shouldLoad = false;
+ }
+ if (g_shouldLoadC)
+ {
+ imguiserDoLoadC(g_loadC_nodes, g_loadC_sizeInBytes);
+ if (g_shouldLoadC) g_loadProcessActive = true;
+ g_shouldLoadC = false;
+ }
+}
+
+void imguiserDestroy()
+{
+
+}
+
+void imguiserBeginFrame()
+{
+ if (!g_loadProcessActive)
+ {
+ g_nodes.clear();
+ // reset text pool
+ g_textPoolIdx = 0;
+ }
+ g_treeNodeIdxScope = 0;
+ g_treeNodeIdxSearch = 0;
+ g_treeNoMatchGroupRef = 0;
+}
+
+void imguiserEndFrame()
+{
+
+}
+
+void imguiserBeginGroup(const char* name, int* numItems)
+{
+ if (g_saveProcessActive)
+ {
+ ImserNode group = imserNodeGroupBegin(name);
+
+ g_nodes.push_back(group);
+ }
+ if (g_loadProcessActive)
+ {
+ // search for group with matching name
+ if (treeSearch(name))
+ {
+ g_treeNodeIdxScope = g_treeNodeIdxSearch;
+ if (g_treeNodeIdxScope == -1) g_treeNodeIdxScope = 0;
+ g_treeNodeIdxSearch = g_treeNodes[g_treeNodeIdxScope].childStart;
+
+ if (numItems)
+ {
+ *numItems = g_treeNodes[g_treeNodeIdxScope].childCount;
+ }
+ }
+ else
+ {
+ g_treeNoMatchGroupRef++;
+ g_treeNodeIdxScope++;
+ }
+ }
+}
+
+void imguiserEndGroup()
+{
+ if (g_saveProcessActive)
+ {
+ ImserNode group = imserNodeGroupEnd();
+
+ g_nodes.push_back(group);
+ }
+ if (g_loadProcessActive)
+ {
+ if (g_treeNoMatchGroupRef == 0)
+ {
+ g_treeNodeIdxScope = g_treeNodes[g_treeNodeIdxScope].parent;
+ if (g_treeNodeIdxScope == -1) g_treeNodeIdxScope = 0;
+ g_treeNodeIdxSearch = 0;
+ }
+ else
+ {
+ g_treeNoMatchGroupRef--;
+ g_treeNodeIdxScope--;
+ }
+ }
+}
+
+void imguiserValue1f(const char* text, float* val)
+{
+ if (g_saveProcessActive)
+ {
+ ImserNode item = imserNodeValue1f(text, *val);
+
+ g_nodes.push_back(item);
+ }
+ if (g_loadProcessActive)
+ {
+ if (text != nullptr)
+ {
+ if (treeSearch(text))
+ {
+ *val = g_nodes[g_treeNodes[g_treeNodeIdxSearch].node].valFloat;
+ }
+ }
+ else
+ {
+ *val = g_nodes[g_treeNodes[g_treeNodeIdxSearch].node].valFloat;
+ treeSearch(nullptr);
+ }
+ }
+}
+
+void imguiserValueBool(const char* text, bool* val)
+{
+ if (g_saveProcessActive)
+ {
+ ImserNode item = imserNodeValueBool(text, *val);
+
+ g_nodes.push_back(item);
+ }
+ if (g_loadProcessActive)
+ {
+ if (text != nullptr)
+ {
+ if (treeSearch(text))
+ {
+ *val = g_nodes[g_treeNodes[g_treeNodeIdxSearch].node].valBool;
+ }
+ }
+ else
+ {
+ *val = g_nodes[g_treeNodes[g_treeNodeIdxSearch].node].valBool;
+ treeSearch(nullptr);
+ }
+ }
+}
+
+bool imguiserCheck(const char* text, bool checked, bool enabled)
+{
+ auto ret = imguiCheck(text, checked, enabled);
+
+ bool temp = checked;
+ imguiserValueBool(text, &temp);
+ if (temp != checked) ret = true;
+
+ return ret;
+}
+
+bool imguiserSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled)
+{
+ auto ret = imguiSlider(text, val, vmin, vmax, vinc, enabled);
+
+ float temp = *val;
+ imguiserValue1f(text, val);
+ if (temp != *val) ret = true;
+
+ return ret;
+}
+
+bool imguiserOffscreenUpdate()
+{
+ return g_saveProcessActive || g_loadProcessActive;
+}
+
+void imguiserSave(const char* filename)
+{
+ g_shouldSave = true;
+ int len = int(strlen(filename) + 1);
+ if (len > 256u) len = 256u;
+ memcpy(g_saveFilename, filename, len);
+}
+
+void imguiserLoad(const char* filename)
+{
+ g_shouldLoad = true;
+ int len = int(strlen(filename) + 1);
+ if (len > 256u) len = 256u;
+ memcpy(g_loadFilename, filename, len);
+}
+
+void imguiserLoadC(const ImserNode* nodes, unsigned int sizeInBytes)
+{
+ g_shouldLoadC = true;
+ g_loadC_nodes = nodes;
+ g_loadC_sizeInBytes = sizeInBytes;
+}
+
+inline void fprintTabs(FILE* file, unsigned int count)
+{
+ static const char tabs[11u] = "\t\t\t\t\t\t\t\t\t\t";
+ char format[] = "%.Xs";
+ format[2] = '0' + (char)((count >= 10) ? 9 : count);
+ fprintf(file, format, tabs);
+}
+
+static void imguiserDoSave(const char* filename)
+{
+ FILE* file = nullptr;
+ fopen_s(&file, filename, "w");
+
+ unsigned int tabAmount = 0;
+ if (file)
+ {
+ fprintf(file, "const ImserNode g_root[] = {\n");
+ tabAmount++;
+
+ for (size_t i = 0u; i < g_nodes.size(); i++)
+ {
+ ImserNode& node = g_nodes[i];
+
+ switch (node.typeID)
+ {
+ case IMSER_TYPE_GROUP_BEGIN:
+ fprintTabs(file, tabAmount);
+ fprintf(file, "imserNodeGroupBegin(\"%s\"),\n", node.name);
+ tabAmount++;
+ break;
+ case IMSER_TYPE_GROUP_END:
+ tabAmount--;
+ fprintTabs(file, tabAmount);
+ fprintf(file, "imserNodeGroupEnd(),\n");
+ break;
+ case IMSER_TYPE_FLOAT:
+ fprintTabs(file, tabAmount);
+ if(node.name) fprintf(file, "imserNodeValue1f(\"%s\", %ff),\n", node.name, node.valFloat);
+ else fprintf(file, "imserNodeValue1f(nullptr, %ff),\n", node.valFloat);
+ break;
+ case IMSER_TYPE_BOOL:
+ fprintTabs(file, tabAmount);
+ if(node.name) fprintf(file, "imserNodeValueBool(\"%s\", %s),\n", node.name, node.valBool ? "true" : "false");
+ else fprintf(file, "imserNodeValueBool(nullptr, %s),\n", node.valBool ? "true" : "false");
+ break;
+ }
+ }
+
+ fprintf(file, "};");
+
+ fclose(file);
+ }
+}
+
+inline void skipWS(FILE* file)
+{
+ fscanf(file, "%*[ \t\n\v\f\r]");
+}
+
+inline const char* extractName(FILE* file, char* buf)
+{
+ const char* name = nullptr;
+ skipWS(file);
+ char c = fgetc(file);
+ if (c == '\"')
+ {
+ fscanf(file, "%255[^\"]", buf);
+
+ name = allocText(buf);
+ }
+ return name;
+}
+
+inline float extractValue1f(FILE* file, char* buf)
+{
+ float value = 0.f;
+ fscanf(file, "%f", &value);
+ return value;
+}
+
+inline bool extractBool(FILE* file, char* buf)
+{
+ skipWS(file);
+ fscanf(file, "%255[^,) \t\n\v\f\r]", buf);
+ bool val = false;
+ if (strcmp(buf, "true") == 0) val = true;
+ return val;
+}
+
+static void generateTree()
+{
+ // generate tree for faster searching
+ {
+ g_treeNodes.clear();
+
+ // create root node
+ {
+ TreeNode n;
+ n.node = -1;
+ n.parent = -1;
+ n.childStart = -1;
+ n.childEnd = -1;
+ n.next = -1;
+ g_treeNodes.push_back(n);
+ }
+ // generate tree by playing node list and tracking state
+ int numNodes = (int)g_nodes.size();
+ int treeNodeIdx = 0;
+ for (int nodeIdx = 0; nodeIdx < numNodes; nodeIdx++)
+ {
+ ImserNode& node = g_nodes[nodeIdx];
+
+ if (node.typeID == IMSER_TYPE_GROUP_BEGIN)
+ {
+ // create new node
+ TreeNode n;
+ n.node = nodeIdx;
+ n.parent = treeNodeIdx;
+ n.childStart = -1;
+ n.childEnd = -1;
+ n.next = -1;
+ n.childCount = 0;
+
+ if (g_treeNodes[treeNodeIdx].childEnd != -1)
+ {
+ g_treeNodes[g_treeNodes[treeNodeIdx].childEnd].next = (int)g_treeNodes.size();
+ }
+ else
+ {
+ g_treeNodes[treeNodeIdx].childStart = (int)g_treeNodes.size();
+ }
+ g_treeNodes[treeNodeIdx].childEnd = (int)g_treeNodes.size();
+ g_treeNodes[treeNodeIdx].childCount++;
+
+ treeNodeIdx = (int)g_treeNodes.size();
+
+ g_treeNodes.push_back(n);
+ }
+ else if (node.typeID == IMSER_TYPE_GROUP_END)
+ {
+ // move active scope back to parent
+ if (treeNodeIdx != -1)
+ {
+ treeNodeIdx = g_treeNodes[treeNodeIdx].parent;
+ }
+ }
+ else if (node.typeID == IMSER_TYPE_FLOAT || node.typeID == IMSER_TYPE_BOOL)
+ {
+ TreeNode n;
+ n.node = nodeIdx;
+ n.parent = treeNodeIdx;
+ n.childStart = -1;
+ n.childEnd = -1;
+ n.next = -1;
+ n.childCount = 0;
+
+ if (g_treeNodes[treeNodeIdx].childEnd != -1)
+ {
+ g_treeNodes[g_treeNodes[treeNodeIdx].childEnd].next = (int)g_treeNodes.size();
+ }
+ else
+ {
+ g_treeNodes[treeNodeIdx].childStart = (int)g_treeNodes.size();
+ }
+ g_treeNodes[treeNodeIdx].childEnd = (int)g_treeNodes.size();
+ g_treeNodes[treeNodeIdx].childCount++;
+
+ g_treeNodes.push_back(n);
+ }
+ }
+ }
+}
+
+static void imguiserDoLoad(const char* filename)
+{
+ FILE* file = nullptr;
+ fopen_s(&file, filename, "r");
+
+ const unsigned int bufSize = 256u;
+ char buf[bufSize];
+
+ if (file)
+ {
+ // enable save process
+ g_saveProcessActive = true;
+ g_nodes.clear();
+ // reset text pool
+ g_textPoolIdx = 0;
+
+ // scan to 'ImserNode'
+ while (!feof(file))
+ {
+ fscanf(file, "%255s,", buf);
+ if (strcmp("ImserNode", buf) == 0)
+ {
+ break;
+ }
+ }
+ // scan to '{'
+ while (!feof(file))
+ {
+ if (fgetc(file) == '{')
+ {
+ break;
+ }
+ }
+ // start reading commands
+ while (!feof(file))
+ {
+ // get command name
+ skipWS(file);
+ fscanf(file, "%255[^(](", buf);
+ if (strcmp(buf, "imserNodeGroupBegin") == 0)
+ {
+ auto name = extractName(file, buf);
+ imguiserBeginGroup(name, nullptr);
+ }
+ else if (strcmp(buf, "imserNodeGroupEnd") == 0)
+ {
+ imguiserEndGroup();
+ }
+ else if (strcmp(buf, "imserNodeValue1f") == 0)
+ {
+ auto name = extractName(file, buf);
+ fscanf(file, "%[^,],", buf);
+ float val = extractValue1f(file, buf);
+ imguiserValue1f(name, &val);
+ }
+ else if (strcmp(buf, "imserNodeValueBool") == 0)
+ {
+ auto name = extractName(file, buf);
+ fscanf(file, "%[^,],", buf);
+ bool val = extractBool(file, buf);
+ imguiserValueBool(name, &val);
+ }
+
+ // scan past close of command
+ fscanf(file, "%[^,],", buf);
+ }
+
+ // disable save process
+ g_saveProcessActive = false;
+
+ fclose(file);
+ }
+ else
+ {
+ g_shouldLoad = false;
+ return;
+ }
+
+ generateTree();
+}
+
+static void imguiserDoLoadC(const ImserNode* nodes, unsigned int sizeInBytes)
+{
+ // copy to g_nodes
+ unsigned int numNodes = sizeInBytes / sizeof(ImserNode);
+
+ g_nodes.clear();
+ // reset text pool
+ g_textPoolIdx = 0;
+
+ g_nodes.resize(numNodes);
+ for (size_t i = 0; i < g_nodes.size(); i++)
+ {
+ g_nodes[i] = nodes[i];
+ }
+
+ generateTree();
+}
+
+ImserNode imserNodeGroupBegin(const char* name)
+{
+ ImserNode group;
+ group.name = name;
+ group.typeID = IMSER_TYPE_GROUP_BEGIN;
+ group.valBool = false;
+ return group;
+}
+
+ImserNode imserNodeGroupEnd()
+{
+ ImserNode group;
+ group.name = nullptr;
+ group.typeID = IMSER_TYPE_GROUP_END;
+ group.valBool = false;
+ return group;
+}
+
+ImserNode imserNodeValue1f(const char* name, float value)
+{
+ ImserNode item;
+ item.name = name;
+ item.typeID = IMSER_TYPE_FLOAT;
+ item.valFloat = value;
+ return item;
+}
+
+ImserNode imserNodeValueBool(const char* name, bool value)
+{
+ ImserNode item;
+ item.name = name;
+ item.typeID = IMSER_TYPE_BOOL;
+ item.valBool = value;
+ return item;
+} \ No newline at end of file
diff --git a/demo/DemoApp/imguiser.h b/demo/DemoApp/imguiser.h
new file mode 100644
index 0000000..2ff3495
--- /dev/null
+++ b/demo/DemoApp/imguiser.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#include "imgui.h"
+
+struct ImserNode;
+
+/// ******************* imguiser public interface ********************
+
+void imguiserInit();
+
+void imguiserUpdate();
+
+void imguiserDestroy();
+
+void imguiserBeginFrame();
+
+void imguiserEndFrame();
+
+void imguiserBeginGroup(const char* name, int* numItems);
+
+void imguiserEndGroup();
+
+bool imguiserCheck(const char* text, bool checked, bool enabled = true);
+
+bool imguiserSlider(const char* text, float* val, float vmin, float vmax, float vinc, bool enabled = true);
+
+bool imguiserOffscreenUpdate();
+
+void imguiserValue1f(const char* text, float* val);
+
+void imguiserValueBool(const char* text, bool* val);
+
+void imguiserSave(const char* filename);
+
+void imguiserLoad(const char* filename);
+
+void imguiserLoadC(const ImserNode* nodes, unsigned int sizeInBytes);
+
+/// **************** imguiser serialization protocol *********************
+
+enum ImserType
+{
+ IMSER_TYPE_GROUP_BEGIN = 0,
+ IMSER_TYPE_GROUP_END = 1,
+ IMSER_TYPE_FLOAT = 2,
+ IMSER_TYPE_BOOL = 3,
+};
+
+struct ImserNode
+{
+ const char* name;
+ ImserType typeID;
+ union
+ {
+ float valFloat;
+ bool valBool;
+ };
+};
+
+ImserNode imserNodeGroupBegin(const char* name);
+
+ImserNode imserNodeGroupEnd();
+
+ImserNode imserNodeValue1f(const char* name, float value);
+
+ImserNode imserNodeValueBool(const char* name, bool value); \ No newline at end of file
diff --git a/demo/DemoApp/loader.cpp b/demo/DemoApp/loader.cpp
new file mode 100644
index 0000000..3b4e5be
--- /dev/null
+++ b/demo/DemoApp/loader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "loader.h"
+
+#include <SDL.h>
+
+#include "appGraphCtx.h"
+#include "mesh.h"
+#include "imgui.h"
+
+#include "NvFlowInterop.h"
+#include "NvFlow.h"
+
+void loadModules(AppGraphCtxType type)
+{
+ loadAppGraphCtx(type);
+ loadNvFlowInterop(type);
+ loadMesh(type);
+ loadImgui(type);
+ loadComputeContext(type);
+}
+
+void unloadModules()
+{
+ unloadComputeContext();
+ unloadImgui();
+ unloadMesh();
+ unloadNvFlowInterop();
+ unloadAppGraphCtx();
+} \ No newline at end of file
diff --git a/demo/DemoApp/loader.h b/demo/DemoApp/loader.h
new file mode 100644
index 0000000..3028325
--- /dev/null
+++ b/demo/DemoApp/loader.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+enum AppGraphCtxType
+{
+ APP_CONTEXT_D3D11 = 1,
+ APP_CONTEXT_D3D12 = 2
+};
+
+#ifndef DEMOAPP_STR
+#define XDEMOAPP_STR(s) DEMOAPP_STR(s)
+#define DEMOAPP_STR(s) #s
+#endif
+
+namespace
+{
+ const char* demoAppDLLName(AppGraphCtxType type)
+ {
+ return (type == APP_CONTEXT_D3D12) ?
+ "DemoAppD3D12" XDEMOAPP_STR(DLL_SUFFIX) ".dll" :
+ "DemoAppD3D11" XDEMOAPP_STR(DLL_SUFFIX) ".dll";
+ }
+
+ const char* nvFlowDLLName(AppGraphCtxType type)
+ {
+ return (type == APP_CONTEXT_D3D12) ?
+ "NvFlowD3D12" XDEMOAPP_STR(DLL_SUFFIX) ".dll" :
+ "NvFlowD3D11" XDEMOAPP_STR(DLL_SUFFIX) ".dll";
+ }
+}
+
+void loadModules(AppGraphCtxType type);
+void unloadModules();
+
+void loadAppGraphCtx(AppGraphCtxType type);
+void unloadAppGraphCtx();
+
+void loadNvFlowInterop(AppGraphCtxType type);
+void unloadNvFlowInterop();
+
+void loadMesh(AppGraphCtxType type);
+void unloadMesh();
+
+void loadImgui(AppGraphCtxType type);
+void unloadImgui();
+
+void loadComputeContext(AppGraphCtxType type);
+void unloadComputeContext();
+
+template<unsigned int maxFunctionCount, void* loadobject(const char*), void unloadobject(void*), void* loadfunction(void*,const char*)>
+struct ModuleLoader
+{
+ static const int m_functionCount = maxFunctionCount;
+ void** m_functionPtrs[m_functionCount] = { nullptr };
+ const char* m_functionNames[m_functionCount] = { nullptr };
+
+ void* m_module = nullptr;
+
+ void* loadFunction(const char* name, int uid, void** ptr)
+ {
+ m_functionPtrs[uid] = ptr;
+ m_functionNames[uid] = name;
+ return SDL_LoadFunction(m_module, name);
+ }
+
+ template <int uid, class ret, class ...Args>
+ ret function(ret(*)(Args...args), const char* name, Args...args)
+ {
+ static void* func = loadFunction(name, uid, &func);
+
+ return ((ret(*)(Args...args))func)(args...);
+ }
+
+ void loadModule(const char* moduleName)
+ {
+ m_module = loadobject(moduleName);
+
+ // load functions with non-null names
+ for (int i = 0; i < m_functionCount; i++)
+ {
+ const char* name = m_functionNames[i];
+ void** funcPtr = m_functionPtrs[i];
+ if (name && funcPtr)
+ {
+ *funcPtr = loadfunction(m_module, name);
+ }
+ }
+ }
+
+ void unloadModule()
+ {
+ unloadobject(m_module);
+
+ for (int i = 0; i < m_functionCount; i++)
+ {
+ void** funcPtr = m_functionPtrs[i];
+ if (funcPtr)
+ {
+ *funcPtr = nullptr;
+ }
+ }
+ }
+
+ ModuleLoader() {}
+}; \ No newline at end of file
diff --git a/demo/DemoApp/main.cpp b/demo/DemoApp/main.cpp
new file mode 100644
index 0000000..e35ea43
--- /dev/null
+++ b/demo/DemoApp/main.cpp
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <SDL.h>
+#include <SDL_video.h>
+#include <SDL_syswm.h>
+
+#include "appGraphCtx.h"
+#include "scene.h"
+
+#include "imgui.h"
+#include "imguiGraph.h"
+#include "imguiInterop.h"
+#include "imguiser.h"
+
+#include "loader.h"
+
+#include "camera.h"
+
+#include <thread>
+
+const int gWinWdefault = 2560 / 2;
+const int gWinHdefault = 1600 / 2;
+int gWinW = gWinWdefault;
+int gWinH = gWinHdefault;
+
+SDL_Window* gWin = nullptr;
+bool gFullscreen = false;
+
+bool gUseD3D12 = false;
+int gAppRunCount = 1;
+
+AppGraphCtx* gAppGraphCtx = nullptr;
+Scene* gScene = nullptr;
+
+Uint64 gTimerFreq = 0u;
+Uint64 gTimerCount = 0;
+float gDeltaTime = 0.f;
+float gFixedDt = 1.f / 60.f;
+bool gFixedTimeStepMode = false;
+
+bool gPaused = false;
+bool gProfileEnabled = false;
+
+Camera gCamera;
+bool gCameraActive = false;
+
+int gMouseX = 0;
+int gMouseY = 0;
+unsigned char gMouseButton = 0;
+
+const int g_imguiBorder = 20;
+const int g_imguiWidth = 200;
+const int g_imguiHeight = 250;
+bool gImguiActive = false;
+bool g_imguiHide = false;
+
+bool gClearDark = false;
+float gClearVal[4] = { 0.33f,0.33f,0.33f,1.f };
+
+void toggleDark()
+{
+ gClearDark = !gClearDark;
+ if (gClearDark)
+ {
+ gClearVal[0] = 0.f;
+ gClearVal[1] = 0.f;
+ gClearVal[2] = 0.f;
+ gClearVal[3] = 1.f;
+ }
+ else
+ {
+ gClearVal[0] = 0.33f;
+ gClearVal[1] = 0.33f;
+ gClearVal[2] = 0.33f;
+ gClearVal[3] = 1.f;
+ }
+}
+
+bool appGraphCtxUpdateSize()
+{
+ return AppGraphCtxUpdateSize(gAppGraphCtx, gWin, gFullscreen);
+}
+
+void appReleaseRenderTargets()
+{
+ AppGraphCtxReleaseRenderTarget(gAppGraphCtx);
+}
+
+#define LEAK_TEST 0
+
+#if LEAK_TEST
+struct AppMemRefCount
+{
+ int refCount = 0;
+ AppMemRefCount() {}
+ ~AppMemRefCount()
+ {
+ if (refCount != 0)
+ {
+ SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Flow Demo App", "Error: Memory Leak", nullptr);
+ }
+ }
+};
+AppMemRefCount gAppMemRefCount;
+
+void* appMalloc(size_t size)
+{
+ gAppMemRefCount.refCount++;
+ return malloc(size);
+}
+
+void appFree(void* ptr)
+{
+ if(ptr) gAppMemRefCount.refCount--;
+ free(ptr);
+}
+#endif
+
+void appInit()
+{
+ loadModules(gUseD3D12 ? APP_CONTEXT_D3D12 : APP_CONTEXT_D3D11);
+
+#if LEAK_TEST
+ NvFlowSetMallocFunc(appMalloc);
+ NvFlowSetFreeFunc(appFree);
+#endif
+
+ // create app graph context
+ gAppGraphCtx = AppGraphCtxCreate(0);
+
+ appGraphCtxUpdateSize();
+
+ gScene = getScene(0);
+
+ AppGraphCtxFrameStart(gAppGraphCtx, gClearVal);
+
+ gScene->init(gAppGraphCtx, gWinW, gWinH);
+
+ // create imgui, connect to app graph context
+ imguiInteropGraphInit(imguiGraphInit, "../../data/DroidSans.ttf", gAppGraphCtx);
+ imguiserInit();
+
+ AppGraphCtxFramePresent(gAppGraphCtx, true);
+}
+
+void appRender()
+{
+ DirectX::XMMATRIX projection;
+ DirectX::XMMATRIX view;
+ gCamera.getViewMatrix(view);
+ gCamera.getProjectionMatrix(projection, gWinW, gWinH);
+
+ bool valid = appGraphCtxUpdateSize();
+
+ if (!valid)
+ {
+ return;
+ }
+
+ AppGraphCtxFrameStart(gAppGraphCtx, gClearVal);
+
+ // interop update
+ imguiInteropGraphUpdate(imguiGraphUpdate, gAppGraphCtx);
+
+ // timer update
+ {
+ Uint64 oldCount = gTimerCount;
+ gTimerFreq = SDL_GetPerformanceFrequency();
+ gTimerCount = SDL_GetPerformanceCounter();
+ if (oldCount > 0)
+ {
+ gDeltaTime = (float(gTimerCount - oldCount)) / float(gTimerFreq);
+ }
+ if (gFixedTimeStepMode)
+ {
+ gDeltaTime = gFixedDt;
+ }
+ }
+
+ static unsigned int maxFramesInFlight = 4;
+
+ // imgui update
+ Scene* newScene = gScene;
+ {
+ imguiserBeginFrame();
+ imguiBeginFrame(gMouseX, gMouseY, gMouseButton, 0);
+
+ // print profile information as needed
+ if (gProfileEnabled)
+ {
+ const int lineSpace = 16;
+
+ imguiDrawText(g_imguiWidth + g_imguiBorder, gWinH - 2 * g_imguiBorder, IMGUI_ALIGN_LEFT, "Performance:", 0xFFFFFFFF);
+
+ const char* label = nullptr;
+ float cpuTime = 0.f;
+ float gpuTime = 0.f;
+ int index = 0;
+ char buf[80];
+ buf[79] = 0;
+ // print frame time
+ {
+ static double frameSum = 0.0;
+ static double frameCount = 0.0;
+ frameSum += gDeltaTime;
+ frameCount += 1.0;
+ frameSum *= 0.99;
+ frameCount *= 0.99;
+ double frameAve = frameSum / frameCount;
+
+ snprintf(buf, 79, "Frame: %.3f ms", 1000.f * frameAve);
+ imguiDrawText(g_imguiWidth + g_imguiBorder, gWinH - 2 * g_imguiBorder - (index + 1) * lineSpace, IMGUI_ALIGN_LEFT, buf, 0xFFFFFFFF);
+ index++;
+
+ snprintf(buf, 79, "MaxFramesInFlight: %d", maxFramesInFlight);
+ imguiDrawText(g_imguiWidth + g_imguiBorder, gWinH - 2 * g_imguiBorder - (index + 1) * lineSpace, IMGUI_ALIGN_LEFT, buf, 0xFFFFFFFF);
+ index++;
+ }
+ int profileIndex = 0;
+ while (AppGraphCtxProfileGet(gAppGraphCtx, &label, &cpuTime, &gpuTime, profileIndex))
+ {
+ snprintf(buf, 79, "%s: gpu(%.3f) cpu(%.3f) ms", label, 1000.f * gpuTime, 1000.f * cpuTime);
+ imguiDrawText(g_imguiWidth + g_imguiBorder, gWinH - 2 * g_imguiBorder - (index + 1) * lineSpace, IMGUI_ALIGN_LEFT,buf, 0xFFFFFFFF);
+ index++;
+ profileIndex++;
+ }
+
+ // print memory usage
+ int statIdx = 0;
+ while(gScene && gScene->getStats(index, statIdx, buf))
+ {
+ imguiDrawText(g_imguiWidth + g_imguiBorder, gWinH - 2 * g_imguiBorder - (index + 1) * lineSpace, IMGUI_ALIGN_LEFT, buf, 0xFFFFFFFF);
+ statIdx++;
+ index++;
+ }
+ }
+
+ static int scrollScene = 0u;
+
+ int sceneX = g_imguiBorder;
+ int sceneY = gWinH - g_imguiHeight;
+ int sceneW = g_imguiWidth - g_imguiBorder;
+ int sceneH = g_imguiHeight - g_imguiBorder;
+
+ imguiBeginScrollArea("Scene",
+ sceneX, sceneY,
+ sceneW, sceneH,
+ &scrollScene);
+
+ for (int i = 0; true; i++)
+ {
+ Scene* scene = getScene(i);
+ if (scene == nullptr) break;
+ if (imguiItem(scene->m_name, true))
+ {
+ newScene = scene;
+ }
+ }
+
+ imguiEndScrollArea();
+
+ gScene->imgui(
+ sceneX, sceneY,
+ sceneW, sceneH
+ );
+
+ imguiEndFrame();
+ imguiserEndFrame();
+ imguiserUpdate();
+ }
+
+ // TODO: less synchronization preferred here
+ if (gScene->shouldReset() || (newScene != gScene))
+ {
+ imguiGraphDraw();
+
+ AppGraphCtxFramePresent(gAppGraphCtx, true);
+
+ AppGraphCtxFrameStart(gAppGraphCtx, gClearVal);
+
+ if (newScene != gScene)
+ {
+ gScene->release();
+ gScene = newScene;
+ gScene->init(gAppGraphCtx, gWinW, gWinH);
+ }
+ else
+ {
+ gScene->reset();
+ }
+
+ imguiGraphDraw();
+
+ AppGraphCtxFramePresent(gAppGraphCtx, true);
+
+ AppGraphCtxFrameStart(gAppGraphCtx, gClearVal);
+ }
+
+ if(!gPaused) gScene->update(gDeltaTime);
+
+ gScene->preDraw();
+
+ gScene->draw(projection,view);
+
+ if (!g_imguiHide)
+ {
+ imguiGraphDraw();
+ }
+
+ AppGraphCtxFramePresent(gAppGraphCtx, false);
+
+ // throttle frames in flight
+ maxFramesInFlight = 4u;
+ {
+ static double frameSum = 0.0;
+ static double frameCount = 0.0;
+ frameSum += gDeltaTime;
+ frameCount += 1.0;
+ frameSum *= 0.99;
+ frameCount *= 0.99;
+ double frameAve = frameSum / frameCount;
+ double targetLatency = 1.f / 60.f;
+ double numFrames = targetLatency / frameAve;
+ if (numFrames < 2.0)
+ {
+ maxFramesInFlight = 2;
+ }
+ else if (numFrames > 6.0)
+ {
+ maxFramesInFlight = 6;
+ }
+ else
+ {
+ maxFramesInFlight = (unsigned int)numFrames;
+ }
+ }
+ AppGraphCtxWaitForFrames(gAppGraphCtx, maxFramesInFlight);
+}
+
+void appRelease()
+{
+ // do this first, since it flushes all GPU work
+ appReleaseRenderTargets();
+
+ gScene->release();
+
+ imguiserDestroy();
+ imguiGraphDestroy();
+
+ AppGraphCtxRelease(gAppGraphCtx);
+
+ gAppGraphCtx = nullptr;
+
+ NvFlowDeferredRelease(2000.f);
+
+ unloadModules();
+}
+
+bool imguiMouseEvent(SDL_Event& e)
+{
+ int x = 0;
+ int y = 0;
+ if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP) {
+ x = e.button.x;
+ y = e.button.y;
+ }
+ else if (e.type == SDL_MOUSEMOTION) {
+ x = e.motion.x;
+ y = e.motion.y;
+ }
+
+ if (e.type == SDL_MOUSEBUTTONDOWN) {
+ if (e.button.button == SDL_BUTTON_LEFT) {
+ gMouseButton = IMGUI_MBUT_LEFT;
+ }
+ else if (e.button.button == SDL_BUTTON_RIGHT) {
+ gMouseButton = IMGUI_MBUT_RIGHT;
+ }
+ }
+ else if (e.type == SDL_MOUSEBUTTONUP) {
+ if (e.button.button == SDL_BUTTON_LEFT) {
+ gMouseButton = 0;
+ }
+ else if (e.button.button == SDL_BUTTON_RIGHT) {
+ gMouseButton = 0;
+ }
+ }
+ else if (e.type == SDL_MOUSEMOTION) {
+ gMouseX = e.motion.x;
+ gMouseY = gWinH - 1 - e.motion.y;
+ }
+
+ bool active = gScene->imguiMouse(gMouseX, gMouseY, gMouseButton);
+
+ active = active || (x < g_imguiWidth && y < g_imguiHeight);
+
+ if (g_imguiHide)
+ {
+ active = false;
+ }
+
+ return active;
+}
+
+void mouseEvent(SDL_Event& e)
+{
+ if (e.type == SDL_MOUSEBUTTONDOWN)
+ {
+ if (!gCameraActive && !g_imguiHide)
+ {
+ gImguiActive = imguiMouseEvent(e);
+ }
+ if (!gImguiActive)
+ {
+ if (e.button.button == SDL_BUTTON_LEFT)
+ {
+ gCamera.rotationStart(e.button.x, e.button.y);
+ gCameraActive = true;
+ }
+ else if (e.button.button == SDL_BUTTON_MIDDLE)
+ {
+ gCamera.translateStart(e.button.x, e.button.y);
+ gCameraActive = true;
+ }
+ else if (e.button.button == SDL_BUTTON_RIGHT)
+ {
+ gCamera.zoomStart(e.button.x, e.button.y);
+ gCameraActive = true;
+ }
+ }
+ }
+ else if (e.type == SDL_MOUSEBUTTONUP)
+ {
+ {
+ gImguiActive = imguiMouseEvent(e);
+ }
+ {
+ if (e.button.button == SDL_BUTTON_LEFT)
+ {
+ gCamera.rotationEnd(e.button.x, e.button.y);
+ gCameraActive = false;
+ }
+ else if (e.button.button == SDL_BUTTON_MIDDLE)
+ {
+ gCamera.translateEnd(e.button.x, e.button.y);
+ gCameraActive = false;
+ }
+ else if (e.button.button == SDL_BUTTON_RIGHT)
+ {
+ gCamera.zoomEnd(e.button.x, e.button.y);
+ gCameraActive = false;
+ }
+ }
+ }
+ else if (e.type == SDL_MOUSEMOTION)
+ {
+ gImguiActive = imguiMouseEvent(e);
+
+ gCamera.rotationMove(e.motion.x, e.motion.y, gWinW, gWinH);
+ gCamera.zoomMove(e.motion.x, e.motion.y, gWinW, gWinH);
+ gCamera.translateMove(e.motion.x, e.motion.y, gWinW, gWinH);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ for (int i = 1; i < argc; i++)
+ {
+ if (0 == strcmp(argv[i], "-d3d12"))
+ {
+ gUseD3D12 = true;
+ }
+ }
+
+ if (SDL_Init(SDL_INIT_VIDEO))
+ {
+ fprintf(stderr, "Failed to init SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ // preserve across transitions
+ gCamera.init(gWinW, gWinH);
+
+ for (; gAppRunCount > 0; gAppRunCount--)
+ {
+ const char* winName = gUseD3D12 ? "NvFlow Demo App D3D12" : "NvFlow Demo App D3D11";
+
+ gWin = SDL_CreateWindow(winName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ gWinW, gWinH, SDL_WINDOW_RESIZABLE /*| SDL_WINDOW_OPENGL*/);
+ if (gWin == nullptr)
+ {
+ return -1;
+ }
+
+ appInit();
+
+ bool shouldRun = true;
+ while (shouldRun)
+ {
+ appRender();
+
+ SDL_Event e;
+ while (SDL_PollEvent(&e))
+ {
+ if (e.type == SDL_QUIT)
+ {
+ shouldRun = false;
+ break;
+ }
+ else if (e.type == SDL_WINDOWEVENT)
+ {
+ if (e.window.event == SDL_WINDOWEVENT_RESIZED)
+ {
+ gWinW = e.window.data1;
+ gWinH = e.window.data2;
+
+ gScene->resize(gWinW, gWinH);
+ }
+ }
+ else if (e.type == SDL_KEYDOWN)
+ {
+ if (e.key.keysym.sym == SDLK_ESCAPE)
+ {
+ shouldRun = false;
+ }
+ if (e.key.keysym.sym == SDLK_F1)
+ {
+ gCamera.isProjectionRH = !gCamera.isProjectionRH;
+ }
+ if (e.key.keysym.sym == SDLK_F11)
+ {
+ gFullscreen = !gFullscreen;
+
+ appReleaseRenderTargets();
+
+ SDL_SetWindowFullscreen(gWin, gFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
+
+ //appInitRenderTargets();
+ }
+ if (e.key.keysym.sym == SDLK_F10)
+ {
+ gAppRunCount++;
+ shouldRun = false;
+ }
+ if (e.key.keysym.sym == SDLK_q)
+ {
+ gFixedTimeStepMode = !gFixedTimeStepMode;
+ }
+ if (e.key.keysym.sym == SDLK_w)
+ {
+ gProfileEnabled = !gProfileEnabled;
+ if(gAppGraphCtx) AppGraphCtxProfileEnable(gAppGraphCtx, gProfileEnabled);
+ }
+ if (e.key.keysym.sym == SDLK_SPACE)
+ {
+ if (gScene) gScene->shoot();
+ }
+ if (e.key.keysym.sym == SDLK_p)
+ {
+ gPaused = !gPaused;
+ }
+ if (e.key.keysym.sym == SDLK_d)
+ {
+ toggleDark();
+ }
+ if (e.key.keysym.sym == SDLK_g)
+ {
+ g_imguiHide = !g_imguiHide;
+ }
+ }
+ else if (e.type == SDL_KEYUP)
+ {
+ }
+ else if (e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEMOTION)
+ {
+ mouseEvent(e);
+ }
+ }
+ }
+
+ appRelease();
+
+ SDL_DestroyWindow(gWin);
+
+ // mark module changes
+ gUseD3D12 = !gUseD3D12;
+ gFullscreen = false;
+ }
+
+ SDL_Quit();
+
+ return 0;
+} \ No newline at end of file
diff --git a/demo/DemoApp/mesh.cpp b/demo/DemoApp/mesh.cpp
new file mode 100644
index 0000000..26acb2f
--- /dev/null
+++ b/demo/DemoApp/mesh.cpp
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "mesh.h"
+
+#include <vector>
+
+struct Mesh
+{
+ std::vector<MeshVertex> m_vertices;
+ std::vector<MeshUint> m_indices;
+
+ float m_bounds[6] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+ MeshContext* m_context = nullptr;
+ MeshIndexBuffer* m_indexBuffer = nullptr;
+ MeshVertexBuffer* m_vertexBuffer = nullptr;
+
+ Mesh() {}
+
+ void loadFromPLY(const char* filename);
+
+ void computeBounds();
+
+ void normalize();
+};
+
+Mesh* MeshCreate(MeshContext* context)
+{
+ Mesh* mesh = new Mesh;
+
+ mesh->m_context = context;
+
+ return mesh;
+}
+
+void MeshLoadFromFile(Mesh* mesh, const char* filename)
+{
+ MeshIndexBufferRelease(mesh->m_indexBuffer);
+ MeshVertexBufferRelease(mesh->m_vertexBuffer);
+
+ mesh->loadFromPLY(filename);
+
+ mesh->computeBounds();
+
+ mesh->normalize();
+
+ mesh->m_vertexBuffer = MeshVertexBufferCreate(mesh->m_context, &mesh->m_vertices[0], (MeshUint)mesh->m_vertices.size());
+ mesh->m_indexBuffer = MeshIndexBufferCreate(mesh->m_context, &mesh->m_indices[0], (MeshUint)mesh->m_indices.size());
+}
+
+void MeshGetData(Mesh* mesh, MeshData* data)
+{
+ data->numVertices = (MeshUint) mesh->m_vertices.size();
+ data->positions = &mesh->m_vertices[0].x;
+ data->positionStride = sizeof(MeshVertex);
+ data->normals = &mesh->m_vertices[0].nx;
+ data->normalStride = sizeof(MeshVertex);
+
+ data->numIndices = (MeshUint) mesh->m_indices.size();
+ data->indices = &mesh->m_indices[0];
+
+ data->boundsMin[0] = mesh->m_bounds[0];
+ data->boundsMin[1] = mesh->m_bounds[1];
+ data->boundsMin[2] = mesh->m_bounds[2];
+ data->boundsMax[0] = mesh->m_bounds[3];
+ data->boundsMax[1] = mesh->m_bounds[4];
+ data->boundsMax[2] = mesh->m_bounds[5];
+}
+
+void MeshDraw(Mesh* mesh, const MeshDrawParams* params)
+{
+ MeshContextDrawParams drawParams;
+ drawParams.params = params;
+ drawParams.indexBuffer = mesh->m_indexBuffer;
+ drawParams.vertexBuffer = mesh->m_vertexBuffer;
+
+ MeshContextDraw(mesh->m_context, &drawParams);
+}
+
+void MeshRelease(Mesh* mesh)
+{
+ if (mesh == nullptr) return;
+
+ MeshIndexBufferRelease(mesh->m_indexBuffer);
+ MeshVertexBufferRelease(mesh->m_vertexBuffer);
+
+ delete mesh;
+}
+
+/// **************** Private functions *******************************
+
+void Mesh::computeBounds()
+{
+ size_t imax = m_vertices.size();
+ if (imax >= 1)
+ {
+ m_bounds[0] = m_bounds[3] = m_vertices[0].x;
+ m_bounds[1] = m_bounds[4] = m_vertices[0].y;
+ m_bounds[2] = m_bounds[5] = m_vertices[0].z;
+
+ for (size_t i = 1; i < imax; i++)
+ {
+ m_bounds[0] = fminf(m_bounds[0], m_vertices[i].x);
+ m_bounds[3] = fmaxf(m_bounds[3], m_vertices[i].x);
+ m_bounds[1] = fminf(m_bounds[1], m_vertices[i].y);
+ m_bounds[4] = fmaxf(m_bounds[4], m_vertices[i].y);
+ m_bounds[2] = fminf(m_bounds[2], m_vertices[i].z);
+ m_bounds[5] = fmaxf(m_bounds[5], m_vertices[i].z);
+ }
+ }
+}
+
+void Mesh::normalize()
+{
+ size_t imax = m_vertices.size();
+ for (size_t i = 0; i < imax; i++)
+ {
+ float x, y, z, w;
+ x = m_vertices[i].nx;
+ y = m_vertices[i].ny;
+ z = m_vertices[i].nz;
+ w = sqrtf(x*x + y*y + z*z);
+ if (w > 0.f)
+ {
+ x /= w;
+ y /= w;
+ z /= w;
+ }
+ m_vertices[i].nx = x;
+ m_vertices[i].ny = y;
+ m_vertices[i].nz = z;
+ }
+}
+
+/// ****************** PLY mesh support *******************************
+
+namespace
+{
+ struct PLYLoader
+ {
+ enum ElementType
+ {
+ ELEM_VERTEX = 0,
+ ELEM_FACE,
+ ELEM_EDGE,
+ ELEM_INVALID
+ };
+
+ enum Format
+ {
+ FORMAT_ASCII = 0,
+ FORMAT_BINARY_LITTLE_ENDIAN,
+ FORMAT_BINARY_BIG_ENDIAN,
+ FORMAT_INVALID
+ };
+
+ // temporary variables
+ FILE* file = nullptr;
+
+ static const int bufSize = 1024u;
+ char buf[bufSize];
+
+ ElementType elementType = ELEM_INVALID;
+ Format format = FORMAT_INVALID;
+
+ int numElements[ELEM_INVALID] = { 0 };
+ int numProperties[ELEM_INVALID] = { 0 };
+
+ int elementList[ELEM_INVALID] = { 0 };
+ int elementListIdx = 0;
+
+ // captured variables
+ std::vector<MeshVertex>& m_vertices;
+ std::vector<uint32_t>& m_indices;
+
+ // capture in constructor
+ PLYLoader(Mesh& mesh) :
+ m_vertices(mesh.m_vertices),
+ m_indices(mesh.m_indices)
+ {
+ }
+
+ // utility functions
+ void getline()
+ {
+ fgets(buf, bufSize, file);
+ };
+ void getstr()
+ {
+ fscanf_s(file, "%s", buf, bufSize);
+ };
+ int getint()
+ {
+ int i = 0;
+ fscanf_s(file, "%d", &i);
+ return i;
+ };
+ bool match(const char* key)
+ {
+ return strncmp(buf, key, bufSize) == 0;
+ };
+
+ // temporary state
+ int elemType = ELEM_INVALID;
+ int elemNum = 0;
+ int elemProperties = 0;
+
+ template<class getFloatType, class advanceFuncType>
+ void getVertices(getFloatType getFloat, advanceFuncType advanceFunc)
+ {
+ for (int i = 0; i < elemNum; i++)
+ {
+ float data[6];
+ for (int j = 0; j < elemProperties; j++)
+ {
+ float val = getFloat();
+ if (j < 6) data[j] = val;
+ }
+ m_vertices.push_back(MeshVertex{
+ data[0], data[1], data[2],
+ data[3], data[4], data[5]
+ });
+ advanceFunc();
+ }
+ }
+
+ template<class getCountType, class getIndexType, class advanceFuncType>
+ void getIndices(getCountType getCount, getIndexType getIndex, advanceFuncType advanceFunc)
+ {
+ for (int i = 0; i < elemNum; i++)
+ {
+ int count = getCount();
+ int indices[4];
+ if (count > 0) indices[0] = getIndex();
+ if (count > 1) indices[1] = getIndex();
+ if (count > 2) indices[2] = getIndex();
+ if (count > 3) indices[3] = getIndex();
+
+ if (count >= 3)
+ {
+ m_indices.push_back(indices[0]);
+ m_indices.push_back(indices[1]);
+ m_indices.push_back(indices[2]);
+ }
+ if (count == 4)
+ {
+ m_indices.push_back(indices[2]);
+ m_indices.push_back(indices[3]);
+ m_indices.push_back(indices[0]);
+ }
+ advanceFunc();
+ }
+ }
+
+ // main phases
+ bool parseHeader()
+ {
+ // verify file format
+ getstr();
+ if (match("ply"))
+ {
+ // extra header information
+ while (feof(file) == 0)
+ {
+ getstr();
+ if (match("element"))
+ {
+ getstr();
+ if (match("vertex")) {
+ elementType = ELEM_VERTEX;
+ }
+ else if (match("face")) {
+ elementType = ELEM_FACE;
+ }
+ else if (match("edge")) {
+ elementType = ELEM_EDGE;
+ }
+ unsigned int idx = (unsigned int)elementType;
+ if (idx < ELEM_INVALID)
+ {
+ numElements[idx] = getint();
+ }
+ if (elementListIdx < ELEM_INVALID)
+ {
+ elementList[elementListIdx++] = elementType;
+ }
+ }
+ else if (match("format"))
+ {
+ getstr();
+ if (match("ascii")) {
+ format = FORMAT_ASCII;
+ }
+ else if (match("binary_big_endian")) {
+ format = FORMAT_BINARY_BIG_ENDIAN;
+ }
+ else if (match("binary_little_endian")) {
+ format = FORMAT_BINARY_LITTLE_ENDIAN;
+ }
+ }
+ else if (match("property"))
+ {
+ unsigned int idx = (unsigned int)elementType;
+ if (idx < ELEM_INVALID)
+ {
+ numProperties[idx]++;
+ }
+ }
+ else if (match("end_header"))
+ {
+ break;
+ }
+ } // end read header
+
+ // advance past newline
+ getline();
+ return true;
+ }
+ return false;
+ }
+
+ void loadData()
+ {
+ // read in each element type
+ for (int eidx = 0; eidx < elementListIdx; eidx++)
+ {
+ elemType = elementList[eidx];
+ elemNum = numElements[elemType];
+ elemProperties = numProperties[elemType];
+
+ if (elemType == ELEM_VERTEX)
+ {
+ // size vertex buffers
+ m_vertices.reserve(elemNum);
+
+ if (format == FORMAT_ASCII)
+ {
+ getVertices(
+ [&]()
+ {
+ float val = 0.f;
+ fscanf_s(file, "%f", &val);
+ return val;
+ },
+ [&]()
+ {
+ getline();
+ }
+ );
+ }
+ else if (format == FORMAT_BINARY_BIG_ENDIAN)
+ {
+ getVertices(
+ [&]()
+ {
+ char data0[4];
+ fread(data0, sizeof(float), 1, file);
+ union
+ {
+ char data1[4];
+ float val;
+ };
+ data1[0] = data0[3];
+ data1[1] = data0[2];
+ data1[2] = data0[1];
+ data1[3] = data0[0];
+ return val;
+ },
+ [&]()
+ {
+ }
+ );
+ }
+ else if (format == FORMAT_BINARY_LITTLE_ENDIAN)
+ {
+ getVertices(
+ [&]()
+ {
+ float val = 0.f;
+ fread(&val, sizeof(float), 1, file);
+ return val;
+ },
+ [&]()
+ {
+ }
+ );
+ }
+ }
+ else if (elemType == ELEM_FACE)
+ {
+ // size vertex buffers
+ m_indices.reserve(3 * elemNum);
+
+ if (format == FORMAT_ASCII)
+ {
+ getIndices(
+ [&]()
+ {
+ return getint();
+ },
+ [&]()
+ {
+ return getint();
+ },
+ [&]()
+ {
+ getline();
+ }
+ );
+ }
+ else if (format == FORMAT_BINARY_BIG_ENDIAN)
+ {
+ getIndices(
+ [&]()
+ {
+ int val = 0;
+ fread(&val, 1, 1, file);
+ return val;
+ },
+ [&]()
+ {
+ char data0[4];
+ fread(data0, sizeof(float), 1, file);
+ union
+ {
+ char data1[4];
+ int val;
+ };
+ data1[0] = data0[3];
+ data1[1] = data0[2];
+ data1[2] = data0[1];
+ data1[3] = data0[0];
+ return val;
+ },
+ [&]()
+ {
+ }
+ );
+ }
+ else if (format == FORMAT_BINARY_LITTLE_ENDIAN)
+ {
+ getIndices(
+ [&]()
+ {
+ int val = 0;
+ fread(&val, 1, 1, file);
+ return val;
+ },
+ [&]()
+ {
+ int val;
+ fread(&val, sizeof(int), 1, file);
+ return val;
+ },
+ [&]()
+ {
+ }
+ );
+ }
+ }
+ else if (elemType == ELEM_EDGE)
+ {
+
+ }
+ }
+ }
+
+ // main entry point
+ void operator()(const char* filename)
+ {
+ fopen_s(&file, filename, "rb");
+ if (file)
+ {
+ if (parseHeader())
+ {
+ loadData();
+ }
+ fclose(file);
+ }
+ }
+ };
+}
+
+void Mesh::loadFromPLY(const char* filename)
+{
+ PLYLoader loader(*this);
+ loader(filename);
+} \ No newline at end of file
diff --git a/demo/DemoApp/mesh.h b/demo/DemoApp/mesh.h
new file mode 100644
index 0000000..9861bac
--- /dev/null
+++ b/demo/DemoApp/mesh.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#include <DirectXMath.h>
+
+#define MESH_API extern "C" __declspec(dllexport)
+
+/// ****************** Mesh Context Public *******************************
+
+typedef unsigned int MeshUint;
+typedef unsigned char MeshUint8;
+
+struct MeshContext;
+
+struct MeshContextDesc;
+
+MESH_API MeshContext* MeshContextCreate(const MeshContextDesc* desc);
+
+MESH_API void MeshContextUpdate(MeshContext* context, const MeshContextDesc* desc);
+
+MESH_API void MeshContextRelease(MeshContext* context);
+
+/// ****************** Mesh Interface Public **********************
+
+struct Mesh;
+
+enum MeshRenderMode
+{
+ MESH_RENDER_SOLID = 0
+};
+
+struct MeshDrawParams
+{
+ MeshUint renderMode;
+ DirectX::XMMATRIX projection;
+ DirectX::XMMATRIX view;
+ DirectX::XMMATRIX model;
+};
+
+struct MeshData
+{
+ MeshUint numVertices;
+ float* positions;
+ MeshUint positionStride;
+ float* normals;
+ MeshUint normalStride;
+
+ MeshUint numIndices;
+ MeshUint* indices;
+
+ float boundsMin[3];
+ float boundsMax[3];
+};
+
+MESH_API Mesh* MeshCreate(MeshContext* context);
+
+MESH_API void MeshLoadFromFile(Mesh* mesh, const char* filename);
+
+MESH_API void MeshGetData(Mesh* mesh, MeshData* data);
+
+MESH_API void MeshDraw(Mesh* mesh, const MeshDrawParams* params);
+
+MESH_API void MeshRelease(Mesh* mesh);
+
+/// ****************** Mesh Context Implementation *******************************
+
+struct MeshVertex
+{
+ float x, y, z;
+ float nx, ny, nz;
+};
+
+struct MeshIndexBuffer;
+struct MeshVertexBuffer;
+
+MESH_API MeshIndexBuffer* MeshIndexBufferCreate(MeshContext* context, MeshUint* indices, MeshUint numIndices);
+
+MESH_API void MeshIndexBufferRelease(MeshIndexBuffer* buffer);
+
+MESH_API MeshVertexBuffer* MeshVertexBufferCreate(MeshContext* context, MeshVertex* vertices, MeshUint numVertices);
+
+MESH_API void MeshVertexBufferRelease(MeshVertexBuffer* buffer);
+
+struct MeshContextDrawParams
+{
+ const MeshDrawParams* params;
+ MeshIndexBuffer* indexBuffer;
+ MeshVertexBuffer* vertexBuffer;
+};
+
+MESH_API void MeshContextDraw(MeshContext* context, const MeshContextDrawParams* params); \ No newline at end of file
diff --git a/demo/DemoApp/meshInterop.h b/demo/DemoApp/meshInterop.h
new file mode 100644
index 0000000..d8b1102
--- /dev/null
+++ b/demo/DemoApp/meshInterop.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#pragma once
+
+#include "mesh.h"
+
+#include "appGraphCtx.h"
+
+MESH_API MeshContext* MeshInteropContextCreate(AppGraphCtx* appctx);
+
+MESH_API void MeshInteropContextUpdate(MeshContext* context, AppGraphCtx* appctx); \ No newline at end of file
diff --git a/demo/DemoApp/meshLoader.cpp b/demo/DemoApp/meshLoader.cpp
new file mode 100644
index 0000000..99e5e49
--- /dev/null
+++ b/demo/DemoApp/meshLoader.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <SDL.h>
+
+#include "loader.h"
+
+#include "mesh.h"
+#include "meshInterop.h"
+
+namespace
+{
+ ModuleLoader<16u, SDL_LoadObject, SDL_UnloadObject, SDL_LoadFunction> g_loader;
+}
+
+void loadMesh(AppGraphCtxType type)
+{
+ const char* moduleName = demoAppDLLName(type);
+
+ g_loader.loadModule(moduleName);
+}
+
+void unloadMesh()
+{
+ g_loader.unloadModule();
+}
+
+MeshContext* MeshContextCreate(const MeshContextDesc* desc)
+{
+ return g_loader.function<0>(MeshContextCreate, "MeshContextCreate", desc);
+}
+
+void MeshContextUpdate(MeshContext* context, const MeshContextDesc* desc)
+{
+ return g_loader.function<1>(MeshContextUpdate, "MeshContextUpdate", context, desc);
+}
+
+void MeshContextRelease(MeshContext* context)
+{
+ return g_loader.function<2>(MeshContextRelease, "MeshContextRelease", context);
+}
+
+MeshIndexBuffer* MeshIndexBufferCreate(MeshContext* context, MeshUint* indices, MeshUint numIndices)
+{
+ return g_loader.function<3>(MeshIndexBufferCreate, "MeshIndexBufferCreate", context, indices, numIndices);
+}
+
+void MeshIndexBufferRelease(MeshIndexBuffer* buffer)
+{
+ return g_loader.function<4>(MeshIndexBufferRelease, "MeshIndexBufferRelease", buffer);
+}
+
+MeshVertexBuffer* MeshVertexBufferCreate(MeshContext* context, MeshVertex* vertices, MeshUint numVertices)
+{
+ return g_loader.function<5>(MeshVertexBufferCreate, "MeshVertexBufferCreate", context, vertices, numVertices);
+}
+
+void MeshVertexBufferRelease(MeshVertexBuffer* buffer)
+{
+ return g_loader.function<6>(MeshVertexBufferRelease, "MeshVertexBufferRelease", buffer);
+}
+
+void MeshContextDraw(MeshContext* context, const MeshContextDrawParams* params)
+{
+ return g_loader.function<7>(MeshContextDraw, "MeshContextDraw", context, params);
+}
+
+MeshContext* MeshInteropContextCreate(AppGraphCtx* appctx)
+{
+ return g_loader.function<8>(MeshInteropContextCreate, "MeshInteropContextCreate", appctx);
+}
+
+void MeshInteropContextUpdate(MeshContext* context, AppGraphCtx* appctx)
+{
+ return g_loader.function<9>(MeshInteropContextUpdate, "MeshInteropContextUpdate", context, appctx);
+} \ No newline at end of file
diff --git a/demo/DemoApp/preset0.h b/demo/DemoApp/preset0.h
new file mode 100644
index 0000000..aba3666
--- /dev/null
+++ b/demo/DemoApp/preset0.h
@@ -0,0 +1,63 @@
+const ImserNode g_root[] = {
+ imserNodeGroupBegin("Effect"),
+ imserNodeGroupBegin("Fluid Simulation"),
+ imserNodeGroupBegin("Damping"),
+ imserNodeValue1f("Velocity", 0.100000f),
+ imserNodeValue1f("Smoke", 0.250000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Fade"),
+ imserNodeValue1f("Velocity", 0.100000f),
+ imserNodeValue1f("Smoke", 0.250000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("MacCormack Correction"),
+ imserNodeValue1f("Velocity", 0.500000f),
+ imserNodeValue1f("Smoke", 0.500000f),
+ imserNodeGroupEnd(),
+ imserNodeValue1f("Vorticity Strength", 9.000000f),
+ imserNodeGroupBegin("Combustion"),
+ imserNodeValue1f("Ignition Temp", 0.050000f),
+ imserNodeValue1f("Cooling Rate", 1.500000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Emitter"),
+ imserNodeValue1f("Emit Velocity", -8.000000f),
+ imserNodeValue1f("Emit Smoke", 0.500000f),
+ imserNodeValue1f("Emit Temp", 2.000000f),
+ imserNodeValue1f("Emit Fuel", 1.400000f),
+ imserNodeValue1f("Alloc Scale", 1.000000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Rendering"),
+ imserNodeValue1f("Alpha Scale", 0.200000f),
+ imserNodeValue1f("Render Mode", 0.000000f),
+ imserNodeValueBool("Debug Render", false),
+ imserNodeValueBool("Edit ColorMap", false),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormap"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.490000f),
+ imserNodeValue1f(nullptr, 1.450000f),
+ imserNodeValue1f(nullptr, 1.260000f),
+ imserNodeValue1f(nullptr, 0.025294f),
+ imserNodeValue1f(nullptr, 0.384255f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.580000f),
+ imserNodeValue1f(nullptr, 0.490000f),
+ imserNodeValue1f(nullptr, 0.109803f),
+ imserNodeValue1f(nullptr, 0.620718f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.830000f),
+ imserNodeValue1f(nullptr, 0.540000f),
+ imserNodeValue1f(nullptr, 0.456667f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.240000f),
+ imserNodeValue1f(nullptr, 0.190000f),
+ imserNodeValue1f(nullptr, 0.350000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.150000f),
+ imserNodeValue1f(nullptr, 0.130000f),
+ imserNodeValue1f(nullptr, 0.100000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+}; \ No newline at end of file
diff --git a/demo/DemoApp/preset1.h b/demo/DemoApp/preset1.h
new file mode 100644
index 0000000..dded481
--- /dev/null
+++ b/demo/DemoApp/preset1.h
@@ -0,0 +1,63 @@
+const ImserNode g_root[] = {
+ imserNodeGroupBegin("Effect"),
+ imserNodeGroupBegin("Fluid Simulation"),
+ imserNodeGroupBegin("Damping"),
+ imserNodeValue1f("Velocity", 0.100000f),
+ imserNodeValue1f("Smoke", 0.250000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Fade"),
+ imserNodeValue1f("Velocity", 0.100000f),
+ imserNodeValue1f("Smoke", 0.250000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("MacCormack Correction"),
+ imserNodeValue1f("Velocity", 0.500000f),
+ imserNodeValue1f("Smoke", 0.500000f),
+ imserNodeGroupEnd(),
+ imserNodeValue1f("Vorticity Strength", 9.000000f),
+ imserNodeGroupBegin("Combustion"),
+ imserNodeValue1f("Ignition Temp", 0.050000f),
+ imserNodeValue1f("Cooling Rate", 1.500000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Emitter"),
+ imserNodeValue1f("Emit Velocity", -8.000000f),
+ imserNodeValue1f("Emit Smoke", 0.500000f),
+ imserNodeValue1f("Emit Temp", 2.000000f),
+ imserNodeValue1f("Emit Fuel", 1.400000f),
+ imserNodeValue1f("Alloc Scale", 1.000000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Rendering"),
+ imserNodeValue1f("Alpha Scale", 0.200000f),
+ imserNodeValue1f("Render Mode", 6.000000f),
+ imserNodeValueBool("Debug Render", false),
+ imserNodeValueBool("Edit ColorMap", false),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormap"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.490000f),
+ imserNodeValue1f(nullptr, 1.450000f),
+ imserNodeValue1f(nullptr, 1.260000f),
+ imserNodeValue1f(nullptr, 0.025294f),
+ imserNodeValue1f(nullptr, 0.384255f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.580000f),
+ imserNodeValue1f(nullptr, 0.490000f),
+ imserNodeValue1f(nullptr, 0.109803f),
+ imserNodeValue1f(nullptr, 0.620718f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.830000f),
+ imserNodeValue1f(nullptr, 0.540000f),
+ imserNodeValue1f(nullptr, 0.456667f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.240000f),
+ imserNodeValue1f(nullptr, 0.190000f),
+ imserNodeValue1f(nullptr, 0.350000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.150000f),
+ imserNodeValue1f(nullptr, 0.130000f),
+ imserNodeValue1f(nullptr, 0.100000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+}; \ No newline at end of file
diff --git a/demo/DemoApp/presetFireBall.h b/demo/DemoApp/presetFireBall.h
new file mode 100644
index 0000000..08b9588
--- /dev/null
+++ b/demo/DemoApp/presetFireBall.h
@@ -0,0 +1,85 @@
+const ImserNode g_root[] = {
+ imserNodeGroupBegin("Effect"),
+ imserNodeGroupBegin("colormap"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.150000f),
+ imserNodeValue1f(nullptr, 0.160000f),
+ imserNodeValue1f(nullptr, 0.150000f),
+ imserNodeValue1f(nullptr, 0.004902f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.220000f),
+ imserNodeValue1f(nullptr, 0.220000f),
+ imserNodeValue1f(nullptr, 0.220000f),
+ imserNodeValue1f(nullptr, 0.504902f),
+ imserNodeValue1f(nullptr, 0.600000f),
+ imserNodeValue1f(nullptr, 0.835294f),
+ imserNodeValue1f(nullptr, 0.392157f),
+ imserNodeValue1f(nullptr, 0.117647f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 1.270000f),
+ imserNodeValue1f(nullptr, 1.200000f),
+ imserNodeValue1f(nullptr, 0.390000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormapMat0"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.270000f),
+ imserNodeValue1f(nullptr, 0.299019f),
+ imserNodeValue1f(nullptr, 0.173204f),
+ imserNodeValue1f(nullptr, 0.350000f),
+ imserNodeValue1f(nullptr, 0.140000f),
+ imserNodeValue1f(nullptr, 1.130000f),
+ imserNodeValue1f(nullptr, 0.662746f),
+ imserNodeValue1f(nullptr, 0.709116f),
+ imserNodeValue1f(nullptr, 0.070000f),
+ imserNodeValue1f(nullptr, 0.080000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.726471f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 0.110000f),
+ imserNodeValue1f(nullptr, 1.080000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormapMat1"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.500000f),
+ imserNodeValue1f(nullptr, 0.600000f),
+ imserNodeValue1f(nullptr, 0.835294f),
+ imserNodeValue1f(nullptr, 1.220000f),
+ imserNodeValue1f(nullptr, 1.360000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 1.270000f),
+ imserNodeValue1f(nullptr, 1.200000f),
+ imserNodeValue1f(nullptr, 0.390000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+}; \ No newline at end of file
diff --git a/demo/DemoApp/presetFlame.h b/demo/DemoApp/presetFlame.h
new file mode 100644
index 0000000..f0a9bea
--- /dev/null
+++ b/demo/DemoApp/presetFlame.h
@@ -0,0 +1,85 @@
+const ImserNode g_root[] = {
+ imserNodeGroupBegin("Effect"),
+ imserNodeGroupBegin("colormap"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.500000f),
+ imserNodeValue1f(nullptr, 0.600000f),
+ imserNodeValue1f(nullptr, 0.835294f),
+ imserNodeValue1f(nullptr, 0.392157f),
+ imserNodeValue1f(nullptr, 0.117647f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 1.270000f),
+ imserNodeValue1f(nullptr, 1.200000f),
+ imserNodeValue1f(nullptr, 0.390000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormapMat0"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.270000f),
+ imserNodeValue1f(nullptr, 0.299019f),
+ imserNodeValue1f(nullptr, 0.173204f),
+ imserNodeValue1f(nullptr, 0.350000f),
+ imserNodeValue1f(nullptr, 0.140000f),
+ imserNodeValue1f(nullptr, 1.130000f),
+ imserNodeValue1f(nullptr, 0.662746f),
+ imserNodeValue1f(nullptr, 0.709116f),
+ imserNodeValue1f(nullptr, 0.070000f),
+ imserNodeValue1f(nullptr, 0.080000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.726471f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 0.110000f),
+ imserNodeValue1f(nullptr, 1.080000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormapMat1"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.050000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.500000f),
+ imserNodeValue1f(nullptr, 0.600000f),
+ imserNodeValue1f(nullptr, 0.835294f),
+ imserNodeValue1f(nullptr, 1.220000f),
+ imserNodeValue1f(nullptr, 1.360000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 1.270000f),
+ imserNodeValue1f(nullptr, 1.200000f),
+ imserNodeValue1f(nullptr, 0.390000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 1.500000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+}; \ No newline at end of file
diff --git a/demo/DemoApp/presetSmoke.h b/demo/DemoApp/presetSmoke.h
new file mode 100644
index 0000000..6229870
--- /dev/null
+++ b/demo/DemoApp/presetSmoke.h
@@ -0,0 +1,46 @@
+const ImserNode g_root[] = {
+ imserNodeGroupBegin("Effect"),
+ imserNodeGroupBegin("Emitter"),
+ imserNodeValue1f("Emit Smoke", 9.800000f),
+ imserNodeValue1f("Emit Temp", 8.900001f),
+ imserNodeValue1f("Emit Fuel", 1.800000f),
+ imserNodeValue1f("Max Emit Dist", 0.400000f),
+ imserNodeValue1f("Min Emit Dist", 0.140000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("Rendering"),
+ imserNodeValue1f("Alpha Scale", 0.20000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupBegin("colormap"),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.025000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.000000f),
+ imserNodeValue1f(nullptr, 0.250277f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.362745f),
+ imserNodeValue1f(nullptr, 0.600000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 0.850000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.800000f),
+ imserNodeValue1f(nullptr, 1.000000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.990000f),
+ imserNodeValue1f(nullptr, 0.700000f),
+ imserNodeGroupEnd(),
+ imserNodeGroupEnd(),
+}; \ No newline at end of file
diff --git a/demo/DemoApp/scene.cpp b/demo/DemoApp/scene.cpp
new file mode 100644
index 0000000..3ad7cce
--- /dev/null
+++ b/demo/DemoApp/scene.cpp
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "scene.h"
+
+#include <stdio.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+#include "scene.h"
+
+#include <SDL.h>
+
+/// Scene registry here
+
+namespace Scenes
+{
+ SceneSimpleFlame sceneSimpleFlame;
+ SceneSimpleFlameThrower sceneSimpleFlameThrower;
+ SceneSimpleFlameAnimated sceneSimpleFlameAnimated;
+ Scene2DTextureEmitter scene2DTextureEmitter1(false);
+ Scene2DTextureEmitter scene2DTextureEmitter2(true);
+ SceneSimpleFlameMesh sceneSimpleFlameMesh;
+ SceneSimpleFlameCollision sceneSimpleFlameCollision;
+ //SceneSimpleFlameCulling sceneSimpleFlameCulling;
+ SceneSimpleFlameConvex sceneSimpleFlameConvex;
+ SceneSimpleFlameCapsule sceneSimpleFlameCapsule;
+ SceneSDFTest sceneSDFTest;
+ SceneCustomLighting sceneCustomLighting;
+ SceneSimpleSmoke sceneSimpleSmoke;
+ SceneDynamicCoupleRate sceneDynamicCoupleRate;
+ SceneCustomEmit sceneCustomEmit;
+ SceneSimpleFlameDouble sceneSimpleFlame2;
+ SceneSimpleFlameFuelMap sceneSimpleFlameFuelMap;
+ SceneSimpleFlameParticleSurface sceneParticleSurface;
+ SceneSimpleFlameBall sceneSimpleFlameBall;
+
+ const int count = 18;
+ Scene* list[count] = {
+ &scene2DTextureEmitter1,
+ &scene2DTextureEmitter2,
+ &sceneSimpleFlame,
+ &sceneSimpleFlameThrower,
+ &sceneSimpleFlameAnimated,
+ &sceneSimpleFlameMesh,
+ &sceneSDFTest,
+ &sceneSimpleFlameCollision,
+ //&sceneSimpleFlameCulling,
+ &sceneSimpleFlameConvex,
+ &sceneSimpleFlameCapsule,
+ &sceneSimpleSmoke,
+ &sceneCustomLighting,
+ &sceneDynamicCoupleRate,
+ &sceneCustomEmit,
+ &sceneSimpleFlame2,
+ &sceneSimpleFlameFuelMap,
+ &sceneParticleSurface,
+ &sceneSimpleFlameBall
+ };
+};
+
+Scene* getScene(int index)
+{
+ if (index < Scenes::count)
+ {
+ return Scenes::list[index];
+ }
+ return nullptr;
+}
+
+void pointsToImage(NvFlowFloat4* image, int imageDim, const CurvePoint* pts, int numPts)
+{
+ using namespace DirectX;
+ for (int i = 0; i < imageDim; i++)
+ {
+ float u = (float(i) + 0.5f) / float(imageDim);
+
+ // find the closest higher and lower control points
+ int xloweri = -1;
+ float xlowerVal = 0.f;
+ int xhigheri = -1;
+ float xhigherVal = 1.f;
+ for (int pt = 0; pt < numPts; pt++)
+ {
+ if (pts[pt].x <= u && pts[pt].x >= xlowerVal)
+ {
+ xloweri = pt;
+ xlowerVal = pts[pt].x;
+ }
+ if (pts[pt].x >= u && pts[pt].x <= xhigherVal)
+ {
+ xhigheri = pt;
+ xhigherVal = pts[pt].x;
+ }
+ }
+
+ // get values for interpolation
+ XMVECTOR a = (xloweri >= 0) ? XMLoadFloat4((XMFLOAT4*)&pts[xloweri].r) : XMVectorSet(0.f, 0.f, 0.f, 0.f);
+ XMVECTOR b = (xhigheri >= 0) ? XMLoadFloat4((XMFLOAT4*)&pts[xhigheri].r) : XMVectorSet(1.f, 1.f, 1.f, 1.f);
+ float t = (u - xlowerVal) / (xhigherVal - xlowerVal);
+ XMVECTOR c = XMVectorLerp(a, b, t);
+
+ XMStoreFloat4((XMFLOAT4*)&image[i], c);
+ }
+}
+
+void Scene::update(float dt)
+{
+ int numSteps = m_timeStepper.getNumSteps(dt);
+
+ for (int i = 0; i < numSteps; i++)
+ {
+ doUpdate(m_timeStepper.m_fixedDt);
+ }
+}
+
+void Scene::resize(int winw, int winh)
+{
+ m_winw = winw;
+ m_winh = winh;
+}
+
+bool Scene::imguiMouse(int mx, int my, unsigned char mbut)
+{
+ m_mx = mx;
+ m_my = my;
+ m_mbut = mbut;
+ return false;
+}
+
+// ************************* SceneFluid *****************************************
+
+void SceneFluid::imguiDesc()
+{
+ {
+ bool enableVTR = (m_flowGridActor.m_gridDesc.enableVTR != false);
+ if (imguiCheck("Enable VTR", enableVTR, true))
+ {
+ if (enableVTR == false)
+ {
+ NvFlowSupport support;
+ if (NvFlowGridQuerySupport(m_flowGridActor.m_grid, m_flowContext.m_gridContext, &support) == eNvFlowSuccess)
+ {
+ m_flowGridActor.m_gridDesc.enableVTR = support.supportsVTR;
+ }
+ }
+ else
+ {
+ m_flowGridActor.m_gridDesc.enableVTR = false;
+ }
+ m_shouldReset = true;
+ }
+ bool lowResDensity = m_flowGridActor.m_gridDesc.densityMultiRes == eNvFlowMultiRes1x1x1;
+ if (imguiCheck("Low Res Density", lowResDensity, true))
+ {
+ if (m_flowGridActor.m_gridDesc.densityMultiRes == eNvFlowMultiRes1x1x1)
+ {
+ m_flowGridActor.m_gridDesc.densityMultiRes = eNvFlowMultiRes2x2x2;
+ }
+ else
+ {
+ m_flowGridActor.m_gridDesc.densityMultiRes = eNvFlowMultiRes1x1x1;
+ }
+ m_shouldReset = true;
+ }
+ if (imguiCheck("Low Latency Mapping", m_flowGridActor.m_gridDesc.lowLatencyMapping, true))
+ {
+ m_flowGridActor.m_gridDesc.lowLatencyMapping = !m_flowGridActor.m_gridDesc.lowLatencyMapping;
+ m_shouldReset = true;
+ }
+ }
+ {
+ if (!m_flowContext.m_multiGPUSupported)
+ {
+ m_flowContext.m_enableMultiGPU = false;
+ }
+ if (imguiCheck("Enable MultiGPU", m_flowContext.m_enableMultiGPU, true))
+ {
+ m_flowContext.m_enableMultiGPU = !m_flowContext.m_enableMultiGPU;
+ if (!m_flowContext.m_multiGPUSupported)
+ {
+ m_flowContext.m_enableMultiGPU = false;
+ }
+ else
+ {
+ m_shouldReset = true;
+ }
+ }
+ }
+ {
+ if (!m_flowContext.m_commandQueueSupported)
+ {
+ m_flowContext.m_enableCommandQueue = false;
+ }
+ if (imguiCheck("Enable MultiQueue", m_flowContext.m_enableCommandQueue, true))
+ {
+ m_flowContext.m_enableCommandQueue = !m_flowContext.m_enableCommandQueue;
+ if (!m_flowContext.m_commandQueueSupported)
+ {
+ m_flowContext.m_enableCommandQueue = false;
+ }
+ else
+ {
+ m_shouldReset = true;
+ }
+ }
+ }
+
+ float oldMemoryLimit = m_flowGridActor.m_memoryLimit;
+ imguiserSlider("Memory Limit", &m_flowGridActor.m_memoryLimit, 1.f, 6.f, 1.f, true);
+ if (oldMemoryLimit != m_flowGridActor.m_memoryLimit)
+ {
+ m_flowGridActor.m_gridDesc.residentScale = m_flowGridActor.m_memoryLimit * m_flowGridActor.m_memoryScale;
+ m_shouldReset = true;
+ }
+
+ if (imguiButton("Reset", true))
+ {
+ m_shouldReset = true;
+ }
+
+ if (imguiButton("Grid Reset", true))
+ {
+ m_shouldGridReset = true;
+ }
+
+ float cellSizeLogf = float(m_flowGridActor.m_cellSizeLogScale);
+ if (imguiserSlider("Cell Size Log Scale", &cellSizeLogf, -6.f, 6.f, 1.f, true))
+ {
+ m_flowGridActor.m_cellSizeLogScale = int(cellSizeLogf);
+ m_shouldGridReset = true;
+ }
+ if (imguiserSlider("Cell Size Scale", &m_flowGridActor.m_cellSizeScale, 0.8f, 1.25f, 0.001f, true))
+ {
+ m_shouldGridReset = true;
+ }
+
+ imguiDescExtra();
+}
+
+void SceneFluid::imguiFluidSim()
+{
+ imguiSeparatorLine();
+ imguiLabel("Fluid Simulation");
+ imguiserBeginGroup("Fluid Simulation", nullptr);
+
+ imguiSeparator();
+ imguiLabel("Damping");
+ imguiserBeginGroup("Damping", nullptr);
+ imguiserSlider("Velocity", &m_flowGridActor.m_materialParams.velocity.damping, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Smoke", &m_flowGridActor.m_materialParams.smoke.damping, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Temp", &m_flowGridActor.m_materialParams.temperature.damping, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel", &m_flowGridActor.m_materialParams.fuel.damping, 0.f, 1.f, 0.01f, true);
+ imguiserEndGroup();
+
+ imguiSeparator();
+ imguiLabel("Fade");
+ imguiserBeginGroup("Fade", nullptr);
+ imguiserSlider("Velocity", &m_flowGridActor.m_materialParams.velocity.fade, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Smoke", &m_flowGridActor.m_materialParams.smoke.fade, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Temp", &m_flowGridActor.m_materialParams.temperature.fade, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel", &m_flowGridActor.m_materialParams.fuel.fade, 0.f, 1.f, 0.01f, true);
+ imguiserEndGroup();
+
+ imguiSeparator();
+ imguiLabel("MacCormack Correction");
+ imguiserBeginGroup("MacCormack Correction", nullptr);
+ imguiserSlider("Velocity", &m_flowGridActor.m_materialParams.velocity.macCormackBlendFactor, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Smoke", &m_flowGridActor.m_materialParams.smoke.macCormackBlendFactor, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Temp", &m_flowGridActor.m_materialParams.temperature.macCormackBlendFactor, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel", &m_flowGridActor.m_materialParams.fuel.macCormackBlendFactor, 0.f, 1.f, 0.01f, true);
+ imguiserEndGroup();
+ imguiLabel("MacCormack Threshold");
+ imguiserBeginGroup("MacCormack Threshold", nullptr);
+ imguiserSlider("Velocity", &m_flowGridActor.m_materialParams.velocity.macCormackBlendThreshold, 0.f, 0.01f, 0.001f, true);
+ imguiserSlider("Smoke", &m_flowGridActor.m_materialParams.smoke.macCormackBlendThreshold, 0.f, 0.01f, 0.001f, true);
+ imguiserSlider("Temp", &m_flowGridActor.m_materialParams.temperature.macCormackBlendThreshold, 0.f, 0.01f, 0.001f, true);
+ imguiserSlider("Fuel", &m_flowGridActor.m_materialParams.fuel.macCormackBlendThreshold, 0.f, 0.01f, 0.001f, true);
+ imguiserEndGroup();
+
+ imguiserSlider("Vorticity Strength", &m_flowGridActor.m_materialParams.vorticityStrength, 0.f, 20.f, 0.1f, true);
+ imguiserSlider("Vorticity Vel Mask", &m_flowGridActor.m_materialParams.vorticityVelocityMask, 0.f, 1.f, 0.01f, true);
+
+ if (imguiCheck("Legacy Pressure", m_flowGridActor.m_gridParams.pressureLegacyMode, true))
+ {
+ m_flowGridActor.m_gridParams.pressureLegacyMode = !m_flowGridActor.m_gridParams.pressureLegacyMode;
+ }
+
+ imguiSeparator();
+ imguiLabel("Combustion");
+ imguiserBeginGroup("Combustion", nullptr);
+ imguiserSlider("Ignition Temp", &m_flowGridActor.m_materialParams.ignitionTemp, 0.f, 0.5f, 0.05f, true);
+ imguiserSlider("Cooling Rate", &m_flowGridActor.m_materialParams.coolingRate, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Buoyancy", &m_flowGridActor.m_materialParams.buoyancyPerTemp, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Expansion", &m_flowGridActor.m_materialParams.divergencePerBurn, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Smoke Per Burn", &m_flowGridActor.m_materialParams.smokePerBurn, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Temp Per Burn", &m_flowGridActor.m_materialParams.tempPerBurn, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Fuel Per Burn", &m_flowGridActor.m_materialParams.fuelPerBurn, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Burn Per Temp", &m_flowGridActor.m_materialParams.burnPerTemp, 0.f, 10.f, 0.1f, true);
+ imguiserEndGroup();
+
+ imguiFluidSimExtra();
+
+ imguiserEndGroup();
+}
+
+void SceneFluid::imguiFluidRender()
+{
+ imguiSeparatorLine();
+ imguiLabel("Rendering");
+ imguiserBeginGroup("Rendering", nullptr);
+ imguiserSlider("Alpha Scale", &m_flowGridActor.m_renderMaterialDefaultParams.alphaScale, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Additive", &m_flowGridActor.m_renderMaterialDefaultParams.additiveFactor, 0.f, 1.f, 0.01f, true);
+ float renderModef = (float)m_flowGridActor.m_renderParams.renderMode;
+ if (imguiserSlider("Render Mode", &renderModef, 0.f, float(eNvFlowVolumeRenderModeCount) - 1.f, 1.f, true))
+ {
+ m_flowGridActor.m_renderParams.renderMode = (NvFlowVolumeRenderMode)((NvFlowUint)renderModef);
+ }
+ float renderChannelf = (float)m_flowGridActor.m_renderParams.renderChannel;
+ if (imguiserSlider("Render Channel", &renderChannelf, 0.f, float(eNvFlowGridTextureChannelCount) - 1.f, 1.f, true))
+ {
+ m_flowGridActor.m_renderParams.renderChannel = (NvFlowGridTextureChannel)((NvFlowUint)renderChannelf);
+ }
+ if (imguiserCheck("Separate Lighting", m_flowGridActor.m_separateLighting, true))
+ {
+ m_flowGridActor.m_separateLighting = !m_flowGridActor.m_separateLighting;
+ }
+ if (imguiserCheck("Debug Render", m_flowGridActor.m_renderParams.debugMode, true))
+ {
+ m_flowGridActor.m_renderParams.debugMode = !m_flowGridActor.m_renderParams.debugMode;
+ }
+ if (m_flowGridActor.m_renderParams.debugMode)
+ {
+ imguiIndent();
+ if (imguiserCheck("Blocks", (m_flowGridActor.m_gridParams.debugVisFlags & eNvFlowGridDebugVisBlocks) != 0, true))
+ {
+ m_flowGridActor.m_gridParams.debugVisFlags = NvFlowGridDebugVisFlags(m_flowGridActor.m_gridParams.debugVisFlags ^ eNvFlowGridDebugVisBlocks);
+ }
+ if (imguiserCheck("Emit Bounds", (m_flowGridActor.m_gridParams.debugVisFlags & eNvFlowGridDebugVisEmitBounds) != 0, true))
+ {
+ m_flowGridActor.m_gridParams.debugVisFlags = NvFlowGridDebugVisFlags(m_flowGridActor.m_gridParams.debugVisFlags ^ eNvFlowGridDebugVisEmitBounds);
+ }
+ if (imguiserCheck("Shapes Simple", (m_flowGridActor.m_gridParams.debugVisFlags & eNvFlowGridDebugVisShapesSimple) != 0, true))
+ {
+ m_flowGridActor.m_gridParams.debugVisFlags = NvFlowGridDebugVisFlags(m_flowGridActor.m_gridParams.debugVisFlags ^ eNvFlowGridDebugVisShapesSimple);
+ }
+ imguiUnindent();
+ }
+ if (imguiserCheck("Edit ColorMap Default", m_flowGridActor.m_colorMap.m_curveEditorActiveDefault, true))
+ {
+ m_flowGridActor.m_colorMap.m_curveEditorActiveDefault = !m_flowGridActor.m_colorMap.m_curveEditorActiveDefault;
+ }
+ if (imguiserCheck("Edit ColorMap Mat0", m_flowGridActor.m_colorMap.m_curveEditorActiveMat0, true))
+ {
+ m_flowGridActor.m_colorMap.m_curveEditorActiveMat0 = !m_flowGridActor.m_colorMap.m_curveEditorActiveMat0;
+ }
+ if (imguiserCheck("Edit ColorMap Mat1", m_flowGridActor.m_colorMap.m_curveEditorActiveMat1, true))
+ {
+ m_flowGridActor.m_colorMap.m_curveEditorActiveMat1 = !m_flowGridActor.m_colorMap.m_curveEditorActiveMat1;
+ }
+ if (imguiserCheck("Multires", m_flowGridActor.m_renderParams.multiRes.enabled, true))
+ {
+ m_flowGridActor.m_renderParams.multiRes.enabled = !m_flowGridActor.m_renderParams.multiRes.enabled;
+ }
+ if (imguiserCheck("Lens Matched", m_flowGridActor.m_renderParams.lensMatchedShading.enabled, true))
+ {
+ m_flowGridActor.m_renderParams.lensMatchedShading.enabled = !m_flowGridActor.m_renderParams.lensMatchedShading.enabled;
+ }
+ if (m_flowGridActor.m_renderParams.multiRes.enabled)
+ {
+ m_flowGridActor.m_renderParams.multiRes.viewport.width = (float)m_winw;
+ m_flowGridActor.m_renderParams.multiRes.viewport.height = (float)m_winh;
+ m_flowGridActor.m_renderParams.multiRes.nonMultiResWidth = (float)m_winw;
+ m_flowGridActor.m_renderParams.multiRes.nonMultiResHeight = (float)m_winh;
+ }
+ if (m_flowGridActor.m_renderParams.lensMatchedShading.enabled)
+ {
+ m_flowGridActor.m_renderParams.lensMatchedShading.viewport.width = (float)m_winw;
+ m_flowGridActor.m_renderParams.lensMatchedShading.viewport.height = (float)m_winh;
+ m_flowGridActor.m_renderParams.lensMatchedShading.nonLMSWidth = (float)m_winw;
+ m_flowGridActor.m_renderParams.lensMatchedShading.nonLMSHeight = (float)m_winh;
+ }
+ imguiserSlider("Screen Percentage", &m_flowGridActor.m_renderParams.screenPercentage, 0.1f, 1.f, 0.01f, true);
+ float smoothVal = float(m_flowGridActor.m_renderParams.smoothColorUpsample);
+ if (imguiserSlider("Upsample Smooth", &smoothVal, 0.f, 1.f, 1.f, true))
+ {
+ m_flowGridActor.m_renderParams.smoothColorUpsample = smoothVal > 0.5f;
+ }
+ if (imguiserCheck("Generate Depth", m_flowGridActor.m_renderParams.generateDepth, true))
+ {
+ m_flowGridActor.m_renderParams.generateDepth = !m_flowGridActor.m_renderParams.generateDepth;
+ }
+ if (imguiserCheck("Generate Depth Vis", m_flowGridActor.m_renderParams.generateDepthDebugMode, true))
+ {
+ m_flowGridActor.m_renderParams.generateDepthDebugMode = !m_flowGridActor.m_renderParams.generateDepthDebugMode;
+ }
+
+ imguiLabel("MultiRes Ray March");
+ float multiResRayMarchf = (float)m_flowGridActor.m_renderParams.multiResRayMarch;
+ if (imguiserSlider("MultiRes levels", &multiResRayMarchf, 0.f, 4.f, 1.f, true))
+ {
+ m_flowGridActor.m_renderParams.multiResRayMarch = (NvFlowMultiResRayMarch)NvFlowUint(multiResRayMarchf);
+ }
+ imguiserSlider("Sampling Rate", &m_flowGridActor.m_renderParams.multiResSamplingScale, 0.1f, 10.f, 0.1f, true);
+
+ imguiLabel("Volume Shadow");
+ if (imguiserCheck("Enabled", m_flowGridActor.m_enableVolumeShadow, true))
+ {
+ m_flowGridActor.m_enableVolumeShadow = !m_flowGridActor.m_enableVolumeShadow;
+ m_shouldReset = true;
+ }
+ if (m_flowGridActor.m_enableVolumeShadow)
+ {
+ if (imguiserCheck("Force Apply", m_flowGridActor.m_forceApplyShadow, true))
+ {
+ m_flowGridActor.m_forceApplyShadow = !m_flowGridActor.m_forceApplyShadow;
+ }
+ imguiserSlider("Light Pan", &m_flowGridActor.m_shadowPan, -4.f, 4.f, 0.01f, true);
+ imguiserSlider("Light Tilt", &m_flowGridActor.m_shadowTilt, -4.f, 4.f, 0.01f, true);
+ if (imguiserSlider("Memory Scale", &m_flowGridActor.m_shadowResidentScale, 0.5f, 2.f, 0.1f, true))
+ {
+ m_shouldReset = true;
+ }
+ imguiserSlider("Intensity Scale", &m_flowGridActor.m_shadowIntensityScale, 0.f, 5.f, 0.01f, true);
+ imguiserSlider("Min Intensity", &m_flowGridActor.m_shadowMinIntensity, 0.0f, 1.f, 0.01f, true);
+ imguiserSlider("BlendTempFactor", &m_flowGridActor.m_shadowBlendCompMask.x, -5.f, 5.f, 0.1f, true);
+ imguiserSlider("BlendBias", &m_flowGridActor.m_shadowBlendBias, -5.0f, 5.f, 0.1f, true);
+ if (imguiserCheck("Debug Vis", m_flowGridActor.m_shadowDebugVis, true))
+ {
+ m_flowGridActor.m_shadowDebugVis = !m_flowGridActor.m_shadowDebugVis;
+ }
+ }
+
+ imguiLabel("Cross Section");
+ if (imguiserCheck("Enabled", m_flowGridActor.m_enableCrossSection, true))
+ {
+ m_flowGridActor.m_enableCrossSection = !m_flowGridActor.m_enableCrossSection;
+ }
+ if (m_flowGridActor.m_enableCrossSection)
+ {
+ if (imguiserCheck("Fullscreen", m_flowGridActor.m_crossSectionParams.fullscreen, true))
+ {
+ m_flowGridActor.m_crossSectionParams.fullscreen = !m_flowGridActor.m_crossSectionParams.fullscreen;
+ }
+ if (imguiserCheck("Point Filter", m_flowGridActor.m_crossSectionParams.pointFilter, true))
+ {
+ m_flowGridActor.m_crossSectionParams.pointFilter = !m_flowGridActor.m_crossSectionParams.pointFilter;
+ }
+ if (imguiserCheck("Velocity Vectors", m_flowGridActor.m_crossSectionParams.velocityVectors, true))
+ {
+ m_flowGridActor.m_crossSectionParams.velocityVectors = !m_flowGridActor.m_crossSectionParams.velocityVectors;
+ }
+ if (imguiserCheck("Outline Cells", m_flowGridActor.m_crossSectionParams.outlineCells, true))
+ {
+ m_flowGridActor.m_crossSectionParams.outlineCells = !m_flowGridActor.m_crossSectionParams.outlineCells;
+ }
+
+ float axis = float(m_flowGridActor.m_crossSectionParams.crossSectionAxis);
+ if (imguiserSlider("Axis", &axis, 0.f, 2.f, 1.f, true))
+ {
+ m_flowGridActor.m_crossSectionParams.crossSectionAxis = NvFlowUint(axis);
+ }
+ imguiserSlider("PosX", &m_flowGridActor.m_crossSectionParams.crossSectionPosition.x, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("PosY", &m_flowGridActor.m_crossSectionParams.crossSectionPosition.y, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("PosZ", &m_flowGridActor.m_crossSectionParams.crossSectionPosition.z, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Scale", &m_flowGridActor.m_crossSectionScale, 0.25f, 20.f, 0.1f, true);
+
+ float renderModef = (float)m_flowGridActor.m_crossSectionParams.renderMode;
+ if (imguiserSlider("Cross Render Mode", &renderModef, 0.f, float(eNvFlowVolumeRenderModeCount) - 1.f, 1.f, true))
+ {
+ m_flowGridActor.m_crossSectionParams.renderMode = (NvFlowVolumeRenderMode)((NvFlowUint)renderModef);
+ }
+ float renderChannelf = (float)m_flowGridActor.m_crossSectionParams.renderChannel;
+ if (imguiserSlider("Cross Render Channel", &renderChannelf, 0.f, float(eNvFlowGridTextureChannelCount) - 1.f, 1.f, true))
+ {
+ m_flowGridActor.m_crossSectionParams.renderChannel = (NvFlowGridTextureChannel)((NvFlowUint)renderChannelf);
+ }
+ imguiserSlider("Intensity", &m_flowGridActor.m_crossSectionParams.intensityScale, 0.01f, 10.f, 0.01f, true);
+ imguiserSlider("Background Color", &m_flowGridActor.m_crossSectionBackgroundColor, 0.f, 1.f, 1.f, true);
+ imguiserSlider("Line Color R", &m_flowGridActor.m_crossSectionLineColor.x, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Line Color G", &m_flowGridActor.m_crossSectionLineColor.y, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Line Color B", &m_flowGridActor.m_crossSectionLineColor.z, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Cell Color R", &m_flowGridActor.m_crossSectionParams.cellColor.x, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Cell Color G", &m_flowGridActor.m_crossSectionParams.cellColor.y, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Cell Color B", &m_flowGridActor.m_crossSectionParams.cellColor.z, 0.f, 1.f, 0.01f, true);
+
+ imguiserSlider("Velocity Scale", &m_flowGridActor.m_crossSectionParams.velocityScale, 0.1f, 10.f, 0.01f, true);
+ imguiserSlider("Vector Length", &m_flowGridActor.m_crossSectionParams.vectorLengthScale, 0.1f, 2.f, 0.01f, true);
+ }
+
+ imguiFluidRenderExtra();
+ imguiserEndGroup();
+}
+
+void SceneFluid::imguiFluidEmitter()
+{
+ imguiSeparatorLine();
+ imguiLabel("Emitter");
+ imguiserBeginGroup("Emitter", nullptr);
+ imguiserSlider("Emit Velocity", &m_emitParams.velocityLinear.y, -16.f, 16.f, 0.1f, true);
+ imguiserSlider("Emit Smoke", &m_emitParams.smoke, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Emit Temp", &m_emitParams.temperature, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Emit Fuel", &m_emitParams.fuel, 0.f, 10.f, 0.1f, true);
+ imguiserSlider("Max Emit Dist", &m_emitParams.maxActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Min Emit Dist", &m_emitParams.minActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Max Edge Dist", &m_emitParams.maxEdgeDist, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Min Edge Dist", &m_emitParams.minEdgeDist, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release Temp", &m_emitParams.fuelReleaseTemp, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release", &m_emitParams.fuelRelease, 0.f, 10.f, 0.1f, true);
+ //imguiserSlider("Slip Thickness", &m_emitParams.slipThickness, 0.f, 1.f, 0.01f, true);
+ //imguiserSlider("Slip Factor", &m_emitParams.slipFactor, 0.f, 1.f, 0.01f, true);
+ float allocScale = m_emitParams.allocationScale.x;
+ if (imguiserSlider("Alloc Scale", &allocScale, 0.f, 2.f, 0.01f, true))
+ {
+ m_emitParams.allocationScale = { allocScale, allocScale, allocScale };
+ }
+ imguiserSlider("Alloc Predict", &m_emitParams.allocationPredict, 0.f, 1.f, 0.01f, true);
+ imguiFluidEmitterExtra();
+ imguiserEndGroup();
+}
+
+void SceneFluid::imguiFluidAlloc()
+{
+ imguiSeparatorLine();
+ imguiLabel("Fluid Allocation");
+ imguiserBeginGroup("Fluid Allocation", nullptr);
+
+ if (imguiserCheck("Big Effect Mode", m_flowGridActor.m_gridParams.bigEffectMode, true))
+ {
+ m_flowGridActor.m_gridParams.bigEffectMode = !m_flowGridActor.m_gridParams.bigEffectMode;
+ }
+ imguiserSlider("Predict Time", &m_flowGridActor.m_gridParams.bigEffectPredictTime, 0.f, 1.f, 0.01f, true);
+
+ imguiserSlider("Velocity Weight", &m_flowGridActor.m_materialParams.velocity.allocWeight, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Smoke Weight", &m_flowGridActor.m_materialParams.smoke.allocWeight, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Temp Weight", &m_flowGridActor.m_materialParams.temperature.allocWeight, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Weight", &m_flowGridActor.m_materialParams.fuel.allocWeight, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Velocity Threshold", &m_flowGridActor.m_materialParams.velocity.allocThreshold, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Smoke Threshold", &m_flowGridActor.m_materialParams.smoke.allocThreshold, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Temp Threshold", &m_flowGridActor.m_materialParams.temperature.allocThreshold, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Threshold", &m_flowGridActor.m_materialParams.fuel.allocThreshold, 0.f, 1.f, 0.01f, true);
+
+ imguiFluidAllocExtra();
+ imguiserEndGroup();
+}
+
+void SceneFluid::imguiFluidTime()
+{
+ imguiSeparatorLine();
+ imguiLabel("Simulation Update Time");
+ {
+ NvFlowQueryTime timeGPU, timeCPU;
+ if (NvFlowGridQueryTime(m_flowGridActor.m_grid, &timeGPU, &timeCPU) == eNvFlowSuccess)
+ {
+ char buf[80];
+ snprintf(buf, sizeof(buf), "GPU: %.3f ms", 1000.f * timeGPU.simulation);
+ imguiValue(buf);
+ snprintf(buf, sizeof(buf), "CPU: %.3f ms", 1000.f * timeCPU.simulation);
+ imguiValue(buf);
+ }
+ }
+ imguiFluidTimeExtra();
+}
+
+void SceneFluid::imguiLoadSave()
+{
+ imguiSeparatorLine();
+
+ static float saveSlot = 0.f;
+ imguiSlider("Save Slot", &saveSlot, 0.f, 7.f, 1.f, true);
+
+ char buf[256u];
+ snprintf(buf, 256u, "../../data/save%d.h", int(saveSlot));
+
+ if (imguiButton("Save"))
+ {
+ imguiserSave(buf);
+ }
+
+ if (imguiButton("Load"))
+ {
+ imguiserLoad(buf);
+ }
+}
+
+void SceneFluid::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ static int scroll = 0u;
+
+ int border = xIn;
+ int x = xIn;
+ int y = border;
+ int w = wIn;
+ int h = m_winh - (hIn + border) - 2 * border;
+ m_editorWidth = x + w;
+
+ imguiBeginScrollArea("Options",
+ x, y,
+ w, h,
+ &scroll);
+
+ imguiserBeginGroup("Effect", nullptr);
+
+ imguiDesc();
+
+ imguiSeparatorLine();
+
+ m_projectile.imgui();
+
+ imguiFluidSim();
+
+ imguiFluidEmitter();
+
+ imguiFluidRender();
+
+ imguiFluidAlloc();
+
+ imguiLoadSave();
+
+ imguiFluidTime();
+
+ imguiEndScrollArea();
+
+ m_flowGridActor.m_colorMap.imguiUpdate(this, m_flowContext.m_renderContext, border, x, y, w, h);
+
+ imguiserEndGroup();
+}
+
+bool SceneFluid::imguiMouse(int mx, int my, unsigned char mbut)
+{
+ Scene::imguiMouse(mx, my, mbut);
+
+ if (mx < m_editorWidth) return true;
+
+ if (m_flowGridActor.m_colorMap.colorMapActive(mx, my, mbut)) return true;
+
+ return false;
+}
+
+void SceneFluid::reset()
+{
+ release();
+ SDL_Delay(30);
+ init(m_appctx, m_winw, m_winh);
+ m_shouldReset = false;
+}
+
+NvFlowUint64 SceneFluid::getGridGPUMemUsage()
+{
+ NvFlowUint64 totalBytes = 0u;
+
+ if (m_flowGridActor.m_grid)
+ {
+ NvFlowGridGPUMemUsage(m_flowGridActor.m_grid, &totalBytes);
+ }
+
+ return totalBytes;
+}
+
+bool SceneFluid::getStats(int lineIdx, int statIdx, char* buf)
+{
+ switch (statIdx)
+ {
+ case 0:
+ {
+ NvFlowUint64 totalBytes = getGridGPUMemUsage();
+ snprintf(buf, 79, "GridGPUMem: %llu bytes", totalBytes);
+ return true;
+ }
+ case 1:
+ {
+ NvFlowUint numLayers = m_flowGridActor.m_statNumLayers;
+ snprintf(buf, 79, "NumLayers: %d layers", numLayers);
+ return true;
+ }
+ case 2:
+ {
+ NvFlowUint numBlocks = m_flowGridActor.m_statNumDensityBlocks;
+ NvFlowUint maxBlocks = m_flowGridActor.m_statMaxDensityBlocks;
+ snprintf(buf, 79, "Density: %d blocks active of %d", numBlocks, maxBlocks);
+ return true;
+ }
+ case 3:
+ {
+ NvFlowUint numBlocks = m_flowGridActor.m_statNumVelocityBlocks;
+ NvFlowUint maxBlocks = m_flowGridActor.m_statMaxVelocityBlocks;
+ snprintf(buf, 79, "Velocity: %d blocks active of %d", numBlocks, maxBlocks);
+ return true;
+ }
+ case 4:
+ {
+ NvFlowUint numCells = m_flowGridActor.m_statNumDensityCells;
+ snprintf(buf, 79, "Density: %d cells active", numCells);
+ return true;
+ }
+ case 5:
+ {
+ NvFlowUint numCells = m_flowGridActor.m_statNumVelocityCells;
+ snprintf(buf, 79, "Velocity: %d cells active", numCells);
+ return true;
+ }
+ case 6:
+ {
+ if (m_flowGridActor.m_statVolumeShadowBlocks > 0u)
+ {
+ NvFlowUint numBlocks = m_flowGridActor.m_statVolumeShadowBlocks;
+ snprintf(buf, 79, "Shadow: %d blocks active", numBlocks);
+ return true;
+ }
+ return false;
+ }
+ case 7:
+ {
+ if (m_flowGridActor.m_statVolumeShadowCells > 0u)
+ {
+ NvFlowUint numCells = m_flowGridActor.m_statVolumeShadowCells;
+ snprintf(buf, 79, "Shadow: %d cells active", numCells);
+ return true;
+ }
+ return false;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+// ***************************** Projectile ********************************
+
+void Projectile::init(AppGraphCtx* appctx, NvFlowContext* context)
+{
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+ m_emitParams.bounds.x.x = m_radius;
+ m_emitParams.bounds.y.y = m_radius;
+ m_emitParams.bounds.z.z = m_radius;
+ m_emitParams.bounds.w.y = 0.f;
+
+ m_emitParams.velocityCoupleRate = { 10.f, 10.f, 10.f };
+
+ m_emitParams.temperature = 0.f;
+ m_emitParams.temperatureCoupleRate = 10.f;
+
+ m_emitParams.fuel = 0.f;
+ m_emitParams.fuelCoupleRate = 10.f;
+
+ m_emitParams.smoke = 0.f;
+ m_emitParams.smokeCoupleRate = 10.f;
+
+ m_emitParams.allocationScale = { 0.f, 0.f, 0.f };
+
+ updateEmitterMode();
+
+ m_appctx = appctx;
+ m_meshContext = MeshInteropContextCreate(appctx);
+ m_mesh = MeshCreate(m_meshContext);
+
+ MeshLoadFromFile(m_mesh, "../../data/sphere_high.ply");
+
+ NvFlowShapeSDFDesc shapeDesc;
+ NvFlowShapeSDFDescDefaults(&shapeDesc);
+ shapeDesc.resolution = { 32u, 32u, 32u };
+ m_shape = NvFlowCreateShapeSDF(context, &shapeDesc);
+
+ // generate sphere SDF
+ const float radius = 0.8f;
+ auto mappedData = NvFlowShapeSDFMap(m_shape, context);
+ if (mappedData.data)
+ {
+ for (NvFlowUint k = 0; k < mappedData.dim.z; k++)
+ for (NvFlowUint j = 0; j < mappedData.dim.y; j++)
+ for (NvFlowUint i = 0; i < mappedData.dim.x; i++)
+ {
+ float& val = mappedData.data[k * mappedData.depthPitch + j * mappedData.rowPitch + i];
+
+ float x = 2.f * (float(i) + 0.5f) / float(mappedData.dim.x) - 1.f;
+ float y = 2.f * (float(j) + 0.5f) / float(mappedData.dim.y) - 1.f;
+ float z = 2.f * (float(k) + 0.5f) / float(mappedData.dim.z) - 1.f;
+
+ float d = sqrtf(x*x + y*y + z*z);
+ float v = d - radius;
+
+ val = v;
+ }
+ NvFlowShapeSDFUnmap(m_shape, context);
+ }
+}
+
+void Projectile::updatePosition(Path& path, float dt)
+{
+ if (path.m_active)
+ {
+ path.m_time -= dt;
+ if (path.m_time > path.m_timeEnd)
+ {
+ float wx = path.m_direction[0];
+ float wy = path.m_direction[1];
+ float wz = path.m_direction[2];
+
+ m_emitParams.smoke = 0.f;
+ m_emitParams.temperature = m_temperature;
+ m_emitParams.fuel = m_fuel;
+ m_emitParams.velocityLinear.x = -m_speed * wx;
+ m_emitParams.velocityLinear.y = -m_speed * wy;
+ m_emitParams.velocityLinear.z = -m_speed * wz;
+ float dist = m_speed * path.m_time;
+ path.m_position[0] = dist * wx + path.m_offset[0];
+ path.m_position[1] = dist * wy + path.m_offset[1];
+ path.m_position[2] = dist * wz + path.m_offset[2];
+ m_emitParams.bounds.w.x = path.m_position[0];
+ m_emitParams.bounds.w.y = path.m_position[1];
+ m_emitParams.bounds.w.z = path.m_position[2];
+ }
+ else
+ {
+ path.m_time = path.m_timeEnd;
+ path.m_active = false;
+ }
+ }
+}
+
+void Projectile::update(NvFlowContext* context, NvFlowGrid* grid, float dt)
+{
+ int maxActive = -1;
+ for (int i = 0; i < m_pathsSize; i++)
+ {
+ Path& path = m_paths[i];
+ if (path.m_active)
+ {
+ maxActive = i;
+ const int numSubSteps = 4;
+ const float convert = 3.14159f / 180.f;
+ float stepdt = dt / float(numSubSteps);
+ for (int i = 0; i < numSubSteps; i++)
+ {
+ updatePosition(path, stepdt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = stepdt;
+
+ NvFlowGridEmit(grid, &shapeDesc, 1u, &m_emitParams, 1u);
+ }
+ }
+ }
+ m_pathsSize = maxActive + 1;
+}
+
+void Projectile::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_view = view;
+ m_projection = projection;
+
+ MeshInteropContextUpdate(m_meshContext, m_appctx);
+
+ if (m_shouldDrawMesh)
+ {
+ for (int i = 0; i < m_pathsSize; i++)
+ {
+ Path& path = m_paths[i];
+ if (path.m_active)
+ {
+ MeshDrawParams meshDrawParams;
+ meshDrawParams.renderMode = MESH_RENDER_SOLID;
+ meshDrawParams.projection = projection;
+ meshDrawParams.view = view;
+ meshDrawParams.model = DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixScaling(0.8f * m_radius, 0.8f * m_radius, 0.8f * m_radius),
+ DirectX::XMMatrixTranslation(path.m_position[0], path.m_position[1], path.m_position[2])
+ );
+
+ MeshDraw(m_mesh, &meshDrawParams);
+ }
+ }
+ }
+}
+
+void Projectile::shoot()
+{
+ // find open path
+ int allocIdx = 0;
+ bool allocSuccess = false;
+ for (; allocIdx < m_pathsCap; allocIdx++)
+ {
+ Path& path = m_paths[allocIdx];
+ if (!path.m_active)
+ {
+ allocSuccess = true;
+ break;
+ }
+ }
+ if (allocSuccess)
+ {
+ // update size
+ if (allocIdx + 1 > m_pathsSize)
+ {
+ m_pathsSize = allocIdx + 1;
+ }
+ // create path reference
+ Path& path = m_paths[allocIdx];
+ path.m_active = true;
+ // compute direction
+ {
+ using namespace DirectX;
+ // compute eye direction
+ XMVECTOR screenDir = XMVectorSet(1.f, 0.f, 0.f, 0.f);
+ XMMATRIX viewInv = XMMatrixInverse(nullptr, m_view);
+ XMVECTOR worldDir = XMVector4Transform(screenDir, viewInv);
+ worldDir = XMVector3Normalize(worldDir);
+
+ XMMATRIX viewProj = XMMatrixMultiply(m_view, m_projection);
+ XMMATRIX viewProjInv = XMMatrixInverse(nullptr, viewProj);
+
+ float txp = 0.f;
+ float txn = 0.f;
+ {
+ XMVECTOR pos = XMVectorSet(0.f, 0.f, 0.f, 1.f);
+ XMVECTOR screencenter = XMVector4Transform(pos, viewProj);
+ screencenter = screencenter / XMVectorSplatW(screencenter);
+
+ pos = worldDir + XMVectorSet(0.f, 0.f, 0.f, 1.f);
+ XMVECTOR screenpos = XMVector4Transform(pos, viewProj);
+ screenpos = screenpos / XMVectorSplatW(screenpos);
+
+ // compute world offset
+ XMVECTOR offset = XMVectorSet(1.f, 0.f, 1.f, 1.f) * screencenter;
+ offset = XMVector4Transform(offset, viewProjInv);
+ offset = offset / XMVectorSplatW(offset);
+ path.m_offset[0] = XMVectorGetX(offset);
+ path.m_offset[1] = XMVectorGetY(offset);
+ path.m_offset[2] = XMVectorGetZ(offset);
+
+ float x0 = XMVectorGetX(screencenter);
+ float x1 = XMVectorGetX(screenpos);
+ txp = (+1.f - x0) / (x1 - x0);
+ txn = (-1.f - x0) / (x1 - x0);
+ }
+ path.m_timeBegin = txp / m_speed;
+ path.m_timeEnd = txn / m_speed;
+ path.m_time = path.m_timeBegin;
+
+ path.m_direction[0] = XMVectorGetX(worldDir);
+ path.m_direction[1] = XMVectorGetY(worldDir);
+ path.m_direction[2] = XMVectorGetZ(worldDir);
+ }
+ // set zeroth position
+ updatePosition(path, 0.f);
+ }
+}
+
+void Projectile::updateEmitterMode()
+{
+ if (m_fireBallMode)
+ {
+ if (m_prediction)
+ {
+ m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ m_emitParams.allocationPredict = 0.4f;
+ }
+ else
+ {
+ m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ m_emitParams.allocationPredict = 0.f;
+ }
+ m_temperature = 2.f;
+ m_fuel = 2.f;
+ }
+ else
+ {
+ m_emitParams.allocationScale = { 0.f, 0.f, 0.f };
+ m_emitParams.allocationPredict = 0.f;
+ m_temperature = 10.f;
+ m_fuel = 0.f;
+ }
+}
+
+void Projectile::imgui()
+{
+ if (imguiButton("Shoot", true))
+ {
+ shoot();
+ }
+ if (imguiCheck("Fire Ball", m_fireBallMode))
+ {
+ m_fireBallMode = !m_fireBallMode;
+ updateEmitterMode();
+ }
+ if (imguiSlider("Radius", &m_radius, 0.f, 1.f, 0.01f, true))
+ {
+ m_emitParams.bounds.x.x = m_radius;
+ m_emitParams.bounds.y.y = m_radius;
+ m_emitParams.bounds.z.z = m_radius;
+ }
+ imguiSlider("Speed", &m_speed, 0.f, 32.f, 0.1f, true);
+ imguiSlider("Temperature", &m_temperature, 0.f, 10.f, 0.1f, true);
+ if (m_fireBallMode)
+ {
+ imguiSlider("Fuel", &m_fuel, 0.f, 10.f, 0.1f, true);
+ if (imguiCheck("Prediction", m_prediction))
+ {
+ m_prediction = !m_prediction;
+ updateEmitterMode();
+ }
+ }
+ if (imguiCheck("Draw Projectile", m_shouldDrawMesh))
+ {
+ m_shouldDrawMesh = !m_shouldDrawMesh;
+ }
+}
+
+void Projectile::release()
+{
+ // set all projectiles inactive
+ for (int i = 0; i < m_pathsSize; i++)
+ {
+ Path& path = m_paths[i];
+ path.m_active = false;
+ }
+
+ NvFlowReleaseShapeSDF(m_shape);
+
+ MeshRelease(m_mesh);
+ MeshContextRelease(m_meshContext);
+} \ No newline at end of file
diff --git a/demo/DemoApp/scene.h b/demo/DemoApp/scene.h
new file mode 100644
index 0000000..fee39e4
--- /dev/null
+++ b/demo/DemoApp/scene.h
@@ -0,0 +1,838 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#ifndef SCENE_H
+#define SCENE_H
+
+#include <DirectXMath.h>
+
+#include <vector>
+
+#include "mesh.h"
+#include "meshInterop.h"
+#include "bitmap.h"
+#include "curveEditor.h"
+
+#include "NvFlow.h"
+#include "NvFlowInterop.h"
+
+struct AppGraphCtx;
+
+struct TimeStepper
+{
+ float m_deltaTime = 0.f;
+ float m_timeError = 0.f;
+ float m_fixedDt = (1.f / 60.f);
+ int m_maxSteps = 1;
+
+ TimeStepper() {}
+
+ int getNumSteps(float dt)
+ {
+ m_deltaTime = dt;
+
+ // compute time steps
+ m_timeError += m_deltaTime;
+
+ int numSteps = int(m_timeError / m_fixedDt);
+ if (numSteps < 0) numSteps = 0;
+
+ m_timeError -= m_fixedDt * float(numSteps);
+
+ if (numSteps > m_maxSteps) numSteps = m_maxSteps;
+
+ return numSteps;
+ }
+};
+
+struct Scene
+{
+ Scene(const char* name) : m_name(name) {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh) = 0;
+ virtual void resize(int winw, int winh);
+ virtual void update(float dt) final;
+ virtual void preDraw() = 0;
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view) = 0;
+ virtual void release() = 0;
+
+ virtual void shoot() = 0;
+
+ virtual NvFlowUint64 getGridGPUMemUsage() = 0;
+ virtual bool getStats(int lineIdx, int statIdx, char* buf) = 0;
+
+ virtual void imgui(int x, int y, int w, int h) = 0;
+ virtual bool imguiMouse(int mx, int my, unsigned char mbut);
+
+ virtual bool shouldReset() = 0;
+ virtual void reset() = 0;
+
+ const char* m_name;
+
+ int m_mx = 0;
+ int m_my = 0;
+ unsigned char m_mbut;
+ int m_winw = 0;
+ int m_winh = 0;
+
+protected:
+ virtual void doUpdate(float dt) = 0;
+
+ AppGraphCtx* m_context = nullptr;
+ TimeStepper m_timeStepper;
+
+ int m_editorWidth = 0;
+
+ friend struct ColorMapped;
+};
+
+struct FlowColorMap
+{
+ NvFlowRenderMaterialPool* m_materialPool = nullptr;
+ NvFlowRenderMaterialHandle m_materialDefault;
+ NvFlowRenderMaterialHandle m_material0;
+ NvFlowRenderMaterialHandle m_material1;
+
+ unsigned int m_curveEditorHeight = 264u;
+
+ bool m_curveEditorActiveDefault = false;
+ bool m_curveEditorActiveMat0 = false;
+ bool m_curveEditorActiveMat1 = false;
+ CurveEditState m_editStateDefault = { 0, 0 };
+ CurveEditState m_editStateMat0 = { 0, 0 };
+ CurveEditState m_editStateMat1 = { 0, 0 };
+ std::vector<CurvePoint> m_curvePointsDefault;
+ std::vector<CurvePoint> m_curvePointsMat0;
+ std::vector<CurvePoint> m_curvePointsMat1;
+
+ void initColorMap(NvFlowContext* context, const CurvePoint* pts, int numPoints, bool ptsEnabled);
+ void updateColorMap(NvFlowContext* context);
+ void imguiUpdate(Scene* scene, NvFlowContext* context, int border, int x, int y, int w, int h);
+ bool colorMapActive(int mx, int my, unsigned char mbut);
+};
+
+struct FlowContext
+{
+ AppGraphCtx* m_appctx = nullptr;
+
+ NvFlowContext* m_renderContext = nullptr;
+ NvFlowDepthStencilView* m_dsv = nullptr;
+ NvFlowRenderTargetView* m_rtv = nullptr;
+
+ NvFlowDevice* m_renderDevice = nullptr;
+ NvFlowDevice* m_gridDevice = nullptr;
+ NvFlowDeviceQueue* m_gridQueue = nullptr;
+ NvFlowDeviceQueue* m_gridCopyQueue = nullptr;
+ NvFlowDeviceQueue* m_renderCopyQueue = nullptr;
+ NvFlowContext* m_gridContext = nullptr;
+ NvFlowContext* m_gridCopyContext = nullptr;
+ NvFlowContext* m_renderCopyContext = nullptr;
+
+ bool m_multiGPUSupported = false;
+ bool m_commandQueueSupported = false;
+ bool m_enableMultiGPU = false;
+ bool m_enableCommandQueue = false;
+ bool m_multiGPUActive = false;
+ bool m_commandQueueActive = false;
+
+ int m_maxFramesInFlight = 3u;
+ int m_framesInFlight = 0;
+
+ FlowContext() {}
+ ~FlowContext() {}
+
+ void init(AppGraphCtx* appctx);
+ void release();
+
+ bool updateBegin();
+ void updateEnd();
+ void preDrawBegin();
+ void preDrawEnd();
+ void drawBegin();
+ void drawEnd();
+
+protected:
+ void createComputeContext();
+ void releaseComputeContext();
+ int computeContextBegin();
+ void computeContextEnd();
+};
+
+struct FlowGridActor
+{
+ AppGraphCtx* m_appctx = nullptr;
+
+ NvFlowGrid* m_grid = nullptr;
+ NvFlowGridProxy* m_gridProxy = nullptr;
+ NvFlowVolumeRender* m_volumeRender = nullptr;
+ NvFlowVolumeShadow* m_volumeShadow = nullptr;
+ NvFlowCrossSection* m_crossSection = nullptr;
+
+ NvFlowGridDesc m_gridDesc;
+ NvFlowGridParams m_gridParams;
+ NvFlowGridMaterialParams m_materialParams;
+ NvFlowRenderMaterialParams m_renderMaterialDefaultParams;
+ NvFlowRenderMaterialParams m_renderMaterialMat0Params;
+ NvFlowRenderMaterialParams m_renderMaterialMat1Params;
+ NvFlowVolumeRenderParams m_renderParams;
+ NvFlowCrossSectionParams m_crossSectionParams;
+
+ FlowColorMap m_colorMap;
+
+ NvFlowGridExport* m_gridExportDebugVis = nullptr;
+ NvFlowGridExport* m_gridExportOverride = nullptr;
+ NvFlowVolumeRenderParams m_renderParamsOverride;
+ bool m_separateLighting = false;
+
+ float m_memoryLimit = 3.f;
+ float m_memoryScale = 0.125f * 0.075f;
+ int m_cellSizeLogScale = 0;
+ float m_cellSizeScale = 1.f;
+
+ bool m_enableVolumeShadow = false;
+ bool m_forceApplyShadow = false;
+ float m_shadowResidentScale = 1.f;
+ float m_shadowIntensityScale = 0.5f;
+ float m_shadowMinIntensity = 0.15f;
+ NvFlowFloat4 m_shadowBlendCompMask = { 0.f, 0.f, 0.f, 0.f };
+ float m_shadowBlendBias = 1.f;
+ bool m_shadowDebugVis = false;
+ float m_shadowPan = 0.f;
+ float m_shadowTilt = 0.f;
+
+ bool m_shadowWasForceApplied = false;
+ NvFlowFloat4 m_forceIntensityCompMask = { 0.f, 0.f, 0.f, 0.f };
+ float m_forceIntensityBias = 1.f;
+
+ bool m_enableCrossSection = false;
+ float m_crossSectionScale = 2.f;
+ float m_crossSectionBackgroundColor = 0.f;
+ NvFlowFloat3 m_crossSectionLineColor = { 141.f / 255.f, 199.f / 255.f, 63.f / 255.f };
+
+ NvFlowUint m_statNumLayers = 0u;
+ NvFlowUint m_statNumDensityBlocks = 0u;
+ NvFlowUint m_statNumDensityCells = 0u;
+ NvFlowUint m_statMaxDensityBlocks = 0u;
+ NvFlowUint m_statNumVelocityBlocks = 0u;
+ NvFlowUint m_statNumVelocityCells = 0u;
+ NvFlowUint m_statMaxVelocityBlocks = 0u;
+
+ NvFlowUint m_statVolumeShadowBlocks = 0u;
+ NvFlowUint m_statVolumeShadowCells = 0u;
+
+ FlowGridActor() {}
+ ~FlowGridActor() {}
+
+ void initParams(size_t vramAmount);
+ void init(FlowContext* flowContext, AppGraphCtx* appctx);
+ void release();
+
+ void updatePreEmit(FlowContext* flowContext, float dt);
+ void updatePostEmit(FlowContext* flowContext, float dt, bool shouldUpdate, bool shouldReset);
+ void preDraw(FlowContext* flowContext);
+ void draw(FlowContext* flowContext, DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+};
+
+struct Projectile
+{
+ struct Path
+ {
+ float m_time = 0.f;
+ float m_timeBegin = 0.f;
+ float m_timeEnd = 0.f;
+ bool m_active = false;
+
+ float m_direction[3] = { 1.f, 0.f, 0.f };
+ float m_offset[3] = { 0.f, 0.f, 0.f };
+ float m_position[3] = { 0.f, 0.f, 0.f };
+ };
+
+ static const int m_pathsCap = 32u;
+ Path m_paths[m_pathsCap];
+ int m_pathsSize = 0;
+
+ NvFlowShapeSDF* m_shape = nullptr;
+ NvFlowGridEmitParams m_emitParams;
+
+ float m_radius = 0.15f;
+ float m_speed = 8.f;
+ float m_temperature = 10.f;
+ float m_fuel = 0.f;
+
+ DirectX::XMMATRIX m_view;
+ DirectX::XMMATRIX m_projection;
+
+ AppGraphCtx* m_appctx = nullptr;
+ MeshContext* m_meshContext = nullptr;
+ Mesh* m_mesh = nullptr;
+ bool m_shouldDrawMesh = true;
+ bool m_fireBallMode = false;
+ bool m_prediction = true;
+
+ Projectile() {}
+
+ void init(AppGraphCtx* appctx, NvFlowContext* context);
+
+ void shoot();
+
+ void update(NvFlowContext* context, NvFlowGrid* grid, float dt);
+
+ void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+
+ void imgui();
+
+ void release();
+
+protected:
+ void updatePosition(Path& path, float dt);
+
+ void updateEmitterMode();
+};
+
+struct SceneFluid : public Scene
+{
+ SceneFluid(const char* name) : Scene(name) {}
+
+ virtual void initParams() = 0;
+
+ void imguiDesc();
+ void imguiFluidSim();
+ void imguiFluidEmitter();
+ void imguiFluidRender();
+ void imguiFluidAlloc();
+ void imguiFluidTime();
+ void imguiLoadSave();
+
+ virtual void imguiDescExtra() {}
+ virtual void imguiFluidSimExtra() {}
+ virtual void imguiFluidEmitterExtra() {}
+ virtual void imguiFluidRenderExtra() {}
+ virtual void imguiFluidAllocExtra() {}
+ virtual void imguiFluidTimeExtra() {}
+
+ virtual void imgui(int x, int y, int w, int h);
+ virtual bool imguiMouse(int mx, int my, unsigned char mbut);
+
+ virtual void shoot() { m_projectile.shoot(); }
+
+ virtual NvFlowUint64 getGridGPUMemUsage();
+ virtual bool getStats(int lineIdx, int statIdx, char* buf);
+
+ AppGraphCtx* m_appctx = nullptr;
+
+ FlowContext m_flowContext;
+ FlowGridActor m_flowGridActor;
+
+ Projectile m_projectile;
+
+ NvFlowShapeSDF* m_shape = nullptr;
+
+ NvFlowGridEmitParams m_emitParams;
+
+ bool m_isFirstRun = true;
+ bool m_shouldReset = false;
+ bool m_shouldGridReset = false;
+ bool m_shouldLoadPreset = false;
+
+ virtual bool shouldReset() { return m_shouldReset; }
+ virtual void reset();
+};
+
+struct SceneSimpleFlame : public SceneFluid
+{
+ SceneSimpleFlame() : SceneFluid("Simple Flame") {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void initParams();
+};
+
+struct SceneSimpleFlameDouble : public SceneSimpleFlame
+{
+ SceneSimpleFlameDouble() { m_name = "Multi Material"; }
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void initParams();
+
+ NvFlowGridEmitParams m_emitParamsA;
+ NvFlowGridEmitParams m_emitParamsB;
+ NvFlowGridMaterialHandle m_materialA;
+ NvFlowGridMaterialHandle m_materialB;
+};
+
+struct SceneSimpleFlameFuelMap : public SceneSimpleFlame
+{
+ SceneSimpleFlameFuelMap() { m_name = "Fuel Map"; }
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void initParams();
+};
+
+struct SceneSimpleFlameParticleSurface : public SceneSimpleFlame
+{
+ SceneSimpleFlameParticleSurface() { m_name = "Particle Surface"; }
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+ virtual void imguiFluidRenderExtra();
+
+ virtual void initParams();
+
+ static void emitCustomAllocFunc(void* userdata, const NvFlowGridEmitCustomAllocParams* params);
+ static void emitCustomEmitVelocityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+ static void emitCustomEmitDensityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+
+ void doEmitCustomAllocFunc(const NvFlowGridEmitCustomAllocParams* params);
+ void doEmitCustomEmitVelocityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+ void doEmitCustomEmitDensityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+
+ NvFlowParticleSurface* m_particleSurface = nullptr;
+
+ NvFlowParticleSurfaceParams m_particleParams = {};
+ NvFlowParticleSurfaceEmitParams m_surfaceEmitParams = {};
+
+ bool m_visualizeSurface = true;
+ float m_time = 0.f;
+
+ std::vector<float> m_positions;
+};
+
+struct SceneSimpleFlameThrower : public SceneSimpleFlame
+{
+ float time = 0.f;
+
+ SceneSimpleFlameThrower() { m_name = "Simple Flame Thrower"; }
+
+ virtual void initParams()
+ {
+ SceneSimpleFlame::initParams();
+
+ m_flowGridActor.m_gridParams.gravity = { 0.f, -0.5f, 0.f };
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.4f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.4f;
+ m_flowGridActor.m_materialParams.vorticityStrength = 20.f;
+
+ m_emitParams.fuel = 2.0f;
+ m_emitParams.temperature = 3.f;
+ m_emitParams.smoke = 0.5f;
+
+ m_emitParams.bounds.x.x = 0.5f;
+ m_emitParams.bounds.y.y = 0.5f;
+ m_emitParams.bounds.z.z = 0.5f;
+
+ m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ m_emitParams.allocationPredict = 0.05f;
+ }
+
+ void init(AppGraphCtx* context, int winw, int winh)
+ {
+ SceneSimpleFlame::init(context, winw, winh);
+ }
+
+ void doUpdate(float dt)
+ {
+ time += dt;
+
+ const float rate = 8.f;
+ const float period = 2.f * 3.14159265f / rate;
+ if (time > period) time -= period;
+
+ m_emitParams.bounds.w.x = 0.f; // 2.f * cosf(rate * time);
+ m_emitParams.bounds.w.z = 0.f; // 2.f * sinf(rate * time);
+
+ float a = 0.25f * cosf(rate * time);
+
+ m_emitParams.velocityLinear.x = +32.f * cosf(a);
+ m_emitParams.velocityLinear.y = -2.f + 64.f * (1.f - cosf(a));
+ m_emitParams.velocityLinear.z = +32.f * sinf(a);
+
+ SceneSimpleFlame::doUpdate(dt);
+ }
+
+ void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+ {
+ SceneSimpleFlame::draw(projection, view);
+ }
+
+ void release()
+ {
+ SceneSimpleFlame::release();
+ }
+};
+
+struct SceneSimpleFlameBall : public SceneSimpleFlame
+{
+ float time = 0.f;
+ float m_radius = 0.6f;
+
+ SceneSimpleFlameBall() { m_name = "Simple Flame Ball"; }
+
+ virtual void initParams();
+
+ void init(AppGraphCtx* context, int winw, int winh);
+
+ void doUpdate(float dt);
+
+ void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+
+ void imguiFluidRenderExtra();
+
+ void imguiFluidEmitterExtra();
+
+ void imguiFluidSimExtra();
+
+ void imgui(int xIn, int yIn, int wIn, int hIn);
+
+ void release();
+};
+
+struct SceneSimpleFlameAnimated : public SceneSimpleFlame
+{
+ float time = 0.f;
+
+ SceneSimpleFlameAnimated() { m_name = "Simple Flame Animated"; }
+
+ virtual void initParams()
+ {
+ SceneSimpleFlame::initParams();
+
+ m_flowGridActor.m_gridParams.gravity = { 0.f, -0.5f, 0.f };
+
+ m_emitParams.fuel = 1.4f;
+ m_emitParams.temperature = 3.f;
+ m_emitParams.smoke = 0.5f;
+
+ m_emitParams.allocationScale = { 1.33f, 1.33f, 1.33f };
+ }
+
+ void init(AppGraphCtx* context, int winw, int winh)
+ {
+ SceneSimpleFlame::init(context, winw, winh);
+ }
+
+ void doUpdate(float dt)
+ {
+ time += dt;
+
+ const float rate = 0.375f;
+ const float period = 2.f * 3.14159265f / rate;
+ if (time > period) time -= period;
+
+ m_emitParams.bounds.w.x = 2.f * cosf(rate * time);
+ m_emitParams.bounds.w.z = 2.f * sinf(rate * time);
+
+ m_emitParams.velocityLinear.x = +8.f * sinf(rate * time);
+ m_emitParams.velocityLinear.y = -2.f;
+ m_emitParams.velocityLinear.z = -8.f * cosf(rate * time);
+
+ m_emitParams.predictVelocityWeight = 1.f;
+ m_emitParams.predictVelocity.x = -4.f * sinf(rate * time);
+ m_emitParams.predictVelocity.y = 0.f;
+ m_emitParams.predictVelocity.z = +4.f * cosf(rate * time);
+
+ SceneSimpleFlame::doUpdate(dt);
+ }
+
+ void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+ {
+ SceneSimpleFlame::draw(projection, view);
+ }
+
+ void release()
+ {
+ SceneSimpleFlame::release();
+ }
+};
+
+struct SceneDynamicCoupleRate : public SceneSimpleFlame
+{
+ float theta = 0.f;
+ float rate = 0.25f;
+ float coupleRateScale = 0.1f;
+ float emitterScale = 1.f;
+
+ SceneDynamicCoupleRate() { m_name = "Dynamic Couple Rate"; }
+
+ virtual void initParams();
+
+ void doUpdate(float dt);
+
+ virtual void imguiFluidEmitterExtra();
+
+ static float positionFunc(float theta);
+ static float velocityFunc(float theta, float rate);
+};
+
+struct SceneSimpleFlameMesh : public SceneSimpleFlame
+{
+ MeshContext* m_meshContext = nullptr;
+ Mesh* m_mesh = nullptr;
+ NvFlowSDFGen* m_sdfGen = nullptr;
+ NvFlowShapeSDF* m_teapotShape = nullptr;
+ bool m_shouldDrawMesh = true;
+
+ NvFlowFloat3 m_sdfScale = { 0.25f, 0.25f, 0.25f };
+ NvFlowFloat3 m_emitterScale = { 0.5f, 0.5f, 0.5f };
+ NvFlowFloat3 m_emitterOffset = { 0.f, 0.33f, 0.f };
+
+ const char* m_meshPath = "../../data/teapot.ply";
+
+ NvFlowGridEmitParams m_teapotEmitParams;
+
+ bool m_animate = true;
+ float m_time = 0.f;
+
+ SceneSimpleFlameMesh() { m_name = "Simple Flame Mesh"; }
+
+ virtual void initParams();
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+
+ virtual void doUpdate(float dt);
+
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+
+ virtual void release();
+
+ virtual void imguiFluidRenderExtra();
+
+ virtual void imguiFluidEmitterExtra();
+};
+
+struct SceneSimpleFlameCollision : public SceneSimpleFlameMesh
+{
+ SceneSimpleFlameCollision()
+ {
+ m_name = "Simple Flame Collision";
+ m_meshPath = "../../data/box.ply";
+ m_sdfScale = { 0.75f, 0.75f, 0.75f };
+ m_emitterScale = { 1.5f, 0.125f, 1.5f };
+ m_emitterOffset = { 0.f, 0.6f, 0.f };
+ }
+};
+
+struct SceneSimpleFlameCulling : public SceneSimpleFlame
+{
+ SceneSimpleFlameCulling() { m_name = "Simple Flame Culling"; }
+
+ virtual void initParams();
+
+ virtual void doUpdate(float dt);
+
+ virtual void imguiFluidEmitterExtra();
+
+ NvFlowUint m_emitGridR = 8u;
+};
+
+struct SceneSimpleFlameConvex : public SceneSimpleFlame
+{
+ SceneSimpleFlameConvex() { m_name = "Convex"; }
+
+ virtual void initParams();
+
+ virtual void doUpdate(float dt);
+
+ virtual void imguiFluidEmitterExtra();
+
+ float m_size = 0.75f;
+ float m_distanceScale = 1.f;
+};
+
+struct SceneSimpleFlameCapsule : public SceneSimpleFlame
+{
+ SceneSimpleFlameCapsule() { m_name = "Capsule"; }
+
+ virtual void initParams();
+
+ virtual void doUpdate(float dt);
+
+ virtual void imguiFluidEmitterExtra();
+
+ float m_capsuleRadius = 0.25f;
+ float m_capsuleLength = 0.75f;
+ float m_distanceScale = 3.5f;
+ bool m_boxMode = false;
+};
+
+struct Scene2DTextureEmitter : public SceneFluid
+{
+ Scene2DTextureEmitter(bool animEnabled) : SceneFluid(animEnabled ? "Logo Pulsed" : "Logo Steady"), m_animEnabled(animEnabled) {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imguiFluidEmitterExtra();
+
+ virtual void initParams();
+
+ Bitmap m_bitmap;
+
+ float m_animTime = 0.f;
+ bool m_animEnabled = false;
+
+ void animChanged();
+};
+
+struct SceneSDFTest : public SceneFluid
+{
+ SceneSDFTest() : SceneFluid("SDF Test") {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void initParams();
+
+ NvFlowSDFGen* m_sdfGen = nullptr;
+
+ MeshContext* m_meshContext = nullptr;
+ Mesh* m_mesh = nullptr;
+};
+
+struct ComputeContext;
+struct ComputeShader;
+struct ComputeConstantBuffer;
+struct ComputeResource;
+struct ComputeResourceRW;
+
+struct SceneCustomLighting : public SceneSDFTest
+{
+ SceneCustomLighting() { m_name = "Custom Lighting"; }
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void initParams();
+
+ float m_time = 0.f;
+
+ NvFlowGridImport* m_import = nullptr;
+
+ ComputeContext* m_computeContext = nullptr;
+ ComputeShader* m_computeShader = nullptr;
+ ComputeConstantBuffer* m_computeConstantBuffer = nullptr;
+ ComputeResource* m_exportBlockList = nullptr;
+ ComputeResource* m_exportBlockTable = nullptr;
+ ComputeResource* m_exportData = nullptr;
+ ComputeResource* m_importBlockList = nullptr;
+ ComputeResource* m_importBlockTable = nullptr;
+ ComputeResourceRW* m_importDataRW = nullptr;
+};
+
+struct SceneSimpleSmoke : public SceneFluid
+{
+ SceneSimpleSmoke() : SceneFluid("Simple Smoke") {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void imguiFluidEmitterExtra();
+ virtual void imguiFluidRenderExtra();
+
+ virtual void initParams();
+
+ NvFlowVolumeShadow* m_volumeShadow = nullptr;
+
+ bool m_animate = false;
+ bool m_animateOld = false;
+ float theta = 0.f;
+ float rate = 0.125f;
+ float coupleRateScale = 0.1f;
+
+ static NvFlowFloat3 positionFunc(float theta);
+ static NvFlowFloat3 velocityFunc(float theta, float rate);
+};
+
+struct SceneCustomEmit : public SceneFluid
+{
+ SceneCustomEmit() : SceneFluid("Custom Emit") {}
+
+ virtual void init(AppGraphCtx* context, int winw, int winh);
+ virtual void doUpdate(float dt);
+ virtual void preDraw();
+ virtual void draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view);
+ virtual void release();
+ virtual void imgui(int x, int y, int w, int h);
+
+ virtual void imguiFluidEmitterExtra();
+
+ virtual void initParams();
+
+ static void emitCustomAllocFunc(void* userdata, const NvFlowGridEmitCustomAllocParams* params);
+ static void emitCustomEmitVelocityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+ static void emitCustomEmitDensityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+
+ void doEmitCustomAllocFunc(const NvFlowGridEmitCustomAllocParams* params);
+ void doEmitCustomEmitVelocityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+ void doEmitCustomEmitDensityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params);
+
+ struct CustomEmitParams
+ {
+ NvFlowUint radius;
+ NvFlowFloat4 targetValue;
+ NvFlowFloat4 blendRate;
+ };
+
+ void doEmitCustomEmit(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params, const CustomEmitParams* customParams);
+
+ ComputeContext* m_customContext = nullptr;
+ ComputeShader* m_customEmitAllocCS = nullptr;
+ ComputeShader* m_customEmitEmitCS = nullptr;
+ ComputeShader* m_customEmitEmit2CS = nullptr;
+ ComputeConstantBuffer* m_customConstantBuffer = nullptr;
+
+ ComputeResourceRW* m_allocMask = nullptr;
+ ComputeResource* m_blockTable = nullptr;
+ ComputeResource* m_blockList = nullptr;
+ ComputeResourceRW* m_dataRW[2u] = { nullptr };
+
+ bool m_fullDomain = false;
+};
+
+Scene* getScene(int index);
+
+void pointsToImage(NvFlowFloat4* image, int imageDim, const CurvePoint* pts, int numPts);
+
+#endif \ No newline at end of file
diff --git a/demo/DemoApp/scene2DTextureEmitter.cpp b/demo/DemoApp/scene2DTextureEmitter.cpp
new file mode 100644
index 0000000..c2d3984
--- /dev/null
+++ b/demo/DemoApp/scene2DTextureEmitter.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace Preset0
+{
+#include "preset0.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+void Scene2DTextureEmitter::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ m_emitParams.bounds.x.x = 1.5f;
+ m_emitParams.bounds.y.y = 1.5f;
+ m_emitParams.bounds.z.z = 0.125f;
+ m_emitParams.velocityLinear.y = 0.f;
+ m_emitParams.fuel = 1.4f;
+ m_emitParams.smoke = 0.5f;
+
+ FILE* file = nullptr;
+ fopen_s(&file, "../../data/GeforceClaw.bmp", "rb");
+ if (file)
+ {
+ m_bitmap.read(file);
+ fclose(file);
+ }
+
+ // grid parameter overrides
+ m_flowGridActor.m_gridParams.gravity = NvFlowFloat3{ 0.f, -1.f, 0.f };
+ //m_flowGridActor.m_gridParams.combustion.buoyancyPerTemp = 2.f;
+ m_flowGridActor.m_materialParams.smokePerBurn = 4.f;
+ m_flowGridActor.m_materialParams.tempPerBurn = 8.f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.4f;
+}
+
+void Scene2DTextureEmitter::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ // more compute resources
+ NvFlowShapeSDFDesc shapeDesc;
+ //NvFlowShapeSDFDescDefaults(&shapeDesc);
+ shapeDesc.resolution.x = m_bitmap.width;
+ shapeDesc.resolution.y = m_bitmap.height;
+ shapeDesc.resolution.z = 1u;
+ m_shape = NvFlowCreateShapeSDF(m_flowContext.m_gridContext, &shapeDesc);
+
+ // generate SDF from bitmap
+ auto mappedData = NvFlowShapeSDFMap(m_shape, m_flowContext.m_gridContext);
+ if (mappedData.data)
+ {
+ NvFlowUint bmRowPitch = ((m_bitmap.bitsPerPixel * m_bitmap.width + 31) / 32) * 4;
+
+ for (NvFlowUint k = 0; k < mappedData.dim.z; k++)
+ for (NvFlowUint j = 0; j < mappedData.dim.y; j++)
+ for (NvFlowUint i = 0; i < mappedData.dim.x; i++)
+ {
+ float& val = mappedData.data[k * mappedData.depthPitch + j * mappedData.rowPitch + i];
+
+ float v = 0.5f;
+
+ NvFlowUint byteIdx = j * bmRowPitch + (i >> 3);
+ NvFlowUint mask = 128 >> (i & 7);
+
+ NvFlowUint inval = mask & m_bitmap.data[byteIdx];
+
+ if (inval)
+ {
+ v = -0.5f;
+ }
+
+ val = v;
+ }
+ NvFlowShapeSDFUnmap(m_shape, m_flowContext.m_gridContext);
+ }
+
+ animChanged();
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] =
+ {
+ {0.f, 0.f,0.f,0.f,0.f },
+ {0.05f,0.f,0.f,0.f,0.5f},
+ {0.6f,0.7f * 141.f / 255.f, 0.7f * 199.f / 255.f, 0.7f * 63.f / 255.f,0.8f},
+ {0.85f,0.9f * 141.f / 255.f, 0.9f * 199.f / 255.f, 0.9f * 63.f / 255.f,0.8f},
+ {1.f,1.5f * 141.f / 255.f, 1.5f * 199.f / 255.f, 1.5f * 63.f / 255.f,0.5f}
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+}
+
+void Scene2DTextureEmitter::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_animTime += dt;
+ if (m_animTime > 8.f) m_animTime = 0.f;
+
+ if (m_animEnabled)
+ {
+ if (m_animTime < 2.f)
+ {
+ m_emitParams.temperature = 0.f;
+ m_emitParams.smoke = 0.f;
+ m_emitParams.fuel = 1.4f;
+ m_emitParams.velocityLinear.y = 1.f;
+ }
+ else if (m_animTime < 2.25f)
+ {
+ m_emitParams.temperature = 5.f;
+ m_emitParams.smoke = 0.5f;
+ m_emitParams.velocityLinear.y = 8.f;
+ }
+ else if (m_animTime < 2.5f)
+ {
+ m_emitParams.temperature = 0.f;
+ m_emitParams.fuel = 0.f;
+ m_emitParams.smoke = 0.f;
+ m_emitParams.velocityLinear.y = 0.f;
+ }
+ }
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sdf.sdfOffset = 0u; // m_shape;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSDF;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ NvFlowShapeSDF* sdfs[] = { m_shape };
+ NvFlowGridUpdateEmitSDFs(m_flowGridActor.m_grid, sdfs, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void Scene2DTextureEmitter::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void Scene2DTextureEmitter::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void Scene2DTextureEmitter::release()
+{
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ NvFlowReleaseShapeSDF(m_shape);
+
+ m_flowContext.release();
+}
+
+void Scene2DTextureEmitter::animChanged()
+{
+ if (!m_animEnabled)
+ {
+ m_emitParams.temperature = 1.f;
+ m_emitParams.smoke = 0.5f;
+ m_emitParams.fuel = 1.2f;
+ m_emitParams.velocityLinear.y = -1.f;
+ }
+ else
+ {
+ m_animTime = 0.f;
+ }
+}
+
+void Scene2DTextureEmitter::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+
+ imguiLabel("Effect");
+
+ if (imguiserCheck("Pulsed", m_animEnabled, true))
+ {
+ m_animEnabled = !m_animEnabled;
+ animChanged();
+ }
+} \ No newline at end of file
diff --git a/demo/DemoApp/sceneCustomEmit.cpp b/demo/DemoApp/sceneCustomEmit.cpp
new file mode 100644
index 0000000..c52db59
--- /dev/null
+++ b/demo/DemoApp/sceneCustomEmit.cpp
@@ -0,0 +1,435 @@
+/*
+* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace PresetFlame
+{
+#include "presetFlame.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+#include "computeContext.h"
+
+namespace
+{
+ // Need BYTE defined for shader bytecode
+ typedef unsigned char BYTE;
+ #include "customEmitAllocCS.hlsl.h"
+ #include "customEmitEmitCS.hlsl.h"
+ #include "customEmitEmit2CS.hlsl.h"
+}
+
+void SceneCustomEmit::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ // grid parameter overrides
+ m_flowGridActor.m_gridParams.gravity = NvFlowFloat3{ 0.f, -1.f, 0.f };
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneCustomEmit::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] = {
+ { 0.f, 0.f,0.f,0.f,0.f },
+ { 0.05f, 0.f,0.f,0.f,0.5f },
+ { 0.6f, 213.f / 255.f,100.f / 255.f,30.f / 255.f,0.8f },
+ { 0.85f, 255.f / 255.f,240.f / 255.f,0.f,0.8f },
+ { 1.f, 1.f,1.f,1.f,0.7f }
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+
+ // create app compute resources
+ {
+ m_customContext = ComputeContextNvFlowContextCreate(m_flowContext.m_gridContext);
+
+ ComputeShaderDesc shaderDesc = {};
+ shaderDesc.cs = g_customEmitAllocCS;
+ shaderDesc.cs_length = sizeof(g_customEmitAllocCS);
+ m_customEmitAllocCS = ComputeShaderCreate(m_customContext, &shaderDesc);
+
+ shaderDesc.cs = g_customEmitEmitCS;
+ shaderDesc.cs_length = sizeof(g_customEmitEmitCS);
+ m_customEmitEmitCS = ComputeShaderCreate(m_customContext, &shaderDesc);
+
+ shaderDesc.cs = g_customEmitEmit2CS;
+ shaderDesc.cs_length = sizeof(g_customEmitEmit2CS);
+ m_customEmitEmit2CS = ComputeShaderCreate(m_customContext, &shaderDesc);
+
+ ComputeConstantBufferDesc cbDesc = {};
+ cbDesc.sizeInBytes = 1024 * sizeof(float);
+ m_customConstantBuffer = ComputeConstantBufferCreate(m_customContext, &cbDesc);
+ }
+
+ // register callbacks
+ {
+ NvFlowGridEmitCustomRegisterAllocFunc(m_flowGridActor.m_grid, emitCustomAllocFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelVelocity, emitCustomEmitVelocityFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelDensity, emitCustomEmitDensityFunc, this);
+ }
+}
+
+void SceneCustomEmit::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ ComputeContextNvFlowContextUpdate(m_customContext, m_flowContext.m_gridContext);
+
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ // Disable traditional emitters here
+ //NvFlowGridEmit(m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+namespace
+{
+ void updateResource(ComputeResource*& computeResource, NvFlowResource* flowResource, ComputeContext* customContext, NvFlowContext* flowContext)
+ {
+ if (computeResource) {
+ ComputeResourceNvFlowUpdate(customContext, computeResource, flowContext, flowResource);
+ }
+ else {
+ computeResource = ComputeResourceNvFlowCreate(customContext, flowContext, flowResource);
+ }
+ }
+ void updateResourceRW(ComputeResourceRW*& computeResourceRW, NvFlowResourceRW* flowResourceRW, ComputeContext* customContext, NvFlowContext* flowContext)
+ {
+ if (computeResourceRW) {
+ ComputeResourceRWNvFlowUpdate(customContext, computeResourceRW, flowContext, flowResourceRW);
+ }
+ else {
+ computeResourceRW = ComputeResourceRWNvFlowCreate(customContext, flowContext, flowResourceRW);
+ }
+ }
+}
+
+void SceneCustomEmit::doEmitCustomAllocFunc(const NvFlowGridEmitCustomAllocParams* params)
+{
+ updateResourceRW(m_allocMask, params->maskResourceRW, m_customContext, m_flowContext.m_renderContext);
+
+ struct ShaderParams
+ {
+ NvFlowUint4 minMaskIdx;
+ NvFlowUint4 maxMaskIdx;
+ };
+
+ NvFlowDim maskDim = params->maskDim;
+
+ NvFlowUint radius = 1u;
+
+ NvFlowUint4 minMaskIdx, maxMaskIdx;
+
+ minMaskIdx.x = maskDim.x / 2 - radius;
+ minMaskIdx.y = maskDim.y / 2 - radius;
+ minMaskIdx.z = maskDim.z / 2 - radius;
+ minMaskIdx.w = 0u;
+
+ maxMaskIdx.x = maskDim.x / 2 + radius + 1;
+ maxMaskIdx.y = maskDim.y / 2 + radius + 1;
+ maxMaskIdx.z = maskDim.z / 2 + radius + 1;
+ maxMaskIdx.w = 0u;
+
+ auto mapped = (ShaderParams*)ComputeConstantBufferMap(m_customContext, m_customConstantBuffer);
+
+ mapped->minMaskIdx = minMaskIdx;
+ mapped->maxMaskIdx = maxMaskIdx;
+
+ ComputeConstantBufferUnmap(m_customContext, m_customConstantBuffer);
+
+ ComputeDispatchParams dparams = {};
+ dparams.shader = m_customEmitAllocCS;
+ dparams.constantBuffer = m_customConstantBuffer;
+ dparams.gridDim[0] = (maxMaskIdx.x - minMaskIdx.x + 7) / 8;
+ dparams.gridDim[1] = (maxMaskIdx.y - minMaskIdx.y + 7) / 8;
+ dparams.gridDim[2] = (maxMaskIdx.z - minMaskIdx.z + 7) / 8;
+ dparams.resourcesRW[0] = m_allocMask;
+
+ ComputeContextDispatch(m_customContext, &dparams);
+}
+
+void SceneCustomEmit::doEmitCustomEmit(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* layeredParams, const CustomEmitParams* customParams)
+{
+ // for each layer
+ for (NvFlowUint layerIdx = 0u; layerIdx < layeredParams->numLayers; layerIdx++)
+ {
+ NvFlowGridEmitCustomEmitLayerParams paramsInst = {};
+ NvFlowGridEmitCustomGetLayerParams(layeredParams, 0u, &paramsInst);
+ auto params = &paramsInst;
+
+ updateResource(m_blockTable, params->blockTable, m_customContext, m_flowContext.m_renderContext);
+ updateResource(m_blockList, params->blockList, m_customContext, m_flowContext.m_renderContext);
+ updateResourceRW(m_dataRW[0u], params->dataRW[0u], m_customContext, m_flowContext.m_renderContext);
+ updateResourceRW(m_dataRW[1u], params->dataRW[1u], m_customContext, m_flowContext.m_renderContext);
+
+ struct ShaderParams
+ {
+ NvFlowShaderPointParams customEmitParams;
+
+ NvFlowUint4 minVidx;
+ NvFlowUint4 maxVidx;
+ NvFlowFloat4 targetValue;
+ NvFlowFloat4 blendRate;
+ };
+
+ const auto& gridDim = params->shaderParams.gridDim;
+ const auto& blockDim = params->shaderParams.blockDim;
+
+ NvFlowUint4 vdim;
+ vdim.x = gridDim.x * blockDim.x;
+ vdim.y = gridDim.y * blockDim.y;
+ vdim.z = gridDim.z * blockDim.z;
+ vdim.w = 1u;
+
+ const NvFlowUint radius = customParams->radius;
+
+ NvFlowUint4 minVidx, maxVidx;
+
+ minVidx.x = vdim.x / 2 - radius;
+ minVidx.y = vdim.y / 2 - radius;
+ minVidx.z = vdim.z / 2 - radius;
+ minVidx.w = 0u;
+
+ maxVidx.x = vdim.x / 2 + radius + 1;
+ maxVidx.y = vdim.y / 2 + radius + 1;
+ maxVidx.z = vdim.z / 2 + radius + 1;
+ maxVidx.w = 0u;
+
+ auto mapped = (ShaderParams*)ComputeConstantBufferMap(m_customContext, m_customConstantBuffer);
+
+ mapped->customEmitParams = params->shaderParams;
+
+ mapped->minVidx = minVidx;
+ mapped->maxVidx = maxVidx;
+ mapped->targetValue = customParams->targetValue;
+ mapped->blendRate = customParams->blendRate;
+
+ ComputeConstantBufferUnmap(m_customContext, m_customConstantBuffer);
+
+ if (m_fullDomain)
+ {
+ ComputeDispatchParams dparams = {};
+ dparams.shader = m_customEmitEmit2CS;
+ dparams.constantBuffer = m_customConstantBuffer;
+ dparams.gridDim[0] = (params->numBlocks * params->shaderParams.blockDim.x + 7) / 8;
+ dparams.gridDim[1] = (params->shaderParams.blockDim.y + 7) / 8;
+ dparams.gridDim[2] = (params->shaderParams.blockDim.z + 7) / 8;
+ dparams.resources[0] = m_blockList;
+ dparams.resources[1] = m_blockTable;
+
+ NvFlowUint localDataFrontIdx = *dataFrontIdx;
+ // single pass
+ {
+ dparams.resources[2] = ComputeResourceRWGetResource(m_dataRW[localDataFrontIdx]);
+ dparams.resourcesRW[0] = m_dataRW[localDataFrontIdx ^ 1u];
+ ComputeContextDispatch(m_customContext, &dparams);
+ localDataFrontIdx = localDataFrontIdx ^ 1u;
+ }
+ }
+ else
+ {
+ ComputeDispatchParams dparams = {};
+ dparams.shader = m_customEmitEmitCS;
+ dparams.constantBuffer = m_customConstantBuffer;
+ dparams.gridDim[0] = (maxVidx.x - minVidx.x + 7) / 8;
+ dparams.gridDim[1] = (maxVidx.y - minVidx.y + 7) / 8;
+ dparams.gridDim[2] = (maxVidx.z - minVidx.z + 7) / 8;
+ dparams.resources[0] = m_blockList;
+ dparams.resources[1] = m_blockTable;
+
+ NvFlowUint localDataFrontIdx = *dataFrontIdx;
+ // doing this twice allow the write to be incomplete
+ for (int i = 0; i < 2; i++)
+ {
+ dparams.resources[2] = ComputeResourceRWGetResource(m_dataRW[localDataFrontIdx]);
+ dparams.resourcesRW[0] = m_dataRW[localDataFrontIdx ^ 1u];
+ ComputeContextDispatch(m_customContext, &dparams);
+ localDataFrontIdx = localDataFrontIdx ^ 1u;
+ }
+ }
+ }
+ // dataFrontIdx must be uniform across layers
+ if (m_fullDomain)
+ {
+ (*dataFrontIdx) = (*dataFrontIdx) ^ 1u;
+ }
+ else
+ {
+ (*dataFrontIdx) = (*dataFrontIdx) ^ 1u;
+ (*dataFrontIdx) = (*dataFrontIdx) ^ 1u;
+ }
+}
+
+void SceneCustomEmit::doEmitCustomEmitVelocityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ CustomEmitParams customParams = {};
+ customParams.radius = 4u;
+ customParams.targetValue = { 0.f, 1.f, 0.f, 0.f };
+ customParams.blendRate = { 0.01f, 0.01f, 0.01f, 0.01f };
+
+ doEmitCustomEmit(dataFrontIdx, params, &customParams);
+}
+
+void SceneCustomEmit::doEmitCustomEmitDensityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ CustomEmitParams customParams = {};
+ customParams.radius = 8u;
+ customParams.targetValue = { 1.f, 1.f, 0.f, 1.f };
+ customParams.blendRate = { 0.01f, 0.01f, 0.01f, 0.01f };
+
+ doEmitCustomEmit(dataFrontIdx, params, &customParams);
+}
+
+void SceneCustomEmit::emitCustomAllocFunc(void* userdata, const NvFlowGridEmitCustomAllocParams* params)
+{
+ ((SceneCustomEmit*)(userdata))->doEmitCustomAllocFunc(params);
+}
+
+void SceneCustomEmit::emitCustomEmitVelocityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneCustomEmit*)(userdata))->doEmitCustomEmitVelocityFunc(dataFrontIdx, params);
+}
+
+void SceneCustomEmit::emitCustomEmitDensityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneCustomEmit*)(userdata))->doEmitCustomEmitDensityFunc(dataFrontIdx, params);
+}
+
+void SceneCustomEmit::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneCustomEmit::imguiFluidEmitterExtra()
+{
+ if (imguiserCheck("Full Domain", m_fullDomain, true))
+ {
+ m_fullDomain = !m_fullDomain;
+ }
+}
+
+void SceneCustomEmit::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneCustomEmit::release()
+{
+ // release app compute resources
+ {
+ ComputeConstantBufferRelease(m_customConstantBuffer);
+
+ ComputeShaderRelease(m_customEmitAllocCS);
+ ComputeShaderRelease(m_customEmitEmitCS);
+ ComputeShaderRelease(m_customEmitEmit2CS);
+
+ ComputeContextRelease(m_customContext);
+
+ if (m_allocMask) ComputeResourceRWRelease(m_allocMask);
+ if (m_blockTable) ComputeResourceRelease(m_blockTable);
+ if (m_blockList) ComputeResourceRelease(m_blockList);
+ if (m_dataRW[0]) ComputeResourceRWRelease(m_dataRW[0u]);
+ if (m_dataRW[1]) ComputeResourceRWRelease(m_dataRW[1u]);
+
+ m_allocMask = nullptr;
+ m_blockTable = nullptr;
+ m_blockList = nullptr;
+ m_dataRW[0] = nullptr;
+ m_dataRW[1] = nullptr;
+ }
+
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ m_flowContext.release();
+}
+
+void SceneCustomEmit::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(PresetFlame::g_root, sizeof(PresetFlame::g_root));
+ m_shouldLoadPreset = false;
+ }
+} \ No newline at end of file
diff --git a/demo/DemoApp/sceneFlow.cpp b/demo/DemoApp/sceneFlow.cpp
new file mode 100644
index 0000000..80f87b1
--- /dev/null
+++ b/demo/DemoApp/sceneFlow.cpp
@@ -0,0 +1,822 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "scene.h"
+
+#include "imgui.h"
+#include "imguiser.h"
+
+// ******************** FlowContext ************************
+
+void FlowContext::init(AppGraphCtx* appctx)
+{
+ m_appctx = appctx;
+
+ m_renderContext = NvFlowInteropCreateContext(appctx);
+ m_dsv = NvFlowInteropCreateDepthStencilView(appctx, m_renderContext);
+ m_rtv = NvFlowInteropCreateRenderTargetView(appctx, m_renderContext);
+
+ // establishes m_gridContext
+ createComputeContext();
+}
+
+void FlowContext::createComputeContext()
+{
+ m_multiGPUSupported = NvFlowDedicatedDeviceAvailable(m_renderContext);
+ m_multiGPUActive = m_multiGPUSupported && m_enableMultiGPU;
+ if (m_multiGPUActive)
+ {
+ NvFlowDeviceDesc deviceDesc = {};
+ NvFlowDeviceDescDefaults(&deviceDesc);
+
+ deviceDesc.mode = eNvFlowDeviceModeProxy;
+ m_renderDevice = NvFlowCreateDevice(m_renderContext, &deviceDesc);
+ deviceDesc.mode = eNvFlowDeviceModeUnique;
+ m_gridDevice = NvFlowCreateDevice(m_renderContext, &deviceDesc);
+
+ NvFlowDeviceQueueDesc deviceQueueDesc = {};
+ deviceQueueDesc.queueType = eNvFlowDeviceQueueTypeGraphics;
+ deviceQueueDesc.lowLatency = false;
+ m_gridQueue = NvFlowCreateDeviceQueue(m_gridDevice, &deviceQueueDesc);
+ deviceQueueDesc.queueType = eNvFlowDeviceQueueTypeCopy;
+ m_gridCopyQueue = NvFlowCreateDeviceQueue(m_gridDevice, &deviceQueueDesc);
+ m_renderCopyQueue = NvFlowCreateDeviceQueue(m_renderDevice, &deviceQueueDesc);
+
+ m_gridContext = NvFlowDeviceQueueCreateContext(m_gridQueue);
+ m_gridCopyContext = NvFlowDeviceQueueCreateContext(m_gridCopyQueue);
+ m_renderCopyContext = NvFlowDeviceQueueCreateContext(m_renderCopyQueue);
+
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ }
+ else
+ {
+ m_commandQueueSupported = NvFlowDedicatedDeviceQueueAvailable(m_renderContext);
+ m_commandQueueActive = m_commandQueueSupported && m_enableCommandQueue;
+ if (m_commandQueueActive)
+ {
+ NvFlowDeviceDesc deviceDesc = {};
+ NvFlowDeviceDescDefaults(&deviceDesc);
+
+ deviceDesc.mode = eNvFlowDeviceModeProxy;
+ m_renderDevice = NvFlowCreateDevice(m_renderContext, &deviceDesc);
+ m_gridDevice = m_renderDevice;
+
+ NvFlowDeviceQueueDesc deviceQueueDesc = {};
+ deviceQueueDesc.queueType = eNvFlowDeviceQueueTypeCompute;
+ deviceQueueDesc.lowLatency = true;
+ m_gridQueue = NvFlowCreateDeviceQueue(m_gridDevice, &deviceQueueDesc);
+ deviceQueueDesc.queueType = eNvFlowDeviceQueueTypeCopy;
+ m_gridCopyQueue = NvFlowCreateDeviceQueue(m_gridDevice, &deviceQueueDesc);
+ m_renderCopyQueue = m_gridCopyQueue;
+
+ m_gridContext = NvFlowDeviceQueueCreateContext(m_gridQueue);
+ m_gridCopyContext = NvFlowDeviceQueueCreateContext(m_gridCopyQueue);
+ m_renderCopyContext = m_gridCopyContext;
+
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ }
+ else
+ {
+ m_gridContext = m_renderContext;
+ m_gridCopyContext = m_renderContext;
+ m_renderCopyContext = m_renderContext;
+ }
+ }
+}
+
+void FlowContext::release()
+{
+ NvFlowReleaseRenderTargetView(m_rtv);
+ NvFlowReleaseDepthStencilView(m_dsv);
+ NvFlowReleaseContext(m_renderContext);
+
+ releaseComputeContext();
+}
+
+void FlowContext::releaseComputeContext()
+{
+ if (m_gridDevice != m_renderDevice)
+ {
+ NvFlowReleaseContext(m_gridContext);
+ NvFlowReleaseContext(m_gridCopyContext);
+ NvFlowReleaseContext(m_renderCopyContext);
+ m_gridContext = nullptr;
+ m_gridCopyContext = nullptr;
+ m_renderCopyContext = nullptr;
+
+ NvFlowReleaseDeviceQueue(m_gridQueue);
+ NvFlowReleaseDeviceQueue(m_gridCopyQueue);
+ NvFlowReleaseDeviceQueue(m_renderCopyQueue);
+ m_gridQueue = nullptr;
+ m_gridCopyQueue = nullptr;
+ m_renderCopyQueue = nullptr;
+
+ NvFlowReleaseDevice(m_gridDevice);
+ NvFlowReleaseDevice(m_renderDevice);
+ m_gridDevice = nullptr;
+ m_renderDevice = nullptr;
+ }
+ else if (m_gridContext != m_renderContext)
+ {
+ NvFlowReleaseContext(m_gridContext);
+ NvFlowReleaseContext(m_gridCopyContext);
+ m_gridContext = nullptr;
+ m_gridCopyContext = nullptr;
+ m_renderCopyContext = nullptr;
+
+ NvFlowReleaseDeviceQueue(m_gridQueue);
+ NvFlowReleaseDeviceQueue(m_gridCopyQueue);
+ m_gridQueue = nullptr;
+ m_gridCopyQueue = nullptr;
+ m_renderCopyQueue = nullptr;
+
+ NvFlowReleaseDevice(m_gridDevice);
+ m_gridDevice = nullptr;
+ m_renderDevice = nullptr;
+ }
+ else
+ {
+ m_gridContext = nullptr;
+ m_gridCopyContext = nullptr;
+ m_renderCopyContext = nullptr;
+
+ m_gridQueue = nullptr;
+ m_gridCopyQueue = nullptr;
+ m_renderCopyQueue = nullptr;
+
+ m_gridDevice = nullptr;
+ m_renderDevice = nullptr;
+ }
+}
+
+int FlowContext::computeContextBegin()
+{
+ int framesInFlight = 0u;
+ if (m_gridDevice != m_renderDevice)
+ {
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ framesInFlight = status.framesInFlight;
+
+ NvFlowDeviceQueueUpdateContext(m_gridCopyQueue, m_gridCopyContext, &status);
+ NvFlowDeviceQueueUpdateContext(m_renderCopyQueue, m_renderCopyContext, &status);
+ }
+ else if (m_gridContext != m_renderContext)
+ {
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ framesInFlight = status.framesInFlight;
+
+ NvFlowDeviceQueueUpdateContext(m_gridCopyQueue, m_gridCopyContext, &status);
+ }
+ else
+ {
+ NvFlowInteropUpdateContext(m_renderContext, m_appctx);
+ NvFlowContextPush(m_gridContext);
+ }
+ return framesInFlight;
+}
+
+void FlowContext::computeContextEnd()
+{
+ if (m_gridDevice != m_renderDevice)
+ {
+ NvFlowDeviceQueueConditionalFlush(m_gridQueue, m_gridContext);
+ NvFlowDeviceQueueConditionalFlush(m_gridCopyQueue, m_gridCopyContext);
+ NvFlowDeviceQueueConditionalFlush(m_renderCopyQueue, m_renderCopyContext);
+ }
+ else if (m_gridContext != m_renderContext)
+ {
+ NvFlowDeviceQueueConditionalFlush(m_gridQueue, m_gridContext);
+ NvFlowDeviceQueueConditionalFlush(m_gridCopyQueue, m_gridCopyContext);
+ }
+ else
+ {
+ NvFlowContextPop(m_gridContext);
+ }
+}
+
+bool FlowContext::updateBegin()
+{
+ m_framesInFlight = computeContextBegin();
+ bool shouldFlush = (m_framesInFlight < m_maxFramesInFlight);
+
+ if (shouldFlush)
+ {
+ NvFlowContextFlushRequestPush(m_gridContext);
+ NvFlowContextFlushRequestPush(m_gridCopyContext);
+ NvFlowContextFlushRequestPush(m_renderCopyContext);
+ }
+
+ return shouldFlush;
+}
+
+void FlowContext::updateEnd()
+{
+ computeContextEnd();
+}
+
+void FlowContext::preDrawBegin()
+{
+ if (m_gridDevice != m_renderDevice)
+ {
+ // update fence status on grid queue, no need to flush
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ NvFlowDeviceQueueUpdateContext(m_gridCopyQueue, m_gridCopyContext, &status);
+ NvFlowDeviceQueueUpdateContext(m_renderCopyQueue, m_renderCopyContext, &status);
+ }
+ else if (m_gridContext != m_renderContext)
+ {
+ // update fence status on grid queue, no need to flush
+ NvFlowDeviceQueueStatus status = {};
+ NvFlowDeviceQueueUpdateContext(m_gridQueue, m_gridContext, &status);
+ NvFlowDeviceQueueUpdateContext(m_gridCopyQueue, m_gridCopyContext, &status);
+ }
+
+ NvFlowInteropUpdateContext(m_renderContext, m_appctx);
+ NvFlowContextPush(m_renderContext);
+}
+
+void FlowContext::preDrawEnd()
+{
+ NvFlowContextPop(m_renderContext);
+
+ // This will make gridProxy flush work
+ if (m_gridDevice != m_renderDevice)
+ {
+ //NvFlowDeviceQueueFlush(m_gridQueue, m_gridContext);
+ NvFlowDeviceQueueConditionalFlush(m_gridCopyQueue, m_gridCopyContext);
+ NvFlowDeviceQueueConditionalFlush(m_renderCopyQueue, m_renderCopyContext);
+ }
+ else if (m_gridContext != m_renderContext)
+ {
+ //NvFlowDeviceQueueFlush(m_gridQueue, m_gridContext);
+ NvFlowDeviceQueueConditionalFlush(m_gridCopyQueue, m_gridCopyContext);
+ }
+}
+
+void FlowContext::drawBegin()
+{
+ NvFlowInteropUpdateContext(m_renderContext, m_appctx);
+ NvFlowInteropUpdateDepthStencilView(m_dsv, m_appctx, m_renderContext);
+ NvFlowInteropUpdateRenderTargetView(m_rtv, m_appctx, m_renderContext);
+ NvFlowContextPush(m_renderContext);
+}
+
+void FlowContext::drawEnd()
+{
+ NvFlowContextPop(m_renderContext);
+}
+
+// ******************* FlowGridActor *************************
+
+void FlowGridActor::initParams(size_t vramAmount)
+{
+ NvFlowGridDescDefaults(&m_gridDesc);
+ NvFlowGridParamsDefaults(&m_gridParams);
+ NvFlowGridMaterialParamsDefaults(&m_materialParams);
+ NvFlowRenderMaterialParamsDefaults(&m_renderMaterialDefaultParams);
+ NvFlowRenderMaterialParamsDefaults(&m_renderMaterialMat0Params);
+ NvFlowRenderMaterialParamsDefaults(&m_renderMaterialMat1Params);
+ NvFlowVolumeRenderParamsDefaults(&m_renderParams);
+ NvFlowCrossSectionParamsDefaults(&m_crossSectionParams);
+
+ m_renderMaterialMat0Params.material = NvFlowGridMaterialHandle{ nullptr, 1u };
+ m_renderMaterialMat1Params.material = NvFlowGridMaterialHandle{ nullptr, 1u };
+
+ // default VTR off on debug build
+ #ifdef _DEBUG
+ m_gridDesc.enableVTR = false;
+ #endif
+
+ // attempt to pick good memory limits based on vramAmount
+ {
+ if (vramAmount <= 2ull * 1024ull * 1024ull * 1024ull)
+ {
+ m_memoryLimit = 1.f;
+ }
+ else if (vramAmount <= 3ull * 1024ull * 1024ull * 1024ull)
+ {
+ m_memoryLimit = 2.f;
+ }
+ }
+
+ m_gridDesc.residentScale = m_memoryLimit * m_memoryScale;
+
+ // configure gravity
+ m_gridParams.gravity = NvFlowFloat3{ 0.f, -1.f, 0.f };
+}
+
+void FlowGridActor::init(FlowContext* flowContext, AppGraphCtx* appctx)
+{
+ m_appctx = appctx;
+
+ // create compute resources
+ m_grid = NvFlowCreateGrid(flowContext->m_gridContext, &m_gridDesc);
+
+ auto proxyGridExport = NvFlowGridGetGridExport(flowContext->m_gridContext, m_grid);
+
+ NvFlowGridProxyDesc proxyDesc = {};
+ proxyDesc.gridContext = flowContext->m_gridContext;
+ proxyDesc.renderContext = flowContext->m_renderContext;
+ proxyDesc.gridCopyContext = flowContext->m_gridCopyContext;
+ proxyDesc.renderCopyContext = flowContext->m_renderCopyContext;
+ proxyDesc.gridExport = proxyGridExport;
+ proxyDesc.proxyType = eNvFlowGridProxyTypePassThrough;
+ if (flowContext->m_multiGPUActive)
+ {
+ proxyDesc.proxyType = eNvFlowGridProxyTypeMultiGPU;
+ }
+ else if (flowContext->m_commandQueueActive)
+ {
+ proxyDesc.proxyType = eNvFlowGridProxyTypeInterQueue;
+ }
+
+ m_gridProxy = NvFlowCreateGridProxy(&proxyDesc);
+
+ auto gridExport = NvFlowGridProxyGetGridExport(m_gridProxy, flowContext->m_renderContext);
+
+ // create render resources
+ NvFlowVolumeRenderDesc volumeRenderDesc;
+ volumeRenderDesc.gridExport = gridExport;
+
+ m_volumeRender = NvFlowCreateVolumeRender(flowContext->m_renderContext, &volumeRenderDesc);
+
+ NvFlowCrossSectionDesc crossSectionDesc = {};
+ crossSectionDesc.gridExport = gridExport;
+
+ m_crossSection = NvFlowCreateCrossSection(flowContext->m_renderContext, &crossSectionDesc);
+
+ NvFlowRenderMaterialPoolDesc materialPoolDesc = {};
+ materialPoolDesc.colorMapResolution = 64u;
+ m_colorMap.m_materialPool = NvFlowCreateRenderMaterialPool(flowContext->m_renderContext, &materialPoolDesc);
+
+ NvFlowRenderMaterialParams materialParams = {};
+ NvFlowRenderMaterialParamsDefaults(&materialParams);
+ m_colorMap.m_materialDefault = NvFlowGetDefaultRenderMaterial(m_colorMap.m_materialPool);
+
+ // set invalid by default for mat0 and mat1
+ materialParams.material = NvFlowGridMaterialHandle{ nullptr, 1u };
+ m_colorMap.m_material0 = NvFlowCreateRenderMaterial(flowContext->m_renderContext, m_colorMap.m_materialPool, &materialParams);
+ m_colorMap.m_material1 = NvFlowCreateRenderMaterial(flowContext->m_renderContext, m_colorMap.m_materialPool, &materialParams);
+
+ m_renderParams.materialPool = m_colorMap.m_materialPool;
+
+ if (m_enableVolumeShadow)
+ {
+ NvFlowVolumeShadowDesc volumeShadowDesc = {};
+ volumeShadowDesc.gridExport = gridExport;
+ volumeShadowDesc.mapWidth = 4 * 256u;
+ volumeShadowDesc.mapHeight = 4 * 256u;
+ volumeShadowDesc.mapDepth = 4 * 256u;
+
+ volumeShadowDesc.minResidentScale = 0.25f * (1.f / 64.f);
+ volumeShadowDesc.maxResidentScale = m_shadowResidentScale * 4.f * 0.25f * (1.f / 64.f);
+
+ m_volumeShadow = NvFlowCreateVolumeShadow(flowContext->m_renderContext, &volumeShadowDesc);
+ }
+}
+
+void FlowGridActor::release()
+{
+ NvFlowReleaseGrid(m_grid);
+ NvFlowReleaseGridProxy(m_gridProxy);
+ NvFlowReleaseVolumeRender(m_volumeRender);
+ NvFlowReleaseCrossSection(m_crossSection);
+ NvFlowReleaseRenderMaterialPool(m_colorMap.m_materialPool);
+ if (m_volumeShadow) NvFlowReleaseVolumeShadow(m_volumeShadow);
+ m_volumeShadow = nullptr;
+}
+
+void FlowGridActor::updatePreEmit(FlowContext* flowContext, float dt)
+{
+ NvFlowGridSetParams(m_grid, &m_gridParams);
+ NvFlowGridSetMaterialParams(m_grid, NvFlowGridGetDefaultMaterial(m_grid), &m_materialParams);
+ NvFlowRenderMaterialUpdate(m_colorMap.m_materialDefault, &m_renderMaterialDefaultParams);
+ NvFlowRenderMaterialUpdate(m_colorMap.m_material0, &m_renderMaterialMat0Params);
+ NvFlowRenderMaterialUpdate(m_colorMap.m_material1, &m_renderMaterialMat1Params);
+}
+
+void FlowGridActor::updatePostEmit(FlowContext* flowContext, float dt, bool shouldUpdate, bool shouldReset)
+{
+ if (shouldReset)
+ {
+ NvFlowGridResetDesc resetDesc = {};
+ NvFlowGridResetDescDefaults(&resetDesc);
+
+ resetDesc.initialLocation = m_gridDesc.initialLocation;
+ resetDesc.halfSize = m_gridDesc.halfSize;
+
+ float scale = powf(1.26f, float(m_cellSizeLogScale)) * m_cellSizeScale;
+ resetDesc.halfSize.x *= scale;
+ resetDesc.halfSize.y *= scale;
+ resetDesc.halfSize.z *= scale;
+
+ NvFlowGridReset(m_grid, &resetDesc);
+ }
+
+ if (shouldUpdate)
+ {
+ NvFlowGridUpdate(m_grid, flowContext->m_gridContext, dt);
+
+ // collect stats
+ if (m_grid)
+ {
+ auto gridExport = NvFlowGridGetGridExport(flowContext->m_gridContext, m_grid);
+
+ // grab for debug vis use
+ if (flowContext->m_gridContext == flowContext->m_renderContext)
+ {
+ m_gridExportDebugVis = gridExport;
+ }
+ else
+ {
+ m_gridExportDebugVis = nullptr;
+ }
+
+ if (gridExport)
+ {
+ NvFlowUint* numBlockss[2] = { &m_statNumVelocityBlocks , &m_statNumDensityBlocks };
+ NvFlowUint* numCellss[2] = { &m_statNumVelocityCells , &m_statNumDensityCells };
+ NvFlowUint* maxBlockss[2] = { &m_statMaxVelocityBlocks , &m_statMaxDensityBlocks };
+ NvFlowGridTextureChannel channels[2] = { eNvFlowGridTextureChannelVelocity, eNvFlowGridTextureChannelDensity };
+ for (NvFlowUint passID = 0u; passID < 2; passID++)
+ {
+ NvFlowUint& numBlocks = *numBlockss[passID];
+ NvFlowUint& numCells = *numCellss[passID];
+ NvFlowUint& maxBlocks = *maxBlockss[passID];
+
+ auto handle = NvFlowGridExportGetHandle(gridExport, flowContext->m_gridContext, channels[passID]);
+
+ NvFlowGridExportLayeredView layeredView = {};
+ NvFlowGridExportGetLayeredView(handle, &layeredView);
+
+ m_statNumLayers = handle.numLayerViews;
+ numBlocks = 0u;
+ maxBlocks = layeredView.mapping.maxBlocks;
+
+ for (NvFlowUint layerIdx = 0u; layerIdx < handle.numLayerViews; layerIdx++)
+ {
+ NvFlowGridExportLayerView layerView = {};
+ NvFlowGridExportGetLayerView(handle, layerIdx, &layerView);
+
+ numBlocks += layerView.mapping.numBlocks;
+ }
+
+ numCells = layeredView.mapping.shaderParams.blockDim.w * numBlocks;
+ }
+ }
+ }
+
+ if (m_enableVolumeShadow && m_volumeShadow)
+ {
+ NvFlowVolumeShadowStats stats = {};
+ NvFlowVolumeShadowGetStats(m_volumeShadow, &stats);
+ m_statVolumeShadowBlocks = stats.shadowBlocksActive;
+ m_statVolumeShadowCells = stats.shadowCellsActive;
+ }
+ else
+ {
+ m_statVolumeShadowBlocks = 0u;
+ m_statVolumeShadowCells = 0u;
+ }
+
+ auto gridExport = NvFlowGridGetGridExport(flowContext->m_gridContext, m_grid);
+ NvFlowGridProxyFlushParams flushParams = {};
+ flushParams.gridContext = flowContext->m_gridContext;
+ flushParams.gridCopyContext = flowContext->m_gridCopyContext;
+ flushParams.renderCopyContext = flowContext->m_renderCopyContext;
+ NvFlowGridProxyPush(m_gridProxy, gridExport, &flushParams);
+ }
+}
+
+void FlowGridActor::preDraw(FlowContext* flowContext)
+{
+ //auto gridView = NvFlowGridGetGridView(m_grid, m_renderContext);
+
+ AppGraphCtxProfileBegin(m_appctx, "UpdateGridView");
+
+ NvFlowGridProxyFlushParams flushParams = {};
+ flushParams.gridContext = flowContext->m_gridContext;
+ flushParams.gridCopyContext = flowContext->m_gridCopyContext;
+ flushParams.renderCopyContext = flowContext->m_renderCopyContext;
+ NvFlowGridProxyFlush(m_gridProxy, &flushParams);
+
+ auto gridExport = NvFlowGridProxyGetGridExport(m_gridProxy, flowContext->m_renderContext);
+
+ AppGraphCtxProfileEnd(m_appctx, "UpdateGridView");
+
+ // replicate render params for override
+ m_renderParamsOverride = m_renderParams;
+
+ // shadow force apply
+ if (m_enableVolumeShadow && m_forceApplyShadow && !m_shadowWasForceApplied)
+ {
+ m_shadowWasForceApplied = true;
+ m_forceIntensityCompMask = m_renderMaterialDefaultParams.intensityCompMask;
+ m_forceIntensityBias = m_renderMaterialDefaultParams.intensityBias;
+ m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 1.f, 0.f };
+ m_renderMaterialDefaultParams.intensityBias = 0.f;
+ }
+ if ((!m_enableVolumeShadow || !m_forceApplyShadow) && m_shadowWasForceApplied)
+ {
+ m_renderMaterialDefaultParams.intensityCompMask = m_forceIntensityCompMask;
+ m_renderMaterialDefaultParams.intensityBias = m_forceIntensityBias;
+ m_shadowWasForceApplied = false;
+ }
+
+ // volume shadow
+ if (m_enableVolumeShadow)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "VolumeShadows");
+
+ NvFlowVolumeShadowParams shadowParams = {};
+
+ const float halfSize = 2.f * (0.5f * (7.5f - 5.f));
+ const float center = 0.5f * (7.5f + 5.f);
+
+ DirectX::XMMATRIX projMat = DirectX::XMMatrixPerspectiveFovLH(DirectX::XM_PI / 4.f, 1.f, center - halfSize, center + halfSize);
+ DirectX::XMMATRIX viewMat = DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixScaling(0.25f, 0.25f, 0.25f),
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixRotationRollPitchYaw(0.f, DirectX::XM_PI / 4.f * m_shadowPan, 0.f),
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixRotationRollPitchYaw(-DirectX::XM_PI / 4.f, 0.f, 0.f),
+ DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixRotationRollPitchYaw(0.f, DirectX::XM_PI / 4.f, 0.f),
+ DirectX::XMMatrixRotationAxis(DirectX::XMVectorSet(1.f, 1.f, 0.f, 1.f), -DirectX::XM_PI / 4.f * m_shadowTilt)
+ )
+ )
+ )
+ ),
+ DirectX::XMMatrixTranslation(0.f, 0.f, 7.f)
+ );
+
+ memcpy(&shadowParams.projectionMatrix, &projMat, sizeof(NvFlowFloat4x4));
+ memcpy(&shadowParams.viewMatrix, &viewMat, sizeof(NvFlowFloat4x4));
+
+ shadowParams.materialPool = m_renderParams.materialPool;
+ shadowParams.intensityScale = m_shadowIntensityScale;
+ shadowParams.minIntensity = m_shadowMinIntensity;
+ shadowParams.shadowBlendCompMask = m_shadowBlendCompMask;
+ shadowParams.shadowBlendBias = m_shadowBlendBias;
+
+ shadowParams.renderChannel = m_renderParams.renderChannel;
+ shadowParams.renderMode = eNvFlowVolumeRenderMode_colormap;
+
+ NvFlowVolumeShadowUpdate(m_volumeShadow, flowContext->m_renderContext, gridExport, &shadowParams);
+
+ gridExport = NvFlowVolumeShadowGetGridExport(m_volumeShadow, flowContext->m_renderContext);
+
+ AppGraphCtxProfileEnd(m_appctx, "VolumeShadows");
+ }
+
+ if (m_separateLighting)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Lighting");
+
+ NvFlowVolumeLightingParams lightingParams = {};
+ lightingParams.materialPool = m_renderParams.materialPool;
+ lightingParams.renderChannel = m_renderParams.renderChannel;
+ lightingParams.renderMode = m_renderParams.renderMode;
+
+ m_renderParamsOverride.renderMode = eNvFlowVolumeRenderMode_raw;
+
+ gridExport = NvFlowVolumeRenderLightGridExport(m_volumeRender, flowContext->m_renderContext, gridExport, &lightingParams);
+
+ AppGraphCtxProfileEnd(m_appctx, "Lighting");
+ }
+
+ m_gridExportOverride = gridExport;
+}
+
+void FlowGridActor::draw(FlowContext* flowContext, DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ memcpy(&m_renderParamsOverride.projectionMatrix, &projection, sizeof(m_renderParamsOverride.projectionMatrix));
+ memcpy(&m_renderParamsOverride.viewMatrix, &view, sizeof(m_renderParamsOverride.viewMatrix));
+ m_renderParamsOverride.depthStencilView = flowContext->m_dsv;
+ m_renderParamsOverride.renderTargetView = flowContext->m_rtv;
+
+ AppGraphCtxProfileBegin(m_appctx, "Render");
+
+ if (m_renderParams.generateDepth)
+ {
+ // ray march with target to composite against
+ {
+ auto renderParamsCopy = m_renderParamsOverride;
+
+ // invalidate renderTargetView since it is not required here
+ renderParamsCopy.renderTargetView = nullptr;
+
+ renderParamsCopy.preColorCompositeOnly = true;
+ renderParamsCopy.colorCompositeOnly = false;
+
+ NvFlowVolumeRenderGridExport(m_volumeRender, flowContext->m_renderContext, m_gridExportOverride, &renderParamsCopy);
+ }
+ // composite to target
+ {
+ auto renderParamsCopy = m_renderParamsOverride;
+
+ renderParamsCopy.preColorCompositeOnly = false;
+ renderParamsCopy.colorCompositeOnly = true;
+
+ NvFlowVolumeRenderGridExport(m_volumeRender, flowContext->m_renderContext, m_gridExportOverride, &renderParamsCopy);
+ }
+ }
+ else
+ {
+ NvFlowVolumeRenderGridExport(m_volumeRender, flowContext->m_renderContext, m_gridExportOverride, &m_renderParamsOverride);
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Render");
+
+ if (m_enableCrossSection)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "CrossSection");
+
+ if (flowContext->m_gridContext != flowContext->m_renderContext)
+ {
+ m_gridExportDebugVis = nullptr;
+ }
+
+ m_crossSectionParams.gridExport = m_gridExportOverride;
+ m_crossSectionParams.gridExportDebugVis = m_gridExportDebugVis;
+
+ // update parameters
+ memcpy(&m_crossSectionParams.projectionMatrix, &projection, sizeof(m_crossSectionParams.projectionMatrix));
+ memcpy(&m_crossSectionParams.viewMatrix, &view, sizeof(m_crossSectionParams.viewMatrix));
+ m_crossSectionParams.depthStencilView = flowContext->m_dsv;
+ m_crossSectionParams.renderTargetView = flowContext->m_rtv;
+
+ float scale = powf(1.26f, float(m_cellSizeLogScale)) * m_cellSizeScale;
+ m_crossSectionParams.crossSectionScale = scale * m_crossSectionScale;
+
+ int backgroundID = int(m_crossSectionBackgroundColor);
+ m_crossSectionParams.backgroundColor = { 0.f, 0.f, 0.f, 1.f };
+ if (backgroundID == 1) m_crossSectionParams.backgroundColor = { 0.33f, 0.33f, 0.33f, 1.f };
+
+ m_crossSectionParams.lineColor = { m_crossSectionLineColor.x, m_crossSectionLineColor.y, m_crossSectionLineColor.z, 1.f };
+
+ m_crossSectionParams.materialPool = m_renderParams.materialPool;
+
+ NvFlowCrossSectionRender(m_crossSection, flowContext->m_renderContext, &m_crossSectionParams);
+
+ AppGraphCtxProfileEnd(m_appctx, "CrossSection");
+ }
+
+ if (m_enableVolumeShadow && m_shadowDebugVis)
+ {
+ NvFlowVolumeShadowDebugRenderParams params = {};
+
+ params.renderTargetView = flowContext->m_rtv;
+
+ memcpy(&params.projectionMatrix, &projection, sizeof(NvFlowFloat4x4));
+ memcpy(&params.viewMatrix, &view, sizeof(NvFlowFloat4x4));
+
+ NvFlowVolumeShadowDebugRender(m_volumeShadow, flowContext->m_renderContext, &params);
+ }
+}
+
+// *********************** Flow Color Map *****************************************
+
+void FlowColorMap::updateColorMap(NvFlowContext* context)
+{
+ NvFlowRenderMaterialHandle materials[3u] = { m_materialDefault, m_material0, m_material1 };
+ std::vector<CurvePoint>* curves[3u] = {&m_curvePointsDefault, &m_curvePointsMat0, &m_curvePointsMat1 };
+ for (NvFlowUint matIdx = 0u; matIdx < 3u; matIdx++)
+ {
+ auto& curve = *curves[matIdx];
+ auto mapped = NvFlowRenderMaterialColorMap(context, materials[matIdx]);
+ if (mapped.data)
+ {
+ pointsToImage(mapped.data, mapped.dim, &curve[0], (unsigned int)curve.size());
+
+ NvFlowRenderMaterialColorUnmap(context, materials[matIdx]);
+ }
+ }
+}
+
+void FlowColorMap::imguiUpdate(Scene* scene, NvFlowContext* context, int border, int x, int y, int w, int h)
+{
+ bool actives[3u] = { m_curveEditorActiveDefault, m_curveEditorActiveMat0, m_curveEditorActiveMat1 };
+ CurveEditState* editStates[3u] = { &m_editStateDefault, &m_editStateMat0 , &m_editStateMat1 };
+ std::vector<CurvePoint>* curves[3u] = { &m_curvePointsDefault, &m_curvePointsMat0, &m_curvePointsMat1 };
+
+ for (NvFlowUint matIdx = 0u; matIdx < 3u; matIdx++)
+ {
+ auto& editState = *editStates[matIdx];
+ auto& curve = *curves[matIdx];
+
+ if (actives[matIdx])
+ {
+ // curve editor
+ {
+ CurveEditParams params;
+ params.mouseState.x = scene->m_mx;
+ params.mouseState.y = scene->m_my;
+ params.mouseState.but = scene->m_mbut;
+ params.editorBounds.x = x + w + border;
+ params.editorBounds.y = y;
+ params.editorBounds.w = scene->m_winw - w - 3 * border;
+ params.editorBounds.h = m_curveEditorHeight - border;
+ params.rangeMin = { 0.f, 0.f, 0.f, 0.f, 0.f };
+ params.rangeMax = { 1.f, 1.5f, 1.5f, 1.5f, 1.f };
+ params.points = &curve[0];
+ params.numPoints = (unsigned int)curve.size();
+
+ if (curveEditor(&editState, &params))
+ {
+ if (editState.action == CURVE_POINT_MODIFY)
+ {
+ curve[editState.activePointIndex] = editState.point;
+ }
+ if (editState.action == CURVE_POINT_INSERT)
+ {
+ curve.insert(curve.begin() + editState.activePointIndex, editState.point);
+ }
+ if (editState.action == CURVE_POINT_REMOVE)
+ {
+ curve.erase(curve.begin() + editState.activePointIndex);
+ }
+
+ updateColorMap(context);
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (imguiserOffscreenUpdate())
+ {
+ const char* groupNames[3u] = {"colormap", "colormapMat0", "colormapMat1"};
+ for (NvFlowUint matIdx = 0u; matIdx < 3u; matIdx++)
+ {
+ auto& curve = *curves[matIdx];
+
+ int oldNumItems = (int)curve.size();
+ int numItems = 5 * oldNumItems;
+ imguiserBeginGroup(groupNames[matIdx], &numItems);
+ numItems /= 5;
+ if (oldNumItems != numItems)
+ {
+ curve.resize(numItems);
+ }
+
+ for (size_t i = 0; i < curve.size(); i++)
+ {
+ auto& pt = curve[i];
+
+ imguiserValue1f(nullptr, &pt.x);
+ imguiserValue1f(nullptr, &pt.r);
+ imguiserValue1f(nullptr, &pt.g);
+ imguiserValue1f(nullptr, &pt.b);
+ imguiserValue1f(nullptr, &pt.a);
+ }
+
+ imguiserEndGroup();
+ }
+
+ updateColorMap(context);
+ }
+}
+
+bool FlowColorMap::colorMapActive(int mx, int my, unsigned char mbut)
+{
+ bool editorActive = m_curveEditorActiveDefault || m_curveEditorActiveMat0 || m_curveEditorActiveMat1;
+ return (editorActive && my < (int)m_curveEditorHeight);
+}
+
+void FlowColorMap::initColorMap(NvFlowContext* context, const CurvePoint* pts, int numPoints, bool ptsEnabled)
+{
+ if (ptsEnabled)
+ {
+ m_curvePointsDefault.reserve(numPoints);
+ m_curvePointsMat0.reserve(numPoints);
+ m_curvePointsMat1.reserve(numPoints);
+
+ m_curvePointsDefault.clear();
+ m_curvePointsMat0.clear();
+ m_curvePointsMat1.clear();
+
+ for (int i = 0; i < numPoints; i++)
+ {
+ m_curvePointsDefault.push_back(pts[i]);
+ m_curvePointsMat0.push_back(pts[i]);
+ m_curvePointsMat1.push_back(pts[i]);
+ }
+ }
+
+ updateColorMap(context);
+} \ No newline at end of file
diff --git a/demo/DemoApp/sceneSDF.cpp b/demo/DemoApp/sceneSDF.cpp
new file mode 100644
index 0000000..301e260
--- /dev/null
+++ b/demo/DemoApp/sceneSDF.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace Preset0
+{
+#include "preset0.h"
+}
+namespace Preset1
+{
+#include "preset1.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+void SceneSDFTest::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ m_emitParams.bounds.x.x = 1.5f;
+ m_emitParams.bounds.y.y = 1.5f;
+ m_emitParams.bounds.z.z = 1.5f;
+ m_emitParams.velocityLinear.y = -8.f;
+ m_emitParams.fuel = 1.4f;
+ m_emitParams.smoke = 0.5f;
+
+ // grid parameter overrides
+ m_flowGridActor.m_separateLighting = false; // disable separate lighting, lower quality due to nonlinear colormap
+
+ m_flowGridActor.m_gridDesc.halfSize.x = 16.f;
+ m_flowGridActor.m_gridDesc.halfSize.y = 16.f;
+ m_flowGridActor.m_gridDesc.halfSize.z = 16.f;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.25f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.25f;
+ m_flowGridActor.m_renderMaterialDefaultParams.alphaScale = 0.2f;
+
+ m_flowGridActor.m_gridParams.gravity = NvFlowFloat3{ 0.f, -0.5f, 0.f };
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneSDFTest::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ using namespace DirectX;
+
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ NvFlowSDFGenDesc sdfDesc;
+ sdfDesc.resolution = { 128u, 128u, 128u };
+
+ m_sdfGen = NvFlowCreateSDFGen(m_flowContext.m_gridContext, &sdfDesc);
+
+ m_meshContext = MeshInteropContextCreate(appctx);
+ m_mesh = MeshCreate(m_meshContext);
+
+ MeshLoadFromFile(m_mesh, "../../data/bunny.ply");
+
+ MeshData meshData;
+ MeshGetData(m_mesh, &meshData);
+
+ NvFlowSDFGenReset(m_sdfGen, m_flowContext.m_gridContext);
+
+ XMMATRIX modelMatrix = XMMatrixMultiply(
+ XMMatrixScaling(8.f, 8.f, 8.f),
+ XMMatrixTranslation(0.f, -0.75f, 0.f)
+ );
+
+ NvFlowSDFGenMeshParams meshParams;
+ meshParams.numVertices = meshData.numVertices;
+ meshParams.positions = meshData.positions;
+ meshParams.positionStride = meshData.positionStride;
+ meshParams.normals = meshData.normals;
+ meshParams.normalStride = meshData.normalStride;
+ meshParams.numIndices = meshData.numIndices;
+ meshParams.indices = meshData.indices;
+ XMStoreFloat4x4((XMFLOAT4X4*)&meshParams.modelMatrix, modelMatrix);
+ meshParams.renderTargetView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_rtv;
+ meshParams.depthStencilView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_dsv;
+
+ NvFlowSDFGenVoxelize(m_sdfGen, m_flowContext.m_gridContext, &meshParams);
+
+ NvFlowSDFGenUpdate(m_sdfGen, m_flowContext.m_gridContext);
+
+ // create shape from SDF
+ m_shape = NvFlowCreateShapeSDFFromTexture3D(
+ m_flowContext.m_gridContext,
+ NvFlowSDFGenShape(m_sdfGen, m_flowContext.m_gridContext)
+ );
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] = {
+ {0.f,0.f,0.f,0.f,0.f},
+ {0.05f,0.2f,0.2f,0.2f,0.25f},
+ {0.6f,0.35f * 141.f / 255.f, 0.1f * 199.f / 255.f, 0.7f * 63.f / 255.f,0.8f},
+ {0.85f,0.75f * 141.f / 255.f, 0.15f * 199.f / 255.f, 1.f * 63.f / 255.f,0.8f},
+ {1.f,1.25f * 141.f / 255.f, 0.2f * 199.f / 255.f, 3.f * 63.f / 255.f,0.5f}
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+}
+
+void SceneSDFTest::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sdf.sdfOffset = 0u; // m_shape;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSDF;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ NvFlowShapeSDF* sdfs[] = { m_shape };
+ NvFlowGridUpdateEmitSDFs(m_flowGridActor.m_grid, sdfs, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSDFTest::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneSDFTest::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ //MeshInteropContextUpdate(m_meshContext, m_appctx);
+
+ //MeshDrawParams meshDrawParams;
+ //meshDrawParams.renderMode = MESH_RENDER_SOLID;
+ //meshDrawParams.projection = projection;
+ //meshDrawParams.view = view;
+ //meshDrawParams.model = DirectX::XMMatrixMultiply(
+ // DirectX::XMMatrixScaling(0.25f, 0.25f, 0.25f),
+ // DirectX::XMMatrixTranslation(0.f, 0.0f, 0.f)
+ // );
+
+ //MeshDraw(m_mesh, &meshDrawParams);
+
+ m_flowContext.drawBegin();
+
+#if 0
+ memcpy(&m_renderParams.projectionMatrix, &projection, sizeof(m_renderParams.projectionMatrix));
+ memcpy(&m_renderParams.viewMatrix, &view, sizeof(m_renderParams.viewMatrix));
+ m_renderParams.modelMatrix = {
+ 1.5f, 0.f, 0.f, 0.f,
+ 0.f, 1.5f, 0.f, 0.f,
+ 0.f, 0.f, 1.5f, 0.f,
+ 0.f, 0.f, 0.f, 1.f
+ };
+
+ m_renderParams.depthStencilView = m_dsv;
+ m_renderParams.renderTargetView = m_rtv;
+
+ auto texture = NvFlowSDFGenShape(m_sdfGen, m_context);
+
+ NvFlowVolumeRenderTexture3D(m_volumeRender, m_context, texture, &m_renderParams);
+#endif
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSDFTest::release()
+{
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ NvFlowReleaseShapeSDF(m_shape);
+
+ NvFlowReleaseSDFGen(m_sdfGen);
+
+ m_flowContext.release();
+
+ MeshRelease(m_mesh);
+ MeshContextRelease(m_meshContext);
+}
+
+void SceneSDFTest::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(Preset0::g_root, sizeof(Preset0::g_root));
+ m_shouldLoadPreset = false;
+ }
+}
+
+// ************************** Scene Custom Lighting ******************************
+
+#include "computeContext.h"
+
+namespace
+{
+ // Need BYTE defined for shader bytecode
+ typedef unsigned char BYTE;
+ #include "customLightingCS.hlsl.h"
+}
+
+void SceneCustomLighting::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSDFTest::init(context, winw, winh);
+
+ auto gridExport = NvFlowGridProxyGetGridExport(m_flowGridActor.m_gridProxy, m_flowContext.m_renderContext);
+
+ NvFlowGridImportDesc importDesc = {};
+ importDesc.gridExport = gridExport;
+
+ m_import = NvFlowCreateGridImport(m_flowContext.m_renderContext, &importDesc);
+
+ // create compute resources
+ m_computeContext = ComputeContextNvFlowContextCreate(m_flowContext.m_renderContext);
+
+ ComputeShaderDesc shaderDesc = {};
+ shaderDesc.cs = g_customLightingCS;
+ shaderDesc.cs_length = sizeof(g_customLightingCS);
+ m_computeShader = ComputeShaderCreate(m_computeContext, &shaderDesc);
+
+ ComputeConstantBufferDesc cbDesc = {};
+ cbDesc.sizeInBytes = 1024 * sizeof(float);
+ m_computeConstantBuffer = ComputeConstantBufferCreate(m_computeContext, &cbDesc);
+}
+
+void SceneCustomLighting::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ ComputeContextNvFlowContextUpdate(m_computeContext, m_flowContext.m_renderContext);
+
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ if (shouldUpdate)
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sdf.sdfOffset = 0u; // m_shape;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSDF;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ NvFlowShapeSDF* sdfs[] = { m_shape };
+ NvFlowGridUpdateEmitSDFs(m_flowGridActor.m_grid, sdfs, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+
+ m_time += dt;
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneCustomLighting::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ //auto gridView = NvFlowGridGetGridView(m_grid, m_context);
+
+ AppGraphCtxProfileBegin(m_appctx, "UpdateGridView");
+
+ NvFlowGridProxyFlushParams flushParams = {};
+ flushParams.gridContext = m_flowContext.m_gridContext;
+ flushParams.gridCopyContext = m_flowContext.m_gridCopyContext;
+ flushParams.renderCopyContext = m_flowContext.m_renderCopyContext;
+ NvFlowGridProxyFlush(m_flowGridActor.m_gridProxy, &flushParams);
+
+ auto gridExport = NvFlowGridProxyGetGridExport(m_flowGridActor.m_gridProxy, m_flowContext.m_renderContext);
+
+ AppGraphCtxProfileEnd(m_appctx, "UpdateGridView");
+
+ AppGraphCtxProfileBegin(m_appctx, "CustomLighting");
+
+ // Only layer 0 for the moment
+ NvFlowUint layerIdx = 0u;
+
+ NvFlowGridExportHandle exportHandle = NvFlowGridExportGetHandle(gridExport, m_flowContext.m_renderContext, eNvFlowGridTextureChannelDensity);
+ NvFlowGridExportLayeredView exportLayeredView;
+ NvFlowGridExportGetLayeredView(exportHandle, &exportLayeredView);
+ NvFlowGridExportLayerView exportLayerView;
+ NvFlowGridExportGetLayerView(exportHandle, layerIdx, &exportLayerView);
+
+ NvFlowGridImportParams importParams = {};
+ importParams.gridExport = gridExport;
+ importParams.channel = eNvFlowGridTextureChannelDensity;
+ importParams.importMode = eNvFlowGridImportModePoint;
+ NvFlowGridImportHandle importHandle = NvFlowGridImportGetHandle(m_import, m_flowContext.m_renderContext, &importParams);
+ NvFlowGridImportLayeredView importLayeredView;
+ NvFlowGridImportGetLayeredView(importHandle, &importLayeredView);
+ NvFlowGridImportLayerView importLayerView;
+ NvFlowGridImportGetLayerView(importHandle, layerIdx, &importLayerView);
+
+ // convert resource from NvFlow types to ComputeResource types
+ {
+ auto updateResource = [&](ComputeResource*& computeResouce, NvFlowResource*& flowResource)
+ {
+ if (computeResouce) {
+ ComputeResourceNvFlowUpdate(m_computeContext, computeResouce, m_flowContext.m_renderContext, flowResource);
+ }
+ else {
+ computeResouce = ComputeResourceNvFlowCreate(m_computeContext, m_flowContext.m_renderContext, flowResource);
+ }
+ };
+ auto updateResourceRW = [&](ComputeResourceRW*& computeResouceRW, NvFlowResourceRW*& flowResourceRW)
+ {
+ if (computeResouceRW) {
+ ComputeResourceRWNvFlowUpdate(m_computeContext, computeResouceRW, m_flowContext.m_renderContext, flowResourceRW);
+ }
+ else {
+ computeResouceRW = ComputeResourceRWNvFlowCreate(m_computeContext, m_flowContext.m_renderContext, flowResourceRW);
+ }
+ };
+ updateResource(m_exportBlockList, exportLayerView.mapping.blockList);
+ updateResource(m_exportBlockTable, exportLayerView.mapping.blockTable);
+ updateResource(m_exportData, exportLayerView.data);
+ updateResource(m_importBlockList, importLayerView.mapping.blockList);
+ updateResource(m_importBlockTable, importLayerView.mapping.blockTable);
+ updateResourceRW(m_importDataRW, importLayerView.dataRW);
+ }
+
+ // dispatch custom lighting operation
+ {
+ struct Light
+ {
+ NvFlowFloat4 location;
+ NvFlowFloat4 intensity;
+ NvFlowFloat4 bias;
+ NvFlowFloat4 falloff;
+ };
+
+ struct ComputeShaderParams
+ {
+ NvFlowShaderLinearParams exportParams;
+ NvFlowShaderLinearParams importParams;
+
+ Light light[3];
+ };
+
+ auto mapped = (ComputeShaderParams*)ComputeConstantBufferMap(m_computeContext, m_computeConstantBuffer);
+
+ mapped->exportParams = exportLayeredView.mapping.shaderParams;
+ mapped->importParams = importLayeredView.mapping.shaderParams;
+
+ if (m_time >= DirectX::XM_2PI)
+ {
+ m_time -= DirectX::XM_2PI;
+ }
+ const float radius = 0.025f;
+ const float a = radius * cosf(m_time);
+ const float b = radius * sinf(m_time);
+
+ mapped->light[0].location = { a, b, 0.f, 1.f };
+ mapped->light[0].intensity = { 1.25f, 0.f, 0.f, 1.f };
+ mapped->light[0].bias = { 0.1f, 0.1f, 0.1f, 0.1f };
+ mapped->light[0].falloff = { 200.f, 200.f, 200.f, 0.f };
+ mapped->light[1].location = { 0.f, a, b, 1.f };
+ mapped->light[1].intensity = { 0.f, 1.25f, 0.f, 1.f };
+ mapped->light[1].bias = { 0.1f, 0.1f, 0.1f, 0.1f };
+ mapped->light[1].falloff = { 200.f, 200.f, 200.f, 0.f };
+ mapped->light[2].location = { b, 0.f, a, 1.f };
+ mapped->light[2].intensity = { 0.f, 0.f, 1.1f, 1.f };
+ mapped->light[2].bias = { 0.1f, 0.1f, 0.1f, 0.1f };
+ mapped->light[2].falloff = { 200.f, 200.f, 200.f, 0.f };
+
+ ComputeConstantBufferUnmap(m_computeContext, m_computeConstantBuffer);
+
+ ComputeDispatchParams dparams = {};
+ dparams.shader = m_computeShader;
+ dparams.constantBuffer = m_computeConstantBuffer;
+ dparams.gridDim[0] = (importLayerView.mapping.numBlocks * importLayeredView.mapping.shaderParams.blockDim.x + 7) / 8;
+ dparams.gridDim[1] = (importLayeredView.mapping.shaderParams.blockDim.y + 7) / 8;
+ dparams.gridDim[2] = (importLayeredView.mapping.shaderParams.blockDim.z + 7) / 8;
+ dparams.resources[0] = m_exportBlockList;
+ dparams.resources[1] = m_exportBlockTable;
+ dparams.resources[2] = m_exportData;
+ dparams.resources[3] = m_importBlockList;
+ dparams.resources[4] = m_importBlockTable;
+ dparams.resourcesRW[0] = m_importDataRW;
+
+ ComputeContextDispatch(m_computeContext, &dparams);
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "CustomLighting");
+
+ AppGraphCtxProfileBegin(m_appctx, "CustomImport");
+
+ // override original gridExport
+ gridExport = NvFlowGridImportGetGridExport(m_import, m_flowContext.m_renderContext);
+
+ AppGraphCtxProfileEnd(m_appctx, "CustomImport");
+
+ m_flowGridActor.m_gridExportOverride = gridExport;
+ m_flowGridActor.m_renderParamsOverride = m_flowGridActor.m_renderParams;
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneCustomLighting::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneCustomLighting::release()
+{
+ NvFlowReleaseGridImport(m_import);
+
+ // release compute resources
+ ComputeConstantBufferRelease(m_computeConstantBuffer);
+ ComputeShaderRelease(m_computeShader);
+ ComputeContextRelease(m_computeContext);
+
+ ComputeResourceRelease(m_exportBlockList);
+ ComputeResourceRelease(m_exportBlockTable);
+ ComputeResourceRelease(m_exportData);
+ ComputeResourceRelease(m_importBlockList);
+ ComputeResourceRelease(m_importBlockTable);
+ ComputeResourceRWRelease(m_importDataRW);
+
+ m_exportBlockList = nullptr;
+ m_exportBlockTable = nullptr;
+ m_exportData = nullptr;
+ m_importBlockList = nullptr;
+ m_importBlockTable = nullptr;
+ m_importDataRW = nullptr;
+
+ SceneSDFTest::release();
+}
+
+void SceneCustomLighting::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ bool shouldLoadPreset = m_shouldLoadPreset;
+ m_shouldLoadPreset = false;
+ SceneSDFTest::imgui(xIn, yIn, wIn, hIn);
+ m_shouldLoadPreset = shouldLoadPreset;
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(Preset1::g_root, sizeof(Preset1::g_root));
+ m_shouldLoadPreset = false;
+ }
+}
+
+void SceneCustomLighting::initParams()
+{
+ SceneSDFTest::initParams();
+} \ No newline at end of file
diff --git a/demo/DemoApp/sceneSimpleFlame.cpp b/demo/DemoApp/sceneSimpleFlame.cpp
new file mode 100644
index 0000000..60b134b
--- /dev/null
+++ b/demo/DemoApp/sceneSimpleFlame.cpp
@@ -0,0 +1,1156 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace PresetFlame
+{
+#include "presetFlame.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+void SceneSimpleFlame::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneSimpleFlame::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ // more compute resources
+ NvFlowShapeSDFDesc shapeDesc;
+ NvFlowShapeSDFDescDefaults(&shapeDesc);
+ m_shape = NvFlowCreateShapeSDF(m_flowContext.m_gridContext, &shapeDesc);
+
+ // generate sphere SDF
+ const float radius = 0.8f;
+ auto mappedData = NvFlowShapeSDFMap(m_shape, m_flowContext.m_gridContext);
+ if (mappedData.data)
+ {
+ for (NvFlowUint k = 0; k < mappedData.dim.z; k++)
+ for (NvFlowUint j = 0; j < mappedData.dim.y; j++)
+ for (NvFlowUint i = 0; i < mappedData.dim.x; i++)
+ {
+ float& val = mappedData.data[k * mappedData.depthPitch + j * mappedData.rowPitch + i];
+
+ float x = 2.f * (float(i) + 0.5f) / float(mappedData.dim.x) - 1.f;
+ float y = 2.f * (float(j) + 0.5f) / float(mappedData.dim.y) - 1.f;
+ float z = 2.f * (float(k) + 0.5f) / float(mappedData.dim.z) - 1.f;
+
+ float d = sqrtf(x*x + y*y + z*z);
+ float v = d - radius;
+
+ val = v;
+ }
+ NvFlowShapeSDFUnmap(m_shape, m_flowContext.m_gridContext);
+ }
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] = {
+ {0.f, 0.f,0.f,0.f,0.f},
+ {0.05f, 0.f,0.f,0.f,0.5f},
+ {0.6f, 213.f / 255.f,100.f / 255.f,30.f / 255.f,0.8f},
+ {0.85f, 255.f / 255.f,240.f / 255.f,0.f,0.8f},
+ {1.f, 1.f,1.f,1.f,0.7f}
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+}
+
+void SceneSimpleFlame::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlame::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneSimpleFlame::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSimpleFlame::release()
+{
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ NvFlowReleaseShapeSDF(m_shape);
+
+ m_flowContext.release();
+}
+
+void SceneSimpleFlame::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(PresetFlame::g_root, sizeof(PresetFlame::g_root));
+ m_shouldLoadPreset = false;
+ }
+}
+
+// *************************** SceneSimpleFlameDouble **********************
+
+void SceneSimpleFlameDouble::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowGridMaterialParams materialParams = {};
+ NvFlowGridMaterialParamsDefaults(&materialParams);
+
+ m_materialA = NvFlowGridCreateMaterial(m_flowGridActor.m_grid, &materialParams);
+
+ materialParams.vorticityStrength = 5.f;
+ materialParams.vorticityVelocityMask = 0.f;
+ materialParams.velocity.macCormackBlendFactor = 0.f;
+ materialParams.smoke.macCormackBlendFactor = 0.75f;
+ materialParams.buoyancyPerTemp *= 5.f;
+
+ m_materialB = NvFlowGridCreateMaterial(m_flowGridActor.m_grid, &materialParams);
+
+ m_flowGridActor.m_renderMaterialMat0Params.material = m_materialA;
+ m_flowGridActor.m_renderMaterialMat1Params.material = m_materialB;
+}
+
+void SceneSimpleFlameDouble::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ m_emitParamsA = m_emitParams;
+ m_emitParamsA.material = m_materialA;
+ m_emitParamsA.bounds.w.x = +0.25f;
+ m_emitParamsA.localToWorld = m_emitParamsA.bounds;
+ m_emitParamsA.velocityLinear.x = -8.f;
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParamsA, 1u);
+
+ m_emitParamsB = m_emitParams;
+ m_emitParamsB.material = m_materialB;
+ m_emitParamsB.bounds.w.x = -0.25f;
+ m_emitParamsB.localToWorld = m_emitParamsB.bounds;
+ m_emitParamsB.velocityLinear.x = +8.f;
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParamsB, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameDouble::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameDouble::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameDouble::release()
+{
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameDouble::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameDouble::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneSimpleFlameFuelMap **********************
+
+void SceneSimpleFlameFuelMap::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ m_flowGridActor.m_renderMaterialMat0Params.material = NvFlowGridGetDefaultMaterial(m_flowGridActor.m_grid);
+
+ m_flowGridActor.m_renderMaterialMat0Params.colorMapCompMask = { 0.f, 4.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialMat0Params.alphaCompMask = { 0.f, 1.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialMat0Params.alphaBias = 0.f;
+
+ //m_flowGridActor.m_renderMaterialMat1Params.material = m_materialB;
+}
+
+void SceneSimpleFlameFuelMap::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameFuelMap::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameFuelMap::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameFuelMap::release()
+{
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameFuelMap::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameFuelMap::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneSimpleFlameParticleSurface **********************
+
+void SceneSimpleFlameParticleSurface::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowParticleSurfaceDesc surfaceDesc = {};
+ surfaceDesc.initialLocation = { 0.f, 0.f, 0.f };
+ surfaceDesc.halfSize = { 8.f, 8.f, 8.f };
+ surfaceDesc.virtualDim = NvFlowDim{512u, 512u, 512u};
+ surfaceDesc.residentScale = 0.125f * 0.125f;
+ surfaceDesc.maxParticles = 64u * 1024u;
+
+ m_particleSurface = NvFlowCreateParticleSurface(m_flowContext.m_gridContext, &surfaceDesc);
+
+ if (!m_visualizeSurface)
+ {
+ NvFlowGridEmitCustomRegisterAllocFunc(m_flowGridActor.m_grid, emitCustomAllocFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelVelocity, emitCustomEmitVelocityFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelDensity, emitCustomEmitDensityFunc, this);
+ }
+
+ // generate positions
+ const NvFlowUint r = 32u;
+
+ m_positions.clear();
+ m_positions.resize(4u * r * r);
+ const float scale = 4.f;
+ const float scaleXInv = scale / float(r);
+ const float scaleYInv = scale / float(r);
+ for (NvFlowUint j = 0u; j < r; j++)
+ {
+ for (NvFlowUint i = 0u; i < r; i++)
+ {
+ float x = scaleXInv * float(i) - scale * 0.5f;
+ float y = scaleYInv * float(j) - scale * 0.5f;
+
+ m_positions[4 * (j * r + i) + 0u] = x;
+ m_positions[4 * (j * r + i) + 1u] = 0.f;
+ m_positions[4 * (j * r + i) + 2u] = y;
+ m_positions[4 * (j * r + i) + 3u] = 1.f;
+ }
+ }
+
+ m_flowGridActor.m_renderMaterialDefaultParams.material = NvFlowGridMaterialHandle{ nullptr, 1u };
+ m_flowGridActor.m_renderMaterialMat0Params.material = NvFlowGridGetDefaultMaterial(m_flowGridActor.m_grid);
+
+ m_particleParams.smoothRadius = 16.f;
+ m_particleParams.surfaceThreshold = 0.001f;
+ m_particleParams.separableSmoothing = true;
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomAllocFunc(void* userdata, const NvFlowGridEmitCustomAllocParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomAllocFunc(params);
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomEmitVelocityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomEmitVelocityFunc(dataFrontIdx, params);
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomEmitDensityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomEmitDensityFunc(dataFrontIdx, params);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomAllocFunc(const NvFlowGridEmitCustomAllocParams* params)
+{
+ NvFlowParticleSurfaceAllocFunc(m_particleSurface, m_flowContext.m_gridContext, params);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomEmitVelocityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ NvFlowParticleSurfaceEmitVelocityFunc(m_particleSurface, m_flowContext.m_gridContext, dataFrontIdx, params, &m_surfaceEmitParams);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomEmitDensityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ NvFlowParticleSurfaceEmitDensityFunc(m_particleSurface, m_flowContext.m_gridContext, dataFrontIdx, params, &m_surfaceEmitParams);
+}
+
+void SceneSimpleFlameParticleSurface::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ // update emit params
+ {
+ // set surface emit params
+ const float coupleRate = 0.5f;
+ m_surfaceEmitParams.deltaTime = dt;
+ m_surfaceEmitParams.velocityLinear = m_emitParams.velocityLinear;
+ m_surfaceEmitParams.velocityCoupleRate = NvFlowFloat3{ coupleRate, coupleRate, coupleRate };
+ m_surfaceEmitParams.smoke = m_emitParams.smoke;
+ m_surfaceEmitParams.smokeCoupleRate = coupleRate;
+ m_surfaceEmitParams.temperature = m_emitParams.temperature;
+ m_surfaceEmitParams.temperatureCoupleRate = coupleRate;
+ m_surfaceEmitParams.fuel = m_emitParams.fuel;
+ m_surfaceEmitParams.fuelCoupleRate = coupleRate;
+ }
+
+ AppGraphCtxProfileBegin(m_appctx, "ParticleSurface");
+
+ {
+ // animate wave surface
+ {
+ const NvFlowUint r = 32u;
+ const float k = 0.125f;
+ const float timeScale = 4.f;
+ const float spaceScale = 32.f;
+ const float pi = 3.14159f;
+
+ const float period = 2.f * pi / (timeScale);
+
+ m_time += dt;
+
+ float offsetX = 0.f; // 3.f * cosf(m_time);
+ float offsetY = 0.f; // 3.f * sinf(m_time);
+
+ const float scale = 4.f;
+ const float scaleInv = 1.f / scale;
+ const float scaleXInv = scale / float(r);
+ const float scaleYInv = scale / float(r);
+ for (NvFlowUint j = 0u; j < r; j++)
+ {
+ for (NvFlowUint i = 0u; i < r; i++)
+ {
+ float x = scaleXInv * float(i) - scale * 0.5f;
+ float y = scaleYInv * float(j) - scale * 0.5f;
+ float d = scaleInv * sqrtf(x * x + y * y);
+
+ m_positions[4 * (j * r + i) + 0u] = x + offsetX;
+ m_positions[4 * (j * r + i) + 2u] = y + offsetY;
+ m_positions[4 * (j * r + i) + 1u] = k * cosf(-timeScale * m_time + spaceScale * d);
+ }
+ }
+ }
+
+ NvFlowParticleSurfaceData particleData = {};
+ particleData.positions = &m_positions[0u];
+ particleData.positionStride = 4 * sizeof(float);
+ particleData.numParticles = NvFlowUint(m_positions.size() / 4u);
+
+ NvFlowParticleSurfaceUpdateParticles(m_particleSurface, m_flowContext.m_gridContext, &particleData);
+
+ NvFlowParticleSurfaceUpdateSurface(m_particleSurface, m_flowContext.m_gridContext, &m_particleParams);
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "ParticleSurface");
+
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ /*
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+ */
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameParticleSurface::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameParticleSurface::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ if (!m_visualizeSurface)
+ {
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+ }
+ else
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Render");
+
+ auto m_renderParams = m_flowGridActor.m_renderParams;
+
+ memcpy(&m_renderParams.projectionMatrix, &projection, sizeof(m_renderParams.projectionMatrix));
+ memcpy(&m_renderParams.viewMatrix, &view, sizeof(m_renderParams.viewMatrix));
+
+ m_renderParams.depthStencilView = m_flowContext.m_dsv;
+ m_renderParams.renderTargetView = m_flowContext.m_rtv;
+
+ auto gridExport = NvFlowParticleSurfaceDebugGridExport(m_particleSurface, m_flowContext.m_renderContext);
+
+ NvFlowVolumeRenderGridExport(m_flowGridActor.m_volumeRender, m_flowContext.m_renderContext, gridExport, &m_renderParams);
+
+ AppGraphCtxProfileEnd(m_appctx, "Render");
+ }
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSimpleFlameParticleSurface::release()
+{
+ SceneSimpleFlame::release();
+
+ NvFlowReleaseParticleSurface(m_particleSurface);
+}
+
+void SceneSimpleFlameParticleSurface::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameParticleSurface::imguiFluidRenderExtra()
+{
+ imguiLabel("Particle Surface");
+ if (imguiserCheck("SurfaceVis", m_visualizeSurface, true))
+ {
+ m_visualizeSurface = !m_visualizeSurface;
+ m_shouldReset = true;
+ }
+ imguiserSlider("Smooth Radius", &m_particleParams.smoothRadius, 1.f, 16.f, 1.f, true);
+ imguiserSlider("Threshold", &m_particleParams.surfaceThreshold, 0.001f, 0.01f, 0.001f, true);
+ if (imguiserCheck("SeparableSmooth", m_particleParams.separableSmoothing, true))
+ {
+ m_particleParams.separableSmoothing = !m_particleParams.separableSmoothing;
+ }
+}
+
+void SceneSimpleFlameParticleSurface::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = -1.f;
+ m_emitParams.fuel = 0.2f;
+ m_emitParams.smoke = 0.1f;
+ m_emitParams.temperature = 8.f;
+
+ m_flowGridActor.m_materialParams.coolingRate = 3.f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneDynamicCoupleRate **********************
+
+void SceneDynamicCoupleRate::initParams()
+{
+ SceneSimpleFlame::initParams();
+ m_emitParams.allocationPredict = 0.3f;
+}
+
+float SceneDynamicCoupleRate::positionFunc(float theta)
+{
+ return 2.f * cosf(theta);
+}
+
+float SceneDynamicCoupleRate::velocityFunc(float theta, float rate)
+{
+ return -2.f * rate * sinf(theta);
+}
+
+void SceneDynamicCoupleRate::doUpdate(float dt)
+{
+ const float pi2 = 2.f * 3.14159265f;
+
+ theta += pi2 * rate * dt;
+
+ if (theta > pi2) theta -= pi2;
+
+ // get position and velocity
+ float position = positionFunc(theta);
+ float velocity = velocityFunc(theta, pi2 * rate);
+
+ // update emitter bounds
+ m_emitParams.bounds.x.x = 0.25f * emitterScale;
+ m_emitParams.bounds.y.y = 0.25f * emitterScale;
+ m_emitParams.bounds.z.z = 0.25f * emitterScale;
+
+ // modulate couple rate as a function of velocity and emitter width
+ const float defaultCoupleRate = 0.5f;
+
+ float emitWidth = m_emitParams.bounds.x.x;
+
+ float coupleRate = fmaxf(coupleRateScale * fabsf(velocity) / emitWidth, defaultCoupleRate);
+
+ m_emitParams.smokeCoupleRate = coupleRate;
+ m_emitParams.temperatureCoupleRate = coupleRate;
+ m_emitParams.fuelCoupleRate = coupleRate;
+ m_emitParams.velocityCoupleRate = { coupleRate, coupleRate, coupleRate };
+
+ m_emitParams.bounds.w.x = position;
+ m_emitParams.velocityLinear.x = velocity;
+
+ m_emitParams.predictVelocityWeight = 1.f;
+ m_emitParams.predictVelocity.x = velocity;
+ m_emitParams.predictVelocity.y = 0.f;
+ m_emitParams.predictVelocity.z = 0.f;
+
+ SceneSimpleFlame::doUpdate(dt);
+}
+
+void SceneDynamicCoupleRate::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Dynamic Couple Rate");
+
+ imguiserSlider("Anim Cycle Time", &rate, 0.f, 0.5f, 0.01f, true);
+ imguiserSlider("Couple Rate Scale", &coupleRateScale, 0.f, 1.0f, 0.01f, true);
+ imguiserSlider("Emitter Scale", &emitterScale, 0.5f, 2.0f, 0.01f, true);
+}
+
+// *************************** SceneSimpleFlameMesh ************************
+
+void SceneSimpleFlameMesh::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ NvFlowGridEmitParamsDefaults(&m_teapotEmitParams);
+
+ m_teapotEmitParams.allocationScale = { 0.f, 0.f, 0.f };
+
+ m_teapotEmitParams.maxActiveDist = -0.08f;
+ m_teapotEmitParams.slipThickness = 0.25f;
+ m_teapotEmitParams.slipFactor = 0.9f;
+}
+
+void SceneSimpleFlameMesh::init(AppGraphCtx* context, int winw, int winh)
+{
+ using namespace DirectX;
+
+ m_meshContext = MeshInteropContextCreate(context);
+ m_mesh = MeshCreate(m_meshContext);
+
+ MeshLoadFromFile(m_mesh, m_meshPath);
+
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowSDFGenDesc sdfDesc;
+ sdfDesc.resolution = { 128u, 128u, 128u };
+
+ m_sdfGen = NvFlowCreateSDFGen(m_flowContext.m_gridContext, &sdfDesc);
+
+ MeshData meshData;
+ MeshGetData(m_mesh, &meshData);
+
+ NvFlowSDFGenReset(m_sdfGen, m_flowContext.m_gridContext);
+
+ XMMATRIX modelMatrix = XMMatrixMultiply(
+ XMMatrixScaling(m_sdfScale.x, m_sdfScale.y, m_sdfScale.z),
+ XMMatrixTranslation(0.f, 0.f, 0.f)
+ );
+
+ NvFlowSDFGenMeshParams meshParams;
+ meshParams.numVertices = meshData.numVertices;
+ meshParams.positions = meshData.positions;
+ meshParams.positionStride = meshData.positionStride;
+ meshParams.normals = meshData.normals;
+ meshParams.normalStride = meshData.normalStride;
+ meshParams.numIndices = meshData.numIndices;
+ meshParams.indices = meshData.indices;
+ XMStoreFloat4x4((XMFLOAT4X4*)&meshParams.modelMatrix, modelMatrix);
+ meshParams.renderTargetView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_rtv;
+ meshParams.depthStencilView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_dsv;
+
+ NvFlowSDFGenVoxelize(m_sdfGen, m_flowContext.m_gridContext, &meshParams);
+
+ NvFlowSDFGenUpdate(m_sdfGen, m_flowContext.m_gridContext);
+
+ // create shape from SDF
+ m_teapotShape = NvFlowCreateShapeSDFFromTexture3D(
+ m_flowContext.m_gridContext,
+ NvFlowSDFGenShape(m_sdfGen, m_flowContext.m_gridContext)
+ );
+}
+
+void SceneSimpleFlameMesh::release()
+{
+ MeshRelease(m_mesh);
+ MeshContextRelease(m_meshContext);
+ NvFlowReleaseShapeSDF(m_teapotShape);
+ NvFlowReleaseSDFGen(m_sdfGen);
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameMesh::doUpdate(float dt)
+{
+ NvFlowGridEmitParams& emitParams = m_teapotEmitParams;
+ emitParams.bounds.x.x = m_emitterScale.x;
+ emitParams.bounds.y.y = m_emitterScale.y;
+ emitParams.bounds.z.z = m_emitterScale.z;
+ emitParams.bounds.w.x = m_emitterOffset.x;
+ emitParams.bounds.w.y = m_emitterOffset.y;
+ emitParams.bounds.w.z = m_emitterOffset.z;
+
+ emitParams.velocityCoupleRate = { 1000.f, 1000.f, 1000.f };
+
+ emitParams.temperature = 0.f;
+ emitParams.temperatureCoupleRate = 10.f;
+
+ emitParams.fuel = 0.f;
+ emitParams.fuelCoupleRate = 10.f;
+
+ emitParams.smoke = 0.f;
+ emitParams.smokeCoupleRate = 10.f;
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sdf.sdfOffset = 0u; // m_teapotShape;
+
+ emitParams.localToWorld = emitParams.bounds;
+ emitParams.shapeType = eNvFlowShapeTypeSDF;
+ emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &emitParams, 1u);
+
+ NvFlowShapeSDF* sdfs[] = { m_teapotShape };
+ NvFlowGridUpdateEmitSDFs(m_flowGridActor.m_grid, sdfs, 1u);
+
+ // animate emitter
+ if (m_animate)
+ {
+ m_time += dt;
+
+ const float rate = 2.f;
+ const float period = 2.f * 3.14159265f / rate;
+ if (m_time > period) m_time -= period;
+
+ m_emitParams.bounds.w.x = 0.15f * sinf(rate * m_time);
+ m_emitParams.bounds.w.z = 0.f;
+ }
+ else
+ {
+ m_emitParams.bounds.w.x = 0.f;
+ m_emitParams.bounds.w.z = 0.f;
+
+ m_time = 0.f;
+ }
+
+ SceneSimpleFlame::doUpdate(dt);
+}
+
+void SceneSimpleFlameMesh::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ MeshInteropContextUpdate(m_meshContext, m_appctx);
+
+ MeshDrawParams meshDrawParams;
+ meshDrawParams.renderMode = MESH_RENDER_SOLID;
+ meshDrawParams.projection = projection;
+ meshDrawParams.view = view;
+ meshDrawParams.model = DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixScaling(m_emitterScale.x * m_sdfScale.x, m_emitterScale.y * m_sdfScale.y, m_emitterScale.z * m_sdfScale.z),
+ DirectX::XMMatrixTranslation(m_emitterOffset.x, m_emitterOffset.y, m_emitterOffset.z)
+ );
+
+ if (m_shouldDrawMesh)
+ {
+ MeshDraw(m_mesh, &meshDrawParams);
+ }
+
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameMesh::imguiFluidRenderExtra()
+{
+ if (imguiserCheck("Draw Mesh", m_shouldDrawMesh, true))
+ {
+ m_shouldDrawMesh = !m_shouldDrawMesh;
+ }
+}
+
+void SceneSimpleFlameMesh::imguiFluidEmitterExtra()
+{
+ if (imguiserCheck("Animate", m_animate, true))
+ {
+ m_animate = !m_animate;
+ }
+ imguiSeparatorLine();
+ imguiLabel("Teapot");
+ imguiserBeginGroup("Teapot", nullptr);
+
+ imguiserSlider("Max Emit Dist", &m_teapotEmitParams.maxActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Min Emit Dist", &m_teapotEmitParams.minActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Slip Thickness", &m_teapotEmitParams.slipThickness, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Slip Factor", &m_teapotEmitParams.slipFactor, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release Temp", &m_teapotEmitParams.fuelReleaseTemp, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release", &m_teapotEmitParams.fuelRelease, 0.f, 10.f, 0.1f, true);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameCulling ************************
+
+void SceneSimpleFlameCulling::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.allocationScale = { 2.f, 2.f, 2.f };
+ m_emitParams.allocationPredict = 0.4f;
+}
+
+void SceneSimpleFlameCulling::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // main emitter
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.box.halfSize = { 0.8f, 0.8f, 0.8f };
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeBox;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+ }
+
+ // grid of emitters
+ {
+ const int r = m_emitGridR;
+ const float scale = 0.125f;
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ NvFlowGridEmitParams emitParams;
+
+ NvFlowGridEmitParamsDefaults(&emitParams);
+
+ emitParams.bounds.x.x = 0.25f;
+ emitParams.bounds.y.y = 0.25f;
+ emitParams.bounds.z.z = 0.25f;
+
+ emitParams.maxActiveDist = -0.08f;
+ emitParams.slipThickness = 0.25f;
+ emitParams.slipFactor = 0.9f;
+
+ emitParams.velocityCoupleRate = { 1000.f, 1000.f, 1000.f };
+
+ emitParams.temperature = 0.f;
+ emitParams.temperatureCoupleRate = 10.f;
+
+ emitParams.fuel = 0.f;
+ emitParams.fuelCoupleRate = 10.f;
+
+ emitParams.smoke = 0.f;
+ emitParams.smokeCoupleRate = 10.f;
+
+ emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ emitParams.allocationPredict = 0.f;
+
+ for (int j = -r; j <= r; j++)
+ {
+ for (int i = -r; i <= r; i++)
+ {
+ if (i == 0 && j == 0) continue;
+
+ emitParams.bounds.w.x = scale * float(i);
+ emitParams.bounds.w.y = 0.f;
+ emitParams.bounds.w.z = scale * float(j);
+
+ emitParams.localToWorld = emitParams.bounds;
+ emitParams.shapeType = eNvFlowShapeTypeSphere;
+ emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &emitParams, 1u);
+ }
+ }
+ }
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameCulling::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Culling");
+ imguiserBeginGroup("Culling", nullptr);
+
+ float r = float(m_emitGridR);
+ imguiserSlider("Emit Grid R", &r, 0.f, 16.f, 1.f, true);
+ m_emitGridR = NvFlowUint(r);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameConvex ************************
+
+void SceneSimpleFlameConvex::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.minActiveDist = -0.3f;
+ m_emitParams.fuel = 2.5f;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.5f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.5f;
+}
+
+void SceneSimpleFlameConvex::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc[8];
+ const float a = 0.866f;
+ const float b = 0.5f;
+ const float d = 4.f * m_size;
+ shapeDesc[0].plane = { +1.f, 0.f, 0.f, d };
+ shapeDesc[1].plane = { -1.f, 0.f, 0.f, d };
+ shapeDesc[2].plane = { +b, 0.f, +a, d };
+ shapeDesc[3].plane = { +b, 0.f, -a, d };
+ shapeDesc[4].plane = { -b, 0.f, +a, d };
+ shapeDesc[5].plane = { -b, 0.f, -a, d };
+ shapeDesc[6].plane = { 0.f, +1.f, 0.f, 0.8f };
+ shapeDesc[7].plane = { 0.f, -1.f, 0.f, 0.8f };
+
+ m_emitParams.bounds.x.x = m_size + 0.25f;
+ //m_emitParams.bounds.y.y = m_barLength;
+ m_emitParams.bounds.z.z = m_size + 0.25f;
+
+ m_emitParams.localToWorld = NvFlowFloat4x4{
+ 0.25f, 0.f, 0.f, 0.f,
+ 0.f, 0.25f, 0.f, 0.f,
+ 0.f, 0.f, 0.25f, 0.f,
+ m_emitParams.bounds.w.x, m_emitParams.bounds.w.y, m_emitParams.bounds.w.z, 1.f
+ };
+ m_emitParams.shapeType = eNvFlowShapeTypePlane;
+ m_emitParams.shapeDistScale = m_distanceScale;
+ m_emitParams.shapeRangeOffset = 0u;
+ m_emitParams.shapeRangeSize = 8u;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, shapeDesc, 8u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameConvex::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Bar");
+ imguiserBeginGroup("Bar", nullptr);
+
+ imguiserSlider("Size", &m_size, 0.f, 4.f, 0.1f, true);
+ imguiserSlider("Distance Scale", &m_distanceScale, 0.1f, 3.f, 0.025f, true);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameCapsule ************************
+
+void SceneSimpleFlameCapsule::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.minActiveDist = -0.3f;
+ m_emitParams.fuel = 2.5f;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.5f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.5f;
+}
+
+void SceneSimpleFlameCapsule::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ if (shouldUpdate)
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc[1];
+ shapeDesc[0].capsule.radius = m_capsuleRadius;
+ shapeDesc[0].capsule.length = m_capsuleLength;
+
+ // generate bounds based on radius and length
+ const float boundInflate = 0.25f;
+ float xbound = 2.f * m_capsuleRadius + m_capsuleLength + boundInflate;
+ float yzbound = 2.f * m_capsuleRadius + boundInflate;
+ m_emitParams.bounds.x.x = 0.5f * xbound;
+ m_emitParams.bounds.y.y = 0.5f * yzbound;
+ m_emitParams.bounds.z.z = 0.5f * yzbound;
+
+ m_emitParams.localToWorld = NvFlowFloat4x4{
+ 1.f, 0.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ m_emitParams.bounds.w.x, m_emitParams.bounds.w.y, m_emitParams.bounds.w.z, 1.f
+ };
+
+ m_emitParams.shapeType = eNvFlowShapeTypeCapsule;
+ m_emitParams.shapeDistScale = m_distanceScale;
+ m_emitParams.deltaTime = dt;
+
+ if (m_boxMode)
+ {
+ m_emitParams.shapeType = eNvFlowShapeTypeBox;
+ shapeDesc[0].box.halfSize.x = 0.5f * m_capsuleLength + m_capsuleRadius;
+ shapeDesc[0].box.halfSize.y = m_capsuleRadius;
+ shapeDesc[0].box.halfSize.z = 0.5f * m_capsuleRadius;
+ }
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameCapsule::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Bar");
+ imguiserBeginGroup("Bar", nullptr);
+
+ imguiserSlider("Capsule Radius", &m_capsuleRadius, 0.f, 1.f, 0.1f, true);
+ imguiserSlider("Capsule Length", &m_capsuleLength, 0.f, 3.f, 0.1f, true);
+ imguiserSlider("Distance Scale", &m_distanceScale, 0.1f, 5.f, 0.025f, true);
+
+ if (imguiserCheck("Box mode", m_boxMode, true))
+ {
+ m_boxMode = !m_boxMode;
+ }
+
+ imguiserEndGroup();
+} \ No newline at end of file
diff --git a/demo/DemoApp/sceneSimpleSmoke.cpp b/demo/DemoApp/sceneSimpleSmoke.cpp
new file mode 100644
index 0000000..da5440d
--- /dev/null
+++ b/demo/DemoApp/sceneSimpleSmoke.cpp
@@ -0,0 +1,399 @@
+/*
+* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, related documentation
+* and any modifications thereto. Any use, reproduction, disclosure or
+* distribution of this software and related documentation without an express
+* license agreement from NVIDIA CORPORATION is strictly prohibited.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace PresetSmoke
+{
+#include "presetSmoke.h"
+}
+namespace PresetFireBall
+{
+#include "PresetFireBall.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+void SceneSimpleSmoke::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_emitParams.allocationPredict = 0.3f;
+
+ // grid actor overrides
+ m_flowGridActor.m_renderParams.renderMode = eNvFlowVolumeRenderMode_colormap;
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 1.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 0.f;
+ m_flowGridActor.m_gridParams.gravity = NvFlowFloat3{ 0.f, -1.f, 0.f };
+
+ m_flowGridActor.m_enableVolumeShadow = true;
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneSimpleSmoke::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ if (m_flowGridActor.m_enableVolumeShadow)
+ {
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 1.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 0.f;
+ }
+ else
+ {
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 1.f;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] = {
+ { 0.f, 0.f,0.f,0.f,0.f },
+ { 0.05f, 0.f,0.f,0.f,0.5f },
+ { 0.6f, 213.f / 255.f,100.f / 255.f,30.f / 255.f,0.8f },
+ { 0.85f, 255.f / 255.f,240.f / 255.f,0.f,0.8f },
+ { 1.f, 1.f,1.f,1.f,0.7f }
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+}
+
+NvFlowFloat3 SceneSimpleSmoke::positionFunc(float theta)
+{
+ return NvFlowFloat3{
+ 3.f * cosf(theta),
+ 0.f,
+ 3.f * sinf(theta)
+ };
+}
+
+NvFlowFloat3 SceneSimpleSmoke::velocityFunc(float theta, float rate)
+{
+ return NvFlowFloat3{
+ -3.f * rate * sinf(theta),
+ 0.f,
+ +3.f * rate * cosf(theta)
+ };
+}
+
+void SceneSimpleSmoke::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ if (m_animate)
+ {
+ const float pi2 = 2.f * 3.14159265f;
+ const float emitterScale = 1.f;
+
+ theta += pi2 * rate * dt;
+
+ if (theta > pi2) theta -= pi2;
+
+ // get position and velocity
+ NvFlowFloat3 position = positionFunc(theta);
+ NvFlowFloat3 velocity = velocityFunc(theta, pi2 * rate);
+
+ // update emitter bounds
+ m_emitParams.bounds.x.x = 0.25f * emitterScale;
+ m_emitParams.bounds.y.y = 0.25f * emitterScale;
+ m_emitParams.bounds.z.z = 0.25f * emitterScale;
+
+ // modulate couple rate as a function of velocity and emitter width
+ const float defaultCoupleRate = 0.5f;
+
+ float emitWidth = m_emitParams.bounds.x.x;
+
+ float velMagn = sqrtf(velocity.x*velocity.x + velocity.y*velocity.y + velocity.z*velocity.z);
+ float coupleRate = fmaxf(coupleRateScale * fabsf(velMagn) / emitWidth, defaultCoupleRate);
+
+ m_emitParams.smokeCoupleRate = coupleRate;
+ m_emitParams.temperatureCoupleRate = coupleRate;
+ m_emitParams.fuelCoupleRate = coupleRate;
+ m_emitParams.velocityCoupleRate = { coupleRate, coupleRate, coupleRate };
+
+ m_emitParams.bounds.w.x = position.x;
+ m_emitParams.bounds.w.y = position.y;
+ m_emitParams.bounds.w.z = position.z;
+ m_emitParams.velocityLinear.x = velocity.x;
+ //m_emitParams.velocityLinear.y = velocity.y;
+ m_emitParams.velocityLinear.z = velocity.z;
+
+ m_emitParams.predictVelocityWeight = 1.f;
+ m_emitParams.predictVelocity.x = velocity.x;
+ //m_emitParams.predictVelocity.y = velocity.y;
+ m_emitParams.predictVelocity.z = velocity.z;
+ }
+ else if (m_animate != m_animateOld)
+ {
+ float coupleRate = 0.5f;
+
+ m_emitParams.smokeCoupleRate = coupleRate;
+ m_emitParams.temperatureCoupleRate = coupleRate;
+ m_emitParams.fuelCoupleRate = coupleRate;
+ m_emitParams.velocityCoupleRate = { coupleRate, coupleRate, coupleRate };
+
+ m_emitParams.bounds.w.x = 0.f;
+ m_emitParams.velocityLinear.x = 0.f;
+
+ m_emitParams.predictVelocityWeight = 0.f;
+ m_emitParams.predictVelocity.x = 0.f;
+ m_emitParams.predictVelocity.y = 0.f;
+ m_emitParams.predictVelocity.z = 0.f;
+ }
+ m_animateOld = m_animate;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleSmoke::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneSimpleSmoke::imguiFluidEmitterExtra()
+{
+ if (imguiserCheck("Animate", m_animate, true))
+ {
+ m_animate = !m_animate;
+ }
+}
+
+void SceneSimpleSmoke::imguiFluidRenderExtra()
+{
+}
+
+void SceneSimpleSmoke::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSimpleSmoke::release()
+{
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ m_flowContext.release();
+}
+
+void SceneSimpleSmoke::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(PresetSmoke::g_root, sizeof(PresetSmoke::g_root));
+ m_shouldLoadPreset = false;
+ }
+}
+
+// ******************************* SceneSimpleFlameBall *************************
+
+void SceneSimpleFlameBall::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_flowGridActor.m_gridDesc.lowLatencyMapping = true;
+ m_flowGridActor.m_memoryLimit = 4.f;
+
+ m_flowGridActor.m_materialParams.smoke.allocWeight = 1.f;
+ m_flowGridActor.m_materialParams.smoke.allocThreshold = 0.02f;
+
+ m_flowGridActor.m_gridParams.gravity = { 0.f, -0.5f, 0.f };
+
+ m_flowGridActor.m_gridParams.bigEffectMode = true;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.3f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.65f;
+ m_flowGridActor.m_materialParams.vorticityStrength = 20.f;
+
+ m_emitParams.fuel = 2.0f;
+ m_emitParams.temperature = 3.f;
+ m_emitParams.smoke = 0.5f;
+
+ m_emitParams.bounds.x.x = m_radius;
+ m_emitParams.bounds.y.y = m_radius;
+ m_emitParams.bounds.z.z = m_radius;
+
+ m_emitParams.bounds.w.y = -2.f;
+
+ m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ m_emitParams.allocationPredict = 0.05f;
+
+ // grid actor overrides
+ m_flowGridActor.m_renderParams.renderMode = eNvFlowVolumeRenderMode_colormap;
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 1.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 0.f;
+
+ m_flowGridActor.m_shadowBlendCompMask = { -2.f, 0.f, 0.f, 0.f };
+ m_flowGridActor.m_shadowBlendBias = 1.f;
+
+ m_flowGridActor.m_enableVolumeShadow = true;
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneSimpleFlameBall::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ if (m_flowGridActor.m_enableVolumeShadow)
+ {
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 1.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 0.f;
+ }
+ else
+ {
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityCompMask = { 0.f, 0.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialDefaultParams.intensityBias = 1.f;
+ }
+}
+
+void SceneSimpleFlameBall::doUpdate(float dt)
+{
+ time += dt;
+
+ m_emitParams.bounds.x.x = m_radius;
+ m_emitParams.bounds.y.y = m_radius;
+ m_emitParams.bounds.z.z = m_radius;
+
+ if (time < 0.25f)
+ {
+ m_emitParams.fuelCoupleRate = 0.f;
+ m_emitParams.velocityCoupleRate = { 0.f, 0.f, 0.f };
+ m_emitParams.smokeCoupleRate = 0.f;
+ m_emitParams.temperatureCoupleRate = 0.f;
+ //m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ }
+ else if (time < 0.75f)
+ {
+ const float coupleRate = 5.f;
+ m_emitParams.fuelCoupleRate = coupleRate;
+ m_emitParams.velocityCoupleRate = { coupleRate, coupleRate, coupleRate };
+ m_emitParams.smokeCoupleRate = coupleRate;
+ m_emitParams.temperatureCoupleRate = coupleRate;
+ //m_emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ }
+ else if (time < 4.f)
+ {
+ m_emitParams.fuelCoupleRate = 0.f;
+ m_emitParams.velocityCoupleRate = { 0.f, 0.f, 0.f };
+ m_emitParams.smokeCoupleRate = 0.f;
+ m_emitParams.temperatureCoupleRate = 0.f;
+ //m_emitParams.allocationScale = { 0.f, 0.f, 0.f };
+ }
+ else
+ {
+ time = 0.f;
+ }
+
+ SceneSimpleFlame::doUpdate(dt);
+}
+
+void SceneSimpleFlameBall::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameBall::release()
+{
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameBall::imguiFluidEmitterExtra()
+{
+ imguiserSlider("Radius", &m_radius, 0.1f, 2.f, 0.05f, true);
+}
+
+void SceneSimpleFlameBall::imguiFluidRenderExtra()
+{
+}
+
+void SceneSimpleFlameBall::imguiFluidSimExtra()
+{
+}
+
+void SceneSimpleFlameBall::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(PresetFireBall::g_root, sizeof(PresetFireBall::g_root));
+ m_shouldLoadPreset = false;
+ }
+} \ No newline at end of file
diff --git a/demo/DemoApp/stb_truetype.h b/demo/DemoApp/stb_truetype.h
new file mode 100644
index 0000000..be40bcb
--- /dev/null
+++ b/demo/DemoApp/stb_truetype.h
@@ -0,0 +1,1839 @@
+// stb_truetype.h - v0.3 - public domain - 2009 Sean Barrett / RAD Game Tools
+//
+// This library processes TrueType files:
+// parse files
+// extract glyph metrics
+// extract glyph shapes
+// render glyphs to one-channel bitmaps with antialiasing (box filter)
+//
+// Todo:
+// non-MS cmaps
+// crashproof on bad data
+// hinting
+// subpixel positioning when rendering bitmap
+// cleartype-style AA
+//
+// ADDITIONAL CONTRIBUTORS
+//
+// Mikko Mononen: compound shape support, more cmap formats
+//
+// VERSIONS
+//
+// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)
+// userdata, malloc-from-userdata, non-zero fill (STB)
+// 0.2 (2009-03-11) Fix unsigned/signed char warnings
+// 0.1 (2009-03-09) First public release
+//
+// USAGE
+//
+// Include this file in whatever places neeed to refer to it. In ONE C/C++
+// file, write:
+// #define STB_TRUETYPE_IMPLEMENTATION
+// before the #include of this file. This expands out the actual
+// implementation into that C/C++ file.
+//
+// Look at the header-file sections below for the API, but here's a quick skim:
+//
+// Simple 3D API (don't ship this, but it's fine for tools and quick start,
+// and you can cut and paste from it to move to more advanced)
+// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture
+// stbtt_GetBakedQuad() -- compute quad to draw for a given char
+//
+// "Load" a font file from a memory buffer (you have to keep the buffer loaded)
+// stbtt_InitFont()
+// stbtt_GetFontOffsetForIndex() -- use for TTC font collections
+//
+// Render a unicode codepoint to a bitmap
+// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
+// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
+// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
+//
+// Character advance/positioning
+// stbtt_GetCodepointHMetrics()
+// stbtt_GetFontVMetrics()
+//
+// NOTES
+//
+// The system uses the raw data found in the .ttf file without changing it
+// and without building auxiliary data structures. This is a bit inefficient
+// on little-endian systems (the data is big-endian), but assuming you're
+// caching the bitmaps or glyph shapes this shouldn't be a big deal.
+//
+// It appears to be very hard to programmatically determine what font a
+// given file is in a general way. I provide an API for this, but I don't
+// recommend it.
+//
+//
+// SOURCE STATISTICS (based on v0.3, 1800 LOC)
+//
+// Documentation & header file 350 LOC \___ 500 LOC documentation
+// Sample code 140 LOC /
+// Truetype parsing 580 LOC ---- 600 LOC TrueType
+// Software rasterization 240 LOC \ .
+// Curve tesselation 120 LOC \__ 500 LOC Bitmap creation
+// Bitmap management 70 LOC /
+// Baked bitmap interface 70 LOC /
+// Font name matching & access 150 LOC ---- 150
+// C runtime library abstraction 60 LOC ---- 60
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+//// SAMPLE PROGRAMS
+////
+//
+// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
+//
+#if 0
+#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
+#include "stb_truetype.h"
+
+char ttf_buffer[1 << 20];
+unsigned char temp_bitmap[512 * 512];
+
+stbtt_chardata cdata[96]; // ASCII 32..126 is 95 glyphs
+GLstbtt_uint ftex;
+
+void my_stbtt_initfont(void)
+{
+ fread(ttf_buffer, 1, 1 << 20, fopen("c:/windows/fonts/times.ttf", "rb"));
+ stbtt_BakeFontBitmap(data, 0, 32.0, temp_bitmap, 512, 512, 32, 96, cdata); // no guarantee this fits!
+ // can free ttf_buffer at this point
+ glGenTextures(1, &ftex);
+ glBindTexture(GL_TEXTURE_2D, ftex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512, 512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
+ // can free temp_bitmap at this point
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+void my_stbtt_print(float x, float y, char *text)
+{
+ // assume orthographic projection with units = screen pixels, origin at top left
+ glBindTexture(GL_TEXTURE_2D, ftex);
+ glBegin(GL_QUADS);
+ while (*text) {
+ if (*text >= 32 && *text < 128) {
+ stbtt_aligned_quad q;
+ stbtt_GetBakedQuad(cdata, 512, 512, *text - 32, &x, &y, &q, 1);//1=opengl,0=old d3d
+ glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y0);
+ glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y0);
+ glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y1);
+ glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y1);
+ }
+ ++text;
+ }
+ glEnd();
+}
+#endif
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Complete program (this compiles): get a single bitmap, print as ASCII art
+//
+#if 0
+#include <stdio.h>
+#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
+#include "stb_truetype.h"
+
+char ttf_buffer[1 << 25];
+
+int main(int argc, char **argv)
+{
+ stbtt_fontinfo font;
+ unsigned char *bitmap;
+ int w, h, i, j, c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
+
+ fread(ttf_buffer, 1, 1 << 25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
+
+ stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
+ bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0, 0);
+
+ for (j = 0; j < h; ++j) {
+ for (i = 0; i < w; ++i)
+ putchar(" .:ioVM@"[bitmap[j*w + i] >> 5]);
+ putchar('\n');
+ }
+ return 0;
+}
+#endif
+//
+// Output:
+//
+// .ii.
+// @@@@@@.
+// V@Mio@@o
+// :i. V@V
+// :oM@@M
+// :@@@MM@M
+// @@o o@M
+// :@@. M@M
+// @@@o@@@@
+// :M@@V:@@.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Complete program: print "Hello World!" banner, with bugs
+//
+#if 0
+int main(int arg, char **argv)
+{
+ unsigned char screen[20][79];
+ int i, j, pos = 0;
+ float scale;
+ char *text = "Heljo World!";
+
+ fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
+ stbtt_InitFont(&font, buffer, 0);
+
+ scale = stbtt_ScaleForPixelHeight(&font, 16);
+ memset(screen, 0, sizeof(screen));
+
+ while (*text) {
+ int advance, lsb, x0, y0, x1, y1, newpos, baseline = 13;
+ stbtt_GetCodepointHMetrics(&font, *text, &advance, &lsb);
+ stbtt_GetCodepointBitmapBox(&font, *text, scale, scale, &x0, &y0, &x1, &y1);
+ newpos = pos + (int)(lsb * scale) + x0;
+ stbtt_MakeCodepointBitmap(&font, &screen[baseline + y0][newpos], x1 - x0, y1 - y0, 79, scale, scale, *text);
+ // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
+ // because this API is really for baking character bitmaps into textures
+ pos += (int)(advance * scale);
+ ++text;
+ }
+
+ for (j = 0; j < 20; ++j) {
+ for (i = 0; i < 79; ++i)
+ putchar(" .:ioVM@"[screen[j][i] >> 5]);
+ putchar('\n');
+ }
+
+ return 0;
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+////
+//// INTEGRATION WITH RUNTIME LIBRARIES
+////
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+// #define your own (u)stbtt_int8/16/32 before including to override this
+#ifndef stbtt_uint8
+typedef unsigned char stbtt_uint8;
+typedef signed char stbtt_int8;
+typedef unsigned short stbtt_uint16;
+typedef signed short stbtt_int16;
+typedef unsigned int stbtt_uint32;
+typedef signed int stbtt_int32;
+#endif
+
+typedef char stbtt__check_size32[sizeof(stbtt_int32) == 4 ? 1 : -1];
+typedef char stbtt__check_size16[sizeof(stbtt_int16) == 2 ? 1 : -1];
+
+// #define your own STBTT_sort() to override this to avoid qsort
+#ifndef STBTT_sort
+#include <stdlib.h>
+#define STBTT_sort(data,num_items,item_size,compare_func) qsort(data,num_items,item_size,compare_func)
+#endif
+
+// #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
+#ifndef STBTT_ifloor
+#include <math.h>
+#define STBTT_ifloor(x) ((int) floor(x))
+#define STBTT_iceil(x) ((int) ceil(x))
+#endif
+
+// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
+#ifndef STBTT_malloc
+#include <malloc.h>
+#define STBTT_malloc(x,u) malloc(x)
+#define STBTT_free(x,u) free(x)
+#endif
+
+#ifndef STBTT_assert
+#include <assert.h>
+#define STBTT_assert(x) assert(x)
+#endif
+
+#ifndef STBTT_strlen
+#include <string.h>
+#define STBTT_strlen(x) strlen(x)
+#endif
+
+#ifndef STBTT_memcpy
+#include <memory.h>
+#define STBTT_memcpy memcpy
+#define STBTT_memset memset
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+//// INTERFACE
+////
+////
+
+#ifndef __STB_INCLUDE_STB_TRUETYPE_H__
+#define __STB_INCLUDE_STB_TRUETYPE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // TEXTURE BAKING API
+ //
+ // If you use this API, you only have to call two functions ever.
+ //
+
+ typedef struct
+ {
+ unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap
+ float xoff, yoff, xadvance;
+ } stbtt_bakedchar;
+
+ extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
+ float pixel_height, // height of font in pixels
+ unsigned char *pixels, int pw, int ph, // bitmap to be filled in
+ int first_char, int num_chars, // characters to bake
+ stbtt_bakedchar *chardata); // you allocate this, it's num_chars long
+ // if return is positive, the first unused row of the bitmap
+ // if return is negative, returns the negative of the number of characters that fit
+ // if return is 0, no characters fit and no rows were used
+ // This uses a very crappy packing.
+
+ typedef struct
+ {
+ float x0, y0, s0, t0; // top-left
+ float x1, y1, s1, t1; // bottom-right
+ } stbtt_aligned_quad;
+
+ extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above
+ int char_index, // character to display
+ float *xpos, float *ypos, // pointers to current position in screen pixel space
+ stbtt_aligned_quad *q, // output: quad to draw
+ int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier
+ // Call GetBakedQuad with char_index = 'character - first_char', and it
+ // creates the quad you need to draw and advances the current position.
+ // It's inefficient; you might want to c&p it and optimize it.
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // FONT LOADING
+ //
+ //
+
+ extern int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
+ // Each .ttf file may have more than one font. Each has a sequential index
+ // number starting from 0. Call this function to get the font offset for a
+ // given index; it returns -1 if the index is out of range. A regular .ttf
+ // file will only define one font and it always be at offset 0, so it will
+ // return '0' for index 0, and -1 for all other indices. You can just skip
+ // this step if you know it's that kind of font.
+
+
+ // The following structure is defined publically so you can declare one on
+ // the stack or as a global or etc.
+ typedef struct
+ {
+ void *userdata;
+ unsigned char *data; // pointer to .ttf file
+ int fontstart; // offset of start of font
+
+ int numGlyphs; // number of glyphs, needed for range checking
+
+ int loca, head, glyf, hhea, hmtx; // table locations as offset from start of .ttf
+ int index_map; // a cmap mapping for our chosen character encoding
+ int indexToLocFormat; // format needed to map from glyph index to glyph
+ } stbtt_fontinfo;
+
+ extern int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
+ // Given an offset into the file that defines a font, this function builds
+ // the necessary cached info for the rest of the system. You must allocate
+ // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
+ // need to do anything special to free it, because the contents are a pure
+ // cache with no additional data structures. Returns 0 on failure.
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // CHARACTER TO GLYPH-INDEX CONVERSIOn
+
+ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
+ // If you're going to perform multiple operations on the same character
+ // and you want a speed-up, call this function with the character you're
+ // going to process, then use glyph-based functions instead of the
+ // codepoint-based functions.
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // CHARACTER PROPERTIES
+ //
+
+ extern float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
+ // computes a scale factor to produce a font whose "height" is 'pixels' tall.
+ // Height is measured as the distance from the highest ascender to the lowest
+ // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
+ // and computing:
+ // scale = pixels / (ascent - descent)
+ // so if you prefer to measure height by the ascent only, use a similar calculation.
+
+ extern void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
+ // ascent is the coordinate above the baseline the font extends; descent
+ // is the coordinate below the baseline the font extends (i.e. it is typically negative)
+ // lineGap is the spacing between one row's descent and the next row's ascent...
+ // so you should advance the vertical position by "*ascent - *descent + *lineGap"
+ // these are expressed in unscaled coordinates
+
+ extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
+ // leftSideBearing is the offset from the current horizontal position to the left edge of the character
+ // advanceWidth is the offset from the current horizontal position to the next horizontal position
+ // these are expressed in unscaled coordinates
+
+ extern int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
+ // an additional amount to add to the 'advance' value between ch1 and ch2
+ // @TODO; for now always returns 0!
+
+ extern int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
+ // Gets the bounding box of the visible part of the glyph, in unscaled coordinates
+
+ extern void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
+ extern int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
+ extern int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+ // as above, but takes one or more glyph indices for greater efficiency
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // GLYPH SHAPES (you probably don't need these, but they have to go before
+ // the bitmaps for C declaration-order reasons)
+ //
+
+#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
+ enum {
+ STBTT_vmove = 1,
+ STBTT_vline,
+ STBTT_vcurve
+ };
+#endif
+
+#ifndef stbtt_vertex // you can predefine this to use different values
+ // (we share this with other code at RAD)
+#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
+ typedef struct
+ {
+ stbtt_vertex_type x, y, cx, cy;
+ unsigned char type, padding;
+ } stbtt_vertex;
+#endif
+
+ extern int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
+ extern int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
+ // returns # of vertices and fills *vertices with the pointer to them
+ // these are expressed in "unscaled" coordinates
+
+ extern void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
+ // frees the data allocated above
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // BITMAP RENDERING
+ //
+
+ extern void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
+ // frees the bitmap allocated below
+
+ extern unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
+ // allocates a large-enough single-channel 8bpp bitmap and renders the
+ // specified character/glyph at the specified scale into it, with
+ // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
+ // *width & *height are filled out with the width & height of the bitmap,
+ // which is stored left-to-right, top-to-bottom.
+ //
+ // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
+
+ extern void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
+ // the same as above, but you pass in storage for the bitmap in the form
+ // of 'output', with row spacing of 'out_stride' bytes. the bitmap is
+ // clipped to out_w/out_h bytes. call the next function to get the
+ // height and width and positioning info
+
+ extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+ // get the bbox of the bitmap centered around the glyph origin; so the
+ // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
+ // the bitmap top left is (leftSideBearing*scale,iy0).
+ // (Note that the bitmap uses y-increases-down, but the shape uses
+ // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
+
+ extern unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
+ extern void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+ extern void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
+
+ //extern void stbtt_get_true_bbox(stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
+
+ // @TODO: don't expose this structure
+ typedef struct
+ {
+ int w, h, stride;
+ unsigned char *pixels;
+ } stbtt__bitmap;
+
+ extern void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata);
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // Finding the right font...
+ //
+ // You should really just solve this offline, keep your own tables
+ // of what font is what, and don't try to get it out of the .ttf file.
+ // That's because getting it out of the .ttf file is really hard, because
+ // the names in the file can appear in many possible encodings, in many
+ // possible languages, and e.g. if you need a case-insensitive comparison,
+ // the details of that depend on the encoding & language in a complex way
+ // (actually underspecified in truetype, but also gigantic).
+ //
+ // But you can use the provided functions in two possible ways:
+ // stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
+ // unicode-encoded names to try to find the font you want;
+ // you can run this before calling stbtt_InitFont()
+ //
+ // stbtt_GetFontNameString() lets you get any of the various strings
+ // from the file yourself and do your own comparisons on them.
+ // You have to have called stbtt_InitFont() first.
+
+
+ extern int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
+ // returns the offset (not index) of the font that matches, or -1 if none
+ // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
+ // if you use any other flag, use a font name like "Arial"; this checks
+ // the 'macStyle' header field; i don't know if fonts set this consistently
+#define STBTT_MACSTYLE_DONTCARE 0
+#define STBTT_MACSTYLE_BOLD 1
+#define STBTT_MACSTYLE_ITALIC 2
+#define STBTT_MACSTYLE_UNDERSCORE 4
+#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0
+
+ extern int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
+ // returns 1/0 whether the first string interpreted as utf8 is identical to
+ // the second string interpreted as big-endian utf16... useful for strings from next func
+
+ extern char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
+ // returns the string (which may be big-endian double byte, e.g. for unicode)
+ // and puts the length in bytes in *length.
+ //
+ // some of the values for the IDs are below; for more see the truetype spec:
+ // http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+ // http://www.microsoft.com/typography/otspec/name.htm
+
+ enum { // platformID
+ STBTT_PLATFORM_ID_UNICODE = 0,
+ STBTT_PLATFORM_ID_MAC = 1,
+ STBTT_PLATFORM_ID_ISO = 2,
+ STBTT_PLATFORM_ID_MICROSOFT = 3
+ };
+
+ enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
+ STBTT_UNICODE_EID_UNICODE_1_0 = 0,
+ STBTT_UNICODE_EID_UNICODE_1_1 = 1,
+ STBTT_UNICODE_EID_ISO_10646 = 2,
+ STBTT_UNICODE_EID_UNICODE_2_0_BMP = 3,
+ STBTT_UNICODE_EID_UNICODE_2_0_FULL = 4,
+ };
+
+ enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
+ STBTT_MS_EID_SYMBOL = 0,
+ STBTT_MS_EID_UNICODE_BMP = 1,
+ STBTT_MS_EID_SHIFTJIS = 2,
+ STBTT_MS_EID_UNICODE_FULL = 10,
+ };
+
+ enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
+ STBTT_MAC_EID_ROMAN = 0, STBTT_MAC_EID_ARABIC = 4,
+ STBTT_MAC_EID_JAPANESE = 1, STBTT_MAC_EID_HEBREW = 5,
+ STBTT_MAC_EID_CHINESE_TRAD = 2, STBTT_MAC_EID_GREEK = 6,
+ STBTT_MAC_EID_KOREAN = 3, STBTT_MAC_EID_RUSSIAN = 7,
+ };
+
+ enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
+ // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
+ STBTT_MS_LANG_ENGLISH = 0x0409, STBTT_MS_LANG_ITALIAN = 0x0410,
+ STBTT_MS_LANG_CHINESE = 0x0804, STBTT_MS_LANG_JAPANESE = 0x0411,
+ STBTT_MS_LANG_DUTCH = 0x0413, STBTT_MS_LANG_KOREAN = 0x0412,
+ STBTT_MS_LANG_FRENCH = 0x040c, STBTT_MS_LANG_RUSSIAN = 0x0419,
+ STBTT_MS_LANG_GERMAN = 0x0407, STBTT_MS_LANG_SPANISH = 0x0409,
+ STBTT_MS_LANG_HEBREW = 0x040d, STBTT_MS_LANG_SWEDISH = 0x041D,
+ };
+
+ enum { // languageID for STBTT_PLATFORM_ID_MAC
+ STBTT_MAC_LANG_ENGLISH = 0, STBTT_MAC_LANG_JAPANESE = 11,
+ STBTT_MAC_LANG_ARABIC = 12, STBTT_MAC_LANG_KOREAN = 23,
+ STBTT_MAC_LANG_DUTCH = 4, STBTT_MAC_LANG_RUSSIAN = 32,
+ STBTT_MAC_LANG_FRENCH = 1, STBTT_MAC_LANG_SPANISH = 6,
+ STBTT_MAC_LANG_GERMAN = 2, STBTT_MAC_LANG_SWEDISH = 5,
+ STBTT_MAC_LANG_HEBREW = 10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED = 33,
+ STBTT_MAC_LANG_ITALIAN = 3, STBTT_MAC_LANG_CHINESE_TRAD = 19,
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __STB_INCLUDE_STB_TRUETYPE_H__
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+////
+//// IMPLEMENTATION
+////
+////
+
+#ifdef STB_TRUETYPE_IMPLEMENTATION
+
+//////////////////////////////////////////////////////////////////////////
+//
+// accessors to parse data from file
+//
+
+// on platforms that don't allow misaligned reads, if we want to allow
+// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE
+
+#define ttBYTE(p) (* (stbtt_uint8 *) (p))
+#define ttCHAR(p) (* (stbtt_int8 *) (p))
+#define ttFixed(p) ttLONG(p)
+
+#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)
+
+#define ttUSHORT(p) (* (stbtt_uint16 *) (p))
+#define ttSHORT(p) (* (stbtt_int16 *) (p))
+#define ttULONG(p) (* (stbtt_uint32 *) (p))
+#define ttLONG(p) (* (stbtt_int32 *) (p))
+
+#else
+
+stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0] * 256 + p[1]; }
+stbtt_int16 ttSHORT(const stbtt_uint8 *p) { return p[0] * 256 + p[1]; }
+stbtt_uint32 ttULONG(const stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; }
+stbtt_int32 ttLONG(const stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; }
+
+#endif
+
+#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
+#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
+
+static int stbtt__isfont(const stbtt_uint8 *font)
+{
+ // check the version number
+ if (stbtt_tag(font, "1")) return 1; // TrueType 1
+ if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this!
+ if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF
+ if (stbtt_tag4(font, 0, 1, 0, 0)) return 1; // OpenType 1.0
+ return 0;
+}
+
+// @OPTIMIZE: binary search
+static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
+{
+ stbtt_int32 num_tables = ttUSHORT(data + fontstart + 4);
+ stbtt_uint32 tabledir = fontstart + 12;
+ stbtt_int32 i;
+ for (i = 0; i < num_tables; ++i) {
+ stbtt_uint32 loc = tabledir + 16 * i;
+ if (stbtt_tag(data + loc + 0, tag))
+ return ttULONG(data + loc + 8);
+ }
+ return 0;
+}
+
+int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)
+{
+ // if it's just a font, there's only one valid index
+ if (stbtt__isfont(font_collection))
+ return index == 0 ? 0 : -1;
+
+ // check if it's a TTC
+ if (stbtt_tag(font_collection, "ttcf")) {
+ // version 1?
+ if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) {
+ stbtt_int32 n = ttLONG(font_collection + 8);
+ if (index >= n)
+ return -1;
+ return ttULONG(font_collection + 12 + index * 14);
+ }
+ }
+ return -1;
+}
+
+int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)
+{
+ stbtt_uint8 *data = (stbtt_uint8 *)data2;
+ stbtt_uint32 cmap, t;
+ stbtt_int32 i, numTables;
+
+ info->data = data;
+ info->fontstart = fontstart;
+
+ cmap = stbtt__find_table(data, fontstart, "cmap");
+ info->loca = stbtt__find_table(data, fontstart, "loca");
+ info->head = stbtt__find_table(data, fontstart, "head");
+ info->glyf = stbtt__find_table(data, fontstart, "glyf");
+ info->hhea = stbtt__find_table(data, fontstart, "hhea");
+ info->hmtx = stbtt__find_table(data, fontstart, "hmtx");
+ if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
+ return 0;
+
+ t = stbtt__find_table(data, fontstart, "maxp");
+ if (t)
+ info->numGlyphs = ttUSHORT(data + t + 4);
+ else
+ info->numGlyphs = 0xffff;
+
+ // find a cmap encoding table we understand *now* to avoid searching
+ // later. (todo: could make this installable)
+ // the same regardless of glyph.
+ numTables = ttUSHORT(data + cmap + 2);
+ info->index_map = 0;
+ for (i = 0; i < numTables; ++i) {
+ stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
+ // find an encoding we understand:
+ switch (ttUSHORT(data + encoding_record)) {
+ case STBTT_PLATFORM_ID_MICROSOFT:
+ switch (ttUSHORT(data + encoding_record + 2)) {
+ case STBTT_MS_EID_UNICODE_BMP:
+ case STBTT_MS_EID_UNICODE_FULL:
+ // MS/Unicode
+ info->index_map = cmap + ttULONG(data + encoding_record + 4);
+ break;
+ }
+ break;
+ }
+ }
+ if (info->index_map == 0)
+ return 0;
+
+ info->indexToLocFormat = ttUSHORT(data + info->head + 50);
+ return 1;
+}
+
+int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
+{
+ stbtt_uint8 *data = info->data;
+ stbtt_uint32 index_map = info->index_map;
+
+ stbtt_uint16 format = ttUSHORT(data + index_map + 0);
+ if (format == 0) { // apple byte encoding
+ stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
+ if (unicode_codepoint < bytes - 6)
+ return ttBYTE(data + index_map + 6 + unicode_codepoint);
+ return 0;
+ }
+ else if (format == 6) {
+ stbtt_uint32 first = ttUSHORT(data + index_map + 6);
+ stbtt_uint32 count = ttUSHORT(data + index_map + 8);
+ if ((stbtt_uint32)unicode_codepoint >= first && (stbtt_uint32)unicode_codepoint < first + count)
+ return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) * 2);
+ return 0;
+ }
+ else if (format == 2) {
+ STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
+ return 0;
+ }
+ else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
+ stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1;
+ stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1;
+ stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10);
+ stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1;
+ stbtt_uint16 item, offset, start, end;
+
+ (void)end;
+
+ // do a binary search of the segments
+ stbtt_uint32 endCount = index_map + 14;
+ stbtt_uint32 search = endCount;
+
+ if (unicode_codepoint > 0xffff)
+ return 0;
+
+ // they lie from endCount .. endCount + segCount
+ // but searchRange is the nearest power of two, so...
+ if (unicode_codepoint >= ttUSHORT(data + search + rangeShift * 2))
+ search += rangeShift * 2;
+
+ // now decrement to bias correctly to find smallest
+ search -= 2;
+ while (entrySelector) {
+ stbtt_uint16 start, end;
+ searchRange >>= 1;
+ start = ttUSHORT(data + search + 2 + segcount * 2 + 2);
+ end = ttUSHORT(data + search + 2);
+ start = ttUSHORT(data + search + searchRange * 2 + segcount * 2 + 2);
+ end = ttUSHORT(data + search + searchRange * 2);
+ if (unicode_codepoint > end)
+ search += searchRange * 2;
+ --entrySelector;
+
+ (void)start;
+ }
+ search += 2;
+
+ item = (stbtt_uint16)((search - endCount) >> 1);
+
+ STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2 * item));
+ start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 * item);
+ end = ttUSHORT(data + index_map + 14 + 2 + 2 * item);
+ if (unicode_codepoint < start)
+ return 0;
+
+ offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 * item);
+ if (offset == 0)
+ return unicode_codepoint + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + 2 * item);
+
+ return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + 2 * item);
+ }
+ else if (format == 12) {
+ stbtt_uint16 ngroups = ttUSHORT(data + index_map + 6);
+ stbtt_int32 low, high;
+ low = 0; high = (stbtt_int32)ngroups;
+ // Binary search the right group.
+ while (low <= high) {
+ stbtt_int32 mid = low + ((high - low) >> 1); // rounds down, so low <= mid < high
+ stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid * 12);
+ stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 + 4);
+ if ((stbtt_uint32)unicode_codepoint < start_char)
+ high = mid - 1;
+ else if ((stbtt_uint32)unicode_codepoint > end_char)
+ low = mid + 1;
+ else {
+ stbtt_uint32 start_glyph = ttULONG(data + index_map + 16 + mid * 12 + 8);
+ return start_glyph + unicode_codepoint - start_char;
+ }
+ }
+ return 0; // not found
+ }
+ // @TODO
+ STBTT_assert(0);
+ return 0;
+}
+
+int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)
+{
+ return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);
+}
+
+static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int16 x, stbtt_int16 y, stbtt_int16 cx, stbtt_int16 cy)
+{
+ v->type = type;
+ v->x = x;
+ v->y = y;
+ v->cx = cx;
+ v->cy = cy;
+}
+
+static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
+{
+ int g1, g2;
+
+ if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
+ if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
+
+ if (info->indexToLocFormat == 0) {
+ g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
+ g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
+ }
+ else {
+ g1 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4);
+ g2 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4 + 4);
+ }
+
+ return g1 == g2 ? -1 : g1; // if length is 0, return -1
+}
+
+int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+ int g = stbtt__GetGlyfOffset(info, glyph_index);
+ if (g < 0) return 0;
+
+ if (x0) *x0 = ttSHORT(info->data + g + 2);
+ if (y0) *y0 = ttSHORT(info->data + g + 4);
+ if (x1) *x1 = ttSHORT(info->data + g + 6);
+ if (y1) *y1 = ttSHORT(info->data + g + 8);
+ return 1;
+}
+
+int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
+{
+ return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, x1, y1);
+}
+
+int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ stbtt_int16 numberOfContours;
+ stbtt_uint8 *endPtsOfContours;
+ stbtt_uint8 *data = info->data;
+ stbtt_vertex *vertices = 0;
+ int num_vertices = 0;
+ int g = stbtt__GetGlyfOffset(info, glyph_index);
+
+ *pvertices = NULL;
+
+ if (g < 0) return 0;
+
+ numberOfContours = ttSHORT(data + g);
+
+ if (numberOfContours > 0) {
+ stbtt_uint8 flags = 0, flagcount;
+ stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off;
+ stbtt_int16 x, y, cx, cy, sx, sy;
+ stbtt_uint8 *points;
+ endPtsOfContours = (data + g + 10);
+ ins = ttUSHORT(data + g + 10 + numberOfContours * 2);
+ points = data + g + 10 + numberOfContours * 2 + 2 + ins;
+
+ n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 - 2);
+
+ m = n + numberOfContours; // a loose bound on how many vertices we might need
+ vertices = (stbtt_vertex *)STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
+ if (vertices == 0)
+ return 0;
+
+ next_move = 0;
+ flagcount = 0;
+
+ // in first pass, we load uninterpreted data into the allocated array
+ // above, shifted to the end of the array so we won't overwrite it when
+ // we create our final data starting from the front
+
+ off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
+
+ // first load flags
+
+ for (i = 0; i < n; ++i) {
+ if (flagcount == 0) {
+ flags = *points++;
+ if (flags & 8)
+ flagcount = *points++;
+ }
+ else
+ --flagcount;
+ vertices[off + i].type = flags;
+ }
+
+ // now load x coordinates
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ flags = vertices[off + i].type;
+ if (flags & 2) {
+ stbtt_int16 dx = *points++;
+ x += (flags & 16) ? dx : -dx; // ???
+ }
+ else {
+ if (!(flags & 16)) {
+ x = x + (stbtt_int16)(points[0] * 256 + points[1]);
+ points += 2;
+ }
+ }
+ vertices[off + i].x = x;
+ }
+
+ // now load y coordinates
+ y = 0;
+ for (i = 0; i < n; ++i) {
+ flags = vertices[off + i].type;
+ if (flags & 4) {
+ stbtt_int16 dy = *points++;
+ y += (flags & 32) ? dy : -dy; // ???
+ }
+ else {
+ if (!(flags & 32)) {
+ y = y + (stbtt_int16)(points[0] * 256 + points[1]);
+ points += 2;
+ }
+ }
+ vertices[off + i].y = y;
+ }
+
+ // now convert them to our format
+ num_vertices = 0;
+ sx = sy = cx = cy = 0;
+ for (i = 0; i < n; ++i) {
+ flags = vertices[off + i].type;
+ x = (stbtt_int16)vertices[off + i].x;
+ y = (stbtt_int16)vertices[off + i].y;
+ if (next_move == i) {
+ // when we get to the end, we have to close the shape explicitly
+ if (i != 0) {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy);
+ else
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0);
+ }
+
+ // now start the new one
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, x, y, 0, 0);
+ next_move = 1 + ttUSHORT(endPtsOfContours + j * 2);
+ ++j;
+ was_off = 0;
+ sx = x;
+ sy = y;
+ }
+ else {
+ if (!(flags & 1)) { // if it's a curve
+ if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + x) >> 1, (cy + y) >> 1, cx, cy);
+ cx = x;
+ cy = y;
+ was_off = 1;
+ }
+ else {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, y, cx, cy);
+ else
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0, 0);
+ was_off = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ if (was_off)
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy);
+ else
+ stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0);
+ }
+ }
+ else if (numberOfContours == -1) {
+ // Compound shapes.
+ int more = 1;
+ stbtt_uint8 *comp = data + g + 10;
+ num_vertices = 0;
+ vertices = 0;
+ while (more) {
+ stbtt_uint16 flags, gidx;
+ int comp_num_verts = 0, i;
+ stbtt_vertex *comp_verts = 0, *tmp = 0;
+ float mtx[6] = { 1,0,0,1,0,0 }, m, n;
+
+ flags = ttSHORT(comp); comp += 2;
+ gidx = ttSHORT(comp); comp += 2;
+
+ if (flags & 2) { // XY values
+ if (flags & 1) { // shorts
+ mtx[4] = ttSHORT(comp); comp += 2;
+ mtx[5] = ttSHORT(comp); comp += 2;
+ }
+ else {
+ mtx[4] = ttCHAR(comp); comp += 1;
+ mtx[5] = ttCHAR(comp); comp += 1;
+ }
+ }
+ else {
+ // @TODO handle matching point
+ STBTT_assert(0);
+ }
+ if (flags & (1 << 3)) { // WE_HAVE_A_SCALE
+ mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
+ mtx[1] = mtx[2] = 0;
+ }
+ else if (flags & (1 << 6)) { // WE_HAVE_AN_X_AND_YSCALE
+ mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2;
+ mtx[1] = mtx[2] = 0;
+ mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
+ }
+ else if (flags & (1 << 7)) { // WE_HAVE_A_TWO_BY_TWO
+ mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2;
+ mtx[1] = ttSHORT(comp) / 16384.0f; comp += 2;
+ mtx[2] = ttSHORT(comp) / 16384.0f; comp += 2;
+ mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
+ }
+
+ // Find transformation scales.
+ m = (float)sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]);
+ n = (float)sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]);
+
+ // Get indexed glyph.
+ comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);
+ if (comp_num_verts > 0) {
+ // Transform vertices.
+ for (i = 0; i < comp_num_verts; ++i) {
+ stbtt_vertex* v = &comp_verts[i];
+ stbtt_vertex_type x, y;
+ x = v->x; y = v->y;
+ v->x = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
+ v->y = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
+ x = v->cx; y = v->cy;
+ v->cx = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
+ v->cy = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
+ }
+ // Append vertices.
+ tmp = (stbtt_vertex*)STBTT_malloc((num_vertices + comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
+ if (!tmp) {
+ if (vertices) STBTT_free(vertices, info->userdata);
+ if (comp_verts) STBTT_free(comp_verts, info->userdata);
+ return 0;
+ }
+ if (num_vertices > 0) memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
+ memcpy(tmp + num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
+ if (vertices) STBTT_free(vertices, info->userdata);
+ vertices = tmp;
+ STBTT_free(comp_verts, info->userdata);
+ num_vertices += comp_num_verts;
+ }
+ // More components ?
+ more = flags & (1 << 5);
+ }
+ }
+ else if (numberOfContours < 0) {
+ // @TODO other compound variations?
+ STBTT_assert(0);
+ }
+ else {
+ // numberOfCounters == 0, do nothing
+ }
+
+ *pvertices = vertices;
+ return num_vertices;
+}
+
+void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
+{
+ stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data + info->hhea + 34);
+ if (glyph_index < numOfLongHorMetrics) {
+ if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * glyph_index);
+ if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * glyph_index + 2);
+ }
+ else {
+ if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * (numOfLongHorMetrics - 1));
+ if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics));
+ }
+}
+
+int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo * /*info*/, int /*glyph1*/, int /*glyph2*/)
+{
+ return 0;
+}
+
+int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo * /*info*/, int /*ch1*/, int /*ch2*/)
+{
+ return 0;
+}
+
+void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
+{
+ stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint), advanceWidth, leftSideBearing);
+}
+
+void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
+{
+ if (ascent) *ascent = ttSHORT(info->data + info->hhea + 4);
+ if (descent) *descent = ttSHORT(info->data + info->hhea + 6);
+ if (lineGap) *lineGap = ttSHORT(info->data + info->hhea + 8);
+}
+
+float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)
+{
+ int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
+ return (float)height / fheight;
+}
+
+void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
+{
+ STBTT_free(v, info->userdata);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// antialiasing software rasterizer
+//
+
+void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ int x0, y0, x1, y1;
+ if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1))
+ x0 = y0 = x1 = y1 = 0; // e.g. space character
+ // now move to integral bboxes (treating pixels as little squares, what pixels get touched)?
+ if (ix0) *ix0 = STBTT_ifloor(x0 * scale_x);
+ if (iy0) *iy0 = -STBTT_iceil(y1 * scale_y);
+ if (ix1) *ix1 = STBTT_iceil(x1 * scale_x);
+ if (iy1) *iy1 = -STBTT_ifloor(y0 * scale_y);
+}
+
+void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
+{
+ stbtt_GetGlyphBitmapBox(font, stbtt_FindGlyphIndex(font, codepoint), scale_x, scale_y, ix0, iy0, ix1, iy1);
+}
+
+typedef struct stbtt__edge {
+ float x0, y0, x1, y1;
+ int invert;
+} stbtt__edge;
+
+typedef struct stbtt__active_edge
+{
+ int x, dx;
+ float ey;
+ struct stbtt__active_edge *next;
+ int valid;
+} stbtt__active_edge;
+
+#define FIXSHIFT 10
+#define FIX (1 << FIXSHIFT)
+#define FIXMASK (FIX-1)
+
+static stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point, void *userdata)
+{
+ stbtt__active_edge *z = (stbtt__active_edge *)STBTT_malloc(sizeof(*z), userdata); // @TODO: make a pool of these!!!
+ float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+ STBTT_assert(e->y0 <= start_point);
+ if (!z) return z;
+ // round dx down to avoid going too far
+ if (dxdy < 0)
+ z->dx = -STBTT_ifloor(FIX * -dxdy);
+ else
+ z->dx = STBTT_ifloor(FIX * dxdy);
+ z->x = STBTT_ifloor(FIX * (e->x0 + dxdy * (start_point - e->y0)));
+ z->x -= off_x * FIX;
+ z->ey = e->y1;
+ z->next = 0;
+ z->valid = e->invert ? 1 : -1;
+ return z;
+}
+
+// note: this routine clips fills that extend off the edges... ideally this
+// wouldn't happen, but it could happen if the truetype glyph bounding boxes
+// are wrong, or if the user supplies a too-small bitmap
+static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)
+{
+ // non-zero winding fill
+ int x0 = 0, w = 0;
+
+ while (e) {
+ if (w == 0) {
+ // if we're currently at zero, we need to record the edge start point
+ x0 = e->x; w += e->valid;
+ }
+ else {
+ int x1 = e->x; w += e->valid;
+ // if we went to zero, we need to draw
+ if (w == 0) {
+ int i = x0 >> FIXSHIFT;
+ int j = x1 >> FIXSHIFT;
+
+ if (i < len && j >= 0) {
+ if (i == j) {
+ // x0,x1 are the same pixel, so compute combined coverage
+ scanline[i] = scanline[i] + (stbtt_uint8)((x1 - x0) * max_weight >> FIXSHIFT);
+ }
+ else {
+ if (i >= 0) // add antialiasing for x0
+ scanline[i] = scanline[i] + (stbtt_uint8)(((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT);
+ else
+ i = -1; // clip
+
+ if (j < len) // add antialiasing for x1
+ scanline[j] = scanline[j] + (stbtt_uint8)(((x1 & FIXMASK) * max_weight) >> FIXSHIFT);
+ else
+ j = len; // clip
+
+ for (++i; i < j; ++i) // fill pixels between x0 and x1
+ scanline[i] = scanline[i] + (stbtt_uint8)max_weight;
+ }
+ }
+ }
+ }
+
+ e = e->next;
+ }
+}
+
+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)
+{
+ stbtt__active_edge *active = NULL;
+ int y, j = 0;
+ int max_weight = (255 / vsubsample); // weight per vertical scanline
+ int s; // vertical subsample index
+ unsigned char scanline_data[512], *scanline;
+
+ if (result->w > 512)
+ scanline = (unsigned char *)STBTT_malloc(result->w, userdata);
+ else
+ scanline = scanline_data;
+
+ y = off_y * vsubsample;
+ e[n].y0 = (off_y + result->h) * (float)vsubsample + 1;
+
+ while (j < result->h) {
+ STBTT_memset(scanline, 0, result->w);
+ for (s = 0; s < vsubsample; ++s) {
+ // find center of pixel for this scanline
+ float scan_y = y + 0.5f;
+ stbtt__active_edge **step = &active;
+
+ // update all active edges;
+ // remove all active edges that terminate before the center of this scanline
+ while (*step) {
+ stbtt__active_edge * z = *step;
+ if (z->ey <= scan_y) {
+ *step = z->next; // delete from list
+ STBTT_assert(z->valid);
+ z->valid = 0;
+ STBTT_free(z, userdata);
+ }
+ else {
+ z->x += z->dx; // advance to position for current scanline
+ step = &((*step)->next); // advance through list
+ }
+ }
+
+ // resort the list if needed
+ for (;;) {
+ int changed = 0;
+ step = &active;
+ while (*step && (*step)->next) {
+ if ((*step)->x > (*step)->next->x) {
+ stbtt__active_edge *t = *step;
+ stbtt__active_edge *q = t->next;
+
+ t->next = q->next;
+ q->next = t;
+ *step = q;
+ changed = 1;
+ }
+ step = &(*step)->next;
+ }
+ if (!changed) break;
+ }
+
+ // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
+ while (e->y0 <= scan_y) {
+ if (e->y1 > scan_y) {
+ stbtt__active_edge *z = new_active(e, off_x, scan_y, userdata);
+ // find insertion point
+ if (active == NULL)
+ active = z;
+ else if (z->x < active->x) {
+ // insert at front
+ z->next = active;
+ active = z;
+ }
+ else {
+ // find thing to insert AFTER
+ stbtt__active_edge *p = active;
+ while (p->next && p->next->x < z->x)
+ p = p->next;
+ // at this point, p->next->x is NOT < z->x
+ z->next = p->next;
+ p->next = z;
+ }
+ }
+ ++e;
+ }
+
+ // now process all active edges in XOR fashion
+ if (active)
+ stbtt__fill_active_edges(scanline, result->w, active, max_weight);
+
+ ++y;
+ }
+ STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);
+ ++j;
+ }
+
+ while (active) {
+ stbtt__active_edge *z = active;
+ active = active->next;
+ STBTT_free(z, userdata);
+ }
+
+ if (scanline != scanline_data)
+ STBTT_free(scanline, userdata);
+}
+
+static int stbtt__edge_compare(const void *p, const void *q)
+{
+ stbtt__edge *a = (stbtt__edge *)p;
+ stbtt__edge *b = (stbtt__edge *)q;
+
+ if (a->y0 < b->y0) return -1;
+ if (a->y0 > b->y0) return 1;
+ return 0;
+}
+
+typedef struct
+{
+ float x, y;
+} stbtt__point;
+
+static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, int off_x, int off_y, int invert, void *userdata)
+{
+ float y_scale_inv = invert ? -scale_y : scale_y;
+ stbtt__edge *e;
+ int n, i, j, k, m;
+ int vsubsample = result->h < 8 ? 15 : 5;
+ // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
+
+ // now we have to blow out the windings into explicit edge lists
+ n = 0;
+ for (i = 0; i < windings; ++i)
+ n += wcount[i];
+
+ e = (stbtt__edge *)STBTT_malloc(sizeof(*e) * (n + 1), userdata); // add an extra one as a sentinel
+ if (e == 0) return;
+ n = 0;
+
+ m = 0;
+ for (i = 0; i < windings; ++i) {
+ stbtt__point *p = pts + m;
+ m += wcount[i];
+ j = wcount[i] - 1;
+ for (k = 0; k < wcount[i]; j = k++) {
+ int a = k, b = j;
+ // skip the edge if horizontal
+ if (p[j].y == p[k].y)
+ continue;
+ // add edge from j to k to the list
+ e[n].invert = 0;
+ if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
+ e[n].invert = 1;
+ a = j, b = k;
+ }
+ e[n].x0 = p[a].x * scale_x;
+ e[n].y0 = p[a].y * y_scale_inv * vsubsample;
+ e[n].x1 = p[b].x * scale_x;
+ e[n].y1 = p[b].y * y_scale_inv * vsubsample;
+ ++n;
+ }
+ }
+
+ // now sort the edges by their highest point (should snap to integer, and then by x)
+ STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);
+
+ // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
+ stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);
+
+ STBTT_free(e, userdata);
+}
+
+static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
+{
+ if (!points) return; // during first pass, it's unallocated
+ points[n].x = x;
+ points[n].y = y;
+}
+
+// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
+static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
+{
+ // midpoint
+ float mx = (x0 + 2 * x1 + x2) / 4;
+ float my = (y0 + 2 * y1 + y2) / 4;
+ // versus directly drawn line
+ float dx = (x0 + x2) / 2 - mx;
+ float dy = (y0 + y2) / 2 - my;
+ if (n > 16) // 65536 segments on one curve better be enough!
+ return 1;
+ if (dx*dx + dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
+ stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, (y0 + y1) / 2.0f, mx, my, objspace_flatness_squared, n + 1);
+ stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, (y1 + y2) / 2.0f, x2, y2, objspace_flatness_squared, n + 1);
+ }
+ else {
+ stbtt__add_point(points, *num_points, x2, y2);
+ *num_points = *num_points + 1;
+ }
+ return 1;
+}
+
+// returns number of contours
+stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
+{
+ stbtt__point *points = 0;
+ int num_points = 0;
+
+ float objspace_flatness_squared = objspace_flatness * objspace_flatness;
+ int i, n = 0, start = 0, pass;
+
+ // count how many "moves" there are to get the contour count
+ for (i = 0; i < num_verts; ++i)
+ if (vertices[i].type == STBTT_vmove)
+ ++n;
+
+ *num_contours = n;
+ if (n == 0) return 0;
+
+ *contour_lengths = (int *)STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
+
+ if (*contour_lengths == 0) {
+ *num_contours = 0;
+ return 0;
+ }
+
+ // make two passes through the points so we don't need to realloc
+ for (pass = 0; pass < 2; ++pass) {
+ float x = 0, y = 0;
+ if (pass == 1) {
+ points = (stbtt__point *)STBTT_malloc(num_points * sizeof(points[0]), userdata);
+ if (points == NULL) goto error;
+ }
+ num_points = 0;
+ n = -1;
+ for (i = 0; i < num_verts; ++i) {
+ switch (vertices[i].type) {
+ case STBTT_vmove:
+ // start the next contour
+ if (n >= 0)
+ (*contour_lengths)[n] = num_points - start;
+ ++n;
+ start = num_points;
+
+ x = vertices[i].x, y = vertices[i].y;
+ stbtt__add_point(points, num_points++, x, y);
+ break;
+ case STBTT_vline:
+ x = vertices[i].x, y = vertices[i].y;
+ stbtt__add_point(points, num_points++, x, y);
+ break;
+ case STBTT_vcurve:
+ stbtt__tesselate_curve(points, &num_points, x, y,
+ vertices[i].cx, vertices[i].cy,
+ vertices[i].x, vertices[i].y,
+ objspace_flatness_squared, 0);
+ x = vertices[i].x, y = vertices[i].y;
+ break;
+ }
+ }
+ (*contour_lengths)[n] = num_points - start;
+ }
+
+ return points;
+error:
+ STBTT_free(points, userdata);
+ STBTT_free(*contour_lengths, userdata);
+ *contour_lengths = 0;
+ *num_contours = 0;
+ return NULL;
+}
+
+void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata)
+{
+ float scale = scale_x > scale_y ? scale_y : scale_x;
+ int winding_count, *winding_lengths;
+ stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
+ if (windings) {
+ stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, x_off, y_off, invert, userdata);
+ STBTT_free(winding_lengths, userdata);
+ STBTT_free(windings, userdata);
+ }
+}
+
+void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
+{
+ STBTT_free(bitmap, userdata);
+}
+
+unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
+{
+ int ix0, iy0, ix1, iy1;
+ stbtt__bitmap gbm;
+ stbtt_vertex *vertices;
+ int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+
+ if (scale_x == 0) scale_x = scale_y;
+ if (scale_y == 0) {
+ if (scale_x == 0) return NULL;
+ scale_y = scale_x;
+ }
+
+ stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0, &iy0, &ix1, &iy1);
+
+ // now we get the size
+ gbm.w = (ix1 - ix0);
+ gbm.h = (iy1 - iy0);
+ gbm.pixels = NULL; // in case we error
+
+ if (width) *width = gbm.w;
+ if (height) *height = gbm.h;
+ if (xoff) *xoff = ix0;
+ if (yoff) *yoff = iy0;
+
+ if (gbm.w && gbm.h) {
+ gbm.pixels = (unsigned char *)STBTT_malloc(gbm.w * gbm.h, info->userdata);
+ if (gbm.pixels) {
+ gbm.stride = gbm.w;
+
+ stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0, iy0, 1, info->userdata);
+ }
+ }
+ STBTT_free(vertices, info->userdata);
+ return gbm.pixels;
+}
+
+void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
+{
+ int ix0, iy0;
+ stbtt_vertex *vertices;
+ int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
+ stbtt__bitmap gbm;
+
+ stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0, &iy0, 0, 0);
+ gbm.pixels = output;
+ gbm.w = out_w;
+ gbm.h = out_h;
+ gbm.stride = out_stride;
+
+ if (gbm.w && gbm.h)
+ stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0, iy0, 1, info->userdata);
+
+ STBTT_free(vertices, info->userdata);
+}
+
+unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
+{
+ return stbtt_GetGlyphBitmap(info, scale_x, scale_y, stbtt_FindGlyphIndex(info, codepoint), width, height, xoff, yoff);
+}
+
+void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
+{
+ stbtt_MakeGlyphBitmap(info, output, out_w, out_h, out_stride, scale_x, scale_y, stbtt_FindGlyphIndex(info, codepoint));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// bitmap baking
+//
+// This is SUPER-SHITTY packing to keep source code small
+
+extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
+ float pixel_height, // height of font in pixels
+ unsigned char *pixels, int pw, int ph, // bitmap to be filled in
+ int first_char, int num_chars, // characters to bake
+ stbtt_bakedchar *chardata)
+{
+ float scale;
+ int x, y, bottom_y, i;
+ stbtt_fontinfo f;
+ stbtt_InitFont(&f, data, offset);
+ STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
+ x = y = 1;
+ bottom_y = 1;
+
+ scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
+
+ for (i = 0; i < num_chars; ++i) {
+ int advance, lsb, x0, y0, x1, y1, gw, gh;
+ int g = stbtt_FindGlyphIndex(&f, first_char + i);
+ stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
+ stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1);
+ gw = x1 - x0;
+ gh = y1 - y0;
+ if (x + gw + 1 >= pw)
+ y = bottom_y, x = 1; // advance to next row
+ if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
+ return -i;
+ STBTT_assert(x + gw < pw);
+ STBTT_assert(y + gh < ph);
+ stbtt_MakeGlyphBitmap(&f, pixels + x + y*pw, gw, gh, pw, scale, scale, g);
+ chardata[i].x0 = (stbtt_int16)x;
+ chardata[i].y0 = (stbtt_int16)y;
+ chardata[i].x1 = (stbtt_int16)(x + gw);
+ chardata[i].y1 = (stbtt_int16)(y + gh);
+ chardata[i].xadvance = scale * advance;
+ chardata[i].xoff = (float)x0;
+ chardata[i].yoff = (float)y0;
+ x = x + gw + 2;
+ if (y + gh + 2 > bottom_y)
+ bottom_y = y + gh + 2;
+ }
+ return bottom_y;
+}
+
+void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
+{
+ float d3d_bias = opengl_fillrule ? 0 : -0.5f;
+ float ipw = 1.0f / pw, iph = 1.0f / ph;
+ stbtt_bakedchar *b = chardata + char_index;
+ int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5);
+ int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5);
+
+ q->x0 = round_x + d3d_bias;
+ q->y0 = round_y + d3d_bias;
+ q->x1 = round_x + b->x1 - b->x0 + d3d_bias;
+ q->y1 = round_y + b->y1 - b->y0 + d3d_bias;
+
+ q->s0 = b->x0 * ipw;
+ q->t0 = b->y0 * ipw;
+ q->s1 = b->x1 * iph;
+ q->t1 = b->y1 * iph;
+
+ *xpos += b->xadvance;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// font name matching -- recommended not to use this
+//
+
+// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
+{
+ stbtt_int32 i = 0;
+
+ // convert utf16 to utf8 and compare the results while converting
+ while (len2) {
+ stbtt_uint16 ch = s2[0] * 256 + s2[1];
+ if (ch < 0x80) {
+ if (i >= len1) return -1;
+ if (s1[i++] != ch) return -1;
+ }
+ else if (ch < 0x800) {
+ if (i + 1 >= len1) return -1;
+ if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
+ if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
+ }
+ else if (ch >= 0xd800 && ch < 0xdc00) {
+ stbtt_uint32 c;
+ stbtt_uint16 ch2 = s2[2] * 256 + s2[3];
+ if (i + 3 >= len1) return -1;
+ c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
+ if (s1[i++] != 0xf0 + (c >> 18)) return -1;
+ if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((c)& 0x3f)) return -1;
+ s2 += 2; // plus another 2 below
+ len2 -= 2;
+ }
+ else if (ch >= 0xdc00 && ch < 0xe000) {
+ return -1;
+ }
+ else {
+ if (i + 2 >= len1) return -1;
+ if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
+ if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
+ if (s1[i++] != 0x80 + ((ch)& 0x3f)) return -1;
+ }
+ s2 += 2;
+ len2 -= 2;
+ }
+ return i;
+}
+
+int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
+{
+ return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*)s1, len1, (stbtt_uint8*)s2, len2);
+}
+
+// returns results in whatever encoding you request... but note that 2-byte encodings
+// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare
+char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
+{
+ stbtt_int32 i, count, stringOffset;
+ stbtt_uint8 *fc = font->data;
+ stbtt_uint32 offset = font->fontstart;
+ stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");
+ if (!nm) return NULL;
+
+ count = ttUSHORT(fc + nm + 2);
+ stringOffset = nm + ttUSHORT(fc + nm + 4);
+ for (i = 0; i < count; ++i) {
+ stbtt_uint32 loc = nm + 6 + 12 * i;
+ if (platformID == ttUSHORT(fc + loc + 0) && encodingID == ttUSHORT(fc + loc + 2)
+ && languageID == ttUSHORT(fc + loc + 4) && nameID == ttUSHORT(fc + loc + 6)) {
+ *length = ttUSHORT(fc + loc + 8);
+ return (char *)(fc + stringOffset + ttUSHORT(fc + loc + 10));
+ }
+ }
+ return NULL;
+}
+
+static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)
+{
+ stbtt_int32 i;
+ stbtt_int32 count = ttUSHORT(fc + nm + 2);
+ stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm + 4);
+
+ for (i = 0; i < count; ++i) {
+ stbtt_uint32 loc = nm + 6 + 12 * i;
+ stbtt_int32 id = ttUSHORT(fc + loc + 6);
+ if (id == target_id) {
+ // find the encoding
+ stbtt_int32 platform = ttUSHORT(fc + loc + 0), encoding = ttUSHORT(fc + loc + 2), language = ttUSHORT(fc + loc + 4);
+
+ // is this a Unicode encoding?
+ if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
+ stbtt_int32 slen = ttUSHORT(fc + loc + 8), off = ttUSHORT(fc + loc + 10);
+
+ // check if there's a prefix match
+ stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc + stringOffset + off, slen);
+ if (matchlen >= 0) {
+ // check for target_id+1 immediately following, with same encoding & language
+ if (i + 1 < count && ttUSHORT(fc + loc + 12 + 6) == next_id && ttUSHORT(fc + loc + 12) == platform && ttUSHORT(fc + loc + 12 + 2) == encoding && ttUSHORT(fc + loc + 12 + 4) == language) {
+ stbtt_int32 slen = ttUSHORT(fc + loc + 12 + 8), off = ttUSHORT(fc + loc + 12 + 10);
+ if (slen == 0) {
+ if (matchlen == nlen)
+ return 1;
+ }
+ else if (matchlen < nlen && name[matchlen] == ' ') {
+ ++matchlen;
+ if (stbtt_CompareUTF8toUTF16_bigendian((char*)(name + matchlen), nlen - matchlen, (char*)(fc + stringOffset + off), slen))
+ return 1;
+ }
+ }
+ else {
+ // if nothing immediately following
+ if (matchlen == nlen)
+ return 1;
+ }
+ }
+ }
+
+ // @TODO handle other encodings
+ }
+ }
+ return 0;
+}
+
+static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
+{
+ stbtt_int32 nlen = STBTT_strlen((char *)name);
+ stbtt_uint32 nm, hd;
+ if (!stbtt__isfont(fc + offset)) return 0;
+
+ // check italics/bold/underline flags in macStyle...
+ if (flags) {
+ hd = stbtt__find_table(fc, offset, "head");
+ if ((ttUSHORT(fc + hd + 44) & 7) != (flags & 7)) return 0;
+ }
+
+ nm = stbtt__find_table(fc, offset, "name");
+ if (!nm) return 0;
+
+ if (flags) {
+ // if we checked the macStyle flags, then just check the family and ignore the subfamily
+ if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
+ }
+ else {
+ if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1;
+ if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1;
+ }
+
+ return 0;
+}
+
+int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)
+{
+ stbtt_int32 i;
+ for (i = 0;; ++i) {
+ stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
+ if (off < 0) return off;
+ if (stbtt__matches((stbtt_uint8 *)font_collection, off, (stbtt_uint8*)name_utf8, flags))
+ return off;
+ }
+}
+
+#endif // STB_TRUETYPE_IMPLEMENTATION \ No newline at end of file