Remove ReadMe.txt from all project files.

Add Curves.h, and CurvesGraphicsView.h/cpp to support bezier color curves.
Add Curves member to Ember.
Add curves capability to EmberCL.
Remove some unused variables in the kernel created in RendererCL::CreateFinalAccumKernelString().
Use glm namespace for vec classes if GLM_VERSION >= 96, else use glm::detail.
As a result of using glm namespace, all instances of min and max had to be qualified with std::
Split ComputeCamera into that and ComputeQuality().
Reduce the amount of ComputeCamera() and MakeDmap() calls on each incremental iter that doesn't use temporal samples.
Fix clamping bug with DE filter widths.
Provide functions to return the kernels from RendererCL to assist with diagnostics and debugging.
Prevent extra newline in EmberRender when only rendering a single image.
Add the ability to delete an ember at a given index in EmberFile.
Allow deleting/focusing ember in library tab with delete and enter keys.
Reorder some code in Fractorium.h to match the tabs order.
Add and call ClearFinalImages() to clear buffers in controller to fix bug where previous CPU render would be shown for a split second when switching from OpenCL back to CPU.
Refactor ember library pointer syncing to a function SyncPointers().
Add the ability to save ember Xmls to an unique automatically generated name after the first time the user has specified a name.
This commit is contained in:
mfeemster 2015-03-21 15:27:37 -07:00
parent f334ce1704
commit 07592c9d78
67 changed files with 1585 additions and 263 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ProductVersion="0.4.1.8" ?> <?define ProductVersion="0.4.1.9" ?>
<?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?> <?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?>
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?> <?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
<?define Manufacturer="Fractorium"?> <?define Manufacturer="Fractorium"?>

View File

@ -266,12 +266,10 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\Source\Ember\Affine2D.h" /> <ClInclude Include="..\..\..\Source\Ember\Affine2D.h" />
<ClInclude Include="..\..\..\Source\Ember\CarToRas.h" /> <ClInclude Include="..\..\..\Source\Ember\CarToRas.h" />
<ClInclude Include="..\..\..\Source\Ember\Curves.h" />
<ClInclude Include="..\..\..\Source\Ember\EmberDefines.h" /> <ClInclude Include="..\..\..\Source\Ember\EmberDefines.h" />
<ClInclude Include="..\..\..\Source\Ember\EmberPch.h" /> <ClInclude Include="..\..\..\Source\Ember\EmberPch.h" />
<ClInclude Include="..\..\..\Source\Ember\Ember.h" /> <ClInclude Include="..\..\..\Source\Ember\Ember.h" />

View File

@ -19,9 +19,6 @@
<UniqueIdentifier>{1ae77918-b5ee-4186-9fec-802fed55144e}</UniqueIdentifier> <UniqueIdentifier>{1ae77918-b5ee-4186-9fec-802fed55144e}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\Source\Ember\Timing.h"> <ClInclude Include="..\..\..\Source\Ember\Timing.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
@ -113,6 +110,9 @@
<ClInclude Include="..\..\..\Source\Ember\RendererBase.h"> <ClInclude Include="..\..\..\Source\Ember\RendererBase.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\..\Source\Ember\Curves.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\Source\Ember\DllMain.cpp"> <ClCompile Include="..\..\..\Source\Ember\DllMain.cpp">

View File

@ -273,9 +273,6 @@
<AdditionalLibraryDirectories>$(CUDA_PATH)lib\$(PlatformName)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(CUDA_PATH)lib\$(PlatformName)</AdditionalLibraryDirectories>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\tbb\build\vs2010\tbb.vcxproj"> <ProjectReference Include="..\..\..\..\tbb\build\vs2010\tbb.vcxproj">
<Project>{f62787dd-1327-448b-9818-030062bcfaa5}</Project> <Project>{f62787dd-1327-448b-9818-030062bcfaa5}</Project>

View File

@ -17,9 +17,6 @@
<UniqueIdentifier>{d66f35ca-a4cd-470a-9c56-653b0665b598}</UniqueIdentifier> <UniqueIdentifier>{d66f35ca-a4cd-470a-9c56-653b0665b598}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\..\Source\EmberCL\DllMain.cpp"> <ClCompile Include="..\..\..\Source\EmberCL\DllMain.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>

View File

@ -299,7 +299,6 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico" /> <None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico" />
<None Include="ReadMe.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\libxml2\win32\VC10\libxml2.vcxproj"> <ProjectReference Include="..\..\..\..\libxml2\win32\VC10\libxml2.vcxproj">

View File

@ -15,7 +15,6 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="ReadMe.txt" />
<None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico"> <None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico">
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</None> </None>

View File

@ -301,7 +301,6 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico" /> <None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico" />
<None Include="ReadMe.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\libjpeg\jpeg.vcxproj"> <ProjectReference Include="..\..\..\..\libjpeg\jpeg.vcxproj">

View File

@ -15,7 +15,6 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="ReadMe.txt" />
<None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico"> <None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico">
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</None> </None>

View File

@ -297,9 +297,6 @@ xcopy /F /Y /R /D "$(SolutionDir)intel64\$(Configuration)\tbb.pdb" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</Command> xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\libxml2\win32\VC10\libxml2.vcxproj"> <ProjectReference Include="..\..\..\..\libxml2\win32\VC10\libxml2.vcxproj">
<Project>{1d6039f6-5078-416f-a3af-a36efc7e6a1c}</Project> <Project>{1d6039f6-5078-416f-a3af-a36efc7e6a1c}</Project>

View File

@ -14,9 +14,6 @@
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\..\Source\EmberCommon\EmberCommon.h"> <ClInclude Include="..\..\..\Source\EmberCommon\EmberCommon.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>

View File

@ -303,6 +303,7 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">Use</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">Use</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\Source\Fractorium\CurvesGraphicsView.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\FinalRenderDialog.cpp" /> <ClCompile Include="..\..\..\Source\Fractorium\FinalRenderDialog.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\FinalRenderEmberController.cpp" /> <ClCompile Include="..\..\..\Source\Fractorium\FinalRenderEmberController.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\Fractorium.cpp"> <ClCompile Include="..\..\..\Source\Fractorium\Fractorium.cpp">
@ -347,6 +348,12 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_CurvesGraphicsView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_DoubleSpinBox.cpp"> <ClCompile Include="GeneratedFiles\Debug\moc_DoubleSpinBox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild>
@ -427,6 +434,12 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_CurvesGraphicsView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_DoubleSpinBox.cpp"> <ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_DoubleSpinBox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -493,6 +506,12 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_CurvesGraphicsView.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_DoubleSpinBox.cpp"> <ClCompile Include="GeneratedFiles\Release\moc_DoubleSpinBox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">true</ExcludedFromBuild>
@ -730,6 +749,32 @@ xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"</
<Command Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/TwoButtonComboWidget.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command> <Command Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/TwoButtonComboWidget.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
</CustomBuild> </CustomBuild>
<ClInclude Include="..\..\..\Source\EmberCommon\EmberCommon.h" /> <ClInclude Include="..\..\..\Source\EmberCommon\EmberCommon.h" />
<CustomBuild Include="..\..\..\Source\Fractorium\CurvesGraphicsView.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(AMDAPPSDKROOT)\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(AMDAPPSDKROOT)\include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(AMDAPPSDKROOT)\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(AMDAPPSDKROOT)\include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">Moc%27ing CurvesGraphicsView.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='ReleaseNvidia|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/CurvesGraphicsView.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(ProjectDir)..\..\..\..\glew\include" "-I$(AMDAPPSDKROOT)\include" "-I$(CUDA_PATH)include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
</CustomBuild>
<ClInclude Include="..\..\..\Source\Fractorium\FinalRenderEmberController.h" /> <ClInclude Include="..\..\..\Source\Fractorium\FinalRenderEmberController.h" />
<ClInclude Include="..\..\..\Source\Fractorium\FractoriumCommon.h" /> <ClInclude Include="..\..\..\Source\Fractorium\FractoriumCommon.h" />
<ClInclude Include="..\..\..\Source\Fractorium\FractoriumEmberController.h" /> <ClInclude Include="..\..\..\Source\Fractorium\FractoriumEmberController.h" />

View File

@ -232,6 +232,18 @@
<ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_TwoButtonComboWidget.cpp"> <ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_TwoButtonComboWidget.cpp">
<Filter>Generated Files\ReleaseNvidia</Filter> <Filter>Generated Files\ReleaseNvidia</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\Source\Fractorium\CurvesGraphicsView.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_CurvesGraphicsView.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_CurvesGraphicsView.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\ReleaseNvidia\moc_CurvesGraphicsView.cpp">
<Filter>Generated Files\ReleaseNvidia</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="GeneratedFiles\ui_Fractorium.h"> <ClInclude Include="GeneratedFiles\ui_Fractorium.h">
@ -329,6 +341,9 @@
<CustomBuild Include="..\..\..\Source\Fractorium\TwoButtonComboWidget.h"> <CustomBuild Include="..\..\..\Source\Fractorium\TwoButtonComboWidget.h">
<Filter>Widgets</Filter> <Filter>Widgets</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="..\..\..\Source\Fractorium\CurvesGraphicsView.h">
<Filter>Widgets</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="..\..\..\Source\Fractorium\Fractorium.rc"> <ResourceCompile Include="..\..\..\Source\Fractorium\Fractorium.rc">

View File

@ -1,4 +1,4 @@
0.4.1.8 Beta 0.4.1.9 Beta
--User changes --User changes
Thread image writing in EmberAnimate and when doing animation sequence in final render dialog. Thread image writing in EmberAnimate and when doing animation sequence in final render dialog.
Add total time output for verbose mode in EmberAnimate to match EmberRender. Add total time output for verbose mode in EmberAnimate to match EmberRender.

284
Source/Ember/Curves.h Normal file
View File

@ -0,0 +1,284 @@
#pragma once
#include "Utils.h"
#include "Isaac.h"
/// <summary>
/// Curves class.
/// </summary>
namespace EmberNs
{
/// <summary>
/// The Bezier curves used to adjust the colors during final accumulation.
/// This functionality was gotten directly from Apophysis.
/// </summary>
template <typename T>
class EMBER_API Curves
{
public:
/// <summary>
/// Constructor which sets the curve and weight values to their defaults.
/// </summary>
Curves(bool init = false)
{
if (init)
Init();
else
Clear();
}
/// <summary>
/// Default copy constructor.
/// </summary>
/// <param name="curves">The Curves object to copy</param>
Curves(const Curves<T>& curves)
{
Curves<T>::operator=<T>(curves);
}
/// <summary>
/// Copy constructor to copy a Curves object of type U.
/// Special case that must be here in the header because it has
/// a second template parameter.
/// </summary>
/// <param name="curves">The Curves object to copy</param>
template <typename U>
Curves(const Curves<U>& curves)
{
Curves<T>::operator=<U>(curves);
}
/// <summary>
/// Default assignment operator.
/// </summary>
/// <param name="curves">The Curves object to copy</param>
Curves<T>& operator = (const Curves<T>& curves)
{
if (this != &curves)
Curves<T>::operator=<T>(curves);
return *this;
}
/// <summary>
/// Assignment operator to assign a Curves object of type U.
/// </summary>
/// <param name="curves">The Curves object to copy</param>
/// <returns>Reference to updated self</returns>
template <typename U>
Curves<T>& operator = (const Curves<U>& curves)
{
for (uint i = 0; i < 4; i++)
{
m_Points[i][0].x = T(curves.m_Points[i][0].x); m_Points[i][0].y = T(curves.m_Points[i][0].y); m_Weights[i].x = T(curves.m_Weights[i].x);
m_Points[i][1].x = T(curves.m_Points[i][1].x); m_Points[i][1].y = T(curves.m_Points[i][1].y); m_Weights[i].y = T(curves.m_Weights[i].y);
m_Points[i][2].x = T(curves.m_Points[i][2].x); m_Points[i][2].y = T(curves.m_Points[i][2].y); m_Weights[i].z = T(curves.m_Weights[i].z);
m_Points[i][3].x = T(curves.m_Points[i][3].x); m_Points[i][3].y = T(curves.m_Points[i][3].y); m_Weights[i].w = T(curves.m_Weights[i].w);
}
return *this;
}
/// <summary>
/// Unary addition operator to add a Curves<T> object to this one.
/// </summary>
/// <param name="curves">The Curves object to add</param>
/// <returns>Reference to updated self</returns>
Curves<T>& operator += (const Curves<T>& curves)
{
for (uint i = 0; i < 4; i++)
{
m_Points[i][0] += curves.m_Points[i][0];
m_Points[i][1] += curves.m_Points[i][1];
m_Points[i][2] += curves.m_Points[i][2];
m_Points[i][3] += curves.m_Points[i][3];
m_Weights[i] += curves.m_Weights[i];
}
return *this;
}
/// <summary>
/// Unary multiplication operator to multiply this object by another Curves<T> object.
/// </summary>
/// <param name="curves">The Curves object to multiply this one by</param>
/// <returns>Reference to updated self</returns>
Curves<T>& operator *= (const Curves<T>& curves)
{
for (uint i = 0; i < 4; i++)
{
m_Points[i][0] *= curves.m_Points[i][0];
m_Points[i][1] *= curves.m_Points[i][1];
m_Points[i][2] *= curves.m_Points[i][2];
m_Points[i][3] *= curves.m_Points[i][3];
m_Weights[i] *= curves.m_Weights[i];
}
return *this;
}
/// <summary>
/// Unary multiplication operator to multiply this object by a scalar of type T.
/// </summary>
/// <param name="t">The scalar to multiply this object by</param>
/// <returns>Reference to updated self</returns>
Curves<T>& operator *= (const T& t)
{
for (uint i = 0; i < 4; i++)
{
m_Points[i][0] *= t;
m_Points[i][1] *= t;
m_Points[i][2] *= t;
m_Points[i][3] *= t;
m_Weights[i] *= t;
}
return *this;
}
/// <summary>
/// Set the curve and weight values to their default state.
/// </summary>
void Init()
{
for (uint i = 0; i < 4; i++)
{
m_Points[i][0] = v2T(0);//0,0 -> 0,0 -> 1,1 -> 1,1.
m_Points[i][1] = v2T(0);
m_Points[i][2] = v2T(1);
m_Points[i][3] = v2T(1);
m_Weights[i] = v4T(1);
}
}
/// <summary>
/// Set the curve and weight values to an empty state.
/// </summary>
void Clear()
{
memset(&m_Points, 0, sizeof(m_Points));
memset(&m_Weights, 0, sizeof(m_Weights));
}
/// <summary>
/// Whether any points are not the default.
/// </summary>
/// <returns>True if any point has been set to a value other than the default, else false.</returns>
bool CurvesSet()
{
bool set = false;
for (uint i = 0; i < 4; i++)
{
if ((m_Points[i][0] != v2T(0)) ||
(m_Points[i][1] != v2T(0)) ||
(m_Points[i][2] != v2T(1)) ||
(m_Points[i][3] != v2T(1)))
{
set = true;
break;
}
}
return set;
}
/// <summary>
/// Wrapper around calling BezierSolve() on each of the 4 weight and point vectors.
/// </summary>
/// <param name="t">The position to apply</param>
/// <returns>vec4<T> that contains the y component of the solution for each vector in each component</returns>
v4T BezierFunc(const T& t)
{
v4T result;
v2T solution(0, 0);
BezierSolve(t, m_Points[0], &m_Weights[0], solution); result.x = solution.y;
BezierSolve(t, m_Points[1], &m_Weights[1], solution); result.y = solution.y;
BezierSolve(t, m_Points[2], &m_Weights[2], solution); result.z = solution.y;
BezierSolve(t, m_Points[3], &m_Weights[3], solution); result.w = solution.y;
return result;
}
private:
/// <summary>
/// Solve the given point and weight vectors for the given position and store
/// the output in the solution vec2 passed in.
/// </summary>
/// <param name="t">The position to apply</param>
/// <param name="src">A pointer to an array of 4 vec2</param>
/// <param name="w">A pointer to an array of 4 weights</param>
/// <param name="solution">The vec2 to store the solution in</param>
void BezierSolve(const T& t, v2T* src, v4T* w, v2T& solution)
{
T s, s2, s3, t2, t3, nom_x, nom_y, denom;
s = 1 - t;
s2 = s * s;
s3 = s * s * s;
t2 = t * t;
t3 = t * t * t;
nom_x = (w->x * s3 * src->x) + (w->y * s2 * 3 * t * src[1].x) + (w->z * s * 3 * t2 * src[2].x) + (w->w * t3 * src[3].x);
nom_y = (w->x * s3 * src->y) + (w->y * s2 * 3 * t * src[1].y) + (w->z * s * 3 * t2 * src[2].y) + (w->w * t3 * src[3].y);
denom = (w->x * s3) + (w->y * s2 * 3 * t) + (w->z * s * 3 * t2) + (w->w * t3);
if (isnan(nom_x) || isnan(nom_y) || isnan(denom) || denom == 0)
return;
solution.x = nom_x / denom;
solution.y = nom_y / denom;
}
public:
v2T m_Points[4][4];
v4T m_Weights[4];
};
//Must declare this outside of the class to provide for both orders of parameters.
/// <summary>
/// Multiplication operator to multiply a Curves<T> object by a scalar of type T.
/// </summary>
/// <param name="curves">The curves object to multiply</param>
/// <param name="t">The scalar to multiply curves by by</param>
/// <returns>Copy of new Curves<T></returns>
template<typename T>
Curves<T> operator * (const Curves<T>& curves, const T& t)
{
Curves<T> c(curves);
for (uint i = 0; i < 4; i++)
{
c.m_Points[i][0] *= t;
c.m_Points[i][1] *= t;
c.m_Points[i][2] *= t;
c.m_Points[i][3] *= t;
c.m_Weights[i] *= t;
}
return c;
}
/// <summary>
/// Multiplication operator for reverse order.
/// </summary>
/// <param name="t">The scalar to multiply curves by by</param>
/// <param name="curves">The curves object to multiply</param>
/// <returns>Copy of new Curves<T></returns>
template<typename T>
Curves<T> operator * (const T& t, const Curves<T>& curves)
{
return curves * t;
}
}

View File

