--User changes:

-Show common folder locations such as documents, downloads, pictures in the sidebar in all file dialogs.
 -Warning message about exceeding memory in final render dialog now suggests strips as the solution to the problem.
 -Strips now has a tooltip explaining what it does.
 -Allow more digits in the spinners on the color section the flame tab.
 -Add manually adjustable size spinners in the final render dialog. Percentage scale and absolute size are fully synced.
 -Default prefix in final render is now the filename when doing animations (coming from sequence section of the library tab).
 -Changed the elliptic variation back to using a less precise version for float, and a more precise version for double. The last release had it always using double.
 -New applied xaos table that shows a read-only view of actual weights by taking the base xform weights and multiplying them by the xaos values.
 -New table in the xaos tab that gives a graphical representation of the probability that each xform is chosen, with and without xaos.
 -Add button to transpose the xaos rows and columns.
 -Add support for importing .chaos files from Chaotica.
 --Pasting back to Chaotica will work for most, but not all, variations due to incompatible parameter names in some.
 -Curves are now splines instead of Bezier. This adds compatibility with Chaotica, but breaks it for Apophysis. Xmls are still pastable, but the color curves will look different.
 --The curve editor on the palette tab can now add points by clicking on the lines and remove points by clicking on the points themselves, just like Chaotica.
 --Splines are saved in four new xml fields: overall_curve, red_curve, green_curve and blue_curve.
 -Allow for specifying the percentage of a sub batch each thread should iterate through per kernel call when running with OpenCL. This gives a roughly 1% performance increase due to having to make less kernel calls while iterating.
 --This field is present for interactive editing (where it's not very useful) and in the final render dialog.
 --On the command line, this is specified as --sbpctth for EmberRender and EmberAnimate.
 -Allow double clicking to toggle the supersample field in the flame tab between 1 and 2 for easily checking the effect of the field.
 -When showing affine values as polar coordinates, show angles normalized to 360 to match Chaotica.
 -Fuse Count spinner now toggles between 15 and 100 when double clicking for easily checking the effect of the field.
 -Added field for limiting the range in the x and y direction that the initial points are chosen from.
 -Added a field called K2 which is an alternative way to set brightness, ignored when zero.
 --This has no effect for many variations, but hs a noticeable effect for some.
 -Added new variations:
 arcsech
 arcsech2
 arcsinh
 arctanh
 asteria
 block
 bwraps_rand
 circlecrop2
 coth_spiral
 crackle2
 depth_blur
 depth_blur2
 depth_gaussian
 depth_gaussian2
 depth_ngon
 depth_ngon2
 depth_sine
 depth_sine2
 dragonfire
 dspherical
 dust
 excinis
 exp2
 flipx
 flowerdb
 foci_p
 gaussian
 glynnia2
 glynnsim4
 glynnsim5
 henon
 henon
 hex_rand
 hex_truchet
 hypershift
 lazyjess
 lens
 lozi
 lozi
 modulusx
 modulusy
 oscilloscope2
 point_symmetry
 pointsymmetry
 projective
 pulse
 rotate
 scry2
 shift
 smartshape
 spher
 squares
 starblur2
 swirl3
 swirl3r
 tanh_spiral
 target0
 target2
 tile_hlp
 truchet_glyph
 truchet_inv
 truchet_knot
 unicorngaloshen
 vibration
 vibration2
 --hex_truchet, hex_rand should always use double. They are extremely sensitive.

--Bug fixes:
 -Bounds sign was flipped for x coordinate of world space when center was not zero.
 -Right clicking and dragging spinner showed menu on mouse up, even if it was very far away.
 -Text boxes for size in final render dialog were hard to type in. Same bug as xform weight used to be so fix the same way.
 -Fix spelling to be plural in toggle color speed box.
 -Stop using the blank user palette to generate flames. Either put colored palettes in it, or exclude it from randoms.
 -Clicking the random palette button for a palette file with only one palette in it would freeze the program.
 -Clicking none scale in final render did not re-render the preview.
 -Use less precision on random xaos. No need for 12 decimal places.
 -The term sub batch is overloaded in the options dialog. Change the naming and tooltip of those settings for cpu and opencl.
 --Also made clear in the tooltip for the default opencl quality setting that the value is per device.
 -The arrows spinner in palette editor appears like a read-only label. Made it look like a spinner.
 -Fix border colors for various spin boxes and table headers in the style sheet. Requires reload.
 -Fix a bug in the bwraps variation which would produce different results than Chaotica and Apophysis.
 -Synth was allowed to be selected for random flame generation when using an Nvidia card but it shouldn't have been because Nvidia has a hard time compiling synth.
 -A casting bug in the OpenCL kernels for log scaling and density filtering was preventing successful compilations on Intel iGPUs. Fixed even though we don't support anything other than AMD and Nvidia.
 -Palette rotation (click and drag) position was not being reset when loading a new flame.
 -When the xform circles were hidden, opening and closing the options dialog would improperly reshow them.
 -Double click toggle was broken on integer spin boxes.
 -Fixed tab order of some controls.
 -Creating a palette from a jpg in the palette editor only produced a single color.
 --Needed to package imageformats/qjpeg.dll with the Windows installer.
 -The basic memory benchmark test flame was not really testing memory. Make it more spread out.
 -Remove the temporal samples field from the flame tab, it was never used because it's only an animation parameter which is specified in the final render dialog or on the command line with EmberAnimate.

--Code changes:
 -Add IsEmpty() to Palette to determine if a palette is all black.
 -Attempt to avoid selecting a blank palette in PaletteList::GetRandomPalette().
 -Add function ScanForChaosNodes() and some associated helper functions in XmlToEmber.
 -Make variation param name correction be case insensitive in XmlToEmber.
 -Report error when assigning a variation param value in XmlToEmber.
 -Add SubBatchPercentPerThread() method to RendererCL.
 -Override enterEvent() and leaveEvent() in DoubleSpinBox and SpinBox to prevent the context menu from showing up on right mouse up after already leaving the spinner.
 -Filtering the mouse wheel event in TableWidget no longer appears to be needed. It was probably an old Qt bug that has been fixed.
 -Gui/ember syncing code in the final render dialog needed to be reworked to accommodate absolute sizes.
This commit is contained in:
Person 2019-04-13 19:00:46 -07:00
parent d9bfe17b42
commit 90ec5b8246
91 changed files with 11011 additions and 1268 deletions

View File

@ -6,7 +6,7 @@
<ProductVersion>3.7</ProductVersion>
<ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>Fractorium_1.0.0.14</OutputName>
<OutputName>Fractorium_1.0.0.15</OutputName>
<OutputType>Package</OutputType>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ProductVersion="1.0.0.14" ?>
<?define ProductVersion="1.0.0.15" ?>
<?define ProductName="Fractorium $(var.ProductVersion) ($(var.GpuType))" ?>
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
<?define Manufacturer="Fractorium"?>
@ -13,7 +13,7 @@
<!--
Change this for every release.
-->
<?define ProductCode="{F303D411-E358-403E-9F59-03BB35813D8B}"?>
<?define ProductCode="{4B40B3EC-7FE5-41DE-824E-EEC006B9D614}"?>
<Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package
@ -51,6 +51,7 @@
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="BenchComponents" />
<ComponentGroupRef Id="PlatformComponents" />
<ComponentGroupRef Id="ImageFormatComponents" />
<ComponentRef Id="FractoriumStartMenuShortcut"/>
<ComponentRef Id="FractoriumDesktopShortcut"/>
</Feature>
@ -84,6 +85,7 @@
<Directory Id="INSTALLFOLDER" Name="Fractorium" >
<Directory Id="INSTALLFOLDERBENCH" Name="Bench" />
<Directory Id="INSTALLFOLDERPLATFORMS" Name="platforms" />
<Directory Id="INSTALLFOLDERIMAGEFORMATS" Name="imageformats" />
</Directory>
</Directory>
@ -316,4 +318,12 @@
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="ImageFormatComponents" Directory="INSTALLFOLDERIMAGEFORMATS">
<Component Id="qjpeg.dll" Guid="da079a2d-1ab7-443c-a21e-4434ef58c6cc">
<File Id="qjpeg.dll" Source="$(env.QTDIR)\plugins\imageformats\qjpeg.dll" KeyPath="yes" Checksum="yes" ProcessorArchitecture="x64" ReadOnly="yes"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>

Binary file not shown.

View File

@ -115,6 +115,7 @@
<ItemGroup>
<ClInclude Include="..\..\..\Source\Ember\Affine2D.h" />
<ClInclude Include="..\..\..\Source\Ember\CarToRas.h" />
<ClInclude Include="..\..\..\Source\Ember\Spline.h" />
<ClInclude Include="..\..\..\Source\Ember\Curves.h" />
<ClInclude Include="..\..\..\Source\Ember\EmberDefines.h" />
<ClInclude Include="..\..\..\Source\Ember\EmberMotion.h" />
@ -151,6 +152,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Source\Ember\Affine2D.cpp" />
<ClCompile Include="..\..\..\Source\Ember\Spline.cpp" />
<ClCompile Include="..\..\..\Source\Ember\DllMain.cpp" />
<ClCompile Include="..\..\..\Source\Ember\Ember.cpp" />
<ClCompile Include="..\..\..\Source\Ember\EmberPch.cpp">

View File

@ -128,6 +128,9 @@
<ClInclude Include="..\..\..\Source\Ember\Variations07.h">
<Filter>Header Files\Variations</Filter>
</ClInclude>
<ClInclude Include="..\..\..\Source\Ember\Spline.h">
<Filter>Header Files\Xml</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Source\Ember\DllMain.cpp">
@ -160,6 +163,9 @@
<ClCompile Include="..\..\..\Source\Ember\PaletteList.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\Source\Ember\Spline.cpp">
<Filter>Header Files\Xml</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Ember.rc">

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

@ -87,30 +87,14 @@
<PostBuildEvent>
<Command>xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Deps\*.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_02.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_03_triangle.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_04_mineshack.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_01_variety_number_128.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_02_b_sides.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_03_old_and_new.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_04_hoard.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fractaldesire_pack_01.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\rce_ordinary_pack_01_colornation.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_01.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_colder.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_dark.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_warmer.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_03.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\*.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\*.ugr" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\dark_windows.qss" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Cored.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Guid.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Widgetsd.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindowsd.dll" "$(OutDir)\platforms\"
</Command>
xcopy /F /Y /R /D "$(QTDIR)\plugins\imageformats\qjpegd.dll" "$(OutDir)\imageformats\"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -145,29 +129,14 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindowsd.dll" "$(OutDir)\platform
<PostBuildEvent>
<Command>xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Deps\*.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\flam3-palettes.xml" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_02.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_03_triangle.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\boxtail_pack_04_mineshack.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_01_variety_number_128.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_02_b_sides.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_03_old_and_new.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fardareismai_pack_04_hoard.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\fractaldesire_pack_01.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\rce_ordinary_pack_01_colornation.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_01.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_colder.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_dark.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_02_warmer.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\tatasz_pack_03.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\*.gradient" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\*.ugr" "$(OutDir)"
xcopy /F /Y /R /D "$(SolutionDir)..\..\..\Data\dark_windows.qss" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Core.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Gui.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\bin\Qt5Widgets.dll" "$(OutDir)"
xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms\"</Command>
xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms\"
xcopy /F /Y /R /D "$(QTDIR)\plugins\imageformats\qjpeg.dll" "$(OutDir)\imageformats\"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -43,6 +43,7 @@ SOURCES += \
$$PRJ_SRC_DIR/RendererBase.cpp \
$$PRJ_SRC_DIR/Renderer.cpp \
$$PRJ_SRC_DIR/VariationList.cpp \
$$PRJ_SRC_DIR/Spline.cpp \
$$PRJ_SRC_DIR/XmlToEmber.cpp
include(deployment.pri)
@ -51,6 +52,7 @@ qtcAddDeployment()
HEADERS += \
$$PRJ_SRC_DIR/Affine2D.h \
$$PRJ_SRC_DIR/CarToRas.h \
$$PRJ_SRC_DIR/Spline.h \
$$PRJ_SRC_DIR/Curves.h \
$$PRJ_SRC_DIR/DensityFilter.h \
$$PRJ_SRC_DIR/EmberDefines.h \

View File

@ -28,6 +28,10 @@ CONFIG(release, debug|release) {
qtplatforms.path = $$BIN_INSTALL_DIR\platforms
qtplatforms.files = $$(QTDIR)\plugins\platforms\qwindows.dll
INSTALLS += qtplatforms
qimageformats.path = $$BIN_INSTALL_DIR\imageformats
qimageformats.files = $$(QTDIR)\plugins\imageformats\qjpeg.dll
INSTALLS += qimageformats
}
CONFIG(debug, debug|release) {
@ -38,6 +42,10 @@ CONFIG(debug, debug|release) {
qtplatforms.path = $$BIN_INSTALL_DIR\platforms
qtplatforms.files = $$(QTDIR)\plugins\platforms\qwindowsd.dll
INSTALLS += qtplatforms
qimageformats.path = $$BIN_INSTALL_DIR\imageformats
qimageformats.files = $$(QTDIR)\plugins\imageformats\qjpeg.dll
INSTALLS += qimageformats
}
}

View File

@ -1,4 +1,4 @@
VERSION = 1.0.0.14
VERSION = 1.0.0.15
win32:CONFIG += skip_target_version_ext
CONFIG += c++14

View File

@ -71,6 +71,10 @@ function TestFileSupersamples([string]$filename, [string]$precision, [string]$su
function BenchAllForFile([string]$filename)
{
#if you want to test extreme speed on your GPU, add this option, --sbpctth=1.0, to increase the amount of each sub batch that is done on each opencl thread per kernel launch.
#set the value from somewhere between 0.025 (the default) and 1.0 (the max).
#this usuall results in a roughly 1% speed improvement.
#however, it can cause the render to fail, especially on the golubaja_rippingfrominside_complexcode and zy0rg_six_bigcomplexcode flames when using double precision.
$misc = "--opencl --device=" + $devices
TestFileSupersamples $filename "--sp" "_f32_cpu" $script:cpuquality ""
TestFileSupersamples $filename "" "_f64_cpu" $script:cpuquality ""
@ -87,13 +91,13 @@ $fileOne = $benchprefix + "tatasz_springcrown_manysimplexforms.flame"
BenchAllForFile $fileOne
$fileOne = $benchprefix + "tyrantwave_flippeddisc_normal.flame"
BenchAllForFile $fileOne
#BenchAllForFile $fileOne
$fileOne = $benchprefix + "golubaja_rippingfrominside_complexcode.flame"
BenchAllForFile $fileOne
$fileOne = $benchprefix + "zy0rg_six_bigcomplexcode.flame"
BenchAllForFile $fileOne
#BenchAllForFile $fileOne
$Script:totalOutput | Out-File -FilePath benchout.txt
$table | Export-Csv -Path ".\benchout.csv" -Force -NoTypeInformation

View File

@ -1,6 +1,6 @@
<flames>
<flame version="EMBER-WIN-1.0.0.7" time="0" name="mfeemster_basicmemory" size="1920 1280" center="0 0" scale="990" rotate="0" supersample="1" filter="1" filter_shape="gaussian" temporal_filter_type="box" temporal_filter_width="1" quality="1000" temporal_samples="100" sub_batch_size="10240" fuse="15" background="0 0 0" brightness="4" gamma="4" highlight_power="1" vibrancy="1" estimator_radius="0" estimator_minimum="0" estimator_curve="0.4" gamma_threshold="0.1" cam_zpos="0" cam_persp="0" cam_yaw="0" cam_pitch="0" cam_dof="0" palette_mode="linear" interpolation="smooth" interpolation_type="log" plugins="linear" new_linear="1" curves="0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 ">
<xform weight="0.333333" color="0.340114" var_color="1" color_speed="0.5" symmetry="0" name="" animate="0" linear="1" coefs="1 0 0 1 0 0" opacity="1"/>
<flame version="EMBER-WIN-1.0.0.15" time="0" name="mfeemster_basicmemory" size="1920 1280" center="0 0" scale="990" rotate="0" supersample="2" filter="1" filter_shape="gaussian" temporal_filter_type="box" temporal_filter_width="1" quality="1000" temporal_samples="100" sub_batch_size="10240" fuse="15" background="0 0 0" brightness="4" gamma="4" highlight_power="1" vibrancy="1" estimator_radius="0" estimator_minimum="0" estimator_curve="0.4" gamma_threshold="0.1" cam_zpos="0" cam_persp="0" cam_yaw="0" cam_pitch="0" cam_dof="0" palette_mode="linear" interpolation="linear" interpolation_type="log" plugins="linear" new_linear="1" curves="0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 ">
<xform weight="0.333333" color="0.340114" var_color="1" color_speed="0.5" symmetry="0" name="" animate="0" linear="1" coefs="0.999822 -0.0188645 0.0188645 0.999822 0 0" opacity="1"/>
<palette count="256" format="RGB">
F1DFDDFAEAEDFDEDEEFDEFEFFFF0F3FCEBF3FDEBEBFBE7E8
FEDADEF8D9E1F1D4D8DFC2C4D89CB8AB82A2934C6E814A5D
@ -35,8 +35,10 @@
E2D4E3C6B7CA9F8EAE667DA96B6071483B573A3247312A49
28213320172A151314100702090001020001010000050100
</palette>
<edit date="Wed Nov 15 21:20:27 -0800 2017" action="edit">
<edit filename="" index="0"/>
<edit date="Sun Feb 17 20:04:18 -0800 2019" action="edit">
<edit date="Wed Nov 15 21:20:27 -0800 2017" action="edit" filename="C:/D/Dev/fractorium/Bin/x64/Release/Bench/mfeemster_basicmemory.flame" index="0">
<edit filename="" index="0"/>
</edit>
</edit>
</flame>
</flames>

View File

@ -39,7 +39,7 @@ QDockWidget::float-button
QDockWidget::title
{
margin: 1px;
margin: 0px;
padding: 2px;
background-color: gray;
}
@ -418,7 +418,7 @@ QHeaderView::section::horizontal:enabled
{
color: black;
background-color: darkgray;
border: 0px solid darkgray;
border: 1px solid darkgray;
border-right: 1px solid gray;
padding-top: 0px;
padding-bottom: 0px;
@ -620,8 +620,12 @@ QSpinBox#ThreadCountSpin,
QSpinBox#RandomCountSpin,
QSpinBox#CpuSubBatchSpin,
QSpinBox#OpenCLSubBatchSpin,
QSpinBox#CpuQualitySpin,
QSpinBox#OpenCLQualitySpin,
QDoubleSpinBox#OpenCLSubBatchPctSpin,
QSpinBox#FinalRenderCurrentSpin,
QSpinBox#FinalRenderThreadCountSpin
QSpinBox#FinalRenderThreadCountSpin,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin
{
padding: 2px;
border: 1px solid gray;
@ -630,8 +634,12 @@ QSpinBox#FinalRenderThreadCountSpin
QSpinBox#ThreadCountSpin:disabled,
QSpinBox#CpuSubBatchSpin:disabled,
QSpinBox#OpenCLSubBatchSpin:disabled,
QSpinBox#CpuQualitySpin:disabled,
QSpinBox#OpenCLQualitySpin:disabled,
QDoubleSpinBox#OpenCLSubBatchPctSpin:disabled,
QSpinBox#FinalRenderCurrentSpin:disabled,
QSpinBox#FinalRenderThreadCountSpin:disabled
QSpinBox#FinalRenderThreadCountSpin:disabled,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin:disabled
{
padding: 2px;
border: 1px solid rgb(35, 35, 35);

View File

@ -39,7 +39,7 @@ QDockWidget::float-button
QDockWidget::title
{
margin: 1px;
margin: 0px;
padding: 2px;
background-color: gray;
}
@ -419,7 +419,7 @@ QHeaderView::section::horizontal:enabled
{
color: black;
background-color: darkgray;
border: 0px solid darkgray;
border: 1px solid darkgray;
border-right: 1px solid gray;
padding-top: 0px;
padding-bottom: 0px;
@ -621,8 +621,12 @@ QSpinBox#ThreadCountSpin,
QSpinBox#RandomCountSpin,
QSpinBox#CpuSubBatchSpin,
QSpinBox#OpenCLSubBatchSpin,
QSpinBox#CpuQualitySpin,
QSpinBox#OpenCLQualitySpin,
QDoubleSpinBox#OpenCLSubBatchPctSpin,
QSpinBox#FinalRenderCurrentSpin,
QSpinBox#FinalRenderThreadCountSpin
QSpinBox#FinalRenderThreadCountSpin,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin
{
padding: 2px;
border: 1px solid gray;
@ -631,8 +635,12 @@ QSpinBox#FinalRenderThreadCountSpin
QSpinBox#ThreadCountSpin:disabled,
QSpinBox#CpuSubBatchSpin:disabled,
QSpinBox#OpenCLSubBatchSpin:disabled,
QSpinBox#CpuQualitySpin:disabled,
QSpinBox#OpenCLQualitySpin:disabled,
QDoubleSpinBox#OpenCLSubBatchPctSpin:disabled,
QSpinBox#FinalRenderCurrentSpin:disabled,
QSpinBox#FinalRenderThreadCountSpin:disabled
QSpinBox#FinalRenderThreadCountSpin:disabled,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin:disabled
{
padding: 2px;
border: 1px solid rgb(35, 35, 35);

View File

@ -39,7 +39,7 @@ QDockWidget::float-button
QDockWidget::title
{
margin: 1px;
margin: 0px;
padding: 2px;
background-color: gray;
}
@ -418,7 +418,7 @@ QHeaderView::section::horizontal:enabled
{
color: black;
background-color: darkgray;
border: 0px solid darkgray;
border: 1px solid darkgray;
border-right: 1px solid gray;
padding-top: 0px;
padding-bottom: 0px;
@ -620,8 +620,12 @@ QSpinBox#ThreadCountSpin,
QSpinBox#RandomCountSpin,
QSpinBox#CpuSubBatchSpin,
QSpinBox#OpenCLSubBatchSpin,
QSpinBox#CpuQualitySpin,
QSpinBox#OpenCLQualitySpin,
QDoubleSpinBox#OpenCLSubBatchPctSpin,
QSpinBox#FinalRenderCurrentSpin,
QSpinBox#FinalRenderThreadCountSpin
QSpinBox#FinalRenderThreadCountSpin,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin
{
padding: 2px;
border: 1px solid gray;
@ -630,8 +634,12 @@ QSpinBox#FinalRenderThreadCountSpin
QSpinBox#ThreadCountSpin:disabled,
QSpinBox#CpuSubBatchSpin:disabled,
QSpinBox#OpenCLSubBatchSpin:disabled,
QSpinBox#CpuQualitySpin:disabled,
QSpinBox#OpenCLQualitySpin:disabled,
QDoubleSpinBox#OpenCLSubBatchPctSpin:disabled,
QSpinBox#FinalRenderCurrentSpin:disabled,
QSpinBox#FinalRenderThreadCountSpin:disabled
QSpinBox#FinalRenderThreadCountSpin:disabled,
QDoubleSpinBox#FinalRenderOpenCLSubBatchPctSpin:disabled
{
padding: 2px;
border: 1px solid rgb(35, 35, 35);

View File

@ -2,6 +2,9 @@
#include "Utils.h"
#include "Isaac.h"
#include "Curves.h"
#define CURVE_POINTS 5
/// <summary>
/// Curves class.
@ -10,8 +13,9 @@
namespace EmberNs
{
/// <summary>
/// The Bezier curves used to adjust the colors during final accumulation.
/// This functionality was gotten directly from Apophysis.
/// The b-spline curves used to adjust the colors during final accumulation.
/// This functionality was gotten inferred from Chaotica.
/// Note this is now incompatible with Apophysis, which uses Bezier curves instead.
/// </summary>
template <typename T>
class EMBER_API Curves
@ -69,14 +73,23 @@ public:
template <typename U>
Curves<T>& operator = (const Curves<U>& curves)
{
for (size_t i = 0; i < 4; i++)
int i = 0;
for (auto& pp : curves.m_Points)
{
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);
int j = 0;
m_Points[i].clear();
for (auto& p : pp)
{
m_Points[i].push_back(p);
j++;
}
i++;
}
i = 0;
return *this;
}
@ -88,13 +101,23 @@ public:
template <typename U>
Curves<T>& operator += (const Curves<U>& curves)
{
for (size_t i = 0; i < 4; i++)
int i = 0;
for (auto& pp : m_Points)
{
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];
int j = 0;
for (auto& p : pp)
{
if (j < curves.m_Points[i].size())
p += curves.m_Points[i][j];
else
break;
j++;
}
i++;
}
return *this;
@ -108,13 +131,23 @@ public:
template <typename U>
Curves<T>& operator *= (const Curves<U>& curves)
{
for (size_t i = 0; i < 4; i++)
int i = 0;
for (auto& pp : m_Points)
{
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];
int j = 0;
for (auto& p : pp)
{
if (j < curves.m_Points[i].size())
p *= curves.m_Points[i][j];
else
break;
j++;
}
i++;
}
return *this;
@ -128,14 +161,9 @@ public:
template <typename U>
Curves<T>& operator *= (const U& t)
{
for (size_t i = 0; i < 4; i++)
{
m_Points[i][0] *= T(t);
m_Points[i][1] *= T(t);
m_Points[i][2] *= T(t);
m_Points[i][3] *= T(t);
m_Weights[i] *= T(t);
}
for (auto& pp : m_Points)
for (auto& p : pp)
p *= T(t);
return *this;
}
@ -147,11 +175,12 @@ public:
{
for (size_t 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);
m_Points[i].resize(5);
m_Points[i][0] = v2T(0);
m_Points[i][1] = v2T(T(0.25));
m_Points[i][2] = v2T(T(0.50));
m_Points[i][3] = v2T(T(0.75));
m_Points[i][4] = v2T(1);
}
}
@ -162,11 +191,12 @@ public:
{
if (i < 4)
{
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);
m_Points[i].resize(5);
m_Points[i][0] = v2T(0);
m_Points[i][1] = v2T(T(0.25));
m_Points[i][2] = v2T(T(0.50));
m_Points[i][3] = v2T(T(0.75));
m_Points[i][4] = v2T(1);
}
}
@ -175,8 +205,8 @@ public:
/// </summary>
void Clear()
{
memset(&m_Points, 0, sizeof(m_Points));
memset(&m_Weights, 0, sizeof(m_Weights));
for (auto& p : m_Points)
p.clear();
}
/// <summary>
@ -189,10 +219,18 @@ public:
for (size_t i = 0; i < 4; i++)
{
if (m_Points[i].size() != CURVE_POINTS)
{
set = true;
break;
}
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)))
(m_Points[i][1] != v2T(T(0.25))) ||
(m_Points[i][2] != v2T(T(0.50))) ||
(m_Points[i][3] != v2T(T(0.75))) ||
(m_Points[i][4] != v2T(1))
)
{
set = true;
break;
@ -202,52 +240,9 @@ public:
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 = 1 - t;
T s2 = s * s;
T s3 = s * s * s;
T t2 = t * t;
T t3 = t * 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);
T 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);
T denom = (w->x * s3) + (w->y * s2 * 3 * t) + (w->z * s * 3 * t2) + (w->w * t3);
if (std::isnan(nom_x) || std::isnan(nom_y) || std::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];
std::array<std::vector<v2T>, 4> m_Points;
};
//Must declare this outside of the class to provide for both orders of parameters.
@ -264,14 +259,9 @@ Curves<T> operator * (const Curves<T>& curves, const U& t)
T tt = T(t);
Curves<T> c(curves);
for (size_t i = 0; i < 4; i++)
{
c.m_Points[i][0] *= tt;
c.m_Points[i][1] *= tt;
c.m_Points[i][2] *= tt;
c.m_Points[i][3] *= tt;
c.m_Weights[i] *= tt;
}
for (auto& pp : c.m_Points)
for (auto& p : pp)
p *= tt;
return c;
}

View File

@ -31,6 +31,7 @@ template EMBER_API class QTIsaac<ISAAC_SIZE, ISAAC_INT>;
#include "Xform.h"
#include "EmberMotion.h"
#include "EmberToXml.h"
#include "Spline.h"
#include "XmlToEmber.h"
#include "SpatialFilter.h"
#include "DensityFilter.h"
@ -77,6 +78,8 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Sinusoidal, T) \
EXPORTPREPOSTREGVAR(Spherical, T) \
EXPORTPREPOSTREGVAR(Swirl, T) \
EXPORTPREPOSTREGVAR(Swirl3, T) \
EXPORTPREPOSTREGVAR(Swirl3r, T) \
EXPORTPREPOSTREGVAR(Horseshoe, T) \
EXPORTPREPOSTREGVAR(Polar, T) \
EXPORTPREPOSTREGVAR(Handkerchief, T) \
@ -109,6 +112,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(JuliaScope, T) \
EXPORTPREPOSTREGVAR(Blur, T) \
EXPORTPREPOSTREGVAR(GaussianBlur, T) \
EXPORTPREPOSTREGVAR(Gaussian, T) \
EXPORTPREPOSTREGVAR(RadialBlur, T) \
EXPORTPREPOSTREGVAR(Pie, T) \
EXPORTPREPOSTREGVAR(Ngon, T) \
@ -128,6 +132,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Disc2, T) \
EXPORTPREPOSTREGVAR(SuperShape, T) \
EXPORTPREPOSTREGVAR(Flower, T) \
EXPORTPREPOSTREGVAR(FlowerDb, T) \
EXPORTPREPOSTREGVAR(Conic, T) \
EXPORTPREPOSTREGVAR(Parabola, T) \
EXPORTPREPOSTREGVAR(Bent2, T) \
@ -145,9 +150,11 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Loonie, T) \
EXPORTPREPOSTREGVAR(Modulus, T) \
EXPORTPREPOSTREGVAR(Oscilloscope, T) \
EXPORTPREPOSTREGVAR(Oscilloscope2, T) \
EXPORTPREPOSTREGVAR(Polar2, T) \
EXPORTPREPOSTREGVAR(Popcorn2, T) \
EXPORTPREPOSTREGVAR(Scry, T) \
EXPORTPREPOSTREGVAR(Scry2, T) \
EXPORTPREPOSTREGVAR(Separation, T) \
EXPORTPREPOSTREGVAR(Split, T) \
EXPORTPREPOSTREGVAR(Splits, T) \
@ -158,6 +165,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Whorl, T) \
EXPORTPREPOSTREGVAR(Waves2, T) \
EXPORTPREPOSTREGVAR(Exp, T) \
EXPORTPREPOSTREGVAR(Exp2, T) \
EXPORTPREPOSTREGVAR(Log, T) \
EXPORTPREPOSTREGVAR(Sin, T) \
EXPORTPREPOSTREGVAR(Cos, T) \
@ -168,6 +176,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Sinh, T) \
EXPORTPREPOSTREGVAR(Cosh, T) \
EXPORTPREPOSTREGVAR(Tanh, T) \
EXPORTPREPOSTREGVAR(TanhSpiral, T) \
EXPORTPREPOSTREGVAR(Sech, T) \
EXPORTPREPOSTREGVAR(Csch, T) \
EXPORTPREPOSTREGVAR(Coth, T) \
@ -176,6 +185,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Hemisphere, T) \
EXPORTPREPOSTREGVAR(Epispiral, T) \
EXPORTPREPOSTREGVAR(Bwraps, T) \
EXPORTPREPOSTREGVAR(BwrapsRand, T) \
EXPORTPREPOSTREGVAR(Extrude, T) \
EXPORTPREPOSTREGVAR(BlurCircle, T) \
EXPORTPREPOSTREGVAR(BlurZoom, T) \
@ -196,6 +206,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Fibonacci, T) \
EXPORTPREPOSTREGVAR(Fibonacci2, T) \
EXPORTPREPOSTREGVAR(Glynnia, T) \
EXPORTPREPOSTREGVAR(Glynnia2, T) \
EXPORTPREPOSTREGVAR(GridOut, T) \
EXPORTPREPOSTREGVAR(Hole, T) \
EXPORTPREPOSTREGVAR(Hypertile, T) \
@ -241,6 +252,8 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(GlynnSim1, T) \
EXPORTPREPOSTREGVAR(GlynnSim2, T) \
EXPORTPREPOSTREGVAR(GlynnSim3, T) \
EXPORTPREPOSTREGVAR(GlynnSim4, T) \
EXPORTPREPOSTREGVAR(GlynnSim5, T) \
EXPORTPREPOSTREGVAR(Starblur, T) \
EXPORTPREPOSTREGVAR(Sineblur, T) \
EXPORTPREPOSTREGVAR(Circleblur, T) \
@ -255,6 +268,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Ovoid3D, T) \
EXPORTPREPOSTREGVAR(Spirograph, T) \
EXPORTPREPOSTREGVAR(Petal, T) \
EXPORTPREPOSTREGVAR(Spher, T) \
EXPORTPREPOSTREGVAR(RoundSpher, T) \
EXPORTPREPOSTREGVAR(RoundSpher3D, T) \
EXPORTPREPOSTREGVAR(SpiralWing, T) \
@ -267,6 +281,8 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Lissajous, T) \
EXPORTPREPOSTREGVAR(Svf, T) \
EXPORTPREPOSTREGVAR(Target, T) \
EXPORTPREPOSTREGVAR(Target0, T) \
EXPORTPREPOSTREGVAR(Target2, T) \
EXPORTPREPOSTREGVAR(Taurus, T) \
EXPORTPREPOSTREGVAR(Collideoscope, T) \
EXPORTPREPOSTREGVAR(BMod, T) \
@ -275,6 +291,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(BCollide, T) \
EXPORTPREPOSTREGVAR(Eclipse, T) \
EXPORTPREPOSTREGVAR(FlipCircle, T) \
EXPORTPREPOSTREGVAR(FlipX, T) \
EXPORTPREPOSTREGVAR(FlipY, T) \
EXPORTPREPOSTREGVAR(ECollide, T) \
EXPORTPREPOSTREGVAR(EJulia, T) \
@ -284,6 +301,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(ERotate, T) \
EXPORTPREPOSTREGVAR(EScale, T) \
EXPORTPREPOSTREGVAR(ESwirl, T) \
EXPORTPREPOSTREGVAR(LazyJess, T) \
EXPORTPREPOSTREGVAR(LazyTravis, T) \
EXPORTPREPOSTREGVAR(Squish, T) \
EXPORTPREPOSTREGVAR(Circus, T) \
@ -311,6 +329,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(SuperShape3D, T) \
EXPORTPREPOSTREGVAR(Sphyp3D, T) \
EXPORTPREPOSTREGVAR(Circlecrop, T) \
EXPORTPREPOSTREGVAR(Circlecrop2, T) \
EXPORTPREPOSTREGVAR(Julian3Dx, T) \
EXPORTPREPOSTREGVAR(Fourth, T) \
EXPORTPREPOSTREGVAR(Mobiq, T) \
@ -336,13 +355,13 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Curvature, T) \
EXPORTPREPOSTREGVAR(Qode, T) \
EXPORTPREPOSTREGVAR(BlurHeart, T) \
EXPORTPREPOSTREGVAR(Truchet, T) \
EXPORTPREPOSTREGVAR(Gdoffs, T) \
EXPORTPREPOSTREGVAR(Octagon, T) \
EXPORTPREPOSTREGVAR(Trade, T) \
EXPORTPREPOSTREGVAR(Juliac, T) \
EXPORTPREPOSTREGVAR(Blade3D, T) \
EXPORTPREPOSTREGVAR(Blob3D, T) \
EXPORTPREPOSTREGVAR(Block, T) \
EXPORTPREPOSTREGVAR(Blocky, T) \
EXPORTPREPOSTREGVAR(Bubble2, T) \
EXPORTPREPOSTREGVAR(CircleLinear, T) \
@ -351,6 +370,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Cubic3D, T) \
EXPORTPREPOSTREGVAR(CubicLattice3D, T) \
EXPORTPREPOSTREGVAR(Foci3D, T) \
EXPORTPREPOSTREGVAR(FociP, T) \
EXPORTPREPOSTREGVAR(Ho, T) \
EXPORTPREPOSTREGVAR(Julia3Dq, T) \
EXPORTPREPOSTREGVAR(Line, T) \
@ -380,6 +400,7 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(BubbleT3D, T) \
EXPORTPREPOSTREGVAR(Synth, T) \
EXPORTPREPOSTREGVAR(Crackle, T) \
EXPORTPREPOSTREGVAR(Crackle2, T) \
EXPORTPREPOSTREGVAR(Erf, T) \
EXPORTPREPOSTREGVAR(Xerf, T) \
EXPORTPREPOSTREGVAR(W, T) \
@ -398,7 +419,12 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(CircleSplit, T) \
EXPORTPREPOSTREGVAR(Cylinder2, T) \
EXPORTPREPOSTREGVAR(TileLog, T) \
EXPORTPREPOSTREGVAR(TileHlp, T) \
EXPORTPREPOSTREGVAR(Truchet, T) \
EXPORTPREPOSTREGVAR(TruchetFill, T) \
EXPORTPREPOSTREGVAR(TruchetGlyph, T) \
EXPORTPREPOSTREGVAR(TruchetInv, T) \
EXPORTPREPOSTREGVAR(TruchetKnot, T) \
EXPORTPREPOSTREGVAR(Waves2Radial, T) \
EXPORTPREPOSTREGVAR(Panorama1, T) \
EXPORTPREPOSTREGVAR(Panorama2, T) \
@ -408,7 +434,44 @@ uint Timing::m_ProcessorCount;
EXPORTPREPOSTREGVAR(Cpow3, T) \
EXPORTPREPOSTREGVAR(Concentric, T) \
EXPORTPREPOSTREGVAR(Hypercrop, T) \
EXPORTPREPOSTREGVAR(Hypershift, T) \
EXPORTPREPOSTREGVAR(Hypershift2, T) \
EXPORTPREPOSTREGVAR(Lens, T) \
EXPORTPREPOSTREGVAR(Projective, T) \
EXPORTPREPOSTREGVAR(DepthBlur, T) \
EXPORTPREPOSTREGVAR(DepthBlur2, T) \
EXPORTPREPOSTREGVAR(DepthGaussian, T) \
EXPORTPREPOSTREGVAR(DepthGaussian2, T) \
EXPORTPREPOSTREGVAR(DepthNgon, T) \
EXPORTPREPOSTREGVAR(DepthNgon2, T) \
EXPORTPREPOSTREGVAR(DepthSine, T) \
EXPORTPREPOSTREGVAR(DepthSine2, T) \
EXPORTPREPOSTREGVAR(CothSpiral, T) \
EXPORTPREPOSTREGVAR(Dust, T) \
EXPORTPREPOSTREGVAR(Asteria, T) \
EXPORTPREPOSTREGVAR(Pulse, T) \
EXPORTPREPOSTREGVAR(Excinis, T) \
EXPORTPREPOSTREGVAR(Vibration, T) \
EXPORTPREPOSTREGVAR(Vibration2, T) \
EXPORTPREPOSTREGVAR(Arcsech, T) \
EXPORTPREPOSTREGVAR(Arcsech2, T) \
EXPORTPREPOSTREGVAR(Arcsinh, T) \
EXPORTPREPOSTREGVAR(Arctanh, T) \
EXPORTPREPOSTREGVAR(HexTruchet, T) \
EXPORTPREPOSTREGVAR(HexRand, T) \
EXPORTPREPOSTREGVAR(Smartshape, T) \
EXPORTPREPOSTREGVAR(Squares, T) \
EXPORTPREPOSTREGVAR(Starblur2, T) \
EXPORTPREPOSTREGVAR(UnicornGaloshen, T) \
EXPORTPREPOSTREGVAR(Dragonfire, T) \
EXPORTPREPOSTREGVAR(Henon, T) \
EXPORTPREPOSTREGVAR(Lozi, T) \
EXPORTPREPOSTREGVAR(PointSymmetry, T) \
EXPORTPREPOSTREGVAR(DSpherical, T) \
EXPORTPREPOSTREGVAR(Modulusx, T) \
EXPORTPREPOSTREGVAR(Modulusy, T) \
EXPORTPREPOSTREGVAR(Rotate, T) \
EXPORTPREPOSTREGVAR(Shift, T) \
template EMBER_API class PostSmartcropVariation<T>; /*Only implemented as post.*/ \
EXPORTPREPOSTREGVAR(DCBubble, T) \
EXPORTPREPOSTREGVAR(DCCarpet, T) \
@ -460,6 +523,7 @@ EXPORT_TWO_TYPE_EMBER(float, float)
//Only ever use float palettes.
template EMBER_API class Palette<float>;
template EMBER_API class PaletteList<float>;
template EMBER_API class Spline<float>;
#ifdef DO_DOUBLE
EXPORT_SINGLE_TYPE_EMBER(double)

View File

@ -106,6 +106,7 @@ public:
m_OrigFinalRasW = ember.m_OrigFinalRasW;
m_OrigFinalRasH = ember.m_OrigFinalRasH;
m_OrigPixPerUnit = T(ember.m_OrigPixPerUnit);
m_RandPointRange = T(ember.m_RandPointRange);
m_SubBatchSize = ember.m_SubBatchSize;
m_FuseCount = ember.m_FuseCount;
m_Supersample = ember.m_Supersample;
@ -129,6 +130,7 @@ public:
m_Vibrancy = T(ember.m_Vibrancy);
m_GammaThresh = T(ember.m_GammaThresh);
m_HighlightPower = T(ember.m_HighlightPower);
m_K2 = T(ember.m_K2);
m_Time = T(ember.m_Time);
m_Background = ember.m_Background;
m_Interp = ember.m_Interp;
@ -530,6 +532,7 @@ public:
/// <param name="width">New width</param>
/// <param name="height">New height</param>
/// <param name="onlyScaleIfNewIsSmaller">True to only scale if the new dimensions are smaller than the original, else always scale.</param>
/// <param name="scaleType">Scale type used to specify how the image should be zoomed using the scale variable with respect to the new size. Possible scaling modes are: width, height, none.</param>
void SetSizeAndAdjustScale(size_t width, size_t height, bool onlyScaleIfNewIsSmaller, eScaleType scaleType)
{
if ((onlyScaleIfNewIsSmaller && (width < m_OrigFinalRasW || height < m_OrigFinalRasH)) || !onlyScaleIfNewIsSmaller)
@ -538,6 +541,8 @@ public:
m_PixelsPerUnit = m_OrigPixPerUnit * (T(width) / T(m_OrigFinalRasW));
else if (scaleType == eScaleType::SCALE_HEIGHT)
m_PixelsPerUnit = m_OrigPixPerUnit * (T(height) / T(m_OrigFinalRasH));
else
m_PixelsPerUnit = m_OrigPixPerUnit;
}
m_ScaleType = scaleType;
@ -744,6 +749,7 @@ public:
InterpI<&Ember<T>::m_FinalRasW>(embers, coefs, size);
InterpI<&Ember<T>::m_FinalRasH>(embers, coefs, size);
InterpI<&Ember<T>::m_SubBatchSize>(embers, coefs, size);
InterpT<&Ember<T>::m_RandPointRange>(embers, coefs, size);
InterpI<&Ember<T>::m_FuseCount>(embers, coefs, size);
InterpI<&Ember<T>::m_Supersample>(embers, coefs, size);
InterpI<&Ember<T>::m_TemporalSamples>(embers, coefs, size);
@ -765,6 +771,7 @@ public:
InterpT<&Ember<T>::m_Vibrancy>(embers, coefs, size);
InterpT<&Ember<T>::m_GammaThresh>(embers, coefs, size);
InterpT<&Ember<T>::m_HighlightPower>(embers, coefs, size);
InterpT<&Ember<T>::m_K2>(embers, coefs, size);
InterpX<Color<T>, &Ember<T>::m_Background>(embers, coefs, size); m_Background.a = bgAlphaSave;//Don't interp alpha.
InterpT<&Ember<T>::m_TemporalFilterExp>(embers, coefs, size);
InterpT<&Ember<T>::m_TemporalFilterWidth>(embers, coefs, size);
@ -1309,6 +1316,14 @@ public:
APP_FMP(m_HighlightPower);
break;
case eEmberMotionParam::FLAME_MOTION_K2:
APP_FMP(m_K2);
break;
case eEmberMotionParam::FLAME_MOTION_RAND_RANGE:
APP_FMP(m_RandPointRange);
break;
case eEmberMotionParam::FLAME_MOTION_BACKGROUND_R:
APP_FMP(m_Background.r);
break;
@ -1359,6 +1374,7 @@ public:
{
//If defaults are on, set to reasonable values.
m_HighlightPower = 1;
m_K2 = 0;
m_Background.Reset();
m_FinalRasW = 100;
m_FinalRasH = 100;
@ -1375,6 +1391,7 @@ public:
m_CamMat = m3T(0);
m_Quality = 1;
m_SubBatchSize = 10240;
m_RandPointRange = 1;
m_FuseCount = 15;
m_MaxRadDE = T(9.0);
m_MinRadDE = 0;
@ -1393,6 +1410,7 @@ public:
{
//Defaults are off, so set to UN-reasonable values.
m_HighlightPower = -1;
m_K2 = -1;
m_Background = Color<T>(-1, -1, -1, 1);
m_FinalRasW = 0;
m_FinalRasH = 0;
@ -1409,6 +1427,7 @@ public:
m_CamMat = m3T(999999);
m_Quality = -1;
m_SubBatchSize = 0;
m_RandPointRange = 0;
m_FuseCount = 0;
m_MaxRadDE = -1;
m_MinRadDE = -1;
@ -1459,6 +1478,7 @@ public:
<< "Quality: " << m_Quality << "\n"
<< "Pixels Per Unit: " << m_PixelsPerUnit << "\n"
<< "Original Pixels Per Unit: " << m_OrigPixPerUnit << "\n"
<< "Initial Point Range: " << m_RandPointRange << "\n"
<< "Sub Batch Size: " << m_SubBatchSize << "\n"
<< "Fuse Count: " << m_FuseCount << "\n"
<< "Zoom: " << m_Zoom << "\n"
@ -1476,6 +1496,7 @@ public:
<< "Vibrancy: " << m_Vibrancy << "\n"
<< "Gamma Threshold: " << m_GammaThresh << "\n"
<< "Highlight Power: " << m_HighlightPower << "\n"
<< "K2: " << m_K2 << "\n"
<< "Time: " << m_Time << "\n"
<< "Background: " << m_Background.r << ", " << m_Background.g << ", " << m_Background.b << ", " << m_Background.a << "\n"
<< "Interp: " << m_Interp << "\n"
@ -1531,6 +1552,10 @@ public:
size_t m_OrigFinalRasH = 1080;//the dimension may change in an editor and the originals are needed for the aspect ratio.
T m_OrigPixPerUnit = 240;
//The range in the x and y directions from the center of the world space from which the initial random point will be selected at the start of each sub batch.
//Or when recovering from a bad point.
T m_RandPointRange = 1;
//The iteration depth. This was a rendering parameter in flam3 but has been made a member here
//so that it can be adjusted more easily.
size_t m_SubBatchSize = DEFAULT_SBS;
@ -1628,6 +1653,9 @@ public:
//Xml field: "highlight_power".
T m_HighlightPower = 1;
//An alternative way to set brightness, ignored when zero.
T m_K2 = 0;
//When animating a file full of many embers, this value is used to specify the time in the animation
//that this ember should be rendered. They must all be sequential and increase by a default value of 1.
//Xml field: "time".

View File

@ -37,7 +37,7 @@ static void sincos(float x, float* s, float* c)
namespace EmberNs
{
#define EMBER_VERSION "1.0.0.14"
#define EMBER_VERSION "1.0.0.15"
#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 ISAAC_SIZE 4
@ -106,6 +106,7 @@ static inline size_t NowMs() { return duration_cast<milliseconds>(Clock::now().t
#define v2T glm::tvec2<T, glm::defaultp>
#define v3T glm::tvec3<T, glm::defaultp>
#define v4T glm::tvec4<T, glm::defaultp>
#define v2F glm::tvec2<float, glm::defaultp>
#define v4F glm::tvec4<float, glm::defaultp>
#define v4D glm::tvec4<double, glm::defaultp>
#define v4bT glm::tvec4<bucketT, glm::defaultp>
@ -118,6 +119,7 @@ static inline size_t NowMs() { return duration_cast<milliseconds>(Clock::now().t
#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 v2F glm::detail::tvec2<float, glm::defaultp>
#define v4F glm::detail::tvec4<float, glm::defaultp>
#define v4D glm::detail::tvec4<double, glm::defaultp>
#define v4bT glm::detail::tvec4<bucketT, glm::defaultp>
@ -154,6 +156,8 @@ enum class eEmberMotionParam : et//These must remain in this order forever.
FLAME_MOTION_GAMMA,
FLAME_MOTION_GAMMA_THRESH,
FLAME_MOTION_HIGHLIGHT_POWER,
FLAME_MOTION_K2,
FLAME_MOTION_RAND_RANGE,
FLAME_MOTION_BACKGROUND_R,
FLAME_MOTION_BACKGROUND_G,
FLAME_MOTION_BACKGROUND_B,

View File

@ -143,10 +143,12 @@ string EmberToXml<T>::ToString(Ember<T>& ember, const string& extraAttributes, s
os << " temporal_samples=\"" << ember.m_TemporalSamples << "\"";
os << " sub_batch_size=\"" << ember.m_SubBatchSize << "\"";
os << " fuse=\"" << ember.m_FuseCount << "\"";
os << " rand_range=\"" << ember.m_RandPointRange << "\"";
os << " background=\"" << ember.m_Background.r << " " << ember.m_Background.g << " " << ember.m_Background.b << "\"";
os << " brightness=\"" << ember.m_Brightness << "\"";
os << " gamma=\"" << ember.m_Gamma << "\"";
os << " highlight_power=\"" << ember.m_HighlightPower << "\"";
os << " logscale_k2=\"" << ember.m_K2 << "\"";
os << " vibrancy=\"" << ember.m_Vibrancy << "\"";
os << " estimator_radius=\"" << ember.m_MaxRadDE << "\"";
os << " estimator_minimum=\"" << ember.m_MinRadDE << "\"";
@ -200,10 +202,42 @@ string EmberToXml<T>::ToString(Ember<T>& ember, const string& extraAttributes, s
{
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 << "1 ";
}
}
os << "\" overall_curve=\"";
for (glm::length_t cj = 0; cj < ember.m_Curves.m_Points[0].size(); cj++)
{
os << ember.m_Curves.m_Points[0][cj].x << " ";
os << ember.m_Curves.m_Points[0][cj].y << " ";
}
os << "\" red_curve=\"";
for (glm::length_t cj = 0; cj < ember.m_Curves.m_Points[1].size(); cj++)
{
os << ember.m_Curves.m_Points[1][cj].x << " ";
os << ember.m_Curves.m_Points[1][cj].y << " ";
}
os << "\" green_curve=\"";
for (glm::length_t cj = 0; cj < ember.m_Curves.m_Points[2].size(); cj++)
{
os << ember.m_Curves.m_Points[2][cj].x << " ";
os << ember.m_Curves.m_Points[2][cj].y << " ";
}
os << "\" blue_curve=\"";
for (glm::length_t cj = 0; cj < ember.m_Curves.m_Points[3].size(); cj++)
{
os << ember.m_Curves.m_Points[3][cj].x << " ";
os << ember.m_Curves.m_Points[3][cj].y << " ";
}
os << "\">\n";
for (i = 0; i < ember.m_EmberMotionElements.size(); ++i)
@ -813,6 +847,14 @@ string EmberToXml<T>::ToString(const EmberMotion<T>& motion)
os << " highlight_power=\"" << motion.m_MotionParams[i].second << "\"";
break;
case eEmberMotionParam::FLAME_MOTION_K2:
os << " logscale_k2=\"" << motion.m_MotionParams[i].second << "\"";
break;
case eEmberMotionParam::FLAME_MOTION_RAND_RANGE:
os << " rand_range=\"" << motion.m_MotionParams[i].second << "\"";
break;
case eEmberMotionParam::FLAME_MOTION_BACKGROUND_R:
r = motion.m_MotionParams[i].second;
break;

View File

@ -15,9 +15,7 @@ namespace EmberNs
using Iterator<T>::NextXformFromIndex; \
using Iterator<T>::DoFinalXform; \
using Iterator<T>::DoBadVals;
template <typename T, typename bucketT> class Renderer;
template <typename T>
struct IterParams
{
@ -40,7 +38,7 @@ struct IterParams
/// Flam3 needlessly computed the final xform on each fuse iteration only to throw it away. It's omitted here as an optimization.
/// Rather than place many conditionals inside the iteration loop, they are broken into separate classes depending
/// on what's contained in the ember's xforms.
/// The biggest difference is whether xaos is present or not it requires extra work when picking
/// The biggest difference is whether xaos is present or not, since it requires extra work when picking
/// the next random xform to use. Further, each of those is broken into two loops, one for embers with a final xform
/// and one without.
/// Last, the fuse loop and real loop are separated and duplicated to omit the conditional check for fuse inside the real loop.
@ -52,9 +50,12 @@ class EMBER_API Iterator
{
public:
/// <summary>
/// Empty constructor and virtual destructor so proper derived class destructors get called.
/// Constructor that takes a pointer to the renderer which is calling this and a virtual destructor so proper derived class destructors get called.
/// </summary>
Iterator() = default;
Iterator()
{
}
virtual ~Iterator() = default;
Iterator(const Iterator<T>& iter) = delete;
@ -196,11 +197,12 @@ protected:
/// the coordinates of the output point are just set to a random number between -1 and 1.
/// </summary>
/// <param name="xforms">The xforms array</param>
/// <param name="range">The range in the x and y directions from the center of the world spcae from which to select the new random point</param>
/// <param name="badVals">The counter for the total number of bad values this sub batch</param>
/// <param name="point">The point which initially had the bad values and which will store the newly computed values</param>
/// <param name="rand">The random context this iterator is using</param>
/// <returns>True if a good value was computed within 5 tries, else false</returns>
inline bool DoBadVals(Xform<T>* xforms, size_t& badVals, Point<T>* point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
inline bool DoBadVals(Xform<T>* xforms, T range, size_t& badVals, Point<T>* point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
{
size_t xformIndex, consec = 0;
Point<T> firstBadPoint;
@ -209,8 +211,8 @@ protected:
{
consec++;
badVals++;
firstBadPoint.m_X = rand.Frand11<T>();//Re-randomize points, but keep the computed color and viz.
firstBadPoint.m_Y = rand.Frand11<T>();
firstBadPoint.m_X = rand.template Frand<T>(-range, range);//Re-randomize points, but keep the computed color and viz.
firstBadPoint.m_Y = rand.template Frand<T>(-range, range);
firstBadPoint.m_Z = 0;
firstBadPoint.m_ColorX = point->m_ColorX;
firstBadPoint.m_Opacity = point->m_Opacity;
@ -223,8 +225,8 @@ protected:
//After 5 tries, nothing worked, so just assign random values between -1 and 1.
if (consec == 5)
{
point->m_X = rand.Frand11<T>();
point->m_Y = rand.Frand11<T>();
point->m_X = rand.template Frand<T>(-range, range);
point->m_Y = rand.template Frand<T>(-range, range);
point->m_Z = 0;
}
@ -310,7 +312,7 @@ public:
for (i = 0; i < params.m_Skip; i++)//Fuse.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
}
DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples.
@ -319,7 +321,7 @@ public:
for (i = 1; i < params.m_Count; i++)//Real loop.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
ember.Proj(samples[i], rand);
@ -332,7 +334,7 @@ public:
for (i = 0; i < params.m_Skip; i++)//Fuse.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
}
samples[0] = p1;
@ -341,7 +343,7 @@ public:
for (i = 1; i < params.m_Count; i++)//Real loop.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &samples[i], rand))
DoBadVals(xforms, badVals, samples + i, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, samples + i, rand);
p1 = samples[i];
ember.Proj(samples[i], rand);
@ -357,7 +359,7 @@ public:
for (i = 0; i < params.m_Skip; i++)//Fuse.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
}
DoFinalXform(ember, p1, samples, rand);//Apply to last fuse point and store as the first element in samples.
@ -365,7 +367,7 @@ public:
for (i = 1; i < params.m_Count; i++)//Real loop.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform.
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
}
@ -377,7 +379,7 @@ public:
for (i = 0; i < params.m_Skip; i++)//Fuse.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(&p1, &p1, rand))
DoBadVals(xforms, badVals, &p1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, &p1, rand);
}
samples[0] = p1;
@ -385,7 +387,7 @@ public:
for (i = 0; i < params.m_Count - 1; i++)//Real loop.
{
if (xforms[NextXformFromIndex(rand.Rand())].Apply(samples + i, samples + i + 1, rand))
DoBadVals(xforms, badVals, samples + i + 1, rand);
DoBadVals(xforms, ember.m_RandPointRange, badVals, samples + i + 1, rand);
}
}
}
@ -415,12 +417,13 @@ public:
/// </summary>
/// <param name="xforms">The xforms array</param>
/// <param name="xformIndex">Index of the last used xform before calling this function</param>
/// <param name="range">The range in the x and y directions from the center of the world spcae from which to select the new random point</param>
/// <param name="lastXformUsed">The saved index of the last xform used within this function</param>
/// <param name="badVals">The counter for the total number of bad values this sub batch</param>
/// <param name="point">The point which initially had the bad values and which will store the newly computed values</param>
/// <param name="rand">The random context this iterator is using</param>
/// <returns>True if a good value was computed within 5 tries, else false</returns>
inline bool DoBadVals(Xform<T>* xforms, size_t& xformIndex, size_t lastXformUsed, size_t& badVals, Point<T>* point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
inline bool DoBadVals(Xform<T>* xforms, size_t& xformIndex, T range, size_t lastXformUsed, size_t& badVals, Point<T>* point, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
{
size_t consec = 0;
Point<T> firstBadPoint;
@ -429,8 +432,8 @@ public:
{
consec++;
badVals++;
firstBadPoint.m_X = rand.Frand11<T>();//Re-randomize points, but keep the computed color and viz.
firstBadPoint.m_Y = rand.Frand11<T>();
firstBadPoint.m_X = rand.template Frand<T>(-range, range);//Re-randomize points, but keep the computed color and viz.
firstBadPoint.m_Y = rand.template Frand<T>(-range, range);
firstBadPoint.m_Z = 0;
firstBadPoint.m_ColorX = point->m_ColorX;
firstBadPoint.m_Opacity = point->m_Opacity;
@ -443,8 +446,8 @@ public:
//After 5 tries, nothing worked, so just assign random.
if (consec == 5)
{
point->m_X = rand.Frand11<T>();
point->m_Y = rand.Frand11<T>();
point->m_X = rand.template Frand<T>(-range, range);
point->m_Y = rand.template Frand<T>(-range, range);
point->m_Z = 0;
}
@ -479,7 +482,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
@ -492,7 +495,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform.
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
ember.Proj(samples[i], rand);
@ -508,7 +511,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
@ -521,7 +524,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
samples[i] = p1;
ember.Proj(samples[i], rand);
@ -540,7 +543,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
@ -552,7 +555,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))//Feed the resulting value of applying the randomly selected xform back into the next iter, and not the result of applying the final xform.
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
DoFinalXform(ember, p1, samples + i, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
@ -567,7 +570,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(&p1, &p1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, &p1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, &p1, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}
@ -579,7 +582,7 @@ public:
xformIndex = NextXformFromIndex(rand.Rand(), lastXformUsed);
if (xforms[xformIndex].Apply(samples + i, samples + i + 1, rand))
DoBadVals(xforms, xformIndex, lastXformUsed, badVals, samples + i + 1, rand);
DoBadVals(xforms, xformIndex, ember.m_RandPointRange, lastXformUsed, badVals, samples + i + 1, rand);
lastXformUsed = xformIndex + 1;//Store the last used transform.
}

View File

@ -415,6 +415,20 @@ public:
return v;
}
/// <summary>
/// Determine if a palette is all black.
/// </summary>
/// <returns>True if all colors are black, else false if at least one component of one color is non zero.</returns>
bool IsEmpty()
{
for (glm::length_t i = 0; i < Size(); i++)
for (glm::length_t j = 0; j < 3; j++)
if (m_Entries[i][j] != 0)
return false;
return true;
}
/// <summary>
/// Convert RGB to HSV.
/// </summary>

View File

@ -258,30 +258,39 @@ bool PaletteList<T>::Add(const string& filename, bool force)
/// <summary>
/// Get the palette at a random index in a random file in the map.
/// Attempt to avoid selecting a palette which is all black.
/// </summary>
/// <returns>A pointer to a random palette in a random file if successful, else nullptr.</returns>
template <typename T>
Palette<T>* PaletteList<T>::GetRandomPalette()
{
auto p = s_Palettes.begin();
size_t i = 0, paletteFileIndex = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand() % Size();
size_t attempts = 0;
//Move p forward i elements.
while (i < paletteFileIndex && p != s_Palettes.end())
while (attempts < Size() * 10)
{
++i;
++p;
auto p = s_Palettes.begin();
auto paletteFileIndex = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand() % Size();
size_t i = 0;
//Move p forward i elements.
while (i < paletteFileIndex && p != s_Palettes.end())
{
++i;
++p;
}
if (i < Size())
{
size_t paletteIndex = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand() % p->second.size();
if (paletteIndex < p->second.size() && !p->second[paletteIndex].IsEmpty())
return &p->second[paletteIndex];
}
attempts++;
}
if (i < Size())
{
size_t paletteIndex = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand() % p->second.size();
if (paletteIndex < p->second.size())
return &p->second[paletteIndex];
}
return nullptr;
return Size() ? &s_Palettes[0][0] : nullptr;
}
/// <summary>

View File

@ -99,7 +99,7 @@ template <typename T, typename bucketT>
void Renderer<T, bucketT>::ComputeQuality()
{
m_Scale = std::pow(T(2.0), Zoom());
m_ScaledQuality = Quality() * m_Scale * m_Scale;
m_ScaledQuality = Quality() * SQR(m_Scale);
}
/// <summary>
@ -591,18 +591,23 @@ FilterAndAccum:
//Compute k1 and k2.
auto fullRun = eRenderStatus::RENDER_OK;//Whether density filtering was run to completion without aborting prematurely or triggering an error.
T area = FinalRasW() * FinalRasH() / (m_PixelsPerUnitX * m_PixelsPerUnitY);//Need to use temps from field if ever implemented.
m_K1 = bucketT((Brightness() * 268) / 256);
m_K1 = Brightness();
//When doing an interactive render, force output early on in the render process, before all iterations are done.
//This presents a problem with the normal calculation of K2 since it relies on the quality value; it will scale the colors
//to be very dark. Correct it by pretending the number of iters done is the exact quality desired and then scale according to that.
if (forceOutput)
if (!m_Ember.m_K2 || forceOutput)
{
T quality = (T(m_Stats.m_Iters) / T(FinalDimensions())) * (m_Scale * m_Scale);
m_K2 = bucketT((Supersample() * Supersample()) / (area * quality * m_TemporalFilter->SumFilt()));
//When doing an interactive render, force output early on in the render process, before all iterations are done.
//This presents a problem with the normal calculation of K2 since it relies on the quality value; it will scale the colors
//to be very dark. Correct it by pretending the number of iters done is the exact quality desired and then scale according to that.
if (forceOutput)
{
T quality = (T(m_Stats.m_Iters) / T(FinalDimensions())) * (m_Scale * m_Scale);
m_K2 = bucketT((Supersample() * Supersample()) / (area * quality * m_TemporalFilter->SumFilt()));
}
else
m_K2 = bucketT((Supersample() * Supersample()) / (area * m_ScaledQuality * m_TemporalFilter->SumFilt()));
}
else
m_K2 = bucketT((Supersample() * Supersample()) / (area * m_ScaledQuality * m_TemporalFilter->SumFilt()));
m_K2 = bucketT(m_Ember.m_K2);
if (!ResetBuckets(false, true))//Only the histogram was reset above, now reset the density filtering buffer.
{
@ -1282,10 +1287,10 @@ EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t temporalSample
//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 = std::min(params.m_Count, totalItersPerThread - m_SubBatch[threadIndex]);
//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.
//This helps correct if iteration happens to be on a bad trajectory.
m_Samples[threadIndex][0].m_X = m_Rand[threadIndex].template Frand11<T>();
m_Samples[threadIndex][0].m_Y = m_Rand[threadIndex].template Frand11<T>();
m_Samples[threadIndex][0].m_X = m_Rand[threadIndex].template Frand<T>(-m_ThreadEmbers[threadIndex].m_RandPointRange, m_ThreadEmbers[threadIndex].m_RandPointRange);
m_Samples[threadIndex][0].m_Y = m_Rand[threadIndex].template Frand<T>(-m_ThreadEmbers[threadIndex].m_RandPointRange, m_ThreadEmbers[threadIndex].m_RandPointRange);
m_Samples[threadIndex][0].m_Z = 0;//m_Ember.m_CamZPos;//Apo set this to 0, then made the user use special variations to kick it. It seems easier to just set it to zpos.
m_Samples[threadIndex][0].m_ColorX = m_Rand[threadIndex].template Frand01<T>();
@ -1727,9 +1732,21 @@ void Renderer<T, bucketT>::ComputeCurves()
{
//Timing t;
auto st = m_Csa.size();
vector<glm::tvec2<float, glm::defaultp>> vals;
vals.reserve(m_Ember.m_Curves.m_Points[0].size());
for (size_t i = 0; i < st; i++)
m_Csa[i] = m_Ember.m_Curves.BezierFunc(i * ONE_OVER_CURVES_LENGTH_M1);
for (glm::length_t i = 0; i < m_Ember.m_Curves.m_Points.size(); i++)//Overall, r, g, b.
{
for (auto& p : m_Ember.m_Curves.m_Points[i])
vals.push_back(p);
Spline<float> spline(vals);//Will internally sort.
for (glm::length_t j = 0; j < st; j++)
m_Csa[j][i] = spline.Interpolate(j * ONE_OVER_CURVES_LENGTH_M1);
vals.clear();
}
//t.Toc("ComputeCurves");
}

View File

@ -7,6 +7,7 @@
#include "Interpolate.h"
#include "CarToRas.h"
#include "EmberToXml.h"
#include "Spline.h"
/// <summary>
/// Renderer.
@ -157,6 +158,7 @@ private:
void VectorizedLogScale(size_t row, size_t rowEnd);
protected:
//public:
T m_Scale;
T m_PixelsPerUnitX;
T m_PixelsPerUnitY;

View File

@ -198,7 +198,6 @@ public:
bool InFinalAccum();
void* m_ProgressParameter = nullptr;
protected:
bool m_EarlyClip = false;
bool m_YAxisUp = false;

127
Source/Ember/Spline.cpp Normal file
View File

@ -0,0 +1,127 @@
// This is a combination of this:
// https://stackoverflow.com/questions/25379422/b-spline-curves/25379851#25379851
// and this, but modified to operate on a spline with any number of points intead of just >= 4:
//
// Spline.cc
// CubicSplineLib/
//
// Source file for the "CubicSpline" class. This object facilitates natural
// cubic spline interpolation. Once instantiated the
// constructor builds the spline polynomials on the intervals of the (x, y)
// data provided and retains them for later invocation. Parallelized using
// OpenMP.
//
// Copyright (C) Geoffrey Lentner 2015. All rights reserved.
// See LICENCE file. (GPL v2.0)
//
// contact: Geoffrey Lentner, B.S.
// Graduate Student / Researcher
// 102 Natural Science Building
// Department of Physics & Astronomy
// University of Louisville
// Louisville, KY 40292 USA
//
// email: geoffrey.lentner@louisville.edu
//
// updated: 2015-1-19 13:10:30 EST
//
#include "EmberPch.h"
#include "Spline.h"
namespace EmberNs
{
/// <summary>
/// Constructor that takes a vector of x,y points, optionally sorts them
/// and builds the spline values.
/// </summary>
/// <param name="_vals">The vector of x,y points</param>
/// <param name="sorted">True to skip sorting, false to sort.</param>
template<class T>
Spline<T>::Spline(const std::vector<v2T>& _vals, bool sorted)
{
n = int(_vals.size() - 1);
vals = _vals;
// if not suppressed, ensure 'x' elements are in ascending order
if (!sorted)
std::sort(vals.begin(), vals.end(), [&](const v2T & lhs, const v2T & rhs) { return lhs.x < rhs.x; });
BuildSplines();
}
/// <summary>
/// Compute spline values for the passed in points.
/// This only needs to be done once.
/// </summary>
template<class T>
void Spline<T>::BuildSplines()
{
a.resize(n + 1);
b.resize(n + 1);
c.resize(n + 1);
d.resize(n + 1);
std::vector<T> w(n);
std::vector<T> h(n);
std::vector<T> ftt(n + 1);
for (int i = 0; i < n; i++)
{
w[i] = (vals[i + 1].x - vals[i].x);
h[i] = (vals[i + 1].y - vals[i].y) / w[i];
}
ftt[0] = 0;
for (int i = 0; i < n - 1; i++)
ftt[i + 1] = 3 * (h[i + 1] - h[i]) / (w[i + 1] + w[i]);
ftt[n] = 0;
for (int i = 0; i < n; i++)
{
a[i] = (ftt[i + 1] - ftt[i]) / (6 * w[i]);
b[i] = ftt[i] / 2;
c[i] = h[i] - w[i] * (ftt[i + 1] + 2 * ftt[i]) / 6;
d[i] = vals[i].y;
}
}
/// <summary>
/// Wrapper to generate y points on the spline for a vector of passed in points.
/// </summary>
/// <param name="newX">The vector of x points to generate spline points for</param>
/// <returns>The vector of computed spline y points.</returns>
template<class T>
std::vector<T> Spline<T>::Interpolate(const std::vector<T>& newX)
{
std::vector<T> output; output.resize(newX.size());
for (int i = 0; i < newX.size(); i++)
output[i] = Interpolate(newX[i]);
return output;
}
/// <summary>
/// Compute a y point on the spline for a the passed in value of x.
/// </summary>
/// <param name="newX">The x points to compute the spline point for</param>
/// <returns>The computed spline y points.</returns>
template<class T>
T Spline<T>::Interpolate(T newX)
{
ClampRef(newX, vals[0].x, vals[n].x);
int j = 0;
while (j < n && newX > vals[j + 1].x)
j++;
auto xmxj = newX - vals[j].x;
auto output = a[j] * (xmxj * xmxj * xmxj) +
b[j] * (xmxj * xmxj) +
c[j] * xmxj +
d[j];
return output;
}
template EMBER_API class Spline<float>;
}

55
Source/Ember/Spline.h Normal file
View File

@ -0,0 +1,55 @@
// This is a combination of this:
// https://stackoverflow.com/questions/25379422/b-spline-curves/25379851#25379851
// and this, but modified to operate on a spline with any number of points intead of just >= 4:
//
// Spline.h
// CubicSplineLib/
//
// Header file for the "CubicSpline" class. This object facilitates natural
// cubic spline interpolation. Once instantiated the
// constructor builds the spline polynomials on the intervals of the (x, y)
// data provided and retains them for later invocation. Parallelized using
// OpenMP.
//
// Copyright (C) Geoffrey Lentner 2015. All rights reserved.
// See LICENCE file. (GPL v2.0)
//
// contact: Geoffrey Lentner, B.S.
// Graduate Student / Researcher
// 102 Natural Science Building
// Department of Physics & Astronomy
// University of Louisville
// Louisville, KY 40292 USA
//
// email: geoffrey.lentner@louisville.edu
//
// updated: 2015-1-19 13:10:30 EST
//
#pragma once
#include "Utils.h"
namespace EmberNs
{
/// <summary>
/// Class taking passed in x,y points, sorting them, and providing a function
/// to compute and return an interpolated spline curve for any value between the
/// first and last x.
/// Template argument expected to be float.
/// </summary>
template<class T = float>
class EMBER_API Spline
{
public:
Spline(const std::vector<v2T>& _vals, bool sorted = false);
std::vector<T> Interpolate(const std::vector<T>& newX);
T Interpolate(T newX);
private:
void BuildSplines();
std::vector<v2T> vals;
std::vector<T> a, b, c, d;
std::vector<T> c_prime, d_prime;
std::vector<T> k;
int n;
};
}

View File

@ -829,6 +829,34 @@ static inline T NormalizeDeg180(T angle)
return a;
}
/// <summary>
/// Put an angular measurement in degrees into the range of 0 - 360.
/// </summary>
/// <param name="angle">The angle to normalize</param>
/// <returns>The normalized angle in a range of 0 - 360</returns>
template <typename T>
static inline T NormalizeDeg360(T angle)
{
if (angle > 360 || angle < -360)
angle = fmod(angle, T(360));
if (angle < 0)
angle += 360;
return angle;
}
/// <summary>
/// Convert an angle where 0 is up to a trigonometry style angle where 0 is to the right.
/// </summary>
/// <param name="Angle">The angle to convert</param>
/// <returns>The trig equivalent of the angle passed in</returns>
template <typename T>
static inline T ToTrigAngle(T angle)
{
return NormalizeDeg360(90 - angle);
}
/// <summary>
/// Determine whether the passed in string ends with the passed in suffix, case sensitive.
/// </summary>
@ -841,6 +869,18 @@ static bool EndsWith(const std::string& str, const std::string& suffix)
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}
/// <summary>
/// Determine whether the passed in string starts with the passed in prefix, case sensitive.
/// </summary>
/// <param name="str">The string to test</param>
/// <param name="suffix">The string to test for</param>
/// <returns>True if str starts with suffix, else false.</returns>
static bool StartsWith(const std::string& str, const std::string& prefix)
{
return str.size() >= prefix.size() &&
str.compare(0, prefix.size(), prefix) == 0;
}
/// <summary>
/// Return a lower case copy of a string.
/// </summary>

View File

@ -50,6 +50,16 @@ public:
return modf(v, &dummy);
}
/// <summary>
/// Return the fractional part of a real number.
/// </summary>
/// <param name="v">The real number whose fractional part will be returned</param>
/// <returns>The fractional part of the value passed in</returns>
static inline T Fract(T x)
{
return x - T(Floor(x));
}
/// <summary>
/// Unsure.
/// </summary>
@ -191,7 +201,7 @@ public:
/// </summary>
/// <param name="a">The value to hash</param>
/// <returns>The hashed value</returns>
static T Hash(int a)
static inline T Hash(int a)
{
a = (a ^ 61) ^ (a >> 16);
a = a + (a << 3);
@ -201,6 +211,128 @@ public:
return (T)a / std::numeric_limits<int>::max();
}
/// <summary>
/// Hash function gotten from Chaotica, which takes an x,y pair and hashes it.
/// Written by Thomas Ludwig and Tatyana Zabanova.
/// </summary>
/// <param name="x">The x value to hash</param>
/// <param name="y">The y value to hash</param>
/// <param name="seed">The seed to hash with</param>
/// <returns>The hashed value</returns>
static inline T HashShadertoy(T x, T y, T seed)
{
return Fract(std::sin(x * T(12.9898) + y * T(78.233) + seed) * T(43758.5453));
}
/// <summary>
/// For the vibration2 variation.
/// </summary>
/// <returns>T</returns>
static inline T Modulate(T amp, T freq, T x)
{
return amp * std::cos(x * freq * M_2PI);
}
/// <summary>
/// Divide real by complex.
/// </summary>
/// <param name="x">The real number</param>
/// <param name="a">The complex number</param>
/// <returns>x / a</returns>
static v2T RealDivComplex(T x, v2T a)
{
T s = x / Zeps(a.x * a.x + a.y * a.y);
return v2T(a.x * s, -a.y * s);
}
/// <summary>
/// Divide complex by complex.
/// </summary>
/// <param name="x">The first complex number</param>
/// <param name="a">The secondcomplex number</param>
/// <returns>a / b</returns>
static v2T ComplexDivComplex(v2T a, v2T b)
{
T s = T(1.0) / Zeps(b.x * b.x + b.y * b.y);
return v2T(a.x * b.x + a.y * b.y, a.y * b.x - a.x * b.y) * s;
}
/// <summary>
/// Multiple complex by real.
/// </summary>
/// <param name="a">The complex number</param>
/// <param name="x">The real number</param>
/// <returns>a * x</returns>
static v2T ComplexMultReal(v2T a, T x)
{
return v2T(a.x * x, a.y * x);
}
/// <summary>
/// Multiply complex by complex.
/// </summary>
/// <param name="a">The first complex number</param>
/// <param name="b">The second complex number</param>
/// <returns>a * b</returns>
static v2T ComplexMultComplex(v2T a, v2T b)
{
return v2T(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}
/// <summary>
/// Add complex to complex.
/// </summary>
/// <param name="a">The first complex number</param>
/// <param name="b">The second complex number</param>
/// <returns>a + b</returns>
static v2T ComplexPlusComplex(v2T a, v2T b)
{
return v2T(a.x + b.x, a.y + b.y);
}
/// <summary>
/// Add complex to real.
/// </summary>
/// <param name="a">The complex number</param>
/// <param name="x">The real number</param>
/// <returns>a + x</returns>
static v2T ComplexPlusReal(v2T a, T x)
{
return v2T(a.x + x, a.y);
}
/// <summary>
/// Subtract real from complex.
/// </summary>
/// <param name="a">The complex number</param>
/// <param name="x">The real number</param>
/// <returns>a - x</returns>
static v2T ComplexMinusReal(v2T a, T x)
{
return v2T(a.x - x, a.y);
}
/// <summary>
/// Compute the square root of a complex number.
/// </summary>
/// <param name="a">The complex number</param>
/// <returns>sqrt(a)</returns>
static v2T ComplexSqrt(v2T a)
{
T mag = Hypot(a.x, a.y);
return ComplexMultReal(v2T(std::sqrt(mag + a.x), Sign(a.y) * std::sqrt(mag - a.x)), T(0.5) * std::sqrt(T(2.0)));
}
/// <summary>
/// Compute the natural logarithm of a complex number.
/// </summary>
/// <param name="a">The complex number</param>
/// <returns>log(a)</returns>
static v2T ComplexLog(v2T a)
{
return v2T(T(0.5) * std::log(a.x * a.x + a.y * a.y), std::atan2(a.y, a.x));
}
/// <summary>
/// Retrieve information about a piece of shared data by looking
/// up its name.
@ -567,9 +699,25 @@ private:
m_P = InitInts();
m_Grad = InitGrad();
m_Offsets = InitOffsets();
m_P1 = InitP1();
m_Q1 = InitQ1();
m_P2 = InitP2();
m_Q2 = InitQ2();
m_PC = InitPC();
m_QC = InitQC();
m_PS = InitPS();
m_QS = InitQS();
m_GlobalMap["NOISE_INDEX"] = make_pair(m_PFloats.data(), m_PFloats.size());
m_GlobalMap["NOISE_POINTS"] = make_pair(static_cast<T*>(&(m_Grad[0].x)), SizeOf(m_Grad) / sizeof(T));
m_GlobalMap["OFFSETS"] = make_pair(static_cast<T*>(&(m_Offsets[0].x)), SizeOf(m_Offsets) / sizeof(T));
m_GlobalMap["P1"] = make_pair(m_P1.data(), m_P1.size());
m_GlobalMap["Q1"] = make_pair(m_Q1.data(), m_Q1.size());
m_GlobalMap["P2"] = make_pair(m_P2.data(), m_P2.size());
m_GlobalMap["Q2"] = make_pair(m_Q2.data(), m_Q2.size());
m_GlobalMap["PC"] = make_pair(m_PC.data(), m_PC.size());
m_GlobalMap["QC"] = make_pair(m_QC.data(), m_QC.size());
m_GlobalMap["PS"] = make_pair(m_PS.data(), m_PS.size());
m_GlobalMap["QS"] = make_pair(m_QS.data(), m_QS.size());
}
/// <summary>
@ -993,8 +1141,179 @@ private:
return g;
}
/// <summary>
/// Initializes the P1 vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitP1()
{
std::vector<T> v =
{
T(-1.4258509801366645672e+11),
T(6.6781041261492395835e+09 ),
T(-1.1548696764841276794e+08),
T(9.8062904098958257677e+05 ),
T(-4.4615792982775076130e+03),
T(1.0650724020080236441e+01 ),
T(-1.0767857011487300348e-02)
};
return v;
}
/// <summary>
/// Initializes the Q1 vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitQ1()
{
std::vector<T> v =
{
T(4.1868604460820175290e+12),
T(4.2091902282580133541e+10),
T(2.0228375140097033958e+08),
T(5.9117614494174794095e+05),
T(1.0742272239517380498e+03),
T(1.0),
T(0.0)
};
return v;
}
/// <summary>
/// Initializes the P2 vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitP2()
{
std::vector<T> v =
{
T(-1.7527881995806511112e+16),
T(1.6608531731299018674e+15 ),
T(-3.6658018905416665164e+13),
T(3.5580665670910619166e+11 ),
T(-1.8113931269860667829e+09),
T(5.0793266148011179143e+06 ),
T(-7.5023342220781607561e+03),
T(4.6179191852758252278e+00)
};
return v;
}
/// <summary>
/// Initializes the Q2 vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitQ2()
{
std::vector<T> v =
{
T(1.7253905888447681194e+18),
T(1.7128800897135812012e+16),
T(8.4899346165481429307e+13),
T(2.7622777286244082666e+11),
T(6.4872502899596389593e+08),
T(1.1267125065029138050e+06),
T(1.3886978985861357615e+03),
T(1.0)
};
return v;
}
/// <summary>
/// Initializes the PC vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitPC()
{
std::vector<T> v =
{
T(-4.4357578167941278571e+06),
T(-9.9422465050776411957e+06),
T(-6.6033732483649391093e+06),
T(-1.5235293511811373833e+06),
T(-1.0982405543459346727e+05),
T(-1.6116166443246101165e+03),
T(0.0)
};
return v;
}
/// <summary>
/// Initializes the QC vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitQC()
{
std::vector<T> v =
{
T(-4.4357578167941278568e+06),
T(-9.9341243899345856590e+06),
T(-6.5853394797230870728e+06),
T(-1.5118095066341608816e+06),
T(-1.0726385991103820119e+05),
T(-1.4550094401904961825e+03),
T(1.0)
};
return v;
}
/// <summary>
/// Initializes the PS vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitPS()
{
std::vector<T> v =
{
T(3.3220913409857223519e+04),
T(8.5145160675335701966e+04),
T(6.6178836581270835179e+04),
T(1.8494262873223866797e+04),
T(1.7063754290207680021e+03),
T(3.5265133846636032186e+01),
T(0.0)
};
return v;
}
/// <summary>
/// Initializes the QS vector used in J1().
/// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL.
/// </summary>
/// <returns>A copy of the locally declared vector</returns>
std::vector<T> InitQS()
{
std::vector<T> v =
{
T(7.0871281941028743574e+05),
T(1.8194580422439972989e+06),
T(1.4194606696037208929e+06),
T(4.0029443582266975117e+05),
T(3.7890229745772202641e+04),
T(8.6383677696049909675e+02),
T(1.0)
};
return v;
}
std::vector<int> m_P;
std::vector<T> m_PFloats;
std::vector<T> m_P1;
std::vector<T> m_Q1;
std::vector<T> m_P2;
std::vector<T> m_Q2;
std::vector<T> m_PC;
std::vector<T> m_QC;
std::vector<T> m_PS;
std::vector<T> m_QS;
std::vector<v2T> m_Offsets;
std::vector<v3T> m_Grad;
std::unordered_map<string, pair<const T*, size_t>> m_GlobalMap;

View File

@ -47,6 +47,11 @@ enum class eVariationAssignType : et
enum class eVariationId : et
{
VAR_ARCH,
VAR_ARCSECH,
VAR_ARCSECH2,
VAR_ARCSINH,
VAR_ARCTANH,
VAR_ASTERIA,
//VAR_ARCSINH,
//VAR_ARCTANH,
VAR_AUGER ,
@ -62,6 +67,7 @@ enum class eVariationId : et
VAR_BLOB ,
VAR_BLOB2 ,
VAR_BLOB3D ,
VAR_BLOCK ,
VAR_BLOCKY ,
VAR_BLUR ,
VAR_BLUR_CIRCLE ,
@ -81,11 +87,13 @@ enum class eVariationId : et
VAR_BUBBLET3D ,
VAR_BUTTERFLY ,
VAR_BWRAPS ,
VAR_BWRAPS_RAND ,
VAR_CARDIOID ,
VAR_CELL ,
VAR_CHECKS ,
VAR_CIRCLEBLUR ,
VAR_CIRCLECROP,
VAR_CIRCLECROP2,
VAR_CIRCLELINEAR,
VAR_CIRCLERAND,
VAR_CIRCLESPLIT,
@ -104,12 +112,14 @@ enum class eVariationId : et
VAR_COSQ,
VAR_COT ,
VAR_COTH ,
VAR_COTH_SPIRAL,
VAR_COTHQ ,
VAR_COTQ ,
VAR_CPOW ,
VAR_CPOW2 ,
VAR_CPOW3 ,
VAR_CRACKLE ,
VAR_CRACKLE2 ,
VAR_CRESCENTS ,
VAR_CROB ,
VAR_CROP ,
@ -130,10 +140,21 @@ enum class eVariationId : et
VAR_CYLINDER2,
VAR_DELTA_A ,
VAR_DEPTH,
VAR_DEPTH_BLUR,
VAR_DEPTH_BLUR2,
VAR_DEPTH_GAUSSIAN,
VAR_DEPTH_GAUSSIAN2,
VAR_DEPTH_NGON,
VAR_DEPTH_NGON2,
VAR_DEPTH_SINE,
VAR_DEPTH_SINE2,
VAR_DIAMOND ,
VAR_DISC ,
VAR_DISC2 ,
VAR_DISC3D ,
VAR_DRAGONFIRE,
VAR_DUST ,
VAR_D_SPHERICAL ,
VAR_ECLIPSE ,
VAR_ECOLLIDE ,
VAR_EDISC ,
@ -151,7 +172,9 @@ enum class eVariationId : et
VAR_ESTIQ,
VAR_ESWIRL ,
VAR_EX ,
VAR_EXCINIS ,
VAR_EXP ,
VAR_EXP2 ,
VAR_EXPO ,
VAR_EXPONENTIAL ,
VAR_EXTRUDE ,
@ -168,20 +191,27 @@ enum class eVariationId : et
VAR_FISHEYE ,
VAR_FLATTEN ,
VAR_FLIP_CIRCLE ,
VAR_FLIP_X ,
VAR_FLIP_Y ,
VAR_FLOWER ,
VAR_FLOWER_DB ,
VAR_FLUX ,
VAR_FOCI ,
VAR_FOCI3D ,
VAR_FOCI_P ,
VAR_FOURTH,
VAR_FUNNEL ,
VAR_GAMMA ,
VAR_GAUSSIAN,
VAR_GAUSSIAN_BLUR,
VAR_GDOFFS,
VAR_GLYNNIA ,
VAR_GLYNNIA2 ,
VAR_GLYNNSIM1 ,
VAR_GLYNNSIM2 ,
VAR_GLYNNSIM3 ,
VAR_GLYNNSIM4 ,
VAR_GLYNNSIM5 ,
VAR_GRIDOUT ,
VAR_HANDKERCHIEF,
VAR_HEART ,
@ -189,15 +219,19 @@ enum class eVariationId : et
VAR_HELICOID,
VAR_HELIX,
VAR_HEMISPHERE ,
VAR_HENON ,
VAR_HEXAPLAY3D ,
VAR_HEXCROP ,
VAR_HEXES ,
VAR_HEXNIX3D ,
VAR_HEX_RAND,
VAR_HEX_TRUCHET,
VAR_HO ,
VAR_HOLE ,
VAR_HORSESHOE ,
VAR_HYPERBOLIC ,
VAR_HYPERCROP ,
VAR_HYPERSHIFT ,
VAR_HYPERSHIFT2 ,
VAR_HYPERTILE ,
VAR_HYPERTILE1 ,
@ -222,8 +256,10 @@ enum class eVariationId : et
VAR_JULIAQ ,
VAR_JULIASCOPE ,
VAR_KALEIDOSCOPE,
VAR_LAZY_TRAVIS ,
VAR_LAZYJESS ,
VAR_LAZYSUSAN ,
VAR_LAZY_TRAVIS ,
VAR_LENS ,
VAR_LINE ,
VAR_LINEAR ,
VAR_LINEAR_T ,
@ -239,6 +275,7 @@ enum class eVariationId : et
VAR_LOONIE2 ,
VAR_LOONIE3 ,
VAR_LOONIE3D ,
VAR_LOZI ,
VAR_MASK ,
VAR_MCARPET ,
VAR_MIRROR_X,
@ -249,6 +286,8 @@ enum class eVariationId : et
VAR_MOBIUS_STRIP,
VAR_MOBIUSN ,
VAR_MODULUS ,
VAR_MODULUSX ,
VAR_MODULUSY ,
VAR_MURL ,
VAR_MURL2 ,
VAR_NBLUR ,
@ -259,6 +298,7 @@ enum class eVariationId : et
VAR_OCTAPOL ,
VAR_ORTHO ,
VAR_OSCILLOSCOPE,
VAR_OSCILLOSCOPE2,
VAR_OVOID ,
VAR_OVOID3D ,
VAR_PANORAMA1 ,
@ -273,6 +313,7 @@ enum class eVariationId : et
VAR_PIXEL_FLOW ,
VAR_POINCARE ,
VAR_POINCARE3D ,
VAR_POINT_SYMMETRY,
VAR_POLAR ,
VAR_POLAR2 ,
VAR_POLYNOMIAL ,
@ -282,10 +323,13 @@ enum class eVariationId : et
VAR_POW_BLOCK ,
VAR_POWER ,
VAR_PRESSURE_WAVE,
VAR_PROJECTIVE ,
VAR_PROSE3D ,
VAR_PSPHERE ,
VAR_PULSE ,
VAR_Q_ODE,
VAR_RADIAL_BLUR ,
//VAR_RADIAL_GAUSSIAN,
VAR_RAND_CUBES ,
VAR_RATIONAL3 ,
VAR_RAYS ,
@ -298,12 +342,14 @@ enum class eVariationId : et
VAR_RINGS2 ,
VAR_RIPPLE ,
VAR_RIPPLED ,
VAR_ROTATE,
VAR_ROTATE_X,
VAR_ROTATE_Y,
VAR_ROTATE_Z,
VAR_ROUNDSPHER ,
VAR_ROUNDSPHER3D,
VAR_SCRY ,
VAR_SCRY2 ,
VAR_SCRY3D ,
VAR_SEC ,
VAR_SECANT2 ,
@ -311,6 +357,7 @@ enum class eVariationId : et
VAR_SECHQ,
VAR_SECQ,
VAR_SEPARATION ,
VAR_SHIFT ,
VAR_SHRED_RAD ,
VAR_SHRED_LIN ,
VAR_SIGMOID ,
@ -323,7 +370,9 @@ enum class eVariationId : et
VAR_SINUS_GRID ,
VAR_SINUSOIDAL ,
VAR_SINUSOIDAL3D,
VAR_SMARTSHAPE,
//VAR_SMARTCROP ,
VAR_SPHER ,
VAR_SPHEREBLUR ,
VAR_SPHERICAL ,
VAR_SPHERICAL3D ,
@ -338,34 +387,48 @@ enum class eVariationId : et
VAR_SPLITS ,
VAR_SPLITS3D ,
VAR_SQUARE ,
VAR_SQUARES ,
VAR_SQUARE3D ,
VAR_SQUARIZE ,
VAR_SQUIRREL ,
VAR_SQUISH,
VAR_SSCHECKS ,
VAR_STARBLUR ,
VAR_STARBLUR2 ,
VAR_STRIPES ,
VAR_STWIN ,
VAR_SUPER_SHAPE ,
VAR_SUPER_SHAPE3D,
VAR_SVF ,
VAR_SWIRL ,
VAR_SWIRL3 ,
VAR_SWIRL3R ,
VAR_SYNTH ,
VAR_TAN ,
VAR_TANCOS,
VAR_TANGENT ,
VAR_TANH ,
VAR_TANHQ ,
VAR_TANH_SPIRAL ,
VAR_TANQ ,
VAR_TARGET ,
VAR_TARGET0 ,
VAR_TARGET2 ,
VAR_TAURUS ,
VAR_TILE_HLP,
VAR_TILE_LOG,
VAR_TRADE ,
VAR_TRUCHET,
VAR_TRUCHET_FILL,
VAR_TRUCHET_GLYPH,
VAR_TRUCHET_INV,
VAR_TRUCHET_KNOT,
VAR_TWINTRIAN ,
VAR_TWO_FACE ,
VAR_UNICORNGALOSHEN,
VAR_UNPOLAR ,
VAR_VIBRATION,
VAR_VIBRATION2,
VAR_VORON,
VAR_W ,
VAR_WAFFLE,
@ -392,6 +455,11 @@ enum class eVariationId : et
VAR_ZTRANSLATE,
VAR_PRE_ARCH,
VAR_PRE_ARCSECH,
VAR_PRE_ARCSECH2,
VAR_PRE_ARCSINH,
VAR_PRE_ARCTANH,
VAR_PRE_ASTERIA,
//VAR_PRE_ARCSINH,
//VAR_PRE_ARCTANH,
VAR_PRE_AUGER,
@ -407,6 +475,7 @@ enum class eVariationId : et
VAR_PRE_BLOB,
VAR_PRE_BLOB2,
VAR_PRE_BLOB3D,
VAR_PRE_BLOCK,
VAR_PRE_BLOCKY,
VAR_PRE_BLUR,
VAR_PRE_BLUR_CIRCLE,
@ -426,11 +495,13 @@ enum class eVariationId : et
VAR_PRE_BUBBLET3D,
VAR_PRE_BUTTERFLY,
VAR_PRE_BWRAPS,
VAR_PRE_BWRAPS_RAND,
VAR_PRE_CARDIOID,
VAR_PRE_CELL,
VAR_PRE_CHECKS,
VAR_PRE_CIRCLEBLUR,
VAR_PRE_CIRCLECROP,
VAR_PRE_CIRCLECROP2,
VAR_PRE_CIRCLELINEAR,
VAR_PRE_CIRCLERAND,
VAR_PRE_CIRCLESPLIT,
@ -449,12 +520,14 @@ enum class eVariationId : et
VAR_PRE_COSQ,
VAR_PRE_COT,
VAR_PRE_COTH,
VAR_PRE_COTH_SPIRAL,
VAR_PRE_COTHQ,
VAR_PRE_COTQ,
VAR_PRE_CPOW,
VAR_PRE_CPOW2,
VAR_PRE_CPOW3,
VAR_PRE_CRACKLE,
VAR_PRE_CRACKLE2,
VAR_PRE_CRESCENTS,
VAR_PRE_CROB,
VAR_PRE_CROP,
@ -475,10 +548,21 @@ enum class eVariationId : et
VAR_PRE_CYLINDER2,
VAR_PRE_DELTA_A,
VAR_PRE_DEPTH,
VAR_PRE_DEPTH_BLUR,
VAR_PRE_DEPTH_BLUR2,
VAR_PRE_DEPTH_GAUSSIAN,
VAR_PRE_DEPTH_GAUSSIAN2,
VAR_PRE_DEPTH_NGON,
VAR_PRE_DEPTH_NGON2,
VAR_PRE_DEPTH_SINE,
VAR_PRE_DEPTH_SINE2,
VAR_PRE_DIAMOND,
VAR_PRE_DISC,
VAR_PRE_DISC2,
VAR_PRE_DISC3D,
VAR_PRE_DRAGONFIRE,
VAR_PRE_DUST,
VAR_PRE_D_SPHERICAL,
VAR_PRE_ECLIPSE,
VAR_PRE_ECOLLIDE,
VAR_PRE_EDISC,
@ -496,7 +580,9 @@ enum class eVariationId : et
VAR_PRE_ESTIQ,
VAR_PRE_ESWIRL,
VAR_PRE_EX,
VAR_PRE_EXCINIS,
VAR_PRE_EXP,
VAR_PRE_EXP2,
VAR_PRE_EXPO,
VAR_PRE_EXPONENTIAL,
VAR_PRE_EXTRUDE,
@ -513,20 +599,27 @@ enum class eVariationId : et
VAR_PRE_FISHEYE,
VAR_PRE_FLATTEN,
VAR_PRE_FLIP_CIRCLE,
VAR_PRE_FLIP_X,
VAR_PRE_FLIP_Y,
VAR_PRE_FLOWER,
VAR_PRE_FLOWER_DB,
VAR_PRE_FLUX,
VAR_PRE_FOCI,
VAR_PRE_FOCI3D,
VAR_PRE_FOCI_P,
VAR_PRE_FOURTH,
VAR_PRE_FUNNEL,
VAR_PRE_GAMMA,
VAR_PRE_GAUSSIAN,
VAR_PRE_GAUSSIAN_BLUR,
VAR_PRE_GDOFFS,
VAR_PRE_GLYNNIA,
VAR_PRE_GLYNNIA2,
VAR_PRE_GLYNNSIM1,
VAR_PRE_GLYNNSIM2,
VAR_PRE_GLYNNSIM3,
VAR_PRE_GLYNNSIM4,
VAR_PRE_GLYNNSIM5,
VAR_PRE_GRIDOUT,
VAR_PRE_HANDKERCHIEF,
VAR_PRE_HEART,
@ -534,15 +627,19 @@ enum class eVariationId : et
VAR_PRE_HELICOID,
VAR_PRE_HELIX,
VAR_PRE_HEMISPHERE,
VAR_PRE_HENON,
VAR_PRE_HEXAPLAY3D,
VAR_PRE_HEXCROP,
VAR_PRE_HEXES,
VAR_PRE_HEXNIX3D,
VAR_PRE_HEX_RAND,
VAR_PRE_HEX_TRUCHET,
VAR_PRE_HO,
VAR_PRE_HOLE,
VAR_PRE_HORSESHOE,
VAR_PRE_HYPERBOLIC,
VAR_PRE_HYPERCROP,
VAR_PRE_HYPERSHIFT,
VAR_PRE_HYPERSHIFT2,
VAR_PRE_HYPERTILE,
VAR_PRE_HYPERTILE1,
@ -567,8 +664,10 @@ enum class eVariationId : et
VAR_PRE_JULIAQ,
VAR_PRE_JULIASCOPE,
VAR_PRE_KALEIDOSCOPE,
VAR_PRE_LAZY_TRAVIS,
VAR_PRE_LAZYJESS,
VAR_PRE_LAZYSUSAN,
VAR_PRE_LAZY_TRAVIS,
VAR_PRE_LENS,
VAR_PRE_LINE,
VAR_PRE_LINEAR,
VAR_PRE_LINEAR_T,
@ -584,6 +683,7 @@ enum class eVariationId : et
VAR_PRE_LOONIE2,
VAR_PRE_LOONIE3,
VAR_PRE_LOONIE3D,
VAR_PRE_LOZI,
VAR_PRE_MASK,
VAR_PRE_MCARPET,
VAR_PRE_MIRROR_X,
@ -594,6 +694,8 @@ enum class eVariationId : et
VAR_PRE_MOBIUS_STRIP,
VAR_PRE_MOBIUSN,
VAR_PRE_MODULUS,
VAR_PRE_MODULUSX,
VAR_PRE_MODULUSY,
VAR_PRE_MURL,
VAR_PRE_MURL2,
VAR_PRE_NBLUR,
@ -604,6 +706,7 @@ enum class eVariationId : et
VAR_PRE_OCTAPOL,
VAR_PRE_ORTHO,
VAR_PRE_OSCILLOSCOPE,
VAR_PRE_OSCILLOSCOPE2,
VAR_PRE_OVOID,
VAR_PRE_OVOID3D,
VAR_PRE_PANORAMA1,
@ -618,6 +721,7 @@ enum class eVariationId : et
VAR_PRE_PIXEL_FLOW,
VAR_PRE_POINCARE,
VAR_PRE_POINCARE3D,
VAR_PRE_POINT_SYMMETRY,
VAR_PRE_POLAR,
VAR_PRE_POLAR2,
VAR_PRE_POLYNOMIAL,
@ -627,8 +731,10 @@ enum class eVariationId : et
VAR_PRE_POW_BLOCK,
VAR_PRE_POWER,
VAR_PRE_PRESSURE_WAVE,
VAR_PRE_PROJECTIVE,
VAR_PRE_PROSE3D,
VAR_PRE_PSPHERE,
VAR_PRE_PULSE,
VAR_PRE_Q_ODE,
VAR_PRE_RADIAL_BLUR,
VAR_PRE_RAND_CUBES,
@ -643,12 +749,14 @@ enum class eVariationId : et
VAR_PRE_RINGS2,
VAR_PRE_RIPPLE,
VAR_PRE_RIPPLED,
VAR_PRE_ROTATE,
VAR_PRE_ROTATE_X,
VAR_PRE_ROTATE_Y,
VAR_PRE_ROTATE_Z,
VAR_PRE_ROUNDSPHER,
VAR_PRE_ROUNDSPHER3D,
VAR_PRE_SCRY,
VAR_PRE_SCRY2,
VAR_PRE_SCRY3D,
VAR_PRE_SEC,
VAR_PRE_SECANT2,
@ -656,6 +764,7 @@ enum class eVariationId : et
VAR_PRE_SECHQ,
VAR_PRE_SECQ,
VAR_PRE_SEPARATION,
VAR_PRE_SHIFT,
VAR_PRE_SHRED_RAD,
VAR_PRE_SHRED_LIN,
VAR_PRE_SIGMOID,
@ -668,7 +777,9 @@ enum class eVariationId : et
VAR_PRE_SINUS_GRID,
VAR_PRE_SINUSOIDAL,
VAR_PRE_SINUSOIDAL3D,
VAR_PRE_SMARTSHAPE,
//VAR_PRE_SMARTCROP,
VAR_PRE_SPHER,
VAR_PRE_SPHEREBLUR,
VAR_PRE_SPHERICAL,
VAR_PRE_SPHERICAL3D,
@ -683,34 +794,48 @@ enum class eVariationId : et
VAR_PRE_SPLITS,
VAR_PRE_SPLITS3D,
VAR_PRE_SQUARE,
VAR_PRE_SQUARES,
VAR_PRE_SQUARE3D,
VAR_PRE_SQUARIZE,
VAR_PRE_SQUIRREL,
VAR_PRE_SQUISH,
VAR_PRE_SSCHECKS,
VAR_PRE_STARBLUR,
VAR_PRE_STARBLUR2,
VAR_PRE_STRIPES,
VAR_PRE_STWIN,
VAR_PRE_SUPER_SHAPE,
VAR_PRE_SUPER_SHAPE3D,
VAR_PRE_SVF,
VAR_PRE_SWIRL,
VAR_PRE_SWIRL3,
VAR_PRE_SWIRL3R,
VAR_PRE_SYNTH,
VAR_PRE_TAN,
VAR_PRE_TANCOS,
VAR_PRE_TANGENT,
VAR_PRE_TANH,
VAR_PRE_TANHQ,
VAR_PRE_TANH_SPIRAL,
VAR_PRE_TANQ,
VAR_PRE_TARGET,
VAR_PRE_TARGET0,
VAR_PRE_TARGET2,
VAR_PRE_TAURUS,
VAR_PRE_TILE_HLP,
VAR_PRE_TILE_LOG,
VAR_PRE_TRADE,
VAR_PRE_TRUCHET,
VAR_PRE_TRUCHET_FILL,
VAR_PRE_TRUCHET_GLYPH,
VAR_PRE_TRUCHET_INV,
VAR_PRE_TRUCHET_KNOT,
VAR_PRE_TWINTRIAN,
VAR_PRE_TWO_FACE,
VAR_PRE_UNICORNGALOSHEN,
VAR_PRE_UNPOLAR,
VAR_PRE_VIBRATION,
VAR_PRE_VIBRATION2,
VAR_PRE_VORON,
VAR_PRE_W,
VAR_PRE_WAFFLE,
@ -737,6 +862,11 @@ enum class eVariationId : et
VAR_PRE_ZTRANSLATE,
VAR_POST_ARCH,
VAR_POST_ARCSECH,
VAR_POST_ARCSECH2,
VAR_POST_ARCSINH,
VAR_POST_ARCTANH,
VAR_POST_ASTERIA,
//VAR_POST_ARCSINH,
//VAR_POST_ARCTANH,
VAR_POST_AUGER,
@ -752,6 +882,7 @@ enum class eVariationId : et
VAR_POST_BLOB,
VAR_POST_BLOB2,
VAR_POST_BLOB3D,
VAR_POST_BLOCK,
VAR_POST_BLOCKY,
VAR_POST_BLUR,
VAR_POST_BLUR_CIRCLE,
@ -771,11 +902,13 @@ enum class eVariationId : et
VAR_POST_BUBBLET3D,
VAR_POST_BUTTERFLY,
VAR_POST_BWRAPS,
VAR_POST_BWRAPS_RAND,
VAR_POST_CARDIOID,
VAR_POST_CELL,
VAR_POST_CHECKS,
VAR_POST_CIRCLEBLUR,
VAR_POST_CIRCLECROP,
VAR_POST_CIRCLECROP2,
VAR_POST_CIRCLELINEAR,
VAR_POST_CIRCLERAND,
VAR_POST_CIRCLESPLIT,
@ -794,12 +927,14 @@ enum class eVariationId : et
VAR_POST_COSQ,
VAR_POST_COT,
VAR_POST_COTH,
VAR_POST_COTH_SPIRAL,
VAR_POST_COTHQ,
VAR_POST_COTQ,
VAR_POST_CPOW,
VAR_POST_CPOW2,
VAR_POST_CPOW3,
VAR_POST_CRACKLE,
VAR_POST_CRACKLE2,
VAR_POST_CRESCENTS,
VAR_POST_CROB,
VAR_POST_CROP,
@ -820,10 +955,21 @@ enum class eVariationId : et
VAR_POST_CYLINDER2,
VAR_POST_DELTA_A,
VAR_POST_DEPTH,
VAR_POST_DEPTH_BLUR,
VAR_POST_DEPTH_BLUR2,
VAR_POST_DEPTH_GAUSSIAN,
VAR_POST_DEPTH_GAUSSIAN2,
VAR_POST_DEPTH_NGON,
VAR_POST_DEPTH_NGON2,
VAR_POST_DEPTH_SINE,
VAR_POST_DEPTH_SINE2,
VAR_POST_DIAMOND,
VAR_POST_DISC,
VAR_POST_DISC2,
VAR_POST_DISC3D,
VAR_POST_DRAGONFIRE,
VAR_POST_DUST,
VAR_POST_D_SPHERICAL,
VAR_POST_ECLIPSE,
VAR_POST_ECOLLIDE,
VAR_POST_EDISC,
@ -841,7 +987,9 @@ enum class eVariationId : et
VAR_POST_ESTIQ,
VAR_POST_ESWIRL,
VAR_POST_EX,
VAR_POST_EXCINIS,
VAR_POST_EXP,
VAR_POST_EXP2,
VAR_POST_EXPO,
VAR_POST_EXPONENTIAL,
VAR_POST_EXTRUDE,
@ -858,20 +1006,27 @@ enum class eVariationId : et
VAR_POST_FISHEYE,
VAR_POST_FLATTEN,
VAR_POST_FLIP_CIRCLE,
VAR_POST_FLIP_X,
VAR_POST_FLIP_Y,
VAR_POST_FLOWER,
VAR_POST_FLOWER_DB,
VAR_POST_FLUX,
VAR_POST_FOCI,
VAR_POST_FOCI3D,
VAR_POST_FOCI_P,
VAR_POST_FOURTH,
VAR_POST_FUNNEL,
VAR_POST_GAMMA,
VAR_POST_GAUSSIAN,
VAR_POST_GAUSSIAN_BLUR,
VAR_POST_GDOFFS,
VAR_POST_GLYNNIA,
VAR_POST_GLYNNIA2,
VAR_POST_GLYNNSIM1,
VAR_POST_GLYNNSIM2,
VAR_POST_GLYNNSIM3,
VAR_POST_GLYNNSIM4,
VAR_POST_GLYNNSIM5,
VAR_POST_GRIDOUT,
VAR_POST_HANDKERCHIEF,
VAR_POST_HEART,
@ -879,15 +1034,19 @@ enum class eVariationId : et
VAR_POST_HELICOID,
VAR_POST_HELIX,
VAR_POST_HEMISPHERE,
VAR_POST_HENON,
VAR_POST_HEXAPLAY3D,
VAR_POST_HEXCROP,
VAR_POST_HEXES,
VAR_POST_HEXNIX3D,
VAR_POST_HEX_RAND,
VAR_POST_HEX_TRUCHET,
VAR_POST_HO,
VAR_POST_HOLE,
VAR_POST_HORSESHOE,
VAR_POST_HYPERBOLIC,
VAR_POST_HYPERCROP,
VAR_POST_HYPERSHIFT,
VAR_POST_HYPERSHIFT2,
VAR_POST_HYPERTILE,
VAR_POST_HYPERTILE1,
@ -912,8 +1071,10 @@ enum class eVariationId : et
VAR_POST_JULIAQ,
VAR_POST_JULIASCOPE,
VAR_POST_KALEIDOSCOPE,
VAR_POST_LAZY_TRAVIS,
VAR_POST_LAZYJESS,
VAR_POST_LAZYSUSAN,
VAR_POST_LAZY_TRAVIS,
VAR_POST_LENS,
VAR_POST_LINE,
VAR_POST_LINEAR,
VAR_POST_LINEAR_T,
@ -929,6 +1090,7 @@ enum class eVariationId : et
VAR_POST_LOONIE2,
VAR_POST_LOONIE3,
VAR_POST_LOONIE3D,
VAR_POST_LOZI,
VAR_POST_MASK,
VAR_POST_MCARPET,
VAR_POST_MIRROR_X,
@ -939,6 +1101,8 @@ enum class eVariationId : et
VAR_POST_MOBIUS_STRIP,
VAR_POST_MOBIUSN,
VAR_POST_MODULUS,
VAR_POST_MODULUSX,
VAR_POST_MODULUSY,
VAR_POST_MURL,
VAR_POST_MURL2,
VAR_POST_NBLUR,
@ -949,6 +1113,7 @@ enum class eVariationId : et
VAR_POST_OCTAPOL,
VAR_POST_ORTHO,
VAR_POST_OSCILLOSCOPE,
VAR_POST_OSCILLOSCOPE2,
VAR_POST_OVOID,
VAR_POST_OVOID3D,
VAR_POST_PANORAMA1,
@ -963,6 +1128,7 @@ enum class eVariationId : et
VAR_POST_PIXEL_FLOW,
VAR_POST_POINCARE,
VAR_POST_POINCARE3D,
VAR_POST_POINT_SYMMETRY,
VAR_POST_POLAR,
VAR_POST_POLAR2,
VAR_POST_POLYNOMIAL,
@ -972,8 +1138,10 @@ enum class eVariationId : et
VAR_POST_POW_BLOCK,
VAR_POST_POWER,
VAR_POST_PRESSURE_WAVE,
VAR_POST_PROJECTIVE,
VAR_POST_PROSE3D,
VAR_POST_PSPHERE,
VAR_POST_PULSE,
VAR_POST_Q_ODE,
VAR_POST_RADIAL_BLUR,
VAR_POST_RAND_CUBES,
@ -988,12 +1156,14 @@ enum class eVariationId : et
VAR_POST_RINGS2,
VAR_POST_RIPPLE,
VAR_POST_RIPPLED,
VAR_POST_ROTATE,
VAR_POST_ROTATE_X,
VAR_POST_ROTATE_Y,
VAR_POST_ROTATE_Z,
VAR_POST_ROUNDSPHER,
VAR_POST_ROUNDSPHER3D,
VAR_POST_SCRY,
VAR_POST_SCRY2,
VAR_POST_SCRY3D,
VAR_POST_SEC,
VAR_POST_SECANT2,
@ -1001,6 +1171,7 @@ enum class eVariationId : et
VAR_POST_SECHQ,
VAR_POST_SECQ,
VAR_POST_SEPARATION,
VAR_POST_SHIFT,
VAR_POST_SHRED_RAD,
VAR_POST_SHRED_LIN,
VAR_POST_SIGMOID,
@ -1013,7 +1184,9 @@ enum class eVariationId : et
VAR_POST_SINUS_GRID,
VAR_POST_SINUSOIDAL,
VAR_POST_SINUSOIDAL3D,
VAR_POST_SMARTSHAPE,
VAR_POST_SMARTCROP,
VAR_POST_SPHER,
VAR_POST_SPHEREBLUR,
VAR_POST_SPHERICAL,
VAR_POST_SPHERICAL3D,
@ -1028,34 +1201,48 @@ enum class eVariationId : et
VAR_POST_SPLITS,
VAR_POST_SPLITS3D,
VAR_POST_SQUARE,
VAR_POST_SQUARES,
VAR_POST_SQUARE3D,
VAR_POST_SQUARIZE,
VAR_POST_SQUIRREL,
VAR_POST_SQUISH,
VAR_POST_SSCHECKS,
VAR_POST_STARBLUR,
VAR_POST_STARBLUR2,
VAR_POST_STRIPES,
VAR_POST_STWIN,
VAR_POST_SUPER_SHAPE,
VAR_POST_SUPER_SHAPE3D,
VAR_POST_SVF,
VAR_POST_SWIRL,
VAR_POST_SWIRL3,
VAR_POST_SWIRL3R,
VAR_POST_SYNTH,
VAR_POST_TAN,
VAR_POST_TANCOS,
VAR_POST_TANGENT,
VAR_POST_TANH,
VAR_POST_TANHQ,
VAR_POST_TANH_SPIRAL,
VAR_POST_TANQ,
VAR_POST_TARGET,
VAR_POST_TARGET0,
VAR_POST_TARGET2,
VAR_POST_TAURUS,
VAR_POST_TILE_HLP,
VAR_POST_TILE_LOG,
VAR_POST_TRADE,
VAR_POST_TRUCHET,
VAR_POST_TRUCHET_FILL,
VAR_POST_TRUCHET_GLYPH,
VAR_POST_TRUCHET_INV,
VAR_POST_TRUCHET_KNOT,
VAR_POST_TWINTRIAN,
VAR_POST_TWO_FACE,
VAR_POST_UNICORNGALOSHEN,
VAR_POST_UNPOLAR,
VAR_POST_VIBRATION,
VAR_POST_VIBRATION2,
VAR_POST_VORON,
VAR_POST_W,
VAR_POST_WAFFLE,

View File

@ -27,6 +27,8 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Sinusoidal)
ADDPREPOSTREGVAR(Spherical)
ADDPREPOSTREGVAR(Swirl)
ADDPREPOSTREGVAR(Swirl3)
ADDPREPOSTREGVAR(Swirl3r)
ADDPREPOSTREGVAR(Horseshoe)
ADDPREPOSTREGVAR(Polar)
ADDPREPOSTREGVAR(Handkerchief)
@ -59,6 +61,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(JuliaScope)
ADDPREPOSTREGVAR(Blur)
ADDPREPOSTREGVAR(GaussianBlur)
ADDPREPOSTREGVAR(Gaussian)
ADDPREPOSTREGVAR(RadialBlur)
ADDPREPOSTREGVAR(Pie)
ADDPREPOSTREGVAR(Ngon)
@ -78,6 +81,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Disc2)
ADDPREPOSTREGVAR(SuperShape)
ADDPREPOSTREGVAR(Flower)
ADDPREPOSTREGVAR(FlowerDb)
ADDPREPOSTREGVAR(Conic)
ADDPREPOSTREGVAR(Parabola)
ADDPREPOSTREGVAR(Bent2)
@ -95,9 +99,11 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Loonie)
ADDPREPOSTREGVAR(Modulus)
ADDPREPOSTREGVAR(Oscilloscope)
ADDPREPOSTREGVAR(Oscilloscope2)
ADDPREPOSTREGVAR(Polar2)
ADDPREPOSTREGVAR(Popcorn2)
ADDPREPOSTREGVAR(Scry)
ADDPREPOSTREGVAR(Scry2)
ADDPREPOSTREGVAR(Separation)
ADDPREPOSTREGVAR(Split)
ADDPREPOSTREGVAR(Splits)
@ -108,6 +114,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Whorl)
ADDPREPOSTREGVAR(Waves2)
ADDPREPOSTREGVAR(Exp)
ADDPREPOSTREGVAR(Exp2)
ADDPREPOSTREGVAR(Log)
ADDPREPOSTREGVAR(Sin)
ADDPREPOSTREGVAR(Cos)
@ -118,6 +125,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Sinh)
ADDPREPOSTREGVAR(Cosh)
ADDPREPOSTREGVAR(Tanh)
ADDPREPOSTREGVAR(TanhSpiral)
ADDPREPOSTREGVAR(Sech)
ADDPREPOSTREGVAR(Csch)
ADDPREPOSTREGVAR(Coth)
@ -126,6 +134,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Hemisphere)
ADDPREPOSTREGVAR(Epispiral)
ADDPREPOSTREGVAR(Bwraps)
ADDPREPOSTREGVAR(BwrapsRand)
ADDPREPOSTREGVAR(BlurCircle)
ADDPREPOSTREGVAR(BlurZoom)
ADDPREPOSTREGVAR(BlurPixelize)
@ -146,6 +155,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Fibonacci)
ADDPREPOSTREGVAR(Fibonacci2)
ADDPREPOSTREGVAR(Glynnia)
ADDPREPOSTREGVAR(Glynnia2)
ADDPREPOSTREGVAR(GridOut)
ADDPREPOSTREGVAR(Hole)
ADDPREPOSTREGVAR(Hypertile)
@ -191,6 +201,8 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(GlynnSim1)
ADDPREPOSTREGVAR(GlynnSim2)
ADDPREPOSTREGVAR(GlynnSim3)
ADDPREPOSTREGVAR(GlynnSim4)
ADDPREPOSTREGVAR(GlynnSim5)
ADDPREPOSTREGVAR(Starblur)
ADDPREPOSTREGVAR(Sineblur)
ADDPREPOSTREGVAR(Circleblur)
@ -205,6 +217,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Ovoid3D)
ADDPREPOSTREGVAR(Spirograph)
ADDPREPOSTREGVAR(Petal)
ADDPREPOSTREGVAR(Spher)
ADDPREPOSTREGVAR(RoundSpher)
ADDPREPOSTREGVAR(RoundSpher3D)
ADDPREPOSTREGVAR(SpiralWing)
@ -217,6 +230,8 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Lissajous)
ADDPREPOSTREGVAR(Svf)
ADDPREPOSTREGVAR(Target)
ADDPREPOSTREGVAR(Target0)
ADDPREPOSTREGVAR(Target2)
ADDPREPOSTREGVAR(Taurus)
ADDPREPOSTREGVAR(Collideoscope)
ADDPREPOSTREGVAR(BMod)
@ -225,6 +240,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(BCollide)
ADDPREPOSTREGVAR(Eclipse)
ADDPREPOSTREGVAR(FlipCircle)
ADDPREPOSTREGVAR(FlipX)
ADDPREPOSTREGVAR(FlipY)
ADDPREPOSTREGVAR(ECollide)
ADDPREPOSTREGVAR(EJulia)
@ -234,6 +250,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(ERotate)
ADDPREPOSTREGVAR(EScale)
ADDPREPOSTREGVAR(ESwirl)
ADDPREPOSTREGVAR(LazyJess)
ADDPREPOSTREGVAR(LazyTravis)
ADDPREPOSTREGVAR(Squish)
ADDPREPOSTREGVAR(Circus)
@ -262,6 +279,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(SuperShape3D)
ADDPREPOSTREGVAR(Sphyp3D)
ADDPREPOSTREGVAR(Circlecrop)
ADDPREPOSTREGVAR(Circlecrop2)
ADDPREPOSTREGVAR(Julian3Dx)
ADDPREPOSTREGVAR(Fourth)
ADDPREPOSTREGVAR(Mobiq)
@ -288,12 +306,17 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Qode)
ADDPREPOSTREGVAR(BlurHeart)
ADDPREPOSTREGVAR(Truchet)
ADDPREPOSTREGVAR(TruchetFill)
ADDPREPOSTREGVAR(TruchetGlyph)
ADDPREPOSTREGVAR(TruchetInv)
ADDPREPOSTREGVAR(TruchetKnot)
ADDPREPOSTREGVAR(Gdoffs)
ADDPREPOSTREGVAR(Octagon)
ADDPREPOSTREGVAR(Trade)
ADDPREPOSTREGVAR(Juliac)
ADDPREPOSTREGVAR(Blade3D)
ADDPREPOSTREGVAR(Blob3D)
ADDPREPOSTREGVAR(Block)
ADDPREPOSTREGVAR(Blocky)
ADDPREPOSTREGVAR(Bubble2)
ADDPREPOSTREGVAR(CircleLinear)
@ -302,6 +325,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Cubic3D)
ADDPREPOSTREGVAR(CubicLattice3D)
ADDPREPOSTREGVAR(Foci3D)
ADDPREPOSTREGVAR(FociP)
ADDPREPOSTREGVAR(Ho)
ADDPREPOSTREGVAR(Julia3Dq)
ADDPREPOSTREGVAR(Line)
@ -331,6 +355,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(BubbleT3D)
ADDPREPOSTREGVAR(Synth)
ADDPREPOSTREGVAR(Crackle)
ADDPREPOSTREGVAR(Crackle2)
m_Variations.push_back(new PostSmartcropVariation<T>());//Post only
ADDPREPOSTREGVAR(Xerf)
ADDPREPOSTREGVAR(Erf)
@ -350,7 +375,7 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(CircleSplit)
ADDPREPOSTREGVAR(Cylinder2)
ADDPREPOSTREGVAR(TileLog)
ADDPREPOSTREGVAR(TruchetFill)
ADDPREPOSTREGVAR(TileHlp)
ADDPREPOSTREGVAR(Waves2Radial)
ADDPREPOSTREGVAR(Panorama1)
ADDPREPOSTREGVAR(Panorama2)
@ -360,7 +385,44 @@ VariationList<T>::VariationList()
ADDPREPOSTREGVAR(Cpow3)
ADDPREPOSTREGVAR(Concentric)
ADDPREPOSTREGVAR(Hypercrop)
ADDPREPOSTREGVAR(Hypershift)
ADDPREPOSTREGVAR(Hypershift2)
ADDPREPOSTREGVAR(Lens)
ADDPREPOSTREGVAR(Projective)
ADDPREPOSTREGVAR(DepthBlur)
ADDPREPOSTREGVAR(DepthBlur2)
ADDPREPOSTREGVAR(DepthGaussian)
ADDPREPOSTREGVAR(DepthGaussian2)
ADDPREPOSTREGVAR(DepthNgon)
ADDPREPOSTREGVAR(DepthNgon2)
ADDPREPOSTREGVAR(DepthSine)
ADDPREPOSTREGVAR(DepthSine2)
ADDPREPOSTREGVAR(CothSpiral)
ADDPREPOSTREGVAR(Dust)
ADDPREPOSTREGVAR(Asteria)
ADDPREPOSTREGVAR(Pulse)
ADDPREPOSTREGVAR(Excinis)
ADDPREPOSTREGVAR(Vibration)
ADDPREPOSTREGVAR(Vibration2)
ADDPREPOSTREGVAR(Arcsech)
ADDPREPOSTREGVAR(Arcsech2)
ADDPREPOSTREGVAR(Arcsinh)
ADDPREPOSTREGVAR(Arctanh)
ADDPREPOSTREGVAR(HexTruchet)
ADDPREPOSTREGVAR(HexRand)
ADDPREPOSTREGVAR(Smartshape)
ADDPREPOSTREGVAR(Squares)
ADDPREPOSTREGVAR(Starblur2)
ADDPREPOSTREGVAR(UnicornGaloshen)
ADDPREPOSTREGVAR(Dragonfire)
ADDPREPOSTREGVAR(Henon)
ADDPREPOSTREGVAR(Lozi)
ADDPREPOSTREGVAR(PointSymmetry)
ADDPREPOSTREGVAR(DSpherical)
ADDPREPOSTREGVAR(Modulusx)
ADDPREPOSTREGVAR(Modulusy)
ADDPREPOSTREGVAR(Rotate)
ADDPREPOSTREGVAR(Shift)
//ADDPREPOSTREGVAR(LinearXZ)
//ADDPREPOSTREGVAR(LinearYZ)
//DC are special.

View File

@ -168,6 +168,157 @@ public:
}
};
/// <summary>
/// swirl3.
/// By Zy0rg.
/// </summary>
template <typename T>
class Swirl3Variation : public ParametricVariation<T>
{
public:
Swirl3Variation(T weight = 1.0) : ParametricVariation<T>("swirl3", eVariationId::VAR_SWIRL3, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(Swirl3Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T rad = helper.m_PrecalcSqrtSumSquares;
T ang = helper.m_PrecalcAtanyx + std::log(rad) * m_Shift;
helper.Out.x = m_Weight * rad * std::cos(ang);
helper.Out.y = m_Weight * rad * std::sin(ang);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t rad = precalcSqrtSumSquares;\n"
<< "\t\treal_t ang = fma(log(rad), " << shift << ", precalcAtanyx);\n"
<< "\t\tvOut.x = " << weight << " * rad * cos(ang);\n"
<< "\t\tvOut.y = " << weight << " * rad * sin(ang);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Shift, prefix + "swirl3_shift", T(0.5)));
}
private:
T m_Shift;
};
/// <summary>
/// swirl3r.
/// By Zy0rg.
/// </summary>
template <typename T>
class Swirl3rVariation : public ParametricVariation<T>
{
public:
Swirl3rVariation(T weight = 1.0) : ParametricVariation<T>("swirl3r", eVariationId::VAR_SWIRL3R, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(Swirl3rVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T rad = helper.m_PrecalcSqrtSumSquares;
T ang = helper.m_PrecalcAtanyx;
T ang2;
if (rad < m_Minr)
ang2 = ang + m_Mina;
else if (rad > m_Maxr)
ang2 = ang + m_Maxa;
else
ang2 = ang + std::log(rad) * m_Shift;
helper.Out.x = m_Weight * rad * std::cos(ang2);
helper.Out.y = m_Weight * rad * std::sin(ang2);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string mmin = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string mmax = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string minr = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string maxr = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string mina = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string maxa = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t rad = precalcSqrtSumSquares;\n"
<< "\t\treal_t ang2, ang = precalcAtanyx;\n"
<< "\n"
<< "\t\tif (rad < " << minr << ")\n"
<< "\t\t ang2 = ang + " << mina << ";\n"
<< "\t\telse if (rad > " << maxr << ")\n"
<< "\t\t ang2 = ang + " << maxa << ";\n"
<< "\t\telse\n"
<< "\t\t ang2 = ang + log(rad) * " << shift << ";\n"
<< "\n"
<< "\t\tvOut.x = " << weight << " * rad * cos(ang);\n"
<< "\t\tvOut.y = " << weight << " * rad * sin(ang);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_Minr = std::min(m_Min, m_Max);
m_Maxr = std::max(m_Min, m_Max);
m_Mina = m_Minr > 0 ? std::log(m_Minr) * m_Shift : 0;
m_Maxa = m_Maxr > 0 ? std::log(m_Maxr) * m_Shift : 0;
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Shift, prefix + "swirl3r_shift", T(0.5)));
m_Params.push_back(ParamWithName<T>(&m_Min, prefix + "swirl3r_min", T(0.5), eParamType::REAL, 0));
m_Params.push_back(ParamWithName<T>(&m_Max, prefix + "swirl3r_max", 1, eParamType::REAL, 0));
m_Params.push_back(ParamWithName<T>(true, &m_Minr, prefix + "swirl3r_minr"));//Precalc.
m_Params.push_back(ParamWithName<T>(true, &m_Maxr, prefix + "swirl3r_maxr"));
m_Params.push_back(ParamWithName<T>(true, &m_Mina, prefix + "swirl3r_mina"));
m_Params.push_back(ParamWithName<T>(true, &m_Maxa, prefix + "swirl3r_maxa"));
}
private:
T m_Shift;
T m_Min;
T m_Max;
T m_Minr;//Precalc.
T m_Maxr;
T m_Mina;
T m_Maxa;
};
/// <summary>
/// Horseshoe:
/// a = atan2(tx, ty);
@ -1918,6 +2069,43 @@ public:
}
};
/// <summary>
/// Gaussian.
/// </summary>
template <typename T>
class GaussianVariation : public Variation<T>
{
public:
GaussianVariation(T weight = 1.0) : Variation<T>("gaussian", eVariationId::VAR_GAUSSIAN, weight) { }
VARCOPY(GaussianVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T angle = rand.Frand01<T>() * M_2PI;
T r = m_Weight * (rand.Frand01<T>() + rand.Frand01<T>() + rand.Frand01<T>() + rand.Frand01<T>() - 2);
helper.Out.x = r * std::cos(angle) + helper.In.x;
helper.Out.y = r * std::sin(angle) + helper.In.y;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss;
string weight = WeightDefineString();
intmax_t varIndex = IndexInXform();
ss << "\t{\n"
<< "\t\treal_t angle = MwcNext01(mwc) * M_2PI;\n"
<< "\t\treal_t r = " << weight << " * (MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) + MwcNext01(mwc) - (real_t)(2.0));\n"
<< "\n"
<< "\t\tvOut.x = fma(r, cos(angle), vIn.x);\n"
<< "\t\tvOut.y = fma(r, sin(angle), vIn.y);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
};
/// <summary>
/// Radial blur.
/// </summary>
@ -2512,7 +2700,7 @@ public:
string weight = WeightDefineString();
intmax_t varIndex = IndexInXform();
ss << "\t{\n"
<< "\t\treal_t u = fma(" << weight << ", SQR(M_2_PI), 1 / Zeps(tan(precalcSqrtSumSquares)));\n";
<< "\t\treal_t u = fma(" << weight << ", SQR(M2PI), 1 / Zeps(tan(precalcSqrtSumSquares)));\n";
if (m_VarType == eVariationType::VARTYPE_REG)
ss << "\t\toutPoint->m_X = outPoint->m_Y = 0;\n";
@ -3066,6 +3254,77 @@ private:
T m_Holes;
};
/// <summary>
/// flowerdb.
/// By dark-beam.
/// </summary>
template <typename T>
class FlowerDbVariation : public ParametricVariation<T>
{
public:
FlowerDbVariation(T weight = 1.0) : ParametricVariation<T>("flowerdb", eVariationId::VAR_FLOWER_DB, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(FlowerDbVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T r = m_Weight * helper.m_PrecalcSqrtSumSquares;
T t = helper.m_PrecalcAtanyx;
T r2 = r * (std::abs((m_Spread + std::sin(m_Petals * t)) * cos(m_PetalsSplit * t)));
helper.Out.x = r2 * std::cos(t);
helper.Out.y = r2 * std::sin(t);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string petals = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string split = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string spread = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string petalssplit = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t r = " << weight << " * precalcSqrtSumSquares;\n"
<< "\t\treal_t t = precalcAtanyx;\n"
<< "\t\treal_t r2 = r * (fabs((" << spread << " + sin(" << petals << " * t)) * cos(" << petalssplit << " * t)));\n"
<< "\n"
<< "\t\tvOut.x = r * cos(t);\n"
<< "\t\tvOut.y = r * sin(t);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_PetalsSplit = m_Petals * m_Split;
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Petals, prefix + "flowerdb_petals", 6));
m_Params.push_back(ParamWithName<T>(&m_Split, prefix + "flowerdb_petal_split"));
m_Params.push_back(ParamWithName<T>(&m_Spread, prefix + "flowerdb_petal_spread", 1));
m_Params.push_back(ParamWithName<T>(true, &m_PetalsSplit, prefix + "flowerdb_petal_split_petals"));//Precalc.
}
private:
T m_Petals;
T m_Split;
T m_Spread;
T m_PetalsSplit;//Precalc.
};
/// <summary>
/// Conic.
/// </summary>
@ -3985,20 +4244,52 @@ public:
//For this to be correct, it must always use double. So there is no point in switching precisions when using this variation.
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
double x2 = 2 * helper.In.x;
double u = helper.m_PrecalcSumSquares + x2;
double v = helper.m_PrecalcSumSquares - x2;
double xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v));
double a = helper.In.x / (1 + xmaxm1);
double ssx = xmaxm1 < 0 ? 0 : std::sqrt(xmaxm1);
helper.Out.x = T(m_WeightDivPiDiv2 * std::asin(Clamp(a, -1.0, 1.0)));
if (typeid(T) == typeid(float))
{
T tmp = helper.m_PrecalcSumSquares + 1;
T x2 = 2 * helper.In.x;
T xmax = T(0.5) * (std::sqrt(tmp + x2) + std::sqrt(tmp - x2));
T a = helper.In.x / xmax;
T b = 1 - a * a;
T ssx = xmax - 1;
const T w = m_WeightDivPiDiv2;
if (helper.In.y > 0)
helper.Out.y = T(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx));
if (b < 0)
b = 0;
else
b = std::sqrt(b);
if (ssx < 0)
ssx = 0;
else
ssx = std::sqrt(ssx);
helper.Out.x = w * std::atan2(a, b);
if (helper.In.y > 0)
helper.Out.y = w * std::log(xmax + ssx);
else
helper.Out.y = -(w * std::log(xmax + ssx));
helper.Out.z = DefaultZ(helper);
}
else
helper.Out.y = T(-(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx)));
{
double x2 = 2 * helper.In.x;
double u = helper.m_PrecalcSumSquares + x2;
double v = helper.m_PrecalcSumSquares - x2;
double xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v));
double a = helper.In.x / (1 + xmaxm1);
double ssx = xmaxm1 < 0 ? 0 : std::sqrt(xmaxm1);
helper.Out.x = T(m_WeightDivPiDiv2 * std::asin(Clamp(a, -1.0, 1.0)));
helper.Out.z = DefaultZ(helper);
if (helper.In.y > 0)
helper.Out.y = T(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx));
else
helper.Out.y = T(-(m_WeightDivPiDiv2 * std::log1p(xmaxm1 + ssx)));
helper.Out.z = DefaultZ(helper);
}
}
virtual string OpenCLString() const override
@ -4009,22 +4300,58 @@ public:
string index = ss2.str();
string weight = WeightDefineString();
string weightDivPiDiv2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\tdouble x2 = 2.0 * vIn.x;\n"
<< "\t\tdouble u = precalcSumSquares + x2;\n"
<< "\t\tdouble v = precalcSumSquares - x2;\n"
<< "\t\tdouble xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v));\n"
<< "\t\tdouble a = vIn.x / (1 + xmaxm1);\n"
<< "\t\tdouble ssx = xmaxm1 < 0 ? 0.0 : sqrt(xmaxm1);\n"
<< "\t\tvOut.x = (" << weightDivPiDiv2 << " * asin(clamp(a, (double)-1.0, (double)1.0)));\n"
<< "\n"
<< "\t\tif (vIn.y > 0)\n"
<< "\t\t\tvOut.y = " << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx);\n"
<< "\t\telse\n"
<< "\t\t\tvOut.y = -(" << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx));\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
if (typeid(T) == typeid(float))
{
ss << "\t{\n"
<< "\t\treal_t tmp = precalcSumSquares + (real_t)(1.0);\n"
<< "\t\treal_t x2 = (real_t)(2.0) * vIn.x;\n"
<< "\t\treal_t xmax = (real_t)(0.5) * (sqrt(tmp + x2) + sqrt(tmp - x2));\n"
<< "\t\treal_t a = vIn.x / xmax;\n"
<< "\t\treal_t b = (real_t)(1.0) - a * a;\n"
<< "\t\treal_t ssx = xmax - (real_t)(1.0);\n"
<< "\t\tconst real_t w = " << weightDivPiDiv2 << ";\n"
<< "\n"
<< "\t\tif (b < 0)\n"
<< "\t\t b = 0;\n"
<< "\t\telse\n"
<< "\t\t b = sqrt(b);\n"
<< "\n"
<< "\t\tif (ssx < 0)\n"
<< "\t\t ssx = 0;\n"
<< "\t\telse\n"
<< "\t\t ssx = sqrt(ssx);\n"
<< "\n"
<< "\t\tvOut.x = w * atan2(a, b);\n"
<< "\n"
<< "\t\tif (vIn.y > 0)\n"
<< "\t\t vOut.y = w * log(xmax + ssx);\n"
<< "\t\telse\n"
<< "\t\t vOut.y = -(w * log(xmax + ssx));\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
}
else
{
ss << "\t{\n"
<< "\t\tdouble x2 = 2.0 * vIn.x;\n"
<< "\t\tdouble u = precalcSumSquares + x2;\n"
<< "\t\tdouble v = precalcSumSquares - x2;\n"
<< "\t\tdouble xmaxm1 = 0.5 * (Sqrt1pm1(u) + Sqrt1pm1(v));\n"
<< "\t\tdouble a = vIn.x / (1 + xmaxm1);\n"
<< "\t\tdouble ssx = xmaxm1 < 0 ? 0.0 : sqrt(xmaxm1);\n"
<< "\t\tvOut.x = (" << weightDivPiDiv2 << " * asin(clamp(a, (double)-1.0, (double)1.0)));\n"
<< "\n"
<< "\t\tif (vIn.y > 0)\n"
<< "\t\t\tvOut.y = " << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx);\n"
<< "\t\telse\n"
<< "\t\t\tvOut.y = -(" << weightDivPiDiv2 << " * log1p(xmaxm1 + ssx));\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
}
return ss.str();
}
@ -4631,10 +4958,10 @@ protected:
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Separation, prefix + "oscilloscope_separation", 1));//Params.
m_Params.push_back(ParamWithName<T>(&m_Frequency, prefix + "oscilloscope_frequency", T(M_PI)));
m_Params.push_back(ParamWithName<T>(&m_Amplitude, prefix + "oscilloscope_amplitude", 1));
m_Params.push_back(ParamWithName<T>(&m_Damping, prefix + "oscilloscope_damping"));
m_Params.push_back(ParamWithName<T>(&m_Separation, prefix + "oscilloscope_separation", 1));//Params.
m_Params.push_back(ParamWithName<T>(&m_Frequency, prefix + "oscilloscope_frequency", T(M_PI)));
m_Params.push_back(ParamWithName<T>(&m_Amplitude, prefix + "oscilloscope_amplitude", 1));
m_Params.push_back(ParamWithName<T>(&m_Damping, prefix + "oscilloscope_damping"));
m_Params.push_back(ParamWithName<T>(true, &m_2PiFreq, prefix + "oscilloscope_2pifreq"));//Precalc.
}
@ -4646,6 +4973,117 @@ private:
T m_2PiFreq;//Precalc.
};
/// <summary>
/// Oscilloscope2.
/// By dark-beam.
/// </summary>
template <typename T>
class Oscilloscope2Variation : public ParametricVariation<T>
{
public:
Oscilloscope2Variation(T weight = 1.0) : ParametricVariation<T>("oscilloscope2", eVariationId::VAR_OSCILLOSCOPE2, weight)
{
Init();
}
PARVARCOPY(Oscilloscope2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T t;
T pt = m_Perturbation * std::sin(m_Tpf2 * helper.In.y);
if (!m_Damping)
t = m_Amplitude * std::cos(m_Tpf * helper.In.x + pt) + m_Separation;
else
t = m_Amplitude * std::exp(-std::abs(helper.In.x) * m_Damping) * std::cos(m_Tpf * helper.In.x + pt) + m_Separation;
if (std::abs(helper.In.y) <= t)
{
helper.Out.x = -(m_Weight * helper.In.x);
helper.Out.y = -(m_Weight * helper.In.y);
}
else
{
helper.Out.x = m_Weight * helper.In.x;
helper.Out.y = m_Weight * helper.In.y;
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string separation = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string frequencyx = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string frequencyy = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string amplitude = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string perturbation = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string damping = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string tpf = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string tpf2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t t;\n"
<< "\t\treal_t pt = " << perturbation << " * sin(" << tpf2 << " * vIn.y);\n"
<< "\n"
<< "\t\tif (!" << damping << ")\n"
<< "\t\t t = fma(" << amplitude << ", cos(fma(" << tpf << ", vIn.x, pt)), " << separation << ");\n"
<< "\t\telse\n"
<< "\t\t t = fma(" << amplitude << ", exp(-fabs(vIn.x) * " << damping << ") * cos(fma(" << tpf << ", vIn.x, pt)), " << separation << ");\n"
<< "\n"
<< "\t\tif (fabs(vIn.y) <= t)\n"
<< "\t\t{\n"
<< "\t\t vOut.x = -(" << weight << " * vIn.x);\n"
<< "\t\t vOut.y = -(" << weight << " * vIn.y);\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t vOut.x = " << weight << " * vIn.x;\n"
<< "\t\t vOut.y = " << weight << " * vIn.y;\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_Tpf = M_2PI * m_FrequencyX;
m_Tpf2 = M_2PI * m_FrequencyY;
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Separation, prefix + "oscilloscope2_separation", 1, eParamType::REAL, 0));//Params.
m_Params.push_back(ParamWithName<T>(&m_FrequencyX, prefix + "oscilloscope2_frequencyx", T(M_PI)));
m_Params.push_back(ParamWithName<T>(&m_FrequencyY, prefix + "oscilloscope2_frequencyy", T(M_PI)));
m_Params.push_back(ParamWithName<T>(&m_Amplitude, prefix + "oscilloscope2_amplitude", 1));
m_Params.push_back(ParamWithName<T>(&m_Perturbation, prefix + "oscilloscope2_perturbation", 1));
m_Params.push_back(ParamWithName<T>(&m_Damping, prefix + "oscilloscope2_damping", 0, eParamType::INTEGER, 0, 1));
m_Params.push_back(ParamWithName<T>(true, &m_Tpf, prefix + "oscilloscope2_tpf"));//Precalc.
m_Params.push_back(ParamWithName<T>(true, &m_Tpf2, prefix + "oscilloscope2_tpf2"));
}
private:
T m_Separation;//Params.
T m_FrequencyX;
T m_FrequencyY;
T m_Amplitude;
T m_Perturbation;
T m_Damping;
T m_Tpf;//Precalc.
T m_Tpf2;
};
/// <summary>
/// Polar2.
/// </summary>
@ -4833,6 +5271,97 @@ private:
T m_InvWeight;//Precalcs only, no params.
};
/// <summary>
/// scry2.
/// By dark-beam, modified by tatasz to increase the speed.
/// </summary>
template <typename T>
class Scry2Variation : public ParametricVariation<T>
{
public:
Scry2Variation(T weight = 1.0) : ParametricVariation<T>("scry2", eVariationId::VAR_SCRY2, weight, true)
{
Init();
}
PARVARCOPY(Scry2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T r2 = helper.m_PrecalcSumSquares;
T s = 1 / Zeps(std::sqrt(r2) * (r2 + 1));
T newX = helper.In.x * s;
T newY = helper.In.y * s;
T dang = (std::atan2(newY, newX) + T(M_PI)) / m_2PiOverPower;
T rad = std::sqrt(SQR(newX) + SQR(newY));
T zang1 = T(Floor<T>(dang));
T xang1 = dang - zang1;
T xang2 = xang1 > 0.5 ? 1 - xang1 : xang1;
T zang = xang1 > 0.5 ? zang1 + 1 : zang1;
T sign = T(xang1 > 0.5 ? -1 : 1);
T xang = std::atan(xang2 * std::tan(m_2PiOverPower * T(0.5)) * 2) / m_2PiOverPower;
T coeff = 1 / std::cos(xang * m_2PiOverPower);
T ang = (zang + sign * xang) * m_2PiOverPower - T(M_PI);
helper.Out.x = m_Weight * coeff * rad * std::cos(ang);
helper.Out.y = m_Weight * coeff * rad * std::sin(ang);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
int i = 0;
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string twopioverpower = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t r2 = precalcSumSquares;\n"
<< "\t\treal_t s = 1 / Zeps(sqrt(r2) * (r2 + 1));\n"
<< "\t\treal_t newX = vIn.x * s;\n"
<< "\t\treal_t newY = vIn.y * s;\n"
<< "\t\treal_t dang = (atan2(newY, newX) + MPI) / " << twopioverpower << ";\n"
<< "\t\treal_t rad = sqrt(SQR(newX) + SQR(newY));\n"
<< "\t\treal_t zang1 = floor(dang);\n"
<< "\t\treal_t xang1 = dang - zang1;\n"
<< "\t\treal_t xang2 = xang1 > 0.5 ? 1 - xang1 : xang1;\n"
<< "\t\treal_t zang = xang1 > 0.5 ? zang1 + 1 : zang1;\n"
<< "\t\treal_t sign = xang1 > 0.5 ? -1.0 : 1.0;\n"
<< "\t\treal_t xang = atan(xang2 * tan(" << twopioverpower << " * 0.5) * 2) / " << twopioverpower << ";\n"
<< "\t\treal_t coeff = 1 / cos(xang * " << twopioverpower << ");\n"
<< "\t\treal_t ang = (zang + sign * xang) * " << twopioverpower << " - MPI;\n"
<< "\t\tvOut.x = " << weight << " * coeff * rad * cos(ang);\n"
<< "\t\tvOut.y = " << weight << " * coeff * rad * sin(ang);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
virtual void Precalc() override
{
m_2PiOverPower = M_2PI / Zeps(m_Power);
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Power, prefix + "scry2_power", 4));
m_Params.push_back(ParamWithName<T>(true, &m_2PiOverPower, prefix + "scry2_2pi_over_power"));//Precalc.
}
private:
T m_Power;
T m_2PiOverPower;//Precalc.
};
/// <summary>
/// Separation.
/// </summary>
@ -5597,7 +6126,6 @@ public:
{
ostringstream ss;
string weight = WeightDefineString();
intmax_t varIndex = IndexInXform();
ss << "\t{\n"
<< "\t\treal_t expe = " << weight << " * exp(vIn.x);\n"
<< "\n"
@ -5609,6 +6137,43 @@ public:
}
};
/// <summary>
/// Exp2.
/// By tatasz.
/// </summary>
template <typename T>
class Exp2Variation : public Variation<T>
{
public:
Exp2Variation(T weight = 1.0) : Variation<T>("exp2", eVariationId::VAR_EXP2, weight) { }
VARCOPY(Exp2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T ypi = helper.In.y * T(M_PI);
T expe = m_Weight * std::exp(helper.In.x * T(M_PI));
helper.Out.x = expe * std::cos(ypi);
helper.Out.y = expe * std::sin(ypi);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss;
string weight = WeightDefineString();
ss << "\t{\n"
<< "\t\treal_t ypi = vIn.y * MPI;\n"
<< "\t\treal_t expe = " << weight << " * exp(vIn.x * MPI);\n"
<< "\n"
<< "\t\tvOut.x = expe * cos(ypi);\n"
<< "\t\tvOut.y = expe * sin(ypi);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
};
/// <summary>
/// Log.
/// </summary>
@ -6053,6 +6618,65 @@ public:
}
};
/// <summary>
/// tanh_spiral.
/// </summary>
template <typename T>
class TanhSpiralVariation : public ParametricVariation<T>
{
public:
TanhSpiralVariation(T weight = 1.0) : ParametricVariation<T>("tanh_spiral", eVariationId::VAR_TANH_SPIRAL, weight)
{
Init();
}
PARVARCOPY(TanhSpiralVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T t2 = (rand.Frand01<T>() - T(0.5)) * M_2PI;
T aux = Zeps(std::cos(m_A * t2) + std::cosh(t2));
helper.Out.x = m_Weight * (std::sinh(t2) / aux);
helper.Out.y = m_Weight * (std::sin(m_A * t2) / aux);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string a = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t t2 = (MwcNext01(mwc) - 0.5) * M_2PI;\n"
<< "\t\treal_t aux = Zeps(cos(" << a << " * t2) + cosh(t2));\n"
<< "\n"
<< "\t\tvOut.x = " << weight << " * (sinh(t2) / aux);\n"
<< "\t\tvOut.y = " << weight << " * (sin(" << a << " * t2) / aux);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_A, prefix + "tanh_spiral_a", 4));
}
private:
T m_A;
};
/// <summary>
/// Sech
/// </summary>
@ -6364,6 +6988,8 @@ MAKEPREPOSTVAR(Linear, linear, LINEAR)
MAKEPREPOSTVAR(Sinusoidal, sinusoidal, SINUSOIDAL)
MAKEPREPOSTVAR(Spherical, spherical, SPHERICAL)
MAKEPREPOSTVAR(Swirl, swirl, SWIRL)
MAKEPREPOSTPARVAR(Swirl3, swirl3, SWIRL3)
MAKEPREPOSTPARVAR(Swirl3r, swirl3r, SWIRL3R)
MAKEPREPOSTVAR(Horseshoe, horseshoe, HORSESHOE)
MAKEPREPOSTVAR(Polar, polar, POLAR)
MAKEPREPOSTVAR(Handkerchief, handkerchief, HANDKERCHIEF)
@ -6396,7 +7022,9 @@ MAKEPREPOSTPARVAR(JuliaNGeneric, julian, JULIAN)
MAKEPREPOSTPARVAR(JuliaScope, juliascope, JULIASCOPE)
MAKEPREPOSTVARASSIGN(Blur, blur, BLUR, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTVARASSIGN(GaussianBlur, gaussian_blur, GAUSSIAN_BLUR, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTVAR(Gaussian, gaussian, GAUSSIAN)
MAKEPREPOSTPARVAR(RadialBlur, radial_blur, RADIAL_BLUR)
//MAKEPREPOSTPARVAR(RadialGaussian, radial_gaussian, RADIAL_GAUSSIAN)
MAKEPREPOSTPARVARASSIGN(Pie, pie, PIE, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVAR(Ngon, ngon, NGON)
MAKEPREPOSTPARVAR(Curl, curl, CURL)
@ -6415,6 +7043,7 @@ MAKEPREPOSTVAR(Cross, cross, CROSS)
MAKEPREPOSTPARVAR(Disc2, disc2, DISC2)
MAKEPREPOSTPARVAR(SuperShape, super_shape, SUPER_SHAPE)
MAKEPREPOSTPARVAR(Flower, flower, FLOWER)
MAKEPREPOSTPARVAR(FlowerDb, flowerdb, FLOWER_DB)
MAKEPREPOSTPARVAR(Conic, conic, CONIC)
MAKEPREPOSTPARVAR(Parabola, parabola, PARABOLA)
MAKEPREPOSTPARVAR(Bent2, bent2, BENT2)
@ -6432,9 +7061,11 @@ MAKEPREPOSTPARVAR(LazySusan, lazysusan, LAZYSUSAN)
MAKEPREPOSTPARVAR(Loonie, loonie, LOONIE)
MAKEPREPOSTPARVAR(Modulus, modulus, MODULUS)
MAKEPREPOSTPARVAR(Oscilloscope, oscilloscope, OSCILLOSCOPE)
MAKEPREPOSTPARVAR(Oscilloscope2, oscilloscope2, OSCILLOSCOPE2)
MAKEPREPOSTPARVAR(Polar2, polar2, POLAR2)
MAKEPREPOSTPARVAR(Popcorn2, popcorn2, POPCORN2)
MAKEPREPOSTPARVAR(Scry, scry, SCRY)
MAKEPREPOSTPARVAR(Scry2, scry2, SCRY2)
MAKEPREPOSTPARVAR(Separation, separation, SEPARATION)
MAKEPREPOSTPARVAR(Split, split, SPLIT)
MAKEPREPOSTPARVAR(Splits, splits, SPLITS)
@ -6445,6 +7076,7 @@ MAKEPREPOSTPARVAR(WedgeSph, wedge_sph, WEDGE_SPH)
MAKEPREPOSTPARVAR(Whorl, whorl, WHORL)
MAKEPREPOSTPARVAR(Waves2, waves2, WAVES2)
MAKEPREPOSTVAR(Exp, exp, EXP)
MAKEPREPOSTVAR(Exp2, exp2, EXP2)
MAKEPREPOSTPARVAR(Log, log, LOG)
MAKEPREPOSTVAR(Sin, sin, SIN)
MAKEPREPOSTVAR(Cos, cos, COS)
@ -6455,6 +7087,7 @@ MAKEPREPOSTVAR(Cot, cot, COT)
MAKEPREPOSTVAR(Sinh, sinh, SINH)
MAKEPREPOSTVAR(Cosh, cosh, COSH)
MAKEPREPOSTVAR(Tanh, tanh, TANH)
MAKEPREPOSTPARVAR(TanhSpiral, tanh_spiral, TANH_SPIRAL)
MAKEPREPOSTVAR(Sech, sech, SECH)
MAKEPREPOSTVAR(Csch, csch, CSCH)
MAKEPREPOSTVAR(Coth, coth, COTH)

View File

@ -119,7 +119,7 @@ private:
/// <summary>
/// Bwraps.
/// Note, this is the same as bwraps2.
/// Note, this is the same as bwraps7, which is the same as bwraps2 except for the precalc function.
/// </summary>
template <typename T>
class BwrapsVariation : public ParametricVariation<T>
@ -240,7 +240,7 @@ public:
virtual void Precalc() override
{
T radius = T(0.5) * (m_BwrapsCellsize / (1 + SQR(m_BwrapsSpace)));
m_G2 = Zeps(SQR(m_BwrapsGain) / Zeps(radius));
m_G2 = SQR(m_BwrapsGain) + T(1.0e-6);
T maxBubble = m_G2 * radius;
if (maxBubble > 2)
@ -283,6 +283,195 @@ private:
T m_Rfactor;
};
/// <summary>
/// bwraps_rand.
/// By tatasz.
/// </summary>
template <typename T>
class BwrapsRandVariation : public ParametricVariation<T>
{
public:
BwrapsRandVariation(T weight = 1.0) : ParametricVariation<T>("bwraps_rand", eVariationId::VAR_BWRAPS_RAND, weight)
{
Init();
}
PARVARCOPY(BwrapsRandVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
if (m_CellSize == 0)
{
helper.Out.x = helper.In.x * m_Weight;
helper.Out.y = helper.In.y * m_Weight;
}
else
{
T Cx = (Floor<T>(helper.In.x * m_InvCellSize) + T(0.5)) * m_CellSize;
T Cy = (Floor<T>(helper.In.y * m_InvCellSize) + T(0.5)) * m_CellSize;
T Lx = helper.In.x - Cx;
T Ly = helper.In.y - Cy;
T radius;
if (m_Symm == 0)
radius = m_HalfCellSizeOver1pSpaceSq * VarFuncs<T>::HashShadertoy(Cx, Cy, m_Seed);
else
radius = m_HalfCellSizeOver1pSpaceSq * VarFuncs<T>::HashShadertoy(SQR(Cx), SQR(Cy), m_Seed);
T mb = m_G2 * radius;
T max_bubble;
if (mb > 2)
max_bubble = 1;
else
max_bubble = mb / (mb * mb * T(0.25) + 1);
T r2 = SQR(radius);
if (SQR(Lx) + SQR(Ly) > r2)
{
helper.Out.x = helper.In.x * m_Weight;
helper.Out.y = helper.In.y * m_Weight;
}
else
{
T rfactor = radius / Zeps(max_bubble);
T Lx2 = Lx * m_G2;
T Ly2 = Ly * m_G2;
T r = rfactor / ((SQR(Lx2) + SQR(Ly2)) * T(0.25) + 1);
T Lx3 = Lx2 * r;
T Ly3 = Ly2 * r;
T r_2 = (SQR(Lx3) + SQR(Ly3)) / Zeps(r2);
T theta = m_InnerTwist * (1 - r_2) + m_OuterTwist * r_2;
T ct = std::cos(theta);
T st = std::sin(theta);
helper.Out.x = (Cx + ct * Lx3 + st * Ly3) * m_Weight;
helper.Out.y = (Cy - st * Lx3 + ct * Ly3) * m_Weight;
}
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string cellsize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string space = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string gain = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string innertwist = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string outertwist = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string symm = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string invcellsize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string g2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string spacesq = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string halfcellsizeover1pspacesq = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\tif (" << cellsize << " == 0)\n"
<< "\t\t{\n"
<< "\t\t vOut.x = vIn.x * " << weight << ";\n"
<< "\t\t vOut.y = vIn.y * " << weight << ";\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t real_t Cx = (floor(vIn.x * " << invcellsize << ") + 0.5) * " << cellsize << ";\n"
<< "\t\t real_t Cy = (floor(vIn.y * " << invcellsize << ") + 0.5) * " << cellsize << ";\n"
<< "\t\t real_t Lx = vIn.x - Cx;\n"
<< "\t\t real_t Ly = vIn.y - Cy;\n"
<< "\t\t real_t radius;\n"
<< "\n"
<< "\t\t if (" << symm << " == 0)\n"
<< "\t\t radius = " << halfcellsizeover1pspacesq << " * HashShadertoy(Cx, Cy, " << seed << ");\n"
<< "\t\t else\n"
<< "\t\t radius = " << halfcellsizeover1pspacesq << " * HashShadertoy(SQR(Cx), SQR(Cy), " << seed << ");\n"
<< "\n"
<< "\t\t real_t mb = " << g2 << " * radius;\n"
<< "\t\t real_t max_bubble;\n"
<< "\n"
<< "\t\t if (mb > 2)\n"
<< "\t\t max_bubble = 1;\n"
<< "\t\t else\n"
<< "\t\t max_bubble = mb / fma(SQR(mb), 0.25, 1.0);\n"
<< "\n"
<< "\t\t real_t r2 = SQR(radius);\n"
<< "\n"
<< "\t\t if (SQR(Lx) + SQR(Ly) > r2)\n"
<< "\t\t {\n"
<< "\t\t vOut.x = vIn.x * " << weight << ";\n"
<< "\t\t vOut.y = vIn.y * " << weight << ";\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t real_t rfactor = radius / Zeps(max_bubble);\n"
<< "\t\t real_t Lx2 = Lx * " << g2 << ";\n"
<< "\t\t real_t Ly2 = Ly * " << g2 << ";\n"
<< "\t\t real_t r = rfactor / fma(fma(Lx2, Lx2, SQR(Ly2)), 0.25, 1.0);\n"
<< "\t\t real_t Lx3 = Lx2 * r;\n"
<< "\t\t real_t Ly3 = Ly2 * r;\n"
<< "\t\t real_t r_2 = fma(Lx3, Lx3, SQR(Ly3)) / Zeps(r2);\n"
<< "\t\t real_t theta = " << innertwist << " * (1.0 - r_2) + " << outertwist << " * r_2;\n"
<< "\t\t real_t ct = cos(theta);\n"
<< "\t\t real_t st = sin(theta);\n"
<< "\n"
<< "\t\t vOut.x = (Cx + ct * Lx3 + st * Ly3) * " << weight << ";\n"
<< "\t\t vOut.y = (Cy - st * Lx3 + ct * Ly3) * " << weight << ";\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_G2 = SQR(m_Gain);
m_InvCellSize = 1 / Zeps(m_CellSize);
m_SpaceSq = SQR(m_Space);
m_HalfCellSizeOver1pSpaceSq = T(0.5) * (m_CellSize / (1 + m_SpaceSq));
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps", "Fract", "HashShadertoy" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_CellSize, prefix + "bwraps_rand_cellsize", 1));
m_Params.push_back(ParamWithName<T>(&m_Space, prefix + "bwraps_rand_space"));
m_Params.push_back(ParamWithName<T>(&m_Gain, prefix + "bwraps_rand_gain", 2));
m_Params.push_back(ParamWithName<T>(&m_InnerTwist, prefix + "bwraps_rand_inner_twist"));
m_Params.push_back(ParamWithName<T>(&m_OuterTwist, prefix + "bwraps_rand_outer_twist"));
m_Params.push_back(ParamWithName<T>(&m_Symm, prefix + "bwraps_rand_symm"));
m_Params.push_back(ParamWithName<T>(&m_Seed, prefix + "bwraps_rand_seed", 1));
m_Params.push_back(ParamWithName<T>(true, &m_InvCellSize, prefix + "bwraps_rand_inv_cellsize"));//Precalc.
m_Params.push_back(ParamWithName<T>(true, &m_G2, prefix + "bwraps_rand_g2"));
m_Params.push_back(ParamWithName<T>(true, &m_SpaceSq, prefix + "bwraps_rand_space_sq"));
m_Params.push_back(ParamWithName<T>(true, &m_HalfCellSizeOver1pSpaceSq, prefix + "bwraps_rand_half_cellsize_over_1_plus_space_sq"));
}
private:
T m_CellSize;
T m_Space;
T m_Gain;
T m_InnerTwist;
T m_OuterTwist;
T m_Symm;
T m_Seed;
T m_InvCellSize;//Precalc.
T m_G2;
T m_SpaceSq;
T m_HalfCellSizeOver1pSpaceSq;
};
/// <summary>
/// BlurCircle.
/// </summary>
@ -2452,7 +2641,7 @@ public:
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) > (real_t)(0.5))\n"
<< "\t\t {\n"
<< "\t\t d = sqrt(r + vIn.x);\n"
<< "\t\t d = Zeps(sqrt(r + vIn.x));\n"
<< "\t\t vOut.x = -(" << v2 << " * d);\n"
<< "\t\t vOut.y = -(" << v2 << " / d * vIn.y);\n"
<< "\t\t }\n"
@ -2492,6 +2681,132 @@ private:
T m_V2;//Precalcs only, no params.
};
/// <summary>
/// Glynnia2.
/// By guagapunyaimel.
/// </summary>
template <typename T>
class Glynnia2Variation : public ParametricVariation<T>
{
public:
Glynnia2Variation(T weight = 1.0) : ParametricVariation<T>("glynnia2", eVariationId::VAR_GLYNNIA2, weight, true, true)
{
Init();
}
PARVARCOPY(Glynnia2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T d, r = helper.m_PrecalcSqrtSumSquares;
if (r > 0 && helper.In.y > 0)
{
if (rand.Frand01<T>() > T(0.5))
{
d = std::sqrt(r + helper.In.x);
helper.Out.x = m_V2 * d;
helper.Out.y = -(m_V2 / d * helper.In.y);
}
else
{
d = r + helper.In.x;
r = m_Weight / std::sqrt(r * (SQR(helper.In.y) + SQR(d)));
helper.Out.x = r * d;
helper.Out.y = r * helper.In.y;
}
}
else
{
if (rand.Frand01<T>() > T(0.5))
{
d = Zeps(std::sqrt(r + helper.In.x));
helper.Out.x = -(m_V2 * d);
helper.Out.y = -(m_V2 / d * helper.In.y);
}
else
{
d = r + helper.In.x;
r = m_Weight / Zeps(std::sqrt(r * (SQR(helper.In.y) + SQR(d))));
helper.Out.x = -(r * d);
helper.Out.y = r * helper.In.y;
}
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string v2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalcs only, no params.
ss << "\t{\n"
<< "\t\treal_t d, r = precalcSqrtSumSquares;\n"
<< "\n"
<< "\t\tif (r > 0 && vIn.y > 0)\n"
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) > (real_t)(0.5))\n"
<< "\t\t {\n"
<< "\t\t d = sqrt(r + vIn.x);\n"
<< "\t\t vOut.x = " << v2 << " * d;\n"
<< "\t\t vOut.y = -(" << v2 << " / d * vIn.y);\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t d = r + vIn.x;\n"
<< "\t\t r = " << weight << " / sqrt(r * fma(vIn.y, vIn.y, SQR(d)));\n"
<< "\t\t vOut.x = r * d;\n"
<< "\t\t vOut.y = r * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) > (real_t)(0.5))\n"
<< "\t\t {\n"
<< "\t\t d = Zeps(sqrt(r + vIn.x));\n"
<< "\t\t vOut.x = -(" << v2 << " * d);\n"
<< "\t\t vOut.y = -(" << v2 << " / d * vIn.y);\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t d = r + vIn.x;\n"
<< "\t\t r = " << weight << " / Zeps(sqrt(r * fma(vIn.y, vIn.y, SQR(d))));\n"
<< "\t\t vOut.x = -(r * d);\n"
<< "\t\t vOut.y = r * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_V2 = m_Weight * std::sqrt(T(2)) / 2;
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(true, &m_V2, prefix + "glynnia2_v2"));//Precalcs only, no params.
}
private:
T m_V2;//Precalcs only, no params.
};
/// <summary>
/// GridOut.
/// </summary>
@ -5657,6 +5972,7 @@ private:
MAKEPREPOSTVAR(Hemisphere, hemisphere, HEMISPHERE)
MAKEPREPOSTPARVAR(Epispiral, epispiral, EPISPIRAL)
MAKEPREPOSTPARVAR(Bwraps, bwraps, BWRAPS)
MAKEPREPOSTPARVAR(BwrapsRand, bwraps_rand, BWRAPS_RAND)
MAKEPREPOSTVARASSIGN(BlurCircle, blur_circle, BLUR_CIRCLE, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVAR(BlurZoom, blur_zoom, BLUR_ZOOM)
MAKEPREPOSTPARVAR(BlurPixelize, blur_pixelize, BLUR_PIXELIZE)
@ -5686,6 +6002,7 @@ MAKEPREPOSTVAR(FDisc, fdisc, FDISC)
MAKEPREPOSTPARVAR(Fibonacci, fibonacci, FIBONACCI)
MAKEPREPOSTPARVAR(Fibonacci2, fibonacci2, FIBONACCI2)
MAKEPREPOSTPARVAR(Glynnia, glynnia, GLYNNIA)
MAKEPREPOSTPARVAR(Glynnia2, glynnia2, GLYNNIA2)
MAKEPREPOSTVAR(GridOut, gridout, GRIDOUT)
MAKEPREPOSTPARVAR(Hole, hole, HOLE)
MAKEPREPOSTPARVAR(Hypertile, hypertile, HYPERTILE)

View File

@ -721,7 +721,7 @@ protected:
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Radius, prefix + "GlynnSim2_radius", 1));
m_Params.push_back(ParamWithName<T>(&m_Radius, prefix + "GlynnSim2_radius", 1, eParamType::REAL, 0));
m_Params.push_back(ParamWithName<T>(&m_Thickness, prefix + "GlynnSim2_thickness", T(0.1), eParamType::REAL, 0, 1));
m_Params.push_back(ParamWithName<T>(&m_Contrast, prefix + "GlynnSim2_contrast", T(0.5), eParamType::REAL, 0, 1));
m_Params.push_back(ParamWithName<T>(&m_Pow, prefix + "GlynnSim2_pow", T(1.5)));
@ -919,6 +919,219 @@ private:
T m_Gamma;
};
/// <summary>
/// GlynnSim4.
/// </summary>
template <typename T>
class GlynnSim4Variation : public ParametricVariation<T>
{
public:
GlynnSim4Variation(T weight = 1.0) : ParametricVariation<T>("GlynnSim4", eVariationId::VAR_GLYNNSIM4, weight, true, true)
{
Init();
}
PARVARCOPY(GlynnSim4Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
if (helper.m_PrecalcSqrtSumSquares < m_Radius)
{
helper.Out.x = m_Weight * m_X;
helper.Out.y = m_Weight * m_Y;
}
else
{
T alpha = std::abs(m_Radius / Zeps(helper.m_PrecalcSqrtSumSquares));
if (rand.Frand01<T>() > m_Contrast * std::pow(alpha, m_Pow))
{
helper.Out.x = m_Weight * helper.In.x;
helper.Out.y = m_Weight * helper.In.y;
}
else
{
helper.Out.x = m_Weight * SQR(alpha) * helper.In.x;
helper.Out.y = m_Weight * SQR(alpha) * helper.In.y;
}
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string contrast = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string pow = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string x = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\tif (precalcSqrtSumSquares < " << radius << ")\n"
<< "\t\t{\n"
<< "\t\t vOut.x = " << weight << " * " << x << ";\n"
<< "\t\t vOut.y = " << weight << " * " << y << ";\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t real_t alpha = fabs(" << radius << " / Zeps(precalcSqrtSumSquares));\n"
<< "\n"
<< "\t\t if (MwcNext01(mwc) > " << contrast << " * pow(alpha, " << pow << "))\n"
<< "\t\t {\n"
<< "\t\t vOut.x = " << weight << " * vIn.x;\n"
<< "\t\t vOut.y = " << weight << " * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t vOut.x = " << weight << " * SQR(alpha) * vIn.x;\n"
<< "\t\t vOut.y = " << weight << " * SQR(alpha) * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Radius, prefix + "GlynnSim4_radius", 1));
m_Params.push_back(ParamWithName<T>(&m_Contrast, prefix + "GlynnSim4_contrast", T(0.5), eParamType::REAL, 0, 1));
m_Params.push_back(ParamWithName<T>(&m_Pow, prefix + "GlynnSim4_pow", T(1.5)));
m_Params.push_back(ParamWithName<T>(&m_X, prefix + "GlynnSim4_X"));
m_Params.push_back(ParamWithName<T>(&m_Y, prefix + "GlynnSim4_Y"));
}
private:
T m_Radius;//Params.
T m_Contrast;
T m_Pow;
T m_X;
T m_Y;
};
/// <summary>
/// GlynnSim5.
/// </summary>
template <typename T>
class GlynnSim5Variation : public ParametricVariation<T>
{
public:
GlynnSim5Variation(T weight = 1.0) : ParametricVariation<T>("GlynnSim5", eVariationId::VAR_GLYNNSIM5, weight, true, true)
{
Init();
}
PARVARCOPY(GlynnSim5Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
if (helper.m_PrecalcSqrtSumSquares < m_Radius1)
{
helper.Out.x = 0;
helper.Out.y = 0;
}
else
{
T alpha = std::abs(m_Radius / Zeps(helper.m_PrecalcSqrtSumSquares));
if (rand.Frand01<T>() > m_Contrast * std::pow(alpha, m_Pow))
{
helper.Out.x = m_Weight * helper.In.x;
helper.Out.y = m_Weight * helper.In.y;
}
else
{
helper.Out.x = m_Weight * SQR(alpha);
helper.Out.y = m_Weight * SQR(alpha);
}
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string thickness = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string contrast = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string pow = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string radius1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\tif (precalcSqrtSumSquares < " << radius1 << ")\n"
<< "\t\t{\n"
<< "\t\t vOut.x = 0;\n"
<< "\t\t vOut.y = 0;\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t real_t alpha = fabs(" << radius << " / Zeps(precalcSqrtSumSquares));\n"
<< "\n"
<< "\t\t if (MwcNext01(mwc) > " << contrast << " * pow(alpha, " << pow << "))\n"
<< "\t\t {\n"
<< "\t\t vOut.x = " << weight << " * vIn.x;\n"
<< "\t\t vOut.y = " << weight << " * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t vOut.x = " << weight << " * SQR(alpha);\n"
<< "\t\t vOut.y = " << weight << " * SQR(alpha);\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
virtual void Precalc() override
{
m_Radius1 = m_Radius + m_Thickness;
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Radius, prefix + "GlynnSim5_radius", 1));
m_Params.push_back(ParamWithName<T>(&m_Thickness, prefix + "GlynnSim5_thickness", T(0.1)));
m_Params.push_back(ParamWithName<T>(&m_Contrast, prefix + "GlynnSim5_contrast", T(0.5), eParamType::REAL, 0, 1));
m_Params.push_back(ParamWithName<T>(&m_Pow, prefix + "GlynnSim5_pow", T(1.5)));
m_Params.push_back(ParamWithName<T>(true, &m_Radius1, prefix + "GlynnSim5_radius1"));//Precalc.
}
private:
T m_Radius;//Params.
T m_Thickness;
T m_Contrast;
T m_Pow;
T m_Radius1;//Precalc.
};
/// <summary>
/// Starblur.
/// </summary>
@ -1986,6 +2199,80 @@ public:
}
};
/// <summary>
/// Spher.
/// </summary>
template <typename T>
class SpherVariation : public Variation<T>
{
public:
SpherVariation(T weight = 1.0) : Variation<T>("spher", eVariationId::VAR_SPHER, weight, true) { }
VARCOPY(SpherVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T r2 = Zeps(helper.m_PrecalcSumSquares);
if (r2 > 1)
{
if (rand.Frand01<T>() < 0.5)
{
helper.Out.x = (m_Weight / r2) * helper.In.x;
helper.Out.y = (m_Weight / r2) * helper.In.y;
}
else
{
helper.Out.x = m_Weight * helper.In.x;
helper.Out.y = m_Weight * helper.In.y;
}
}
else
{
helper.Out.x = 0;
helper.Out.y = 0;
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss;
intmax_t varIndex = IndexInXform();
string weight = WeightDefineString();
ss << "\t{\n"
<< "\t\treal_t r2 = Zeps(precalcSumSquares);\n"
<< "\n"
<< "\t\tif (r2 > 1)\n"
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) < 0.5)\n"
<< "\t\t {\n"
<< "\t\t vOut.x = (" << weight << " / r2) * vIn.x;\n"
<< "\t\t vOut.y = (" << weight << " / r2) * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t vOut.x = " << weight << " * vIn.x;\n"
<< "\t\t vOut.y = " << weight << " * vIn.y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t vOut.x = 0;\n"
<< "\t\t vOut.y = 0;\n"
<< "\t\t}\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
};
/// <summary>
/// RoundSpher.
/// </summary>
@ -3055,9 +3342,9 @@ protected:
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Even, prefix + "target_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Odd, prefix + "target_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Size, prefix + "target_size", 1, eParamType::REAL, EPS, TMAX));
m_Params.push_back(ParamWithName<T>(&m_Even, prefix + "target_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Odd, prefix + "target_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Size, prefix + "target_size", 1, eParamType::REAL, EPS, TMAX));
m_Params.push_back(ParamWithName<T>(true, &m_SizeDiv2, prefix + "target_size_2"));//Precalc.
}
@ -3068,6 +3355,191 @@ private:
T m_SizeDiv2;//Precalc.
};
/// <summary>
/// target0.
/// By Mark Faber.
/// </summary>
template <typename T>
class Target0Variation : public ParametricVariation<T>
{
public:
Target0Variation(T weight = 1.0) : ParametricVariation<T>("target0", eVariationId::VAR_TARGET0, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(Target0Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T a = helper.m_PrecalcAtanyx;
T t = std::log(helper.m_PrecalcSqrtSumSquares);
if (t < 0)
t -= m_SizeDiv2;
t = fmod(std::abs(t), m_Size);
if (t < m_SizeDiv2)
a += m_Even;
else
a += m_Odd;
helper.Out.x = helper.m_PrecalcSqrtSumSquares * std::cos(a) * m_Weight;
helper.Out.y = helper.m_PrecalcSqrtSumSquares * std::sin(a) * m_Weight;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0;
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string even = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string odd = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string size = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string sizeDiv2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t a = precalcAtanyx;\n"
<< "\t\treal_t t = log(precalcSqrtSumSquares);\n"
<< "\n"
<< "\t\tif (t < (real_t)(0.0))\n"
<< "\t\t t -= " << sizeDiv2 << ";\n"
<< "\n"
<< "\t\tt = fmod(fabs(t), " << size << ");\n"
<< "\n"
<< "\t\tif (t < " << sizeDiv2 << ")\n"
<< "\t\t a += " << even << ";\n"
<< "\t\telse\n"
<< "\t\t a += " << odd << ";\n"
<< "\n"
<< "\t\tvOut.x = precalcSqrtSumSquares * cos(a) * " << weight << ";\n"
<< "\t\tvOut.y = precalcSqrtSumSquares * sin(a) * " << weight << ";\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_SizeDiv2 = m_Size * T(0.5);
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Even, prefix + "target0_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Odd, prefix + "target0_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Size, prefix + "target0_size", 0, eParamType::REAL, 0));
m_Params.push_back(ParamWithName<T>(true, &m_SizeDiv2, prefix + "target0_size_2"));//Precalc.
}
private:
T m_Even;
T m_Odd;
T m_Size;
T m_SizeDiv2;//Precalc.
};
/// <summary>
/// target2.
/// By Mark Faber.
/// </summary>
template <typename T>
class Target2Variation : public ParametricVariation<T>
{
public:
Target2Variation(T weight = 1.0) : ParametricVariation<T>("target2", eVariationId::VAR_TARGET2, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(Target2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T a = helper.m_PrecalcAtanyx;
T t = std::log(helper.m_PrecalcSqrtSumSquares);
t = m_Tightness * std::log(helper.m_PrecalcSqrtSumSquares) + T(M_1_PI) * (a + T(M_PI));
if (t < 0)
t -= m_SizeDiv2;
t = fmod(std::abs(t), m_Size);
if (t < m_SizeDiv2)
a += m_Even;
else
a += m_Odd;
helper.Out.x = helper.m_PrecalcSqrtSumSquares * std::cos(a) * m_Weight;
helper.Out.y = helper.m_PrecalcSqrtSumSquares * std::sin(a) * m_Weight;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0;
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string even = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string odd = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string size = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string thightness = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string sizeDiv2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t a = precalcAtanyx;\n"
<< "\t\treal_t t = log(precalcSqrtSumSquares);\n"
<< "\t\tt = fma(" << thightness << ", log(precalcSqrtSumSquares), M1PI * (a + MPI));\n"
<< "\n"
<< "\t\tif (t < (real_t)(0.0))\n"
<< "\t\t t -= " << sizeDiv2 << ";\n"
<< "\n"
<< "\t\tt = fmod(fabs(t), " << size << ");\n"
<< "\n"
<< "\t\tif (t < " << sizeDiv2 << ")\n"
<< "\t\t a += " << even << ";\n"
<< "\t\telse\n"
<< "\t\t a += " << odd << ";\n"
<< "\n"
<< "\t\tvOut.x = precalcSqrtSumSquares * cos(a) * " << weight << ";\n"
<< "\t\tvOut.y = precalcSqrtSumSquares * sin(a) * " << weight << ";\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_SizeDiv2 = m_Size * T(0.5);
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Even, prefix + "target2_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Odd, prefix + "target2_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Size, prefix + "target2_size", 1, eParamType::REAL, EPS, TMAX));
m_Params.push_back(ParamWithName<T>(&m_Tightness, prefix + "target2_thightness"));
m_Params.push_back(ParamWithName<T>(true, &m_SizeDiv2, prefix + "target2_size_2"));//Precalc.
}
private:
T m_Even;
T m_Odd;
T m_Size;
T m_Tightness;
T m_SizeDiv2;//Precalc.
};
/// <summary>
/// taurus.
/// </summary>
@ -3780,6 +4252,49 @@ private:
T m_WeightSquared;
};
/// <summary>
/// flipx.
/// By tatasz.
/// </summary>
template <typename T>
class FlipXVariation : public Variation<T>
{
public:
FlipXVariation(T weight = 1.0) : Variation<T>("flipx", eVariationId::VAR_FLIP_X, weight) { }
VARCOPY(FlipXVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
helper.Out.y = m_Weight * helper.In.y;
if (helper.In.y > 0)
helper.Out.x = -(m_Weight * helper.In.x);
else
helper.Out.x = m_Weight * helper.In.x;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss;
intmax_t varIndex = IndexInXform();
string weight = WeightDefineString();
ss << "\t{\n"
<< "\t\tvOut.y = " << weight << " * vIn.y;\n"
<< "\n"
<< "\t\tif (vIn.y > 0)\n"
<< "\t\t vOut.x = -(" << weight << " * vIn.x);\n"
<< "\t\telse\n"
<< "\t\t vOut.x = " << weight << " * vIn.x;\n"
<< "\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
};
/// <summary>
/// flipy.
/// </summary>
@ -4558,6 +5073,8 @@ MAKEPREPOSTPARVAR(Kaleidoscope, Kaleidoscope, KALEIDOSCOPE)
MAKEPREPOSTPARVAR(GlynnSim1, GlynnSim1, GLYNNSIM1)
MAKEPREPOSTPARVAR(GlynnSim2, GlynnSim2, GLYNNSIM2)
MAKEPREPOSTPARVAR(GlynnSim3, GlynnSim3, GLYNNSIM3)
MAKEPREPOSTPARVAR(GlynnSim4, GlynnSim4, GLYNNSIM4)
MAKEPREPOSTPARVAR(GlynnSim5, GlynnSim5, GLYNNSIM5)
MAKEPREPOSTPARVARASSIGN(Starblur, starblur, STARBLUR, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVARASSIGN(Sineblur, sineblur, SINEBLUR, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTVARASSIGN(Circleblur, circleblur, CIRCLEBLUR, eVariationAssignType::ASSIGNTYPE_SUM)
@ -4573,6 +5090,7 @@ MAKEPREPOSTPARVAR(Ovoid, ovoid, OVOID)
MAKEPREPOSTPARVAR(Ovoid3D, ovoid3d, OVOID3D)
MAKEPREPOSTPARVARASSIGN(Spirograph, Spirograph, SPIROGRAPH, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTVAR(Petal, petal, PETAL)
MAKEPREPOSTVAR(Spher, spher, SPHER)
MAKEPREPOSTVAR(RoundSpher, roundspher, ROUNDSPHER)
MAKEPREPOSTVAR(RoundSpher3D, roundspher3D, ROUNDSPHER3D)
MAKEPREPOSTVAR(SpiralWing, spiralwing, SPIRAL_WING)
@ -4585,6 +5103,8 @@ MAKEPREPOSTPARVAR(MobiusStrip, mobius_strip, MOBIUS_STRIP)
MAKEPREPOSTPARVARASSIGN(Lissajous, Lissajous, LISSAJOUS, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVAR(Svf, svf, SVF)
MAKEPREPOSTPARVAR(Target, target, TARGET)
MAKEPREPOSTPARVAR(Target0, target0, TARGET0)
MAKEPREPOSTPARVAR(Target2, target2, TARGET2)
MAKEPREPOSTPARVAR(Taurus, taurus, TAURUS)
MAKEPREPOSTPARVAR(Collideoscope, collideoscope, COLLIDEOSCOPE)
MAKEPREPOSTPARVAR(BMod, bMod, BMOD)
@ -4593,6 +5113,7 @@ MAKEPREPOSTPARVAR(BTransform, bTransform, BTRANSFORM)
MAKEPREPOSTPARVAR(BCollide, bCollide, BCOLLIDE)
MAKEPREPOSTPARVAR(Eclipse, eclipse, ECLIPSE)
MAKEPREPOSTPARVAR(FlipCircle, flipcircle, FLIP_CIRCLE)
MAKEPREPOSTVAR(FlipX, flipx, FLIP_X)
MAKEPREPOSTVAR(FlipY, flipy, FLIP_Y)
MAKEPREPOSTPARVAR(ECollide, eCollide, ECOLLIDE)
MAKEPREPOSTPARVAR(EJulia, eJulia, EJULIA)

View File

@ -87,6 +87,246 @@ private:
T m_Out;
};
/// <summary>
/// lazyjess.
/// By FarDareisMai.
/// </summary>
template <typename T>
class LazyJessVariation : public ParametricVariation<T>
{
public:
LazyJessVariation(T weight = 1.0) : ParametricVariation<T>("lazyjess", eVariationId::VAR_LAZYJESS, weight, true, true)
{
Init();
}
PARVARCOPY(LazyJessVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T theta, sina, cosa;
T x = helper.In.x;
T y = helper.In.y;
T modulus = helper.m_PrecalcSqrtSumSquares;
// n==2 requires a special case
if (m_N == T(2))
{
if (std::abs(x) < m_Weight) // If the input point falls inside the designated area...
{
// // ...then rotate it.
theta = std::atan2(y, x) + m_Spin;
sina = std::sin(theta);
cosa = std::cos(theta);
x = m_Weight * modulus * cosa;
y = m_Weight * modulus * sina;
if (std::abs(x) < m_Weight)
{
helper.Out.x = x;
helper.Out.y = y;
}
else // If it is now part of a corner that falls outside the designated area...
{
// ...then flip and rotate into place.
theta = std::atan2(y, x) - m_Spin + m_CornerRotation;
sina = std::sin(theta);
cosa = std::cos(theta);
helper.Out.x = m_Weight * modulus * cosa;
helper.Out.y = -(m_Weight * modulus * sina);
}
}
else
{
modulus = 1 + m_Space / Zeps(modulus);
helper.Out.x = m_Weight * modulus * x;
helper.Out.y = m_Weight * modulus * y;
}
}
else
{
// Calculate the distance r from origin to the edge of the polygon at the angle of the input point.
theta = std::atan2(y, x) + M_2PI;
T theta_diff = std::fmod(theta + m_HalfSlice, m_PieSlice);
T r = m_Weight * T(M_SQRT2) * m_SinVertex / Zeps(std::sin(T(M_PI) - theta_diff - m_Vertex));
if (modulus < r)
{
// Again, rotating points within designated area.
theta = std::atan2(y, x) + m_Spin + M_2PI;
sina = std::sin(theta);
cosa = std::cos(theta);
x = m_Weight * modulus * cosa;
y = m_Weight * modulus * sina;
// Calculating r and modulus for our rotated point.
theta_diff = std::fmod(theta + m_HalfSlice, m_PieSlice);
r = m_Weight * T(M_SQRT2) * m_SinVertex / Zeps(std::sin(T(M_PI) - theta_diff - m_Vertex));
modulus = VarFuncs<T>::Hypot(x, y);
if (modulus < r)
{
helper.Out.x = x;
helper.Out.y = y;
}
else
{
// Again, flipping and rotating corners that fall outside the designated area.
theta = std::atan2(y, x) - m_Spin + m_CornerRotation + M_2PI;
sina = std::sin(theta);
cosa = std::cos(theta);
helper.Out.x = m_Weight * modulus * cosa;
helper.Out.y = -(m_Weight * modulus * sina);
}
}
else
{
modulus = 1 + m_Space / Zeps(modulus);
helper.Out.x = m_Weight * modulus * x;
helper.Out.y = m_Weight * modulus * y;
}
}
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string n = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string spin = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string space = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string corner = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string vertex = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string sinvertex = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string pieslice = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string halfslice = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string cornerrotation = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t theta, sina, cosa;\n"
<< "\t\treal_t x = vIn.x;\n"
<< "\t\treal_t y = vIn.y;\n"
<< "\t\treal_t modulus = precalcSqrtSumSquares;\n"
<< "\n"
<< "\t\tif (" << n << " == 2.0)\n"
<< "\t\t{\n"
<< "\t\t if (fabs(x) < " << weight << ")\n"
<< "\t\t {\n"
<< "\t\t theta = atan2(y, x) + " << spin << ";\n"
<< "\t\t sina = sin(theta);\n"
<< "\t\t cosa = cos(theta);\n"
<< "\t\t x = " << weight << " * modulus * cosa;\n"
<< "\t\t y = " << weight << " * modulus * sina;\n"
<< "\n"
<< "\t\t if (fabs(x) < " << weight << ")\n"
<< "\t\t {\n"
<< "\t\t vOut.x = x;\n"
<< "\t\t vOut.y = y;\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t theta = atan2(y, x) - " << spin << " + " << cornerrotation << ";\n"
<< "\t\t sina = sin(theta);\n"
<< "\t\t cosa = cos(theta);\n"
<< "\t\t vOut.x = " << weight << " * modulus * cosa;\n"
<< "\t\t vOut.y = -(" << weight << " * modulus * sina);\n"
<< "\t\t }\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t modulus = 1 + " << space << " / Zeps(modulus);\n"
<< "\t\t vOut.x = " << weight << " * modulus * x;\n"
<< "\t\t vOut.y = " << weight << " * modulus * y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t theta = atan2(y, x) + M_2PI;\n"
<< "\t\t real_t theta_diff = fmod(theta + " << halfslice << ", " << pieslice << ");\n"
<< "\t\t real_t r = " << weight << " * M_SQRT2 * " << sinvertex << " / Zeps(sin(MPI - theta_diff - " << vertex << "));\n"
<< "\n"
<< "\t\t if (modulus < r)\n"
<< "\t\t {\n"
<< "\t\t theta = atan2(y, x) + " << spin << " + M_2PI;\n"
<< "\t\t sina = sin(theta);\n"
<< "\t\t cosa = cos(theta);\n"
<< "\t\t x = " << weight << " * modulus * cosa;\n"
<< "\t\t y = " << weight << " * modulus * sina;\n"
<< "\t\t theta_diff = fmod(theta + " << halfslice << ", " << pieslice << ");\n"
<< "\t\t r = " << weight << " * M_SQRT2 * " << sinvertex << " / Zeps(sin(MPI - theta_diff - " << vertex << "));\n"
<< "\t\t modulus = Hypot(x, y);\n"
<< "\n"
<< "\t\t if (modulus < r)\n"
<< "\t\t {\n"
<< "\t\t vOut.x = x;\n"
<< "\t\t vOut.y = y;\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t theta = atan2(y, x) - " << spin << " + " << cornerrotation << " + M_2PI;\n"
<< "\t\t sina = sin(theta);\n"
<< "\t\t cosa = cos(theta);\n"
<< "\t\t vOut.x = " << weight << " * modulus * cosa;\n"
<< "\t\t vOut.y = -(" << weight << " * modulus * sina);\n"
<< "\t\t }\n"
<< "\t\t }\n"
<< "\t\t else\n"
<< "\t\t {\n"
<< "\t\t modulus = 1 + " << space << " / Zeps(modulus);\n"
<< "\t\t vOut.x = " << weight << " * modulus * x;\n"
<< "\t\t vOut.y = " << weight << " * modulus * y;\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_Vertex = T(M_PI) * (m_N - 2) / Zeps(2 * m_N);
m_SinVertex = std::sin(m_Vertex);
m_PieSlice = M_2PI / Zeps(m_N);
m_HalfSlice = m_PieSlice / 2;
m_CornerRotation = (m_Corner - 1) * m_PieSlice;
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps", "Hypot" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_N, prefix + "lazyjess_n", 4, eParamType::INTEGER_NONZERO, 2));
m_Params.push_back(ParamWithName<T>(&m_Spin, prefix + "lazyjess_spin", T(M_PI), eParamType::REAL_CYCLIC, 0, M_2PI));
m_Params.push_back(ParamWithName<T>(&m_Space, prefix + "lazyjess_space"));
m_Params.push_back(ParamWithName<T>(&m_Corner, prefix + "lazyjess_corner", 1, eParamType::INTEGER_NONZERO));
m_Params.push_back(ParamWithName<T>(true, &m_Vertex, prefix + "lazyjess_vertex"));//Precalc.
m_Params.push_back(ParamWithName<T>(true, &m_SinVertex, prefix + "lazyjess_sin_vertex"));
m_Params.push_back(ParamWithName<T>(true, &m_PieSlice, prefix + "lazyjess_pie_slice"));
m_Params.push_back(ParamWithName<T>(true, &m_HalfSlice, prefix + "lazyjess_half_slice"));
m_Params.push_back(ParamWithName<T>(true, &m_CornerRotation, prefix + "lazyjess_corner_rotation"));
}
private:
T m_N;
T m_Spin;
T m_Space;
T m_Corner;
T m_Vertex;//Precalc.
T m_SinVertex;
T m_PieSlice;
T m_HalfSlice;
T m_CornerRotation;
};
/// <summary>
/// lazyTravis.
/// </summary>
@ -2106,6 +2346,116 @@ private:
T m_Ca;//Precalc.
};
/// <summary>
/// circlecrop2.
/// By tatasz.
/// </summary>
template <typename T>
class Circlecrop2Variation : public ParametricVariation<T>
{
public:
Circlecrop2Variation(T weight = 1.0) : ParametricVariation<T>("circlecrop2", eVariationId::VAR_CIRCLECROP2, weight, true, true, false, false, true)
{
Init();
}
PARVARCOPY(Circlecrop2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T rad = helper.m_PrecalcSqrtSumSquares;
T ang = helper.m_PrecalcAtanyx;
T s = 0;
T c = 0;
if (rad > m_Out || rad < m_In)
{
if (!m_Zero)
{
s = std::sin(ang) * m_OutWeight;
c = std::cos(ang) * m_OutWeight;
}
}
else
{
s = helper.In.x * m_Weight;
c = helper.In.y * m_Weight;
}
helper.Out.x = s;
helper.Out.y = c;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string inner = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string outer = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string zero = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string in = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string out = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string outweight = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t rad = precalcSqrtSumSquares;\n"
<< "\t\treal_t ang = precalcAtanyx;\n"
<< "\t\treal_t s = 0;\n"
<< "\t\treal_t c = 0;\n"
<< "\n"
<< "\t\tif (rad > " << out << " || rad < " << in << ")\n"
<< "\t\t{\n"
<< "\t\t if (!" << zero << ")\n"
<< "\t\t {\n"
<< "\t\t s = sin(ang) * " << outweight << ";\n"
<< "\t\t c = cos(ang) * " << outweight << ";\n"
<< "\t\t }\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t s = vIn.x * " << weight << ";\n"
<< "\t\t c = vIn.y * " << weight << ";\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.x = s;\n"
<< "\t\tvOut.y = c;\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual void Precalc() override
{
m_In = std::min(m_Inner, m_Outer);
m_Out = std::max(m_Inner, m_Outer);
m_OutWeight = m_Out * m_Weight;
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Inner, prefix + "circlecrop2_inner", T(0.5)));
m_Params.push_back(ParamWithName<T>(&m_Outer, prefix + "circlecrop2_outer", 1));
m_Params.push_back(ParamWithName<T>(&m_Zero, prefix + "circlecrop2_zero", 1, eParamType::INTEGER, 0, 1));
m_Params.push_back(ParamWithName<T>(true, &m_In, prefix + "circlecrop2_in"));
m_Params.push_back(ParamWithName<T>(true, &m_Out, prefix + "circlecrop2_out"));
m_Params.push_back(ParamWithName<T>(true, &m_OutWeight, prefix + "circlecrop2_out_weight"));
}
private:
T m_Inner;
T m_Outer;
T m_Zero;
T m_In;//Precalc.
T m_Out;
T m_OutWeight;
};
/// <summary>
/// julian3Dx.
/// </summary>
@ -4453,6 +4803,80 @@ private:
T m_Scale;
};
/// <summary>
/// truchet_knot.
/// </summary>
template <typename T>
class TruchetKnotVariation : public Variation<T>
{
public:
TruchetKnotVariation(T weight = 1.0) : Variation<T>("truchet_knot", eVariationId::VAR_TRUCHET_KNOT, weight) { }
VARCOPY(TruchetKnotVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T wd = T(0.5);
T space = T(0.1);
T cellx = T(Floor<T>(helper.In.x));
T celly = T(Floor<T>(helper.In.y));
T xy0x = (rand.Frand01<T>() - T(0.5)) * wd;
T xy0y = (rand.Frand01<T>() * 2 - 1) * (1 - space - wd * T(0.5));
T dir0 = std::abs(cellx + celly);
T dir1 = dir0 - 2 * Floor<T>(dir0 * T(0.5));
T xyx, xyy;
if (dir1 < 0.5)
{
xyx = xy0x;
xyy = xy0y;
}
else
{
xyx = -xy0y;//y and x intentionally flipped.
xyy = xy0x;
}
helper.Out.x = m_Weight * (cellx + xyx);
helper.Out.y = m_Weight * (celly + xyy);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss;
intmax_t varIndex = IndexInXform();
string weight = WeightDefineString();
ss << "\t{\n"
<< "\t\treal_t wd = 0.5;\n"
<< "\t\treal_t space = 0.1;\n"
<< "\t\treal_t cellx = floor(vIn.x);\n"
<< "\t\treal_t celly = floor(vIn.y);\n"
<< "\t\treal_t xy0x = (MwcNext01(mwc) - 0.5) * wd;\n"
<< "\t\treal_t xy0y = fma(MwcNext01(mwc), 2.0, -1.0) * (1.0 - space - wd * 0.5);\n"
<< "\t\treal_t dir0 = fabs(cellx + celly);\n"
<< "\t\treal_t dir1 = dir0 - 2.0 * floor(dir0 / 2.0);\n"
<< "\t\treal_t xyx, xyy;\n"
<< "\n"
<< "\t\tif (dir1 < 0.5)\n"
<< "\t\t{\n"
<< "\t\t xyx = xy0x;\n"
<< "\t\t xyy = xy0y;\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t xyx = -xy0y;//y and x intentionally flipped.\n"
<< "\t\t xyy = xy0x;\n"
<< "\t\t}\n"
<< "\n"
<< "\t\tvOut.x = " << weight << " * (cellx + xyx);\n"
<< "\t\tvOut.y = " << weight << " * (celly + xyy);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
};
/// <summary>
/// gdoffs.
/// </summary>
@ -5193,7 +5617,86 @@ private:
T m_Vy;
};
/// <summary>
/// block.
/// By TyrantWave.
/// </summary>
template <typename T>
class BlockVariation : public ParametricVariation<T>
{
public:
BlockVariation(T weight = 1.0) : ParametricVariation<T>("block", eVariationId::VAR_BLOCK, weight, true)
{
Init();
}
PARVARCOPY(BlockVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T tmp = helper.m_PrecalcSumSquares + 1;
T x2 = 2 * helper.In.x;
T y2 = 2 * helper.In.y;
T xmax = T(0.5) * (std::sqrt(tmp + x2) + std::sqrt(tmp - x2));
T ymax = T(0.5) * (std::sqrt(tmp + y2) + std::sqrt(tmp - y2));
T a = helper.In.x / Zeps(xmax);
T b = VarFuncs<T>::SafeSqrt(1 - SQR(a));
helper.Out.x = m_WightDivPiOver2 * std::atan2(a, b);
a = helper.In.y / Zeps(ymax);
b = VarFuncs<T>::SafeSqrt(1 - SQR(a));
helper.Out.y = m_WightDivPiOver2 * std::atan2(a, b);
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
int i = 0;
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string wdpio2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;//Precalcs only, no params.
ss << "\t{\n"
<< "\t\treal_t tmp = precalcSumSquares + 1;\n"
<< "\t\treal_t x2 = 2 * vIn.x;\n"
<< "\t\treal_t y2 = 2 * vIn.y;\n"
<< "\t\treal_t xmax = 0.5 * (sqrt(tmp + x2) + sqrt(tmp - x2));\n"
<< "\t\treal_t ymax = 0.5 * (sqrt(tmp + y2) + sqrt(tmp - y2));\n"
<< "\t\treal_t a = vIn.x / Zeps(xmax);\n"
<< "\t\treal_t b = SafeSqrt(1 - SQR(a));\n"
<< "\t\tvOut.x = " << wdpio2 << " * atan2(a, b);\n"
<< "\t\ta = vIn.y / Zeps(ymax);\n"
<< "\t\tb = SafeSqrt(1 - SQR(a));\n"
<< "\t\tvOut.y = " << wdpio2 << " * atan2(a, b);\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "SafeSqrt", "Zeps" };
}
virtual void Precalc() override
{
m_WightDivPiOver2 = m_Weight * T(M_2_PI);
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(true, &m_WightDivPiOver2, prefix + "block_weightdivpiover2"));//Precalcs only, no params.
}
private:
T m_WightDivPiOver2;
};
MAKEPREPOSTPARVAR(ESwirl, eSwirl, ESWIRL)
MAKEPREPOSTPARVAR(LazyJess, lazyjess, LAZYJESS)
MAKEPREPOSTPARVAR(LazyTravis, lazyTravis, LAZY_TRAVIS)
MAKEPREPOSTPARVAR(Squish, squish, SQUISH)
MAKEPREPOSTPARVAR(Circus, circus, CIRCUS)
@ -5214,6 +5717,7 @@ MAKEPREPOSTVARASSIGN(Square3D, square3D, SQUARE3D, eVariationAssignType::ASSIGNT
MAKEPREPOSTPARVARASSIGN(SuperShape3D, SuperShape3D, SUPER_SHAPE3D, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVAR(Sphyp3D, sphyp3D, SPHYP3D)
MAKEPREPOSTPARVAR(Circlecrop, circlecrop, CIRCLECROP)
MAKEPREPOSTPARVAR(Circlecrop2, circlecrop2, CIRCLECROP2)
MAKEPREPOSTPARVAR(Julian3Dx, julian3Dx, JULIAN3DX)
MAKEPREPOSTPARVAR(Fourth, fourth, FOURTH)
MAKEPREPOSTPARVAR(Mobiq, mobiq, MOBIQ)
@ -5240,6 +5744,7 @@ MAKEPREPOSTVAR(Curvature, curvature, CURVATURE)
MAKEPREPOSTPARVAR(Qode, q_ode, Q_ODE)
MAKEPREPOSTPARVARASSIGN(BlurHeart, blur_heart, BLUR_HEART, eVariationAssignType::ASSIGNTYPE_SUM)
MAKEPREPOSTPARVAR(Truchet, Truchet, TRUCHET)
MAKEPREPOSTVAR(TruchetKnot, truchet_knot, TRUCHET_KNOT)
MAKEPREPOSTPARVAR(Gdoffs, gdoffs, GDOFFS)
MAKEPREPOSTPARVAR(Octagon, octagon, OCTAGON)
MAKEPREPOSTPARVAR(Trade, trade, TRADE)
@ -5247,6 +5752,7 @@ MAKEPREPOSTPARVAR(Juliac, Juliac, JULIAC)
MAKEPREPOSTVAR(Blade3D, blade3D, BLADE3D)
MAKEPREPOSTPARVAR(Blob3D, blob3D, BLOB3D)
MAKEPREPOSTPARVAR(Blocky, blocky, BLOCKY)
MAKEPREPOSTPARVAR(Block, block, BLOCK)
///// <summary>

View File

@ -1083,6 +1083,77 @@ public:
}
};
/// <summary>
/// foci_p.
/// Idea by Chaosfissure.
/// </summary>
template <typename T>
class FociPVariation : public ParametricVariation<T>
{
public:
FociPVariation(T weight = 1.0) : ParametricVariation<T>("foci_p", eVariationId::VAR_FOCI_P, weight)
{
Init();
}
PARVARCOPY(FociPVariation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T exp_x = Zeps(std::exp(helper.In.x));
T exp_x_2 = exp_x * m_C1;
T exp_nz = m_C2 / exp_x;
T cos_y = std::cos(helper.In.y);
T sin_y = std::sin(helper.In.y);
T r = m_Weight / Zeps(exp_x_2 + exp_nz - cos_y);
helper.Out.x = (exp_x_2 - exp_nz) * r;
helper.Out.y = sin_y * r;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string c1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string c2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t exp_x = Zeps(exp(vIn.x));\n"
<< "\t\treal_t exp_x_2 = exp_x * " << c1 << ";\n"
<< "\t\treal_t exp_nz = " << c2 << " / exp_x;\n"
<< "\t\treal_t cos_y = cos(vIn.y);\n"
<< "\t\treal_t sin_y = sin(vIn.y);\n"
<< "\t\treal_t r = " << weight << " / Zeps(exp_x_2 + exp_nz - cos_y);\n"
<< "\n"
<< "\t\tvOut.x = (exp_x_2 - exp_nz) * r;\n"
<< "\t\tvOut.y = sin_y * r;\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps" };
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_C1, prefix + "foci_p_c1", T(0.5)));
m_Params.push_back(ParamWithName<T>(&m_C2, prefix + "foci_p_c2", T(0.5)));
}
private:
T m_C1;
T m_C2;
};
/// <summary>
/// ho.
/// </summary>
@ -4330,6 +4401,7 @@ MAKEPREPOSTPARVAR(CircleTrans1, CircleTrans1, CIRCLETRANS1)
MAKEPREPOSTPARVAR(Cubic3D, cubic3D, CUBIC3D)
MAKEPREPOSTPARVAR(CubicLattice3D, cubicLattice_3D, CUBIC_LATTICE3D)
MAKEPREPOSTVAR(Foci3D, foci_3D, FOCI3D)
MAKEPREPOSTPARVAR(FociP, foci_p, FOCI_P)
MAKEPREPOSTPARVAR(Ho, ho, HO)
MAKEPREPOSTPARVAR(Julia3Dq, julia3Dq, JULIA3DQ)
MAKEPREPOSTPARVARASSIGN(Line, line, LINE, eVariationAssignType::ASSIGNTYPE_SUM)

View File

@ -3807,13 +3807,13 @@ public:
ss2 << "_" << XformIndexInEmber();
string weight = WeightDefineString();
string index = ss2.str() + "]";
string cellSize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string distort = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string z = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string cellSize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string distort = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string z = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string halfCellSize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string cache = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string cache = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\tint di = -1, dj = -1;\n"
<< "\t\tint i = 0;\n"
@ -3884,13 +3884,13 @@ protected:
string prefix = Prefix();
m_Params.clear();
m_Params.reserve(8);
m_Params.push_back(ParamWithName<T>(&m_CellSize, prefix + "crackle_cellsize", 1, eParamType::REAL, T(0.0001)));
m_Params.push_back(ParamWithName<T>(&m_Power, prefix + "crackle_power", T(0.2)));
m_Params.push_back(ParamWithName<T>(&m_Distort, prefix + "crackle_distort"));
m_Params.push_back(ParamWithName<T>(&m_Scale, prefix + "crackle_scale", 1));
m_Params.push_back(ParamWithName<T>(&m_Z, prefix + "crackle_z"));
m_Params.push_back(ParamWithName<T>(&m_CellSize, prefix + "crackle_cellsize", 1, eParamType::REAL, T(0.0001)));
m_Params.push_back(ParamWithName<T>(&m_Power, prefix + "crackle_power", T(0.2)));
m_Params.push_back(ParamWithName<T>(&m_Distort, prefix + "crackle_distort"));
m_Params.push_back(ParamWithName<T>(&m_Scale, prefix + "crackle_scale", 1));
m_Params.push_back(ParamWithName<T>(&m_Z, prefix + "crackle_z"));
m_Params.push_back(ParamWithName<T>(true, &m_HalfCellSize, prefix + "crackle_half_cellsize"));
m_Params.push_back(ParamWithName<T>(true, &(m_C[0][0].x), prefix + "crackle_cache", sizeof(m_C)));
m_Params.push_back(ParamWithName<T>(true, &(m_C[0][0].x), prefix + "crackle_cache", sizeof(m_C)));
}
private:
@ -3927,6 +3927,115 @@ private:
shared_ptr<VarFuncs<T>> m_VarFuncs = VarFuncs<T>::Instance();
};
/// <summary>
/// crackle2.
/// By tatasz.
/// </summary>
template <typename T>
class Crackle2Variation : public ParametricVariation<T>
{
public:
Crackle2Variation(T weight = 1.0) : ParametricVariation<T>("crackle2", eVariationId::VAR_CRACKLE2, weight)
{
Init();
}
PARVARCOPY(Crackle2Variation)
virtual void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) override
{
T seed = 34554;
v2T cell(Floor(helper.In.x), Floor(helper.In.y));
v2T xy0(cell.x + m_OneOverCellsize * VarFuncs<T>::HashShadertoy(cell.x, cell.y, seed), cell.y + m_OneOverCellsize * VarFuncs<T>::HashShadertoy(cell.y, cell.x * 3, seed + 7));
v2T xy1_aux;
if (rand.Frand01<T>() < 0.5)
{
if (rand.Frand01<T>() < 0.5)
xy1_aux = v2T(cell.x, cell.y + 1);
else
xy1_aux = v2T(cell.x, cell.y - 1);
}
else
{
if (rand.Frand01<T>() < 0.5)
xy1_aux = v2T(cell.x + 1, cell.y);
else
xy1_aux = v2T(cell.x - 1, cell.y);
}
v2T xy1(xy1_aux.x + m_OneOverCellsize * VarFuncs<T>::HashShadertoy(xy1_aux.x, xy1_aux.y, seed), xy1_aux.y + m_OneOverCellsize * VarFuncs<T>::HashShadertoy(xy1_aux.y, xy1_aux.x * 3, seed + 7));
v2T v = xy1 - xy0;
v2T result = (xy0 + v * rand.Frand01<T>()) * m_Cellsize;
helper.Out.x = result.x;
helper.Out.y = result.y;
helper.Out.z = DefaultZ(helper);
}
virtual string OpenCLString() const override
{
ostringstream ss, ss2;
intmax_t i = 0, varIndex = IndexInXform();
ss2 << "_" << XformIndexInEmber() << "]";
string index = ss2.str();
string weight = WeightDefineString();
string cellsize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
string oneovercellsize = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n"
<< "\t\treal_t seed = 34554.0;\n"
<< "\t\treal2 cell = (real2)(floor(vIn.x), floor(vIn.y));\n"
<< "\t\treal2 xy0 = (real2)(cell.x + " << oneovercellsize << " * HashShadertoy(cell.x, cell.y, seed), cell.y + " << oneovercellsize << " * HashShadertoy(cell.y, cell.x * 3.0, seed + 7.0));\n"
<< "\t\treal2 xy1_aux;\n"
<< "\t\t\n"
<< "\t\tif (MwcNext01(mwc) < 0.5)\n"
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) < 0.5)\n"
<< "\t\t xy1_aux = (real2)(cell.x, cell.y + 1);\n"
<< "\t\t else\n"
<< "\t\t xy1_aux = (real2)(cell.x, cell.y - 1);\n"
<< "\t\t}\n"
<< "\t\telse\n"
<< "\t\t{\n"
<< "\t\t if (MwcNext01(mwc) < 0.5)\n"
<< "\t\t xy1_aux = (real2)(cell.x + 1, cell.y);\n"
<< "\t\t else\n"
<< "\t\t xy1_aux = (real2)(cell.x - 1, cell.y);\n"
<< "\t\t}\n"
<< "\t\t\n"
<< "\t\treal2 xy1 = (real2)(xy1_aux.x + " << oneovercellsize << " * HashShadertoy(xy1_aux.x, xy1_aux.y, seed), xy1_aux.y + " << oneovercellsize << " * HashShadertoy(xy1_aux.y, xy1_aux.x * 3.0, seed + 7.0));\n"
<< "\t\treal2 v = xy1 - xy0;\n"
<< "\t\treal2 result = (xy0 + v * MwcNext01(mwc)) * " << cellsize << ";\n"
<< "\t\tvOut.x = result.x;\n"
<< "\t\tvOut.y = result.y;\n"
<< "\t\tvOut.z = " << DefaultZCl()
<< "\t}\n";
return ss.str();
}
virtual vector<string> OpenCLGlobalFuncNames() const override
{
return vector<string> { "Zeps", "Fract", "HashShadertoy" };
}
virtual void Precalc() override
{
m_OneOverCellsize = 1 / Zeps(m_Cellsize);
}
protected:
void Init()
{
string prefix = Prefix();
m_Params.clear();
m_Params.push_back(ParamWithName<T>(&m_Cellsize, prefix + "crackle2_cellsize", 1, eParamType::REAL, T(0.0001)));
m_Params.push_back(ParamWithName<T>(true, &m_OneOverCellsize, prefix + "crackle2_one_over_cellsize"));
}
private:
T m_Cellsize;
T m_OneOverCellsize;
};
/// <summary>
/// post_smartcrop.
/// This variation is special in that it only exists as a post_.
@ -5417,6 +5526,7 @@ MAKEPREPOSTPARVAR(Crob, crob, CROB)
MAKEPREPOSTPARVAR(BubbleT3D, bubbleT3D, BUBBLET3D)
MAKEPREPOSTPARVAR(Synth, synth, SYNTH)
MAKEPREPOSTPARVAR(Crackle, crackle, CRACKLE)
MAKEPREPOSTPARVAR(Crackle2, crackle2, CRACKLE2)
MAKEPREPOSTVAR(Erf, erf, ERF)
MAKEPREPOSTVAR(Xerf, xerf, XERF)
MAKEPREPOSTPARVAR(W, w, W)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
#include "PaletteList.h"
#include "VariationList.h"
#include "Ember.h"
#include "Spline.h"
#ifdef __APPLE__
#include <libgen.h>
@ -33,7 +34,7 @@ private:
};
/// <summary>
/// Class for reading Xml files into ember objects.
/// Class for reading standard Xml flame files as well as Chaotica .chaos files into ember objects.
/// This class derives from EmberReport, so the caller is able
/// to retrieve a text dump of error information if any errors occur.
/// Since this class contains a VariationList object, it's important to declare one
@ -57,15 +58,22 @@ public:
private:
template <typename Alloc, template <typename, typename> class C>
void ScanForEmberNodes(xmlNode* curNode, const char* parentFile, C<Ember<T>, Alloc>& embers, bool useDefaults);
template <typename Alloc, template <typename, typename> class C>
void ScanForChaosNodes(xmlNode* curNode, const char* parentFile, C<Ember<T>, Alloc>& embers, bool useDefaults);
bool ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber);
bool ParseEmberElementFromChaos(xmlNode* emberNode, Ember<T>& currentEmber);
bool AttToEmberMotionFloat(xmlAttrPtr att, const char* attStr, eEmberMotionParam param, EmberMotion<T>& motion);
bool ParseXform(xmlNode* childNode, Xform<T>& xform, bool motion, bool fromEmber);
static string GetCorrectedParamName(const unordered_map<string, string>& names, const char* name);
static string GetCorrectedVariationName(vector<pair<pair<string, string>, vector<string>>>& vec, xmlAttrPtr att);
static string GetCorrectedVariationName(vector<pair<pair<string, string>, vector<string>>>& vec, const string& varname);
static bool XmlContainsTag(xmlAttrPtr att, const char* name);
bool ParseHexColors(const char* colstr, Ember<T>& ember, size_t numColors, intmax_t chan);
template <typename valT>
bool ParseAndAssign(const xmlChar* name, const char* attStr, const char* str, valT& val, bool& b);
template <typename valT>
bool ParseAndAssignContent(xmlNode* node, const char* fieldname, const char* fieldnameval, valT& val);
bool ParseAndAssignContent(xmlNode* node, const char* fieldname, const char* fieldnameval, std::string& val);
static bool m_Init;
static unordered_map<string, string> m_BadParamNames;

View File

@ -62,8 +62,11 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
}
for (auto& renderer : renderers)
if (auto rendererCL = dynamic_cast<RendererCLBase*>(renderer.get()))
if (auto rendererCL = dynamic_cast<RendererCL<T, float>*>(renderer.get()))
{
rendererCL->OptAffine(true);//Optimize empty affines for final renderers, this is normally false for the interactive renderer.
rendererCL->SubBatchPercentPerThread(float(opt.SBPctPerTh()));
}
if (opt.DoProgress())
renderers[0]->Callback(progress.get());

View File

@ -165,7 +165,7 @@ string DEOpenCLKernelCreator::CreateLogScaleAssignDEKernelString()
"\n"
" if (histogram[index].w != 0)\n"
" {\n"
" real_bucket_t logScale = (logFilter->m_K1 * log(1.0 + histogram[index].w * logFilter->m_K2)) / histogram[index].w;\n"
" real_bucket_t logScale = (logFilter->m_K1 * log((real_bucket_t)fma(histogram[index].w, logFilter->m_K2, (real_bucket_t)1.0))) / histogram[index].w;\n"
"\n"
" accumulator[index] = histogram[index] * logScale;\n"//Using a single real4 vector operation doubles the speed from doing each component individually.
" }\n"
@ -336,7 +336,7 @@ string DEOpenCLKernelCreator::CreateGaussianDEKernel(size_t ss)
"\n"
" if (bucket.w != 0)\n"
" {\n"
" cacheLog = (densityFilter->m_K1 * log(1.0 + bucket.w * densityFilter->m_K2)) / bucket.w;\n";
" cacheLog = (densityFilter->m_K1 * log((real_bucket_t)fma(bucket.w, densityFilter->m_K2, (real_bucket_t)1.0))) / bucket.w;\n";
if (doSS)
{
@ -513,7 +513,7 @@ string DEOpenCLKernelCreator::CreateGaussianDEKernelNoLocalCache(size_t ss)
"\n"
" if (bucket.w != 0)\n"
" {\n"
" cacheLog = (densityFilter->m_K1 * log(1.0 + bucket.w * densityFilter->m_K2)) / bucket.w;\n";
" cacheLog = (densityFilter->m_K1 * log((real_bucket_t)fma(bucket.w, densityFilter->m_K2, (real_bucket_t)1.0))) / bucket.w;\n";
if (doSS)
{

View File

@ -182,6 +182,12 @@ static const char* RandFunctionString =
" return MwcNext(s) * (1.0 / 4294967296.0);\n"
"}\n"
"\n"
"inline real_t MwcNextFRange(uint2* s, real_t lower, real_t upper)\n"
"{\n"
" real_t f = (real_t)MwcNext(s) / (real_t)UINT_MAX;\n"
" return lower + (f * (upper - lower));\n"
"}\n"
"\n"
"inline real_t MwcNextNeg1Pos1(uint2* s)\n"
"{\n"
" real_t f = (real_t)MwcNext(s) / (real_t)UINT_MAX;\n"

View File

@ -196,6 +196,7 @@ static const char* XformCLStructString =
template <typename T>
struct ALIGN EmberCL
{
T m_RandPointRange;
T m_CamZPos;
T m_CamPerspective;
T m_CamYaw;
@ -213,6 +214,7 @@ struct ALIGN EmberCL
static const char* EmberCLStructString =
"typedef struct __attribute__ " ALIGN_CL " _EmberCL\n"
"{\n"
" real_t m_RandPointRange;\n"
" real_t m_CamZPos;\n"
" real_t m_CamPerspective;\n"
" real_t m_CamYaw;\n"

View File

@ -20,6 +20,16 @@ FunctionMapper::FunctionMapper()
"{\n"
" return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);\n"
"}\n";
s_GlobalMap["Fract"] =
"inline real_t Fract(real_t x)\n"
"{\n"
" return x - floor(x);\n"
"}\n";
s_GlobalMap["HashShadertoy"] =
"inline real_t HashShadertoy(real_t x, real_t y, real_t seed)\n"
"{\n"
" return Fract(sin(fma(x, 12.9898, fma(y, 78.233, seed))) * 43758.5453);\n"
"}\n";
s_GlobalMap["Sign"] =
"inline real_t Sign(real_t v)\n"
"{\n"
@ -125,6 +135,59 @@ FunctionMapper::FunctionMapper()
" *val1 = *val2;\n"
" *val2 = tmp;\n"
"}\n";
s_GlobalMap["Modulate"] =
"inline real_t Modulate(real_t amp, real_t freq, real_t x)\n"
"{\n"
" return amp * cos(x * freq * M_2PI);\n"
"}\n";
s_GlobalMap["RealDivComplex"] =
"inline real2 RealDivComplex(real_t x, real2 a)\n"
"{\n"
" real_t s = x / Zeps(fma(a.x, a.x, a.y * a.y));\n"
" return (real2)(a.x * s, -a.y * s);\n"
"}\n";
s_GlobalMap["ComplexDivComplex"] =
"inline real2 ComplexDivComplex(real2 a, real2 b)\n"
"{\n"
" real_t s = 1.0 / Zeps(fma(b.x, b.x, b.y * b.y));\n"
" return (real2)(fma(a.x, b.x, a.y * b.y), fma(a.y, b.x, -(a.x * b.y))) * s;\n"
"}\n";
s_GlobalMap["ComplexMultReal"] =
"inline real2 ComplexMultReal(real2 a, real_t x)\n"
"{\n"
" return (real2)(a.x * x, a.y * x);\n"
"}\n";
s_GlobalMap["ComplexMultComplex"] =
"inline real2 ComplexMultComplex(real2 a, real2 b)\n"
"{\n"
" return (real2)(fma(a.x, b.x, -(a.y * b.y)), fma(a.x, b.y, a.y * b.x));\n"
"}\n";
s_GlobalMap["ComplexPlusReal"] =
"inline real2 ComplexPlusReal(real2 a, real_t x)\n"
"{\n"
" return (real2)(a.x + x, a.y);\n"
"}\n";
s_GlobalMap["ComplexPlusComplex"] =
"inline real2 ComplexPlusComplex(real2 a, real2 b)\n"
"{\n"
" return (real2)(a.x + b.x, a.y + b.y);\n"
"}\n";
s_GlobalMap["ComplexMinusReal"] =
"inline real2 ComplexMinusReal(real2 a, real_t x)\n"
"{\n"
" return (real2)(a.x - x, a.y);\n"
"}\n";
s_GlobalMap["ComplexSqrt"] =
"inline real2 ComplexSqrt(real2 a)\n"
"{\n"
" real_t mag = Hypot(a.x, a.y);\n"
" return ComplexMultReal((real2)(sqrt(mag + a.x), Sign(a.y) * sqrt(mag - a.x)), 0.5 * sqrt(2.0));\n"
"}\n";
s_GlobalMap["ComplexLog"] =
"inline real2 ComplexLog(real2 a)\n"
"{\n"
" return (real2)(0.5 * log(fma(a.x, a.x, a.y * a.y)), atan2(a.y, a.x));\n"
"}\n";
s_GlobalMap["Hash"] =
"inline real_t Hash(int a)\n"
"{\n"
@ -296,6 +359,92 @@ FunctionMapper::FunctionMapper()
"\n"
" return n;\n"
"}\n";
s_GlobalMap["EvalRational"] =
"inline real_t EvalRational(__global real_t* num, __global real_t* denom, real_t z_, int count)//This function was taken from boost.org.\n"
"{\n"
" real_t z = z_;\n"
" real_t s1, s2;\n"
"\n"
" if (z <= 1)\n"
" {\n"
" s1 = num[count - 1];\n"
" s2 = denom[count - 1];\n"
"\n"
" for (int i = count - 2; i >= 0; --i)\n"
" {\n"
" s1 *= z;\n"
" s2 *= z;\n"
" s1 += num[i];\n"
" s2 += denom[i];\n"
" }\n"
" }\n"
" else\n"
" {\n"
" z = 1 / z;\n"
" s1 = num[0];\n"
" s2 = denom[0];\n"
"\n"
" for (unsigned i = 1; i < count; ++i)\n"
" {\n"
" s1 *= z;\n"
" s2 *= z;\n"
" s1 += num[i];\n"
" s2 += denom[i];\n"
" }\n"
" }\n"
"\n"
" return s1 / s2;\n"
"}\n";
s_GlobalMap["J1"] =
"inline real_t J1(real_t x, __global real_t* P1, __global real_t* Q1, __global real_t* P2, __global real_t* Q2, __global real_t* PC, __global real_t* QC, __global real_t* PS, __global real_t* QS)//This function was taken from boost.org.\n"
"{\n"
" real_t x1 = 3.8317059702075123156e+00,\n"
" x2 = 7.0155866698156187535e+00,\n"
" x11 = 9.810e+02,\n"
" x12 = -3.2527979248768438556e-04,\n"
" x21 = 1.7960e+03,\n"
" x22 = -3.8330184381246462950e-05;\n"
" real_t value, factor, r, rc, rs, w;\n"
" w = fabs(x);\n"
"\n"
" if (x == 0)\n"
" {\n"
" return 0.0;\n"
" }\n"
"\n"
" if (w <= 4) // w in (0, 4]\n"
" {\n"
" real_t y = x * x;\n"
" r = EvalRational(P1, Q1, y, 7);\n"
" factor = w * (w + x1) * ((w - x11 / 256) - x12);\n"
" value = factor * r;\n"
" }\n"
" else if (w <= 8) // w in (4, 8]\n"
" {\n"
" real_t y = x * x;\n"
" r = EvalRational(P2, Q2, y, 8);\n"
" factor = w * (w + x2) * ((w - x21 / 256) - x22);\n"
" value = factor * r;\n"
" }\n"
" else // w in (8, \infty)\n"
" {\n"
" real_t y = 8 / w;\n"
" real_t y2 = y * y;\n"
" rc = EvalRational(PC, QC, y2, 7);\n"
" rs = EvalRational(PS, QS, y2, 7);\n"
" factor = 1 / (sqrt(w) * 1.772453850905516027);//sqrt pi\n"
" real_t sx = sin(x);\n"
" real_t cx = cos(x);\n"
" value = factor * (rc * (sx - cx) + y * rs * (sx + cx));\n"
" }\n"
"\n"
" if (x < 0)\n"
" {\n"
" value *= -1; // odd function\n"
" }\n"
"\n"
" return value;\n"
"}\n";
s_GlobalMap["JacobiElliptic"] =
"inline void JacobiElliptic(real_t uu, real_t emmc, real_t* sn, real_t* cn, real_t* dn)\n"
"{\n"

View File

@ -289,11 +289,11 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember,
" {\n"
" fuse = true;\n"
" itersToDo = fuseCount;\n"
//Calling MwcNextNeg1Pos1() twice is deliberate. The first call to mwc is not very random since it just does
//Calling MwcNextFRange() twice is deliberate. The first call to mwc is not very random since it just does
//an xor. So it must be called twice to get it in a good random state.
" firstPoint.m_X = MwcNextNeg1Pos1(&mwc);\n"
" firstPoint.m_X = MwcNextNeg1Pos1(&mwc);\n"
" firstPoint.m_Y = MwcNextNeg1Pos1(&mwc);\n"
" firstPoint.m_X = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" firstPoint.m_X = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" firstPoint.m_Y = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" firstPoint.m_Z = 0.0;\n"
" firstPoint.m_ColorX = MwcNext01(&mwc);\n"
" firstPoint.m_LastXfUsed = 0 - 1;\n"//This ensures the first iteration chooses from the unweighted distribution array, all subsequent will choose from the weighted ones.
@ -382,8 +382,8 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember,
"\n"
" if (!ok)\n"
" {\n"
" firstPoint.m_X = MwcNextNeg1Pos1(&mwc);\n"
" firstPoint.m_Y = MwcNextNeg1Pos1(&mwc);\n"
" firstPoint.m_X = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" firstPoint.m_Y = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" firstPoint.m_Z = 0.0;\n"
" firstPoint.m_ColorX = secondPoint.m_ColorX;\n"
" consec++;\n"
@ -394,8 +394,8 @@ string IterOpenCLKernelCreator<T>::CreateIterKernelString(const Ember<T>& ember,
"\n"
" if (!ok)\n"
" {\n"
" secondPoint.m_X = MwcNextNeg1Pos1(&mwc);\n"
" secondPoint.m_Y = MwcNextNeg1Pos1(&mwc);\n"
" secondPoint.m_X = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" secondPoint.m_Y = MwcNextFRange(&mwc, -ember->m_RandPointRange, ember->m_RandPointRange);\n"
" secondPoint.m_Z = 0.0;\n"
" }\n"
#ifndef STRAIGHT_RAND

View File

@ -34,6 +34,7 @@ RendererCL<T, bucketT>::RendererCL(const vector<pair<size_t, size_t>>& devices,
m_FinalFormat.image_channel_order = CL_RGBA;
m_FinalFormat.image_channel_data_type = CL_FLOAT;
m_CompileBegun = [&]() { };
m_IterCountPerKernel = size_t(m_SubBatchPercentPerThread * m_Ember.m_SubBatchSize);
Init(devices, shared, outputTexID);
}
@ -86,7 +87,7 @@ bool RendererCL<T, bucketT>::Init(const vector<pair<size_t, size_t>>& devices, b
if (b)
{
m_Devices.push_back(std::move(cld));//Success, so move to the vector, else it will go out of scope and be deleted.
m_Devices.push_back(std::move(cld));//Success, so move to the device vector, else it will go out of scope and be deleted.
}
else
{
@ -330,6 +331,26 @@ bool RendererCL<T, bucketT>::WriteRandomPoints(size_t device)
}
#endif
/// <summary>
/// Set the percentage of a sub batch that should be executed in each thread per kernel call.
/// </summary>
/// <param name="f">The percentage as a value from 0.01 to 1.0</param>
template <typename T, typename bucketT>
void RendererCL<T, bucketT>::SubBatchPercentPerThread(float f)
{
m_SubBatchPercentPerThread = Clamp(f, 0.01f, 1.0f);
}
/// <summary>
/// Get the percentage of a sub batch that should be executed in each thread per kernel call.
/// </summary>
/// <returns>The percentage as a value from 0.01 to 1.0</returns>
template <typename T, typename bucketT>
float RendererCL<T, bucketT>::SubBatchPercentPerThread() const
{
return m_SubBatchPercentPerThread;
}
/// <summary>
/// Get the kernel string for the last built iter program.
/// </summary>
@ -660,7 +681,7 @@ bool RendererCL<T, bucketT>::Alloc(bool histOnly)
if (b && !(b = device->m_Wrapper.AddBuffer(m_XformsBufferName, SizeOf(m_XformsCL)))) { ErrorStr(loc, "Failed to set xforms buffer", device.get()); break; }
if (b && !(b = device->m_Wrapper.AddBuffer(m_ParVarsBufferName, 128 * sizeof(T)))) { ErrorStr(loc, "Failed to set parametric variations buffer", device.get()); break; }
if (b && !(b = device->m_Wrapper.AddBuffer(m_ParVarsBufferName, 128 * sizeof(T)))) { ErrorStr(loc, "Failed to set parametric variations buffer", device.get()); break; }//Will be resized with the needed amount later.
if (b && !(b = device->m_Wrapper.AddBuffer(m_DistBufferName, CHOOSE_XFORM_GRAIN))) { ErrorStr(loc, "Failed to set xforms distribution buffer", device.get()); break; }//Will be resized for xaos.
@ -967,6 +988,7 @@ bool RendererCL<T, bucketT>::RunIter(size_t iterCount, size_t temporalSample, si
vector<std::thread> threadVec;
std::atomic<size_t> atomLaunchesRan;
std::atomic<intmax_t> atomItersRan, atomItersRemaining;
m_IterCountPerKernel = size_t(m_SubBatchPercentPerThread * m_Ember.m_SubBatchSize);
size_t adjustedIterCountPerKernel = m_IterCountPerKernel;
itersRan = 0;
atomItersRan.store(0);
@ -994,6 +1016,7 @@ bool RendererCL<T, bucketT>::RunIter(size_t iterCount, size_t temporalSample, si
bool b = true;
auto& wrapper = m_Devices[dev]->m_Wrapper;
intmax_t itersRemaining = 0;
//Timing looptimer;
while (b && (atomLaunchesRan.fetch_add(1) + 1 <= launches) && ((itersRemaining = atomItersRemaining.load()) > 0) && success && !m_Abort)
{
@ -1001,6 +1024,7 @@ bool RendererCL<T, bucketT>::RunIter(size_t iterCount, size_t temporalSample, si
while (Paused())
std::this_thread::sleep_for(500ms);
//looptimer.Tic();
cl_uint argIndex = 0;
#ifdef TEST_CL
uint fuse = 0;
@ -1084,6 +1108,8 @@ bool RendererCL<T, bucketT>::RunIter(size_t iterCount, size_t temporalSample, si
m_ProgressTimer.Tic();
}
}
//cout << "CL kernel call " << atomLaunchesRan << " took: " << looptimer.Toc() << endl;
}
};
@ -1747,19 +1773,20 @@ template <typename T, typename bucketT>
void RendererCL<T, bucketT>::ConvertEmber(Ember<T>& ember, EmberCL<T>& emberCL, vector<XformCL<T>>& xformsCL)
{
memset(&emberCL, 0, sizeof(EmberCL<T>));//Might not really be needed.
emberCL.m_RotA = m_RotMat.A();
emberCL.m_RotB = m_RotMat.B();
emberCL.m_RotD = m_RotMat.D();
emberCL.m_RotE = m_RotMat.E();
emberCL.m_CamMat = ember.m_CamMat;
emberCL.m_CenterX = CenterX();
emberCL.m_CenterY = ember.m_RotCenterY;
emberCL.m_RandPointRange = ember.m_RandPointRange;
emberCL.m_CamZPos = ember.m_CamZPos;
emberCL.m_CamPerspective = ember.m_CamPerspective;
emberCL.m_CamYaw = ember.m_CamYaw;
emberCL.m_CamPitch = ember.m_CamPitch;
emberCL.m_CamDepthBlur = ember.m_CamDepthBlur;
emberCL.m_BlurCoef = ember.BlurCoef();
emberCL.m_CamMat = ember.m_CamMat;
emberCL.m_CenterX = CenterX();
emberCL.m_CenterY = ember.m_RotCenterY;
emberCL.m_RotA = m_RotMat.A();
emberCL.m_RotB = m_RotMat.B();
emberCL.m_RotD = m_RotMat.D();
emberCL.m_RotE = m_RotMat.E();
for (size_t i = 0; i < ember.TotalXformCount() && i < xformsCL.size(); i++)
{

View File

@ -141,6 +141,8 @@ public:
#ifdef TEST_CL
bool WriteRandomPoints(size_t device);
#endif
void SubBatchPercentPerThread(float f);
float SubBatchPercentPerThread() const;
const string& IterKernel() const;
const string& DEKernel() const;
const string& FinalAccumKernel() const;
@ -205,6 +207,7 @@ private:
bool m_Init = false;
bool m_Shared = false;
bool m_DoublePrecision = typeid(T) == typeid(double);
float m_SubBatchPercentPerThread = 0.025f;//0.025 * 10,240 gives a default value of 256 iters per thread for the default sub batch size of 10,240 which almost all flames will use.
//It's critical that these numbers never change. They are
//based on the cuburn model of each kernel launch containing
//256 threads. 32 wide by 8 high. Everything done in the OpenCL

View File

@ -100,6 +100,7 @@ enum class eOptionIDs : et
OPT_QUALITY,
OPT_DE_MIN,
OPT_DE_MAX,
OPT_SBPKTH,
OPT_PIXEL_ASPECT,
OPT_STAGGER,
OPT_AVG_THRESH,
@ -400,17 +401,18 @@ public:
INITUINTOPTION(StartCount, Eou(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_START_COUNT, _T("--startcount"), 0, SO_REQ_SEP, " --startcount=<val> The number to add to each flame name when generating a sequence. Useful for programs like ffmpeg which require numerically increasing filenames [default: 0].\n"));
INITUINTOPTION(Padding, Eou(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_PADDING, _T("--padding"), 0, SO_REQ_SEP, " --padding=<val> Override the amount of zero padding added to each flame name when generating a sequence. Useful for programs like ffmpeg which require fixed width filenames [default: 0 (auto calculate padding)].\n"));
//Double.
INITDOUBLEOPTION(SizeScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_SS, _T("--ss"), 1.0, SO_REQ_SEP, " --ss=<val> Size scale. All dimensions are scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(WidthScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_WS, _T("--ws"), 1.0, SO_REQ_SEP, " --ws=<val> Width scale. The width is scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(HeightScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_HS, _T("--hs"), 1.0, SO_REQ_SEP, " --hs=<val> Height scale. The height is scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(QualityScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_QS, _T("--qs"), 1.0, SO_REQ_SEP, " --qs=<val> Quality scale. All quality values are scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(Quality, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_QUALITY, _T("--quality"), 0.0, SO_REQ_SEP, " --quality=<val> Override the quality of the flame if not 0 [default: 0].\n"));
INITDOUBLEOPTION(DeMin, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_DE_MIN, _T("--demin"), -1.0, SO_REQ_SEP, " --demin=<val> Override the minimum size of the density estimator filter radius if not -1 [default: -1].\n"));
INITDOUBLEOPTION(DeMax, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_DE_MAX, _T("--demax"), -1.0, SO_REQ_SEP, " --demax=<val> Override the maximum size of the density estimator filter radius if not -1 [default: -1].\n"));
INITDOUBLEOPTION(AspectRatio, Eod(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PIXEL_ASPECT, _T("--pixel_aspect"), 1.0, SO_REQ_SEP, " --pixel_aspect=<val> Aspect ratio of pixels (width over height), eg. 0.90909 for NTSC [default: 1.0].\n"));
INITDOUBLEOPTION(Stagger, Eod(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_STAGGER, _T("--stagger"), 0.0, SO_REQ_SEP, " --stagger=<val> Affects simultaneity of xform interpolation during flame interpolation.\n"
"\t Represents how 'separate' the xforms are interpolated. Set to 1 for each\n"
"\t xform to be interpolated individually, fractions control interpolation overlap [default: 0].\n"));
INITDOUBLEOPTION(SizeScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_SS, _T("--ss"), 1.0, SO_REQ_SEP, " --ss=<val> Size scale. All dimensions are scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(WidthScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_WS, _T("--ws"), 1.0, SO_REQ_SEP, " --ws=<val> Width scale. The width is scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(HeightScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_HS, _T("--hs"), 1.0, SO_REQ_SEP, " --hs=<val> Height scale. The height is scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(QualityScale, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_QS, _T("--qs"), 1.0, SO_REQ_SEP, " --qs=<val> Quality scale. All quality values are scaled by this amount [default: 1.0].\n"));
INITDOUBLEOPTION(Quality, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_QUALITY, _T("--quality"), 0.0, SO_REQ_SEP, " --quality=<val> Override the quality of the flame if not 0 [default: 0].\n"));
INITDOUBLEOPTION(SBPctPerTh, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_SBPKTH, _T("--sbpctth"), 0.025, SO_REQ_SEP, " --sbpctth=<val> The percentage of a sub batch from 0.01 to 1.0 to complete per thread per kernel launch done in OpenCL rendering. This is for performance tuning with OpenCL and does not apply to CPU rendering [default: 0.025 (256 iters)].\n"));
INITDOUBLEOPTION(DeMin, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_DE_MIN, _T("--demin"), -1.0, SO_REQ_SEP, " --demin=<val> Override the minimum size of the density estimator filter radius if not -1 [default: -1].\n"));
INITDOUBLEOPTION(DeMax, Eod(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_DE_MAX, _T("--demax"), -1.0, SO_REQ_SEP, " --demax=<val> Override the maximum size of the density estimator filter radius if not -1 [default: -1].\n"));
INITDOUBLEOPTION(AspectRatio, Eod(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PIXEL_ASPECT, _T("--pixel_aspect"), 1.0, SO_REQ_SEP, " --pixel_aspect=<val> Aspect ratio of pixels (width over height), eg. 0.90909 for NTSC [default: 1.0].\n"));
INITDOUBLEOPTION(Stagger, Eod(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_STAGGER, _T("--stagger"), 0.0, SO_REQ_SEP, " --stagger=<val> Affects simultaneity of xform interpolation during flame interpolation.\n"
"\t Represents how 'separate' the xforms are interpolated. Set to 1 for each\n"
"\t xform to be interpolated individually, fractions control interpolation overlap [default: 0].\n"));
INITDOUBLEOPTION(AvgThresh, Eod(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_AVG_THRESH, _T("--avg"), 20.0, SO_REQ_SEP, " --avg=<val> Minimum average pixel channel sum (r + g + b) threshold from 0 - 765. Ignored if sequence, inter or rotate were specified [default: 20].\n"));
INITDOUBLEOPTION(BlackThresh, Eod(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_BLACK_THRESH, _T("--black"), 0.01, SO_REQ_SEP, " --black=<val> Minimum number of allowed black pixels as a percentage from 0 - 1. Ignored if sequence, inter or rotate were specified [default: 0.01].\n"));
INITDOUBLEOPTION(WhiteLimit, Eod(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_WHITE_LIMIT, _T("--white"), 0.05, SO_REQ_SEP, " --white=<val> Maximum number of allowed white pixels as a percentage from 0 - 1. Ignored if sequence, inter or rotate were specified [default: 0.05].\n"));
@ -556,6 +558,7 @@ public:
PARSEOPTION(eOptionIDs::OPT_HS, HeightScale);
PARSEOPTION(eOptionIDs::OPT_QS, QualityScale);
PARSEOPTION(eOptionIDs::OPT_QUALITY, Quality);
PARSEOPTION(eOptionIDs::OPT_SBPKTH, SBPctPerTh);
PARSEOPTION(eOptionIDs::OPT_DE_MIN, DeMin);
PARSEOPTION(eOptionIDs::OPT_DE_MAX, DeMax);
PARSEOPTION(eOptionIDs::OPT_PIXEL_ASPECT, AspectRatio);
@ -848,6 +851,7 @@ public:
Eod Quality;
Eod DeMin;
Eod DeMax;
Eod SBPctPerTh;
Eod AspectRatio;
Eod Stagger;
Eod AvgThresh;

View File

@ -61,8 +61,11 @@ bool EmberRender(int argc, _TCHAR* argv[], EmberOptions& opt)
if (opt.EmberCL() && renderer->RendererType() != eRendererType::OPENCL_RENDERER)//OpenCL init failed, so fall back to CPU.
opt.EmberCL(false);
if (auto rendererCL = dynamic_cast<RendererCLBase*>(renderer.get()))
if (auto rendererCL = dynamic_cast<RendererCL<T, float>*>(renderer.get()))
{
rendererCL->OptAffine(true);//Optimize empty affines for final renderers, this is normally false for the interactive renderer.
rendererCL->SubBatchPercentPerThread(float(opt.SBPctPerTh()));
}
if (!InitPaletteList<float>(fullpath, opt.PalettePath()))//For any modern flames, the palette isn't used. This is for legacy purposes and should be removed.
return false;

View File

@ -42,7 +42,7 @@ using namespace Imath;
using namespace EmberNs;
using namespace EmberCommon;
//#define DO_NVIDIA 1
#define DO_NVIDIA 1
void writeRgba1(const char filename[],
const Rgba* pixels,
@ -1124,6 +1124,10 @@ bool TestConstants()
stringVec.push_back("2*M_PI");
stringVec.push_back("M_PI*2");
stringVec.push_back("M_PI * 2");
stringVec.push_back("2 * MPI");
stringVec.push_back("2*MPI");
stringVec.push_back("MPI*2");
stringVec.push_back("MPI * 2");
for (size_t i = 0; i < vlf->Size(); i++)
{
@ -1136,6 +1140,97 @@ bool TestConstants()
}
}
stringVec.clear();
stringVec.push_back("3 * M_PI");
stringVec.push_back("3*M_PI");
stringVec.push_back("M_PI*3");
stringVec.push_back("M_PI * 3");
//stringVec.push_back("3 * MPI");//Gives a false positive for prose3d.
stringVec.push_back("3*MPI");
stringVec.push_back("MPI*3");
stringVec.push_back("MPI * 3");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " should be using M_3PI." << endl;
success = false;
}
}
stringVec.clear();
stringVec.push_back("M_PI");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " is using M_PI, but should be using MPI." << endl;
success = false;
}
}
stringVec.clear();
stringVec.push_back("M_2_PI");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " is using M_2_PI, but should be using M2PI." << endl;
success = false;
}
}
stringVec.clear();
stringVec.push_back("M_1_PI");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " is using M_1_PI, but should be using M1PI." << endl;
success = false;
}
}
stringVec.clear();
stringVec.push_back("M_PI_4");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " is using M_PI_4, but should be using MPI4." << endl;
success = false;
}
}
stringVec.clear();
stringVec.push_back("M_PI_2");
for (size_t i = 0; i < vlf->Size(); i++)
{
auto var = vlf->GetVariation(i);
if (SearchVar(var, stringVec, false))
{
cout << "Variation " << var->Name() << " is using M_PI_2, but should be using MPI2." << endl;
success = false;
}
}
return success;
}

View File

@ -58,7 +58,7 @@
<enum>QFrame::NoFrame</enum>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;Fractorium 1.0.0.14&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&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;a href=&quot;http://fractorium.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;fractorium.com&lt;/span&gt;&lt;/a&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;Fractorium 1.0.0.15&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&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;a href=&quot;http://fractorium.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;fractorium.com&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@ -104,7 +104,7 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.1pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;Developers:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Lead: &lt;/span&gt;&lt;a href=&quot;http://www.fractorium.com&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Matt Feemster&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br /&gt;Contributors: &lt;/span&gt;&lt;a href=&quot;http://blog.highlyillogical.org/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Simon Detheridge&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;https://www.deviantart.com/triptychaos&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Michel Mastriani.&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
@ -114,8 +114,8 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Code and theory questions: &lt;/span&gt;&lt;a href=&quot;https://github.com/scottdraves/flam3&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Erik Reckase&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://fractron9000.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Mike Thiesen&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;https://github.com/scottdraves/flam3&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Scott Draves&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;https://github.com/stevenrobertson/cuburn&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Steve Robertson&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://www.chaoticafractals.com/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Thomas Ludwig&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;Code Copied:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/scottdraves/flam3&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;flam3&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Scott Draves, Erik Reckase (GPL v2)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://github.com/stevenrobertson/cuburn&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;cuburn&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://fractron9000.sourceforge.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Fractron 9000&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Mike Thiesen (GPL)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://sourceforge.net/projects/apophysis7x&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Apophysis&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://jwildfire.org/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;JWildfire&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Andreas Maschke (LGPL)&lt;br /&gt;gradLib: Stian Broen&lt;br /&gt;ColorPickerWidget: Etienne Moutot&lt;br /&gt;Numerous Apophysis plugin developers (GPL)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/scottdraves/flam3&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;flam3&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Scott Draves, Erik Reckase (GPL v2)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://github.com/stevenrobertson/cuburn&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;cuburn&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://fractron9000.sourceforge.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Fractron 9000&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Mike Thiesen (GPL)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://sourceforge.net/projects/apophysis7x&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Apophysis&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://jwildfire.org/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;JWildfire&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Andreas Maschke (LGPL)&lt;br /&gt;gradLib: Stian Broen&lt;br /&gt;ColorPickerWidget: Etienne Moutot&lt;br /&gt;Numerous Apophysis plugin developers (GPL)&lt;br /&gt;Chaotica variations&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:7.875pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;Libraries Linked:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.qt.io/developers/&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Qt&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Digia Plc (GPL v3, LGPL v2)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://g-truc.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;glm&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Christophe Riccio (MIT License)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://threadingbuildingblocks.org&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;Threading Building Blocks&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Intel Corporation (GPLv2)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://libjpeg.sourceforge.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;libjpeg&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Independent JPEG Group (Free Software License)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://libpng.org&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;libpng&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Glenn Randers-Pehrson et al (Libpng License)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://xmlsoft.org&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;libxml2&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Daniel Veillard (MIT License)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://zlib.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;zlib&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Jean-loup Gailly, Mark Adler (Zlib License)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://burtleburtle.net/bob/cplus/isaac.hpp&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;QTIsaac&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Robert J. Jenkins, Quinn Tyler Jackson (Public Domain)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;http://cas.ee.ic.ac.uk/people/dt10/research/rngs-gpu-mwc64x.html&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;MWC64X Random Number Generator&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: David Thomas (Public Domain)&lt;br /&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/brofield/simpleopt&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;SimpleOpt&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;: Brodie Thiesfield (MIT License)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;

View File

@ -10,60 +10,21 @@ 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();
Curves<float> curves(true);
Set(curves);
show();
//qDebug() << "Original scene rect is: " << m_OriginalRect;
}
@ -78,7 +39,6 @@ void CurvesGraphicsView::PointChanged(int curveIndex, int pointIndex, const QPoi
{
double x = point.x() / width();
double y = (height() - point.y()) / height();
emit PointChangedSignal(curveIndex, pointIndex, QPointF(x, y));
}
@ -86,14 +46,13 @@ void CurvesGraphicsView::PointChanged(int curveIndex, int pointIndex, const QPoi
/// 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>
/// <param name="pointIndex">The point within the curve whose value will be retrieved, 0-3.</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)
if (curveIndex < 4 && pointIndex < m_Points[curveIndex].size())
{
EllipseItem* item = (pointIndex == 1) ? m_Points[curveIndex].first : m_Points[curveIndex].second;
EllipseItem* item = m_Points[curveIndex][pointIndex];
return QPointF(item->pos().x() / width(), (height() - item->pos().y()) / height());
}
@ -104,19 +63,50 @@ QPointF CurvesGraphicsView::Get(int curveIndex, int pointIndex)
/// 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="pointIndex">The point within the curve which will be set, 0-3</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 (curveIndex < 4 && pointIndex < m_Points[curveIndex].size())
{
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());
m_Points[curveIndex][pointIndex]->setPos(point.x() * width(), (1.0 - point.y()) * height());//Scale to scene dimensions, Y axis is flipped.
}
}
void CurvesGraphicsView::Set(Curves<float>& curves)
{
m_Scene.clear();
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_XLine);
m_Scene.addItem(m_YLine);
auto createpoints = [&](int index, vector<EllipseItem*>& items, Qt::GlobalColor col, int zval)
{
items.clear();
m_Points[index].clear();
for (int i = 0; i < curves.m_Points[index].size(); i++)
{
auto item = new EllipseItem(QRectF(-5, -5, 10, 10), index, i, this);
items.push_back(item);
item->setBrush(QBrush(col));
m_Scene.addItem(item);
m_Points[index].push_back(item);
item->setZValue(zval);
QPointF point(curves.m_Points[index][i].x, curves.m_Points[index][i].y);
Set(index, i, point);
}
};
createpoints(0, m_AllP, Qt::GlobalColor::black, 2);
createpoints(1, m_RedP, Qt::GlobalColor::red, 1);
createpoints(2, m_GrnP, Qt::GlobalColor::green, 1);
createpoints(3, m_BluP, Qt::GlobalColor::blue, 1);
}
/// <summary>
/// Set the topmost curve but setting its Z value.
/// All other curves will get a value one less.
@ -124,35 +114,36 @@ void CurvesGraphicsView::Set(int curveIndex, int pointIndex, const QPointF& poin
/// <param name="curveIndex">The curve to set</param>
void CurvesGraphicsView::SetTop(CurveIndex curveIndex)
{
size_t 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;
case CurveIndex::ALL:
m_Index = 0;
break;
case CurveIndex::RED:
m_Index = 1;
break;
case CurveIndex::GREEN:
m_Index = 2;
break;
case CurveIndex::BLUE:
default:
m_Index = 3;
}
for (size_t i = 0; i < 4; i++)
{
if (i == index)
if (i == m_Index)
{
m_Points[i].first->setZValue(2);
m_Points[i].second->setZValue(2);
for (auto& p : m_Points[i])
p->setZValue(2);
}
else
{
m_Points[i].first->setZValue(1);
m_Points[i].second->setZValue(1);
for (auto& p : m_Points[i])
p->setZValue(1);
}
}
}
@ -164,50 +155,124 @@ void CurvesGraphicsView::SetTop(CurveIndex curveIndex)
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);
auto points = m_Points;
for (auto& p : points)
{
if (p.size() < 2)
return;
std::sort(p.begin(), p.end(), [&](auto & lhs, auto & rhs) { return lhs->pos().x() < rhs->pos().x(); });
}
//Create 4 new paths. These must be constructed every time and cannot be members.
//Need to sort the points here first based on their x coordinate.
QPainterPath paths[4] =
{
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft())),
QPainterPath(mapFromScene(rect.bottomLeft()))
QPainterPath(points[0][0]->pos()),
QPainterPath(points[1][0]->pos()),
QPainterPath(points[2][0]->pos()),
QPainterPath(points[3][0]->pos())
};
int topmost = 0;
//Draw paths for all but the topmost curve.
//Construct paths or all curves, and draw them 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()));
vector<v2F> vals;
vals.reserve(points[i].size());
if (m_Points[i].first->zValue() == 1)
for (auto& p : points[i])
vals.push_back({ p->pos().x(), p->pos().y() });
Spline<float> spline(vals);
for (int j = 0; j < rect.width(); j++)
{
auto x = j;
auto y = spline.Interpolate(x);
paths[i].lineTo(QPointF(x, y));
}
if (points[i][0]->zValue() == 1)
{
painter.setPen(*m_Pens[i]);
painter.drawPath(paths[i]);
}
else
topmost = i;
}
//Draw the topmost curve.
for (i = 0; i < 4; i++)
painter.setPen(*m_Pens[topmost]);
painter.drawPath(paths[topmost]);
}
void CurvesGraphicsView::mousePressEvent(QMouseEvent* e)
{
QGraphicsView::mousePressEvent(e);
auto thresh = devicePixelRatioF() * 2;
auto findpoint = [&](int x, int y) -> int
{
if (m_Points[i].first->zValue() == 2)
for (int i = 0; i < m_Points[m_Index].size(); i++)
{
painter.setPen(*m_Pens[i]);
painter.drawPath(paths[i]);
break;
auto item = m_Points[m_Index][i];
auto xdist = std::abs(item->pos().x() - x);
auto ydist = std::abs(item->pos().y() - y);
if (xdist < thresh && ydist < thresh)
return i;
}
return -1;
};
if (e->button() == Qt::RightButton)//Right button does whole image rotation and scaling.
{
int i = findpoint(e->pos().x(), e->pos().y());
if (i != -1)
emit PointRemovedSignal(m_Index, i);
}
else if (findpoint(e->pos().x(), e->pos().y()) == -1)
{
QRectF rect = scene()->sceneRect();
auto points = m_Points[m_Index];
if (points.size() < 2)
return;
std::sort(points.begin(), points.end(), [&](auto & lhs, auto & rhs) { return lhs->pos().x() < rhs->pos().x(); });
vector<v2F> vals;
vals.reserve(points.size());
for (auto& p : points)
vals.push_back({ p->pos().x(), p->pos().y() });
Spline<float> spline(vals);
for (int j = 0; j < rect.width(); j++)
{
auto y = spline.Interpolate(j);
auto xdist = std::abs(j - e->pos().x());
auto ydist = std::abs(y - e->pos().y());
if (xdist < thresh && ydist < thresh)
{
double x = e->pos().x() / (double)width();
double y = (height() - e->pos().y()) / (double)height();
emit PointAddedSignal(m_Index, QPointF(x, y));
break;
}
}
}
}

View File

@ -37,35 +37,37 @@ public:
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 Set(Curves<float>& curves);
void SetTop(CurveIndex curveIndex);
Q_SIGNALS:
void PointChangedSignal(int curveIndex, int pointIndex, const QPointF& point);
void PointAddedSignal(size_t curveIndex, const QPointF& point);
void PointRemovedSignal(size_t curveIndex, int pointIndex);
protected:
virtual void paintEvent(QPaintEvent* e) override;
virtual void mousePressEvent(QMouseEvent* e) override;
size_t m_Index = 0;
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;
std::vector<EllipseItem*> m_AllP;
std::vector<EllipseItem*> m_RedP;
std::vector<EllipseItem*> m_GrnP;
std::vector<EllipseItem*> m_BluP;
QGraphicsLineItem* m_XLine;
QGraphicsLineItem* m_YLine;
QPen* m_Pens[4];
std::array<QPen*, 4> m_Pens;
QGraphicsScene m_Scene;
QRectF m_OriginalRect;
std::pair<EllipseItem*, EllipseItem*> m_Points[4];
std::array<std::vector<EllipseItem*>, 4> m_Points;
};
/// <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.
@ -116,7 +118,7 @@ protected:
/// <summary>
/// Overridden itemChange event to notify the parent control that it has moved.
/// Movement is also restriced to the scene rect.
/// Movement is also restricted 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>

View File

@ -184,6 +184,8 @@ bool DoubleSpinBox::eventFilter(QObject* o, QEvent* e)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
e->accept();
return true;
}
else if (!m_Settings->ToggleType() &&
me->type() == QMouseEvent::MouseButtonRelease &&
@ -191,12 +193,16 @@ bool DoubleSpinBox::eventFilter(QObject* o, QEvent* e)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
e->accept();
return true;
}
else if (!m_Settings->ToggleType() &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
e->accept();
return true;
}
else if (m_DoubleClick &&
((!m_Settings->ToggleType() && e->type() == QMouseEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) ||
@ -207,6 +213,7 @@ bool DoubleSpinBox::eventFilter(QObject* o, QEvent* e)
else
setValue(m_DoubleClickNonZero);
e->accept();
return true;
}
}
@ -246,11 +253,13 @@ bool DoubleSpinBox::eventFilter(QObject* o, QEvent* e)
}
}
e->accept();
return true;
}
}
else if (dynamic_cast<QKeyEvent*>(e))
{
e->accept();
return true;
}
}
@ -378,6 +387,31 @@ SpecialDoubleSpinBox::SpecialDoubleSpinBox(QWidget* p, int h, double step)
{
}
/// <summary>
/// Called when focus enters the spinner.
/// When leaving the spinner, the context menu was disabled so it doesn't pop up on
/// distant loctions on the screen when dragging with the right mouse button then releasing.
/// So re-enable it here just to ensure whenever they focus this control, the menu works.
/// </summary>
/// <param name="e">The event</param>
void SpecialDoubleSpinBox::enterEvent(QEvent* e)
{
this->setContextMenuPolicy(Qt::ActionsContextMenu);
DoubleSpinBox::enterEvent(e);
}
/// <summary>
/// Called when focus leaves the spinner.
/// When leaving the spinner, disable the context menu so it doesn't pop up on distant loctions on the screen
/// when dragging with the right mouse button then releasing.
/// </summary>
/// <param name="e">The event</param>
void SpecialDoubleSpinBox::leaveEvent(QEvent* e)
{
this->setContextMenuPolicy(Qt::PreventContextMenu);
DoubleSpinBox::leaveEvent(e);
}
/// <summary>
/// Event filter for taking special action on right click events.
/// </summary>

View File

@ -75,6 +75,8 @@ public:
virtual ~SpecialDoubleSpinBox() { }
protected:
virtual void enterEvent(QEvent* e) override;
virtual void leaveEvent(QEvent* e) override;
virtual bool eventFilter(QObject* o, QEvent* e) override;
};

View File

@ -35,14 +35,32 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF
connect(ui.FinalRenderScaleWidthRadioButton, SIGNAL(toggled(bool)), this, SLOT(OnScaleRadioButtonChanged(bool)), Qt::QueuedConnection);
connect(ui.FinalRenderScaleHeightRadioButton, SIGNAL(toggled(bool)), this, SLOT(OnScaleRadioButtonChanged(bool)), Qt::QueuedConnection);
connect(ui.FinalRenderDeviceTable, SIGNAL(cellChanged(int, int)), this, SLOT(OnDeviceTableCellChanged(int, int)), Qt::QueuedConnection);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, 1, m_WidthScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnWidthScaleChanged(double)), true, 1.0, 1.0, 1.0);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, 1, m_HeightScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnHeightScaleChanged(double)), true, 1.0, 1.0, 1.0);
m_WidthScaleSpin->setDecimals(3);
m_HeightScaleSpin->setDecimals(3);
m_WidthScaleSpin->setSuffix(" ( )");
m_HeightScaleSpin->setSuffix(" ( )");
m_WidthScaleSpin->SmallStep(0.001);
m_HeightScaleSpin->SmallStep(0.001);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, -1, m_WidthScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnWidthScaleChanged(double)), true, 1.0, 1.0, 1.0);
SetupSpinner<SpinBox, int>(ui.FinalRenderSizeTable, this, row, -1, m_WidthSpin, spinHeight, 10, std::numeric_limits<int>::max(), 10, SIGNAL(valueChanged(int)), SLOT(OnWidthChanged(int)), true, 1920, 1920, 1920);
SetupSpinner<DoubleSpinBox, double>(ui.FinalRenderSizeTable, this, row, -1, m_HeightScaleSpin, spinHeight, 0.001, 99.99, 0.1, SIGNAL(valueChanged(double)), SLOT(OnHeightScaleChanged(double)), true, 1.0, 1.0, 1.0);
SetupSpinner<SpinBox, int>(ui.FinalRenderSizeTable, this, row, -1, m_HeightSpin, spinHeight, 10, std::numeric_limits<int>::max(), 10, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)), true, 1080, 1080, 1080);
int spinsize = 120;
m_WidthScaleSpin->setDecimals(4);
m_HeightScaleSpin->setDecimals(4);
m_WidthScaleSpin->setFixedWidth(spinsize);
m_HeightScaleSpin->setFixedWidth(spinsize);
m_WidthScaleSpin->SmallStep(0.0001);
m_HeightScaleSpin->SmallStep(0.0001);
m_WidthSpin->setFixedWidth(spinsize);
m_HeightSpin->setFixedWidth(spinsize);
m_WidthSpinnerWidget = new DoubleIntSpinnerWidget(m_WidthScaleSpin, m_WidthSpin, ui.FinalRenderSizeTable);
m_WidthSpinnerWidget->m_DoubleSpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_WidthSpinnerWidget->m_SpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_WidthSpinnerWidget->setMinimumWidth(spinsize);
m_WidthSpinnerWidget->setMaximumWidth(spinsize);
ui.FinalRenderSizeTable->setCellWidget(0, 1, m_WidthSpinnerWidget);
//
m_HeightSpinnerWidget = new DoubleIntSpinnerWidget(m_HeightScaleSpin, m_HeightSpin, ui.FinalRenderSizeTable);
m_HeightSpinnerWidget->m_DoubleSpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_HeightSpinnerWidget->m_SpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_HeightSpinnerWidget->setMinimumWidth(spinsize);
m_HeightSpinnerWidget->setMaximumWidth(spinsize);
ui.FinalRenderSizeTable->setCellWidget(1, 1, m_HeightSpinnerWidget);
row = 0;
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 1000, 1000, 1000);
SetupSpinner<SpinBox, int> (table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 50, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000, 1000, 1000);
@ -139,6 +157,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF
ui.FinalRenderThreadPriorityComboBox->setCurrentIndex(Clamp<int>(m_Settings->FinalThreadPriority() / 25, 0, tpc));
#endif
ui.FinalRenderOpenCLSubBatchPctSpin->setValue(m_Settings->FinalOpenCLSubBatchPct());
m_QualitySpin->setValue(m_Settings->FinalQuality());
m_TemporalSamplesSpin->setValue(m_Settings->FinalTemporalSamples());
m_SupersampleSpin->setValue(m_Settings->FinalSupersample());
@ -188,6 +207,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF
w = SetTabOrder(this, w, ui.FinalRenderApplyToAllCheckBox);
w = SetTabOrder(this, w, ui.FinalRenderThreadCountSpin);
w = SetTabOrder(this, w, ui.FinalRenderThreadPriorityComboBox);
w = SetTabOrder(this, w, ui.FinalRenderOpenCLSubBatchPctSpin);
w = SetTabOrder(this, w, m_WidthScaleSpin);
w = SetTabOrder(this, w, m_HeightScaleSpin);
w = SetTabOrder(this, w, ui.FinalRenderScaleNoneRadioButton);
@ -260,6 +280,7 @@ int FractoriumFinalRenderDialog::ThreadPriority()
return ui.FinalRenderThreadPriorityComboBox->currentIndex() * 25;
}
#endif
double FractoriumFinalRenderDialog::OpenCLSubBatchPct() { return ui.FinalRenderOpenCLSubBatchPctSpin->value(); }
double FractoriumFinalRenderDialog::WidthScale() { return m_WidthScaleSpin->value(); }
double FractoriumFinalRenderDialog::HeightScale() { return m_HeightScaleSpin->value(); }
double FractoriumFinalRenderDialog::Quality() { return m_QualitySpin->value(); }
@ -294,6 +315,7 @@ FinalRenderGuiState FractoriumFinalRenderDialog::State()
state.m_Devices = Devices();
state.m_ThreadCount = ThreadCount();
state.m_ThreadPriority = ThreadPriority();
state.m_SubBatchPct = OpenCLSubBatchPct();
state.m_WidthScale = WidthScale();
state.m_HeightScale = HeightScale();
state.m_Quality = Quality();
@ -384,6 +406,7 @@ void FractoriumFinalRenderDialog::OnOpenCLCheckBoxStateChanged(int state)
{
bool checked = state == Qt::Checked;
ui.FinalRenderDeviceTable->setEnabled(checked);
ui.FinalRenderOpenCLSubBatchPctSpin->setEnabled(checked);
ui.FinalRenderThreadCountSpin->setEnabled(!checked);
ui.FinalRenderThreadPriorityLabel->setEnabled(!checked);
ui.FinalRenderThreadPriorityComboBox->setEnabled(!checked);
@ -462,11 +485,38 @@ void FractoriumFinalRenderDialog::OnApplyAllCheckBoxStateChanged(int state)
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnWidthScaleChanged(double d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
if (m_Controller.get())
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked())
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
}
}
/// <summary>
/// The width spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the height spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnWidthChanged(int d)
{
if (m_Controller.get())
{
m_Controller->SyncGuiToEmbers(m_WidthSpin->value(), m_HeightSpin->value());//Copy changed width value from gui to ember (height will be copied even though it hasn't changed).
m_Controller->SyncCurrentToSizeSpinners(true, false, true, false);//Compute how much the original width had to be scaled by to equal the new width and put the value in the width scale spinner.
if (ui.FinalRenderKeepAspectCheckBox->isChecked())
{
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());//Make the height scale spinner match the newly computed width scale spinner.
m_Controller->SyncGuiToEmbers(0, 0, false, true);//Scale height by the amount in the height scale spinner and assign the value to the ember height.
m_Controller->SyncCurrentToSizeSpinners(false, true, false, true);//Copy new height value from the ember to the height spinner.
}
}
if (SetMemory()) {}
}
/// <summary>
@ -477,11 +527,38 @@ void FractoriumFinalRenderDialog::OnWidthScaleChanged(double d)
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnHeightScaleChanged(double d)
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked() && m_Controller.get())
m_WidthScaleSpin->SetValueStealth(m_HeightScaleSpin->value());
if (m_Controller.get())
{
if (ui.FinalRenderKeepAspectCheckBox->isChecked())
m_WidthScaleSpin->SetValueStealth(m_HeightScaleSpin->value());
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
if (SetMemory())
m_Controller->SyncCurrentToSizeSpinners(false, true);
}
}
/// <summary>
/// The height spinner was changed, recompute required memory.
/// If the aspect ratio checkbox is checked, set the value of
/// the width spinner as well to be in proportion.
/// </summary>
/// <param name="d">Ignored</param>
void FractoriumFinalRenderDialog::OnHeightChanged(int d)
{
if (m_Controller.get())
{
m_Controller->SyncGuiToEmbers(m_WidthSpin->value(), m_HeightSpin->value());//Copy changed height value from gui to ember (width will be copied even though it hasn't changed).
m_Controller->SyncCurrentToSizeSpinners(true, false, false, true);//Compute how much the original height had to be scaled by to equal the new height and put the value in the height scale spinner.
if (ui.FinalRenderKeepAspectCheckBox->isChecked())
{
m_WidthScaleSpin->SetValueStealth(m_HeightScaleSpin->value());//Make the width scale spinner match the newly computed height scale spinner.
m_Controller->SyncGuiToEmbers(0, 0, true, false);//Scale width by the amount in the width scale spinner and assign the value to the ember width.
m_Controller->SyncCurrentToSizeSpinners(false, true, true, false);//Copy new width value from the ember to the width spinner.
}
}
if (SetMemory()) {}
}
/// <summary>
@ -492,8 +569,9 @@ void FractoriumFinalRenderDialog::OnHeightScaleChanged(double d)
void FractoriumFinalRenderDialog::OnKeepAspectCheckBoxStateChanged(int state)
{
if (state && m_Controller.get())
m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
m_HeightScaleSpin->setValue(m_WidthScaleSpin->value());
//m_HeightScaleSpin->SetValueStealth(m_WidthScaleSpin->value());
SetMemory();
}
@ -501,7 +579,7 @@ void FractoriumFinalRenderDialog::OnKeepAspectCheckBoxStateChanged(int state)
/// The scaling method radio button selection was changed.
/// </summary>
/// <param name="checked">The state of the radio button</param>
void FractoriumFinalRenderDialog::OnScaleRadioButtonChanged(bool checked)
void FractoriumFinalRenderDialog::OnScaleRadioButtonChanged(bool checked)//This is wrong. Does not react when scale is switched back to zero. Fix!//TODO
{
if (checked)
SetMemory();
@ -714,6 +792,8 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
if (m_Controller.get() && m_Controller->m_Run)//On Linux, this event will be called when the main window minimized/maximized while rendering, so filter it out.
return;
QString firstfile;
if (CreateControllerFromGUI(true))//Create controller if it does not exist, or if it does and the renderer is not running.
{
int index = int(m_Fractorium->m_Controller->Index()) + 1;
@ -727,6 +807,7 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
ember.m_Supersample = m_Settings->FinalSupersample();
ember.m_TemporalSamples = m_Settings->FinalTemporalSamples();
});//Copy the whole file, will take about 0.2ms per ember in the file.
firstfile = efi.m_Filename;
#else
Ember<float> ed;
EmberFile<float> efi;
@ -737,6 +818,7 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
ember.m_Supersample = m_Settings->FinalSupersample();
ember.m_TemporalSamples = m_Settings->FinalTemporalSamples();
});//Copy the whole file, will take about 0.2ms per ember in the file.
firstfile = efi.m_Filename;
#endif
m_Controller->SetEmberFile(efi, true);//Move the temp file into the final render controller.
ui.FinalRenderCurrentSpin->setMaximum(int(efi.Size()));
@ -758,6 +840,7 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
ui.FinalRenderDoAllCheckBox->setChecked(true);
ui.FinalRenderDoSequenceCheckBox->setChecked(true);
ui.FinalRenderApplyToAllCheckBox->setChecked(true);
m_PrefixEdit->setText(firstfile + "_");
}
ui.FinalRenderTextOutput->clear();

View File

@ -73,6 +73,7 @@ public:
uint Current();
uint ThreadCount();
int ThreadPriority();
double OpenCLSubBatchPct();
double WidthScale();
double HeightScale();
double Quality();
@ -94,7 +95,9 @@ public slots:
void OnCurrentSpinChanged(int d);
void OnApplyAllCheckBoxStateChanged(int state);
void OnWidthScaleChanged(double d);
void OnWidthChanged(int d);
void OnHeightScaleChanged(double d);
void OnHeightChanged(int d);
void OnKeepAspectCheckBoxStateChanged(int state);
void OnScaleRadioButtonChanged(bool checked);
void OnDeviceTableCellChanged(int row, int col);
@ -127,7 +130,11 @@ private:
int m_PathCellIndex;
Timing m_RenderTimer;
DoubleSpinBox* m_WidthScaleSpin;
SpinBox* m_WidthSpin;
DoubleSpinBox* m_HeightScaleSpin;
SpinBox* m_HeightSpin;
DoubleIntSpinnerWidget* m_WidthSpinnerWidget;
DoubleIntSpinnerWidget* m_HeightSpinnerWidget;
DoubleSpinBox* m_QualitySpin;
SpinBox* m_TemporalSamplesSpin;
SpinBox* m_SupersampleSpin;

View File

@ -418,11 +418,57 @@
</item>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="FinalRenderOpenCLSubBatchPctSpin">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>220</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The percentage of a sub batch to execute on each thread per kernel call when using OpenCL. Default: 0.025 (256 iters).&lt;/p&gt;&lt;p&gt;Increase this number for slightly faster render times.&lt;/p&gt;&lt;p&gt;Note that this can cause a crash and subsequent restart of the graphics driver if each kernel call takes too long. So reduce the value if you encounter such a problem.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>OpenCL Sub Batch Percent Per Thread </string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
@ -692,7 +738,7 @@
</widget>
</item>
<item>
<widget class="TableWidget" name="FinalRenderParamsTable">
<widget class="QTableWidget" name="FinalRenderParamsTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -890,6 +936,9 @@
<property name="text">
<string>Strips</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of sections to split rendering into. The first number is the value desired, and the second number in parentheses is the value actually used because it must divide evenly into the final image height.&lt;/p&gt;&lt;p&gt;Use this if you do not have enough memory to render a given size and supersample. You will know you are memory limited when you see a warning in the text box below.&lt;/p&gt;&lt;p&gt;Use this sparingly since the number of iterations required are scaled by the value in this field.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="3" column="1">
<property name="text">
@ -913,6 +962,9 @@
<property name="text">
<string>Iterations</string>
</property>
<property name="toolTip">
<string>The total number of iterations that will be done to complete a single image</string>
</property>
</item>
<item row="5" column="1">
<property name="text">
@ -1203,13 +1255,6 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TableWidget</class>
<extends>QTableWidget</extends>
<header>TableWidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>FinalRenderEarlyClipCheckBox</tabstop>
<tabstop>FinalRenderDoublePrecisionCheckBox</tabstop>
@ -1221,13 +1266,18 @@
<tabstop>FinalRenderDoSequenceCheckBox</tabstop>
<tabstop>FinalRenderPng16BitCheckBox</tabstop>
<tabstop>FinalRenderCurrentSpin</tabstop>
<tabstop>FinalRenderStopButton</tabstop>
<tabstop>FinalRenderStartButton</tabstop>
<tabstop>FinalRenderThreadCountSpin</tabstop>
<tabstop>FinalRenderThreadPriorityComboBox</tabstop>
<tabstop>FinalRenderOpenCLSubBatchPctSpin</tabstop>
<tabstop>FinalRenderApplyToAllCheckBox</tabstop>
<tabstop>FinalRenderKeepAspectCheckBox</tabstop>
<tabstop>FinalRenderScaleNoneRadioButton</tabstop>
<tabstop>FinalRenderScaleWidthRadioButton</tabstop>
<tabstop>FinalRenderScaleHeightRadioButton</tabstop>
<tabstop>FinalRenderScaleNoneRadioButton</tabstop>
<tabstop>FinalRenderKeepAspectCheckBox</tabstop>
<tabstop>FinalRenderTextOutput</tabstop>
<tabstop>FinalRenderStartButton</tabstop>
<tabstop>FinalRenderPauseButton</tabstop>
<tabstop>FinalRenderStopButton</tabstop>
<tabstop>FinalRenderCloseButton</tabstop>
</tabstops>
<resources/>

View File

@ -368,6 +368,7 @@ template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFil
/// Resets the rendering process.
/// </summary>
/// <param name="index">The index in the file from which to retrieve the ember</param>
/// <param name="verbatim">Unused</param>
template <typename T>
void FinalRenderEmberController<T>::SetEmber(size_t index, bool verbatim)
{
@ -420,6 +421,7 @@ bool FinalRenderEmberController<T>::Render()
/// </summary>
/// <param name="renderType">The type of render to create</param>
/// <param name="devices">The platform,device index pairs of the devices to use</param>
/// <param name="updatePreviews">Unused</param>
/// <param name="shared">True if shared with OpenGL, else false. Always false in this case.</param>
/// <returns>True if nothing went wrong, else false.</returns>
template <typename T>
@ -477,7 +479,7 @@ bool FinalRenderEmberController<T>::CreateRenderer(eRendererType renderType, con
/// Note this is only called on the primary renderer.
/// </summary>
/// <param name="ember">The ember currently being rendered</param>
/// <param name="foo">An extra dummy parameter</param>
/// <param name="foo">An extra dummy parameter, unused.</param>
/// <param name="fraction">The progress fraction from 0-100</param>
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
@ -527,17 +529,19 @@ void FinalRenderEmberController<T>::SyncCurrentToGui()
/// </summary>
/// <param name="widthOverride">Width override to use instead of scaling the original width</param>
/// <param name="heightOverride">Height override to use instead of scaling the original height</param>
/// <param name="dowidth">Whether to apply width adjustment to the ember</param>
/// <param name="doheight">Whether to apply height adjustment to the ember</param>
template <typename T>
void FinalRenderEmberController<T>::SyncGuiToEmbers(size_t widthOverride, size_t heightOverride)
void FinalRenderEmberController<T>::SyncGuiToEmbers(size_t widthOverride, size_t heightOverride, bool dowidth, bool doheight)
{
if (m_FinalRenderDialog->ApplyToAll())
{
for (auto& ember : m_EmberFile.m_Embers)
SyncGuiToEmber(ember, widthOverride, heightOverride);
SyncGuiToEmber(ember, widthOverride, heightOverride, dowidth, doheight);
}
else
{
SyncGuiToEmber(*m_Ember, widthOverride, heightOverride);
SyncGuiToEmber(*m_Ember, widthOverride, heightOverride, dowidth, doheight);
}
}
@ -556,6 +560,9 @@ bool FinalRenderEmberController<T>::SyncGuiToRenderer()
m_Renderer->YAxisUp(m_FinalRenderDialog->YAxisUp());
m_Renderer->ThreadCount(m_FinalRenderDialog->ThreadCount());
m_Renderer->Priority((eThreadPriority)m_FinalRenderDialog->ThreadPriority());
if (auto rendererCL = dynamic_cast<RendererCL<T, float>*>(m_Renderer.get()))
rendererCL->SubBatchPercentPerThread(m_FinalRenderDialog->OpenCLSubBatchPct());
}
else if (!m_Renderers.empty())
{
@ -566,6 +573,9 @@ bool FinalRenderEmberController<T>::SyncGuiToRenderer()
m_Renderers[i]->YAxisUp(m_FinalRenderDialog->YAxisUp());
m_Renderers[i]->ThreadCount(m_FinalRenderDialog->ThreadCount());
m_Renderers[i]->Priority((eThreadPriority)m_FinalRenderDialog->ThreadPriority());
if (auto rendererCL = dynamic_cast<RendererCL<T, float>*>(m_Renderers[i].get()))
rendererCL->SubBatchPercentPerThread(m_FinalRenderDialog->OpenCLSubBatchPct());
}
}
else
@ -583,19 +593,27 @@ bool FinalRenderEmberController<T>::SyncGuiToRenderer()
/// </summary>
/// <param name="scale">Whether to update the scale values</param>
/// <param name="size">Whether to update the size suffix text</param>
/// <param name="dowidth">Whether to apply width value to the width scale spinner</param>
/// <param name="doheight">Whether to apply height value to the height scale spinner</param>
template <typename T>
void FinalRenderEmberController<T>::SyncCurrentToSizeSpinners(bool scale, bool size)
void FinalRenderEmberController<T>::SyncCurrentToSizeSpinners(bool scale, bool size, bool doWidth, bool doHeight)
{
if (scale)
{
m_FinalRenderDialog->m_WidthScaleSpin->SetValueStealth(double(m_Ember->m_FinalRasW) / m_Ember->m_OrigFinalRasW);//Work backward to determine the scale.
m_FinalRenderDialog->m_HeightScaleSpin->SetValueStealth(double(m_Ember->m_FinalRasH) / m_Ember->m_OrigFinalRasH);
if (doWidth)
m_FinalRenderDialog->m_WidthScaleSpin->SetValueStealth(double(m_Ember->m_FinalRasW) / m_Ember->m_OrigFinalRasW);//Work backward to determine the scale.
if (doHeight)
m_FinalRenderDialog->m_HeightScaleSpin->SetValueStealth(double(m_Ember->m_FinalRasH) / m_Ember->m_OrigFinalRasH);
}
if (size)
{
m_FinalRenderDialog->m_WidthScaleSpin->setSuffix(" (" + ToString<qulonglong>(m_Ember->m_FinalRasW) + ")");
m_FinalRenderDialog->m_HeightScaleSpin->setSuffix(" (" + ToString<qulonglong>(m_Ember->m_FinalRasH) + ")");
if (doWidth)
m_FinalRenderDialog->m_WidthSpinnerWidget->m_SpinBox->SetValueStealth(m_Ember->m_FinalRasW);
if (doHeight)
m_FinalRenderDialog->m_HeightSpinnerWidget->m_SpinBox->SetValueStealth(m_Ember->m_FinalRasH);
}
}
@ -800,7 +818,7 @@ void FinalRenderEmberController<T>::HandleFinishedProgress()
/// </summary>
/// <param name="ember">The ember currently being rendered</param>
/// <param name="stats">The renderer stats</param>
/// <param name="pixels">The timer which was started at the beginning of the render</param>
/// <param name="renderTimer">The timer which was started at the beginning of the render</param>
template<typename T>
void FinalRenderEmberController<T>::RenderComplete(Ember<T>& ember, const EmberStats& stats, Timing& renderTimer)
{
@ -845,6 +863,7 @@ void FinalRenderEmberController<T>::RenderComplete(Ember<T>& ember, const EmberS
m_Settings->FinalExt(m_GuiState.m_Ext);
m_Settings->FinalThreadCount(m_GuiState.m_ThreadCount);
m_Settings->FinalThreadPriority(m_GuiState.m_ThreadPriority);
m_Settings->FinalOpenCLSubBatchPct(m_GuiState.m_SubBatchPct);
m_Settings->FinalQuality(m_GuiState.m_Quality);
m_Settings->FinalTemporalSamples(m_GuiState.m_TemporalSamples);
m_Settings->FinalSupersample(m_GuiState.m_Supersample);
@ -860,8 +879,10 @@ void FinalRenderEmberController<T>::RenderComplete(Ember<T>& ember, const EmberS
/// <param name="ember">The ember whose values will be modified</param>
/// <param name="widthOverride">Width override to use instead of scaling the original width</param>
/// <param name="heightOverride">Height override to use instead of scaling the original height</param>
/// <param name="dowidth">Whether to use the computed/overridden width value, or use the existing value in the ember</param>
/// <param name="doheight">Whether to use the computed/overridden height value, or use the existing value in the ember</param>
template <typename T>
void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t widthOverride, size_t heightOverride)
void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t widthOverride, size_t heightOverride, bool dowidth, bool doheight)
{
size_t w;
size_t h;
@ -879,8 +900,8 @@ void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t width
h = ember.m_OrigFinalRasH * hScale;
}
w = std::max<size_t>(w, 10);
h = std::max<size_t>(h, 10);
w = dowidth ? std::max<size_t>(w, 10) : ember.m_FinalRasW;
h = doheight ? std::max<size_t>(h, 10) : ember.m_FinalRasH;
ember.SetSizeAndAdjustScale(w, h, false, m_FinalRenderDialog->Scale());
ember.m_Quality = m_FinalRenderDialog->m_QualitySpin->value();
ember.m_Supersample = m_FinalRenderDialog->m_SupersampleSpin->value();
@ -973,7 +994,7 @@ QString FinalRenderEmberController<T>::CheckMemory(const tuple<size_t, size_t, s
}
if (!s.isEmpty())
s += "Rendering will most likely fail.";
s += "Rendering will most likely fail.\n\nMake strips > 1 to fix this. Strips must divide into the height evenly, and will also scale the number of iterations performed.";
return s;
}

View File

@ -39,6 +39,7 @@ struct FinalRenderGuiState
QList<QVariant> m_Devices;
uint m_ThreadCount;
int m_ThreadPriority;
double m_SubBatchPct;
double m_WidthScale;
double m_HeightScale;
double m_Quality;
@ -62,8 +63,8 @@ public:
virtual ~FinalRenderEmberControllerBase() { }
virtual void SyncCurrentToGui() { }
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) { }
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) { }
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0, bool dowidth = true, bool doheight = true) { }
virtual void SyncCurrentToSizeSpinners(bool scale, bool size, bool doWidth = true, bool doHeight = true) { }
virtual void ResetProgress(bool total = true) { }
virtual tuple<size_t, size_t, size_t> SyncAndComputeMemory() { return tuple<size_t, size_t, size_t>(0, 0, 0); }
virtual double OriginalAspect() { return 1; }
@ -120,8 +121,8 @@ public:
//Virtual functions overridden from FinalRenderEmberControllerBase.
virtual void SyncCurrentToGui() override;
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0) override;
virtual void SyncCurrentToSizeSpinners(bool scale, bool size) override;
virtual void SyncGuiToEmbers(size_t widthOverride = 0, size_t heightOverride = 0, bool dowidth = true, bool doheight = true) override;
virtual void SyncCurrentToSizeSpinners(bool scale, bool size, bool doWidth = true, bool doHeight = true) override;
virtual void ResetProgress(bool total = true) override;
virtual tuple<size_t, size_t, size_t> SyncAndComputeMemory() override;
virtual double OriginalAspect() override { return double(m_Ember->m_OrigFinalRasW) / m_Ember->m_OrigFinalRasH; }
@ -141,7 +142,7 @@ protected:
void SaveCurrentRender(Ember<T>& ember, const EmberImageComments& comments, vector<v4F>& pixels, size_t width, size_t height, bool png16Bit, bool transparency);
void RenderComplete(Ember<T>& ember);
void RenderComplete(Ember<T>& ember, const EmberStats& stats, Timing& renderTimer);
void SyncGuiToEmber(Ember<T>& ember, size_t widthOverride = 0, size_t heightOverride = 0);
void SyncGuiToEmber(Ember<T>& ember, size_t widthOverride = 0, size_t heightOverride = 0, bool dowidth = true, bool doheight = true);
bool SyncGuiToRenderer();
void SetProgressComplete(int val);

View File

@ -53,6 +53,12 @@ Fractorium::Fractorium(QWidget* p)
);
}
m_Urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first())
<< QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first())
<< QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first())
<< QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first())
<< QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first())
;
m_FontSize = 9;
m_VarSortMode = 1;//Sort by weight by default.
m_PaletteSortMode = 0;//Sort by palette ascending by default.
@ -238,6 +244,14 @@ Fractorium::~Fractorium()
m_Controller->SaveCurrentFileOnShutdown();
}
/// <summary>
/// Return the URLs used to determine the icons that show up in the location bar in all file/folder dialogs.
/// </summary>
QList<QUrl> Fractorium::Urls()
{
return m_Urls;
}
/// <summary>
/// Set the coordinate text in the status bar.
/// </summary>
@ -502,7 +516,7 @@ void Fractorium::dragEnterEvent(QDragEnterEvent* e)
QFileInfo fileInfo(localFile);
QString suf = fileInfo.suffix();
if (suf == "flam3" || suf == "flame" || suf == "xml")
if (suf == "flam3" || suf == "flame" || suf == "xml" || suf == "chaos")
{
e->accept();
break;
@ -541,7 +555,7 @@ void Fractorium::dropEvent(QDropEvent* e)
QFileInfo fileInfo(localFile);
QString suf = fileInfo.suffix();
if (suf == "flam3" || suf == "flame" || suf == "xml")
if (suf == "flam3" || suf == "flame" || suf == "xml" || suf == "chaos")
filenames << localFile;
}
}
@ -603,8 +617,9 @@ QStringList Fractorium::SetupOpenXmlDialog()
connect(m_OpenFileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->OpenXmlExt(filter); });
m_OpenFileDialog->setFileMode(QFileDialog::ExistingFiles);
m_OpenFileDialog->setAcceptMode(QFileDialog::AcceptOpen);
m_OpenFileDialog->setNameFilter("flam3 (*.flam3);;flame (*.flame);;xml (*.xml)");
m_OpenFileDialog->setNameFilter("flam3 (*.flam3);;flame (*.flame);;xml (*.xml);;chaos (*.chaos)");
m_OpenFileDialog->setWindowTitle("Open Flame");
m_OpenFileDialog->setSidebarUrls(m_Urls);
}
QStringList filenames;
@ -621,7 +636,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
#else
auto defaultFilter(m_Settings->OpenXmlExt());
auto filenames = QFileDialog::getOpenFileNames(this, tr("Open Flame"), m_Settings->OpenFolder(), tr("flam3(*.flam3);; flame(*.flame);; fml(*.xml)"), &defaultFilter);
auto filenames = QFileDialog::getOpenFileNames(this, tr("Open Flame"), m_Settings->OpenFolder(), tr("flam3(*.flam3);; flame(*.flame);; xml(*.xml);; chaos (*.chaos)"), &defaultFilter);
m_Settings->OpenXmlExt(defaultFilter);
if (!filenames.empty())
@ -659,6 +674,7 @@ QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
});
m_SaveFileDialog->setNameFilter("flam3 (*.flam3);;flame (*.flame);;xml (*.xml)");
m_SaveFileDialog->setWindowTitle("Save flame as xml");
m_SaveFileDialog->setSidebarUrls(m_Urls);
}
QString filename;
@ -714,6 +730,7 @@ QString Fractorium::SetupSaveImageDialog(const QString& defaultFilename)
m_SaveImageDialog->setNameFilter(".jpg;;.png;;.exr");
#endif
m_SaveImageDialog->setWindowTitle("Save image");
m_SaveImageDialog->setSidebarUrls(m_Urls);
}
QString filename;
@ -754,6 +771,7 @@ QString Fractorium::SetupSaveFolderDialog()
m_FolderDialog->setFileMode(QFileDialog::Directory);
m_FolderDialog->setOption(QFileDialog::ShowDirsOnly, true);
m_FolderDialog->setWindowTitle("Save to folder");
m_FolderDialog->setSidebarUrls(m_Urls);
}
QString filename;
@ -825,11 +843,11 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_DECurveSpin);
w = SetTabOrder(this, w, m_SbsSpin);//Flame iteration.
w = SetTabOrder(this, w, m_FuseSpin);
w = SetTabOrder(this, w, m_RandRangeSpin);
w = SetTabOrder(this, w, m_QualitySpin);
w = SetTabOrder(this, w, m_SupersampleSpin);
w = SetTabOrder(this, w, m_InterpTypeCombo);//Flame animation.
w = SetTabOrder(this, w, m_AffineInterpTypeCombo);
w = SetTabOrder(this, w, m_TemporalSamplesSpin);
w = SetTabOrder(this, w, m_TemporalFilterWidthSpin);
w = SetTabOrder(this, w, m_TemporalFilterTypeCombo);
w = SetTabOrder(this, ui.LibraryTree, ui.SequenceStartCountSpinBox);//Library.
@ -881,11 +899,11 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_PreY2Spin);
w = SetTabOrder(this, w, m_PreO1Spin);
w = SetTabOrder(this, w, m_PreO2Spin);
w = SetTabOrder(this, w, ui.PreFlipVerticalButton);
w = SetTabOrder(this, w, ui.PreCopyButton);
w = SetTabOrder(this, w, ui.PreFlipVerticalButton);
w = SetTabOrder(this, w, ui.PreResetButton);
w = SetTabOrder(this, w, ui.PrePasteButton);
w = SetTabOrder(this, w, ui.PreFlipHorizontalButton);
w = SetTabOrder(this, w, ui.PrePasteButton);
w = SetTabOrder(this, w, ui.PreRotate90CcButton);
w = SetTabOrder(this, w, ui.PreRotateCcButton);
w = SetTabOrder(this, w, ui.PreRotateCombo);
@ -901,6 +919,7 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, ui.PreScaleUpButton);
w = SetTabOrder(this, w, ui.PreRandomButton);
w = SetTabOrder(this, w, ui.ShowPreAffineCurrentRadio);
w = SetTabOrder(this, w, ui.ShowPreAffineSelectedRadio);
w = SetTabOrder(this, w, ui.ShowPreAffineAllRadio);
w = SetTabOrder(this, w, ui.SwapAffinesButton);
w = SetTabOrder(this, w, ui.PostAffineGroupBox);
@ -910,11 +929,11 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_PostY2Spin);
w = SetTabOrder(this, w, m_PostO1Spin);
w = SetTabOrder(this, w, m_PostO2Spin);
w = SetTabOrder(this, w, ui.PostFlipVerticalButton);
w = SetTabOrder(this, w, ui.PostCopyButton);
w = SetTabOrder(this, w, ui.PostFlipVerticalButton);
w = SetTabOrder(this, w, ui.PostResetButton);
w = SetTabOrder(this, w, ui.PostPasteButton);
w = SetTabOrder(this, w, ui.PostFlipHorizontalButton);
w = SetTabOrder(this, w, ui.PostPasteButton);
w = SetTabOrder(this, w, ui.PostRotate90CcButton);
w = SetTabOrder(this, w, ui.PostRotateCcButton);
w = SetTabOrder(this, w, ui.PostRotateCombo);
@ -930,6 +949,7 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, ui.PostScaleUpButton);
w = SetTabOrder(this, w, ui.PostRandomButton);
w = SetTabOrder(this, w, ui.ShowPostAffineCurrentRadio);
w = SetTabOrder(this, w, ui.ShowPostAffineSelectedRadio);
w = SetTabOrder(this, w, ui.ShowPostAffineAllRadio);
w = SetTabOrder(this, w, ui.PolarAffineCheckBox);
w = SetTabOrder(this, w, ui.LocalPivotRadio);
@ -940,6 +960,7 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, ui.RandomXaosButton);
w = SetTabOrder(this, w, ui.AddLayerButton);
w = SetTabOrder(this, w, ui.AddLayerSpinBox);
w = SetTabOrder(this, w, ui.TransposeXaosButton);
//Xforms xaos is done dynamically every time.
w = SetTabOrder(this, ui.PaletteFilenameCombo, m_PaletteHueSpin);//Palette.
w = SetTabOrder(this, w, m_PaletteContrastSpin);

View File

@ -99,6 +99,7 @@ public:
bool DrawXforms();
bool DrawImage();
bool DrawGrid();
QList<QUrl> Urls();
//Library.
void SyncFileCountToSequenceCount();
@ -214,6 +215,7 @@ public slots:
void OnGammaThresholdChanged(double d);
void OnVibrancyChanged(double d);
void OnHighlightPowerChanged(double d);
void OnK2Changed(double d);
void OnBackgroundColorButtonClicked(bool checked);
void OnColorSelected(const QColor& color);
void OnPaletteModeComboCurrentIndexChanged(int index);
@ -238,9 +240,9 @@ public slots:
void OnDEFilterCurveWidthChanged(double d);
void OnSbsChanged(int d);//Iteration.
void OnFuseChanged(int d);
void OnRandRangeChanged(double d);
void OnQualityChanged(double d);
void OnSupersampleChanged(int d);
void OnTemporalSamplesChanged(int d);
void OnAffineInterpTypeComboCurrentIndexChanged(int index);
void OnInterpTypeComboCurrentIndexChanged(int index);
@ -299,7 +301,7 @@ public slots:
void OnRandomColorIndicesButtonClicked(bool b);
void OnToggleColorIndicesButtonClicked(bool b);
void OnRandomColorSpeedButtonClicked(bool b);
void OnToggleColorSpeedButtonClicked(bool b);
void OnToggleColorSpeedsButtonClicked(bool b);
void OnXformColorSpeedChanged(double d);
void OnXformOpacityChanged(double d);
@ -308,6 +310,8 @@ public slots:
void OnXformRefPaletteResized(int logicalIndex, int oldSize, int newSize);
void OnResetCurvesButtonClicked(bool checked);
void OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point);
void OnCurvesPointAdded(size_t curveIndex, const QPointF& point);
void OnCurvesPointRemoved(size_t curveIndex, int pointIndex);
void OnCurvesAllRadioButtonToggled(bool checked);
void OnCurvesRedRadioButtonToggled(bool checked);
void OnCurvesGreenRadioButtonToggled(bool checked);
@ -330,8 +334,11 @@ public slots:
void OnClearXaosButtonClicked(bool checked);
void OnRandomXaosButtonClicked(bool checked);
void OnAddLayerButtonClicked(bool checked);
void OnTransposeXaosButtonClicked(bool checked);
void OnXaosRowDoubleClicked(int logicalIndex);
void OnXaosColDoubleClicked(int logicalIndex);
void OnXaosHScrollValueChanged(int value);
void OnXaosVScrollValueChanged(int value);
void OnXaosTableModelDataChanged(const QModelIndex& indexA, const QModelIndex& indexB);
//Palette.
@ -464,6 +471,7 @@ private:
DoubleSpinBox* m_GammaThresholdSpin;
DoubleSpinBox* m_VibrancySpin;
DoubleSpinBox* m_HighlightSpin;
DoubleSpinBox* m_K2Spin;
QPushButton* m_BackgroundColorButton;
StealthComboBox* m_PaletteModeCombo;
SpinBox* m_WidthSpin;//Geometry.
@ -487,9 +495,9 @@ private:
DoubleSpinBox* m_DECurveSpin;
SpinBox* m_SbsSpin;//Iteration.
SpinBox* m_FuseSpin;
DoubleSpinBox* m_RandRangeSpin;
DoubleSpinBox* m_QualitySpin;
SpinBox* m_SupersampleSpin;
SpinBox* m_TemporalSamplesSpin;
StealthComboBox* m_AffineInterpTypeCombo;
StealthComboBox* m_InterpTypeCombo;
@ -528,6 +536,7 @@ private:
//Xaos.
DoubleSpinBox* m_XaosSpinBox;
QStandardItemModel* m_XaosTableModel;
QStandardItemModel* m_AppliedXaosTableModel;
DoubleSpinBoxTableItemDelegate* m_XaosTableItemDelegate;
//Palette.
@ -553,6 +562,7 @@ private:
QTableWidgetItem* m_InfoFinalXformItem;
//Files.
QList<QUrl> m_Urls;
#ifndef __APPLE__
QFileDialog* m_SaveFileDialog = nullptr;
QFileDialog* m_SaveImageDialog = nullptr;
@ -582,6 +592,7 @@ private:
int m_VarSortMode;
int m_PaletteSortMode;
int m_PreviousPaletteRow;
int m_BgRow;
vector<byte> m_PreviewVec;
shared_ptr<OpenCLInfo> m_Info;
unique_ptr<FractoriumEmberControllerBase> m_Controller;

File diff suppressed because it is too large Load Diff

View File

@ -528,7 +528,7 @@ static QString BaseStyle()
"{\n"
"\tcolor: black;\n"
"\tbackground-color: lightgray;\n"
"\tborder: 0px solid darkgray;\n"
"\tborder: 1px solid darkgray;\n"
"\tborder-right: 1px solid gray;\n"
"\tpadding-top: 0px;\n"
"\tpadding-bottom: 0px;\n"

View File

@ -146,6 +146,7 @@ public:
virtual void GammaThresholdChanged(double d) { }
virtual void VibrancyChanged(double d) { }
virtual void HighlightPowerChanged(double d) { }
virtual void K2Changed(double d) { }
virtual void PaletteModeChanged(uint i) { }
virtual void WidthChanged(uint i) { }
virtual void HeightChanged(uint i) { }
@ -169,14 +170,16 @@ public:
virtual void DEFilterCurveWidthChanged(double d) { }
virtual void SbsChanged(int d) { }
virtual void FuseChanged(int d) { }
virtual void RandRangeChanged(double d) { }
virtual void QualityChanged(double d) { }
virtual void SupersampleChanged(int d) { }
virtual void TemporalSamplesChanged(int d) { }
virtual void AffineInterpTypeChanged(int i) { }
virtual void InterpTypeChanged(int i) { }
virtual void BackgroundChanged(const QColor& color) { }
virtual void ClearColorCurves(int i) { }
virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { }
virtual void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) { }
virtual void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) { }
//Xforms.
virtual void CurrentXformComboChanged(int index) { }
@ -210,7 +213,7 @@ public:
virtual void RandomColorIndicesButtonClicked() { }
virtual void ToggleColorIndicesButtonClicked() { }
virtual void RandomColorSpeedButtonClicked() { }
virtual void ToggleColorSpeedButtonClicked() { }
virtual void ToggleColorSpeedsButtonClicked() { }
virtual void XformColorSpeedChanged(double d) { }
virtual void XformOpacityChanged(double d) { }
virtual void XformDirectColorChanged(double d) { }
@ -230,10 +233,12 @@ public:
//Xaos.
virtual void FillXaos() { }
virtual void FillAppliedXaos() { }
virtual void XaosChanged(int x, int y, double val) { }
virtual void ClearXaos() { }
virtual void RandomXaos() { }
virtual void AddLayer(int xforms) { }
virtual void TransposeXaos() { }
//Palette.
virtual size_t InitPaletteList(const QString& s) { return 0; }
@ -421,6 +426,7 @@ public:
virtual void GammaThresholdChanged(double d) override;
virtual void VibrancyChanged(double d) override;
virtual void HighlightPowerChanged(double d) override;
virtual void K2Changed(double d) override;
virtual void PaletteModeChanged(uint i) override;
virtual void WidthChanged(uint i) override;
virtual void HeightChanged(uint i) override;
@ -444,14 +450,16 @@ public:
virtual void DEFilterCurveWidthChanged(double d) override;
virtual void SbsChanged(int d) override;
virtual void FuseChanged(int d) override;
virtual void RandRangeChanged(double d) override;
virtual void QualityChanged(double d) override;
virtual void SupersampleChanged(int d) override;
virtual void TemporalSamplesChanged(int d) override;
virtual void AffineInterpTypeChanged(int index) override;
virtual void InterpTypeChanged(int index) override;
virtual void BackgroundChanged(const QColor& col) override;
virtual void ClearColorCurves(int i) override;
virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override;
virtual void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) override;
virtual void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) override;
//Xforms.
virtual void CurrentXformComboChanged(int index) override;
@ -488,7 +496,7 @@ public:
virtual void RandomColorIndicesButtonClicked() override;
virtual void ToggleColorIndicesButtonClicked() override;
virtual void RandomColorSpeedButtonClicked() override;
virtual void ToggleColorSpeedButtonClicked() override;
virtual void ToggleColorSpeedsButtonClicked() override;
virtual void XformColorSpeedChanged(double d) override;
virtual void XformOpacityChanged(double d) override;
virtual void XformDirectColorChanged(double d) override;
@ -507,10 +515,12 @@ public:
//Xforms Xaos.
virtual void FillXaos() override;
virtual void FillAppliedXaos() override;
virtual void XaosChanged(int x, int y, double val) override;
virtual void ClearXaos() override;
virtual void RandomXaos() override;
virtual void AddLayer(int xforms) override;
virtual void TransposeXaos() override;
//Xforms Selection.
virtual QString MakeXformCaption(size_t i) override;
@ -612,9 +622,7 @@ public:
m_PreviewRun = false;
m_PreviewRenderer.Abort();
m_PreviewResult.cancel();
while (m_PreviewResult.isRunning())
QApplication::processEvents();
m_PreviewResult.waitForFinished();
}
bool EarlyClip()

View File

@ -189,8 +189,8 @@ void Fractorium::UpdateHistogramBounds()
if (auto r = m_Controller->Renderer())
{
ul.sprintf("UL: %3.3f, %3.3f", r->LowerLeftX(), r->UpperRightY());//These bounds include gutter padding.
ur.sprintf("UR: %3.3f, %3.3f", -r->LowerLeftX(), r->UpperRightY());
lr.sprintf("LR: %3.3f, %3.3f", -r->LowerLeftX(), r->LowerLeftY());
ur.sprintf("UR: %3.3f, %3.3f", r->UpperRightX(), r->UpperRightY());
lr.sprintf("LR: %3.3f, %3.3f", r->UpperRightX(), r->LowerLeftY());
ll.sprintf("LL: %3.3f, %3.3f", r->LowerLeftX(), r->LowerLeftY());
wh.sprintf("W x H: %4u x %4u", r->SuperRasW(), r->SuperRasH());
g.sprintf("%u", (uint)r->GutterWidth());

View File

@ -60,7 +60,7 @@ void FractoriumEmberController<T>::NewFlock(size_t count)
m_EmberFile.Clear();
m_EmberFile.m_Filename = EmberFile<T>::DefaultFilename();
vector<eVariationId> filteredVariations;
vector<eVariationId>& filteredVariationsRef = m_FilteredVariations;
vector<eVariationId>* filteredVariationsRef = &m_FilteredVariations;
auto& deviceNames = OpenCLInfo::Instance()->AllDeviceNames();
for (auto& dev : deviceNames)
@ -70,15 +70,18 @@ void FractoriumEmberController<T>::NewFlock(size_t count)
if (nv)//Nvidia cannot handle synth. It takes over a minute to compile and uses about 4GB of memory.
{
filteredVariations = m_FilteredVariations;
filteredVariationsRef = filteredVariations;
std::remove(filteredVariations.begin(), filteredVariations.end(), eVariationId::VAR_SYNTH);
std::remove(filteredVariations.begin(), filteredVariations.end(), eVariationId::VAR_PRE_SYNTH);
std::remove(filteredVariations.begin(), filteredVariations.end(), eVariationId::VAR_POST_SYNTH);
filteredVariations.erase(std::remove_if(filteredVariations.begin(), filteredVariations.end(),
[&](const eVariationId & id) -> bool
{
return id == eVariationId::VAR_SYNTH || id == eVariationId::VAR_PRE_SYNTH || id == eVariationId::VAR_POST_SYNTH;
}
), filteredVariations.end());
filteredVariationsRef = &filteredVariations;
}
for (size_t i = 0; i < count; i++)
{
m_SheepTools->Random(ember, filteredVariationsRef, static_cast<intmax_t>(QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedFrand<T>(-2, 2)), 0, 8);
m_SheepTools->Random(ember, *filteredVariationsRef, static_cast<intmax_t>(QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedFrand<T>(-2, 2)), 0, 8);
ParamsToEmber(ember);
ember.m_Index = i;
ember.m_Name = m_EmberFile.m_Filename.toStdString() + "_" + ToString(i + 1ULL).toStdString();
@ -892,7 +895,9 @@ void FractoriumEmberController<T>::ClearFlame()
}
}
m_Ember.m_Curves.Init();
FillXforms();
FillCurvesControl();
});
}

View File

@ -45,6 +45,8 @@ void Fractorium::InitPaletteUI()
connect(paletteTable->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(OnPaletteHeaderSectionClicked(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.CurvesView, SIGNAL(PointAddedSignal(size_t, const QPointF&)), this, SLOT(OnCurvesPointAdded(size_t, const QPointF&)), Qt::QueuedConnection);
connect(ui.CurvesView, SIGNAL(PointRemovedSignal(size_t, int)), this, SLOT(OnCurvesPointRemoved(size_t, int)), 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);
@ -208,6 +210,8 @@ void Fractorium::OnPaletteAdjust(int d) { m_Controller->PaletteAdjust(); }
template <typename T>
void FractoriumEmberController<T>::SetBasePaletteAndAdjust(const Palette<float>& palette)
{
//The temp palette is assigned the palette read when the file was parsed/saved. The user can apply adjustments on the GUI later.
//These adjustments will be applied to the temp palette, then assigned back to m_Ember.m_Palette.
m_TempPalette = palette;//Deep copy.
ApplyPaletteToEmber();//Copy temp palette to ember palette and apply adjustments.
UpdateAdjustedPaletteGUI(m_Ember.m_Palette);//Show the adjusted palette.
@ -288,7 +292,7 @@ void Fractorium::OnPreviewPaletteMouseReleased()
/// <param name="col">Ignored</param>
void Fractorium::OnPreviewPaletteCellDoubleClicked(int row, int col)
{
m_PreviewPaletteRotation = 0;
m_PreviewPaletteRotation = m_PreviewPaletteMouseDownRotation = 0;
m_PreviewPaletteMouseDown = false;
m_Controller->PaletteAdjust();
}
@ -335,7 +339,8 @@ void Fractorium::OnPaletteRandomSelectButtonClicked(bool checked)
uint i = 0;
int rowCount = ui.PaletteListTable->rowCount();
while (((i = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand(rowCount)) == uint(m_PreviousPaletteRow)) || i >= uint(rowCount));
if (rowCount > 1)//If only one palette in the current palette file, just use it.
while (((i = QTIsaac<ISAAC_SIZE, ISAAC_INT>::LockedRand(rowCount)) == uint(m_PreviousPaletteRow)) || i >= uint(rowCount));
if (checked)
OnPaletteCellDoubleClicked(i, 1);//Will clear the adjustments.
@ -539,6 +544,7 @@ void Fractorium::OnPaletteHeaderSectionClicked(int col)
/// </summary>
void Fractorium::ResetPaletteControls()
{
m_PreviewPaletteRotation = m_PreviewPaletteMouseDownRotation = 0;
m_PaletteHueSpin->SetValueStealth(0);
m_PaletteSaturationSpin->SetValueStealth(0);
m_PaletteBrightnessSpin->SetValueStealth(0);
@ -599,7 +605,7 @@ void Fractorium::OnResetCurvesButtonClicked(bool checked)
/// 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="curveIndex">The curve index, 0-3/</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>
@ -614,6 +620,49 @@ void FractoriumEmberController<T>::ColorCurveChanged(int curveIndex, int pointIn
void Fractorium::OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point) { m_Controller->ColorCurveChanged(curveIndex, pointIndex, point); }
/// <summary>
/// Remove curve point.
/// Called when right clicking on a color curve point.
/// 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./</param>
/// <param name="pointIndex">The point index within the selected curve.</param>
template <typename T>
void FractoriumEmberController<T>::ColorCurvesPointRemoved(size_t curveIndex, int pointIndex)
{
Update([&]
{
if (m_Ember.m_Curves.m_Points[curveIndex].size() > 2)
{
m_Ember.m_Curves.m_Points[curveIndex].erase(m_Ember.m_Curves.m_Points[curveIndex].begin() + pointIndex);
std::sort(m_Ember.m_Curves.m_Points[curveIndex].begin(), m_Ember.m_Curves.m_Points[curveIndex].end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; });
}
}, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY);
FillCurvesControl();
}
void Fractorium::OnCurvesPointRemoved(size_t curveIndex, int pointIndex) { m_Controller->ColorCurvesPointRemoved(curveIndex, pointIndex); }
/// <summary>
/// Add a curve point.
/// Called when clicking in between points on a color curve.
/// 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./</param>
/// <param name="pointIndex">The point to add to the selected curve.</param>
template <typename T>
void FractoriumEmberController<T>::ColorCurvesPointAdded(size_t curveIndex, const QPointF& point)
{
Update([&]
{
m_Ember.m_Curves.m_Points[curveIndex].push_back({ point.x(), point.y() });
std::sort(m_Ember.m_Curves.m_Points[curveIndex].begin(), m_Ember.m_Curves.m_Points[curveIndex].end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; });
}, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY);
FillCurvesControl();
}
void Fractorium::OnCurvesPointAdded(size_t curveIndex, const QPointF& point) { m_Controller->ColorCurvesPointAdded(curveIndex, 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.
@ -632,16 +681,7 @@ template <typename T>
void FractoriumEmberController<T>::FillCurvesControl()
{
m_Fractorium->ui.CurvesView->blockSignals(true);
for (auto i = 0; i < 4; i++)
{
for (auto 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->Set(m_Ember.m_Curves);
m_Fractorium->ui.CurvesView->blockSignals(false);
m_Fractorium->ui.CurvesView->update();
}

View File

@ -22,13 +22,21 @@ void Fractorium::InitParamsUI()
SetFixedTableHeader(ui.IterationTableHeader->horizontalHeader());
SetFixedTableHeader(ui.AnimationTableHeader->horizontalHeader());
//Color.
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_BrightnessSpin, spinHeight, 0.05, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnBrightnessChanged(double)), true, 4.0, 4.0, 4.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_GammaSpin, spinHeight, 1, 9999, 0.5, SIGNAL(valueChanged(double)), SLOT(OnGammaChanged(double)), true, 4.0, 4.0, 4.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_GammaThresholdSpin, spinHeight, 0, 10, 0.01, SIGNAL(valueChanged(double)), SLOT(OnGammaThresholdChanged(double)), true, 0.1, 0.1, 0.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_VibrancySpin, spinHeight, 0, 30, 0.01, SIGNAL(valueChanged(double)), SLOT(OnVibrancyChanged(double)), true, 1.0, 1.0, 0.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_HighlightSpin, spinHeight, -1.0, 10, 0.1, SIGNAL(valueChanged(double)), SLOT(OnHighlightPowerChanged(double)), true, 1.0, 1.0, -1.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_BrightnessSpin, spinHeight, 0.05, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnBrightnessChanged(double)), true, 4.0, 4.0, 4.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_GammaSpin, spinHeight, 1, 9999, 0.5, SIGNAL(valueChanged(double)), SLOT(OnGammaChanged(double)), true, 4.0, 4.0, 4.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_GammaThresholdSpin, spinHeight, 0, 10, 0.01, SIGNAL(valueChanged(double)), SLOT(OnGammaThresholdChanged(double)), true, 0.1, 0.1, 0.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_VibrancySpin, spinHeight, 0, 30, 0.01, SIGNAL(valueChanged(double)), SLOT(OnVibrancyChanged(double)), true, 1.0, 1.0, 0.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_HighlightSpin, spinHeight, -1.0, 10, 0.1, SIGNAL(valueChanged(double)), SLOT(OnHighlightPowerChanged(double)), true, 1.0, 1.0, -1.0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_K2Spin, spinHeight, 0, 10.0, 0.0001, SIGNAL(valueChanged(double)), SLOT(OnK2Changed(double)), true, 0, 0.0001, 0);
m_HighlightSpin->DoubleClickLowVal(-1.0);
m_GammaThresholdSpin->setDecimals(4);
int dec = 6;
m_BrightnessSpin->setDecimals(dec);
m_GammaSpin->setDecimals(dec);
m_GammaThresholdSpin->setDecimals(dec);
m_VibrancySpin->setDecimals(dec);
m_HighlightSpin->setDecimals(dec);
m_K2Spin->setDecimals(dec);
m_BgRow = row;
m_BackgroundColorButton = new QPushButton("...", table);
m_BackgroundColorButton->setMinimumWidth(21);
m_BackgroundColorButton->setMaximumWidth(21);
@ -48,7 +56,7 @@ void Fractorium::InitParamsUI()
SetupSpinner<SpinBox, int> (table, this, row, 1, m_HeightSpin, spinHeight, 10, 2048, 50, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)), true, height(), height(), height());
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_CenterXSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterXChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_CenterYSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterYChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 25, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RotateSpin, spinHeight, -180, 180, 10, SIGNAL(valueChanged(double)), SLOT(OnRotateChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0);
@ -66,20 +74,20 @@ void Fractorium::InitParamsUI()
m_Controller->ResizeAndScale(m_WidthSpin->DoubleClickNonZero(), val, eScaleType::SCALE_HEIGHT);
m_WidthSpin->SetValueStealth(m_WidthSpin->DoubleClickNonZero());
};
//Set w/h max values.
m_CenterXSpin->setDecimals(3);
m_CenterYSpin->setDecimals(3);
m_ZPosSpin->setDecimals(3);
m_PerspectiveSpin->setDecimals(4);
m_DepthBlurSpin->setDecimals(3);
dec = 4;
m_CenterXSpin->setDecimals(dec);
m_CenterYSpin->setDecimals(dec);
m_ZPosSpin->setDecimals(dec);
m_PerspectiveSpin->setDecimals(dec);
m_DepthBlurSpin->setDecimals(dec);
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
//Filter.
row = 0;
table = ui.FilterTable;
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_SpatialFilterWidthSpin, spinHeight, 0, 2, 0.1, SIGNAL(valueChanged(double)), SLOT(OnSpatialFilterWidthChanged(double)), true, 1.0, 1.0, 0);
m_SpatialFilterWidthSpin->DoubleClickLowVal(0.1);
comboVals = SpatialFilterCreator<float>::FilterTypes();
SetupCombo(table, this, row, 1, m_SpatialFilterTypeCombo, comboVals, SIGNAL(currentIndexChanged(const QString&)), SLOT(OnSpatialFilterTypeComboCurrentIndexChanged(const QString&)));
m_SpatialFilterTypeCombo->SetCurrentIndexStealth(0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_DEFilterMinRadiusSpin, spinHeight, 0, 25, 1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterMinRadiusWidthChanged(double)), true, 0, 0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_DEFilterMaxRadiusSpin, spinHeight, 0, 25, 1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterMaxRadiusWidthChanged(double)), true, 0.0, 9.0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_DECurveSpin, spinHeight, 0.15, 5, 0.1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterCurveWidthChanged(double)), true, 0.4, 0.4, 0.4);
@ -88,10 +96,15 @@ void Fractorium::InitParamsUI()
row = 0;
table = ui.IterationTable;
auto quality = m_Settings->OpenCL() ? m_Settings->OpenClQuality() : m_Settings->CpuQuality();
SetupSpinner<SpinBox, int>( table, this, row, 1, m_SbsSpin, spinHeight, 1000, 100000, 100, SIGNAL(valueChanged(int)), SLOT(OnSbsChanged(int)), true, DEFAULT_SBS, DEFAULT_SBS, DEFAULT_SBS);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_FuseSpin, spinHeight, 1, 1000, 5, SIGNAL(valueChanged(int)), SLOT(OnFuseChanged(int)), true, 15, 15, 15);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, quality, 10, 10);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 1, 1, 1);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_SbsSpin, spinHeight, 1000, 100000, 100, SIGNAL(valueChanged(int)), SLOT(OnSbsChanged(int)), true, DEFAULT_SBS, DEFAULT_SBS, DEFAULT_SBS);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_FuseSpin, spinHeight, 1, 1000, 5, SIGNAL(valueChanged(int)), SLOT(OnFuseChanged(int)), true, 15, 100, 15);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RandRangeSpin, spinHeight, 0.01, 1000, 0.1, SIGNAL(valueChanged(double)), SLOT(OnRandRangeChanged(double)), true, 1, 10, 1);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, quality, 10, 10);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 1, 2, 1);
m_RandRangeSpin->DoubleClickLowVal(1);
m_RandRangeSpin->setDecimals(4);
m_FuseSpin->DoubleClickLowVal(15);
m_SupersampleSpin->DoubleClickLowVal(1);
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
//Animation.
row = 0;
@ -106,10 +119,10 @@ void Fractorium::InitParamsUI()
comboVals.push_back("Log");
SetupCombo( table, this, row, 1, m_AffineInterpTypeCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnAffineInterpTypeComboCurrentIndexChanged(int)));
m_AffineInterpTypeCombo->SetCurrentIndexStealth(int(eAffineInterp::AFFINE_INTERP_LOG));
SetupSpinner<SpinBox, int>( table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 1, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1);
comboVals = TemporalFilterCreator<float>::FilterTypes();
SetupCombo( table, this, row, 1, m_TemporalFilterTypeCombo, comboVals, SIGNAL(currentIndexChanged(const QString&)), SLOT(OnTemporalFilterTypeComboCurrentIndexChanged(const QString&)));
m_TemporalFilterTypeCombo->SetCurrentIndexStealth(int(eTemporalFilterType::GAUSSIAN_TEMPORAL_FILTER));
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
}
@ -140,6 +153,7 @@ void FractoriumEmberController<T>::BrightnessChanged(double d)
ember.m_Brightness = d;
}, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll());
}
void Fractorium::OnBrightnessChanged(double d) { m_Controller->BrightnessChanged(d); }
/// <summary>
@ -203,6 +217,22 @@ template <typename T> void FractoriumEmberController<T>::HighlightPowerChanged(d
}
void Fractorium::OnHighlightPowerChanged(double d) { m_Controller->HighlightPowerChanged(d); }
/// <summary>
/// Set the k2 brightness value to be used for final accum.
/// Called when k2 is changed.
/// Resets the rendering process to the final accumulation stage.
/// </summary>
/// <param name="d">The k2 value</param>
template <typename T> void FractoriumEmberController<T>::K2Changed(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_K2 = d;
}, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll());
}
void Fractorium::OnK2Changed(double d) { m_Controller->K2Changed(d); }
/// <summary>
/// Show the color selection dialog.
/// Called when background color button is clicked.
@ -223,7 +253,7 @@ void Fractorium::OnBackgroundColorButtonClicked(bool checked)
template <typename T>
void FractoriumEmberController<T>::BackgroundChanged(const QColor& color)
{
int itemRow = 5;
auto itemRow = m_Fractorium->m_BgRow;
auto colorTable = m_Fractorium->ui.ColorTable;
colorTable->item(itemRow, 1)->setBackgroundColor(color);
auto r = ToString(color.red());
@ -553,6 +583,22 @@ template <typename T> void FractoriumEmberController<T>::SbsChanged(int d)
}
void Fractorium::OnSbsChanged(int d) { m_Controller->SbsChanged(d); }
/// <summary>
/// Set the range from which to chose the starting random points, as well as point resets due to bad points.
/// Called when the rand range spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The sub batch size value to set</param>
template <typename T> void FractoriumEmberController<T>::RandRangeChanged(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_RandPointRange = d;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
}
void Fractorium::OnRandRangeChanged(double d) { m_Controller->RandRangeChanged(d); }
/// <summary>
/// Set the number of samples to disregard for each sub batch.
/// Called when the fuse count spinner is changed.
@ -662,26 +708,6 @@ void FractoriumEmberController<T>::InterpTypeChanged(int i)
void Fractorium::OnInterpTypeComboCurrentIndexChanged(int index) { m_Controller->InterpTypeChanged(index); }
/// <summary>
/// Set the temporal samples to be used with animation.
/// Called when the temporal samples spinner is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The temporal samples value</param>
template <typename T>
void FractoriumEmberController<T>::TemporalSamplesChanged(int i)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_TemporalSamples = i;//This will be reset on every render to trick the renderer into not thinking it's doing an animation. So setting this has no real effect. Users should set it in the final render dialog when animating.
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_TemporalSamples = i;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());//Don't do anything until animation is implemented.
}
void Fractorium::OnTemporalSamplesChanged(int d) { m_Controller->TemporalSamplesChanged(d); }
/// <summary>
/// Set the temporal filter width to be used with animation.
/// Called when the temporal filter width spinner is changed.
@ -754,8 +780,9 @@ void FractoriumEmberController<T>::FillParamTablesAndPalette()
m_Fractorium->m_GammaThresholdSpin->SetValueStealth(m_Ember.m_GammaThresh);
m_Fractorium->m_VibrancySpin->SetValueStealth(m_Ember.m_Vibrancy);
m_Fractorium->m_HighlightSpin->SetValueStealth(m_Ember.m_HighlightPower);
m_Fractorium->m_K2Spin->SetValueStealth(m_Ember.m_K2);
m_Fractorium->m_ColorDialog->setCurrentColor(QColor(m_Ember.m_Background.r * 255, m_Ember.m_Background.g * 255, m_Ember.m_Background.b * 255));
m_Fractorium->ui.ColorTable->item(5, 1)->setBackgroundColor(m_Fractorium->m_ColorDialog->currentColor());
m_Fractorium->ui.ColorTable->item(m_Fractorium->m_BgRow, 1)->setBackgroundColor(m_Fractorium->m_ColorDialog->currentColor());
BackgroundChanged(m_Fractorium->m_ColorDialog->currentColor());
m_Fractorium->m_PaletteModeCombo->SetCurrentIndexStealth(int(m_Ember.m_PaletteMode));
m_Fractorium->m_WidthSpin->SetValueStealth(m_Ember.m_FinalRasW);//Geometry.
@ -779,31 +806,21 @@ void FractoriumEmberController<T>::FillParamTablesAndPalette()
m_Fractorium->m_DECurveSpin->SetValueStealth(m_Ember.m_CurveDE);
m_Fractorium->m_SbsSpin->SetValueStealth(m_Ember.m_SubBatchSize);//Iteration.
m_Fractorium->m_FuseSpin->SetValueStealth(m_Ember.m_FuseCount);
m_Fractorium->m_RandRangeSpin->SetValueStealth(m_Ember.m_RandPointRange);
m_Fractorium->m_QualitySpin->SetValueStealth(m_Ember.m_Quality);
m_Fractorium->m_SupersampleSpin->SetValueStealth(m_Ember.m_Supersample);
m_Fractorium->m_TemporalSamplesSpin->SetValueStealth(m_Ember.m_TemporalSamples);
m_Fractorium->m_AffineInterpTypeCombo->SetCurrentIndexStealth(int(m_Ember.m_AffineInterp));
m_Fractorium->m_InterpTypeCombo->SetCurrentIndexStealth(int(m_Ember.m_Interp));
//Palette related items:
//The temp palette is assigned the palette read when the file was parsed/saved. The user can apply adjustments on the GUI later.
//These adjustments will be applied to the temp palette, then assigned back to m_Ember.m_Palette.
//Normally, the temp palette is assigned whenever the user clicks on a palette cell. But since this is not
//called in response to that event, it is skipped here so must do it manually.
m_TempPalette = m_Ember.m_Palette;
//Palette controls are reset on each ember load. This means that if the palette was adjusted, saved, the selected ember
//changed to another, then back, the previously adjusted palette will now be considered the base, and all adjustments set to 0.
//To fix this, the caller must preserve the temp palette and the adjustment values and reassign. See Fractorium::CreateControllerFromOptions()
//for an example.
m_Fractorium->ResetPaletteControls();
auto temp = m_Ember.m_Palette.m_Filename;
if (temp.get())
m_Fractorium->SetPaletteFileComboIndex(*temp.get());
//Update the palette preview widget.
m_Fractorium->ResetPaletteControls();
//Since the controls were cleared above, the adjusted palette will be identical to the base palette.
//Callers can set, apply and display palette adjustments after this function exits if needed.
UpdateAdjustedPaletteGUI(m_Ember.m_Palette);//Updating the palette GUI will trigger a full render.
SetBasePaletteAndAdjust(m_Ember.m_Palette);//Updating the palette GUI will trigger a full render.
InitLockedScale();
}
@ -820,6 +837,7 @@ void FractoriumEmberController<T>::ParamsToEmber(Ember<T>& ember)
ember.m_GammaThresh = m_Fractorium->m_GammaThresholdSpin->value();
ember.m_Vibrancy = m_Fractorium->m_VibrancySpin->value();
ember.m_HighlightPower = m_Fractorium->m_HighlightSpin->value();
ember.m_K2 = m_Fractorium->m_K2Spin->value();
ember.m_Background.r = color.red() / 255.0;
ember.m_Background.g = color.green() / 255.0;
ember.m_Background.b = color.blue() / 255.0;
@ -845,9 +863,9 @@ void FractoriumEmberController<T>::ParamsToEmber(Ember<T>& ember)
ember.m_CurveDE = m_Fractorium->m_DECurveSpin->value();
ember.m_SubBatchSize = m_Fractorium->m_SbsSpin->value();
ember.m_FuseCount = m_Fractorium->m_FuseSpin->value();
ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value();
ember.m_Quality = m_Fractorium->m_QualitySpin->value();
ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();
ember.m_TemporalSamples = m_Fractorium->m_TemporalSamplesSpin->value();
ember.m_AffineInterp = eAffineInterp(m_Fractorium->m_AffineInterpTypeCombo->currentIndex());
ember.m_Interp = eInterp(m_Fractorium->m_InterpTypeCombo->currentIndex());
ember.SyncSize();

View File

@ -587,6 +587,9 @@ bool FractoriumEmberController<T>::CreateRenderer(eRendererType renderType, cons
if (m_Fractorium->m_QualitySpin->value() < val)
m_Fractorium->m_QualitySpin->setValue(val);
if (auto rendererCL = dynamic_cast<RendererCL<T, float>*>(m_Renderer.get()))
rendererCL->SubBatchPercentPerThread(float(s->OpenCLSubBatchPct()));
}
else
{

View File

@ -55,6 +55,16 @@ void FractoriumSettings::EnsureDefaults()
FinalThreadPriority(Clamp<int>(FinalThreadPriority(), (int)eThreadPriority::LOWEST, (int)eThreadPriority::HIGHEST));
CpuSubBatch(std::max(1u, CpuSubBatch()));
OpenCLSubBatch(std::max(1u, OpenCLSubBatch()));
if (OpenCLSubBatchPct() == 0)
OpenCLSubBatchPct(0.025);//Default to 256 iters per thread when using the default sub batch size of 10,240.
OpenCLSubBatchPct(Clamp(OpenCLSubBatchPct(), 0.01, 1.0));
if (FinalOpenCLSubBatchPct() == 0)
FinalOpenCLSubBatchPct(0.025);//Default to 256 iters per thread when using the default sub batch size of 10,240.
FinalOpenCLSubBatchPct(Clamp(FinalOpenCLSubBatchPct(), 0.01, 1.0));
RandomCount(std::max(1u, RandomCount()));
if (CpuQuality() == 0)
@ -118,74 +128,77 @@ void FractoriumSettings::EnsureDefaults()
/// Interactive renderer settings.
/// </summary>
bool FractoriumSettings::EarlyClip() { return value(EARLYCLIP).toBool(); }
void FractoriumSettings::EarlyClip(bool b) { setValue(EARLYCLIP, b); }
bool FractoriumSettings::EarlyClip() { return value(EARLYCLIP).toBool(); }
void FractoriumSettings::EarlyClip(bool b) { setValue(EARLYCLIP, b); }
bool FractoriumSettings::YAxisUp() { return value(YAXISUP).toBool(); }
void FractoriumSettings::YAxisUp(bool b) { setValue(YAXISUP, b); }
bool FractoriumSettings::YAxisUp() { return value(YAXISUP).toBool(); }
void FractoriumSettings::YAxisUp(bool b) { setValue(YAXISUP, b); }
bool FractoriumSettings::Transparency() { return value(TRANSPARENCY).toBool(); }
void FractoriumSettings::Transparency(bool b) { setValue(TRANSPARENCY, b); }
bool FractoriumSettings::Transparency() { return value(TRANSPARENCY).toBool(); }
void FractoriumSettings::Transparency(bool b) { setValue(TRANSPARENCY, b); }
bool FractoriumSettings::OpenCL() { return value(OPENCL).toBool(); }
void FractoriumSettings::OpenCL(bool b) { setValue(OPENCL, b); }
bool FractoriumSettings::OpenCL() { return value(OPENCL).toBool(); }
void FractoriumSettings::OpenCL(bool b) { setValue(OPENCL, b); }
bool FractoriumSettings::SharedTexture() { return value(SHAREDTEXTURE).toBool(); }
void FractoriumSettings::SharedTexture(bool b) { setValue(SHAREDTEXTURE, b); }
bool FractoriumSettings::SharedTexture() { return value(SHAREDTEXTURE).toBool(); }
void FractoriumSettings::SharedTexture(bool b) { setValue(SHAREDTEXTURE, b); }
bool FractoriumSettings::Double() { return value(DOUBLEPRECISION).toBool(); }
void FractoriumSettings::Double(bool b) { setValue(DOUBLEPRECISION, b); }
bool FractoriumSettings::Double() { return value(DOUBLEPRECISION).toBool(); }
void FractoriumSettings::Double(bool b) { setValue(DOUBLEPRECISION, b); }
bool FractoriumSettings::ShowAllXforms() { return value(SHOWALLXFORMS).toBool(); }
void FractoriumSettings::ShowAllXforms(bool b) { setValue(SHOWALLXFORMS, b); }
bool FractoriumSettings::ShowAllXforms() { return value(SHOWALLXFORMS).toBool(); }
void FractoriumSettings::ShowAllXforms(bool b) { setValue(SHOWALLXFORMS, b); }
bool FractoriumSettings::ShowXforms() { return value(SHOWXFORMS, QVariant::fromValue(true)).toBool(); }
void FractoriumSettings::ShowXforms(bool b) { setValue(SHOWXFORMS, b); }
bool FractoriumSettings::ShowXforms() { return value(SHOWXFORMS, QVariant::fromValue(true)).toBool(); }
void FractoriumSettings::ShowXforms(bool b) { setValue(SHOWXFORMS, b); }
bool FractoriumSettings::ShowGrid() { return value(SHOWGRID, QVariant::fromValue(true)).toBool(); }
void FractoriumSettings::ShowGrid(bool b) { setValue(SHOWGRID, b); }
bool FractoriumSettings::ShowGrid() { return value(SHOWGRID, QVariant::fromValue(true)).toBool(); }
void FractoriumSettings::ShowGrid(bool b) { setValue(SHOWGRID, b); }
bool FractoriumSettings::ToggleType() { return value(TOGGLETYPE).toBool(); }
void FractoriumSettings::ToggleType(bool b) { setValue(TOGGLETYPE, b); }
bool FractoriumSettings::ToggleType() { return value(TOGGLETYPE).toBool(); }
void FractoriumSettings::ToggleType(bool b) { setValue(TOGGLETYPE, b); }
bool FractoriumSettings::Png16Bit() { return value(PNG16BIT).toBool(); }
void FractoriumSettings::Png16Bit(bool b) { setValue(PNG16BIT, b); }
bool FractoriumSettings::Png16Bit() { return value(PNG16BIT).toBool(); }
void FractoriumSettings::Png16Bit(bool b) { setValue(PNG16BIT, b); }
bool FractoriumSettings::ContinuousUpdate() { return value(CONTUPDATE).toBool(); }
void FractoriumSettings::ContinuousUpdate(bool b) { setValue(CONTUPDATE, b); }
bool FractoriumSettings::ContinuousUpdate() { return value(CONTUPDATE).toBool(); }
void FractoriumSettings::ContinuousUpdate(bool b) { setValue(CONTUPDATE, b); }
QList<QVariant> FractoriumSettings::Devices() { return value(DEVICES).toList(); }
void FractoriumSettings::Devices(const QList<QVariant>& devices) { setValue(DEVICES, devices); }
QList<QVariant> FractoriumSettings::Devices() { return value(DEVICES).toList(); }
void FractoriumSettings::Devices(const QList<QVariant>& devices) { setValue(DEVICES, devices); }
uint FractoriumSettings::ThreadCount() { return value(THREADCOUNT).toUInt(); }
void FractoriumSettings::ThreadCount(uint i) { setValue(THREADCOUNT, i); }
uint FractoriumSettings::ThreadCount() { return value(THREADCOUNT).toUInt(); }
void FractoriumSettings::ThreadCount(uint i) { setValue(THREADCOUNT, i); }
bool FractoriumSettings::CpuDEFilter() { return value(CPUDEFILTER).toBool(); }
void FractoriumSettings::CpuDEFilter(bool b) { setValue(CPUDEFILTER, b); }
bool FractoriumSettings::CpuDEFilter() { return value(CPUDEFILTER).toBool(); }
void FractoriumSettings::CpuDEFilter(bool b) { setValue(CPUDEFILTER, b); }
bool FractoriumSettings::OpenCLDEFilter() { return value(OPENCLDEFILTER).toBool(); }
void FractoriumSettings::OpenCLDEFilter(bool b) { setValue(OPENCLDEFILTER, b); }
bool FractoriumSettings::OpenCLDEFilter() { return value(OPENCLDEFILTER).toBool(); }
void FractoriumSettings::OpenCLDEFilter(bool b) { setValue(OPENCLDEFILTER, b); }
uint FractoriumSettings::CpuSubBatch() { return value(CPUSUBBATCH).toUInt(); }
void FractoriumSettings::CpuSubBatch(uint i) { setValue(CPUSUBBATCH, i); }
uint FractoriumSettings::CpuSubBatch() { return value(CPUSUBBATCH).toUInt(); }
void FractoriumSettings::CpuSubBatch(uint i) { setValue(CPUSUBBATCH, i); }
uint FractoriumSettings::OpenCLSubBatch() { return value(OPENCLSUBBATCH).toUInt(); }
void FractoriumSettings::OpenCLSubBatch(uint i) { setValue(OPENCLSUBBATCH, i); }
double FractoriumSettings::OpenCLSubBatchPct() { return value(OPENCLSUBBATCHPCT).toDouble(); }
void FractoriumSettings::OpenCLSubBatchPct(double d) { setValue(OPENCLSUBBATCHPCT, d); }
uint FractoriumSettings::RandomCount() { return value(RANDOMCOUNT).toUInt(); }
void FractoriumSettings::RandomCount(uint i) { setValue(RANDOMCOUNT, i); }
uint FractoriumSettings::OpenCLSubBatch() { return value(OPENCLSUBBATCH).toUInt(); }
void FractoriumSettings::OpenCLSubBatch(uint i) { setValue(OPENCLSUBBATCH, i); }
uint FractoriumSettings::CpuQuality() { return value(CPUQUALITY).toUInt(); }
void FractoriumSettings::CpuQuality(uint i) { setValue(CPUQUALITY, i); }
uint FractoriumSettings::RandomCount() { return value(RANDOMCOUNT).toUInt(); }
void FractoriumSettings::RandomCount(uint i) { setValue(RANDOMCOUNT, i); }
uint FractoriumSettings::OpenClQuality() { return value(OPENCLQUALITY).toUInt(); }
void FractoriumSettings::OpenClQuality(uint i) { setValue(OPENCLQUALITY, i); }
uint FractoriumSettings::CpuQuality() { return value(CPUQUALITY).toUInt(); }
void FractoriumSettings::CpuQuality(uint i) { setValue(CPUQUALITY, i); }
bool FractoriumSettings::LoadLast() { return value(LOADLAST).toBool(); }
void FractoriumSettings::LoadLast(bool b) { setValue(LOADLAST, b); }
uint FractoriumSettings::OpenClQuality() { return value(OPENCLQUALITY).toUInt(); }
void FractoriumSettings::OpenClQuality(uint i) { setValue(OPENCLQUALITY, i); }
bool FractoriumSettings::RotateAndScale() { return value(ROTSCALE).toBool(); }
void FractoriumSettings::RotateAndScale(bool b) { setValue(ROTSCALE, b); }
bool FractoriumSettings::LoadLast() { return value(LOADLAST).toBool(); }
void FractoriumSettings::LoadLast(bool b) { setValue(LOADLAST, b); }
bool FractoriumSettings::RotateAndScale() { return value(ROTSCALE).toBool(); }
void FractoriumSettings::RotateAndScale(bool b) { setValue(ROTSCALE, b); }
/// <summary>
/// Sequence generation settings.
@ -253,62 +266,65 @@ void FractoriumSettings::VarFilterNonparam(int i) { setValue(VARFILTERNONPARAM,
/// Final render settings.
/// </summary>
bool FractoriumSettings::FinalEarlyClip() { return value(FINALEARLYCLIP).toBool(); }
void FractoriumSettings::FinalEarlyClip(bool b) { setValue(FINALEARLYCLIP, b); }
bool FractoriumSettings::FinalEarlyClip() { return value(FINALEARLYCLIP).toBool(); }
void FractoriumSettings::FinalEarlyClip(bool b) { setValue(FINALEARLYCLIP, b); }
bool FractoriumSettings::FinalYAxisUp() { return value(FINALYAXISUP).toBool(); }
void FractoriumSettings::FinalYAxisUp(bool b) { setValue(FINALYAXISUP, b); }
bool FractoriumSettings::FinalYAxisUp() { return value(FINALYAXISUP).toBool(); }
void FractoriumSettings::FinalYAxisUp(bool b) { setValue(FINALYAXISUP, b); }
bool FractoriumSettings::FinalTransparency() { return value(FINALTRANSPARENCY).toBool(); }
void FractoriumSettings::FinalTransparency(bool b) { setValue(FINALTRANSPARENCY, b); }
bool FractoriumSettings::FinalTransparency() { return value(FINALTRANSPARENCY).toBool(); }
void FractoriumSettings::FinalTransparency(bool b) { setValue(FINALTRANSPARENCY, b); }
bool FractoriumSettings::FinalOpenCL() { return value(FINALOPENCL).toBool(); }
void FractoriumSettings::FinalOpenCL(bool b) { setValue(FINALOPENCL, b); }
bool FractoriumSettings::FinalOpenCL() { return value(FINALOPENCL).toBool(); }
void FractoriumSettings::FinalOpenCL(bool b) { setValue(FINALOPENCL, b); }
bool FractoriumSettings::FinalDouble() { return value(FINALDOUBLEPRECISION).toBool(); }
void FractoriumSettings::FinalDouble(bool b) { setValue(FINALDOUBLEPRECISION, b); }
bool FractoriumSettings::FinalDouble() { return value(FINALDOUBLEPRECISION).toBool(); }
void FractoriumSettings::FinalDouble(bool b) { setValue(FINALDOUBLEPRECISION, b); }
bool FractoriumSettings::FinalSaveXml() { return value(FINALSAVEXML).toBool(); }
void FractoriumSettings::FinalSaveXml(bool b) { setValue(FINALSAVEXML, b); }
bool FractoriumSettings::FinalSaveXml() { return value(FINALSAVEXML).toBool(); }
void FractoriumSettings::FinalSaveXml(bool b) { setValue(FINALSAVEXML, b); }
bool FractoriumSettings::FinalDoAll() { return value(FINALDOALL).toBool(); }
void FractoriumSettings::FinalDoAll(bool b) { setValue(FINALDOALL, b); }
bool FractoriumSettings::FinalDoAll() { return value(FINALDOALL).toBool(); }
void FractoriumSettings::FinalDoAll(bool b) { setValue(FINALDOALL, b); }
bool FractoriumSettings::FinalDoSequence() { return value(FINALDOSEQUENCE).toBool(); }
void FractoriumSettings::FinalDoSequence(bool b) { setValue(FINALDOSEQUENCE, b); }
bool FractoriumSettings::FinalDoSequence() { return value(FINALDOSEQUENCE).toBool(); }
void FractoriumSettings::FinalDoSequence(bool b) { setValue(FINALDOSEQUENCE, b); }
bool FractoriumSettings::FinalPng16Bit() { return value(FINALPNG16BIT).toBool(); }
void FractoriumSettings::FinalPng16Bit(bool b) { setValue(FINALPNG16BIT, b); }
bool FractoriumSettings::FinalPng16Bit() { return value(FINALPNG16BIT).toBool(); }
void FractoriumSettings::FinalPng16Bit(bool b) { setValue(FINALPNG16BIT, b); }
bool FractoriumSettings::FinalKeepAspect() { return value(FINALKEEPASPECT).toBool(); }
void FractoriumSettings::FinalKeepAspect(bool b) { setValue(FINALKEEPASPECT, b); }
bool FractoriumSettings::FinalKeepAspect() { return value(FINALKEEPASPECT).toBool(); }
void FractoriumSettings::FinalKeepAspect(bool b) { setValue(FINALKEEPASPECT, b); }
uint FractoriumSettings::FinalScale() { return value(FINALSCALE).toUInt(); }
void FractoriumSettings::FinalScale(uint i) { setValue(FINALSCALE, i); }
uint FractoriumSettings::FinalScale() { return value(FINALSCALE).toUInt(); }
void FractoriumSettings::FinalScale(uint i) { setValue(FINALSCALE, i); }
QString FractoriumSettings::FinalExt() { return value(FINALEXT).toString(); }
void FractoriumSettings::FinalExt(const QString& s) { setValue(FINALEXT, s); }
QString FractoriumSettings::FinalExt() { return value(FINALEXT).toString(); }
void FractoriumSettings::FinalExt(const QString& s) { setValue(FINALEXT, s); }
QList<QVariant> FractoriumSettings::FinalDevices() { return value(FINALDEVICES).toList(); }
void FractoriumSettings::FinalDevices(const QList<QVariant>& devices) { setValue(FINALDEVICES, devices); }
QList<QVariant> FractoriumSettings::FinalDevices() { return value(FINALDEVICES).toList(); }
void FractoriumSettings::FinalDevices(const QList<QVariant>& devices) { setValue(FINALDEVICES, devices); }
uint FractoriumSettings::FinalThreadCount() { return value(FINALTHREADCOUNT).toUInt(); }
void FractoriumSettings::FinalThreadCount(uint i) { setValue(FINALTHREADCOUNT, i); }
uint FractoriumSettings::FinalThreadCount() { return value(FINALTHREADCOUNT).toUInt(); }
void FractoriumSettings::FinalThreadCount(uint i) { setValue(FINALTHREADCOUNT, i); }
int FractoriumSettings::FinalThreadPriority() { return value(FINALTHREADPRIORITY).toInt(); }
void FractoriumSettings::FinalThreadPriority(int i) { setValue(FINALTHREADPRIORITY, i); }
int FractoriumSettings::FinalThreadPriority() { return value(FINALTHREADPRIORITY).toInt(); }
void FractoriumSettings::FinalThreadPriority(int i) { setValue(FINALTHREADPRIORITY, i); }
uint FractoriumSettings::FinalQuality() { return value(FINALQUALITY).toUInt(); }
void FractoriumSettings::FinalQuality(uint i) { setValue(FINALQUALITY, i); }
double FractoriumSettings::FinalOpenCLSubBatchPct() { return value(FINALOPENCLSUBBATCHPCT).toDouble(); }
void FractoriumSettings::FinalOpenCLSubBatchPct(double d) { setValue(FINALOPENCLSUBBATCHPCT, d); }
uint FractoriumSettings::FinalTemporalSamples() { return value(FINALTEMPORALSAMPLES).toUInt(); }
void FractoriumSettings::FinalTemporalSamples(uint i) { setValue(FINALTEMPORALSAMPLES, i); }
uint FractoriumSettings::FinalQuality() { return value(FINALQUALITY).toUInt(); }
void FractoriumSettings::FinalQuality(uint i) { setValue(FINALQUALITY, i); }
uint FractoriumSettings::FinalSupersample() { return value(FINALSUPERSAMPLE).toUInt(); }
void FractoriumSettings::FinalSupersample(uint i) { setValue(FINALSUPERSAMPLE, i); }
uint FractoriumSettings::FinalTemporalSamples() { return value(FINALTEMPORALSAMPLES).toUInt(); }
void FractoriumSettings::FinalTemporalSamples(uint i) { setValue(FINALTEMPORALSAMPLES, i); }
size_t FractoriumSettings::FinalStrips() { return value(FINALSTRIPS).toULongLong(); }
void FractoriumSettings::FinalStrips(size_t i) { setValue(FINALSTRIPS, uint(i)); }
uint FractoriumSettings::FinalSupersample() { return value(FINALSUPERSAMPLE).toUInt(); }
void FractoriumSettings::FinalSupersample(uint i) { setValue(FINALSUPERSAMPLE, i); }
size_t FractoriumSettings::FinalStrips() { return value(FINALSTRIPS).toULongLong(); }
void FractoriumSettings::FinalStrips(size_t i) { setValue(FINALSTRIPS, uint(i)); }
/// <summary>
/// Xml file saving settings.

View File

@ -24,6 +24,7 @@
#define OPENCLDEFILTER "render/opencldefilter"
#define CPUSUBBATCH "render/cpusubbatch"
#define OPENCLSUBBATCH "render/openclsubbatch"
#define OPENCLSUBBATCHPCT "render/openclsubbatchpct"
#define RANDOMCOUNT "render/randomcount"
#define CPUQUALITY "render/cpuquality"
#define OPENCLQUALITY "render/openclquality"
@ -50,25 +51,26 @@
#define VARFILTERPARAM "varfilter/paramcheckbox"
#define VARFILTERNONPARAM "varfilter/nonparamcheckbox"
#define FINALEARLYCLIP "finalrender/earlyclip"
#define FINALYAXISUP "finalrender/finalyaxisup"
#define FINALTRANSPARENCY "finalrender/transparency"
#define FINALOPENCL "finalrender/opencl"
#define FINALDOUBLEPRECISION "finalrender/dp64"
#define FINALSAVEXML "finalrender/savexml"
#define FINALDOALL "finalrender/doall"
#define FINALDOSEQUENCE "finalrender/dosequence"
#define FINALPNG16BIT "finalrender/png16bit"
#define FINALKEEPASPECT "finalrender/keepaspect"
#define FINALSCALE "finalrender/scale"
#define FINALEXT "finalrender/ext"
#define FINALDEVICES "finalrender/devices"
#define FINALTHREADCOUNT "finalrender/threadcount"
#define FINALTHREADPRIORITY "finalrender/threadpriority"
#define FINALQUALITY "finalrender/quality"
#define FINALTEMPORALSAMPLES "finalrender/temporalsamples"
#define FINALSUPERSAMPLE "finalrender/supersample"
#define FINALSTRIPS "finalrender/strips"
#define FINALEARLYCLIP "finalrender/earlyclip"
#define FINALYAXISUP "finalrender/finalyaxisup"
#define FINALTRANSPARENCY "finalrender/transparency"
#define FINALOPENCL "finalrender/opencl"
#define FINALDOUBLEPRECISION "finalrender/dp64"
#define FINALSAVEXML "finalrender/savexml"
#define FINALDOALL "finalrender/doall"
#define FINALDOSEQUENCE "finalrender/dosequence"
#define FINALPNG16BIT "finalrender/png16bit"
#define FINALKEEPASPECT "finalrender/keepaspect"
#define FINALSCALE "finalrender/scale"
#define FINALEXT "finalrender/ext"
#define FINALDEVICES "finalrender/devices"
#define FINALTHREADCOUNT "finalrender/threadcount"
#define FINALTHREADPRIORITY "finalrender/threadpriority"
#define FINALOPENCLSUBBATCHPCT "finalrender/openclsubbatchpct"
#define FINALQUALITY "finalrender/quality"
#define FINALTEMPORALSAMPLES "finalrender/temporalsamples"
#define FINALSUPERSAMPLE "finalrender/supersample"
#define FINALSTRIPS "finalrender/strips"
#define XMLWIDTH "xml/width"
#define XMLHEIGHT "xml/height"
@ -157,6 +159,9 @@ public:
uint CpuSubBatch();
void CpuSubBatch(uint i);
double OpenCLSubBatchPct();
void OpenCLSubBatchPct(double d);
uint OpenCLSubBatch();
void OpenCLSubBatch(uint i);
@ -274,6 +279,9 @@ public:
int FinalThreadPriority();
void FinalThreadPriority(int b);
double FinalOpenCLSubBatchPct();
void FinalOpenCLSubBatchPct(double d);
uint FinalQuality();
void FinalQuality(uint i);

View File

@ -128,6 +128,8 @@ void Fractorium::OnActionStartStopRenderer(bool checked)
/// <param name="checked">Check state, show editor if true, else hide.</param>
void Fractorium::OnActionDrawXforms(bool checked)
{
m_Settings->ShowXforms(checked);
if (!ui.ActionDrawImage->isChecked() && !ui.ActionDrawXforms->isChecked())
ui.ActionDrawImage->setChecked(true);

View File

@ -18,13 +18,17 @@ void Fractorium::InitXaosUI()
m_XaosSpinBox->setDecimals(XAOS_PREC);
m_XaosSpinBox->setObjectName("XaosSpinBox");
m_XaosTableModel = nullptr;
m_AppliedXaosTableModel = nullptr;
m_XaosTableItemDelegate = new DoubleSpinBoxTableItemDelegate(m_XaosSpinBox, this);
connect(m_XaosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnXaosChanged(double)), Qt::QueuedConnection);
connect(ui.ClearXaosButton, SIGNAL(clicked(bool)), this, SLOT(OnClearXaosButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.RandomXaosButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomXaosButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.TransposeXaosButton, SIGNAL(clicked(bool)), this, SLOT(OnTransposeXaosButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.AddLayerButton, SIGNAL(clicked(bool)), this, SLOT(OnAddLayerButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.XaosTableView->verticalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnXaosRowDoubleClicked(int)), Qt::QueuedConnection);
connect(ui.XaosTableView->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(OnXaosColDoubleClicked(int)), Qt::QueuedConnection);
connect(ui.XaosTableView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(OnXaosHScrollValueChanged(int)), Qt::QueuedConnection);
connect(ui.XaosTableView->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(OnXaosVScrollValueChanged(int)), Qt::QueuedConnection);
}
/// <summary>
@ -49,6 +53,62 @@ void FractoriumEmberController<T>::FillXaos()
m_Fractorium->ui.XaosTableView->resizeColumnsToContents();
}
/// <summary>
/// Fill the xaos table with the xaos values applied to the xform weights from the ember.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::FillAppliedXaos()
{
m_Ember.CalcNormalizedWeights(m_NormalizedWeights);
for (int i = 0, count = int(XformCount()); i < count; i++)//Column.
{
if (auto xform = m_Ember.GetXform(i))
{
T norm = 0;
double start = 0, offset = 0;
auto tempweights = m_NormalizedWeights;
for (int j = 0; j < count; j++)//Row.
{
tempweights[j] *= xform->Xaos(j);
QModelIndex index = m_Fractorium->m_AppliedXaosTableModel->index(j, i, QModelIndex());//j and i are intentionally swapped here.
m_Fractorium->m_AppliedXaosTableModel->setData(index, TruncPrecision(xform->Xaos(j) * xform->m_Weight, 4));//Applied xaos is just a read only table for display purposes.
}
QPixmap pixmap(m_Fractorium->ui.XaosAppliedTableView->columnWidth(i) - 8, m_Fractorium->ui.XaosTableView->rowHeight(0) * count);
QPainter painter(&pixmap);
auto twi = new QTableWidgetItem();
for (auto& w : tempweights) norm += w;
for (auto& w : tempweights) w = norm == T(0) ? T(0) : w / norm;
if (norm)
{
for (size_t i = 0; i < tempweights.size() && offset <= pixmap.height(); i++)
{
offset = std::min<T>(offset + tempweights[i] * pixmap.height(), pixmap.height());
painter.fillRect(0, start, pixmap.width(), offset, m_Fractorium->m_XformComboColors[i % XFORM_COLOR_COUNT]);
start = offset;
}
}
else
{
painter.fillRect(0, 0, pixmap.width(), pixmap.height(), m_Fractorium->m_XformComboColors[0]);
}
twi->setData(Qt::DecorationRole, pixmap);
m_Fractorium->ui.XaosDistVizTableWidget->setItem(0, i, twi);
}
}
m_Fractorium->ui.XaosDistVizTableWidget->resizeRowsToContents();
m_Fractorium->ui.XaosDistVizTableWidget->resizeColumnsToContents();
m_Fractorium->ui.XaosAppliedTableView->resizeRowsToContents();
m_Fractorium->ui.XaosAppliedTableView->resizeColumnsToContents();
}
/// <summary>
/// Set the xaos value.
/// Called when any xaos spinner is changed.
@ -68,7 +128,10 @@ void FractoriumEmberController<T>::XaosChanged(int x, int y, double val)
if (auto xform = m_Ember.GetXform(x))
if (!IsClose<T>(newVal, xform->Xaos(y), T(1e-7)))
{
Update([&] { xform->SetXaos(y, newVal); });
FillAppliedXaos();
}
}
void Fractorium::OnXaosChanged(double d)
@ -91,13 +154,14 @@ void Fractorium::OnXaosTableModelDataChanged(const QModelIndex& indexA, const QM
void Fractorium::FillXaosTable()
{
int count = int(m_Controller->XformCount());
QStringList hl, vl;
QStringList hl, vl, blanks;
auto oldModel = std::make_unique<QStandardItemModel>(m_XaosTableModel);
hl.reserve(count);
vl.reserve(count);
blanks.push_back("");
m_XaosTableModel = new QStandardItemModel(count, count, this);
m_AppliedXaosTableModel = new QStandardItemModel(count, count, this);
connect(m_XaosTableModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(OnXaosTableModelDataChanged(QModelIndex, QModelIndex)));
ui.XaosTableView->blockSignals(true);
for (int i = 0; i < count; i++)
{
@ -108,14 +172,30 @@ void Fractorium::FillXaosTable()
m_XaosTableModel->setHorizontalHeaderLabels(hl);
m_XaosTableModel->setVerticalHeaderLabels(vl);
m_AppliedXaosTableModel->setHorizontalHeaderLabels(hl);
m_AppliedXaosTableModel->setVerticalHeaderLabels(vl);
ui.XaosDistVizTableWidget->setRowCount(1);
ui.XaosDistVizTableWidget->setColumnCount(count);
ui.XaosDistVizTableWidget->setHorizontalHeaderLabels(hl);
ui.XaosDistVizTableWidget->setVerticalHeaderLabels(blanks);
ui.XaosDistVizTableWidget->verticalHeader()->setSectionsClickable(false);
ui.XaosDistVizTableWidget->horizontalHeader()->setSectionsClickable(false);
ui.XaosTableView->setModel(m_XaosTableModel);
ui.XaosTableView->setItemDelegate(m_XaosTableItemDelegate);
ui.XaosAppliedTableView->setModel(m_AppliedXaosTableModel);
ui.XaosTableView->setItemDelegate(m_XaosTableItemDelegate);//No need for a delegate on the applied table because it's read-only.
ui.XaosDistVizTableWidget->verticalHeader()->setFixedWidth(ui.XaosTableView->verticalHeader()->width());
SetTabOrder(this, ui.ClearXaosButton, ui.RandomXaosButton);
ui.XaosDistVizTableWidget->setRowHeight(0, ui.XaosTableView->rowHeight(0) * count);
m_Controller->FillXaos();
ui.XaosTableView->blockSignals(false);
m_Controller->FillAppliedXaos();
//Needed to get the dark stylesheet to correctly color the top left corner button.
auto widgetList = ui.XaosTableView->findChildren<QAbstractButton*>();
for (auto& it : widgetList)
it->setEnabled(true);
widgetList = ui.XaosAppliedTableView->findChildren<QAbstractButton*>();
for (auto& it : widgetList)
it->setEnabled(true);
}
@ -128,6 +208,7 @@ void FractoriumEmberController<T>::ClearXaos()
{
Update([&] { m_Ember.ClearXaos(); });
FillXaos();
FillAppliedXaos();
}
void Fractorium::OnClearXaosButtonClicked(bool checked) { m_Controller->ClearXaos(); }
@ -143,21 +224,21 @@ void FractoriumEmberController<T>::RandomXaos()
{
Update([&]
{
for (size_t i = 0; i < m_Ember.XformCount(); i++)
size_t i = 0;
while (auto xform = m_Ember.GetXform(i++))
{
if (auto xform = m_Ember.GetXform(i))
for (size_t j = 0; j < m_Ember.XformCount(); j++)
{
for (size_t j = 0; j < m_Ember.XformCount(); j++)
{
if (m_Rand.RandBit())
xform->SetXaos(j, T(m_Rand.RandBit()));
else
xform->SetXaos(j, m_Rand.Frand<T>(0, 3));
}
if (m_Rand.RandBit())
xform->SetXaos(j, T(m_Rand.RandBit()));
else
xform->SetXaos(j, TruncPrecision(m_Rand.Frand<T>(0, 3), 3));
}
}
});
FillXaos();
FillAppliedXaos();
}
void Fractorium::OnRandomXaosButtonClicked(bool checked) { m_Controller->RandomXaos(); }
@ -169,6 +250,7 @@ void Fractorium::OnRandomXaosButtonClicked(bool checked) { m_Controller->RandomX
/// From existing to new: 0.
/// From new to existing: 0.
/// From new to new: 1.
/// Resets the rendering process.
/// </summary>
/// <param name="xforms">The number of new xforms to add to create the layer</param>
template <typename T>
@ -186,6 +268,41 @@ void FractoriumEmberController<T>::AddLayer(int xforms)
void Fractorium::OnAddLayerButtonClicked(bool checked) { m_Controller->AddLayer(ui.AddLayerSpinBox->value()); }
/// <summary>
/// Flip the row and column values of the xaos table.
/// Resets the rendering process.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::TransposeXaos()
{
Update([&]
{
size_t i = 0, j = 0;
vector<vector<double>> tempxaos;
tempxaos.reserve(m_Ember.XformCount());
while (auto xform = m_Ember.GetXform(i++))
{
vector<double> tempvec;
tempvec.reserve(m_Ember.XformCount());
for (j = 0; j < m_Ember.XformCount(); j++)
tempvec.push_back(xform->Xaos(j));
tempxaos.push_back(std::move(tempvec));
}
for (j = 0; j < tempxaos.size(); j++)
for (i = 0; i < tempxaos[j].size(); i++)
if (auto xform = m_Ember.GetXform(i))
xform->SetXaos(j, T(tempxaos[j][i]));
});
FillXaos();
FillAppliedXaos();
}
void Fractorium::OnTransposeXaosButtonClicked(bool checked) { m_Controller->TransposeXaos(); }
/// <summary>
/// Toggle all xaos values in one row on left mouse button double click and resize all cells to fit their data.
/// Skip toggling and only refit on right mouse button double click.
@ -201,6 +318,7 @@ void Fractorium::OnXaosRowDoubleClicked(int logicalIndex)
ui.XaosTableView->resizeRowsToContents();
ui.XaosTableView->resizeColumnsToContents();
m_Controller->FillAppliedXaos();
}
/// <summary>
@ -218,6 +336,33 @@ void Fractorium::OnXaosColDoubleClicked(int logicalIndex)
ui.XaosTableView->resizeRowsToContents();
ui.XaosTableView->resizeColumnsToContents();
m_Controller->FillAppliedXaos();
}
/// <summary>
/// Take the value of the horizontal scrollbar on the xaos table and set the same
/// horizontal scroll bar position on XaosDistVizTableWidget and XaosAppliedTableView.
/// This allows them to easily see the same part of all three tables at the same time
/// when there are more xforms than can fit on the screen at once.
/// </summary>
/// <param name="value">The value of the xaos table horizontal scroll bar</param>
void Fractorium::OnXaosHScrollValueChanged(int value)
{
ui.XaosDistVizTableWidget->horizontalScrollBar()->setValue(value);
ui.XaosAppliedTableView->horizontalScrollBar()->setValue(value);
}
/// <summary>
/// Take the value of the vertical scrollbar on the xaos table and set the same
/// vertical scroll bar position on XaosDistVizTableWidget and XaosAppliedTableView.
/// This allows them to easily see the same part of all three tables at the same time
/// when there are more xforms than can fit on the screen at once.
/// </summary>
/// <param name="value">The value of the xaos table vertical scroll bar</param>
void Fractorium::OnXaosVScrollValueChanged(int value)
{
ui.XaosDistVizTableWidget->verticalScrollBar()->setValue(value);
ui.XaosAppliedTableView->verticalScrollBar()->setValue(value);
}
template class FractoriumEmberController<float>;

View File

@ -24,7 +24,6 @@ void Fractorium::InitXformsUI()
m_XformWeightSpinnerButtonWidget = new SpinnerLabelButtonWidget(m_XformWeightSpin, "=", 20, 19, ui.XformWeightNameTable);
m_XformWeightSpinnerButtonWidget->m_SpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_XformWeightSpinnerButtonWidget->m_Label->setStyleSheet("border: 0px;");
m_XformWeightSpinnerButtonWidget->m_Label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_XformWeightSpinnerButtonWidget->m_Label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_XformWeightSpinnerButtonWidget->m_Button->setToolTip("Equalize weights");
m_XformWeightSpinnerButtonWidget->m_Button->setStyleSheet("text-align: center center");
@ -380,8 +379,11 @@ void FractoriumEmberController<T>::XformWeightChanged(double d)
xform->m_Weight = d;
}, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL);
SetNormalizedWeightText(CurrentXform());
FillAppliedXaos();
}
void Fractorium::OnXformWeightChanged(double d) { m_Controller->XformWeightChanged(d); }
/// <summary>
/// Equalize the weights of all xforms in the ember.
/// </summary>
@ -393,8 +395,11 @@ void FractoriumEmberController<T>::EqualizeWeights()
m_Ember.EqualizeWeights();
m_Fractorium->m_XformWeightSpin->setValue(xform->m_Weight);//Will trigger an update, so pass false to updateRender below.
}, eXformUpdate::UPDATE_CURRENT, false);
FillAppliedXaos();
}
void Fractorium::OnEqualWeightButtonClicked(bool checked) { m_Controller->EqualizeWeights(); }
/// <summary>
/// Set the name of the current xform.
/// Update the corresponding xform checkbox text with the name.

View File

@ -667,9 +667,9 @@ void FractoriumEmberController<T>::FillAffineWithXform(Xform<T>* xform, bool pre
if (m_Fractorium->ui.PolarAffineCheckBox->isChecked())
{
spinners[0]->SetValueStealth(RAD_2_DEG * std::atan2(affine.D(), affine.A()));
spinners[1]->SetValueStealth(RAD_2_DEG * std::atan2(affine.E(), affine.B()));
spinners[2]->SetValueStealth(RAD_2_DEG * std::atan2(affine.F(), affine.C()));
spinners[0]->SetValueStealth(NormalizeDeg360(RAD_2_DEG * std::atan2(affine.D(), affine.A())));
spinners[1]->SetValueStealth(NormalizeDeg360(RAD_2_DEG * std::atan2(affine.E(), affine.B())));
spinners[2]->SetValueStealth(NormalizeDeg360(RAD_2_DEG * std::atan2(affine.F(), affine.C())));
spinners[3]->SetValueStealth(VarFuncs<T>::Hypot(affine.D(), affine.A()));
spinners[4]->SetValueStealth(VarFuncs<T>::Hypot(affine.E(), affine.B()));
spinners[5]->SetValueStealth(VarFuncs<T>::Hypot(affine.F(), affine.C()));

View File

@ -16,10 +16,10 @@ void Fractorium::InitXformsColorUI()
ui.XformPaletteRefTable->setItem(0, 0, m_PaletteRefItem);
ui.XformPaletteRefTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
connect(ui.XformPaletteRefTable->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), this, SLOT(OnXformRefPaletteResized(int, int, int)), Qt::QueuedConnection);
connect(ui.RandomColorIndicesButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomColorIndicesButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.ToggleColorIndicesButton, SIGNAL(clicked(bool)), this, SLOT(OnToggleColorIndicesButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.RandomColorSpeedButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomColorSpeedButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.ToggleColorSpeedButton, SIGNAL(clicked(bool)), this, SLOT(OnToggleColorSpeedButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.RandomColorIndicesButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomColorIndicesButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.ToggleColorIndicesButton, SIGNAL(clicked(bool)), this, SLOT(OnToggleColorIndicesButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.RandomColorSpeedButton, SIGNAL(clicked(bool)), this, SLOT(OnRandomColorSpeedButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.ToggleColorSpeedsButton, SIGNAL(clicked(bool)), this, SLOT(OnToggleColorSpeedsButtonClicked(bool)), Qt::QueuedConnection);
SetupSpinner<DoubleSpinBox, double>(ui.XformColorIndexTable, this, row, 1, m_XformColorIndexSpin, spinHeight, 0, 1, 0.01, SIGNAL(valueChanged(double)), SLOT(OnXformColorIndexChanged(double)), false, 0, 1, 0);
SetupSpinner<DoubleSpinBox, double>(ui.XformColorValuesTable, this, row, 1, m_XformColorSpeedSpin, spinHeight, -1, 1, 0.1, SIGNAL(valueChanged(double)), SLOT(OnXformColorSpeedChanged(double)), true, 0.5, 0.5, 0);
SetupSpinner<DoubleSpinBox, double>(ui.XformColorValuesTable, this, row, 1, m_XformOpacitySpin, spinHeight, 0, 1, 0.1, SIGNAL(valueChanged(double)), SLOT(OnXformOpacityChanged(double)), true, 1, 1, 0);
@ -137,13 +137,13 @@ void Fractorium::OnRandomColorSpeedButtonClicked(bool b) { m_Controller->RandomC
/// Resets the rendering process.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::ToggleColorSpeedButtonClicked()
void FractoriumEmberController<T>::ToggleColorSpeedsButtonClicked()
{
char ch = 1;
UpdateXform([&](Xform<T>* xform, size_t xfindex, size_t selIndex) { xform->m_ColorSpeed = (T(ch ^= 1) ? 0.5 : 0.0); }, eXformUpdate::UPDATE_ALL);
m_Fractorium->m_XformColorSpeedSpin->SetValueStealth(CurrentXform()->m_ColorSpeed);
}
void Fractorium::OnToggleColorSpeedButtonClicked(bool b) { m_Controller->ToggleColorSpeedButtonClicked(); }
void Fractorium::OnToggleColorSpeedsButtonClicked(bool b) { m_Controller->ToggleColorSpeedsButtonClicked(); }
/// <summary>
/// Set the color speed of the selected xforms.

View File

@ -49,6 +49,7 @@ FractoriumOptionsDialog::FractoriumOptionsDialog(QWidget* p, Qt::WindowFlags f)
ui.OpenCLCheckBox->setEnabled(false);
ui.SharedTextureCheckBox->setChecked(false);
ui.SharedTextureCheckBox->setEnabled(false);
ui.OpenCLSubBatchPctSpin->setEnabled(false);
ui.OpenCLSubBatchSpin->setEnabled(false);
ui.OpenCLQualitySpin->setEnabled(false);
ui.OpenCLFilteringDERadioButton->setEnabled(false);
@ -132,6 +133,7 @@ void FractoriumOptionsDialog::OnOpenCLCheckBoxStateChanged(int state)
ui.ThreadCountSpin->setEnabled(!checked);
ui.CpuSubBatchSpin->setEnabled(!checked);
ui.SharedTextureCheckBox->setEnabled(checked);
ui.OpenCLSubBatchPctSpin->setEnabled(checked);
ui.OpenCLSubBatchSpin->setEnabled(checked);
ui.OpenCLQualitySpin->setEnabled(checked);
ui.CpuQualitySpin->setEnabled(!checked);
@ -197,6 +199,7 @@ void FractoriumOptionsDialog::GuiToData()
m_Settings->CpuQuality(CpuQuality());
m_Settings->OpenClQuality(OpenClQuality());
m_Settings->CpuSubBatch(ui.CpuSubBatchSpin->value());
m_Settings->OpenCLSubBatchPct(ui.OpenCLSubBatchPctSpin->value());
m_Settings->OpenCLSubBatch(ui.OpenCLSubBatchSpin->value());
m_Settings->CpuDEFilter(ui.CpuFilteringDERadioButton->isChecked());
m_Settings->OpenCLDEFilter(ui.OpenCLFilteringDERadioButton->isChecked());
@ -236,6 +239,7 @@ void FractoriumOptionsDialog::DataToGui()
ui.CpuQualitySpin->setValue(m_Settings->CpuQuality());
ui.OpenCLQualitySpin->setValue(m_Settings->OpenClQuality());
ui.CpuSubBatchSpin->setValue(m_Settings->CpuSubBatch());
ui.OpenCLSubBatchPctSpin->setValue(m_Settings->OpenCLSubBatchPct());
ui.OpenCLSubBatchSpin->setValue(m_Settings->OpenCLSubBatch());
SettingsToDeviceTable(ui.DeviceTable, devices);

View File

@ -248,7 +248,7 @@
</item>
<item row="16" column="0" colspan="2">
<layout class="QGridLayout" name="InteractiveRenderingTabGridLayout">
<item row="3" column="1">
<item row="4" column="1">
<widget class="QGroupBox" name="InteraciveGpuFilteringGroupBox">
<property name="title">
<string>OpenCL Filtering</string>
@ -292,7 +292,42 @@
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="OpenCLQualitySpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default quality per device to use for the interactive renderer when using OpenCL.&lt;/p&gt;&lt;p&gt;30 is a good number for this, but you can use a larger value if you have a faster GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>OpenCL Quality </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QSpinBox" name="OpenCLSubBatchSpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of ~8M iteration chunks ran using OpenCL in interactive mode for each mouse movement.&lt;/p&gt;&lt;p&gt;Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>OpenCL Chunks per Mouse Movement </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="InteraciveCpuFilteringGroupBox">
<property name="title">
<string>CPU Filtering</string>
@ -339,69 +374,13 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="OpenCLSubBatchSpin">
<property name="toolTip">
<string>The number of ~8M iteration chunks ran using OpenCL
in interactive mode for each mouse movement</string>
</property>
<property name="prefix">
<string>OpenCL Sub Batch </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="OpenCLQualitySpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default quality to use for the interactive renderer when using OpenCL.&lt;/p&gt;&lt;p&gt;30 is a good number for this, but you can use a larger value if you have a faster GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>OpenCL Quality </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="CpuQualitySpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default quality to use for the interactive renderer when using the CPU.&lt;/p&gt;&lt;p&gt;10 is a good number for this, but you can use a larger value if you have a faster system.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>CPU Quality </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="CpuSubBatchSpin">
<property name="toolTip">
<string>The number of 10,000 iteration chunks ran per thread on the CPU
in interactive mode for each mouse movement</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of ~10,000 iteration chunks ran per thread on the CPU in interactive mode for each mouse movement.&lt;/p&gt;&lt;p&gt;Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.&lt;/p&gt;&lt;p&gt;The number of iterations done in each chunk is controlled by the Sub Batch Size field in the Flame tab.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>CPU Sub Batch </string>
<string>CPU Chunks per Mouse Movement </string>
</property>
<property name="minimum">
<number>1</number>
@ -411,6 +390,22 @@ in interactive mode for each mouse movement</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="ThreadCountSpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of threads to use with CPU rendering.&lt;/p&gt;&lt;p&gt;Decrease for more responsive editing, increase for better performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>Threads </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="RandomCountSpin">
<property name="toolTip">
@ -427,19 +422,47 @@ in interactive mode for each mouse movement</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="ThreadCountSpin">
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="OpenCLSubBatchPctSpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of threads to use with CPU rendering.&lt;/p&gt;&lt;p&gt;Decrease for more responsive editing, increase for better performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The percentage of a sub batch to execute on each thread per kernel call when using OpenCL in interactive mode. Default: 0.025 (256 iters).&lt;/p&gt;&lt;p&gt;Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.&lt;/p&gt;&lt;p&gt;Note that this can cause a crash and subsequent restart of the graphics driver if each kernel call takes too long. So reduce the value if you encounter such a problem.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>Threads </string>
<string>OpenCL Sub Batch Percent Per Thread </string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.025000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="CpuQualitySpin">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The default quality to use for the interactive renderer when using the CPU.&lt;/p&gt;&lt;p&gt;10 is a good number for this, but you can use a larger value if you have a faster system.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefix">
<string>CPU Quality </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>64</number>
<number>99999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
@ -538,7 +561,7 @@ in interactive mode for each mouse movement</string>
<number>6</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="TableWidget" name="OptionsXmlSavingTable">
<widget class="QTableWidget" name="OptionsXmlSavingTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -731,7 +754,7 @@ in interactive mode for each mouse movement</string>
<number>6</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="TableWidget" name="OptionsIdentityTable">
<widget class="QTableWidget" name="OptionsIdentityTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -922,13 +945,6 @@ in interactive mode for each mouse movement</string>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TableWidget</class>
<extends>QTableWidget</extends>
<header>TableWidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>EarlyClipCheckBox</tabstop>
<tabstop>OpenCLCheckBox</tabstop>
@ -946,8 +962,9 @@ in interactive mode for each mouse movement</string>
<tabstop>CpuSubBatchSpin</tabstop>
<tabstop>RandomCountSpin</tabstop>
<tabstop>OpenCLQualitySpin</tabstop>
<tabstop>OpenCLSubBatchSpin</tabstop>
<tabstop>OpenCLSubBatchPctSpin</tabstop>
<tabstop>CpuQualitySpin</tabstop>
<tabstop>OpenCLSubBatchSpin</tabstop>
<tabstop>CpuFilteringLogRadioButton</tabstop>
<tabstop>CpuFilteringDERadioButton</tabstop>
<tabstop>OpenCLFilteringLogRadioButton</tabstop>

View File

@ -231,8 +231,11 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="suffix">
<string/>

View File

@ -1,13 +1,11 @@
#include "FractoriumPch.h"
#include "PaletteEditor.h"
#include "Fractorium.h"
/// <summary>
/// Constructor which passes parent widget to the base and sets up slots and other ui
/// elements.
/// This takes a reference to a palette list, which it then searches for user created palettes
/// and only populates the combo box with those.
/// </summary>
/// <param name="paletteList">A reference to an existing palette list, gotten from the main window.</param>
/// <param name="p">The parent widget</param>
PaletteEditor::PaletteEditor(QWidget* p) :
QDialog(p),
@ -519,6 +517,7 @@ QStringList PaletteEditor::SetupOpenImagesDialog()
m_FileDialog->setWindowTitle("Open Image");
m_FileDialog->setDirectory(settings->OpenPaletteImageFolder());
m_FileDialog->selectNameFilter("*.jpg");
m_FileDialog->setSidebarUrls(dynamic_cast<Fractorium*>(parent())->Urls());
}
if (m_FileDialog->exec() == QDialog::Accepted)

View File

@ -639,6 +639,7 @@ void QssDialog::SetupFileDialog()
m_FileDialog->setViewMode(QFileDialog::List);
m_FileDialog->setDirectory(m_Parent->m_SettingsPath);
m_FileDialog->setOption(QFileDialog::DontUseNativeDialog, true);
m_FileDialog->setSidebarUrls(dynamic_cast<Fractorium*>(parent())->Urls());
}
#endif

View File

@ -176,6 +176,8 @@ bool SpinBox::eventFilter(QObject* o, QEvent* e)
{
m_MouseDownPoint = m_MouseMovePoint = me->pos();
StartTimer();
e->accept();
return true;
}
else if (!m_Settings->ToggleType() &&
me->type() == QMouseEvent::MouseButtonRelease &&
@ -183,18 +185,22 @@ bool SpinBox::eventFilter(QObject* o, QEvent* e)
{
StopTimer();
m_MouseDownPoint = m_MouseMovePoint = me->pos();
e->accept();
return true;
}
else if (!m_Settings->ToggleType() &&
me->type() == QMouseEvent::MouseMove &&
QGuiApplication::mouseButtons() & Qt::RightButton)
{
m_MouseMovePoint = me->pos();
e->accept();
return true;
}
else if (m_DoubleClick &&
((!m_Settings->ToggleType() && e->type() == QMouseEvent::MouseButtonDblClick && me->button() == Qt::LeftButton) ||
(m_Settings->ToggleType() && me->type() == QMouseEvent::MouseButtonRelease && me->button() == Qt::RightButton)))
{
if (IsClose(m_DoubleClickLowVal, value()))
if (m_DoubleClickLowVal == value())
{
m_DoubleClickZeroEvent(this, m_DoubleClickZero);
setValue(m_DoubleClickZero);
@ -204,6 +210,9 @@ bool SpinBox::eventFilter(QObject* o, QEvent* e)
m_DoubleClickNonZeroEvent(this, m_DoubleClickNonZero);
setValue(m_DoubleClickNonZero);
}
e->accept();
return true;
}
}
else
@ -241,12 +250,16 @@ bool SpinBox::eventFilter(QObject* o, QEvent* e)
setValue(value() - (ctrl ? m_Step * 10 : m_Step));
}
}
}
else if (dynamic_cast<QKeyEvent*>(e))
{
e->accept();
return true;
}
}
else if (dynamic_cast<QKeyEvent*>(e))
{
e->accept();
return true;
}
}
return QSpinBox::eventFilter(o, e);

View File

@ -7,20 +7,8 @@
/// </summary>
/// <summary>
/// The entire purpose for this subclass is to overcome a glaring flaw
/// in the way Qt handles table drawing.
/// For most of the tables Fractorium uses, it draw the grid lines. Qt draws them
/// in a very naive manner, whereby it draws lines above the first row and below
/// the last row. It also draws to the left of the first column and to the right
/// of the last column. This has the effect of putting an additional border inside
/// of the specified border. This extra border becomes very noticeable when changing
/// the background color of a cell.
/// The workaround is to scrunch the size of the table up by one pixel. However,
/// since the viewable area is then smaller than the size of the table, it will scroll
/// by one pixel if the mouse is hovered over the table and the user moves the mouse wheel.
/// This subclass is done solely to filter out the mouse wheel event.
/// Note that this filtering only applies to the table as a whole, which means
/// mouse wheel events still get properly routed to spinners.
/// The purpose of this subclass is to allow for dragging the contents of a table cell.
/// It's used in the palette preview table.
/// </summary>
class TableWidget : public QTableWidget
{
@ -45,20 +33,15 @@ signals:
protected:
/// <summary>
/// Event filter to ignore mouse wheel events and also handle others such as mouse move and mouse button release.
/// Event filter to handle dragging and releasing the mouse.
/// Sadly, QTableWidget makes these hard to get to, so we must handle them here.
/// </summary>
/// <param name="obj">The object sending the event</param>
/// <param name="e">The event</param>
/// <returns>True if mouse wheel, else return the result of calling the base fucntion.</returns>
/// <returns>The result of calling the base fucntion.</returns>
bool eventFilter(QObject* obj, QEvent* e)
{
if (e->type() == QEvent::Wheel)
{
e->ignore();
return true;
}
else if (e->type() == QEvent::MouseMove)
if (e->type() == QEvent::MouseMove)
{
if (auto me = dynamic_cast<QMouseEvent*>(e))
{

View File

@ -1,6 +1,7 @@
#pragma once
#include "FractoriumPch.h"
#include "SpinBox.h"
#include "DoubleSpinBox.h"
/// <summary>
@ -114,7 +115,42 @@ public:
QPushButton* m_Button;
};
class SpinnerLabelButtonWidget : public QWidget
class SpinnerLabelWidget : public QWidget
{
Q_OBJECT
public:
/// <summary>
/// Constructor that passes the parent to the base, then creates a QLabel,
/// then creates a QPushButton and sets up its caption and dimensions, then
/// assigns the DoubleSpinBox.
/// </summary>
/// <param name="spinBox">The pre-created DoubleSpinBox</param>
/// <param name="h">The height of the label</param>
/// <param name="p">The parent widget</param>
SpinnerLabelWidget(DoubleSpinBox* spinBox, int h, QWidget* p)
: QWidget(p)
{
m_L = new QHBoxLayout(this);
m_SpinBox = spinBox;
m_Label = new QLabel(p);
m_Label->setMinimumHeight(h);
m_Label->setMaximumHeight(h);
m_L->addWidget(spinBox);
m_L->addWidget(m_Label);
m_L->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_L->setMargin(0);
m_L->setSpacing(0);
setLayout(m_L);
}
DoubleSpinBox* m_SpinBox;
QLabel* m_Label;
protected:
QHBoxLayout* m_L;
};
class SpinnerLabelButtonWidget : public SpinnerLabelWidget
{
Q_OBJECT
@ -130,14 +166,9 @@ public:
/// <param name="h">The height of the button</param>
/// <param name="p">The parent widget</param>
SpinnerLabelButtonWidget(DoubleSpinBox* spinBox, QString buttonCaption, int w, int h, QWidget* p)
: QWidget(p)
: SpinnerLabelWidget(spinBox, h, p)
{
QHBoxLayout* l = new QHBoxLayout(this);
m_Button = new QPushButton(buttonCaption, p);
m_SpinBox = spinBox;
m_Label = new QLabel(p);
m_Label->setMinimumHeight(h);
m_Label->setMaximumHeight(h);
if (w != -1)
{
@ -147,16 +178,41 @@ public:
m_Button->setMinimumHeight(h);
m_Button->setMaximumHeight(h);
l->addWidget(spinBox);
l->addWidget(m_Label);
l->addWidget(m_Button);
l->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
l->setMargin(0);
l->setSpacing(0);
setLayout(l);
m_L->addWidget(m_Button);
}
DoubleSpinBox* m_SpinBox;
QPushButton* m_Button;
QLabel* m_Label;
};
class DoubleIntSpinnerWidget : public QWidget
{
Q_OBJECT
public:
/// <summary>
/// Constructor that passes the parent to the base, then creates a QHBoxLayout,
/// and adds the passed in DoubleSpinBox and SpinBox to the layout.
/// </summary>
/// <param name="doubleSpinBox">The pre-created DoubleSpinBox</param>
/// <param name="spinBox">The pre-created SpinBox</param>
/// <param name="p">The parent widget</param>
DoubleIntSpinnerWidget(DoubleSpinBox* doubleSpinBox, SpinBox* spinBox, QWidget* p)
: QWidget(p)
{
m_L = new QHBoxLayout(this);
m_DoubleSpinBox = doubleSpinBox;
m_SpinBox = spinBox;
m_L->addWidget(doubleSpinBox);
m_L->addWidget(spinBox);
m_L->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_L->setMargin(0);
m_L->setSpacing(0);
setLayout(m_L);
}
DoubleSpinBox* m_DoubleSpinBox;
SpinBox* m_SpinBox;
protected:
QHBoxLayout* m_L;
};