@ -1,6 +1,7 @@
#include "EmberPch.h" #include "EmberPch.h"
#include "EmberDefines.h" #include "EmberDefines.h"
#include "Isaac.h" #include "Isaac.h"
#include "Curves.h"
#include "Ember.h" #include "Ember.h"
#include "Utils.h" #include "Utils.h"
#include "Iterator.h" #include "Iterator.h"
@ -390,6 +391,7 @@ template<> unique_ptr<QTIsaac<ISAAC_SIZE, ISAAC_INT>> QTIsaac<ISAAC_SIZE, ISAAC_
template EMBER_API class Ember<T>; \ template EMBER_API class Ember<T>; \
/*template EMBER_API class RenderCallback<T>;*/ \ /*template EMBER_API class RenderCallback<T>;*/ \
template EMBER_API class CarToRas<T>; \ template EMBER_API class CarToRas<T>; \
template EMBER_API class Curves<T>; \
template EMBER_API class XmlToEmber<T>; \ template EMBER_API class XmlToEmber<T>; \
template EMBER_API class EmberToXml<T>; template EMBER_API class EmberToXml<T>;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Curves.h"
#include "Xform.h" #include "Xform.h"
#include "PaletteList.h" #include "PaletteList.h"
#include "SpatialFilter.h" #include "SpatialFilter.h"
@ -150,6 +151,7 @@ public:
m_Index = ember.m_Index; m_Index = ember.m_Index;
m_ScaleType = ember.ScaleType(); m_ScaleType = ember.ScaleType();
m_Palette = ember.m_Palette; m_Palette = ember.m_Palette;
m_Curves = ember.m_Curves;
m_Xforms.clear(); m_Xforms.clear();
@ -243,6 +245,9 @@ public:
m_PaletteMode = PALETTE_STEP; m_PaletteMode = PALETTE_STEP;
m_PaletteInterp = INTERP_HSV; m_PaletteInterp = INTERP_HSV;
//Curves.
m_Curves.Init();
m_Name = "No name"; m_Name = "No name";
m_ParentFilename = "No parent"; m_ParentFilename = "No parent";
@ -795,6 +800,7 @@ public:
InterpT<&Ember<T>::m_MinRadDE>(embers, coefs, size); InterpT<&Ember<T>::m_MinRadDE>(embers, coefs, size);
InterpT<&Ember<T>::m_CurveDE>(embers, coefs, size); InterpT<&Ember<T>::m_CurveDE>(embers, coefs, size);
InterpT<&Ember<T>::m_SpatialFilterRadius>(embers, coefs, size); InterpT<&Ember<T>::m_SpatialFilterRadius>(embers, coefs, size);
InterpX<Curves<T>, &Ember<T>::m_Curves>(embers, coefs, size);
//An extra step needed here due to the OOD that was not needed in the original. //An extra step needed here due to the OOD that was not needed in the original.
//A small price to pay for the conveniences it affords us elsewhere. //A small price to pay for the conveniences it affords us elsewhere.
@ -1362,6 +1368,7 @@ public:
m_Xforms.clear(); m_Xforms.clear();
m_FinalXform.Clear(); m_FinalXform.Clear();
m_Curves.Init();
ClearEdit(); ClearEdit();
} }
@ -1651,6 +1658,9 @@ public:
//Xml field: "color" or "colors" or "palette" . //Xml field: "color" or "colors" or "palette" .
Palette<T> m_Palette; Palette<T> m_Palette;
//Curves used to adjust the color during final accumulation.
Curves<T> m_Curves;
//Strings. //Strings.
//The name of this ember. //The name of this ember.
@ -1674,6 +1684,15 @@ private:
/// </summary> /// </summary>
eScaleType m_ScaleType; eScaleType m_ScaleType;
//The vector containing all of the xforms.
//Xml field: "xform".
vector<Xform<T>> m_Xforms;
//Optional final xform. Default is empty.
//Discussed in section 3.2 of the paper, page 6.
//Xml field: "finalxform".
Xform<T> m_FinalXform;
/// <summary> /// <summary>
/// Interpolation function that takes the address of a member variable of type T as a template parameter. /// Interpolation function that takes the address of a member variable of type T as a template parameter.
/// This is an alternative to using macros. /// This is an alternative to using macros.
@ -1739,15 +1758,6 @@ private:
for (size_t k = 0; k < size; k++) for (size_t k = 0; k < size; k++)
xform->*m += coefs[k] * embers[k].GetTotalXform(i)->*m; xform->*m += coefs[k] * embers[k].GetTotalXform(i)->*m;
} }
//The vector containing all of the xforms.
//Xml field: "xform".
vector<Xform<T>> m_Xforms;
//Optional final xform. Default is empty.
//Discussed in section 3.2 of the paper, page 6.
//Xml field: "finalxform".
Xform<T> m_FinalXform;
}; };
/// <summary> /// <summary>

View File

@ -42,7 +42,7 @@
namespace EmberNs namespace EmberNs
{ {
#define EMBER_VERSION "0.4.1.8" #define EMBER_VERSION "0.4.1.9"
#define EPS6 T(1e-6) #define EPS6 T(1e-6)
#define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way. #define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
#define ISAAC_SIZE 4 #define ISAAC_SIZE 4
@ -83,13 +83,23 @@ typedef std::chrono::high_resolution_clock Clock;
#define DO_DOUBLE 1//Comment this out for shorter build times during development. Always uncomment for release. #define DO_DOUBLE 1//Comment this out for shorter build times during development. Always uncomment for release.
//#define ISAAC_FLAM3_DEBUG 1//This is almost never needed, but is very useful when troubleshooting difficult bugs. Enable it to do a side by side comparison with flam3. //#define ISAAC_FLAM3_DEBUG 1//This is almost never needed, but is very useful when troubleshooting difficult bugs. Enable it to do a side by side comparison with flam3.
#define v2T glm::detail::tvec2<T, glm::defaultp> #if GLM_VERSION >= 96
#define v3T glm::detail::tvec3<T, glm::defaultp> #define v2T glm::tvec2<T, glm::defaultp>
#define v4T glm::detail::tvec4<T, glm::defaultp> #define v3T glm::tvec3<T, glm::defaultp>
#define m2T glm::detail::tmat2x2<T, glm::defaultp> #define v4T glm::tvec4<T, glm::defaultp>
#define m3T glm::detail::tmat3x3<T, glm::defaultp> #define m2T glm::tmat2x2<T, glm::defaultp>
#define m4T glm::detail::tmat4x4<T, glm::defaultp> #define m3T glm::tmat3x3<T, glm::defaultp>
#define m23T glm::detail::tmat2x3<T, glm::defaultp> #define m4T glm::tmat4x4<T, glm::defaultp>
#define m23T glm::tmat2x3<T, glm::defaultp>
#else
#define v2T glm::detail::tvec2<T, glm::defaultp>
#define v3T glm::detail::tvec3<T, glm::defaultp>
#define v4T glm::detail::tvec4<T, glm::defaultp>
#define m2T glm::detail::tmat2x2<T, glm::defaultp>
#define m3T glm::detail::tmat3x3<T, glm::defaultp>
#define m4T glm::detail::tmat4x4<T, glm::defaultp>
#define m23T glm::detail::tmat2x3<T, glm::defaultp>
#endif
enum eInterp : uint { EMBER_INTERP_LINEAR = 0, EMBER_INTERP_SMOOTH = 1 }; enum eInterp : uint { EMBER_INTERP_LINEAR = 0, EMBER_INTERP_SMOOTH = 1 };
enum eAffineInterp : uint { INTERP_LINEAR = 0, INTERP_LOG = 1, INTERP_COMPAT = 2, INTERP_OLDER = 3 }; enum eAffineInterp : uint { INTERP_LINEAR = 0, INTERP_LOG = 1, INTERP_COMPAT = 2, INTERP_OLDER = 3 };

View File

@ -78,5 +78,7 @@
using namespace tbb; using namespace tbb;
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
using namespace glm;
using namespace glm::detail;
using glm::uint; using glm::uint;
using glm::uint16; using glm::uint16;

View File

@ -145,7 +145,7 @@ public:
os << " zoom=\"" << ember.m_Zoom << "\""; os << " zoom=\"" << ember.m_Zoom << "\"";
os << " rotate=\"" << ember.m_Rotate << "\""; os << " rotate=\"" << ember.m_Rotate << "\"";
os << " supersample=\"" << max<size_t>(1, ember.m_Supersample) << "\""; os << " supersample=\"" << std::max<size_t>(1, ember.m_Supersample) << "\"";
os << " filter=\"" << ember.m_SpatialFilterRadius << "\""; os << " filter=\"" << ember.m_SpatialFilterRadius << "\"";
os << " filter_shape=\"" << ToLower(SpatialFilterCreator<T>::ToString(ember.m_SpatialFilterType)) << "\""; os << " filter_shape=\"" << ToLower(SpatialFilterCreator<T>::ToString(ember.m_SpatialFilterType)) << "\"";
@ -207,7 +207,19 @@ public:
os << "\""; os << "\"";
os << " new_linear=\"1\""; os << " new_linear=\"1\"";
os << ">\n"; os << " curves=\"";
for (glm::length_t ci = 0; ci < 4; ci++)
{
for (glm::length_t cj = 0; cj < 4; cj++)
{
os << ember.m_Curves.m_Points[ci][cj].x << " ";
os << ember.m_Curves.m_Points[ci][cj].y << " ";
os << ember.m_Curves.m_Weights[ci][cj] << " ";
}
}
os << "\">\n";
//This is a grey area, what to do about symmetry to avoid duplicating the symmetry xforms when reading back?//TODO//BUG. //This is a grey area, what to do about symmetry to avoid duplicating the symmetry xforms when reading back?//TODO//BUG.
//if (ember.m_Symmetry) //if (ember.m_Symmetry)

View File

@ -533,7 +533,7 @@ public:
} }
//Identify the most saturated channel. //Identify the most saturated channel.
maxc = max(max(cBuf[0], cBuf[1]), cBuf[2]); maxc = std::max(std::max(cBuf[0], cBuf[1]), cBuf[2]);
maxa = ls * maxc; maxa = ls * maxc;
//If a channel is saturated and highlight power is non-negative //If a channel is saturated and highlight power is non-negative

View File

@ -28,41 +28,6 @@ Renderer<T, bucketT>::~Renderer()
/// Non-virtual processing functions. /// Non-virtual processing functions.
/// </summary> /// </summary>
/// <summary>
/// Compute the camera.
/// This sets up the bounds of the cartesian plane that the raster bounds correspond to.
/// This must be called after ComputeBounds() which sets up the raster bounds.
/// </summary>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::ComputeCamera()
{
m_Scale = pow(T(2.0), Zoom());
m_ScaledQuality = Quality() * m_Scale * m_Scale;
m_PixelsPerUnitX = PixelsPerUnit() * m_Scale;
m_PixelsPerUnitY = m_PixelsPerUnitX;
m_PixelsPerUnitX /= PixelAspectRatio();
T shift = 0;
T t0 = T(m_GutterWidth) / (Supersample() * m_PixelsPerUnitX);
T t1 = T(m_GutterWidth) / (Supersample() * m_PixelsPerUnitY);
//These go from ll to ur, moving from negative to positive.
m_LowerLeftX = CenterX() - FinalRasW() / m_PixelsPerUnitX / T(2.0);
m_LowerLeftY = CenterY() - FinalRasH() / m_PixelsPerUnitY / T(2.0);
m_UpperRightX = m_LowerLeftX + FinalRasW() / m_PixelsPerUnitX;
m_UpperRightY = m_LowerLeftY + FinalRasH() / m_PixelsPerUnitY;
T carLlX = m_LowerLeftX - t0;
T carLlY = m_LowerLeftY - t1 + shift;
T carUrX = m_UpperRightX + t0;
T carUrY = m_UpperRightY + t1 + shift;
m_RotMat.MakeID();
m_RotMat.Rotate(-Rotate());
m_CarToRas.Init(carLlX, carLlY, carUrX, carUrY, m_SuperRasW, m_SuperRasH, PixelAspectRatio());
}
/// <summary> /// <summary>
/// Add an ember to the end of the embers vector and reset the rendering process. /// Add an ember to the end of the embers vector and reset the rendering process.
/// Reset the rendering process. /// Reset the rendering process.
@ -124,7 +89,7 @@ void Renderer<T, bucketT>::ComputeBounds()
//If the radius of the density estimation filter is greater than the //If the radius of the density estimation filter is greater than the
//gutter width, have to pad with more. Otherwise, use the same value. //gutter width, have to pad with more. Otherwise, use the same value.
for (size_t i = 0; i < m_Embers.size(); i++) for (size_t i = 0; i < m_Embers.size(); i++)
maxDEFilterWidth = max(size_t(ceil(m_Embers[i].m_MaxRadDE) * m_Ember.m_Supersample), maxDEFilterWidth); maxDEFilterWidth = std::max<size_t>(size_t(ceil(m_Embers[i].m_MaxRadDE) * m_Ember.m_Supersample), maxDEFilterWidth);
//Need an extra ss = (int)floor(m_Supersample / 2.0) of pixels so that a local iteration count for DE can be determined.//SMOULDER //Need an extra ss = (int)floor(m_Supersample / 2.0) of pixels so that a local iteration count for DE can be determined.//SMOULDER
if (maxDEFilterWidth > 0) if (maxDEFilterWidth > 0)
@ -140,6 +105,50 @@ void Renderer<T, bucketT>::ComputeBounds()
m_SuperSize = m_SuperRasW * m_SuperRasH; m_SuperSize = m_SuperRasW * m_SuperRasH;
} }
/// <summary>
/// Compute the scale based on the zoom, then the quality based on the computed scale.
/// This sets up the bounds of the cartesian plane that the raster bounds correspond to.
/// This must be called before ComputeCamera() which will use scale.
/// </summary>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::ComputeQuality()
{
m_Scale = pow(T(2.0), Zoom());
m_ScaledQuality = Quality() * m_Scale * m_Scale;
}
/// <summary>
/// Compute the camera.
/// This sets up the bounds of the cartesian plane that the raster bounds correspond to.
/// This must be called after ComputeBounds() which sets up the raster bounds.
/// </summary>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::ComputeCamera()
{
m_PixelsPerUnitX = PixelsPerUnit() * m_Scale;
m_PixelsPerUnitY = m_PixelsPerUnitX;
m_PixelsPerUnitX /= PixelAspectRatio();
T shift = 0;
T t0 = T(m_GutterWidth) / (Supersample() * m_PixelsPerUnitX);
T t1 = T(m_GutterWidth) / (Supersample() * m_PixelsPerUnitY);
//These go from ll to ur, moving from negative to positive.
m_LowerLeftX = CenterX() - FinalRasW() / m_PixelsPerUnitX / T(2.0);
m_LowerLeftY = CenterY() - FinalRasH() / m_PixelsPerUnitY / T(2.0);
m_UpperRightX = m_LowerLeftX + FinalRasW() / m_PixelsPerUnitX;
m_UpperRightY = m_LowerLeftY + FinalRasH() / m_PixelsPerUnitY;
T carLlX = m_LowerLeftX - t0;
T carLlY = m_LowerLeftY - t1 + shift;
T carUrX = m_UpperRightX + t0;
T carUrY = m_UpperRightY + t1 + shift;
m_RotMat.MakeID();
m_RotMat.Rotate(-Rotate());
m_CarToRas.Init(carLlX, carLlY, carUrX, carUrY, m_SuperRasW, m_SuperRasH, PixelAspectRatio());
}
/// <summary> /// <summary>
/// Set the current ember. /// Set the current ember.
/// This will also populate the vector of embers with a single element copy /// This will also populate the vector of embers with a single element copy
@ -327,7 +336,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
bool accumOnly = m_ProcessAction == ACCUM_ONLY; bool accumOnly = m_ProcessAction == ACCUM_ONLY;
bool resume = m_ProcessState != NONE; bool resume = m_ProcessState != NONE;
bool newFilterAlloc; bool newFilterAlloc;
size_t temporalSample = 0; size_t i, temporalSample = 0;
T deTime; T deTime;
eRenderStatus success = RENDER_OK; eRenderStatus success = RENDER_OK;
//double iterationTime = 0; //double iterationTime = 0;
@ -353,6 +362,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
m_Gamma = 0; m_Gamma = 0;
m_Vibrancy = 0;//Accumulate these after each temporal sample. m_Vibrancy = 0;//Accumulate these after each temporal sample.
m_VibGamCount = 0; m_VibGamCount = 0;
m_CurvesSet = false;
m_Background.Clear(); m_Background.Clear();
} }
//User requested an increase in quality after finishing. //User requested an increase in quality after finishing.
@ -365,6 +375,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
m_Vibrancy = 0; m_Vibrancy = 0;
m_VibGamCount = 0; m_VibGamCount = 0;
m_Background.Clear(); m_Background.Clear();
ComputeQuality();//Must recompute quality when doing a quality increase.
} }
//Make sure values are within valid range. //Make sure values are within valid range.
@ -427,8 +438,9 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
Interpolater<T>::Interpolate(m_Embers, deTime, 0, m_Ember); Interpolater<T>::Interpolate(m_Embers, deTime, 0, m_Ember);
//it.Toc("Interp 2"); //it.Toc("Interp 2");
ClampGte<T>(m_Ember.m_MinRadDE, 0); ClampGteRef<T>(m_Ember.m_MinRadDE, 0);
ClampGte<T>(m_Ember.m_MaxRadDE, 0); ClampGteRef<T>(m_Ember.m_MaxRadDE, 0);
ClampGteRef<T>(m_Ember.m_MaxRadDE, m_Ember.m_MinRadDE);
if (!CreateDEFilter(newFilterAlloc)) if (!CreateDEFilter(newFilterAlloc))
{ {
@ -446,7 +458,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//Interpolate again. //Interpolate again.
//it.Tic(); //it.Tic();
if (m_Embers.size() > 1) if (TemporalSamples() > 1 && m_Embers.size() > 1)
Interpolater<T>::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators. Interpolater<T>::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
//it.Toc("Interp 3"); //it.Toc("Interp 3");
@ -458,13 +470,16 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
goto Finish; goto Finish;
} }
ComputeCamera(); //Don't need to do this every time through for a single image.
if (TemporalSamples() > 1 || !resume)
//For each temporal sample, the palette m_Dmap needs to be re-created with color scalar. 1 if no temporal samples. {
MakeDmap(colorScalar); ComputeQuality();
ComputeCamera();
MakeDmap(colorScalar);//For each temporal sample, the palette m_Dmap needs to be re-created with color scalar. 1 if no temporal samples.
}
//The actual number of times to iterate. Each thread will get (totalIters / ThreadCount) iters to do. //The actual number of times to iterate. Each thread will get (totalIters / ThreadCount) iters to do.
//This is based on zoom and scale calculated in ComputeCamera(). //This is based on zoom and scale calculated in ComputeQuality().
//Note that the iter count is based on the final image dimensions, and not the super sampled dimensions. //Note that the iter count is based on the final image dimensions, and not the super sampled dimensions.
size_t itersPerTemporalSample = ItersPerTemporalSample();//The total number of iterations for this temporal sample without overrides. size_t itersPerTemporalSample = ItersPerTemporalSample();//The total number of iterations for this temporal sample without overrides.
size_t sampleItersToDo;//The number of iterations to actually do in this sample, considering overrides. size_t sampleItersToDo;//The number of iterations to actually do in this sample, considering overrides.
@ -474,7 +489,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
else else
sampleItersToDo = itersPerTemporalSample;//Run as many iters as specified to complete this temporal sample. sampleItersToDo = itersPerTemporalSample;//Run as many iters as specified to complete this temporal sample.
sampleItersToDo = min(sampleItersToDo, itersPerTemporalSample - m_LastIter); sampleItersToDo = std::min<size_t>(sampleItersToDo, itersPerTemporalSample - m_LastIter);
EmberStats stats = Iterate(sampleItersToDo, temporalSample);//The heavy work is done here. EmberStats stats = Iterate(sampleItersToDo, temporalSample);//The heavy work is done here.
//If no iters were executed, something went catastrophically wrong. //If no iters were executed, something went catastrophically wrong.
@ -602,6 +617,13 @@ AccumOnly:
//Make sure a filter has been created. //Make sure a filter has been created.
CreateSpatialFilter(newFilterAlloc); CreateSpatialFilter(newFilterAlloc);
m_CurvesSet = m_Ember.m_Curves.CurvesSet();
//Color curves must be re-calculated as well.
if (m_CurvesSet)
for (i = 0; i < COLORMAP_LENGTH; i++)
m_Csa[i] = m_Ember.m_Curves.BezierFunc(i / T(COLORMAP_LENGTH_MINUS_1)) * T(COLORMAP_LENGTH_MINUS_1);
if (AccumulatorToFinalImage(finalImage, finalOffset) == RENDER_OK) if (AccumulatorToFinalImage(finalImage, finalOffset) == RENDER_OK)
{ {
m_Stats.m_RenderMs = m_RenderTimer.Toc();//Record total time from the very beginning to the very end, including all intermediate calls. m_Stats.m_RenderMs = m_RenderTimer.Toc();//Record total time from the very beginning to the very end, including all intermediate calls.
@ -839,17 +861,17 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
parallel_for(size_t(0), threads, [&] (size_t threadIndex) parallel_for(size_t(0), threads, [&] (size_t threadIndex)
{ {
size_t pixelNumber = 0; size_t pixelNumber = 0;
int localStartRow = int(min(startRow + (threadIndex * chunkSize), endRow - 1)); int localStartRow = int(std::min<size_t>(startRow + (threadIndex * chunkSize), endRow - 1));
int localEndRow = int(min(localStartRow + chunkSize, endRow)); int localEndRow = int(std::min<size_t>(localStartRow + chunkSize, endRow));
size_t pixelsThisThread = size_t(localEndRow - localStartRow) * m_SuperRasW; size_t pixelsThisThread = size_t(localEndRow - localStartRow) * m_SuperRasW;
double lastPercent = 0; double lastPercent = 0;
glm::detail::tvec4<bucketT, glm::defaultp> logScaleBucket; tvec4<bucketT, glm::defaultp> logScaleBucket;
for (intmax_t j = localStartRow; (j < localEndRow) && !m_Abort; j++) for (intmax_t j = localStartRow; (j < localEndRow) && !m_Abort; j++)
{ {
size_t bucketRowStart = j * m_SuperRasW;//Pull out of inner loop for optimization. size_t bucketRowStart = j * m_SuperRasW;//Pull out of inner loop for optimization.
const glm::detail::tvec4<bucketT, glm::defaultp>* bucket; const tvec4<bucketT, glm::defaultp>* bucket;
const glm::detail::tvec4<bucketT, glm::defaultp>* buckets = m_HistBuckets.data(); const tvec4<bucketT, glm::defaultp>* buckets = m_HistBuckets.data();
const T* filterCoefs = m_DensityFilter->Coefs(); const T* filterCoefs = m_DensityFilter->Coefs();
const T* filterWidths = m_DensityFilter->Widths(); const T* filterWidths = m_DensityFilter->Widths();
@ -875,10 +897,10 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
//The original contained a glaring flaw as it would run past the boundaries of the buffers //The original contained a glaring flaw as it would run past the boundaries of the buffers
//when calculating the density for a box centered on the last row or column. //when calculating the density for a box centered on the last row or column.
//Clamp here to not run over the edge. //Clamp here to not run over the edge.
intmax_t densityBoxLeftX = (i - min(i, ss)); intmax_t densityBoxLeftX = (i - std::min(i, ss));
intmax_t densityBoxRightX = (i + min(ss, intmax_t(m_SuperRasW) - i - 1)); intmax_t densityBoxRightX = (i + std::min(ss, intmax_t(m_SuperRasW) - i - 1));
intmax_t densityBoxTopY = (j - min(j, ss)); intmax_t densityBoxTopY = (j - std::min(j, ss));
intmax_t densityBoxBottomY = (j + min(ss, intmax_t(m_SuperRasH) - j - 1)); intmax_t densityBoxBottomY = (j + std::min(ss, intmax_t(m_SuperRasH) - j - 1));
//Count density in ssxss area. //Count density in ssxss area.
//Original went one col at a time, which is cache inefficient. Go one row at at time here for a slight speedup. //Original went one col at a time, which is cache inefficient. Go one row at at time here for a slight speedup.
@ -1048,7 +1070,7 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
Color<bucketT> newBucket; Color<bucketT> newBucket;
size_t pixelsRowStart = (m_YAxisUp ? ((FinalRasH() - j) - 1) : j) * FinalRowSize();//Pull out of inner loop for optimization. size_t pixelsRowStart = (m_YAxisUp ? ((FinalRasH() - j) - 1) : j) * FinalRowSize();//Pull out of inner loop for optimization.
size_t y = m_DensityFilterOffset + (j * Supersample());//Start at the beginning row of each super sample block. size_t y = m_DensityFilterOffset + (j * Supersample());//Start at the beginning row of each super sample block.
uint16* p16; glm::uint16* p16;
for (size_t i = 0; i < FinalRasW(); i++, pixelsRowStart += PixelSize()) for (size_t i = 0; i < FinalRasW(); i++, pixelsRowStart += PixelSize())
{ {
@ -1074,13 +1096,20 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
if (BytesPerChannel() == 2) if (BytesPerChannel() == 2)
{ {
p16 = reinterpret_cast<uint16*>(pixels + pixelsRowStart); p16 = reinterpret_cast<glm::uint16*>(pixels + pixelsRowStart);
if (EarlyClip()) if (EarlyClip())
{ {
p16[0] = uint16(Clamp<bucketT>(newBucket.r, 0, 255) * bucketT(256)); if (m_CurvesSet)
p16[1] = uint16(Clamp<bucketT>(newBucket.g, 0, 255) * bucketT(256)); {
p16[2] = uint16(Clamp<bucketT>(newBucket.b, 0, 255) * bucketT(256)); CurveAdjust(newBucket.r, 1);
CurveAdjust(newBucket.g, 2);
CurveAdjust(newBucket.b, 3);
}
p16[0] = glm::uint16(Clamp<bucketT>(newBucket.r, 0, 255) * bucketT(256));
p16[1] = glm::uint16(Clamp<bucketT>(newBucket.g, 0, 255) * bucketT(256));
p16[2] = glm::uint16(Clamp<bucketT>(newBucket.b, 0, 255) * bucketT(256));
if (NumChannels() > 3) if (NumChannels() > 3)
{ {
@ -1092,13 +1121,20 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
} }
else else
{ {
GammaCorrection(*(reinterpret_cast<glm::detail::tvec4<bucketT, glm::defaultp>*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, p16); GammaCorrection(*(reinterpret_cast<tvec4<bucketT, glm::defaultp>*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, p16);
} }
} }
else else
{ {
if (EarlyClip()) if (EarlyClip())
{ {
if (m_CurvesSet)
{
CurveAdjust(newBucket.r, 1);
CurveAdjust(newBucket.g, 2);
CurveAdjust(newBucket.b, 3);
}
pixels[pixelsRowStart] = byte(Clamp<bucketT>(newBucket.r, 0, 255)); pixels[pixelsRowStart] = byte(Clamp<bucketT>(newBucket.r, 0, 255));
pixels[pixelsRowStart + 1] = byte(Clamp<bucketT>(newBucket.g, 0, 255)); pixels[pixelsRowStart + 1] = byte(Clamp<bucketT>(newBucket.g, 0, 255));
pixels[pixelsRowStart + 2] = byte(Clamp<bucketT>(newBucket.b, 0, 255)); pixels[pixelsRowStart + 2] = byte(Clamp<bucketT>(newBucket.b, 0, 255));
@ -1113,7 +1149,7 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
} }
else else
{ {
GammaCorrection(*(reinterpret_cast<glm::detail::tvec4<bucketT, glm::defaultp>*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, pixels + pixelsRowStart); GammaCorrection(*(reinterpret_cast<tvec4<bucketT, glm::defaultp>*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, pixels + pixelsRowStart);
} }
} }
} }
@ -1183,7 +1219,7 @@ EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t temporalSample
IterParams<T> params; IterParams<T> params;
m_BadVals[threadIndex] = 0; m_BadVals[threadIndex] = 0;
params.m_Count = min(totalItersPerThread, SubBatchSize()); params.m_Count = std::min(totalItersPerThread, SubBatchSize());
params.m_Skip = FuseCount(); params.m_Skip = FuseCount();
//params.m_OneColDiv2 = m_CarToRas.OneCol() / 2; //params.m_OneColDiv2 = m_CarToRas.OneCol() / 2;
//params.m_OneRowDiv2 = m_CarToRas.OneRow() / 2; //params.m_OneRowDiv2 = m_CarToRas.OneRow() / 2;
@ -1193,7 +1229,7 @@ EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t temporalSample
{ {
//Must recalculate the number of iters to run on each sub batch because the last batch will most likely have less than SubBatchSize iters. //Must recalculate the number of iters to run on each sub batch because the last batch will most likely have less than SubBatchSize iters.
//For example, if 51,000 are requested, and the sbs is 10,000, it should run 5 sub batches of 10,000 iters, and one final sub batch of 1,000 iters. //For example, if 51,000 are requested, and the sbs is 10,000, it should run 5 sub batches of 10,000 iters, and one final sub batch of 1,000 iters.
params.m_Count = min(params.m_Count, totalItersPerThread - m_SubBatch[threadIndex]); params.m_Count = std::min(params.m_Count, totalItersPerThread - m_SubBatch[threadIndex]);
//Use first as random point, the rest are iterated points. //Use first as random point, the rest are iterated points.
//Note that this gets reset with a new random point for each subBatchSize iterations. //Note that this gets reset with a new random point for each subBatchSize iterations.
@ -1290,16 +1326,16 @@ void Renderer<T, bucketT>::PixelAspectRatio(T pixelAspectRatio)
/// Non-virtual renderer properties, getters only. /// Non-virtual renderer properties, getters only.
/// </summary> /// </summary>
template <typename T, typename bucketT> T Renderer<T, bucketT>::Scale() const { return m_Scale; } template <typename T, typename bucketT> T Renderer<T, bucketT>::Scale() const { return m_Scale; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitX() const { return m_PixelsPerUnitX; } template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitX() const { return m_PixelsPerUnitX; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitY() const { return m_PixelsPerUnitY; } template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitY() const { return m_PixelsPerUnitY; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::K1() const { return m_K1; } template <typename T, typename bucketT> T Renderer<T, bucketT>::K1() const { return m_K1; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::K2() const { return m_K2; } template <typename T, typename bucketT> T Renderer<T, bucketT>::K2() const { return m_K2; }
template <typename T, typename bucketT> const CarToRas<T>* Renderer<T, bucketT>::CoordMap() const { return &m_CarToRas; } template <typename T, typename bucketT> const CarToRas<T>* Renderer<T, bucketT>::CoordMap() const { return &m_CarToRas; }
template <typename T, typename bucketT> glm::detail::tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::HistBuckets() { return m_HistBuckets.data(); } template <typename T, typename bucketT> tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::HistBuckets() { return m_HistBuckets.data(); }
template <typename T, typename bucketT> glm::detail::tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::AccumulatorBuckets() { return m_AccumulatorBuckets.data(); } template <typename T, typename bucketT> tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::AccumulatorBuckets() { return m_AccumulatorBuckets.data(); }
template <typename T, typename bucketT> SpatialFilter<T>* Renderer<T, bucketT>::GetSpatialFilter() { return m_SpatialFilter.get(); } template <typename T, typename bucketT> SpatialFilter<T>* Renderer<T, bucketT>::GetSpatialFilter() { return m_SpatialFilter.get(); }
template <typename T, typename bucketT> TemporalFilter<T>* Renderer<T, bucketT>::GetTemporalFilter() { return m_TemporalFilter.get(); } template <typename T, typename bucketT> TemporalFilter<T>* Renderer<T, bucketT>::GetTemporalFilter() { return m_TemporalFilter.get(); }
/// <summary> /// <summary>
/// Virtual renderer properties overridden from RendererBase, getters only. /// Virtual renderer properties overridden from RendererBase, getters only.
@ -1405,7 +1441,7 @@ void Renderer<T, bucketT>::Accumulate(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, Poin
{ {
size_t histIndex, intColorIndex, histSize = m_HistBuckets.size(); size_t histIndex, intColorIndex, histSize = m_HistBuckets.size();
bucketT colorIndex, colorIndexFrac; bucketT colorIndex, colorIndexFrac;
const glm::detail::tvec4<bucketT, glm::defaultp>* dmap = &(palette->m_Entries[0]); const tvec4<bucketT, glm::defaultp>* dmap = &(palette->m_Entries[0]);
//T oneColDiv2 = m_CarToRas.OneCol() / 2; //T oneColDiv2 = m_CarToRas.OneCol() / 2;
//T oneRowDiv2 = m_CarToRas.OneRow() / 2; //T oneRowDiv2 = m_CarToRas.OneRow() / 2;
@ -1512,7 +1548,7 @@ void Renderer<T, bucketT>::Accumulate(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, Poin
/// <param name="j">The row of the bucket</param> /// <param name="j">The row of the bucket</param>
/// <param name="jj">The offset to add to the row</param> /// <param name="jj">The offset to add to the row</param>
template <typename T, typename bucketT> template <typename T, typename bucketT>
void Renderer<T, bucketT>::AddToAccum(const glm::detail::tvec4<bucketT, glm::defaultp>& bucket, intmax_t i, intmax_t ii, intmax_t j, intmax_t jj) void Renderer<T, bucketT>::AddToAccum(const tvec4<bucketT, glm::defaultp>& bucket, intmax_t i, intmax_t ii, intmax_t j, intmax_t jj)
{ {
if (j + jj >= 0 && j + jj < intmax_t(m_SuperRasH) && i + ii >= 0 && i + ii < intmax_t(m_SuperRasW)) if (j + jj >= 0 && j + jj < intmax_t(m_SuperRasH) && i + ii >= 0 && i + ii < intmax_t(m_SuperRasW))
m_AccumulatorBuckets[(i + ii) + ((j + jj) * m_SuperRasW)] += bucket; m_AccumulatorBuckets[(i + ii) + ((j + jj) * m_SuperRasW)] += bucket;
@ -1536,7 +1572,7 @@ void Renderer<T, bucketT>::AddToAccum(const glm::detail::tvec4<bucketT, glm::def
/// <param name="correctedChannels">The storage space for the corrected values to be written to</param> /// <param name="correctedChannels">The storage space for the corrected values to be written to</param>
template <typename T, typename bucketT> template <typename T, typename bucketT>
template <typename accumT> template <typename accumT>
void Renderer<T, bucketT>::GammaCorrection(glm::detail::tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels) void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels)
{ {
T alpha, ls, a; T alpha, ls, a;
bucketT newRgb[3];//Would normally use a Color<bucketT>, but don't want to call a needless constructor every time this function is called, which is once per pixel. bucketT newRgb[3];//Would normally use a Color<bucketT>, but don't want to call a needless constructor every time this function is called, which is once per pixel.
@ -1573,9 +1609,16 @@ void Renderer<T, bucketT>::GammaCorrection(glm::detail::tvec4<bucketT, glm::defa
} }
if (!scale) if (!scale)
{
correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255));//Early clip, just assign directly. correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255));//Early clip, just assign directly.
}
else else
{
if (m_CurvesSet)
CurveAdjust(a, rgbi + 1);
correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255) * scaleVal);//Final accum, multiply by 1 for 8 bpc, or 256 for 16 bpc. correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255) * scaleVal);//Final accum, multiply by 1 for 8 bpc, or 256 for 16 bpc.
}
} }
if (doAlpha) if (doAlpha)
@ -1589,6 +1632,15 @@ void Renderer<T, bucketT>::GammaCorrection(glm::detail::tvec4<bucketT, glm::defa
} }
} }
template <typename T, typename bucketT>
void Renderer<T, bucketT>::CurveAdjust(T& a, const glm::length_t& index)
{
size_t tempIndex = size_t(Clamp<T>(a, 0, COLORMAP_LENGTH_MINUS_1));
size_t tempIndex2 = size_t(Clamp<T>(m_Csa[tempIndex].x, 0, COLORMAP_LENGTH_MINUS_1));
a = std::round(m_Csa[tempIndex2][index]);
}
//This class had to be implemented in a cpp file because the compiler was breaking. //This class had to be implemented in a cpp file because the compiler was breaking.
//So the explicit instantiation must be declared here rather than in Ember.cpp where //So the explicit instantiation must be declared here rather than in Ember.cpp where
//all of the other classes are done. //all of the other classes are done.

View File

@ -56,13 +56,14 @@ public:
//Virtual processing functions overriden from RendererBase. //Virtual processing functions overriden from RendererBase.
virtual void ComputeBounds() override; virtual void ComputeBounds() override;
virtual void ComputeQuality() override;
virtual void ComputeCamera() override; virtual void ComputeCamera() override;
virtual void SetEmber(Ember<T>& ember, eProcessAction action = FULL_RENDER) override; virtual void SetEmber(Ember<T>& ember, eProcessAction action = FULL_RENDER) override;
virtual void SetEmber(vector<Ember<T>>& embers) override; virtual void SetEmber(vector<Ember<T>>& embers) override;
virtual bool CreateDEFilter(bool& newAlloc) override; virtual bool CreateDEFilter(bool& newAlloc) override;
virtual bool CreateSpatialFilter(bool& newAlloc) override; virtual bool CreateSpatialFilter(bool& newAlloc) override;
virtual bool CreateTemporalFilter(bool& newAlloc) override; virtual bool CreateTemporalFilter(bool& newAlloc) override;
virtual size_t HistBucketSize() const override { return sizeof(glm::detail::tvec4<bucketT, glm::defaultp>); } virtual size_t HistBucketSize() const override { return sizeof(tvec4<bucketT, glm::defaultp>); }
virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) override; virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) override;
virtual EmberImageComments ImageComments(EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) override; virtual EmberImageComments ImageComments(EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) override;
@ -83,16 +84,16 @@ public:
void PixelAspectRatio(T pixelAspectRatio); void PixelAspectRatio(T pixelAspectRatio);
//Non-virtual renderer properties, getters only. //Non-virtual renderer properties, getters only.
inline T Scale() const; inline T Scale() const;
inline T PixelsPerUnitX() const; inline T PixelsPerUnitX() const;
inline T PixelsPerUnitY() const; inline T PixelsPerUnitY() const;
inline T K1() const; inline T K1() const;
inline T K2() const; inline T K2() const;
inline const CarToRas<T>* CoordMap() const; inline const CarToRas<T>* CoordMap() const;
inline glm::detail::tvec4<bucketT, glm::defaultp>* HistBuckets(); inline tvec4<bucketT, glm::defaultp>* HistBuckets();
inline glm::detail::tvec4<bucketT, glm::defaultp>* AccumulatorBuckets(); inline tvec4<bucketT, glm::defaultp>* AccumulatorBuckets();
inline SpatialFilter<T>* GetSpatialFilter(); inline SpatialFilter<T>* GetSpatialFilter();
inline TemporalFilter<T>* GetTemporalFilter(); inline TemporalFilter<T>* GetTemporalFilter();
//Virtual renderer properties overridden from RendererBase, getters only. //Virtual renderer properties overridden from RendererBase, getters only.
virtual double ScaledQuality() const override; virtual double ScaledQuality() const override;
@ -150,8 +151,9 @@ protected:
private: private:
//Miscellaneous non-virtual functions used only in this class. //Miscellaneous non-virtual functions used only in this class.
void Accumulate(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, Point<T>* samples, size_t sampleCount, const Palette<bucketT>* palette); void Accumulate(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, Point<T>* samples, size_t sampleCount, const Palette<bucketT>* palette);
/*inline*/ void AddToAccum(const glm::detail::tvec4<bucketT, glm::defaultp>& bucket, intmax_t i, intmax_t ii, intmax_t j, intmax_t jj); /*inline*/ void AddToAccum(const tvec4<bucketT, glm::defaultp>& bucket, intmax_t i, intmax_t ii, intmax_t j, intmax_t jj);
template <typename accumT> void GammaCorrection(glm::detail::tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels); template <typename accumT> void GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels);
void CurveAdjust(T& a, const glm::length_t& index);
protected: protected:
T m_Scale; T m_Scale;
@ -177,9 +179,9 @@ protected:
Iterator<T>* m_Iterator; Iterator<T>* m_Iterator;
unique_ptr<StandardIterator<T>> m_StandardIterator; unique_ptr<StandardIterator<T>> m_StandardIterator;
unique_ptr<XaosIterator<T>> m_XaosIterator; unique_ptr<XaosIterator<T>> m_XaosIterator;
Palette<bucketT> m_Dmap; Palette<bucketT> m_Dmap, m_Csa;
vector<glm::detail::tvec4<bucketT, glm::defaultp>> m_HistBuckets; vector<tvec4<bucketT, glm::defaultp>> m_HistBuckets;
vector<glm::detail::tvec4<bucketT, glm::defaultp>> m_AccumulatorBuckets; vector<tvec4<bucketT, glm::defaultp>> m_AccumulatorBuckets;
unique_ptr<SpatialFilter<T>> m_SpatialFilter; unique_ptr<SpatialFilter<T>> m_SpatialFilter;
unique_ptr<TemporalFilter<T>> m_TemporalFilter; unique_ptr<TemporalFilter<T>> m_TemporalFilter;
unique_ptr<DensityFilter<T>> m_DensityFilter; unique_ptr<DensityFilter<T>> m_DensityFilter;

View File

@ -16,6 +16,7 @@ RendererBase::RendererBase()
m_YAxisUp = false; m_YAxisUp = false;
m_InsertPalette = false; m_InsertPalette = false;
m_ReclaimOnResize = false; m_ReclaimOnResize = false;
m_CurvesSet = false;
m_NumChannels = 3; m_NumChannels = 3;
m_BytesPerChannel = 1; m_BytesPerChannel = 1;
m_SuperSize = 0; m_SuperSize = 0;
@ -469,7 +470,7 @@ void RendererBase::ThreadCount(size_t threads, const char* seedString)
if (seedString) if (seedString)
{ {
memset(seeds, 0, isaacSize * sizeof(ISAAC_INT)); memset(seeds, 0, isaacSize * sizeof(ISAAC_INT));
memcpy(reinterpret_cast<char*>(seeds), seedString, min(strlen(seedString), isaacSize * sizeof(ISAAC_INT))); memcpy(reinterpret_cast<char*>(seeds), seedString, std::min(strlen(seedString), isaacSize * sizeof(ISAAC_INT)));
} }
//This is critical for multithreading, otherwise the threads all happen //This is critical for multithreading, otherwise the threads all happen

View File

@ -117,6 +117,7 @@ public:
virtual bool CreateSpatialFilter(bool& newAlloc) = 0; virtual bool CreateSpatialFilter(bool& newAlloc) = 0;
virtual bool CreateTemporalFilter(bool& newAlloc) = 0; virtual bool CreateTemporalFilter(bool& newAlloc) = 0;
virtual void ComputeBounds() = 0; virtual void ComputeBounds() = 0;
virtual void ComputeQuality() = 0;
virtual void ComputeCamera() = 0; virtual void ComputeCamera() = 0;
virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) = 0; virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) = 0;
virtual EmberImageComments ImageComments(EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) = 0; virtual EmberImageComments ImageComments(EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) = 0;
@ -201,6 +202,7 @@ protected:
bool m_InFinalAccum; bool m_InFinalAccum;
bool m_InsertPalette; bool m_InsertPalette;
bool m_ReclaimOnResize; bool m_ReclaimOnResize;
bool m_CurvesSet;
volatile bool m_Abort; volatile bool m_Abort;
size_t m_SuperRasW; size_t m_SuperRasW;
size_t m_SuperRasH; size_t m_SuperRasH;

View File

@ -1288,6 +1288,7 @@ public:
m_Renderer->CreateSpatialFilter(newAlloc); m_Renderer->CreateSpatialFilter(newAlloc);
m_Renderer->CreateDEFilter(newAlloc); m_Renderer->CreateDEFilter(newAlloc);
m_Renderer->ComputeBounds(); m_Renderer->ComputeBounds();
m_Renderer->ComputeQuality();
m_Renderer->ComputeCamera(); m_Renderer->ComputeCamera();
if (ember.XaosPresent()) if (ember.XaosPresent())

View File

@ -1506,7 +1506,7 @@ public:
{ {
case REAL : case REAL :
{ {
*m_Param = max(min(val, m_Max), m_Min); *m_Param = std::max(std::min(val, m_Max), m_Min);
break; break;
} }
@ -1524,7 +1524,7 @@ public:
case REAL_NONZERO : case REAL_NONZERO :
{ {
T vd = max(min(val, m_Max), m_Min); T vd = std::max(std::min(val, m_Max), m_Min);
if (IsNearZero(vd)) if (IsNearZero(vd))
*m_Param = EPS * SignNz(vd); *m_Param = EPS * SignNz(vd);
@ -1536,14 +1536,14 @@ public:
case INTEGER : case INTEGER :
{ {
*m_Param = T(int(max(min<T>(T(Floor<T>(val + T(0.5))), m_Max), m_Min))); *m_Param = T(int(std::max(std::min<T>(T(Floor<T>(val + T(0.5))), m_Max), m_Min)));
break; break;
} }
case INTEGER_NONZERO : case INTEGER_NONZERO :
default: default:
{ {
int vi = int(max(min<T>(T(Floor<T>(val + T(0.5))), m_Max), m_Min)); int vi = int(std::max(std::min<T>(T(Floor<T>(val + T(0.5))), m_Max), m_Min));
if (vi == 0) if (vi == 0)
vi = int(SignNz<T>(val)); vi = int(SignNz<T>(val));

View File

@ -3773,8 +3773,8 @@ public:
{ {
m_XAmpV = m_Weight * m_XAmp; m_XAmpV = m_Weight * m_XAmp;
m_YAmpV = m_Weight * m_YAmp; m_YAmpV = m_Weight * m_YAmp;
m_XLengthV = 1 / max(SQR(m_XLength), T(1e-20)); m_XLengthV = 1 / std::max(SQR(m_XLength), T(1e-20));
m_YLengthV = 1 / max(SQR(m_YLength), T(1e-20)); m_YLengthV = 1 / std::max(SQR(m_YLength), T(1e-20));
} }
virtual void Random(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override virtual void Random(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override

View File

@ -4610,7 +4610,7 @@ public:
T y = (helper.In.y * m_S) + m_CenterY; T y = (helper.In.y * m_S) + m_CenterY;
//Calculate distance from center but constrain it to EPS. //Calculate distance from center but constrain it to EPS.
T d = max(EPS, sqrt(SQR(x) * SQR(y))); T d = std::max(EPS, sqrt(SQR(x) * SQR(y)));
//Normalize x and y. //Normalize x and y.
T nx = x / d; T nx = x / d;

View File

@ -4530,7 +4530,7 @@ public:
m_Ay = ((fabs(m_AreaY) < 0.1) ? T(0.1) : fabs(m_AreaY)) * agdoa; m_Ay = ((fabs(m_AreaY) < 0.1) ? T(0.1) : fabs(m_AreaY)) * agdoa;
m_Cx = m_CenterX * agdoc; m_Cx = m_CenterX * agdoc;
m_Cy = m_CenterY * agdoc; m_Cy = m_CenterY * agdoc;
m_B = m_Gamma * agdoa / (max(m_Ax, m_Ay)); m_B = m_Gamma * agdoa / (std::max(m_Ax, m_Ay));
} }
protected: protected:

View File

@ -2119,8 +2119,8 @@ public:
const T ay = rand.Frand<T>(T(-0.5), T(0.5)); const T ay = rand.Frand<T>(T(-0.5), T(0.5));
const T az = rand.Frand<T>(T(-0.5), T(0.5)); const T az = rand.Frand<T>(T(-0.5), T(0.5));
const T r = sqrt(Sqr(helper.In.x - m_X0) + Sqr(helper.In.y - m_Y0) + Sqr(helper.In.z - m_Z0)); const T r = sqrt(Sqr(helper.In.x - m_X0) + Sqr(helper.In.y - m_Y0) + Sqr(helper.In.z - m_Z0));
const T rc = ((m_Invert != 0 ? max<T>(1 - r, 0) : max<T>(r, 0)) - m_MinDist) * m_InternalScatter;//Original called a macro named min, which internally performed max. const T rc = ((m_Invert != 0 ? std::max<T>(1 - r, 0) : std::max<T>(r, 0)) - m_MinDist) * m_InternalScatter;//Original called a macro named min, which internally performed max.
const T rs = max<T>(rc, 0); const T rs = std::max<T>(rc, 0);
T sigma, phi, rad, sigmas, sigmac, phis, phic; T sigma, phi, rad, sigmas, sigmac, phis, phic;
T scale, denom; T scale, denom;
@ -2279,8 +2279,8 @@ public:
{ {
const v4T random(rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5))); const v4T random(rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5)), rand.Frand<T>(T(-0.5), T(0.5)));
const T distA = sqrt(Sqr(helper.In.x - m_X0) + Sqr(helper.In.y - m_Y0) + Sqr(helper.In.z - m_Z0)); const T distA = sqrt(Sqr(helper.In.x - m_X0) + Sqr(helper.In.y - m_Y0) + Sqr(helper.In.z - m_Z0));
const T distB = m_Invert != 0 ? max<T>(1 - distA, 0) : max<T>(distA, 0);//Original called a macro named min, which internally performed max. const T distB = m_Invert != 0 ? std::max<T>(1 - distA, 0) : std::max<T>(distA, 0);//Original called a macro named min, which internally performed max.
const T dist = max<T>((distB - m_MinDist) * m_RMax, 0); const T dist = std::max<T>((distB - m_MinDist) * m_RMax, 0);
switch (int(m_Type)) switch (int(m_Type))
{ {
@ -2484,11 +2484,11 @@ public:
break; break;
case 1://Square. case 1://Square.
default: default:
radius = max(fabs(helper.In.x - m_CenterX), max(fabs(helper.In.y - m_CenterY), (fabs(helper.In.z - m_CenterZ))));//Original called a macro named min, which internally performed max. radius = std::max(fabs(helper.In.x - m_CenterX), std::max(fabs(helper.In.y - m_CenterY), (fabs(helper.In.z - m_CenterZ))));//Original called a macro named min, which internally performed max.
break; break;
} }
const T dist = max<T>(((m_InvertDistance != 0 ? max<T>(1 - radius, 0) : max<T>(radius, 0)) - m_MinDistance) * m_RMax, 0); const T dist = std::max<T>(((m_InvertDistance != 0 ? std::max<T>(1 - radius, 0) : std::max<T>(radius, 0)) - m_MinDistance) * m_RMax, 0);
switch (int(m_BlurType)) switch (int(m_BlurType))
{ {

View File

@ -550,8 +550,8 @@ private:
char* attStr; char* attStr;
const char* loc = __FUNCTION__; const char* loc = __FUNCTION__;
int soloXform = -1; int soloXform = -1;
uint i, count, index = 0; uint i, j, count, index = 0;
double vals[10]; double vals[16];
xmlAttrPtr att, curAtt; xmlAttrPtr att, curAtt;
xmlNodePtr editNode, childNode, motionNode; xmlNodePtr editNode, childNode, motionNode;
@ -704,6 +704,20 @@ private:
Atof(attStr, currentEmber.m_Hue); Atof(attStr, currentEmber.m_Hue);
currentEmber.m_Hue = fmod(currentEmber.m_Hue, T(0.5));//Orig did fmod 1, but want it in the range -0.5 - 0.5. currentEmber.m_Hue = fmod(currentEmber.m_Hue, T(0.5));//Orig did fmod 1, but want it in the range -0.5 - 0.5.
} }
else if (!Compare(curAtt->name, "curves"))
{
stringstream ss(attStr);
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
ss >> currentEmber.m_Curves.m_Points[i][j].x;
ss >> currentEmber.m_Curves.m_Points[i][j].y;
ss >> currentEmber.m_Curves.m_Weights[i][j];
}
}
}
xmlFree(attStr); xmlFree(attStr);
} }

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,8 FILEVERSION 0,4,1,9
PRODUCTVERSION 0,4,1,8 PRODUCTVERSION 0,4,1,9
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as animations with motion blur" VALUE "FileDescription", "Renders fractal flames as animations with motion blur"
VALUE "FileVersion", "0.4.1.8" VALUE "FileVersion", "0.4.1.9"
VALUE "InternalName", "EmberAnimate.rc" VALUE "InternalName", "EmberAnimate.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberAnimate.rc" VALUE "OriginalFilename", "EmberAnimate.rc"
VALUE "ProductName", "Ember Animate" VALUE "ProductName", "Ember Animate"
VALUE "ProductVersion", "0.4.1.8" VALUE "ProductVersion", "0.4.1.9"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -140,6 +140,21 @@ static const char* CalcAlphaFunctionString =
"}\n" "}\n"
"\n"; "\n";
/// <summary>
/// OpenCL equivalent of Renderer::CurveAdjust().
/// Only use float here instead of real_t because the output will be passed to write_imagef()
/// during final accumulation, which only takes floats.
/// </summary>
static const char* CurveAdjustFunctionString =
"static inline void CurveAdjust(__constant real4reals* csa, float* a, uint index)\n"
"{\n"
" uint tempIndex = (uint)Clamp(*a, 0.0, (float)COLORMAP_LENGTH_MINUS_1);\n"
" uint tempIndex2 = (uint)Clamp(csa[tempIndex].m_Real4.x, 0.0, (real_t)COLORMAP_LENGTH_MINUS_1);\n"
"\n"
" *a = (float)round(csa[tempIndex2].m_Reals[index]);\n"
"}\n";
/// <summary> /// <summary>
/// Use MWC 64 from David Thomas at the Imperial College of London for /// Use MWC 64 from David Thomas at the Imperial College of London for
/// random numbers in OpenCL, instead of ISAAC which was used /// random numbers in OpenCL, instead of ISAAC which was used

View File

@ -197,6 +197,7 @@ string FinalAccumOpenCLKernelCreator<T>::CreateFinalAccumKernelString(bool early
RgbToHsvFunctionString << RgbToHsvFunctionString <<
HsvToRgbFunctionString << HsvToRgbFunctionString <<
CalcAlphaFunctionString << CalcAlphaFunctionString <<
CurveAdjustFunctionString <<
SpatialFilterCLStructString; SpatialFilterCLStructString;
if (earlyClip) if (earlyClip)
@ -231,6 +232,8 @@ string FinalAccumOpenCLKernelCreator<T>::CreateFinalAccumKernelString(bool early
" __write_only image2d_t pixels,\n" " __write_only image2d_t pixels,\n"
" __constant SpatialFilterCL* spatialFilter,\n" " __constant SpatialFilterCL* spatialFilter,\n"
" __constant real_t* filterCoefs,\n" " __constant real_t* filterCoefs,\n"
" __constant real4reals* csa,\n"
" const uint doCurves,\n"
" const real_t alphaBase,\n" " const real_t alphaBase,\n"
" const real_t alphaScale\n" " const real_t alphaScale\n"
"\t)\n" "\t)\n"
@ -245,14 +248,11 @@ string FinalAccumOpenCLKernelCreator<T>::CreateFinalAccumKernelString(bool early
" finalCoord.x = GLOBAL_ID_X;\n" " finalCoord.x = GLOBAL_ID_X;\n"
" finalCoord.y = (int)((spatialFilter->m_YAxisUp == 1) ? ((spatialFilter->m_FinalRasH - GLOBAL_ID_Y) - 1) : GLOBAL_ID_Y);\n" " finalCoord.y = (int)((spatialFilter->m_YAxisUp == 1) ? ((spatialFilter->m_FinalRasH - GLOBAL_ID_Y) - 1) : GLOBAL_ID_Y);\n"
" float4floats finalColor;\n" " float4floats finalColor;\n"
" real_t alpha, ls;\n"
" int ii, jj;\n" " int ii, jj;\n"
" uint filterKRowIndex;\n" " uint filterKRowIndex;\n"
" const __global real4reals* accumBucket;\n" " const __global real4reals* accumBucket;\n"
" real4reals newBucket;\n" " real4reals newBucket;\n"
" newBucket.m_Real4 = 0;\n" " newBucket.m_Real4 = 0;\n"
" real4reals newRgb;\n"
" newRgb.m_Real4 = 0;\n"
"\n" "\n"
" for (jj = 0; jj < spatialFilter->m_FilterWidth; jj++)\n" " for (jj = 0; jj < spatialFilter->m_FilterWidth; jj++)\n"
" {\n" " {\n"
@ -269,7 +269,7 @@ string FinalAccumOpenCLKernelCreator<T>::CreateFinalAccumKernelString(bool early
"\n"; "\n";
//Not supporting 2 bytes per channel on the GPU. If the user wants it, run on the CPU. //Not supporting 2 bytes per channel on the GPU. If the user wants it, run on the CPU.
if (earlyClip)//If early clip, simply assign values directly to the temp uint4 since they've been gamma corrected already, then write it straight to the output image below. if (earlyClip)//If early clip, simply assign values directly to the temp float4 since they've been gamma corrected already, then write it straight to the output image below.
{ {
os << os <<
" finalColor.m_Float4.x = (float)newBucket.m_Real4.x;\n"//CPU side clamps, skip here because write_imagef() does the clamping for us. " finalColor.m_Float4.x = (float)newBucket.m_Real4.x;\n"//CPU side clamps, skip here because write_imagef() does the clamping for us.
@ -307,6 +307,14 @@ string FinalAccumOpenCLKernelCreator<T>::CreateFinalAccumKernelString(bool early
} }
os << os <<
"\n"
" if (doCurves)\n"
" {\n"
" CurveAdjust(csa, &(finalColor.m_Floats[0]), 1);\n"
" CurveAdjust(csa, &(finalColor.m_Floats[1]), 2);\n"
" CurveAdjust(csa, &(finalColor.m_Floats[2]), 3);\n"
" }\n"
"\n"
" finalColor.m_Float4 /= 255.0f;\n" " finalColor.m_Float4 /= 255.0f;\n"
" write_imagef(pixels, finalCoord, finalColor.m_Float4);\n"//Use write_imagef instead of write_imageui because only the former works when sharing with an OpenGL texture. " write_imagef(pixels, finalCoord, finalColor.m_Float4);\n"//Use write_imagef instead of write_imageui because only the former works when sharing with an OpenGL texture.
" barrier(CLK_GLOBAL_MEM_FENCE);\n"//Required, or else page tearing will occur during interactive rendering. " barrier(CLK_GLOBAL_MEM_FENCE);\n"//Required, or else page tearing will occur during interactive rendering.

View File

@ -33,6 +33,7 @@ RendererCL<T>::RendererCL(uint platform, uint device, bool shared, GLuint output
m_DEWidthsBufferName = "DEWidths"; m_DEWidthsBufferName = "DEWidths";
m_DECoefIndicesBufferName = "DECoefIndices"; m_DECoefIndicesBufferName = "DECoefIndices";
m_SpatialFilterCoefsBufferName = "SpatialFilterCoefs"; m_SpatialFilterCoefsBufferName = "SpatialFilterCoefs";
m_CurvesCsaName = "CurvesCsa";
m_HistBufferName = "Hist"; m_HistBufferName = "Hist";
m_AccumBufferName = "Accum"; m_AccumBufferName = "Accum";
m_FinalImageName = "Final"; m_FinalImageName = "Final";
@ -282,6 +283,21 @@ bool RendererCL<T>::WriteRandomPoints()
template <typename T> template <typename T>
string RendererCL<T>::IterKernel() { return m_IterKernel; } string RendererCL<T>::IterKernel() { return m_IterKernel; }
/// <summary>
/// Get the kernel string for the last built density filtering program.
/// </summary>
/// <returns>The string representation of the kernel for the last built density filtering program.</returns>
template <typename T>
string RendererCL<T>::DEKernel() { return m_DEOpenCLKernelCreator.GaussianDEKernel(Supersample(), m_DensityFilterCL.m_FilterWidth); }
/// <summary>
/// Get the kernel string for the last built final accumulation program.
/// </summary>
/// <returns>The string representation of the kernel for the last built final accumulation program.</returns>
template <typename T>
string RendererCL<T>::FinalAccumKernel() { return m_FinalAccumOpenCLKernelCreator.FinalAccumKernel(EarlyClip(), Renderer<T, T>::NumChannels(), Transparency()); }
/// <summary> /// <summary>
/// Virtual functions overridden from RendererCLBase. /// Virtual functions overridden from RendererCLBase.
/// </summary> /// </summary>
@ -551,17 +567,17 @@ bool RendererCL<T>::Alloc()
size_t accumLength = SuperSize() * sizeof(v4T); size_t accumLength = SuperSize() * sizeof(v4T);
const char* loc = __FUNCTION__; const char* loc = __FUNCTION__;
if (b && !(b = m_Wrapper.AddBuffer(m_EmberBufferName, sizeof(m_EmberCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_EmberBufferName, sizeof(m_EmberCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_XformsBufferName, SizeOf(m_XformsCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_XformsBufferName, SizeOf(m_XformsCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_ParVarsBufferName, 128 * sizeof(T)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_ParVarsBufferName, 128 * sizeof(T)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_DistBufferName, CHOOSE_XFORM_GRAIN))) { m_ErrorReport.push_back(loc); }//Will be resized for xaos. if (b && !(b = m_Wrapper.AddBuffer(m_DistBufferName, CHOOSE_XFORM_GRAIN))) { m_ErrorReport.push_back(loc); }//Will be resized for xaos.
if (b && !(b = m_Wrapper.AddBuffer(m_CarToRasBufferName, sizeof(m_CarToRasCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_CarToRasBufferName, sizeof(m_CarToRasCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_DEFilterParamsBufferName, sizeof(m_DensityFilterCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_DEFilterParamsBufferName, sizeof(m_DensityFilterCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_SpatialFilterParamsBufferName, sizeof(m_SpatialFilterCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddBuffer(m_SpatialFilterParamsBufferName, sizeof(m_SpatialFilterCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_CurvesCsaName, SizeOf(m_Csa.m_Entries)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddBuffer(m_HistBufferName, histLength))) { m_ErrorReport.push_back(loc); }//Histogram. Will memset to zero later. if (b && !(b = m_Wrapper.AddBuffer(m_HistBufferName, histLength))) { m_ErrorReport.push_back(loc); }//Histogram. Will memset to zero later.
if (b && !(b = m_Wrapper.AddBuffer(m_AccumBufferName, accumLength))) { m_ErrorReport.push_back(loc); }//Accum buffer. if (b && !(b = m_Wrapper.AddBuffer(m_AccumBufferName, accumLength))) { m_ErrorReport.push_back(loc); }//Accum buffer.
if (b && !(b = m_Wrapper.AddBuffer(m_PointsBufferName, IterGridKernelCount() * sizeof(PointCL<T>)))) { m_ErrorReport.push_back(loc); }//Points between iter calls. if (b && !(b = m_Wrapper.AddBuffer(m_PointsBufferName, IterGridKernelCount() * sizeof(PointCL<T>)))) { m_ErrorReport.push_back(loc); }//Points between iter calls.
LeaveResize(); LeaveResize();
@ -809,8 +825,8 @@ bool RendererCL<T>::RunIter(size_t iterCount, size_t temporalSample, size_t& ite
//fuse = ((m_Calls % 4) == 0 ? 100u : 0u); //fuse = ((m_Calls % 4) == 0 ? 100u : 0u);
#endif #endif
itersRemaining = iterCount - itersRan; itersRemaining = iterCount - itersRan;
uint gridW = uint(min(ceil(double(itersRemaining) / double(iterCountPerBlock)), double(IterGridBlockWidth()))); uint gridW = uint(std::min(ceil(double(itersRemaining) / double(iterCountPerBlock)), double(IterGridBlockWidth())));
uint gridH = uint(min(ceil(double(itersRemaining) / double(gridW * iterCountPerBlock)), double(IterGridBlockHeight()))); uint gridH = uint(std::min(ceil(double(itersRemaining) / double(gridW * iterCountPerBlock)), double(IterGridBlockHeight())));
uint iterCountThisLaunch = iterCountPerBlock * gridW * gridH; uint iterCountThisLaunch = iterCountPerBlock * gridW * gridH;
//Similar to what's done in the base class. //Similar to what's done in the base class.
@ -1071,6 +1087,7 @@ eRenderStatus RendererCL<T>::RunFinalAccum()
uint gridH; uint gridH;
uint blockW; uint blockW;
uint blockH; uint blockH;
uint curvesSet = m_CurvesSet ? 1 : 0;
const char* loc = __FUNCTION__; const char* loc = __FUNCTION__;
if (!m_Abort && accumKernelIndex != -1) if (!m_Abort && accumKernelIndex != -1)
@ -1079,6 +1096,7 @@ eRenderStatus RendererCL<T>::RunFinalAccum()
m_SpatialFilterCL = ConvertSpatialFilter(); m_SpatialFilterCL = ConvertSpatialFilter();
if (b && !(b = m_Wrapper.AddAndWriteBuffer(m_SpatialFilterParamsBufferName, reinterpret_cast<void*>(&m_SpatialFilterCL), sizeof(m_SpatialFilterCL)))) { m_ErrorReport.push_back(loc); } if (b && !(b = m_Wrapper.AddAndWriteBuffer(m_SpatialFilterParamsBufferName, reinterpret_cast<void*>(&m_SpatialFilterCL), sizeof(m_SpatialFilterCL)))) { m_ErrorReport.push_back(loc); }
if (b && !(b = m_Wrapper.AddAndWriteBuffer(m_CurvesCsaName, m_Csa.m_Entries.data(), SizeOf(m_Csa.m_Entries)))) { m_ErrorReport.push_back(loc); }
//Since early clip requires gamma correcting the entire accumulator first, //Since early clip requires gamma correcting the entire accumulator first,
//it can't be done inside of the normal final accumulation kernel, so //it can't be done inside of the normal final accumulation kernel, so
@ -1119,6 +1137,9 @@ eRenderStatus RendererCL<T>::RunFinalAccum()
if (b && !(b = m_Wrapper.SetImageArg (accumKernelIndex, argIndex++, m_Wrapper.Shared(), m_FinalImageName))) { m_ErrorReport.push_back(loc); }//Final image. if (b && !(b = m_Wrapper.SetImageArg (accumKernelIndex, argIndex++, m_Wrapper.Shared(), m_FinalImageName))) { m_ErrorReport.push_back(loc); }//Final image.
if (b && !(b = m_Wrapper.SetBufferArg(accumKernelIndex, argIndex++, m_SpatialFilterParamsBufferName))) { m_ErrorReport.push_back(loc); }//SpatialFilterCL. if (b && !(b = m_Wrapper.SetBufferArg(accumKernelIndex, argIndex++, m_SpatialFilterParamsBufferName))) { m_ErrorReport.push_back(loc); }//SpatialFilterCL.
if (b && !(b = m_Wrapper.SetBufferArg(accumKernelIndex, argIndex++, m_SpatialFilterCoefsBufferName))) { m_ErrorReport.push_back(loc); }//Filter coefs. if (b && !(b = m_Wrapper.SetBufferArg(accumKernelIndex, argIndex++, m_SpatialFilterCoefsBufferName))) { m_ErrorReport.push_back(loc); }//Filter coefs.
if (b && !(b = m_Wrapper.SetBufferArg(accumKernelIndex, argIndex++, m_CurvesCsaName))) { m_ErrorReport.push_back(loc); }//Curve points.
if (b && !(b = m_Wrapper.SetArg (accumKernelIndex, argIndex++, curvesSet))) { m_ErrorReport.push_back(loc); }//Do curves.
if (b && !(b = m_Wrapper.SetArg (accumKernelIndex, argIndex++, alphaBase))) { m_ErrorReport.push_back(loc); }//Alpha base. if (b && !(b = m_Wrapper.SetArg (accumKernelIndex, argIndex++, alphaBase))) { m_ErrorReport.push_back(loc); }//Alpha base.
if (b && !(b = m_Wrapper.SetArg (accumKernelIndex, argIndex++, alphaScale))) { m_ErrorReport.push_back(loc); }//Alpha scale. if (b && !(b = m_Wrapper.SetArg (accumKernelIndex, argIndex++, alphaScale))) { m_ErrorReport.push_back(loc); }//Alpha scale.

View File

@ -121,6 +121,8 @@ public:
bool WriteRandomPoints(); bool WriteRandomPoints();
#endif #endif
string IterKernel(); string IterKernel();
string DEKernel();
string FinalAccumKernel();
//Virtual functions overridden from RendererCLBase. //Virtual functions overridden from RendererCLBase.
virtual bool ReadFinal(byte* pixels); virtual bool ReadFinal(byte* pixels);
@ -193,6 +195,7 @@ private:
string m_CarToRasBufferName; string m_CarToRasBufferName;
string m_DEFilterParamsBufferName; string m_DEFilterParamsBufferName;
string m_SpatialFilterParamsBufferName; string m_SpatialFilterParamsBufferName;
string m_CurvesCsaName;
string m_DECoefsBufferName; string m_DECoefsBufferName;
string m_DEWidthsBufferName; string m_DEWidthsBufferName;
string m_DECoefIndicesBufferName; string m_DECoefIndicesBufferName;

View File

@ -146,7 +146,7 @@ static bool WritePng(const char* filename, byte* image, size_t width, size_t hei
png_infop info_ptr; png_infop info_ptr;
png_text text[PNG_COMMENT_MAX]; png_text text[PNG_COMMENT_MAX];
size_t i; size_t i;
uint16 testbe = 1; glm::uint16 testbe = 1;
vector<byte*> rows(height); vector<byte*> rows(height);
text[0].compression = PNG_TEXT_COMPRESSION_NONE; text[0].compression = PNG_TEXT_COMPRESSION_NONE;

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,8 FILEVERSION 0,4,1,9
PRODUCTVERSION 0,4,1,8 PRODUCTVERSION 0,4,1,9
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Manipulates fractal flames parameter files" VALUE "FileDescription", "Manipulates fractal flames parameter files"
VALUE "FileVersion", "0.4.1.8" VALUE "FileVersion", "0.4.1.9"
VALUE "InternalName", "EmberGenome.rc" VALUE "InternalName", "EmberGenome.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberGenome.rc" VALUE "OriginalFilename", "EmberGenome.rc"
VALUE "ProductName", "Ember Genome" VALUE "ProductName", "Ember Genome"
VALUE "ProductVersion", "0.4.1.8" VALUE "ProductVersion", "0.4.1.9"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -158,7 +158,7 @@ bool EmberRender(EmberOptions& opt)
{ {
if (opt.Verbose() && embers.size() > 1) if (opt.Verbose() && embers.size() > 1)
cout << "\nFlame = " << i + 1 << "/" << embers.size() << endl; cout << "\nFlame = " << i + 1 << "/" << embers.size() << endl;
else else if (embers.size() > 1)
VerbosePrint(endl); VerbosePrint(endl);
if (opt.Supersample() > 0) if (opt.Supersample() > 0)

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,8 FILEVERSION 0,4,1,9
PRODUCTVERSION 0,4,1,8 PRODUCTVERSION 0,4,1,9
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as single images" VALUE "FileDescription", "Renders fractal flames as single images"
VALUE "FileVersion", "0.4.1.8" VALUE "FileVersion", "0.4.1.9"
VALUE "InternalName", "EmberRender.rc" VALUE "InternalName", "EmberRender.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberRender.rc" VALUE "OriginalFilename", "EmberRender.rc"
VALUE "ProductName", "Ember Render" VALUE "ProductName", "Ember Render"
VALUE "ProductVersion", "0.4.1.8" VALUE "ProductVersion", "0.4.1.9"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -1529,6 +1529,7 @@ void TestCpuGpuResults()
renderer.CreateSpatialFilter(newAlloc); renderer.CreateSpatialFilter(newAlloc);
renderer.CreateDEFilter(newAlloc); renderer.CreateDEFilter(newAlloc);
renderer.ComputeBounds(); renderer.ComputeBounds();
renderer.ComputeQuality();
renderer.ComputeCamera(); renderer.ComputeCamera();
renderer.AssignIterator(); renderer.AssignIterator();
@ -1614,6 +1615,7 @@ void TestGpuVectorRead()
renderer.CreateSpatialFilter(newAlloc); renderer.CreateSpatialFilter(newAlloc);
renderer.CreateDEFilter(newAlloc); renderer.CreateDEFilter(newAlloc);
renderer.ComputeBounds(); renderer.ComputeBounds();
renderer.ComputeQuality();
renderer.ComputeCamera(); renderer.ComputeCamera();
renderer.AssignIterator(); renderer.AssignIterator();
@ -1746,11 +1748,84 @@ double RandD(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
return ((((rand.Rand()^(rand.Rand()<<15))&0xfffffff)*3.72529e-09)-0.5); return ((((rand.Rand()^(rand.Rand()<<15))&0xfffffff)*3.72529e-09)-0.5);
} }
#define BEZ_POINT_LENGTH 4
void BezierSolve(double t, glm::vec2* src, double* w, glm::vec2& solution)
{
double s, s2, s3, t2, t3, nom_x, nom_y, denom;
s = 1 - t;
s2 = s * s;
s3 = s * s * s;
t2 = t * t;
t3 = t * t * t;
nom_x = w[0] * s3 * src[0].x + w[1] * s2 * 3 * t * src[1].x + w[2] * s * 3 * t2 * src[2].x + w[3] * t3 * src[3].x;
nom_y = w[0] * s3 * src[0].y + w[1] * s2 * 3 * t * src[1].y + w[2] * s * 3 * t2 * src[2].y + w[3] * t3 * src[3].y;
denom = w[0] * s3 + w[1] * s2 * 3 * t + w[2] * s * 3 * t2 + w[3] * t3;
if (isnan(nom_x) || isnan(nom_y) || isnan(denom) || denom == 0)
return;
solution.x = nom_x / denom;
solution.y = nom_y / denom;
}
void BezierSetRect(glm::vec2* points, bool flip, glm::vec4& rect)
{
double f;
for (int i = 0; i < BEZ_POINT_LENGTH; i++)
{
if (flip)
f = 1 - points[i].y;
else
f = points[i].y;
points[i].x = points[i].x * (rect.z - rect.x) + rect.x;
points[i].y = f * (rect.w - rect.y) + rect.y;
}
}
void BezierUnsetRect(glm::vec2* points, bool flip, glm::vec4& rect)
{
if ((rect.z - rect.x) == 0 || (rect.w - rect.y) == 0)
return;
for (int i = 0; i < BEZ_POINT_LENGTH; i++)
{
points[i].x = (points[i].x - rect.x) / (rect.z - rect.x);
points[i].y = (points[i].y - rect.y) / (rect.w - rect.y);
if (flip)
points[i].y = 1 - points[i].y;
}
}
struct BezierPoints
{
glm::vec2 points[4];
};
struct BezierWeights
{
double points[4];
};
int _tmain(int argc, _TCHAR* argv[]) int _tmain(int argc, _TCHAR* argv[])
{ {
//int i; //int i;
Timing t(4); Timing t(4);
QTIsaac<ISAAC_SIZE, ISAAC_INT> rand; QTIsaac<ISAAC_SIZE, ISAAC_INT> rand;
glm::vec2 solution, src[4];
double bezT = 1, w[4];
BezierPoints curvePoints[4];
BezierWeights curveWeights[4];
BezierSolve(bezT, src, w, solution);
//cout << pow(-1, 5.1) << endl; //cout << pow(-1, 5.1) << endl;
@ -1818,7 +1893,7 @@ int _tmain(int argc, _TCHAR* argv[])
//std::complex<double> cd, cd2; //std::complex<double> cd, cd2;
//cd2 = sin(cd); //cd2 = sin(cd);
/*
t.Tic(); t.Tic();
VariationList<float> vlf; VariationList<float> vlf;
t.Toc("Creating VariationList<float>"); t.Toc("Creating VariationList<float>");
@ -1905,7 +1980,7 @@ int _tmain(int argc, _TCHAR* argv[])
t.Tic(); t.Tic();
TestOperations<float>(); TestOperations<float>();
t.Toc("TestOperations()"); t.Toc("TestOperations()");
*/
//t.Tic(); //t.Tic();
//TestVarsSimilar<float>(); //TestVarsSimilar<float>();
//t.Toc("TestVarsSimilar()"); //t.Toc("TestVarsSimilar()");

View File

@ -58,7 +58,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Fractorium 0.4.1.8 Beta&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Matt Feemster&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Fractorium 0.4.1.9 Beta&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Matt Feemster&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="textFormat"> <property name="textFormat">
<enum>Qt::RichText</enum> <enum>Qt::RichText</enum>

View File

@ -0,0 +1,213 @@
#include "FractoriumPch.h"
#include "CurvesGraphicsView.h"
/// <summary>
/// Construct the scene which will have a fixed rect.
/// Construct all points, pens and axes.
/// </summary>
/// <param name="parent">Pass to the parent</param>
CurvesGraphicsView::CurvesGraphicsView(QWidget* parent)
: QGraphicsView(parent)
{
m_Scene.setSceneRect(0, 0, 245, 245);
m_AllP1 = new EllipseItem(QRectF(-5, -5, 10, 10), 0, 1, this);
m_AllP1->setBrush(QBrush(Qt::GlobalColor::black));
m_AllP2 = new EllipseItem(QRectF(-5, -5, 10, 10), 0, 2, this);
m_AllP2->setBrush(QBrush(Qt::GlobalColor::black));
m_RedP1 = new EllipseItem(QRectF(-5, -5, 10, 10), 1, 1, this);
m_RedP1->setBrush(QBrush(Qt::GlobalColor::red));
m_RedP2 = new EllipseItem(QRectF(-5, -5, 10, 10), 1, 2, this);
m_RedP2->setBrush(QBrush(Qt::GlobalColor::red));
m_GrnP1 = new EllipseItem(QRectF(-5, -5, 10, 10), 2, 1, this);
m_GrnP1->setBrush(QBrush(Qt::GlobalColor::green));
m_GrnP2 = new EllipseItem(QRectF(-5, -5, 10, 10), 2, 2, this);
m_GrnP2->setBrush(QBrush(Qt::GlobalColor::green));
m_BluP1 = new EllipseItem(QRectF(-5, -5, 10, 10), 3, 1, this);
m_BluP1->setBrush(QBrush(Qt::GlobalColor::blue));
m_BluP2 = new EllipseItem(QRectF(-5, -5, 10, 10), 3, 2, this);
m_BluP2->setBrush(QBrush(Qt::GlobalColor::blue));
m_AxisPen = QPen(Qt::GlobalColor::white);
m_XLine = new QGraphicsLineItem();
m_XLine->setPen(m_AxisPen);
m_XLine->setZValue(0);
m_YLine = new QGraphicsLineItem();
m_YLine->setPen(m_AxisPen);
m_YLine->setZValue(0);
m_Scene.addItem(m_AllP1); m_Points[0].first = m_AllP1; m_AllP1->setZValue(2);
m_Scene.addItem(m_AllP2); m_Points[0].second = m_AllP2; m_AllP2->setZValue(2);
m_Scene.addItem(m_RedP1); m_Points[1].first = m_RedP1;
m_Scene.addItem(m_RedP2); m_Points[1].second = m_RedP2;
m_Scene.addItem(m_GrnP1); m_Points[2].first = m_GrnP1;
m_Scene.addItem(m_GrnP2); m_Points[2].second = m_GrnP2;
m_Scene.addItem(m_BluP1); m_Points[3].first = m_BluP1;
m_Scene.addItem(m_BluP2); m_Points[3].second = m_BluP2;
m_Scene.addItem(m_XLine);
m_Scene.addItem(m_YLine);
m_APen = QPen(Qt::GlobalColor::black); m_Pens[0] = &m_APen;
m_RPen = QPen(Qt::GlobalColor::red); m_Pens[1] = &m_RPen;
m_GPen = QPen(Qt::GlobalColor::green); m_Pens[2] = &m_GPen;
m_BPen = QPen(Qt::GlobalColor::blue); m_Pens[3] = &m_BPen;
m_APen.setWidth(2);
m_RPen.setWidth(2);
m_GPen.setWidth(2);
m_BPen.setWidth(2);
setScene(&m_Scene);
SetTop(CurveIndex::ALL);
//qDebug() << "Original scene rect before setting anything is: " << sceneRect();
m_OriginalRect = sceneRect();
show();
//qDebug() << "Original scene rect is: " << m_OriginalRect;
}
/// <summary>
/// Get the position of a given point within a given curve.
/// </summary>
/// <param name="curveIndex">The curve whose point value will be retrieved, 0-3.</param>
/// <param name="pointIndex">The point within the curve value will be retrieved, 1-2.</param>
/// <param name="point">The position of the point. X,Y will each be within 0-1.</param>
void CurvesGraphicsView::PointChanged(int curveIndex, int pointIndex, const QPointF& point)
{
double x = point.x() / width();
double y = (height() - point.y()) / height();
emit PointChangedSignal(curveIndex, pointIndex, QPointF(x, y));
}
/// <summary>
/// Get the position of a given point within a given curve.
/// </summary>
/// <param name="curveIndex">The curve whose point value will be retrieved, 0-3.</param>
/// <param name="pointIndex">The point within the curve whose value will be retrieved, 1-2.</param>
/// <returns>The position of the point. X,Y will each be within 0-1.</returns>
QPointF CurvesGraphicsView::Get(int curveIndex, int pointIndex)
{
if (curveIndex < 4)
{
EllipseItem* item = (pointIndex == 1) ? m_Points[curveIndex].first : m_Points[curveIndex].second;
return QPointF(item->pos().x() / width(), (height() - item->pos().y()) / height());
}
return QPointF();
}
/// <summary>
/// Set the position of a given point within a given curve.
/// </summary>
/// <param name="curveIndex">The curve whose point will be set, 0-3.</param>
/// <param name="pointIndex">The point within the curve which will be set, 1-2</param>
/// <param name="point">The position to set the point to. X,Y will each be within 0-1.</param>
void CurvesGraphicsView::Set(int curveIndex, int pointIndex, const QPointF& point)
{
if (curveIndex < 4)
{
if (pointIndex == 1)
m_Points[curveIndex].first->setPos(point.x() * width(), (1.0 - point.y()) * height());//Scale to scene dimensions, Y axis is flipped.
else
m_Points[curveIndex].second->setPos(point.x() * width(), (1.0 - point.y()) * height());
}
}
/// <summary>
/// Set the topmost curve but setting its Z value.
/// All other curves will get a value one less.
/// </summary>
/// <param name="curveIndex">The curve to set</param>
void CurvesGraphicsView::SetTop(CurveIndex curveIndex)
{
int index;
switch (curveIndex)
{
case CurveIndex::ALL:
index = 0;
break;
case CurveIndex::RED:
index = 1;
break;
case CurveIndex::GREEN:
index = 2;
break;
case CurveIndex::BLUE:
default:
index = 3;
}
for (int i = 0; i < 4; i++)
{
if (i == index)
{
m_Points[i].first->setZValue(2);
m_Points[i].second->setZValue(2);
}
else
{
m_Points[i].first->setZValue(1);
m_Points[i].second->setZValue(1);
}
}
}
/// <summary>
/// Overridden paint even which draws the points, axes and curves.
/// </summary>
/// <param name="e">Ignored</param>
void CurvesGraphicsView::paintEvent(QPaintEvent* e)
{
QGraphicsView::paintEvent(e);
int i;
QRectF rect = scene()->sceneRect();
double w2 = width() / 2;
double h2 = height() / 2;
//Draw axis lines.
m_XLine->setLine(QLineF(0, h2, width(), h2));
m_YLine->setLine(QLineF(w2, 0, w2, height()));
//This must be constructed every time and cannot be a member.
QPainter painter(viewport());
painter.setClipRect(rect);
painter.setRenderHint(QPainter::Antialiasing);
//Create 4 new paths. These must be constructed every time and cannot be members.
QPainterPath paths[4] =
{
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft()))
};
//Draw paths for all but the topmost curve.
for (i = 0; i < 4; i++)
{
paths[i].cubicTo(m_Points[i].first->pos(), m_Points[i].second->pos(), mapFromScene(rect.topRight()));
if (m_Points[i].first->zValue() == 1)
{
painter.setPen(*m_Pens[i]);
painter.drawPath(paths[i]);
}
}
//Draw the topmost curve.
for (i = 0; i < 4; i++)
{
if (m_Points[i].first->zValue() == 2)
{
painter.setPen(*m_Pens[i]);
painter.drawPath(paths[i]);
break;
}
}
}

View File

@ -0,0 +1,150 @@
#pragma once
#include "FractoriumPch.h"
/// <summary>
/// CurvesGraphicsView and EllipseItem classes.
/// </summary>
class EllipseItem;
/// <summary>
/// Enumeration used for setting values on a specific curve.
/// </summary>
enum CurveIndex
{
ALL,
RED,
GREEN,
BLUE
};
/// <summary>
/// Derivation to display points on bezier cuves for the user to drag.
/// Selection logic and updating is handled by the base class.
/// Changes here will affect the current ember and vice versa.
/// The points, axis lines and pens are kept as members and the curves
/// themselves are drawn on the fly during each paint event.
/// Pointers to these are kept in arrays to make manipulating them in loops easier.
/// Note that this must work off a fixed rect size, hence why the control is not resizeable.
/// </summary>
class CurvesGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
CurvesGraphicsView(QWidget* parent = 0);
void PointChanged(int curveIndex, int pointIndex, const QPointF& point);
QPointF Get(int curveIndex, int pointIndex);
void Set(int curveIndex, int pointIndex, const QPointF& point);
void SetTop(CurveIndex curveIndex);
Q_SIGNALS:
void PointChangedSignal(int curveIndex, int pointIndex, const QPointF& point);
protected:
virtual void paintEvent(QPaintEvent* e) override;
QPen m_APen;
QPen m_RPen;
QPen m_GPen;
QPen m_BPen;
QPen m_AxisPen;
EllipseItem* m_AllP1;
EllipseItem* m_AllP2;
EllipseItem* m_RedP1;
EllipseItem* m_RedP2;
EllipseItem* m_GrnP1;
EllipseItem* m_GrnP2;
EllipseItem* m_BluP1;
EllipseItem* m_BluP2;
QGraphicsLineItem* m_XLine;
QGraphicsLineItem* m_YLine;
QPen* m_Pens[4];
QGraphicsScene m_Scene;
QRectF m_OriginalRect;
std::pair<EllipseItem*, EllipseItem*> m_Points[4];
};
/// <summary>
/// Derivation for draggable points needed to trigger an event whenever the item is changed.
/// Custom drawing is also done to omit drawing a selection rectangle.
/// </summary>
class EllipseItem : public QGraphicsEllipseItem
{
public:
/// <summary>
/// Construct the point and specify the curve index it's part of, as well as the
/// point index within the curve.
/// </summary>
/// <param name="rect">Pass to the parent</param>
/// <param name="curveIndex">The curve's index this point is a part of, 0-3.</param>
/// <param name="pointIndex">The point index within the curve</param>
/// <param name="viewParent">The graphics view this point is displayed on</param>
/// <param name="p">The parent widget of this item</param>
EllipseItem(const QRectF &rect, int curveIndex, int pointIndex, CurvesGraphicsView* viewParent, QGraphicsItem *parent = 0)
: QGraphicsEllipseItem(rect, parent)
{
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemIsMovable);
setPen(Qt::NoPen);
m_CurveIndex = curveIndex;
m_PointIndex = pointIndex;
m_ViewParent = viewParent;
}
/// <summary>
/// Index properties, getters only.
/// </summary>
int CurveIndex() const { return m_CurveIndex; }
int PointIndex() const { return m_PointIndex; }
protected:
/// <summary>
/// Overridden paint event to disable the selection rectangle.
/// </summary>
/// <param name="painter">Unused and just passed to QGraphicsEllipseItem::paint()</param>
/// <param name="option">Drawing options used which will have the QStyle::State_Selected flag unset</param>
/// <param name="widget">Unused and just passed to QGraphicsEllipseItem::paint()</param>
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
{
QStyleOptionGraphicsItem myOption(*option);
myOption.state &= ~QStyle::State_Selected;
QGraphicsEllipseItem::paint(painter, &myOption, widget);
}
/// <summary>
/// Overridden itemChange event to notify the parent control that it has moved.
/// Movement is also restriced to the scene rect.
/// </summary>
/// <param name="change">Action is only taken if this value equals ItemPositionChange</param>
/// <param name="value">The new position. This will be clamped to the scene rect.</param>
/// <returns>The new position</returns>
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
{
if (change == ItemPositionChange && scene())
{
//Value is the new position.
QPointF newPos = value.toPointF();
QRectF rect = scene()->sceneRect();
if (!rect.contains(newPos))
{
//Keep the item inside the scene rect.
newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
}
m_ViewParent->PointChanged(m_CurveIndex, m_PointIndex, newPos);
return newPos;
}
return QGraphicsEllipseItem::itemChange(change, value);
}
int m_CurveIndex;
int m_PointIndex;
CurvesGraphicsView* m_ViewParent;
};

View File

@ -84,6 +84,23 @@ public:
return m_Embers.size(); return m_Embers.size();
} }
/// <summary>
/// Delete the ember at the given index.
/// Will not delete anything if the size is already 1.
/// </summary>
/// <param name="index">The index of the ember to delete</param>
/// <returns>True if successfully deleted, else false.</returns>
bool Delete(size_t index)
{
if (Size() > 1 && index < Size())
{
m_Embers.erase(m_Embers.begin() + index);
return true;
}
else
return false;
}
/// <summary> /// <summary>
/// Ensure all ember names are unique. /// Ensure all ember names are unique.
/// </summary> /// </summary>
@ -116,6 +133,7 @@ public:
/// <summary> /// <summary>
/// Ensures a given input filename is unique by appending a count to the end. /// Ensures a given input filename is unique by appending a count to the end.
/// </summary> /// </summary>
/// <param name="filename">The filename to ensure is unique</param>
/// <returns>The passed in name if it was unique, else a uniquely made name.</returns> /// <returns>The passed in name if it was unique, else a uniquely made name.</returns>
static QString UniqueFilename(const QString& filename) static QString UniqueFilename(const QString& filename)
{ {

View File

@ -139,7 +139,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(FractoriumSettings* set
QSize s = size(); QSize s = size();
int desktopHeight = qApp->desktop()->availableGeometry().height(); int desktopHeight = qApp->desktop()->availableGeometry().height();
s.setHeight(min(s.height(), int(double(desktopHeight * 0.90)))); s.setHeight(std::min(s.height(), int(double(desktopHeight * 0.90))));
setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, s, qApp->desktop()->availableGeometry())); setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, s, qApp->desktop()->availableGeometry()));
QWidget* w = SetTabOrder(this, ui.FinalRenderEarlyClipCheckBox, ui.FinalRenderYAxisUpCheckBox); QWidget* w = SetTabOrder(this, ui.FinalRenderEarlyClipCheckBox, ui.FinalRenderYAxisUpCheckBox);

View File

@ -115,8 +115,8 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_PreviewEmber = *m_Ember; m_PreviewEmber = *m_Ember;
m_PreviewEmber.m_Quality = 100; m_PreviewEmber.m_Quality = 100;
m_PreviewEmber.m_TemporalSamples = 1; m_PreviewEmber.m_TemporalSamples = 1;
m_PreviewEmber.m_FinalRasW = max<size_t>(1, min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasW)));//Ensure neither is zero. m_PreviewEmber.m_FinalRasW = std::max<size_t>(1, std::min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasW)));//Ensure neither is zero.
m_PreviewEmber.m_FinalRasH = max<size_t>(1, min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasH))); m_PreviewEmber.m_FinalRasH = std::max<size_t>(1, std::min<size_t>(maxDim, size_t(scalePercentage * m_Ember->m_FinalRasH)));
m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember->m_PixelsPerUnit; m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember->m_PixelsPerUnit;
m_FinalPreviewRenderer->EarlyClip(m_FinalRenderDialog->EarlyClip()); m_FinalPreviewRenderer->EarlyClip(m_FinalRenderDialog->EarlyClip());
@ -597,6 +597,7 @@ tuple<size_t, size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemor
m_Renderer->CreateTemporalFilter(b); m_Renderer->CreateTemporalFilter(b);
m_Renderer->NumChannels(channels); m_Renderer->NumChannels(channels);
m_Renderer->ComputeBounds(); m_Renderer->ComputeBounds();
m_Renderer->ComputeQuality();
m_Renderer->ComputeCamera(); m_Renderer->ComputeCamera();
CancelPreviewRender(); CancelPreviewRender();
m_FinalPreviewRenderFunc(); m_FinalPreviewRenderFunc();
@ -741,8 +742,8 @@ void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t width
h = ember.m_OrigFinalRasH * hScale; h = ember.m_OrigFinalRasH * hScale;
} }
w = max<size_t>(w, 10); w = std::max<size_t>(w, 10);
h = max<size_t>(h, 10); h = std::max<size_t>(h, 10);
ember.SetSizeAndAdjustScale(w, h, false, m_FinalRenderDialog->Scale()); ember.SetSizeAndAdjustScale(w, h, false, m_FinalRenderDialog->Scale());
ember.m_Quality = m_FinalRenderDialog->m_QualitySpin->value(); ember.m_Quality = m_FinalRenderDialog->m_QualitySpin->value();

View File

@ -264,8 +264,9 @@ void Fractorium::dockLocationChanged(Qt::DockWidgetArea area)
/// </summary> /// </summary>
/// <summary> /// <summary>
/// Event filter for taking special action on dock widget resize events, /// Event filter for taking special action on:
/// which in turn trigger GLParentScrollArea events. /// Dock widget resize events, which in turn trigger GLParentScrollArea events.
/// Library tree key events, specifically delete.
/// </summary> /// </summary>
/// <param name="o">The object</param> /// <param name="o">The object</param>
/// <param name="e">The eevent</param> /// <param name="e">The eevent</param>
@ -278,6 +279,19 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
m_HeightSpin->DoubleClickNonZero(ui.GLParentScrollArea->height()); m_HeightSpin->DoubleClickNonZero(ui.GLParentScrollArea->height());
//qDebug() << "scroll area resized"; //qDebug() << "scroll area resized";
} }
else if (o == ui.LibraryTree)
{
if (QKeyEvent* ke = dynamic_cast<QKeyEvent*>(e))
{
if (ke->key() == Qt::Key_Delete && e->type() == QEvent::KeyRelease)
{
auto p = GetCurrentEmberIndex();
if (ui.LibraryTree->topLevelItem(0)->childCount() > 1 && p.second)
OnDelete(p);
}
}
}
return QMainWindow::eventFilter(o, e); return QMainWindow::eventFilter(o, e);
} }

View File

@ -10,6 +10,7 @@
#include "FinalRenderDialog.h" #include "FinalRenderDialog.h"
#include "OptionsDialog.h" #include "OptionsDialog.h"
#include "AboutDialog.h" #include "AboutDialog.h"
#include "CurvesGraphicsView.h"
/// <summary> /// <summary>
/// Fractorium class. /// Fractorium class.
@ -140,6 +141,11 @@ public slots:
void OnSaveEntireFileAsXmlButtonClicked(bool checked); void OnSaveEntireFileAsXmlButtonClicked(bool checked);
void OnSaveCurrentToOpenedFileButtonClicked(bool checked); void OnSaveCurrentToOpenedFileButtonClicked(bool checked);
//Library.
void OnEmberTreeItemChanged(QTreeWidgetItem* item, int col);
void OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col);
void OnDelete(const pair<size_t, QTreeWidgetItem*>& p);
//Params. //Params.
void OnBrightnessChanged(double d);//Color. void OnBrightnessChanged(double d);//Color.
void OnGammaChanged(double d); void OnGammaChanged(double d);
@ -222,7 +228,13 @@ public slots:
void OnXformDirectColorChanged(double d); void OnXformDirectColorChanged(double d);
void OnSoloXformCheckBoxStateChanged(int state); void OnSoloXformCheckBoxStateChanged(int state);
void OnXformRefPaletteResized(int logicalIndex, int oldSize, int newSize); void OnXformRefPaletteResized(int logicalIndex, int oldSize, int newSize);
void OnResetCurvesButtonClicked(bool checked);
void OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point);
void OnCurvesAllRadioButtonToggled(bool checked);
void OnCurvesRedRadioButtonToggled(bool checked);
void OnCurvesGreenRadioButtonToggled(bool checked);
void OnCurvesBlueRadioButtonToggled(bool checked);
//Xforms Variations. //Xforms Variations.
void OnVariationSpinBoxValueChanged(double d); void OnVariationSpinBoxValueChanged(double d);
void OnTreeHeaderSectionClicked(int); void OnTreeHeaderSectionClicked(int);
@ -242,10 +254,6 @@ public slots:
void OnPaletteRandomSelectButtonClicked(bool checked); void OnPaletteRandomSelectButtonClicked(bool checked);
void OnPaletteRandomAdjustButtonClicked(bool checked); void OnPaletteRandomAdjustButtonClicked(bool checked);
//Library.
void OnEmberTreeItemChanged(QTreeWidgetItem* item, int col);
void OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col);
//Rendering/progress. //Rendering/progress.
void StartRenderTimer(); void StartRenderTimer();
void IdleTimer(); void IdleTimer();
@ -287,6 +295,9 @@ private:
//Embers. //Embers.
bool HaveFinal(); bool HaveFinal();
//Library.
pair<size_t, QTreeWidgetItem*> GetCurrentEmberIndex();
//Params. //Params.
//Xforms. //Xforms.
@ -304,8 +315,6 @@ private:
//Palette. //Palette.
void ResetPaletteControls(); void ResetPaletteControls();
//Library.
//Info. //Info.
void UpdateHistogramBounds(); void UpdateHistogramBounds();
void ErrorReportToQTextEdit(const vector<string>& errors, QTextEdit* textEdit, bool clear = true); void ErrorReportToQTextEdit(const vector<string>& errors, QTextEdit* textEdit, bool clear = true);

Binary file not shown.

View File

@ -353,7 +353,7 @@
<enum>QTabWidget::Triangular</enum> <enum>QTabWidget::Triangular</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>0</number>
</property> </property>
<property name="usesScrollButtons"> <property name="usesScrollButtons">
<bool>true</bool> <bool>true</bool>
@ -420,7 +420,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QTreeWidget" name="LibraryTree"> <widget class="QTreeWidget" name="LibraryTree">
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::StrongFocus</enum> <enum>Qt::WheelFocus</enum>
</property> </property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum> <enum>Qt::CustomContextMenu</enum>
@ -504,8 +504,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>73</width> <width>259</width>
<height>837</height> <height>852</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
@ -2285,7 +2285,7 @@ SpinBox
<enum>QTabWidget::Triangular</enum> <enum>QTabWidget::Triangular</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>2</number>
</property> </property>
<widget class="QWidget" name="ColorTab"> <widget class="QWidget" name="ColorTab">
<property name="sizePolicy"> <property name="sizePolicy">
@ -2775,6 +2775,134 @@ SpinBox
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="2">
<widget class="CurvesGraphicsView" name="CurvesView">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>245</width>
<height>245</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>245</width>
<height>245</height>
</size>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="backgroundBrush">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>219</red>
<green>219</green>
<blue>219</blue>
</color>
</brush>
</property>
<property name="sceneRect">
<rectf>
<x>0.000000000000000</x>
<y>0.000000000000000</y>
<width>245.000000000000000</width>
<height>245.000000000000000</height>
</rectf>
</property>
<property name="resizeAnchor">
<enum>QGraphicsView::NoAnchor</enum>
</property>
<property name="viewportUpdateMode">
<enum>QGraphicsView::FullViewportUpdate</enum>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Curve</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="CurvesAllRadio">
<property name="text">
<string>All</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="CurvesRedRadio">
<property name="text">
<string>Red</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="CurvesGreenRadio">
<property name="text">
<string>Green</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="CurvesBlueRadio">
<property name="text">
<string>Blue</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="1">
<widget class="QPushButton" name="ResetCurvesButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reset Curves</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="AffineTab"> <widget class="QWidget" name="AffineTab">
@ -2825,8 +2953,8 @@ SpinBox
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>245</width> <width>118</width>
<height>747</height> <height>618</height>
</rect> </rect>
</property> </property>
<property name="autoFillBackground"> <property name="autoFillBackground">
@ -5048,8 +5176,8 @@ SpinBox
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>73</width> <width>259</width>
<height>454</height> <height>853</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -5855,6 +5983,11 @@ SpinBox
<header>GLWidget.h</header> <header>GLWidget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>CurvesGraphicsView</class>
<extends>QGraphicsView</extends>
<header>curvesgraphicsview.h</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>DockWidget</tabstop> <tabstop>DockWidget</tabstop>

View File

@ -95,7 +95,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
m_PreviewRun = true; m_PreviewRun = true;
m_PreviewRunning = true; m_PreviewRunning = true;
m_PreviewRenderer->ThreadCount(max(1u, Timing::ProcessorCount() - 1));//Leave one processor free so the GUI can breathe. m_PreviewRenderer->ThreadCount(std::max(1u, Timing::ProcessorCount() - 1));//Leave one processor free so the GUI can breathe.
QTreeWidget* tree = m_Fractorium->ui.LibraryTree; QTreeWidget* tree = m_Fractorium->ui.LibraryTree;
if (QTreeWidgetItem* top = tree->topLevelItem(0)) if (QTreeWidgetItem* top = tree->topLevelItem(0))
@ -208,7 +208,7 @@ void FractoriumEmberController<T>::SetEmber(size_t index)
/// Wrapper to call a function, then optionally add the requested action to the rendering queue. /// Wrapper to call a function, then optionally add the requested action to the rendering queue.
/// </summary> /// </summary>
/// <param name="func">The function to call</param> /// <param name="func">The function to call</param>
/// <param name="updateRender">True to update renderer, else false. Default: false.</param> /// <param name="updateRender">True to update renderer, else false. Default: true.</param>
/// <param name="action">The action to add to the rendering queue. Default: FULL_RENDER.</param> /// <param name="action">The action to add to the rendering queue. Default: FULL_RENDER.</param>
template <typename T> template <typename T>
void FractoriumEmberController<T>::Update(std::function<void (void)> func, bool updateRender, eProcessAction action) void FractoriumEmberController<T>::Update(std::function<void (void)> func, bool updateRender, eProcessAction action)

View File

@ -55,7 +55,7 @@ public:
virtual void CopyTempPalette(Palette<double>& palette) { } virtual void CopyTempPalette(Palette<double>& palette) { }
#endif #endif
virtual void SetEmber(size_t index) { } virtual void SetEmber(size_t index) { }
virtual void Clear() { } //virtual void Clear() { }
virtual void AddXform() { } virtual void AddXform() { }
virtual void DuplicateXform() { } virtual void DuplicateXform() { }
virtual void ClearCurrentXform() { } virtual void ClearCurrentXform() { }
@ -98,6 +98,17 @@ public:
//Toolbar. //Toolbar.
//Library.
virtual void SyncNames() { }
virtual void SyncPointers() { }
virtual void FillLibraryTree(int selectIndex = -1) { }
virtual void UpdateLibraryTree() { }
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) { }
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { }
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) { }
virtual void StopPreviewRender() { }
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) { }
//Params. //Params.
virtual void SetCenter(double x, double y) { } virtual void SetCenter(double x, double y) { }
virtual void FillParamTablesAndPalette() { } virtual void FillParamTablesAndPalette() { }
@ -156,6 +167,8 @@ public:
virtual void XformColorSpeedChanged(double d) { } virtual void XformColorSpeedChanged(double d) { }
virtual void XformOpacityChanged(double d) { } virtual void XformOpacityChanged(double d) { }
virtual void XformDirectColorChanged(double d) { } virtual void XformDirectColorChanged(double d) { }
virtual void ClearColorCurves() { }
virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { }//need to put this in a different section because it's not xform specific.//TODO
void SetPaletteRefTable(QPixmap* pixmap); void SetPaletteRefTable(QPixmap* pixmap);
//Xforms Variations. //Xforms Variations.
@ -177,15 +190,6 @@ public:
virtual QRgb GetQRgbFromPaletteIndex(uint i) { return QRgb(); } virtual QRgb GetQRgbFromPaletteIndex(uint i) { return QRgb(); }
virtual void PaletteCellClicked(int row, int col) { } virtual void PaletteCellClicked(int row, int col) { }
//Library.
virtual void SyncNames() { }
virtual void FillLibraryTree(int selectIndex = -1) { }
virtual void UpdateLibraryTree() { }
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) { }
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { }
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) { }
virtual void StopPreviewRender() { }
//Info. //Info.
//Rendering/progress. //Rendering/progress.
@ -198,6 +202,7 @@ public:
void StartRenderTimer(); void StartRenderTimer();
void DelayedStartRenderTimer(); void DelayedStartRenderTimer();
void StopRenderTimer(bool wait); void StopRenderTimer(bool wait);
void ClearFinalImages();
void Shutdown(); void Shutdown();
void UpdateRender(eProcessAction action = FULL_RENDER); void UpdateRender(eProcessAction action = FULL_RENDER);
void DeleteRenderer(); void DeleteRenderer();
@ -271,7 +276,7 @@ public:
virtual void CopyTempPalette(Palette<double>& palette) override; virtual void CopyTempPalette(Palette<double>& palette) override;
#endif #endif
virtual void SetEmber(size_t index) override; virtual void SetEmber(size_t index) override;
virtual void Clear() override { } //virtual void Clear() override { }
virtual void AddXform() override; virtual void AddXform() override;
virtual void DuplicateXform() override; virtual void DuplicateXform() override;
virtual void ClearCurrentXform() override; virtual void ClearCurrentXform() override;
@ -317,6 +322,17 @@ public:
//Toolbar. //Toolbar.
//Library.
virtual void SyncNames() override;
virtual void SyncPointers() override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) override;
virtual void StopPreviewRender() override;
//Params. //Params.
virtual void SetCenter(double x, double y) override; virtual void SetCenter(double x, double y) override;
virtual void FillParamTablesAndPalette() override; virtual void FillParamTablesAndPalette() override;
@ -378,6 +394,8 @@ public:
virtual void XformColorSpeedChanged(double d) override; virtual void XformColorSpeedChanged(double d) override;
virtual void XformOpacityChanged(double d) override; virtual void XformOpacityChanged(double d) override;
virtual void XformDirectColorChanged(double d) override; virtual void XformDirectColorChanged(double d) override;
virtual void ClearColorCurves() override;
virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override;
void FillColorWithXform(Xform<T>* xform); void FillColorWithXform(Xform<T>* xform);
//Xforms Variations. //Xforms Variations.
@ -400,15 +418,6 @@ public:
virtual QRgb GetQRgbFromPaletteIndex(uint i) override { return QRgb(); } virtual QRgb GetQRgbFromPaletteIndex(uint i) override { return QRgb(); }
virtual void PaletteCellClicked(int row, int col) override; virtual void PaletteCellClicked(int row, int col) override;
//Library.
virtual void SyncNames() override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) override;
virtual void StopPreviewRender() override;
//Info. //Info.
//Rendering/progress. //Rendering/progress.
@ -433,6 +442,7 @@ private:
//Xforms Color. //Xforms Color.
void SetCurrentXformColorIndex(double d); void SetCurrentXformColorIndex(double d);
void FillCurvesControl();
//Palette. //Palette.
void UpdateAdjustedPaletteGUI(Palette<T>& palette); void UpdateAdjustedPaletteGUI(Palette<T>& palette);

View File

@ -8,6 +8,35 @@ void Fractorium::InitLibraryUI()
{ {
connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::QueuedConnection); connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection); connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
ui.LibraryTree->installEventFilter(this);//Needed for keypress events other than enter.
}
/// <summary>
/// Get the index of the currently selected ember in the library tree.
/// </summary>
/// <returns>A pair containing the index of the item clicked and a pointer to the item</param>
pair<size_t, QTreeWidgetItem*> Fractorium::GetCurrentEmberIndex()
{
size_t index = 0;
QTreeWidgetItem* item = nullptr;
QTreeWidget* tree = ui.LibraryTree;
if (QTreeWidgetItem* top = tree->topLevelItem(0))
{
for (int i = 0; i < top->childCount(); i++)//Iterate through all of the children, which will represent the open embers.
{
item = top->child(index);
if (item && !item->isSelected())
index++;
else
break;
}
}
return pair<size_t, QTreeWidgetItem*>(index, item);
} }
/// <summary> /// <summary>
@ -30,11 +59,10 @@ void FractoriumEmberController<T>::SyncNames()
{ {
EmberTreeWidgetItem<T>* item; EmberTreeWidgetItem<T>* item;
QTreeWidget* tree = m_Fractorium->ui.LibraryTree; QTreeWidget* tree = m_Fractorium->ui.LibraryTree;
QTreeWidgetItem* top = tree->topLevelItem(0);
tree->blockSignals(true); tree->blockSignals(true);
if (top) if (QTreeWidgetItem* top = tree->topLevelItem(0))
{ {
for (int i = 0; i < top->childCount(); i++)//Iterate through all of the children, which will represent the open embers. for (int i = 0; i < top->childCount(); i++)//Iterate through all of the children, which will represent the open embers.
{ {
@ -46,6 +74,31 @@ void FractoriumEmberController<T>::SyncNames()
tree->blockSignals(false); tree->blockSignals(false);
} }
/// <summary>
/// Set all libary tree entries to point to the underlying ember they represent.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::SyncPointers()
{
EmberTreeWidgetItem<T>* item;
QTreeWidget* tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (QTreeWidgetItem* top = tree->topLevelItem(0))
{
size_t childCount = top->childCount();
for (int i = 0; i < childCount; i++)//Iterate through all of the children, which will represent the open embers.
{
if ((item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i))) && i < m_EmberFile.Size())//Cast the child widget to the EmberTreeWidgetItem type.
item->SetEmberPointer(&m_EmberFile.m_Embers[i]);
}
}
tree->blockSignals(false);
}
/// <summary> /// <summary>
/// Fill the library tree with the names of the embers in the /// Fill the library tree with the names of the embers in the
/// currently opened file. /// currently opened file.
@ -135,12 +188,7 @@ void FractoriumEmberController<T>::UpdateLibraryTree()
//When adding elements to the vector, they may have been reshuffled which will have invalidated //When adding elements to the vector, they may have been reshuffled which will have invalidated
//the pointers contained in the EmberTreeWidgetItems. So reassign all pointers here. //the pointers contained in the EmberTreeWidgetItems. So reassign all pointers here.
for (i = 0; i < m_EmberFile.Size(); i++) SyncPointers();
{
if (EmberTreeWidgetItem<T>* emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))
emberItem->SetEmberPointer(&m_EmberFile.m_Embers[i]);
}
tree->blockSignals(false); tree->blockSignals(false);
RenderPreviews(childCount, m_EmberFile.Size()); RenderPreviews(childCount, m_EmberFile.Size());
} }
@ -221,6 +269,47 @@ void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* i
void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { m_Controller->EmberTreeItemDoubleClicked(item, col); } void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { m_Controller->EmberTreeItemDoubleClicked(item, col); }
/// <summary>
/// Delete the currently selected item in the tree.
/// Note this is not necessarilly the current ember, it's just the item
/// in the tree that is selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
template <typename T>
void FractoriumEmberController<T>::Delete(const pair<size_t, QTreeWidgetItem*>& p)
{
QTreeWidget* tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (m_EmberFile.Delete(p.first))
{
delete p.second;
SyncPointers();
}
tree->blockSignals(false);
//If there is now only one item left and it wasn't selected, select it.
if (QTreeWidgetItem* top = tree->topLevelItem(0))
{
if (top->childCount() == 1)
if (auto item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(0)))
if (item->GetEmber()->m_Name != m_Ember.m_Name)
EmberTreeItemDoubleClicked(top->child(0), 0);
}
}
/// <summary>
/// Called when the user presses and releases the delete key while the library tree has the focus,
/// and an item is selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
void Fractorium::OnDelete(const pair<size_t, QTreeWidgetItem*>& p)
{
m_Controller->Delete(p);
}
/// <summary> /// <summary>
/// Stop the preview renderer if it's already running. /// Stop the preview renderer if it's already running.
/// Clear all of the existing preview images, then start the preview rendering thread. /// Clear all of the existing preview images, then start the preview rendering thread.

View File

@ -252,7 +252,11 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
QString filename; QString filename;
FractoriumSettings* s = m_Fractorium->m_Settings; FractoriumSettings* s = m_Fractorium->m_Settings;
if (QFile::exists(m_LastSaveCurrent)) if (s->SaveAutoUnique() && m_LastSaveCurrent != "")
{
filename = EmberFile<T>::UniqueFilename(m_LastSaveCurrent);
}
else if (QFile::exists(m_LastSaveCurrent))
{ {
filename = m_LastSaveCurrent; filename = m_LastSaveCurrent;
} }
@ -281,7 +285,9 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
if (writer.Save(filename.toStdString().c_str(), ember, 0, true, false, true)) if (writer.Save(filename.toStdString().c_str(), ember, 0, true, false, true))
{ {
s->SaveFolder(fileInfo.canonicalPath()); s->SaveFolder(fileInfo.canonicalPath());
m_LastSaveCurrent = filename;
if (!s->SaveAutoUnique() || m_LastSaveCurrent == "")//Only save filename on first time through when doing auto unique names.
m_LastSaveCurrent = filename;
} }
else else
m_Fractorium->ShowCritical("Save Failed", "Could not save file, try saving to a different folder."); m_Fractorium->ShowCritical("Save Failed", "Could not save file, try saving to a different folder.");
@ -301,7 +307,9 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
QString filename; QString filename;
FractoriumSettings* s = m_Fractorium->m_Settings; FractoriumSettings* s = m_Fractorium->m_Settings;
if (QFile::exists(m_LastSaveAll)) if (s->SaveAutoUnique() && m_LastSaveAll != "")
filename = EmberFile<T>::UniqueFilename(m_LastSaveAll);
else if (QFile::exists(m_LastSaveAll))
filename = m_LastSaveAll; filename = m_LastSaveAll;
else else
filename = m_Fractorium->SetupSaveXmlDialog(m_EmberFile.m_Filename); filename = m_Fractorium->SetupSaveXmlDialog(m_EmberFile.m_Filename);
@ -320,7 +328,9 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, false, true)) if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, false, true))
{ {
m_LastSaveAll = filename; if (!s->SaveAutoUnique() || m_LastSaveAll == "")//Only save filename on first time through when doing auto unique names.
m_LastSaveAll = filename;
s->SaveFolder(fileInfo.canonicalPath()); s->SaveFolder(fileInfo.canonicalPath());
} }
else else
@ -398,7 +408,7 @@ void FractoriumEmberController<T>::Undo()
int index = m_Ember.GetTotalXformIndex(CurrentXform()); int index = m_Ember.GetTotalXformIndex(CurrentXform());
m_LastEditWasUndoRedo = true; m_LastEditWasUndoRedo = true;
m_UndoIndex = max(0u, m_UndoIndex - 1u); m_UndoIndex = std::max(0u, m_UndoIndex - 1u);
SetEmber(m_UndoList[m_UndoIndex], true); SetEmber(m_UndoList[m_UndoIndex], true);
m_EditState = UNDO_REDO; m_EditState = UNDO_REDO;
@ -423,7 +433,7 @@ void FractoriumEmberController<T>::Redo()
int index = m_Ember.GetTotalXformIndex(CurrentXform()); int index = m_Ember.GetTotalXformIndex(CurrentXform());
m_LastEditWasUndoRedo = true; m_LastEditWasUndoRedo = true;
m_UndoIndex = min<uint>(m_UndoIndex + 1, m_UndoList.size() - 1); m_UndoIndex = std::min<uint>(m_UndoIndex + 1, m_UndoList.size() - 1);
SetEmber(m_UndoList[m_UndoIndex], true); SetEmber(m_UndoList[m_UndoIndex], true);
m_EditState = UNDO_REDO; m_EditState = UNDO_REDO;

View File

@ -26,9 +26,11 @@
#include <QLineEdit> #include <QLineEdit>
#include <QSpinBox> #include <QSpinBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QPainterPath>
#include <QPushButton> #include <QPushButton>
#include <QComboBox> #include <QComboBox>
#include <QColorDialog> #include <QColorDialog>
#include <QGraphicsView>
#include <QTreeWidget> #include <QTreeWidget>
#include <QWheelEvent> #include <QWheelEvent>
#include <QItemDelegate> #include <QItemDelegate>

View File

@ -67,11 +67,22 @@ void FractoriumEmberControllerBase::StopRenderTimer(bool wait)
void FractoriumEmberControllerBase::Shutdown() void FractoriumEmberControllerBase::Shutdown()
{ {
StopRenderTimer(true); StopRenderTimer(true);
ClearFinalImages();
while(m_Fractorium->ui.GLDisplay->Drawing()) while(m_Fractorium->ui.GLDisplay->Drawing())
QApplication::processEvents(); QApplication::processEvents();
} }
/// <summary>
/// Clear the output image buffers.
/// </summary>
void FractoriumEmberControllerBase::ClearFinalImages()
{
Memset(m_FinalImage[0]);
Memset(m_FinalImage[1]);
//Unsure if we should also call RendererCL::ClearFinal() as well. At the moment it seems unnecessary.
}
/// <summary> /// <summary>
/// Update the state of the renderer. /// Update the state of the renderer.
/// Upon changing values, some intelligence is used to avoid blindly restarting the /// Upon changing values, some intelligence is used to avoid blindly restarting the
@ -442,7 +453,11 @@ bool FractoriumEmberController<T>::Render()
//Uncomment for debugging kernel build and execution errors. //Uncomment for debugging kernel build and execution errors.
//m_Fractorium->ui.InfoRenderingTextEdit->setText(QString::fromStdString(m_Fractorium->m_Wrapper.DumpInfo())); //m_Fractorium->ui.InfoRenderingTextEdit->setText(QString::fromStdString(m_Fractorium->m_Wrapper.DumpInfo()));
//if (rendererCL) //if (rendererCL)
// m_Fractorium->ui.InfoRenderingTextEdit->setText(QString::fromStdString(rendererCL->IterKernel())); //{
// string s = "OpenCL Kernels: \r\n" + rendererCL->IterKernel() + "\r\n" + rendererCL->DEKernel() + "\r\n" + rendererCL->FinalAccumKernel();
//
// QMetaObject::invokeMethod(m_Fractorium->ui.InfoRenderingTextEdit, "setText", Qt::QueuedConnection, Q_ARG(const QString&, QString::fromStdString(s)));
//}
} }
} }
else//Something went very wrong, show error report. else//Something went very wrong, show error report.
@ -460,12 +475,16 @@ bool FractoriumEmberController<T>::Render()
m_Rendering = false; m_Rendering = false;
StopRenderTimer(true); StopRenderTimer(true);
m_Fractorium->m_RenderStatusLabel->setText("Rendering failed 3 or more times, stopping all rendering, see info tab. Try changing renderer types."); m_Fractorium->m_RenderStatusLabel->setText("Rendering failed 3 or more times, stopping all rendering, see info tab. Try changing renderer types.");
Memset(m_FinalImage[m_FinalImageIndex]); ClearFinalImages();
if (rendererCL)
rendererCL->ClearFinal();
m_GLController->ClearWindow(); m_GLController->ClearWindow();
if (rendererCL)
{
//string s = "OpenCL Kernels: \r\n" + rendererCL->IterKernel() + "\r\n" + rendererCL->DEKernel() + "\r\n" + rendererCL->FinalAccumKernel();
rendererCL->ClearFinal();
//QMetaObject::invokeMethod(m_Fractorium->ui.InfoRenderingTextEdit, "setText", Qt::QueuedConnection, Q_ARG(const QString&, QString::fromStdString(s)));
}
} }
} }
} }

View File

@ -39,7 +39,7 @@ void FractoriumSettings::EnsureDefaults()
XmlSupersample(2); XmlSupersample(2);
if (ThreadCount() == 0 || ThreadCount() > Timing::ProcessorCount()) if (ThreadCount() == 0 || ThreadCount() > Timing::ProcessorCount())
ThreadCount(max(1u, Timing::ProcessorCount() - 1));//Default to one less to keep the UI responsive for first time users. ThreadCount(std::max(1u, Timing::ProcessorCount() - 1));//Default to one less to keep the UI responsive for first time users.
if (FinalThreadCount() == 0 || FinalThreadCount() > Timing::ProcessorCount()) if (FinalThreadCount() == 0 || FinalThreadCount() > Timing::ProcessorCount())
FinalThreadCount(Timing::ProcessorCount()); FinalThreadCount(Timing::ProcessorCount());
@ -172,8 +172,8 @@ void FractoriumSettings::FinalKeepAspect(bool b) { setValue(FINALKEEPASPECT,
uint FractoriumSettings::FinalScale() { return value(FINALSCALE).toUInt(); } uint FractoriumSettings::FinalScale() { return value(FINALSCALE).toUInt(); }
void FractoriumSettings::FinalScale(uint i) { setValue(FINALSCALE, i); } void FractoriumSettings::FinalScale(uint i) { setValue(FINALSCALE, i); }
QString FractoriumSettings::FinalExt() { return value(FINALEXT).toString(); } QString FractoriumSettings::FinalExt() { return value(FINALEXT).toString(); }
void FractoriumSettings::FinalExt(const QString& s) { setValue(FINALEXT, s); } void FractoriumSettings::FinalExt(const QString& s) { setValue(FINALEXT, s); }
uint FractoriumSettings::FinalPlatformIndex() { return value(FINALPLATFORMINDEX).toUInt(); } uint FractoriumSettings::FinalPlatformIndex() { return value(FINALPLATFORMINDEX).toUInt(); }
void FractoriumSettings::FinalPlatformIndex(uint i) { setValue(FINALPLATFORMINDEX, i); } void FractoriumSettings::FinalPlatformIndex(uint i) { setValue(FINALPLATFORMINDEX, i); }
@ -239,3 +239,6 @@ void FractoriumSettings::OpenImageExt(const QString& s) { setValue(OPENIMAGEE
QString FractoriumSettings::SaveImageExt() { return value(SAVEIMAGEEXT).toString(); } QString FractoriumSettings::SaveImageExt() { return value(SAVEIMAGEEXT).toString(); }
void FractoriumSettings::SaveImageExt(const QString& s) { setValue(SAVEIMAGEEXT, s); } void FractoriumSettings::SaveImageExt(const QString& s) { setValue(SAVEIMAGEEXT, s); }
bool FractoriumSettings::SaveAutoUnique() { return value(AUTOUNIQUE).toBool(); }
void FractoriumSettings::SaveAutoUnique(bool b) { setValue(AUTOUNIQUE, b); }

View File

@ -52,6 +52,7 @@
#define SAVEXMLEXT "file/savexmlext" #define SAVEXMLEXT "file/savexmlext"
#define OPENIMAGEEXT "file/openimageext" #define OPENIMAGEEXT "file/openimageext"
#define SAVEIMAGEEXT "file/saveimageext" #define SAVEIMAGEEXT "file/saveimageext"
#define AUTOUNIQUE "file/autounique"
#define IDENTITYID "identity/id" #define IDENTITYID "identity/id"
#define IDENTITYURL "identity/url" #define IDENTITYURL "identity/url"
@ -189,6 +190,9 @@ public:
QString SaveImageExt(); QString SaveImageExt();
void SaveImageExt(const QString& s); void SaveImageExt(const QString& s);
bool SaveAutoUnique();
void SaveAutoUnique(bool b);
QString Id(); QString Id();
void Id(const QString& s); void Id(const QString& s);

View File

@ -25,8 +25,15 @@ void Fractorium::InitXformsColorUI()
m_XformColorSpeedSpin->setDecimals(3); m_XformColorSpeedSpin->setDecimals(3);
m_XformOpacitySpin->setDecimals(3); m_XformOpacitySpin->setDecimals(3);
m_XformDirectColorSpin->setDecimals(3); m_XformDirectColorSpin->setDecimals(3);
connect(ui.XformColorScroll, SIGNAL(valueChanged(int)), this, SLOT(OnXformScrollColorIndexChanged(int)), Qt::QueuedConnection); connect(ui.XformColorScroll, SIGNAL(valueChanged(int)), this, SLOT(OnXformScrollColorIndexChanged(int)), Qt::QueuedConnection);
connect(ui.SoloXformCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSoloXformCheckBoxStateChanged(int)), Qt::QueuedConnection); connect(ui.SoloXformCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSoloXformCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.ResetCurvesButton, SIGNAL(clicked(bool)), this, SLOT(OnResetCurvesButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.CurvesView, SIGNAL(PointChangedSignal(int, int, const QPointF&)), this, SLOT(OnCurvesPointChanged(int, int, const QPointF&)), Qt::QueuedConnection);
connect(ui.CurvesAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesAllRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.CurvesRedRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesRedRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.CurvesGreenRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesGreenRadioButtonToggled(bool)), Qt::QueuedConnection);
connect(ui.CurvesBlueRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesBlueRadioButtonToggled(bool)), Qt::QueuedConnection);
} }
/// <summary> /// <summary>
@ -144,6 +151,55 @@ void Fractorium::OnXformRefPaletteResized(int logicalIndex, int oldSize, int new
m_Controller->SetPaletteRefTable(nullptr); m_Controller->SetPaletteRefTable(nullptr);
} }
/// <summary>
/// Reset the color curve values in the current ember to their default state and also update the curves control.
/// Called when ResetCurvesButton is clicked.
/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::ClearColorCurves()
{
Update([&]
{
m_Ember.m_Curves.Init();
}, true, m_Renderer->EarlyClip() ? FILTER_AND_ACCUM : ACCUM_ONLY);
FillCurvesControl();
}
void Fractorium::OnResetCurvesButtonClicked(bool checked) { m_Controller->ClearColorCurves(); }
/// <summary>
/// Set the coordinate of the curve point.
/// Called when the position of any of the points in the curves editor is is changed.
/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip.
/// </summary>
/// <param name="curveIndex">The curve index, 0-1/</param>
/// <param name="pointIndex">The point index within the selected curve, 1-2.</param>
/// <param name="point">The new coordinate of the point in terms of the curves control rect.</param>
template <typename T>
void FractoriumEmberController<T>::ColorCurveChanged(int curveIndex, int pointIndex, const QPointF& point)
{
Update([&]
{
m_Ember.m_Curves.m_Points[curveIndex][pointIndex].x = point.x();
m_Ember.m_Curves.m_Points[curveIndex][pointIndex].y = point.y();
}, true, m_Renderer->EarlyClip() ? FILTER_AND_ACCUM : ACCUM_ONLY);
}
void Fractorium::OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point) { m_Controller->ColorCurveChanged(curveIndex, pointIndex, point); }
/// <summary>
/// Set the top most points in the curves control, which makes it easier to
/// select a point by putting it on top of all the others.
/// Called when the any of the curve color radio buttons are toggled.
/// </summary>
/// <param name="curveIndex">The curve index, 0-1/</param>
void Fractorium::OnCurvesAllRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::ALL); }
void Fractorium::OnCurvesRedRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::RED); }
void Fractorium::OnCurvesGreenRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::GREEN); }
void Fractorium::OnCurvesBlueRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::BLUE); }
/// <summary> /// <summary>
/// Set the current xform color index spinner to the current xform's color index. /// Set the current xform color index spinner to the current xform's color index.
/// Set the color cell in the palette ref table. /// Set the color cell in the palette ref table.
@ -168,6 +224,28 @@ void FractoriumEmberController<T>::SetCurrentXformColorIndex(double d)
}, false); }, false);
} }
/// <summary>
/// Set the points in the curves control to the values of the curve points in the current ember.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::FillCurvesControl()
{
m_Fractorium->ui.CurvesView->blockSignals(true);
for (int i = 0; i < 4; i++)
{
for (int j = 1; j < 3; j++)//Only do middle points.
{
QPointF point(m_Ember.m_Curves.m_Points[i][j].x, m_Ember.m_Curves.m_Points[i][j].y);
m_Fractorium->ui.CurvesView->Set(i, j, point);
}
}
m_Fractorium->ui.CurvesView->blockSignals(false);
m_Fractorium->ui.CurvesView->update();
}
/// <summary> /// <summary>
/// Set the color index, speed and opacity spinners with the values of the current xform. /// Set the color index, speed and opacity spinners with the values of the current xform.
/// Set the cells of the palette ref table as well. /// Set the cells of the palette ref table as well.
@ -180,6 +258,7 @@ void FractoriumEmberController<T>::FillColorWithXform(Xform<T>* xform)
m_Fractorium->m_XformColorSpeedSpin->SetValueStealth(xform->m_ColorSpeed); m_Fractorium->m_XformColorSpeedSpin->SetValueStealth(xform->m_ColorSpeed);
m_Fractorium->m_XformOpacitySpin->SetValueStealth(xform->m_Opacity); m_Fractorium->m_XformOpacitySpin->SetValueStealth(xform->m_Opacity);
m_Fractorium->m_XformDirectColorSpin->SetValueStealth(xform->m_DirectColor); m_Fractorium->m_XformDirectColorSpin->SetValueStealth(xform->m_DirectColor);
FillCurvesControl();
m_Fractorium->OnXformColorIndexChanged(xform->m_ColorX, false);//Had to call stealth before to avoid doing an update, now manually update related controls, still without doing an update. m_Fractorium->OnXformColorIndexChanged(xform->m_ColorX, false);//Had to call stealth before to avoid doing an update, now manually update related controls, still without doing an update.
} }

View File

@ -203,7 +203,7 @@ void GLEmberController<double>::QueryVMP()
/// by an m4<float>. /// by an m4<float>.
/// </summary> /// </summary>
template <> template <>
void GLEmberController<float>::MultMatrix(glm::detail::tmat4x4<float, glm::defaultp>& mat) void GLEmberController<float>::MultMatrix(tmat4x4<float, glm::defaultp>& mat)
{ {
m_GL->glMultMatrixf(glm::value_ptr(mat)); m_GL->glMultMatrixf(glm::value_ptr(mat));
} }
@ -214,7 +214,7 @@ void GLEmberController<float>::MultMatrix(glm::detail::tmat4x4<float, glm::defau
/// by an m4<double>. /// by an m4<double>.
/// </summary> /// </summary>
template <> template <>
void GLEmberController<double>::MultMatrix(glm::detail::tmat4x4<double, glm::defaultp>& mat) void GLEmberController<double>::MultMatrix(tmat4x4<double, glm::defaultp>& mat)
{ {
m_GL->glMultMatrixd(glm::value_ptr(mat)); m_GL->glMultMatrixd(glm::value_ptr(mat));
} }

View File

@ -855,7 +855,7 @@ void GLWidget::DrawGrid()
RendererBase* renderer = m_Fractorium->m_Controller->Renderer(); RendererBase* renderer = m_Fractorium->m_Controller->Renderer();
float unitX = fabs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f; float unitX = fabs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
float unitY = fabs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f; float unitY = fabs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
float rad = max(unitX, unitY); float rad = std::max(unitX, unitY);
float xLow = floor(-unitX); float xLow = floor(-unitX);
float xHigh = ceil(unitX); float xHigh = ceil(unitX);
float yLow = floor(-unitY); float yLow = floor(-unitY);

View File

@ -88,6 +88,7 @@ FractoriumOptionsDialog::FractoriumOptionsDialog(FractoriumSettings* settings, Q
m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples()); m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples());
m_XmlQualitySpin->setValue(m_Settings->XmlQuality()); m_XmlQualitySpin->setValue(m_Settings->XmlQuality());
m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample()); m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample());
ui.AutoUniqueCheckBox->setChecked(m_Settings->SaveAutoUnique());
OnOpenCLCheckBoxStateChanged(ui.OpenCLCheckBox->isChecked()); OnOpenCLCheckBoxStateChanged(ui.OpenCLCheckBox->isChecked());
} }
@ -102,6 +103,7 @@ bool FractoriumOptionsDialog::Transparency() { return ui.TransparencyCheckBox->i
bool FractoriumOptionsDialog::OpenCL() { return ui.OpenCLCheckBox->isChecked(); } bool FractoriumOptionsDialog::OpenCL() { return ui.OpenCLCheckBox->isChecked(); }
bool FractoriumOptionsDialog::Double() { return ui.DoublePrecisionCheckBox->isChecked(); } bool FractoriumOptionsDialog::Double() { return ui.DoublePrecisionCheckBox->isChecked(); }
bool FractoriumOptionsDialog::ShowAllXforms() { return ui.ShowAllXformsCheckBox->isChecked(); } bool FractoriumOptionsDialog::ShowAllXforms() { return ui.ShowAllXformsCheckBox->isChecked(); }
bool FractoriumOptionsDialog::AutoUnique() { return ui.AutoUniqueCheckBox->isChecked(); }
uint FractoriumOptionsDialog::PlatformIndex() { return ui.PlatformCombo->currentIndex(); } uint FractoriumOptionsDialog::PlatformIndex() { return ui.PlatformCombo->currentIndex(); }
uint FractoriumOptionsDialog::DeviceIndex() { return ui.DeviceCombo->currentIndex(); } uint FractoriumOptionsDialog::DeviceIndex() { return ui.DeviceCombo->currentIndex(); }
uint FractoriumOptionsDialog::ThreadCount() { return ui.ThreadCountSpin->value(); } uint FractoriumOptionsDialog::ThreadCount() { return ui.ThreadCountSpin->value(); }
@ -162,6 +164,7 @@ void FractoriumOptionsDialog::accept()
m_Settings->XmlTemporalSamples(m_XmlTemporalSamplesSpin->value()); m_Settings->XmlTemporalSamples(m_XmlTemporalSamplesSpin->value());
m_Settings->XmlQuality(m_XmlQualitySpin->value()); m_Settings->XmlQuality(m_XmlQualitySpin->value());
m_Settings->XmlSupersample(m_XmlSupersampleSpin->value()); m_Settings->XmlSupersample(m_XmlSupersampleSpin->value());
m_Settings->SaveAutoUnique(AutoUnique());
//Identity. //Identity.
m_Settings->Id(m_IdEdit->text()); m_Settings->Id(m_IdEdit->text());
@ -196,7 +199,8 @@ void FractoriumOptionsDialog::reject()
m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples()); m_XmlTemporalSamplesSpin->setValue(m_Settings->XmlTemporalSamples());
m_XmlQualitySpin->setValue(m_Settings->XmlQuality()); m_XmlQualitySpin->setValue(m_Settings->XmlQuality());
m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample()); m_XmlSupersampleSpin->setValue(m_Settings->XmlSupersample());
ui.AutoUniqueCheckBox->setChecked(m_Settings->SaveAutoUnique());
//Identity. //Identity.
m_IdEdit->setText(m_Settings->Id()); m_IdEdit->setText(m_Settings->Id());
m_UrlEdit->setText(m_Settings->Url()); m_UrlEdit->setText(m_Settings->Url());

View File

@ -40,6 +40,7 @@ private:
bool OpenCL(); bool OpenCL();
bool Double(); bool Double();
bool ShowAllXforms(); bool ShowAllXforms();
bool AutoUnique();
uint PlatformIndex(); uint PlatformIndex();
uint DeviceIndex(); uint DeviceIndex();
uint ThreadCount(); uint ThreadCount();

View File

@ -486,6 +486,13 @@ in interactive mode for each mouse movement</string>
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="AutoUniqueCheckBox">
<property name="text">
<string>Auto Unique Filenames</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="OptionsIdentityTab"> <widget class="QWidget" name="OptionsIdentityTab">

View File

@ -77,7 +77,7 @@ void SpinBox::DoubleClickNonZero(int val)
/// <param name="step">The small step to use for scrolling while the shift key is down</param> /// <param name="step">The small step to use for scrolling while the shift key is down</param>
void SpinBox::SmallStep(int step) void SpinBox::SmallStep(int step)
{ {
m_SmallStep = min(1, step); m_SmallStep = std::min(1, step);
} }
/// <summary> /// <summary>