From 90ec5b82463c4183861de2e2ffdb42f6e5c9dedf Mon Sep 17 00:00:00 2001 From: Person Date: Sat, 13 Apr 2019 19:00:46 -0700 Subject: [PATCH] --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. --- .../Installer/FractoriumInstaller.wixproj | 2 +- Builds/MSVC/Installer/Product.wxs | 14 +- Builds/MSVC/VS2017/Ember.rc | Bin 4522 -> 4522 bytes Builds/MSVC/VS2017/Ember.vcxproj | 2 + Builds/MSVC/VS2017/Ember.vcxproj.filters | 6 + Builds/MSVC/VS2017/EmberAnimate.rc | 10 +- Builds/MSVC/VS2017/EmberCL.rc | Bin 4548 -> 4548 bytes Builds/MSVC/VS2017/EmberGenome.rc | 10 +- Builds/MSVC/VS2017/EmberRender.rc | 10 +- Builds/MSVC/VS2017/Fractorium.rc | Bin 4490 -> 4490 bytes Builds/MSVC/VS2017/Fractorium.vcxproj | 45 +- Builds/QtCreator/Ember/Ember.pro | 2 + Builds/QtCreator/Fractorium/Fractorium.pro | 8 + Builds/QtCreator/defaults.pri | 2 +- Data/Bench/EmberBench.ps1 | 8 +- Data/Bench/mfeemster_basicmemory.flame | 10 +- Data/dark_linux.qss | 16 +- Data/dark_mac.qss | 16 +- Data/dark_windows.qss | 16 +- Source/Ember/Curves.h | 178 +- Source/Ember/Ember.cpp | 66 +- Source/Ember/Ember.h | 28 + Source/Ember/EmberDefines.h | 6 +- Source/Ember/EmberToXml.cpp | 44 +- Source/Ember/Iterator.h | 67 +- Source/Ember/Palette.h | 14 + Source/Ember/PaletteList.cpp | 39 +- Source/Ember/Renderer.cpp | 45 +- Source/Ember/Renderer.h | 2 + Source/Ember/RendererBase.h | 1 - Source/Ember/Spline.cpp | 127 + Source/Ember/Spline.h | 55 + Source/Ember/Utils.h | 40 + Source/Ember/VarFuncs.h | 321 +- Source/Ember/Variation.h | 193 +- Source/Ember/VariationList.cpp | 64 +- Source/Ember/Variations01.h | 699 ++- Source/Ember/Variations02.h | 323 +- Source/Ember/Variations03.h | 529 +- Source/Ember/Variations04.h | 506 ++ Source/Ember/Variations05.h | 72 + Source/Ember/Variations06.h | 134 +- Source/Ember/Variations07.h | 4537 ++++++++++++++++- Source/Ember/XmlToEmber.cpp | 1113 +++- Source/Ember/XmlToEmber.h | 10 +- Source/EmberAnimate/EmberAnimate.cpp | 5 +- Source/EmberCL/DEOpenCLKernelCreator.cpp | 6 +- Source/EmberCL/EmberCLFunctions.h | 6 + Source/EmberCL/EmberCLStructs.h | 2 + Source/EmberCL/FunctionMapper.cpp | 149 + Source/EmberCL/IterOpenCLKernelCreator.cpp | 16 +- Source/EmberCL/RendererCL.cpp | 45 +- Source/EmberCL/RendererCL.h | 3 + Source/EmberCommon/EmberOptions.h | 26 +- Source/EmberRender/EmberRender.cpp | 5 +- Source/EmberTester/EmberTester.cpp | 97 +- Source/Fractorium/AboutDialog.ui | 8 +- Source/Fractorium/CurvesGraphicsView.cpp | 237 +- Source/Fractorium/CurvesGraphicsView.h | 24 +- Source/Fractorium/DoubleSpinBox.cpp | 34 + Source/Fractorium/DoubleSpinBox.h | 2 + Source/Fractorium/FinalRenderDialog.cpp | 119 +- Source/Fractorium/FinalRenderDialog.h | 7 + Source/Fractorium/FinalRenderDialog.ui | 74 +- .../Fractorium/FinalRenderEmberController.cpp | 49 +- .../Fractorium/FinalRenderEmberController.h | 11 +- Source/Fractorium/Fractorium.cpp | 39 +- Source/Fractorium/Fractorium.h | 17 +- Source/Fractorium/Fractorium.ui | 922 ++-- Source/Fractorium/FractoriumCommon.h | 2 +- Source/Fractorium/FractoriumEmberController.h | 22 +- Source/Fractorium/FractoriumInfo.cpp | 4 +- Source/Fractorium/FractoriumMenus.cpp | 17 +- Source/Fractorium/FractoriumPalette.cpp | 66 +- Source/Fractorium/FractoriumParams.cpp | 128 +- Source/Fractorium/FractoriumRender.cpp | 3 + Source/Fractorium/FractoriumSettings.cpp | 184 +- Source/Fractorium/FractoriumSettings.h | 46 +- Source/Fractorium/FractoriumToolbar.cpp | 2 + Source/Fractorium/FractoriumXaos.cpp | 171 +- Source/Fractorium/FractoriumXforms.cpp | 7 +- Source/Fractorium/FractoriumXformsAffine.cpp | 6 +- Source/Fractorium/FractoriumXformsColor.cpp | 12 +- Source/Fractorium/OptionsDialog.cpp | 4 + Source/Fractorium/OptionsDialog.ui | 165 +- Source/Fractorium/PaletteEditor.ui | 5 +- .../PaletteEditor/PaletteEditor.cpp | 5 +- Source/Fractorium/QssDialog.cpp | 1 + Source/Fractorium/SpinBox.cpp | 21 +- Source/Fractorium/TableWidget.h | 27 +- Source/Fractorium/TwoButtonComboWidget.h | 88 +- 91 files changed, 11011 insertions(+), 1268 deletions(-) create mode 100644 Source/Ember/Spline.cpp create mode 100644 Source/Ember/Spline.h diff --git a/Builds/MSVC/Installer/FractoriumInstaller.wixproj b/Builds/MSVC/Installer/FractoriumInstaller.wixproj index 0b83aad..0d7b452 100644 --- a/Builds/MSVC/Installer/FractoriumInstaller.wixproj +++ b/Builds/MSVC/Installer/FractoriumInstaller.wixproj @@ -6,7 +6,7 @@ 3.7 {c8096c47-e358-438c-a520-146d46b0637d} 2.0 - Fractorium_1.0.0.14 + Fractorium_1.0.0.15 Package $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs index 8005ca9..a429897 100644 --- a/Builds/MSVC/Installer/Product.wxs +++ b/Builds/MSVC/Installer/Product.wxs @@ -1,6 +1,6 @@ - + @@ -13,7 +13,7 @@ - + + @@ -84,6 +85,7 @@ + @@ -316,4 +318,12 @@ + + + + + + + + \ No newline at end of file diff --git a/Builds/MSVC/VS2017/Ember.rc b/Builds/MSVC/VS2017/Ember.rc index e1d20d882230ef2a054c6b17218d71e67f726790..cd1a580ca4834922064b20470275232bf1cab1f6 100644 GIT binary patch delta 43 xcmZ3byh?e)Hx5SA$=^9F8BI4Eavo;_aum76CkybbVzivRo98W1cqK0*3jjm?4Zr{Z delta 43 xcmZ3byh?e)Hx5RV$=^9F8BI1Davo;_aum76CkybbVzijNo98W1cqK0*3jjlv4Z8pU diff --git a/Builds/MSVC/VS2017/Ember.vcxproj b/Builds/MSVC/VS2017/Ember.vcxproj index e8162e1..7292477 100644 --- a/Builds/MSVC/VS2017/Ember.vcxproj +++ b/Builds/MSVC/VS2017/Ember.vcxproj @@ -115,6 +115,7 @@ + @@ -151,6 +152,7 @@ + diff --git a/Builds/MSVC/VS2017/Ember.vcxproj.filters b/Builds/MSVC/VS2017/Ember.vcxproj.filters index e19c36a..b3b4441 100644 --- a/Builds/MSVC/VS2017/Ember.vcxproj.filters +++ b/Builds/MSVC/VS2017/Ember.vcxproj.filters @@ -128,6 +128,9 @@ Header Files\Variations + + Header Files\Xml + @@ -160,6 +163,9 @@ Source Files + + Header Files\Xml + diff --git a/Builds/MSVC/VS2017/EmberAnimate.rc b/Builds/MSVC/VS2017/EmberAnimate.rc index 92d545c..b1c234f 100644 --- a/Builds/MSVC/VS2017/EmberAnimate.rc +++ b/Builds/MSVC/VS2017/EmberAnimate.rc @@ -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" diff --git a/Builds/MSVC/VS2017/EmberCL.rc b/Builds/MSVC/VS2017/EmberCL.rc index 7d7c094207c997997a66994c5fe8d7874e09ebd2..d8d1f2ea72a84223f5c32e5e4501432269f91a74 100644 GIT binary patch delta 49 zcmX@2d_;M}7Y;_#$zM4v8BI6qb6#fxatwLJC(H4yW3-%nmgg(8DTC7Fi@d^{Z}7fh F1^})W5d8oE delta 49 zcmX@2d_;M}7Y;^~$zM4v8BI3pb6#fxatwLJC(H4yW3-rjmgg(834_w)i@d^{Z}7fh F1^}&)5cmK9 diff --git a/Builds/MSVC/VS2017/EmberGenome.rc b/Builds/MSVC/VS2017/EmberGenome.rc index aa13199..a07d554 100644 --- a/Builds/MSVC/VS2017/EmberGenome.rc +++ b/Builds/MSVC/VS2017/EmberGenome.rc @@ -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" diff --git a/Builds/MSVC/VS2017/EmberRender.rc b/Builds/MSVC/VS2017/EmberRender.rc index 987f9bd..224f559 100644 --- a/Builds/MSVC/VS2017/EmberRender.rc +++ b/Builds/MSVC/VS2017/EmberRender.rc @@ -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" diff --git a/Builds/MSVC/VS2017/Fractorium.rc b/Builds/MSVC/VS2017/Fractorium.rc index 0a03cc540cb0de73b070bdf946372ccb0b866332..ad173a0c044cfe0ea9ed3df57331de47c7d1d827 100644 GIT binary patch delta 46 zcmeBD?o!@xj)T#3@_7zRR#OIE2Cm8doT8hRIA<^c1q->wH(%o3#>i;8xs#WX1pqz% B4C(*? delta 46 zcmeBD?o!@xj)T!;@_7zRRucwZ2Cm8doT8hRIA<^c1q->wH(%o3#>i;0xs#WX1pqyv B4CVj; diff --git a/Builds/MSVC/VS2017/Fractorium.vcxproj b/Builds/MSVC/VS2017/Fractorium.vcxproj index e5b1616..e64bf01 100644 --- a/Builds/MSVC/VS2017/Fractorium.vcxproj +++ b/Builds/MSVC/VS2017/Fractorium.vcxproj @@ -87,30 +87,14 @@ 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\" - +xcopy /F /Y /R /D "$(QTDIR)\plugins\imageformats\qjpegd.dll" "$(OutDir)\imageformats\" @@ -145,29 +129,14 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindowsd.dll" "$(OutDir)\platform 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\" +xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms\" +xcopy /F /Y /R /D "$(QTDIR)\plugins\imageformats\qjpeg.dll" "$(OutDir)\imageformats\" diff --git a/Builds/QtCreator/Ember/Ember.pro b/Builds/QtCreator/Ember/Ember.pro index 44da87e..98ac54e 100644 --- a/Builds/QtCreator/Ember/Ember.pro +++ b/Builds/QtCreator/Ember/Ember.pro @@ -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 \ diff --git a/Builds/QtCreator/Fractorium/Fractorium.pro b/Builds/QtCreator/Fractorium/Fractorium.pro index ca11c7e..31d14b2 100644 --- a/Builds/QtCreator/Fractorium/Fractorium.pro +++ b/Builds/QtCreator/Fractorium/Fractorium.pro @@ -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 } } diff --git a/Builds/QtCreator/defaults.pri b/Builds/QtCreator/defaults.pri index a1e9978..4b86194 100644 --- a/Builds/QtCreator/defaults.pri +++ b/Builds/QtCreator/defaults.pri @@ -1,4 +1,4 @@ -VERSION = 1.0.0.14 +VERSION = 1.0.0.15 win32:CONFIG += skip_target_version_ext CONFIG += c++14 diff --git a/Data/Bench/EmberBench.ps1 b/Data/Bench/EmberBench.ps1 index e612a38..0768cdf 100644 --- a/Data/Bench/EmberBench.ps1 +++ b/Data/Bench/EmberBench.ps1 @@ -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 diff --git a/Data/Bench/mfeemster_basicmemory.flame b/Data/Bench/mfeemster_basicmemory.flame index 2a7ccdc..92d0e7d 100644 --- a/Data/Bench/mfeemster_basicmemory.flame +++ b/Data/Bench/mfeemster_basicmemory.flame @@ -1,6 +1,6 @@ - - + + F1DFDDFAEAEDFDEDEEFDEFEFFFF0F3FCEBF3FDEBEBFBE7E8 FEDADEF8D9E1F1D4D8DFC2C4D89CB8AB82A2934C6E814A5D @@ -35,8 +35,10 @@ E2D4E3C6B7CA9F8EAE667DA96B6071483B573A3247312A49 28213320172A151314100702090001020001010000050100 - - + + + + diff --git a/Data/dark_linux.qss b/Data/dark_linux.qss index 1638c0e..2d9b3b7 100644 --- a/Data/dark_linux.qss +++ b/Data/dark_linux.qss @@ -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); diff --git a/Data/dark_mac.qss b/Data/dark_mac.qss index 85adb9b..9379e45 100644 --- a/Data/dark_mac.qss +++ b/Data/dark_mac.qss @@ -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); diff --git a/Data/dark_windows.qss b/Data/dark_windows.qss index 1638c0e..2d9b3b7 100644 --- a/Data/dark_windows.qss +++ b/Data/dark_windows.qss @@ -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); diff --git a/Source/Ember/Curves.h b/Source/Ember/Curves.h index 32cf561..36267a2 100644 --- a/Source/Ember/Curves.h +++ b/Source/Ember/Curves.h @@ -2,6 +2,9 @@ #include "Utils.h" #include "Isaac.h" +#include "Curves.h" + +#define CURVE_POINTS 5 /// /// Curves class. @@ -10,8 +13,9 @@ namespace EmberNs { /// -/// 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. /// template class EMBER_API Curves @@ -69,14 +73,23 @@ public: template Curves& operator = (const Curves& 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 Curves& operator += (const Curves& 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 Curves& operator *= (const Curves& 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 Curves& 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: /// void Clear() { - memset(&m_Points, 0, sizeof(m_Points)); - memset(&m_Weights, 0, sizeof(m_Weights)); + for (auto& p : m_Points) + p.clear(); } /// @@ -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; } - /// - /// Wrapper around calling BezierSolve() on each of the 4 weight and point vectors. - /// - /// The position to apply - /// vec4 that contains the y component of the solution for each vector in each component - 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: - /// - /// Solve the given point and weight vectors for the given position and store - /// the output in the solution vec2 passed in. - /// - /// The position to apply - /// A pointer to an array of 4 vec2 - /// A pointer to an array of 4 weights - /// The vec2 to store the solution in - 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, 4> m_Points; }; //Must declare this outside of the class to provide for both orders of parameters. @@ -264,14 +259,9 @@ Curves operator * (const Curves& curves, const U& t) T tt = T(t); Curves 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; } diff --git a/Source/Ember/Ember.cpp b/Source/Ember/Ember.cpp index 67ebed0..c4c3d0e 100644 --- a/Source/Ember/Ember.cpp +++ b/Source/Ember/Ember.cpp @@ -31,6 +31,7 @@ template EMBER_API class QTIsaac; #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; /*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; template EMBER_API class PaletteList; +template EMBER_API class Spline; #ifdef DO_DOUBLE EXPORT_SINGLE_TYPE_EMBER(double) diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index a28d831..a4c85e3 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -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: /// New width /// New height /// True to only scale if the new dimensions are smaller than the original, else always scale. + /// 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. 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::m_FinalRasW>(embers, coefs, size); InterpI<&Ember::m_FinalRasH>(embers, coefs, size); InterpI<&Ember::m_SubBatchSize>(embers, coefs, size); + InterpT<&Ember::m_RandPointRange>(embers, coefs, size); InterpI<&Ember::m_FuseCount>(embers, coefs, size); InterpI<&Ember::m_Supersample>(embers, coefs, size); InterpI<&Ember::m_TemporalSamples>(embers, coefs, size); @@ -765,6 +771,7 @@ public: InterpT<&Ember::m_Vibrancy>(embers, coefs, size); InterpT<&Ember::m_GammaThresh>(embers, coefs, size); InterpT<&Ember::m_HighlightPower>(embers, coefs, size); + InterpT<&Ember::m_K2>(embers, coefs, size); InterpX, &Ember::m_Background>(embers, coefs, size); m_Background.a = bgAlphaSave;//Don't interp alpha. InterpT<&Ember::m_TemporalFilterExp>(embers, coefs, size); InterpT<&Ember::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(-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". diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h index b46b1c8..45a933e 100644 --- a/Source/Ember/EmberDefines.h +++ b/Source/Ember/EmberDefines.h @@ -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::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(Clock::now().t #define v2T glm::tvec2 #define v3T glm::tvec3 #define v4T glm::tvec4 + #define v2F glm::tvec2 #define v4F glm::tvec4 #define v4D glm::tvec4 #define v4bT glm::tvec4 @@ -118,6 +119,7 @@ static inline size_t NowMs() { return duration_cast(Clock::now().t #define v2T glm::detail::tvec2 #define v3T glm::detail::tvec3 #define v4T glm::detail::tvec4 + #define v2F glm::detail::tvec2 #define v4F glm::detail::tvec4 #define v4D glm::detail::tvec4 #define v4bT glm::detail::tvec4 @@ -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, diff --git a/Source/Ember/EmberToXml.cpp b/Source/Ember/EmberToXml.cpp index 91be425..cb8d640 100644 --- a/Source/Ember/EmberToXml.cpp +++ b/Source/Ember/EmberToXml.cpp @@ -143,10 +143,12 @@ string EmberToXml::ToString(Ember& 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::ToString(Ember& 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::ToString(const EmberMotion& 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; diff --git a/Source/Ember/Iterator.h b/Source/Ember/Iterator.h index 4d1dda8..afd4264 100644 --- a/Source/Ember/Iterator.h +++ b/Source/Ember/Iterator.h @@ -15,9 +15,7 @@ namespace EmberNs using Iterator::NextXformFromIndex; \ using Iterator::DoFinalXform; \ using Iterator::DoBadVals; - -template class Renderer; - + template 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: /// - /// 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. /// - Iterator() = default; + Iterator() + { + } + virtual ~Iterator() = default; Iterator(const Iterator& iter) = delete; @@ -196,11 +197,12 @@ protected: /// the coordinates of the output point are just set to a random number between -1 and 1. /// /// The xforms array + /// The range in the x and y directions from the center of the world spcae from which to select the new random point /// The counter for the total number of bad values this sub batch /// The point which initially had the bad values and which will store the newly computed values /// The random context this iterator is using /// True if a good value was computed within 5 tries, else false - inline bool DoBadVals(Xform* xforms, size_t& badVals, Point* point, QTIsaac& rand) + inline bool DoBadVals(Xform* xforms, T range, size_t& badVals, Point* point, QTIsaac& rand) { size_t xformIndex, consec = 0; Point firstBadPoint; @@ -209,8 +211,8 @@ protected: { consec++; badVals++; - firstBadPoint.m_X = rand.Frand11();//Re-randomize points, but keep the computed color and viz. - firstBadPoint.m_Y = rand.Frand11(); + firstBadPoint.m_X = rand.template Frand(-range, range);//Re-randomize points, but keep the computed color and viz. + firstBadPoint.m_Y = rand.template Frand(-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(); - point->m_Y = rand.Frand11(); + point->m_X = rand.template Frand(-range, range); + point->m_Y = rand.template Frand(-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: /// /// The xforms array /// Index of the last used xform before calling this function + /// The range in the x and y directions from the center of the world spcae from which to select the new random point /// The saved index of the last xform used within this function /// The counter for the total number of bad values this sub batch /// The point which initially had the bad values and which will store the newly computed values /// The random context this iterator is using /// True if a good value was computed within 5 tries, else false - inline bool DoBadVals(Xform* xforms, size_t& xformIndex, size_t lastXformUsed, size_t& badVals, Point* point, QTIsaac& rand) + inline bool DoBadVals(Xform* xforms, size_t& xformIndex, T range, size_t lastXformUsed, size_t& badVals, Point* point, QTIsaac& rand) { size_t consec = 0; Point firstBadPoint; @@ -429,8 +432,8 @@ public: { consec++; badVals++; - firstBadPoint.m_X = rand.Frand11();//Re-randomize points, but keep the computed color and viz. - firstBadPoint.m_Y = rand.Frand11(); + firstBadPoint.m_X = rand.template Frand(-range, range);//Re-randomize points, but keep the computed color and viz. + firstBadPoint.m_Y = rand.template Frand(-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(); - point->m_Y = rand.Frand11(); + point->m_X = rand.template Frand(-range, range); + point->m_Y = rand.template Frand(-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. } diff --git a/Source/Ember/Palette.h b/Source/Ember/Palette.h index 2b88792..5af747a 100644 --- a/Source/Ember/Palette.h +++ b/Source/Ember/Palette.h @@ -415,6 +415,20 @@ public: return v; } + /// + /// Determine if a palette is all black. + /// + /// True if all colors are black, else false if at least one component of one color is non zero. + 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; + } + /// /// Convert RGB to HSV. /// diff --git a/Source/Ember/PaletteList.cpp b/Source/Ember/PaletteList.cpp index 3a8d85c..a637ea2 100644 --- a/Source/Ember/PaletteList.cpp +++ b/Source/Ember/PaletteList.cpp @@ -258,30 +258,39 @@ bool PaletteList::Add(const string& filename, bool force) /// /// Get the palette at a random index in a random file in the map. +/// Attempt to avoid selecting a palette which is all black. /// /// A pointer to a random palette in a random file if successful, else nullptr. template Palette* PaletteList::GetRandomPalette() { - auto p = s_Palettes.begin(); - size_t i = 0, paletteFileIndex = QTIsaac::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::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::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::LockedRand() % p->second.size(); - - if (paletteIndex < p->second.size()) - return &p->second[paletteIndex]; - } - - return nullptr; + return Size() ? &s_Palettes[0][0] : nullptr; } /// diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index a348f78..2467b3e 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -99,7 +99,7 @@ template void Renderer::ComputeQuality() { m_Scale = std::pow(T(2.0), Zoom()); - m_ScaledQuality = Quality() * m_Scale * m_Scale; + m_ScaledQuality = Quality() * SQR(m_Scale); } /// @@ -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::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(); - m_Samples[threadIndex][0].m_Y = m_Rand[threadIndex].template Frand11(); + m_Samples[threadIndex][0].m_X = m_Rand[threadIndex].template Frand(-m_ThreadEmbers[threadIndex].m_RandPointRange, m_ThreadEmbers[threadIndex].m_RandPointRange); + m_Samples[threadIndex][0].m_Y = m_Rand[threadIndex].template Frand(-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(); @@ -1727,9 +1732,21 @@ void Renderer::ComputeCurves() { //Timing t; auto st = m_Csa.size(); + vector> 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 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"); } diff --git a/Source/Ember/Renderer.h b/Source/Ember/Renderer.h index b8e0b60..c654ac1 100644 --- a/Source/Ember/Renderer.h +++ b/Source/Ember/Renderer.h @@ -7,6 +7,7 @@ #include "Interpolate.h" #include "CarToRas.h" #include "EmberToXml.h" +#include "Spline.h" /// /// 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; diff --git a/Source/Ember/RendererBase.h b/Source/Ember/RendererBase.h index 4d616e1..06ae94f 100644 --- a/Source/Ember/RendererBase.h +++ b/Source/Ember/RendererBase.h @@ -198,7 +198,6 @@ public: bool InFinalAccum(); void* m_ProgressParameter = nullptr; - protected: bool m_EarlyClip = false; bool m_YAxisUp = false; diff --git a/Source/Ember/Spline.cpp b/Source/Ember/Spline.cpp new file mode 100644 index 0000000..2806bf3 --- /dev/null +++ b/Source/Ember/Spline.cpp @@ -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 +{ +/// +/// Constructor that takes a vector of x,y points, optionally sorts them +/// and builds the spline values. +/// +/// The vector of x,y points +/// True to skip sorting, false to sort. +template +Spline::Spline(const std::vector& _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(); +} + +/// +/// Compute spline values for the passed in points. +/// This only needs to be done once. +/// +template +void Spline::BuildSplines() +{ + a.resize(n + 1); + b.resize(n + 1); + c.resize(n + 1); + d.resize(n + 1); + std::vector w(n); + std::vector h(n); + std::vector 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; + } +} + +/// +/// Wrapper to generate y points on the spline for a vector of passed in points. +/// +/// The vector of x points to generate spline points for +/// The vector of computed spline y points. +template +std::vector Spline::Interpolate(const std::vector& newX) +{ + std::vector output; output.resize(newX.size()); + + for (int i = 0; i < newX.size(); i++) + output[i] = Interpolate(newX[i]); + + return output; +} + +/// +/// Compute a y point on the spline for a the passed in value of x. +/// +/// The x points to compute the spline point for +/// The computed spline y points. +template +T Spline::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; +} diff --git a/Source/Ember/Spline.h b/Source/Ember/Spline.h new file mode 100644 index 0000000..b208451 --- /dev/null +++ b/Source/Ember/Spline.h @@ -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 +{ +/// +/// 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. +/// +template +class EMBER_API Spline +{ +public: + Spline(const std::vector& _vals, bool sorted = false); + std::vector Interpolate(const std::vector& newX); + T Interpolate(T newX); + +private: + void BuildSplines(); + std::vector vals; + std::vector a, b, c, d; + std::vector c_prime, d_prime; + std::vector k; + int n; +}; +} diff --git a/Source/Ember/Utils.h b/Source/Ember/Utils.h index 0896a0b..671ea06 100644 --- a/Source/Ember/Utils.h +++ b/Source/Ember/Utils.h @@ -829,6 +829,34 @@ static inline T NormalizeDeg180(T angle) return a; } +/// +/// Put an angular measurement in degrees into the range of 0 - 360. +/// +/// The angle to normalize +/// The normalized angle in a range of 0 - 360 +template +static inline T NormalizeDeg360(T angle) +{ + if (angle > 360 || angle < -360) + angle = fmod(angle, T(360)); + + if (angle < 0) + angle += 360; + + return angle; +} + +/// +/// Convert an angle where 0 is up to a trigonometry style angle where 0 is to the right. +/// +/// The angle to convert +/// The trig equivalent of the angle passed in +template +static inline T ToTrigAngle(T angle) +{ + return NormalizeDeg360(90 - angle); +} + /// /// Determine whether the passed in string ends with the passed in suffix, case sensitive. /// @@ -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; } +/// +/// Determine whether the passed in string starts with the passed in prefix, case sensitive. +/// +/// The string to test +/// The string to test for +/// True if str starts with suffix, else false. +static bool StartsWith(const std::string& str, const std::string& prefix) +{ + return str.size() >= prefix.size() && + str.compare(0, prefix.size(), prefix) == 0; +} + /// /// Return a lower case copy of a string. /// diff --git a/Source/Ember/VarFuncs.h b/Source/Ember/VarFuncs.h index c2449f3..e134920 100644 --- a/Source/Ember/VarFuncs.h +++ b/Source/Ember/VarFuncs.h @@ -50,6 +50,16 @@ public: return modf(v, &dummy); } + /// + /// Return the fractional part of a real number. + /// + /// The real number whose fractional part will be returned + /// The fractional part of the value passed in + static inline T Fract(T x) + { + return x - T(Floor(x)); + } + /// /// Unsure. /// @@ -191,7 +201,7 @@ public: /// /// The value to hash /// The hashed value - 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::max(); } + /// + /// Hash function gotten from Chaotica, which takes an x,y pair and hashes it. + /// Written by Thomas Ludwig and Tatyana Zabanova. + /// + /// The x value to hash + /// The y value to hash + /// The seed to hash with + /// The hashed value + 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)); + } + + /// + /// For the vibration2 variation. + /// + /// T + static inline T Modulate(T amp, T freq, T x) + { + return amp * std::cos(x * freq * M_2PI); + } + + /// + /// Divide real by complex. + /// + /// The real number + /// The complex number + /// x / a + 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); + } + + /// + /// Divide complex by complex. + /// + /// The first complex number + /// The secondcomplex number + /// a / b + 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; + } + + /// + /// Multiple complex by real. + /// + /// The complex number + /// The real number + /// a * x + static v2T ComplexMultReal(v2T a, T x) + { + return v2T(a.x * x, a.y * x); + } + + /// + /// Multiply complex by complex. + /// + /// The first complex number + /// The second complex number + /// a * b + 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); + } + + /// + /// Add complex to complex. + /// + /// The first complex number + /// The second complex number + /// a + b + static v2T ComplexPlusComplex(v2T a, v2T b) + { + return v2T(a.x + b.x, a.y + b.y); + } + + /// + /// Add complex to real. + /// + /// The complex number + /// The real number + /// a + x + static v2T ComplexPlusReal(v2T a, T x) + { + return v2T(a.x + x, a.y); + } + + /// + /// Subtract real from complex. + /// + /// The complex number + /// The real number + /// a - x + static v2T ComplexMinusReal(v2T a, T x) + { + return v2T(a.x - x, a.y); + } + + /// + /// Compute the square root of a complex number. + /// + /// The complex number + /// sqrt(a) + 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))); + } + + /// + /// Compute the natural logarithm of a complex number. + /// + /// The complex number + /// log(a) + 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)); + } + /// /// 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(&(m_Grad[0].x)), SizeOf(m_Grad) / sizeof(T)); m_GlobalMap["OFFSETS"] = make_pair(static_cast(&(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()); } /// @@ -993,8 +1141,179 @@ private: return g; } + /// + /// Initializes the P1 vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitP1() + { + std::vector 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; + } + + /// + /// Initializes the Q1 vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitQ1() + { + std::vector 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; + } + + /// + /// Initializes the P2 vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitP2() + { + std::vector 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; + } + + /// + /// Initializes the Q2 vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitQ2() + { + std::vector 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; + } + + /// + /// Initializes the PC vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitPC() + { + std::vector 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; + } + + /// + /// Initializes the QC vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitQC() + { + std::vector 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; + } + + /// + /// Initializes the PS vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitPS() + { + std::vector 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; + } + + /// + /// Initializes the QS vector used in J1(). + /// Note J1() comes with std in C++, but needed to be manually implemented in OpenCL. + /// + /// A copy of the locally declared vector + std::vector InitQS() + { + std::vector 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 m_P; std::vector m_PFloats; + std::vector m_P1; + std::vector m_Q1; + std::vector m_P2; + std::vector m_Q2; + std::vector m_PC; + std::vector m_QC; + std::vector m_PS; + std::vector m_QS; std::vector m_Offsets; std::vector m_Grad; std::unordered_map> m_GlobalMap; diff --git a/Source/Ember/Variation.h b/Source/Ember/Variation.h index e7d09e2..cdaf277 100644 --- a/Source/Ember/Variation.h +++ b/Source/Ember/Variation.h @@ -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, diff --git a/Source/Ember/VariationList.cpp b/Source/Ember/VariationList.cpp index fdae759..6327510 100644 --- a/Source/Ember/VariationList.cpp +++ b/Source/Ember/VariationList.cpp @@ -27,6 +27,8 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Sinusoidal) ADDPREPOSTREGVAR(Spherical) ADDPREPOSTREGVAR(Swirl) + ADDPREPOSTREGVAR(Swirl3) + ADDPREPOSTREGVAR(Swirl3r) ADDPREPOSTREGVAR(Horseshoe) ADDPREPOSTREGVAR(Polar) ADDPREPOSTREGVAR(Handkerchief) @@ -59,6 +61,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(JuliaScope) ADDPREPOSTREGVAR(Blur) ADDPREPOSTREGVAR(GaussianBlur) + ADDPREPOSTREGVAR(Gaussian) ADDPREPOSTREGVAR(RadialBlur) ADDPREPOSTREGVAR(Pie) ADDPREPOSTREGVAR(Ngon) @@ -78,6 +81,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Disc2) ADDPREPOSTREGVAR(SuperShape) ADDPREPOSTREGVAR(Flower) + ADDPREPOSTREGVAR(FlowerDb) ADDPREPOSTREGVAR(Conic) ADDPREPOSTREGVAR(Parabola) ADDPREPOSTREGVAR(Bent2) @@ -95,9 +99,11 @@ VariationList::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::VariationList() ADDPREPOSTREGVAR(Whorl) ADDPREPOSTREGVAR(Waves2) ADDPREPOSTREGVAR(Exp) + ADDPREPOSTREGVAR(Exp2) ADDPREPOSTREGVAR(Log) ADDPREPOSTREGVAR(Sin) ADDPREPOSTREGVAR(Cos) @@ -118,6 +125,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Sinh) ADDPREPOSTREGVAR(Cosh) ADDPREPOSTREGVAR(Tanh) + ADDPREPOSTREGVAR(TanhSpiral) ADDPREPOSTREGVAR(Sech) ADDPREPOSTREGVAR(Csch) ADDPREPOSTREGVAR(Coth) @@ -126,6 +134,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Hemisphere) ADDPREPOSTREGVAR(Epispiral) ADDPREPOSTREGVAR(Bwraps) + ADDPREPOSTREGVAR(BwrapsRand) ADDPREPOSTREGVAR(BlurCircle) ADDPREPOSTREGVAR(BlurZoom) ADDPREPOSTREGVAR(BlurPixelize) @@ -146,6 +155,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Fibonacci) ADDPREPOSTREGVAR(Fibonacci2) ADDPREPOSTREGVAR(Glynnia) + ADDPREPOSTREGVAR(Glynnia2) ADDPREPOSTREGVAR(GridOut) ADDPREPOSTREGVAR(Hole) ADDPREPOSTREGVAR(Hypertile) @@ -191,6 +201,8 @@ VariationList::VariationList() ADDPREPOSTREGVAR(GlynnSim1) ADDPREPOSTREGVAR(GlynnSim2) ADDPREPOSTREGVAR(GlynnSim3) + ADDPREPOSTREGVAR(GlynnSim4) + ADDPREPOSTREGVAR(GlynnSim5) ADDPREPOSTREGVAR(Starblur) ADDPREPOSTREGVAR(Sineblur) ADDPREPOSTREGVAR(Circleblur) @@ -205,6 +217,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Ovoid3D) ADDPREPOSTREGVAR(Spirograph) ADDPREPOSTREGVAR(Petal) + ADDPREPOSTREGVAR(Spher) ADDPREPOSTREGVAR(RoundSpher) ADDPREPOSTREGVAR(RoundSpher3D) ADDPREPOSTREGVAR(SpiralWing) @@ -217,6 +230,8 @@ VariationList::VariationList() ADDPREPOSTREGVAR(Lissajous) ADDPREPOSTREGVAR(Svf) ADDPREPOSTREGVAR(Target) + ADDPREPOSTREGVAR(Target0) + ADDPREPOSTREGVAR(Target2) ADDPREPOSTREGVAR(Taurus) ADDPREPOSTREGVAR(Collideoscope) ADDPREPOSTREGVAR(BMod) @@ -225,6 +240,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(BCollide) ADDPREPOSTREGVAR(Eclipse) ADDPREPOSTREGVAR(FlipCircle) + ADDPREPOSTREGVAR(FlipX) ADDPREPOSTREGVAR(FlipY) ADDPREPOSTREGVAR(ECollide) ADDPREPOSTREGVAR(EJulia) @@ -234,6 +250,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(ERotate) ADDPREPOSTREGVAR(EScale) ADDPREPOSTREGVAR(ESwirl) + ADDPREPOSTREGVAR(LazyJess) ADDPREPOSTREGVAR(LazyTravis) ADDPREPOSTREGVAR(Squish) ADDPREPOSTREGVAR(Circus) @@ -262,6 +279,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(SuperShape3D) ADDPREPOSTREGVAR(Sphyp3D) ADDPREPOSTREGVAR(Circlecrop) + ADDPREPOSTREGVAR(Circlecrop2) ADDPREPOSTREGVAR(Julian3Dx) ADDPREPOSTREGVAR(Fourth) ADDPREPOSTREGVAR(Mobiq) @@ -288,12 +306,17 @@ VariationList::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::VariationList() ADDPREPOSTREGVAR(Cubic3D) ADDPREPOSTREGVAR(CubicLattice3D) ADDPREPOSTREGVAR(Foci3D) + ADDPREPOSTREGVAR(FociP) ADDPREPOSTREGVAR(Ho) ADDPREPOSTREGVAR(Julia3Dq) ADDPREPOSTREGVAR(Line) @@ -331,6 +355,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(BubbleT3D) ADDPREPOSTREGVAR(Synth) ADDPREPOSTREGVAR(Crackle) + ADDPREPOSTREGVAR(Crackle2) m_Variations.push_back(new PostSmartcropVariation());//Post only ADDPREPOSTREGVAR(Xerf) ADDPREPOSTREGVAR(Erf) @@ -350,7 +375,7 @@ VariationList::VariationList() ADDPREPOSTREGVAR(CircleSplit) ADDPREPOSTREGVAR(Cylinder2) ADDPREPOSTREGVAR(TileLog) - ADDPREPOSTREGVAR(TruchetFill) + ADDPREPOSTREGVAR(TileHlp) ADDPREPOSTREGVAR(Waves2Radial) ADDPREPOSTREGVAR(Panorama1) ADDPREPOSTREGVAR(Panorama2) @@ -360,7 +385,44 @@ VariationList::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. diff --git a/Source/Ember/Variations01.h b/Source/Ember/Variations01.h index eb73a98..79c2e26 100644 --- a/Source/Ember/Variations01.h +++ b/Source/Ember/Variations01.h @@ -168,6 +168,157 @@ public: } }; +/// +/// swirl3. +/// By Zy0rg. +/// +template +class Swirl3Variation : public ParametricVariation +{ +public: + Swirl3Variation(T weight = 1.0) : ParametricVariation("swirl3", eVariationId::VAR_SWIRL3, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Swirl3Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Shift, prefix + "swirl3_shift", T(0.5))); + } + +private: + T m_Shift; +}; + +/// +/// swirl3r. +/// By Zy0rg. +/// +template +class Swirl3rVariation : public ParametricVariation +{ +public: + Swirl3rVariation(T weight = 1.0) : ParametricVariation("swirl3r", eVariationId::VAR_SWIRL3R, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Swirl3rVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Shift, prefix + "swirl3r_shift", T(0.5))); + m_Params.push_back(ParamWithName(&m_Min, prefix + "swirl3r_min", T(0.5), eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Max, prefix + "swirl3r_max", 1, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(true, &m_Minr, prefix + "swirl3r_minr"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Maxr, prefix + "swirl3r_maxr")); + m_Params.push_back(ParamWithName(true, &m_Mina, prefix + "swirl3r_mina")); + m_Params.push_back(ParamWithName(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; +}; + /// /// Horseshoe: /// a = atan2(tx, ty); @@ -1918,6 +2069,43 @@ public: } }; +/// +/// Gaussian. +/// +template +class GaussianVariation : public Variation +{ +public: + GaussianVariation(T weight = 1.0) : Variation("gaussian", eVariationId::VAR_GAUSSIAN, weight) { } + + VARCOPY(GaussianVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = rand.Frand01() * M_2PI; + T r = m_Weight * (rand.Frand01() + rand.Frand01() + rand.Frand01() + rand.Frand01() - 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(); + } +}; + /// /// Radial blur. /// @@ -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; }; +/// +/// flowerdb. +/// By dark-beam. +/// +template +class FlowerDbVariation : public ParametricVariation +{ +public: + FlowerDbVariation(T weight = 1.0) : ParametricVariation("flowerdb", eVariationId::VAR_FLOWER_DB, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(FlowerDbVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Petals, prefix + "flowerdb_petals", 6)); + m_Params.push_back(ParamWithName(&m_Split, prefix + "flowerdb_petal_split")); + m_Params.push_back(ParamWithName(&m_Spread, prefix + "flowerdb_petal_spread", 1)); + m_Params.push_back(ParamWithName(true, &m_PetalsSplit, prefix + "flowerdb_petal_split_petals"));//Precalc. + } + +private: + T m_Petals; + T m_Split; + T m_Spread; + T m_PetalsSplit;//Precalc. +}; + /// /// Conic. /// @@ -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& helper, Point& outPoint, QTIsaac& 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(&m_Separation, prefix + "oscilloscope_separation", 1));//Params. - m_Params.push_back(ParamWithName(&m_Frequency, prefix + "oscilloscope_frequency", T(M_PI))); - m_Params.push_back(ParamWithName(&m_Amplitude, prefix + "oscilloscope_amplitude", 1)); - m_Params.push_back(ParamWithName(&m_Damping, prefix + "oscilloscope_damping")); + m_Params.push_back(ParamWithName(&m_Separation, prefix + "oscilloscope_separation", 1));//Params. + m_Params.push_back(ParamWithName(&m_Frequency, prefix + "oscilloscope_frequency", T(M_PI))); + m_Params.push_back(ParamWithName(&m_Amplitude, prefix + "oscilloscope_amplitude", 1)); + m_Params.push_back(ParamWithName(&m_Damping, prefix + "oscilloscope_damping")); m_Params.push_back(ParamWithName(true, &m_2PiFreq, prefix + "oscilloscope_2pifreq"));//Precalc. } @@ -4646,6 +4973,117 @@ private: T m_2PiFreq;//Precalc. }; +/// +/// Oscilloscope2. +/// By dark-beam. +/// +template +class Oscilloscope2Variation : public ParametricVariation +{ +public: + Oscilloscope2Variation(T weight = 1.0) : ParametricVariation("oscilloscope2", eVariationId::VAR_OSCILLOSCOPE2, weight) + { + Init(); + } + + PARVARCOPY(Oscilloscope2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Separation, prefix + "oscilloscope2_separation", 1, eParamType::REAL, 0));//Params. + m_Params.push_back(ParamWithName(&m_FrequencyX, prefix + "oscilloscope2_frequencyx", T(M_PI))); + m_Params.push_back(ParamWithName(&m_FrequencyY, prefix + "oscilloscope2_frequencyy", T(M_PI))); + m_Params.push_back(ParamWithName(&m_Amplitude, prefix + "oscilloscope2_amplitude", 1)); + m_Params.push_back(ParamWithName(&m_Perturbation, prefix + "oscilloscope2_perturbation", 1)); + m_Params.push_back(ParamWithName(&m_Damping, prefix + "oscilloscope2_damping", 0, eParamType::INTEGER, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_Tpf, prefix + "oscilloscope2_tpf"));//Precalc. + m_Params.push_back(ParamWithName(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; +}; + /// /// Polar2. /// @@ -4833,6 +5271,97 @@ private: T m_InvWeight;//Precalcs only, no params. }; +/// +/// scry2. +/// By dark-beam, modified by tatasz to increase the speed. +/// +template +class Scry2Variation : public ParametricVariation +{ +public: + Scry2Variation(T weight = 1.0) : ParametricVariation("scry2", eVariationId::VAR_SCRY2, weight, true) + { + Init(); + } + + PARVARCOPY(Scry2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(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 OpenCLGlobalFuncNames() const override + { + return vector { "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(&m_Power, prefix + "scry2_power", 4)); + m_Params.push_back(ParamWithName(true, &m_2PiOverPower, prefix + "scry2_2pi_over_power"));//Precalc. + } + +private: + T m_Power; + T m_2PiOverPower;//Precalc. +}; + /// /// Separation. /// @@ -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: } }; +/// +/// Exp2. +/// By tatasz. +/// +template +class Exp2Variation : public Variation +{ +public: + Exp2Variation(T weight = 1.0) : Variation("exp2", eVariationId::VAR_EXP2, weight) { } + + VARCOPY(Exp2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(); + } +}; + /// /// Log. /// @@ -6053,6 +6618,65 @@ public: } }; +/// +/// tanh_spiral. +/// +template +class TanhSpiralVariation : public ParametricVariation +{ +public: + TanhSpiralVariation(T weight = 1.0) : ParametricVariation("tanh_spiral", eVariationId::VAR_TANH_SPIRAL, weight) + { + Init(); + } + + PARVARCOPY(TanhSpiralVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t2 = (rand.Frand01() - 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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "tanh_spiral_a", 4)); + } + +private: + T m_A; +}; + /// /// Sech /// @@ -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) diff --git a/Source/Ember/Variations02.h b/Source/Ember/Variations02.h index feb311e..a5ea044 100644 --- a/Source/Ember/Variations02.h +++ b/Source/Ember/Variations02.h @@ -119,7 +119,7 @@ private: /// /// 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. /// template class BwrapsVariation : public ParametricVariation @@ -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; }; +/// +/// bwraps_rand. +/// By tatasz. +/// +template +class BwrapsRandVariation : public ParametricVariation +{ +public: + BwrapsRandVariation(T weight = 1.0) : ParametricVariation("bwraps_rand", eVariationId::VAR_BWRAPS_RAND, weight) + { + Init(); + } + + PARVARCOPY(BwrapsRandVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(helper.In.x * m_InvCellSize) + T(0.5)) * m_CellSize; + T Cy = (Floor(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::HashShadertoy(Cx, Cy, m_Seed); + else + radius = m_HalfCellSizeOver1pSpaceSq * VarFuncs::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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_CellSize, prefix + "bwraps_rand_cellsize", 1)); + m_Params.push_back(ParamWithName(&m_Space, prefix + "bwraps_rand_space")); + m_Params.push_back(ParamWithName(&m_Gain, prefix + "bwraps_rand_gain", 2)); + m_Params.push_back(ParamWithName(&m_InnerTwist, prefix + "bwraps_rand_inner_twist")); + m_Params.push_back(ParamWithName(&m_OuterTwist, prefix + "bwraps_rand_outer_twist")); + m_Params.push_back(ParamWithName(&m_Symm, prefix + "bwraps_rand_symm")); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "bwraps_rand_seed", 1)); + m_Params.push_back(ParamWithName(true, &m_InvCellSize, prefix + "bwraps_rand_inv_cellsize"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_G2, prefix + "bwraps_rand_g2")); + m_Params.push_back(ParamWithName(true, &m_SpaceSq, prefix + "bwraps_rand_space_sq")); + m_Params.push_back(ParamWithName(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; +}; + /// /// BlurCircle. /// @@ -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. }; +/// +/// Glynnia2. +/// By guagapunyaimel. +/// +template +class Glynnia2Variation : public ParametricVariation +{ +public: + Glynnia2Variation(T weight = 1.0) : ParametricVariation("glynnia2", eVariationId::VAR_GLYNNIA2, weight, true, true) + { + Init(); + } + + PARVARCOPY(Glynnia2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T d, r = helper.m_PrecalcSqrtSumSquares; + + if (r > 0 && helper.In.y > 0) + { + if (rand.Frand01() > 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(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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_V2, prefix + "glynnia2_v2"));//Precalcs only, no params. + } + +private: + T m_V2;//Precalcs only, no params. +}; + /// /// GridOut. /// @@ -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) diff --git a/Source/Ember/Variations03.h b/Source/Ember/Variations03.h index 71a8393..239dede 100644 --- a/Source/Ember/Variations03.h +++ b/Source/Ember/Variations03.h @@ -721,7 +721,7 @@ protected: { string prefix = Prefix(); m_Params.clear(); - m_Params.push_back(ParamWithName(&m_Radius, prefix + "GlynnSim2_radius", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "GlynnSim2_radius", 1, eParamType::REAL, 0)); m_Params.push_back(ParamWithName(&m_Thickness, prefix + "GlynnSim2_thickness", T(0.1), eParamType::REAL, 0, 1)); m_Params.push_back(ParamWithName(&m_Contrast, prefix + "GlynnSim2_contrast", T(0.5), eParamType::REAL, 0, 1)); m_Params.push_back(ParamWithName(&m_Pow, prefix + "GlynnSim2_pow", T(1.5))); @@ -919,6 +919,219 @@ private: T m_Gamma; }; +/// +/// GlynnSim4. +/// +template +class GlynnSim4Variation : public ParametricVariation +{ +public: + GlynnSim4Variation(T weight = 1.0) : ParametricVariation("GlynnSim4", eVariationId::VAR_GLYNNSIM4, weight, true, true) + { + Init(); + } + + PARVARCOPY(GlynnSim4Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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() > 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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "GlynnSim4_radius", 1)); + m_Params.push_back(ParamWithName(&m_Contrast, prefix + "GlynnSim4_contrast", T(0.5), eParamType::REAL, 0, 1)); + m_Params.push_back(ParamWithName(&m_Pow, prefix + "GlynnSim4_pow", T(1.5))); + m_Params.push_back(ParamWithName(&m_X, prefix + "GlynnSim4_X")); + m_Params.push_back(ParamWithName(&m_Y, prefix + "GlynnSim4_Y")); + } + +private: + T m_Radius;//Params. + T m_Contrast; + T m_Pow; + T m_X; + T m_Y; +}; + +/// +/// GlynnSim5. +/// +template +class GlynnSim5Variation : public ParametricVariation +{ +public: + GlynnSim5Variation(T weight = 1.0) : ParametricVariation("GlynnSim5", eVariationId::VAR_GLYNNSIM5, weight, true, true) + { + Init(); + } + + PARVARCOPY(GlynnSim5Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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() > 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 OpenCLGlobalFuncNames() const override + { + return vector { "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(&m_Radius, prefix + "GlynnSim5_radius", 1)); + m_Params.push_back(ParamWithName(&m_Thickness, prefix + "GlynnSim5_thickness", T(0.1))); + m_Params.push_back(ParamWithName(&m_Contrast, prefix + "GlynnSim5_contrast", T(0.5), eParamType::REAL, 0, 1)); + m_Params.push_back(ParamWithName(&m_Pow, prefix + "GlynnSim5_pow", T(1.5))); + m_Params.push_back(ParamWithName(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. +}; + /// /// Starblur. /// @@ -1986,6 +2199,80 @@ public: } }; +/// +/// Spher. +/// +template +class SpherVariation : public Variation +{ +public: + SpherVariation(T weight = 1.0) : Variation("spher", eVariationId::VAR_SPHER, weight, true) { } + + VARCOPY(SpherVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r2 = Zeps(helper.m_PrecalcSumSquares); + + if (r2 > 1) + { + if (rand.Frand01() < 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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } +}; + /// /// RoundSpher. /// @@ -3055,9 +3342,9 @@ protected: { string prefix = Prefix(); m_Params.clear(); - m_Params.push_back(ParamWithName(&m_Even, prefix + "target_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); - m_Params.push_back(ParamWithName(&m_Odd, prefix + "target_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); - m_Params.push_back(ParamWithName(&m_Size, prefix + "target_size", 1, eParamType::REAL, EPS, TMAX)); + m_Params.push_back(ParamWithName(&m_Even, prefix + "target_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Odd, prefix + "target_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Size, prefix + "target_size", 1, eParamType::REAL, EPS, TMAX)); m_Params.push_back(ParamWithName(true, &m_SizeDiv2, prefix + "target_size_2"));//Precalc. } @@ -3068,6 +3355,191 @@ private: T m_SizeDiv2;//Precalc. }; +/// +/// target0. +/// By Mark Faber. +/// +template +class Target0Variation : public ParametricVariation +{ +public: + Target0Variation(T weight = 1.0) : ParametricVariation("target0", eVariationId::VAR_TARGET0, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Target0Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Even, prefix + "target0_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Odd, prefix + "target0_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Size, prefix + "target0_size", 0, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(true, &m_SizeDiv2, prefix + "target0_size_2"));//Precalc. + } + +private: + T m_Even; + T m_Odd; + T m_Size; + T m_SizeDiv2;//Precalc. +}; + +/// +/// target2. +/// By Mark Faber. +/// +template +class Target2Variation : public ParametricVariation +{ +public: + Target2Variation(T weight = 1.0) : ParametricVariation("target2", eVariationId::VAR_TARGET2, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Target2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Even, prefix + "target2_even", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Odd, prefix + "target2_odd", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Size, prefix + "target2_size", 1, eParamType::REAL, EPS, TMAX)); + m_Params.push_back(ParamWithName(&m_Tightness, prefix + "target2_thightness")); + m_Params.push_back(ParamWithName(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. +}; + /// /// taurus. /// @@ -3780,6 +4252,49 @@ private: T m_WeightSquared; }; +/// +/// flipx. +/// By tatasz. +/// +template +class FlipXVariation : public Variation +{ +public: + FlipXVariation(T weight = 1.0) : Variation("flipx", eVariationId::VAR_FLIP_X, weight) { } + + VARCOPY(FlipXVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(); + } +}; + /// /// flipy. /// @@ -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) diff --git a/Source/Ember/Variations04.h b/Source/Ember/Variations04.h index f5103bc..2a8515c 100644 --- a/Source/Ember/Variations04.h +++ b/Source/Ember/Variations04.h @@ -87,6 +87,246 @@ private: T m_Out; }; +/// +/// lazyjess. +/// By FarDareisMai. +/// +template +class LazyJessVariation : public ParametricVariation +{ +public: + LazyJessVariation(T weight = 1.0) : ParametricVariation("lazyjess", eVariationId::VAR_LAZYJESS, weight, true, true) + { + Init(); + } + + PARVARCOPY(LazyJessVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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::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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Hypot" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_N, prefix + "lazyjess_n", 4, eParamType::INTEGER_NONZERO, 2)); + m_Params.push_back(ParamWithName(&m_Spin, prefix + "lazyjess_spin", T(M_PI), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Space, prefix + "lazyjess_space")); + m_Params.push_back(ParamWithName(&m_Corner, prefix + "lazyjess_corner", 1, eParamType::INTEGER_NONZERO)); + m_Params.push_back(ParamWithName(true, &m_Vertex, prefix + "lazyjess_vertex"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_SinVertex, prefix + "lazyjess_sin_vertex")); + m_Params.push_back(ParamWithName(true, &m_PieSlice, prefix + "lazyjess_pie_slice")); + m_Params.push_back(ParamWithName(true, &m_HalfSlice, prefix + "lazyjess_half_slice")); + m_Params.push_back(ParamWithName(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; +}; + /// /// lazyTravis. /// @@ -2106,6 +2346,116 @@ private: T m_Ca;//Precalc. }; +/// +/// circlecrop2. +/// By tatasz. +/// +template +class Circlecrop2Variation : public ParametricVariation +{ +public: + Circlecrop2Variation(T weight = 1.0) : ParametricVariation("circlecrop2", eVariationId::VAR_CIRCLECROP2, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(Circlecrop2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(&m_Inner, prefix + "circlecrop2_inner", T(0.5))); + m_Params.push_back(ParamWithName(&m_Outer, prefix + "circlecrop2_outer", 1)); + m_Params.push_back(ParamWithName(&m_Zero, prefix + "circlecrop2_zero", 1, eParamType::INTEGER, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_In, prefix + "circlecrop2_in")); + m_Params.push_back(ParamWithName(true, &m_Out, prefix + "circlecrop2_out")); + m_Params.push_back(ParamWithName(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; +}; + /// /// julian3Dx. /// @@ -4453,6 +4803,80 @@ private: T m_Scale; }; +/// +/// truchet_knot. +/// +template +class TruchetKnotVariation : public Variation +{ +public: + TruchetKnotVariation(T weight = 1.0) : Variation("truchet_knot", eVariationId::VAR_TRUCHET_KNOT, weight) { } + + VARCOPY(TruchetKnotVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T wd = T(0.5); + T space = T(0.1); + T cellx = T(Floor(helper.In.x)); + T celly = T(Floor(helper.In.y)); + T xy0x = (rand.Frand01() - T(0.5)) * wd; + T xy0y = (rand.Frand01() * 2 - 1) * (1 - space - wd * T(0.5)); + T dir0 = std::abs(cellx + celly); + T dir1 = dir0 - 2 * Floor(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(); + } +}; + /// /// gdoffs. /// @@ -5193,7 +5617,86 @@ private: T m_Vy; }; +/// +/// block. +/// By TyrantWave. +/// +template +class BlockVariation : public ParametricVariation +{ +public: + BlockVariation(T weight = 1.0) : ParametricVariation("block", eVariationId::VAR_BLOCK, weight, true) + { + Init(); + } + + PARVARCOPY(BlockVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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::SafeSqrt(1 - SQR(a)); + helper.Out.x = m_WightDivPiOver2 * std::atan2(a, b); + a = helper.In.y / Zeps(ymax); + b = VarFuncs::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 OpenCLGlobalFuncNames() const override + { + return vector { "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(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) ///// diff --git a/Source/Ember/Variations05.h b/Source/Ember/Variations05.h index 197fa9f..520ab10 100644 --- a/Source/Ember/Variations05.h +++ b/Source/Ember/Variations05.h @@ -1083,6 +1083,77 @@ public: } }; +/// +/// foci_p. +/// Idea by Chaosfissure. +/// +template +class FociPVariation : public ParametricVariation +{ +public: + FociPVariation(T weight = 1.0) : ParametricVariation("foci_p", eVariationId::VAR_FOCI_P, weight) + { + Init(); + } + + PARVARCOPY(FociPVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_C1, prefix + "foci_p_c1", T(0.5))); + m_Params.push_back(ParamWithName(&m_C2, prefix + "foci_p_c2", T(0.5))); + } + +private: + T m_C1; + T m_C2; +}; + /// /// ho. /// @@ -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) diff --git a/Source/Ember/Variations06.h b/Source/Ember/Variations06.h index c01a9eb..17cf86b 100644 --- a/Source/Ember/Variations06.h +++ b/Source/Ember/Variations06.h @@ -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(&m_CellSize, prefix + "crackle_cellsize", 1, eParamType::REAL, T(0.0001))); - m_Params.push_back(ParamWithName(&m_Power, prefix + "crackle_power", T(0.2))); - m_Params.push_back(ParamWithName(&m_Distort, prefix + "crackle_distort")); - m_Params.push_back(ParamWithName(&m_Scale, prefix + "crackle_scale", 1)); - m_Params.push_back(ParamWithName(&m_Z, prefix + "crackle_z")); + m_Params.push_back(ParamWithName(&m_CellSize, prefix + "crackle_cellsize", 1, eParamType::REAL, T(0.0001))); + m_Params.push_back(ParamWithName(&m_Power, prefix + "crackle_power", T(0.2))); + m_Params.push_back(ParamWithName(&m_Distort, prefix + "crackle_distort")); + m_Params.push_back(ParamWithName(&m_Scale, prefix + "crackle_scale", 1)); + m_Params.push_back(ParamWithName(&m_Z, prefix + "crackle_z")); m_Params.push_back(ParamWithName(true, &m_HalfCellSize, prefix + "crackle_half_cellsize")); - m_Params.push_back(ParamWithName(true, &(m_C[0][0].x), prefix + "crackle_cache", sizeof(m_C))); + m_Params.push_back(ParamWithName(true, &(m_C[0][0].x), prefix + "crackle_cache", sizeof(m_C))); } private: @@ -3927,6 +3927,115 @@ private: shared_ptr> m_VarFuncs = VarFuncs::Instance(); }; +/// +/// crackle2. +/// By tatasz. +/// +template +class Crackle2Variation : public ParametricVariation +{ +public: + Crackle2Variation(T weight = 1.0) : ParametricVariation("crackle2", eVariationId::VAR_CRACKLE2, weight) + { + Init(); + } + + PARVARCOPY(Crackle2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T seed = 34554; + v2T cell(Floor(helper.In.x), Floor(helper.In.y)); + v2T xy0(cell.x + m_OneOverCellsize * VarFuncs::HashShadertoy(cell.x, cell.y, seed), cell.y + m_OneOverCellsize * VarFuncs::HashShadertoy(cell.y, cell.x * 3, seed + 7)); + v2T xy1_aux; + + if (rand.Frand01() < 0.5) + { + if (rand.Frand01() < 0.5) + xy1_aux = v2T(cell.x, cell.y + 1); + else + xy1_aux = v2T(cell.x, cell.y - 1); + } + else + { + if (rand.Frand01() < 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::HashShadertoy(xy1_aux.x, xy1_aux.y, seed), xy1_aux.y + m_OneOverCellsize * VarFuncs::HashShadertoy(xy1_aux.y, xy1_aux.x * 3, seed + 7)); + v2T v = xy1 - xy0; + v2T result = (xy0 + v * rand.Frand01()) * 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 OpenCLGlobalFuncNames() const override + { + return vector { "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(&m_Cellsize, prefix + "crackle2_cellsize", 1, eParamType::REAL, T(0.0001))); + m_Params.push_back(ParamWithName(true, &m_OneOverCellsize, prefix + "crackle2_one_over_cellsize")); + } + +private: + T m_Cellsize; + T m_OneOverCellsize; +}; + /// /// 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) diff --git a/Source/Ember/Variations07.h b/Source/Ember/Variations07.h index 8195ac9..6615e1a 100644 --- a/Source/Ember/Variations07.h +++ b/Source/Ember/Variations07.h @@ -180,8 +180,8 @@ public: << "\t\t JacobiElliptic(vIn.y * " << freqx << ", " << jacok << ", &jcbSn, &jcbCn, &jcbDn);\n" << "\t\t vOut.x = " << weight << " * fma(CsX, jcbSn, vIn.x);\n" << "\t\t}\n" - //<< "\t\telse if (" << pwx << " < 0 && " << pwx << " > -1e-4)\n" - //<< "\t\t vOut.x = " << weight << " * (vIn.x + CsX * _j1(vIn.y * " << freqx << "));\n"//This is not implemented in OpenCL. + << "\t\telse if (" << pwx << " < 0 && " << pwx << " > -1e-4)\n" + << "\t\t vOut.x = " << weight << " * (vIn.x + CsX * J1(vIn.y * " << freqx << ", globalShared + P1, globalShared + Q1, globalShared + P2, globalShared + Q2, globalShared + PC, globalShared + QC, globalShared + PS, globalShared + QS));\n"//J1 is manually implemented in OpenCL. << "\t\telse\n" << "\t\t vOut.x = " << weight << " * fma(CsX, sin(SignNz(vIn.y) * pow(Zeps(fabs(vIn.y)), " << pwx << ") * " << freqx << "), vIn.x);\n" << "\n" @@ -190,8 +190,8 @@ public: << "\t\t JacobiElliptic(vIn.x * " << freqy << ", " << jacok << ", &jcbSn, &jcbCn, &jcbDn);\n" << "\t\t vOut.y = " << weight << " * fma(CsY, jcbSn, vIn.y);\n" << "\t\t}\n" - //<< "\t\telse if (" << pwy << " < 0 && " << pwy << " > -1e-4)\n" - //<< "\t\t vOut.y = " << weight << " * (vIn.y + CsY * _j1(vIn.x * " << freqy << "));\n"//This is not implemented in OpenCL. + << "\t\telse if (" << pwy << " < 0 && " << pwy << " > -1e-4)\n" + << "\t\t vOut.y = " << weight << " * (vIn.y + CsY * J1(vIn.x * " << freqy << ", globalShared + P1, globalShared + Q1, globalShared + P2, globalShared + Q2, globalShared + PC, globalShared + QC, globalShared + PS, globalShared + QS));\n"//J1 is manually implemented in OpenCL. << "\t\telse\n" << "\t\t vOut.y = " << weight << " * fma(CsY, sin(SignNz(vIn.x) * pow(Zeps(fabs(vIn.x)), " << pwy << ") * " << freqy << "), vIn.y);\n" << "\n" @@ -202,7 +202,12 @@ public: virtual vector OpenCLGlobalFuncNames() const override { - return vector { "Zeps", "Sqr", "SignNz", "SafeDivInv", "JacobiElliptic" }; + return vector { "Zeps", "Sqr", "SignNz", "SafeDivInv", "JacobiElliptic", "EvalRational", "J1" }; + } + + virtual vector OpenCLGlobalDataNames() const override + { + return vector { "P1", "Q1", "P2", "Q2", "PC", "QC", "PS", "QS" }; } virtual void Precalc() override @@ -216,16 +221,16 @@ protected: { string prefix = Prefix(); m_Params.clear(); - m_Params.push_back(ParamWithName(&m_Freqx, prefix + "waves2b_freqx", 2)); - m_Params.push_back(ParamWithName(&m_Freqy, prefix + "waves2b_freqy", 2)); - m_Params.push_back(ParamWithName(&m_Pwx, prefix + "waves2b_pwx", 1, eParamType::REAL, -10, 10)); - m_Params.push_back(ParamWithName(&m_Pwy, prefix + "waves2b_pwy", 1, eParamType::REAL, -10, 10)); - m_Params.push_back(ParamWithName(&m_Scalex, prefix + "waves2b_scalex", 1)); + m_Params.push_back(ParamWithName(&m_Freqx, prefix + "waves2b_freqx", 2)); + m_Params.push_back(ParamWithName(&m_Freqy, prefix + "waves2b_freqy", 2)); + m_Params.push_back(ParamWithName(&m_Pwx, prefix + "waves2b_pwx", 1, eParamType::REAL, -10, 10)); + m_Params.push_back(ParamWithName(&m_Pwy, prefix + "waves2b_pwy", 1, eParamType::REAL, -10, 10)); + m_Params.push_back(ParamWithName(&m_Scalex, prefix + "waves2b_scalex", 1)); m_Params.push_back(ParamWithName(&m_Scaleinfx, prefix + "waves2b_scaleinfx", 1)); - m_Params.push_back(ParamWithName(&m_Scaley, prefix + "waves2b_scaley", 1)); + m_Params.push_back(ParamWithName(&m_Scaley, prefix + "waves2b_scaley", 1)); m_Params.push_back(ParamWithName(&m_Scaleinfy, prefix + "waves2b_scaleinfy", 1)); - m_Params.push_back(ParamWithName(&m_Unity, prefix + "waves2b_unity", 1)); - m_Params.push_back(ParamWithName(&m_Jacok, prefix + "waves2b_jacok", T(0.25), eParamType::REAL, -1, 1)); + m_Params.push_back(ParamWithName(&m_Unity, prefix + "waves2b_unity", 1)); + m_Params.push_back(ParamWithName(&m_Jacok, prefix + "waves2b_jacok", T(0.25), eParamType::REAL, -1, 1)); m_Params.push_back(ParamWithName(true, &m_Six, prefix + "waves2b_six"));//Precalc. m_Params.push_back(ParamWithName(true, &m_Siy, prefix + "waves2b_siy")); } @@ -862,7 +867,7 @@ private: /// /// log_db. -/// By DarkBeam, taken from JWildfire. +/// By dark-beam, taken from JWildfire. /// http://jwildfire.org/forum/viewtopic.php?f=23&t=1450&p=2692#p2692 /// template @@ -1083,10 +1088,87 @@ public: } }; +/// +/// tile_hlp. +/// By zy0rg. +/// +template +class TileHlpVariation : public ParametricVariation +{ +public: + TileHlpVariation(T weight = 1.0) : ParametricVariation("tile_hlp", eVariationId::VAR_TILE_HLP, weight) + { + Init(); + } + + PARVARCOPY(TileHlpVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T temp, x = helper.In.x / m_Width; + bool pos = x > 0; + + if (std::cos((pos ? x - (int)x : x + (int)x) * M_PI) < rand.Frand01() * 2 - 1) + temp = pos ? -m_Vwidth : m_Vwidth; + else + temp = 0; + + helper.Out.x = m_Weight * helper.In.x + temp; + 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 width = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string vwidth = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t temp, x = vIn.x / Zeps(" << width << ");\n" + << "\t\tbool pos = x > 0;\n" + << "\n" + << "\t\tif (cos((pos ? x - (int)x : x + (int)x) * MPI) < MwcNext01(mwc) * 2 - 1)\n" + << "\t\t temp = pos ? -" << vwidth << " : " << vwidth << ";\n" + << "\t\telse\n" + << "\t\t temp = 0;\n" + << "\t\tvOut.x = fma(" << weight << ", vIn.x, temp);\n" + << "\t\tvOut.y = " << weight << " * vIn.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + + virtual void Precalc() override + { + m_Vwidth = m_Width * m_Weight; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Width, prefix + "tile_hlp_width", 1, eParamType::REAL_NONZERO)); + m_Params.push_back(ParamWithName(true, &m_Vwidth, prefix + "tile_hlp_v_width"));//Precalc. + } + +private: + T m_Width; + T m_Vwidth;//Precalc. +}; + /// /// tile_log. /// By zy0rg. -/// http://zy0rg.deviantart.com /// template class TileLogVariation : public ParametricVariation @@ -1364,7 +1446,7 @@ public: m_OneOverEx = T(1) / m_FinalExponent; m_Width = m_ArcWidth > T(1) ? T(1) : (m_ArcWidth < T(0.001) ? T(0.001) : m_ArcWidth); m_Seed2 = std::sqrt(m_Seed * T(1.5)) / Zeps(m_Seed * T(0.5)) * T(0.25); - m_Rmax = T(0.5) * (std::pow(T(2), m_OneOverEx) - T(1)) * m_Width; + m_Rmax = Zeps(T(0.5) * (std::pow(T(2), m_OneOverEx) - T(1)) * m_Width); m_Scale = T(1) / m_Weight; } @@ -1373,15 +1455,15 @@ protected: { string prefix = Prefix(); m_Params.clear(); - m_Params.push_back(ParamWithName(&m_Exponent, prefix + "Truchet_fill_exponent", 2, eParamType::REAL_CYCLIC, T(0.001), 2)); - m_Params.push_back(ParamWithName(&m_ArcWidth, prefix + "Truchet_fill_arc_width", T(0.5), eParamType::REAL_CYCLIC, T(0.001), 1)); - m_Params.push_back(ParamWithName(&m_Seed, prefix + "Truchet_fill_seed")); + m_Params.push_back(ParamWithName(&m_Exponent, prefix + "Truchet_fill_exponent", 2, eParamType::REAL_CYCLIC, T(0.001), 2)); + m_Params.push_back(ParamWithName(&m_ArcWidth, prefix + "Truchet_fill_arc_width", T(0.5), eParamType::REAL_CYCLIC, T(0.001), 1)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "Truchet_fill_seed")); m_Params.push_back(ParamWithName(true, &m_FinalExponent, prefix + "Truchet_fill_final_exponent"));//Precalc - m_Params.push_back(ParamWithName(true, &m_OneOverEx, prefix + "Truchet_fill_oneoverex")); - m_Params.push_back(ParamWithName(true, &m_Width, prefix + "Truchet_fill_width")); - m_Params.push_back(ParamWithName(true, &m_Seed2, prefix + "Truchet_fill_seed2")); - m_Params.push_back(ParamWithName(true, &m_Rmax, prefix + "Truchet_fill_rmax")); - m_Params.push_back(ParamWithName(true, &m_Scale, prefix + "Truchet_fill_scale")); + m_Params.push_back(ParamWithName(true, &m_OneOverEx, prefix + "Truchet_fill_oneoverex")); + m_Params.push_back(ParamWithName(true, &m_Width, prefix + "Truchet_fill_width")); + m_Params.push_back(ParamWithName(true, &m_Seed2, prefix + "Truchet_fill_seed2")); + m_Params.push_back(ParamWithName(true, &m_Rmax, prefix + "Truchet_fill_rmax")); + m_Params.push_back(ParamWithName(true, &m_Scale, prefix + "Truchet_fill_scale")); } private: @@ -1567,53 +1649,6 @@ public: } }; -/// -/// arcsinh. -/// -/* - template - class ArcsinhVariation : public ParametricVariation - { - public: - ArcsinhVariation(T weight = 1.0) : ParametricVariation("arcsinh", eVariationId::VAR_ARCSINH, weight, false, false, false, false, false) - { - } - - PARVARCOPY(ArcsinhVariation) - - virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override - { - std::complex z(helper.m_TransX, helper.m_TransY); - std::complex result = m_Vpi * std::log(z + std::sqrt(z * z + 1.0)); - helper.Out.x = result.real(); - helper.Out.y = result.imag(); - helper.Out.z = DefaultZ(helper); - } - - virtual string OpenCLString() const override//Hold off on this for now, opencl doesn't have support for complex. - { - ostringstream ss, ss2; - - return ss.str(); - } - - virtual void Precalc() override - { - m_Vpi = m_Weight * M_2_PI; - } - - protected: - void Init() - { - string prefix = Prefix(); - m_Params.clear(); - m_Params.push_back(ParamWithName(true, &m_Vpi, prefix + "arcsinh_vpi"));//Precalc. - } - - private: - T m_Vpi;//Precalc. - };*/ - /// /// helicoid. /// @@ -1776,7 +1811,7 @@ public: ss << "\t{\n" << "\t\treal_t ang = MwcNext01(mwc) * M_2PI;\n" << "\t\treal_t angz = acos(MwcNext01(mwc) * 2 - 1);\n" - << "\t\treal_t r = " << weight << " * exp(log(acos((" << power << " == 1.0 ? MwcNext01(mwc) : exp(log(MwcNext01(mwc)) * " << power << ")) * 2 - 1) / M_PI) / 1.5);\n" + << "\t\treal_t r = " << weight << " * exp(log(acos((" << power << " == 1.0 ? MwcNext01(mwc) : exp(log(MwcNext01(mwc)) * " << power << ")) * 2 - 1) / MPI) / 1.5);\n" << "\t\treal_t s = sin(ang);\n" << "\t\treal_t c = cos(ang);\n" << "\t\treal_t sz = sin(angz);\n" @@ -2088,10 +2123,10 @@ public: << "\t\treal_t fx = vIn.x;\n" << "\t\treal_t fy = vIn.y;\n" << "\t\treal_t fz = vIn.z;\n" - << "\t\treal_t a0 = M_PI / " << n << ";\n" + << "\t\treal_t a0 = MPI / " << n << ";\n" << "\t\treal_t len = 1 / Zeps(cos(a0));\n" << "\t\treal_t d = " << rad << " * sin(a0) * len;\n" - << "\t\treal_t angle = floor(precalcAtanyx * " << coeff << ") / " << coeff << " + M_PI / " << n << ";\n" + << "\t\treal_t angle = floor(precalcAtanyx * " << coeff << ") / " << coeff << " + MPI / " << n << ";\n" << "\t\treal_t x0 = cos(angle) * len;\n" << "\t\treal_t y0 = sin(angle) * len;\n" << "\t\treal_t xmx = vIn.x - x0;\n" @@ -2159,6 +2194,84 @@ private: T m_Coeff;//Precalc. }; +/// +/// hypershift. +/// +template +class HypershiftVariation : public ParametricVariation +{ +public: + HypershiftVariation(T weight = 1.0) : ParametricVariation("hypershift", eVariationId::VAR_HYPERSHIFT, weight, true) + { + Init(); + } + + PARVARCOPY(HypershiftVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T rad = 1 / Zeps(helper.m_PrecalcSumSquares); + T x = rad * helper.In.x + m_Shift; + T y = rad * helper.In.y; + rad = m_Weight * m_Scale / Zeps(x * x + y * y); + + if (m_VarType == eVariationType::VARTYPE_REG) + outPoint.m_X = outPoint.m_Y = outPoint.m_Z = 0;//This variation assigns, instead of summing, so order will matter. + + helper.Out.x = rad * x + m_Shift; + helper.Out.y = rad * 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 shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t rad = 1 / Zeps(precalcSumSquares);\n" + << "\t\treal_t x = fma(rad, vIn.x, " << shift << ");\n" + << "\t\treal_t y = rad * vIn.y;\n" + << "\t\trad = " << weight << " * " << scale << " / Zeps(fma(x, x, SQR(y)));\n"; + + if (m_VarType == eVariationType::VARTYPE_REG) + ss << "\t\toutPoint->m_X = outPoint->m_Y = outPoint->m_Z = 0;\n"; + + ss << "\t\tvOut.x = fma(rad, x, " << shift << ");\n" + << "\t\tvOut.y = rad * y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Scale = 1 - SQR(m_Shift); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "hypershift_shift", T(0.01))); + m_Params.push_back(ParamWithName(true, &m_Scale, prefix + "hypershift_scale"));//Precalc. + } + +private: + T m_Shift; + T m_Scale;//Precalc. +}; + /// /// hypershift2. /// @@ -2214,7 +2327,7 @@ public: << "\t\treal_t x = rad * fx + " << shift << ";\n" << "\t\treal_t y = rad * fy;\n" << "\t\trad = " << weight << " * " << shift << " / Zeps(fma(x, x, SQR(y)));\n" - << "\t\treal_t angle = (MwcNextRange(mwc, (int)" << p << ") * 2 + 1) * M_PI / " << p << ";\n" + << "\t\treal_t angle = (MwcNextRange(mwc, (int)" << p << ") * 2 + 1) * MPI / " << p << ";\n" << "\t\treal_t X = fma(rad, x, " << shift << ");\n" << "\t\treal_t Y = rad * y;\n" << "\t\treal_t cosa = cos(angle);\n" @@ -2240,7 +2353,7 @@ public: m_Shift = m_Shift / std::sqrt(1 - Sqr(spq) - Sqr(spp)); m_Scale2 = 1 / std::sqrt(Sqr(sin(T(M_PI) / 2 + pp)) / Sqr(spq) - 1); m_Scale2 = m_Scale2 * (std::sin(T(M_PI) / 2 + pp) / spq - 1); - m_Scale = 1 - m_Shift * m_Shift; + m_Scale = 1 - SQR(m_Shift); } virtual vector OpenCLGlobalFuncNames() const override @@ -2268,6 +2381,4237 @@ private: T m_Scale2; }; +/// +/// lens. +/// By tatasz. +/// +template +class LensVariation : public Variation +{ +public: + LensVariation(T weight = 1.0) : Variation("lens", eVariationId::VAR_LENS, weight) + { + } + + VARCOPY(LensVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = T(0.5) * (SQR(helper.In.x) - SQR(helper.In.y)) * m_Weight; + helper.Out.y = helper.In.x * helper.In.y * m_Weight; + helper.Out.z = DefaultZ(helper); + } + + virtual string OpenCLString() const override + { + ostringstream ss; + string weight = WeightDefineString(); + ss << "\t{\n" + << "\t\tvOut.x = (real_t)0.5 * fma(vIn.x, vIn.x, -SQR(vIn.y)) * " << weight << ";\n" + << "\t\tvOut.y = vIn.x * vIn.y * " << weight << ";\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } +}; + +/// +/// projective. +/// By eralex61. +/// +template +class ProjectiveVariation : public ParametricVariation +{ +public: + ProjectiveVariation(T weight = 1.0) : ParametricVariation("projective", eVariationId::VAR_PROJECTIVE, weight) + { + Init(); + } + + PARVARCOPY(ProjectiveVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T s = m_Weight / Zeps(m_A * helper.In.x + m_B * helper.In.y + m_C); + helper.Out.x = (m_A1 * helper.In.x + m_B1 * helper.In.y + m_C1) * s; + helper.Out.y = (m_A2 * helper.In.x + m_B2 * helper.In.y + m_C2) * s; + 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; + string b = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string a1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string b1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string a2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string b2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string c2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t s = " << weight << " / Zeps(fma(" << a << ", vIn.x, fma(" << b << ", vIn.y, " << c << ")));\n" + << "\t\tvOut.x = fma(" << a1 << ", vIn.x, fma(" << b1 << ", vIn.y, " << c1 << ")) * s;\n" + << "\t\tvOut.y = fma(" << a2 << ", vIn.x, fma(" << b2 << ", vIn.y, " << c2 << ")) * s;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "projective_A")); + m_Params.push_back(ParamWithName(&m_B, prefix + "projective_B")); + m_Params.push_back(ParamWithName(&m_C, prefix + "projective_C", 1)); + m_Params.push_back(ParamWithName(&m_A1, prefix + "projective_A1", 1)); + m_Params.push_back(ParamWithName(&m_B1, prefix + "projective_B1")); + m_Params.push_back(ParamWithName(&m_C1, prefix + "projective_C1")); + m_Params.push_back(ParamWithName(&m_A2, prefix + "projective_A2")); + m_Params.push_back(ParamWithName(&m_B2, prefix + "projective_B2", 1)); + m_Params.push_back(ParamWithName(&m_C2, prefix + "projective_C2")); + } + +private: + T m_A; + T m_B; + T m_C; + T m_A1; + T m_B1; + T m_C1; + T m_A2; + T m_B2; + T m_C2; +}; + +/// +/// depth_blur. +/// By tatasz. +/// +template +class DepthBlurVariation : public ParametricVariation +{ +public: + DepthBlurVariation(T weight = 1.0) : ParametricVariation("depth_blur", eVariationId::VAR_DEPTH_BLUR, weight, true, true) + { + Init(); + } + + PARVARCOPY(DepthBlurVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = helper.m_PrecalcSqrtSumSquares; + + if (rad > m_Radius) + { + T f = rand.Frand01() * m_Power2; + T int_angle = std::trunc(f); + f = f - int_angle; + T x = f * m_Length; + T z = std::sqrt(1 + SQR(x) - 2 * x * m_CosAlpha); + + if (!(((int)int_angle) & 1)) + int_angle = m_2piOverPower * (((int)int_angle) / 2) + std::asin(m_SinAlpha * x / Zeps(z)); + else + int_angle = m_2piOverPower * (((int)int_angle) / 2) - std::asin(m_SinAlpha * x / Zeps(z)); + + z *= std::sqrt(rand.Frand01()); + by = std::sin(int_angle - T(M_PI_2)); + bx = std::cos(int_angle - T(M_PI_2)); + T aux = z * m_BlurOver10 * (rad - m_Radius); + by = aux * by; + bx = aux * bx; + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string range = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string alpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string length = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twopioverpower = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinalpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosalpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t f = MwcNext01(mwc) * " << power2 << ";\n" + << "\t\t real_t int_angle = trunc(f);\n" + << "\t\t f = f - int_angle;\n" + << "\t\t real_t x = f * " << length << ";\n" + << "\t\t real_t z = sqrt(1 + SQR(x) - 2 * x * " << cosalpha << ");\n" + << "\n" + << "\t\t if (!(((int)int_angle) & 1))\n" + << "\t\t int_angle = " << twopioverpower << " * (((int)int_angle) / 2) + asin(" << sinalpha << " * x / Zeps(z));\n" + << "\t\t else\n" + << "\t\t int_angle = " << twopioverpower << " * (((int)int_angle) / 2) - asin(" << sinalpha << " * x / Zeps(z));\n" + << "\n" + << "\t\t z *= sqrt(MwcNext01(mwc));\n" + << "\t\t by = sin(int_angle - MPI2);\n" + << "\t\t bx = cos(int_angle - MPI2);\n" + << "\t\t real_t aux = z * " << blurover10 << " * (rad - " << radius << ");\n" + << "\t\t by = aux * by;\n" + << "\t\t bx = aux * bx;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T alpha = T(M_PI) / Zeps(m_Power); + m_Length = T(std::sqrt(1 + SQR(m_Range) - 2 * m_Range * std::cos(alpha))); + m_Alpha = std::asin(std::sin(alpha) * m_Range / Zeps(m_Length)); + m_BlurOver10 = m_Blur / 10; + m_Power2 = m_Power * 2; + m_2piOverPower = M_2PI / Zeps(m_Power); + m_SinAlpha = std::sin(m_Alpha); + m_CosAlpha = std::cos(m_Alpha); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_blur_power", 5)); + m_Params.push_back(ParamWithName(&m_Range, prefix + "depth_blur_range", T(0.401623))); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_blur_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_blur_radius", 1)); + m_Params.push_back(ParamWithName(true, &m_Alpha, prefix + "depth_blur_alpha"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Length, prefix + "depth_blur_length")); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_blur_blur_over_10")); + m_Params.push_back(ParamWithName(true, &m_Power2, prefix + "depth_blur_power2")); + m_Params.push_back(ParamWithName(true, &m_2piOverPower, prefix + "depth_blur_2pi_over_power")); + m_Params.push_back(ParamWithName(true, &m_SinAlpha, prefix + "depth_blur_sin_alpha")); + m_Params.push_back(ParamWithName(true, &m_CosAlpha, prefix + "depth_blur_cos_alpha")); + } + +private: + T m_Power; + T m_Range; + T m_Blur; + T m_Radius; + T m_Alpha;//Precalc. + T m_Length; + T m_BlurOver10; + T m_Power2; + T m_2piOverPower; + T m_SinAlpha; + T m_CosAlpha; + +}; + +/// +/// depth_blur2. +/// By tatasz. +/// +template +class DepthBlur2Variation : public ParametricVariation +{ +public: + DepthBlur2Variation(T weight = 1.0) : ParametricVariation("depth_blur2", eVariationId::VAR_DEPTH_BLUR2, weight) + { + Init(); + } + + PARVARCOPY(DepthBlur2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = std::sqrt(Sqr((helper.In.x - m_X0) / m_OneOverMulXSq) + Sqr((helper.In.y - m_Y0) / m_OneOverMulYSq)); + + if (rad > m_Radius) + { + T f = rand.Frand01() * m_Power2; + T int_angle = std::trunc(f); + f = f - int_angle; + T x = f * m_Length; + T z = std::sqrt(1 + SQR(x) - 2 * x * std::cos(m_Alpha)); + + if (!(((int)int_angle) & 1)) + int_angle = m_2piOverPower * (((int)int_angle) / 2) + std::asin(std::sin(m_Alpha) * x / Zeps(z)); + else + int_angle = m_2piOverPower * (((int)int_angle) / 2) - std::asin(std::sin(m_Alpha) * x / Zeps(z)); + + z *= std::sqrt(rand.Frand01()); + by = std::sin(int_angle - T(M_PI_2)); + bx = std::cos(int_angle - T(M_PI_2)); + T aux = z * m_BlurOver10 * std::exp(std::log(rad - m_Radius) * m_Exp); + by = aux * by; + bx = aux * bx; + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string range = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string x0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mulx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string muly = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string exp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string alpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string length = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twopioverpower = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = sqrt(Sqr((vIn.x - " << x0 << ") / " << oneovermulsqx << ") + Sqr((vIn.y - " << y0 << ") / " << oneovermulsqy << "));\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t f = MwcNext01(mwc) * " << power2 << ";\n" + << "\t\t real_t int_angle = trunc(f);\n" + << "\t\t f = f - int_angle;\n" + << "\t\t real_t x = f * " << length << ";\n" + << "\t\t real_t z = sqrt(1 + SQR(x) - 2 * x * cos(" << alpha << "));\n" + << "\n" + << "\t\t if (!(((int)int_angle) & 1))\n" + << "\t\t int_angle = " << twopioverpower << " * (((int)int_angle) / 2) + asin(sin(" << alpha << ") * x / Zeps(z));\n" + << "\t\t else\n" + << "\t\t int_angle = " << twopioverpower << " * (((int)int_angle) / 2) - asin(sin(" << alpha << ") * x / Zeps(z));\n" + << "\n" + << "\t\t z *= sqrt(MwcNext01(mwc));\n" + << "\t\t by = sin(int_angle - MPI2);\n" + << "\t\t bx = cos(int_angle - MPI2);\n" + << "\t\t real_t aux = z * " << blurover10 << " * exp(log(rad - " << radius << ") * " << exp << ");\n" + << "\t\t by = aux * by;\n" + << "\t\t bx = aux * bx;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Alpha = T(M_PI) / Zeps(m_Power); + m_Length = T(std::sqrt(1 + SQR(m_Range) - 2 * m_Range * std::cos(m_Alpha))); + m_Alpha = std::asin(std::sin(m_Alpha) * m_Range / Zeps(m_Length)); + m_BlurOver10 = m_Blur / 10; + m_Power2 = m_Power * 2; + m_2piOverPower = M_2PI / Zeps(m_Power); + m_OneOverMulXSq = 1 / Zeps(SQR(m_MulX)); + m_OneOverMulYSq = 1 / Zeps(SQR(m_MulY)); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_blur2_power", 5)); + m_Params.push_back(ParamWithName(&m_Range, prefix + "depth_blur2_range", T(0.401623))); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_blur2_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_blur2_radius", 1)); + m_Params.push_back(ParamWithName(&m_X0, prefix + "depth_blur2_x0", 0)); + m_Params.push_back(ParamWithName(&m_Y0, prefix + "depth_blur2_y0", 0)); + m_Params.push_back(ParamWithName(&m_MulX, prefix + "depth_blur2_mulx", 1)); + m_Params.push_back(ParamWithName(&m_MulY, prefix + "depth_blur2_muly", 1)); + m_Params.push_back(ParamWithName(&m_Exp, prefix + "depth_blur2_exp", 1)); + m_Params.push_back(ParamWithName(true, &m_Alpha, prefix + "depth_blur2_alpha"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Length, prefix + "depth_blur2_length")); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_blur2_blur_over_10")); + m_Params.push_back(ParamWithName(true, &m_Power2, prefix + "depth_blur2_power2")); + m_Params.push_back(ParamWithName(true, &m_2piOverPower, prefix + "depth_blur2_2pi_over_power")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulXSq, prefix + "depth_blur2_one_over_mulx_sq")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulYSq, prefix + "depth_blur2_one_over_muly_sq")); + } + +private: + T m_Power; + T m_Range; + T m_Blur; + T m_Radius; + T m_X0; + T m_Y0; + T m_MulX; + T m_MulY; + T m_Exp; + T m_Alpha;//Precalc. + T m_Length; + T m_BlurOver10; + T m_Power2; + T m_2piOverPower; + T m_OneOverMulXSq; + T m_OneOverMulYSq; +}; + +/// +/// depth_gaussian. +/// By tatasz. +/// +template +class DepthGaussianVariation : public ParametricVariation +{ +public: + DepthGaussianVariation(T weight = 1.0) : ParametricVariation("depth_gaussian", eVariationId::VAR_DEPTH_GAUSSIAN, weight, true, true) + { + Init(); + } + + PARVARCOPY(DepthGaussianVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = helper.m_PrecalcSqrtSumSquares; + + if (rad > m_Radius) + { + T r = std::sqrt(-2 * log(rand.Frand01())); + T ang = rand.Frand01() * M_2PI; + bx = std::cos(ang); + by = std::sin(ang); + T aux = (r * m_BlurOver10 * (rad - m_Radius)); + by = aux * by; + bx = aux * bx; + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t r = sqrt(-2 * log(MwcNext01(mwc)));\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t bx = cos(ang);\n" + << "\t\t by = sin(ang);\n" + << "\t\t real_t aux = (r * " << blurover10 << " * (rad - " << radius << "));\n" + << "\t\t by = aux * by;\n" + << "\t\t bx = aux * bx;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_BlurOver10 = m_Blur / 10; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_gaussian_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_gaussian_radius", 1)); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_gaussian_blur_over_10"));//Precalc. + } + +private: + T m_Blur; + T m_Radius; + T m_BlurOver10;//Precalc. +}; + +/// +/// depth_gaussian2. +/// By tatasz. +/// +template +class DepthGaussian2Variation : public ParametricVariation +{ +public: + DepthGaussian2Variation(T weight = 1.0) : ParametricVariation("depth_gaussian2", eVariationId::VAR_DEPTH_GAUSSIAN2, weight) + { + Init(); + } + + PARVARCOPY(DepthGaussian2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = std::sqrt(Sqr((helper.In.x - m_X0) / m_OneOverMulXSq) + Sqr((helper.In.y - m_Y0) / m_OneOverMulYSq)); + + if (rad > m_Radius) + { + T r = std::sqrt(-2 * std::log(rand.Frand01())); + T ang = rand.Frand01() * M_2PI; + bx = std::cos(ang); + by = std::sin(ang); + T aux = r * m_BlurOver10 * std::exp(std::log(rad - m_Radius) * m_Exp); + by = aux * by; + bx = aux * bx; + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string x0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mulx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string muly = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string exp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = sqrt(Sqr((vIn.x - " << x0 << ") / " << oneovermulsqx << ") + Sqr((vIn.y - " << y0 << ") / " << oneovermulsqy << "));\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t r = sqrt(-2 * log(MwcNext01(mwc)));\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t bx = cos(ang);\n" + << "\t\t by = sin(ang);\n" + << "\t\t real_t aux = r * " << blurover10 << " * exp(log(rad - " << radius << ") * " << exp << ");\n" + << "\t\t by = aux * by;\n" + << "\t\t bx = aux * bx;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_BlurOver10 = m_Blur / 10; + m_OneOverMulXSq = 1 / Zeps(SQR(m_MulX)); + m_OneOverMulYSq = 1 / Zeps(SQR(m_MulY)); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_gaussian2_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_gaussian2_radius", 1)); + m_Params.push_back(ParamWithName(&m_X0, prefix + "depth_gaussian2_x0", 0)); + m_Params.push_back(ParamWithName(&m_Y0, prefix + "depth_gaussian2_y0", 0)); + m_Params.push_back(ParamWithName(&m_MulX, prefix + "depth_gaussian2_mulx", 1)); + m_Params.push_back(ParamWithName(&m_MulY, prefix + "depth_gaussian2_muly", 1)); + m_Params.push_back(ParamWithName(&m_Exp, prefix + "depth_gaussian2_exp", 1)); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_gaussian2_blur_over_10"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_OneOverMulXSq, prefix + "depth_gaussian2_one_over_mulx_sq")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulYSq, prefix + "depth_gaussian2_one_over_muly_sq")); + } + +private: + T m_Blur; + T m_Radius; + T m_X0; + T m_Y0; + T m_MulX; + T m_MulY; + T m_Exp; + T m_BlurOver10;//Precalc. + T m_OneOverMulXSq; + T m_OneOverMulYSq; +}; + +/// +/// depth_ngon. +/// By tatasz. +/// +template +class DepthNgonVariation : public ParametricVariation +{ +public: + DepthNgonVariation(T weight = 1.0) : ParametricVariation("depth_ngon", eVariationId::VAR_DEPTH_NGON, weight, true, true) + { + Init(); + } + + PARVARCOPY(DepthNgonVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = helper.m_PrecalcSqrtSumSquares; + + if (rad > m_Radius) + { + T ang = rand.Frand01() * M_2PI; + T phi = ang - m_Side * Floor(ang / Zeps(m_Side)); + + if (phi > m_HalfSide) + phi -= m_Side; + + phi = 1 / Zeps(std::cos(phi)); + T aux = phi * m_BlurOver10 * (rad - m_Radius); + bx = aux * std::cos(ang); + by = aux * std::sin(ang); + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string side = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string halfside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t real_t phi = ang - " << side << " * floor(ang / Zeps(" << side << "));\n" + << "\n" + << "\t\t if (phi > " << halfside << ")\n" + << "\t\t phi -= " << side << ";\n" + << "\n" + << "\t\t phi = 1 / Zeps(cos(phi));\n" + << "\t\t real_t aux = phi * " << blurover10 << " * (rad - " << radius << ");\n" + << "\t\t bx = aux * cos(ang);\n" + << "\t\t by = aux * sin(ang);\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Side = M_2PI / Zeps(m_Power); + m_HalfSide = m_Side / 2; + m_BlurOver10 = m_Blur / 10; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_ngon_power", 5)); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_ngon_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_ngon_radius", 1)); + m_Params.push_back(ParamWithName(true, &m_Side, prefix + "depth_ngon_side"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_HalfSide, prefix + "depth_ngon_half_side")); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_ngon_blur_over_10")); + } + +private: + T m_Power; + T m_Blur; + T m_Radius; + T m_Side;//Precalc. + T m_HalfSide; + T m_BlurOver10; +}; + +/// +/// depth_ngon2. +/// By tatasz. +/// +template +class DepthNgon2Variation : public ParametricVariation +{ +public: + DepthNgon2Variation(T weight = 1.0) : ParametricVariation("depth_ngon2", eVariationId::VAR_DEPTH_NGON2, weight) + { + Init(); + } + + PARVARCOPY(DepthNgon2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = std::sqrt(Sqr((helper.In.x - m_X0) / m_OneOverMulXSq) + Sqr((helper.In.y - m_Y0) / m_OneOverMulYSq)); + + if (rad > m_Radius) + { + T ang = rand.Frand01() * M_2PI; + T phi = ang - m_Side * Floor(ang / Zeps(m_Side)); + + if (phi > m_HalfSide) + phi -= m_Side; + + phi = 1 / Zeps(std::cos(phi)); + T aux = phi * m_BlurOver10 * std::exp(std::log(rad - m_Radius) * m_Exp); + bx = aux * std::cos(ang); + by = aux * std::sin(ang); + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string x0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mulx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string muly = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string exp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string side = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string halfside = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = sqrt(Sqr((vIn.x - " << x0 << ") / " << oneovermulsqx << ") + Sqr((vIn.y - " << y0 << ") / " << oneovermulsqy << "));\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t real_t phi = ang - " << side << " * floor(ang / Zeps(" << side << "));\n" + << "\n" + << "\t\t if (phi > " << halfside << ")\n" + << "\t\t phi -= " << side << ";\n" + << "\n" + << "\t\t phi = 1 / Zeps(cos(phi));\n" + << "\t\t real_t aux = phi * " << blurover10 << " * exp(log(rad - " << radius << ") * " << exp << ");\n" + << "\t\t bx = aux * cos(ang);\n" + << "\t\t by = aux * sin(ang);\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Side = M_2PI / Zeps(m_Power); + m_HalfSide = m_Side / 2; + m_BlurOver10 = m_Blur / 10; + m_OneOverMulXSq = 1 / Zeps(SQR(m_MulX)); + m_OneOverMulYSq = 1 / Zeps(SQR(m_MulY)); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_ngon2_power", 5)); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_ngon2_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_ngon2_radius", 1)); + m_Params.push_back(ParamWithName(&m_X0, prefix + "depth_ngon2_x0", 0)); + m_Params.push_back(ParamWithName(&m_Y0, prefix + "depth_ngon2_y0", 0)); + m_Params.push_back(ParamWithName(&m_MulX, prefix + "depth_ngon2_mulx", 1)); + m_Params.push_back(ParamWithName(&m_MulY, prefix + "depth_ngon2_muly", 1)); + m_Params.push_back(ParamWithName(&m_Exp, prefix + "depth_ngon2_exp", 1)); + m_Params.push_back(ParamWithName(true, &m_Side, prefix + "depth_ngon2_side"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_HalfSide, prefix + "depth_ngon2_half_side")); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_ngon2_blur_over_10")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulXSq, prefix + "depth_ngon2_one_over_mulx_sq")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulYSq, prefix + "depth_ngon2_one_over_muly_sq")); + } + +private: + T m_Power; + T m_Blur; + T m_Radius; + T m_X0; + T m_Y0; + T m_MulX; + T m_MulY; + T m_Exp; + T m_Side;//Precalc. + T m_HalfSide; + T m_BlurOver10; + T m_OneOverMulXSq; + T m_OneOverMulYSq; +}; + +/// +/// depth_sine. +/// By tatasz. +/// +template +class DepthSineVariation : public ParametricVariation +{ +public: + DepthSineVariation(T weight = 1.0) : ParametricVariation("depth_sine", eVariationId::VAR_DEPTH_SINE, weight, true, true) + { + Init(); + } + + PARVARCOPY(DepthSineVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = helper.m_PrecalcSqrtSumSquares; + + if (rad > m_Radius) + { + T ang = rand.Frand01() * M_2PI; + T r = (m_Power == 1 ? std::acos(rand.Frand01() * 2 - 1) / T(M_PI) : std::acos(std::exp(std::log(1 - rand.Frand01()) * m_Power) * 2 - 1) / T(M_PI)); + T aux = r * m_BlurOver10 * (rad - m_Radius); + bx = aux * std::cos(ang); + by = aux * std::sin(ang); + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t real_t r = (" << power << " == 1 ? acos(fma(MwcNext01(mwc), 2, -1.0)) / MPI : acos(exp(log(1 - MwcNext01(mwc)) * " << power << ") * 2 - 1) / MPI);\n" + << "\t\t real_t aux = r * " << blurover10 << " * (rad - " << radius << ");\n" + << "\t\t bx = aux * cos(ang);\n" + << "\t\t by = aux * sin(ang);\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_BlurOver10 = m_Blur / 10; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_sine_power", 1, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_sine_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_sine_radius", 1)); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_sine_blur_over_10"));//Precalc. + } + +private: + T m_Power; + T m_Blur; + T m_Radius; + T m_BlurOver10;//Precalc. +}; + +/// +/// depth_sine2. +/// By tatasz. +/// +template +class DepthSine2Variation : public ParametricVariation +{ +public: + DepthSine2Variation(T weight = 1.0) : ParametricVariation("depth_sine2", eVariationId::VAR_DEPTH_SINE2, weight) + { + Init(); + } + + PARVARCOPY(DepthSine2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T bx = 0; + T by = 0; + T rad = std::sqrt(Sqr((helper.In.x - m_X0) / m_OneOverMulXSq) + Sqr((helper.In.y - m_Y0) / m_OneOverMulYSq)); + + if (rad > m_Radius) + { + T ang = rand.Frand01() * M_2PI; + T r = (m_Power == 1 ? std::acos(rand.Frand01() * 2 - 1) / T(M_PI) : std::acos(std::exp(std::log(1 - rand.Frand01()) * m_Power) * 2 - 1) / T(M_PI)); + T aux = r * m_BlurOver10 * std::exp(std::log(rad - m_Radius) * m_Exp); + bx = aux * std::cos(ang); + by = aux * std::sin(ang); + } + + helper.Out.x = m_Weight * (helper.In.x + bx); + helper.Out.y = m_Weight * (helper.In.y + by); + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blur = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string x0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y0 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mulx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string muly = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string exp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string blurover10 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string oneovermulsqy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t bx = 0;\n" + << "\t\treal_t by = 0;\n" + << "\t\treal_t rad = sqrt(Sqr((vIn.x - " << x0 << ") / " << oneovermulsqx << ") + Sqr((vIn.y - " << y0 << ") / " << oneovermulsqy << "));\n" + << "\n" + << "\t\tif (rad > " << radius << ")\n" + << "\t\t{\n" + << "\t\t real_t ang = MwcNext01(mwc) * M_2PI;\n" + << "\t\t real_t r = (" << power << " == 1 ? acos(fma(MwcNext01(mwc), 2, -1.0)) / MPI : acos(exp(log(1 - MwcNext01(mwc)) * " << power << ") * 2 - 1) / MPI);\n" + << "\t\t real_t aux = r * " << blurover10 << " * exp(log(rad - " << radius << ") * " << exp << ");\n" + << "\t\t bx = aux * cos(ang);\n" + << "\t\t by = aux * sin(ang);\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + bx);\n" + << "\t\tvOut.y = " << weight << " * (vIn.y + by);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_BlurOver10 = m_Blur / 10; + m_OneOverMulXSq = 1 / Zeps(SQR(m_MulX)); + m_OneOverMulYSq = 1 / Zeps(SQR(m_MulY)); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "depth_sine2_power", 1, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Blur, prefix + "depth_sine2_blur", 1)); + m_Params.push_back(ParamWithName(&m_Radius, prefix + "depth_sine2_radius", 1)); + m_Params.push_back(ParamWithName(&m_X0, prefix + "depth_sine2_x0", 0)); + m_Params.push_back(ParamWithName(&m_Y0, prefix + "depth_sine2_y0", 0)); + m_Params.push_back(ParamWithName(&m_MulX, prefix + "depth_sine2_mulx", 1)); + m_Params.push_back(ParamWithName(&m_MulY, prefix + "depth_sine2_muly", 1)); + m_Params.push_back(ParamWithName(&m_Exp, prefix + "depth_sine2_exp", 1)); + m_Params.push_back(ParamWithName(true, &m_BlurOver10, prefix + "depth_sine2_blur_over_10"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_OneOverMulXSq, prefix + "depth_sine2_one_over_mulx_sq")); + m_Params.push_back(ParamWithName(true, &m_OneOverMulYSq, prefix + "depth_sine2_one_over_muly_sq")); + } + +private: + T m_Power; + T m_Blur; + T m_Radius; + T m_X0; + T m_Y0; + T m_MulX; + T m_MulY; + T m_Exp; + T m_BlurOver10;//Precalc. + T m_OneOverMulXSq; + T m_OneOverMulYSq; +}; + +/// +/// coth_spiral. +/// +template +class CothSpiralVariation : public ParametricVariation +{ +public: + CothSpiralVariation(T weight = 1.0) : ParametricVariation("coth_spiral", eVariationId::VAR_COTH_SPIRAL, weight) + { + Init(); + } + + PARVARCOPY(CothSpiralVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T t2 = (rand.Frand01() - 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 OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "coth_spiral_a", 4)); + } + +private: + T m_A; +}; + +/// +/// dust. +/// By tatasz. +/// +template +class DustVariation : public ParametricVariation +{ +public: + DustVariation(T weight = 1.0) : ParametricVariation("dust", eVariationId::VAR_DUST, weight) + { + Init(); + } + + PARVARCOPY(DustVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T X = std::fmod(T(Floor(helper.In.x)), m_Zdens) / m_Zdens; + T Y = std::fmod(T(Floor(helper.In.y)), m_Zdens) / m_Zdens; + T random_x = VarFuncs::HashShadertoy(X, Y, 0); + T random_y = VarFuncs::HashShadertoy(Y, X, 0); + T a = (X + random_x * m_Dist) * M_2PI; + T r = std::exp(std::log(Y + random_y * m_Dist) * m_Power); + helper.Out.x = m_Weight * std::cos(a) * r; + helper.Out.y = m_Weight * std::sin(a) * 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 dens = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string zdens = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t X = fmod(floor(vIn.x), " << zdens << ") / " << zdens << ";\n" + << "\t\treal_t Y = fmod(floor(vIn.y), " << zdens << ") / " << zdens << ";\n" + << "\t\treal_t random_x = HashShadertoy(X, Y, 0.0);\n" + << "\t\treal_t random_y = HashShadertoy(Y, X, 0.0);\n" + << "\t\treal_t a = fma(random_x, " << dist << ", X) * M_2PI;\n" + << "\t\treal_t r = exp(log(fma(random_y, " << dist << ", Y)) * " << power << ");\n" + << "\t\tvOut.x = " << weight << " * cos(a) * r;\n" + << "\t\tvOut.y = " << weight << " * sin(a) * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Zdens = Zeps(m_Density); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Density, prefix + "dust_density", 5, eParamType::REAL_NONZERO)); + m_Params.push_back(ParamWithName(&m_Dist, prefix + "dust_distortion", 1)); + m_Params.push_back(ParamWithName(&m_Power, prefix + "dust_power", 1)); + m_Params.push_back(ParamWithName(true, &m_Zdens, prefix + "dust_zdens"));//Precalc. + } + +private: + T m_Density; + T m_Dist; + T m_Power; + T m_Zdens;//Precalc. +}; + +/// +/// asteria. +/// By dark-beam. +/// +template +class AsteriaVariation : public ParametricVariation +{ +public: + AsteriaVariation(T weight = 1.0) : ParametricVariation("asteria", eVariationId::VAR_ASTERIA, weight) + { + Init(); + } + + PARVARCOPY(AsteriaVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T x0 = m_Weight * helper.In.x; + T y0 = m_Weight * helper.In.y; + T xx = x0; + T yy = y0; + T r = SQR(xx) + SQR(yy); + xx = Sqr(std::abs(xx) - 1); + yy = Sqr(std::abs(yy) - 1); + T r2 = std::sqrt(yy + xx); + bool in1 = r < 1; + bool out2 = r2 < 1; + + if (in1 && out2) + in1 = (rand.Frand01() > 0.35); + else + in1 = !in1; + + if (in1) + { + helper.Out.x = x0; + helper.Out.y = y0; + } + else + { + xx = x0 * m_CosAlpha - y0 * m_SinAlpha; + yy = x0 * m_SinAlpha + y0 * m_CosAlpha; + T nx = xx / std::sqrt(1 - SQR(yy)) * (1 - std::sqrt(1 - Sqr(-std::abs(yy) + 1))); + xx = nx * m_CosAlpha + yy * m_SinAlpha; + yy = -nx * m_SinAlpha + yy * m_CosAlpha; + helper.Out.x = xx; + helper.Out.y = yy; + } + + 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 alpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sina = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosa = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t x0 = " << weight << " * vIn.x;\n" + << "\t\treal_t y0 = " << weight << " * vIn.y;\n" + << "\t\treal_t xx = x0;\n" + << "\t\treal_t yy = y0;\n" + << "\t\treal_t r = SQR(xx) + SQR(yy);\n" + << "\t\txx = Sqr(fabs(xx) - 1);\n" + << "\t\tyy = Sqr(fabs(yy) - 1);\n" + << "\t\treal_t r2 = sqrt(yy + xx);\n" + << "\t\tbool in1 = r < 1;\n" + << "\t\tbool out2 = r2 < 1;\n" + << "\n" + << "\t\tif (in1 && out2)\n" + << "\t\t in1 = MwcNext01(mwc) > 0.35;\n" + << "\t\telse\n" + << "\t\t in1 = !in1;\n" + << "\n" + << "\t\tif (in1)\n" + << "\t\t{\n" + << "\t\t vOut.x = x0;\n" + << "\t\t vOut.y = y0;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t xx = x0 * " << cosa << " - y0 * " << sina << ";\n" + << "\t\t yy = x0 * " << sina << " + y0 * " << cosa << ";\n" + << "\t\t real_t nx = xx / sqrt(1 - SQR(yy)) * (1 - sqrt(1 - Sqr(-fabs(yy) + 1)));\n" + << "\t\t xx = nx * " << cosa << " + yy * " << sina << ";\n" + << "\t\t yy = -nx * " << sina << " + yy * " << cosa << ";\n" + << "\t\t vOut.x = xx;\n" + << "\t\t vOut.y = yy;\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_SinAlpha = T(std::sin(M_PI * m_Alpha)); + m_CosAlpha = T(std::cos(M_PI * m_Alpha)); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Alpha, prefix + "asteria_alpha", 0, eParamType::REAL_CYCLIC, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_SinAlpha, prefix + "asteria_sin_alpha")); + m_Params.push_back(ParamWithName(true, &m_CosAlpha, prefix + "asteria_cos_alpha")); + } + +private: + T m_Alpha; + T m_SinAlpha;//Precalc. + T m_CosAlpha; +}; + +/// +/// pulse. +/// By FarDareisMai. +/// +template +class PulseVariation : public ParametricVariation +{ +public: + PulseVariation(T weight = 1.0) : ParametricVariation("pulse", eVariationId::VAR_PULSE, weight) + { + Init(); + } + + PARVARCOPY(PulseVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = m_Weight * (helper.In.x + m_ScaleX * std::sin(helper.In.x * m_FreqX)); + helper.Out.y = m_Weight * (helper.In.y + m_ScaleY * std::sin(helper.In.y * m_FreqY)); + 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 freqx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freqy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scalex = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaley = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = " << weight << " * fma(" << scalex << ", sin(vIn.x * " << freqx << "), vIn.x);\n" + << "\t\tvOut.y = " << weight << " * fma(" << scaley << ", sin(vIn.y * " << freqy << "), vIn.y);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_FreqX, prefix + "pulse_freqx", 2)); + m_Params.push_back(ParamWithName(&m_FreqY, prefix + "pulse_freqy", 2)); + m_Params.push_back(ParamWithName(&m_ScaleX, prefix + "pulse_scalex", 1)); + m_Params.push_back(ParamWithName(&m_ScaleY, prefix + "pulse_scaley", 1)); + } + +private: + T m_FreqX; + T m_FreqY; + T m_ScaleX; + T m_ScaleY; +}; + +/// +/// excinis. +/// +template +class ExcinisVariation : public ParametricVariation +{ +public: + ExcinisVariation(T weight = 1.0) : ParametricVariation("excinis", eVariationId::VAR_EXCINIS, weight, true, true) + { + Init(); + } + + PARVARCOPY(ExcinisVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r_prior = helper.m_PrecalcSqrtSumSquares * m_LengthScalar; + T r_sign = T(r_prior >= 0 ? 1 : -1); + T r_eps = std::abs(r_prior) > m_Eps ? 0 : r_sign * m_Eps; + T r = m_Weight / Zeps(r_prior + r_eps); + T r_func; + + if (m_RadiusFunc < 1) + r_func = r; + else if (m_RadiusFunc < 2) + r_func = std::cos(r); + else if (m_RadiusFunc < 3) + r_func = std::exp(r); + else if (m_RadiusFunc < 4) + r_func = std::log(std::abs(r) + std::abs(r_eps)); + else + r_func = 1 / Zeps(r + r_eps); + + helper.Out.x = (helper.In.x - helper.In.y) * (helper.In.x + helper.In.y) * r_func; + helper.Out.y = 2 * helper.In.x * helper.In.y * r_func; + 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 lengthscalar = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radiusfunc = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string eps = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r_prior = precalcSqrtSumSquares * " << lengthscalar << ";\n" + << "\t\treal_t r_sign = r_prior >= 0.0 ? 1.0 : -1.0;\n" + << "\t\treal_t r_eps = fabs(r_prior) > " << eps << " ? 0 : r_sign * " << eps << ";\n" + << "\t\treal_t r = " << weight << " / Zeps(r_prior + r_eps);\n" + << "\t\treal_t r_func;\n" + << "\n" + << "\t\tif (" << radiusfunc << " < 1)\n" + << "\t\t r_func = r;\n" + << "\t\telse if (" << radiusfunc << " < 2)\n" + << "\t\t r_func = cos(r);\n" + << "\t\telse if (" << radiusfunc << " < 3)\n" + << "\t\t r_func = exp(r);\n" + << "\t\telse if (" << radiusfunc << " < 4)\n" + << "\t\t r_func = log(fabs(r) + fabs(r_eps));\n" + << "\t\telse\n" + << "\t\t r_func = 1 / Zeps(r + r_eps);\n" + << "\n" + << "\t\tvOut.x = (vIn.x - vIn.y) * (vIn.x + vIn.y) * r_func;\n" + << "\t\tvOut.y = 2 * vIn.x * vIn.y * r_func;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_LengthScalar, prefix + "excinis_lengthscalar", 1)); + m_Params.push_back(ParamWithName(&m_RadiusFunc, prefix + "excinis_radiusFunc", 0, eParamType::INTEGER, 0, 5)); + m_Params.push_back(ParamWithName(&m_Eps, prefix + "excinis_eps", T(0.1))); + } + +private: + T m_LengthScalar; + T m_RadiusFunc; + T m_Eps; +}; + +/// +/// vibration. +/// By FarDareisMai. +/// +template +class VibrationVariation : public ParametricVariation +{ +public: + VibrationVariation(T weight = 1.0) : ParametricVariation("vibration", eVariationId::VAR_VIBRATION, weight) + { + Init(); + } + + PARVARCOPY(VibrationVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T d_along_dir = helper.In.x * m_CosDir + helper.In.y * m_SinDir; + T local_amp = m_Amp * std::sin((d_along_dir * m_ScaledFreq) + m_PhaseShift); + T x = helper.In.x + local_amp * m_CosTot; + T y = helper.In.y + local_amp * m_SinTot; + d_along_dir = helper.In.x * m_CosDir2 + helper.In.y * m_SinDir2; + local_amp = m_Amp2 * std::sin((d_along_dir * m_ScaledFreq2) + m_PhaseShift2); + x += local_amp * m_CosTot2; + y += local_amp * m_SinTot2; + helper.Out.x = m_Weight * x; + helper.Out.y = m_Weight * 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 dir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phase = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freq2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amp2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phase2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosdir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sindir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string costot = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sintot = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaledfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phaseshift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosdir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sindir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string costot2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sintot2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaledfreq2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phaseshift2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t d_along_dir = fma(vIn.x, " << cosdir << ", vIn.y * " << sindir << ");\n" + << "\t\treal_t local_amp = " << amp << " * sin(fma(d_along_dir, " << scaledfreq << ", " << phaseshift << "));\n" + << "\t\treal_t x = fma(local_amp, " << costot << ", vIn.x);\n" + << "\t\treal_t y = fma(local_amp, " << sintot << ", vIn.y);\n" + << "\t\td_along_dir = fma(vIn.x, " << cosdir2 << ", vIn.y * " << sindir2 << ");\n" + << "\t\tlocal_amp = " << amp2 << " * sin(fma(d_along_dir, " << scaledfreq2 << ", " << phaseshift2 << "));\n" + << "\t\tx += local_amp * " << costot2 << ";\n" + << "\t\ty += local_amp * " << sintot2 << ";\n" + << "\n" + << "\t\tvOut.x = " << weight << " * x;\n" + << "\t\tvOut.y = " << weight << " * y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T totalangle = m_Angle + m_Dir; + m_CosDir = std::cos(m_Dir); + m_SinDir = std::sin(m_Dir); + m_CosTot = std::cos(totalangle); + m_SinTot = std::sin(totalangle); + m_ScaledFreq = m_Freq * M_2PI; + m_PhaseShift = M_2PI * m_Phase / Zeps(m_Freq); + T totalangle2 = m_Angle2 + m_Dir2; + m_CosDir2 = std::cos(m_Dir2); + m_SinDir2 = std::sin(m_Dir2); + m_CosTot2 = std::cos(totalangle2); + m_SinTot2 = std::sin(totalangle2); + m_ScaledFreq2 = m_Freq2 * M_2PI; + m_PhaseShift2 = M_2PI * m_Phase2 / Zeps(m_Freq2); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Dir, prefix + "vibration_dir", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "vibration_angle", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Freq, prefix + "vibration_freq", 1)); + m_Params.push_back(ParamWithName(&m_Amp, prefix + "vibration_amp", T(0.25))); + m_Params.push_back(ParamWithName(&m_Phase, prefix + "vibration_phase", 0, eParamType::REAL_CYCLIC, 0, 1)); + m_Params.push_back(ParamWithName(&m_Dir2, prefix + "vibration_dir2", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Angle2, prefix + "vibration_angle2", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Freq2, prefix + "vibration_freq2", 1)); + m_Params.push_back(ParamWithName(&m_Amp2, prefix + "vibration_amp2", T(0.25))); + m_Params.push_back(ParamWithName(&m_Phase2, prefix + "vibration_phase2", 0, eParamType::REAL_CYCLIC, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_CosDir, prefix + "vibration_cos_dir")); + m_Params.push_back(ParamWithName(true, &m_SinDir, prefix + "vibration_sin_dir")); + m_Params.push_back(ParamWithName(true, &m_CosTot, prefix + "vibration_cos_tot")); + m_Params.push_back(ParamWithName(true, &m_SinTot, prefix + "vibration_sin_tot")); + m_Params.push_back(ParamWithName(true, &m_ScaledFreq, prefix + "vibration_scaled_freq")); + m_Params.push_back(ParamWithName(true, &m_PhaseShift, prefix + "vibration_phase_shift")); + m_Params.push_back(ParamWithName(true, &m_CosDir2, prefix + "vibration_cos_dir2")); + m_Params.push_back(ParamWithName(true, &m_SinDir2, prefix + "vibration_sin_dir2")); + m_Params.push_back(ParamWithName(true, &m_CosTot2, prefix + "vibration_cos_tot2")); + m_Params.push_back(ParamWithName(true, &m_SinTot2, prefix + "vibration_sin_tot2")); + m_Params.push_back(ParamWithName(true, &m_ScaledFreq2, prefix + "vibration_scaled_freq2")); + m_Params.push_back(ParamWithName(true, &m_PhaseShift2, prefix + "vibration_phase_shift2")); + } + +private: + T m_Dir; + T m_Angle; + T m_Freq; + T m_Amp; + T m_Phase; + T m_Dir2; + T m_Angle2; + T m_Freq2; + T m_Amp2; + T m_Phase2; + T m_CosDir; + T m_SinDir; + T m_CosTot; + T m_SinTot; + T m_ScaledFreq; + T m_PhaseShift; + T m_CosDir2; + T m_SinDir2; + T m_CosTot2; + T m_SinTot2; + T m_ScaledFreq2; + T m_PhaseShift2; +}; + +/// +/// vibration2. +/// By FarDareisMai. +/// +template +class Vibration2Variation : public ParametricVariation +{ +public: + Vibration2Variation(T weight = 1.0) : ParametricVariation("vibration2", eVariationId::VAR_VIBRATION2, weight) + { + Init(); + } + + PARVARCOPY(Vibration2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T d_along_dir = helper.In.x * m_CosDir + helper.In.y * m_SinDir; + T dirL = m_Dir + VarFuncs::Modulate(m_Dm, m_Dmfreq, d_along_dir); + T angleL = m_Angle + VarFuncs::Modulate(m_Tm, m_Tmfreq, d_along_dir); + T freqL = VarFuncs::Modulate(m_Fm, m_Fmfreq, d_along_dir) / Zeps(m_Freq); + T ampL = m_Amp + m_Amp * VarFuncs::Modulate(m_Am, m_Amfreq, d_along_dir); + T total_angle = angleL + dirL; + T cos_dir = std::cos(dirL); + T sin_dir = std::sin(dirL); + T cos_tot = std::cos(total_angle); + T sin_tot = std::sin(total_angle); + d_along_dir = helper.In.x * cos_dir + helper.In.y * sin_dir; + T local_amp = ampL * std::sin((d_along_dir * m_ScaledFreq) + freqL + m_PhaseShift); + T x = helper.In.x + local_amp * cos_tot; + T y = helper.In.y + local_amp * sin_tot; + d_along_dir = helper.In.x * m_CosDir2 + helper.In.y * m_SinDir2; + dirL = m_Dir2 + VarFuncs::Modulate(m_D2m, m_D2mfreq, d_along_dir); + angleL = m_Angle2 + VarFuncs::Modulate(m_T2m, m_T2mfreq, d_along_dir); + freqL = VarFuncs::Modulate(m_F2m, m_F2mfreq, d_along_dir) / Zeps(m_Freq2); + ampL = m_Amp2 + m_Amp2 * VarFuncs::Modulate(m_A2m, m_A2mfreq, d_along_dir); + total_angle = angleL + dirL; + cos_dir = std::cos(dirL); + sin_dir = std::sin(dirL); + cos_tot = std::cos(total_angle); + sin_tot = std::sin(total_angle); + d_along_dir = helper.In.x * cos_dir + helper.In.y * sin_dir; + local_amp = ampL * std::sin((d_along_dir * m_ScaledFreq2) + freqL + m_PhaseShift2); + x += local_amp * cos_tot; + y += local_amp * sin_tot; + helper.Out.x = m_Weight * x; + helper.Out.y = m_Weight * 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 dir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phase = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string freq2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amp2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phase2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dm = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string dmfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string tm = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string tmfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string fm = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string fmfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string am = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string d2m = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string d2mfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string t2m = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string t2mfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string f2m = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string f2mfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string a2m = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string a2mfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosdir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sindir = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaledfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phaseshift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosdir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sindir2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scaledfreq2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string phaseshift2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t d_along_dir = fma(vIn.x, " << cosdir << ", vIn.y * " << sindir << ");\n" + << "\t\treal_t dirL = " << dir << " + Modulate(" << dm << ", " << dmfreq << ", d_along_dir);\n" + << "\t\treal_t angleL = " << angle << " + Modulate(" << tm << ", " << tmfreq << ", d_along_dir);\n" + << "\t\treal_t freqL = Modulate(" << fm << ", " << fmfreq << ", d_along_dir) / Zeps(" << freq << ");\n" + << "\t\treal_t ampL = fma(" << amp << ", Modulate(" << am << ", " << amfreq << ", d_along_dir), " << amp << ");\n" + << "\t\treal_t total_angle = angleL + dirL;\n" + << "\t\treal_t cos_dir = cos(dirL);\n" + << "\t\treal_t sin_dir = sin(dirL);\n" + << "\t\treal_t cos_tot = cos(total_angle);\n" + << "\t\treal_t sin_tot = sin(total_angle);\n" + << "\t\td_along_dir = fma(vIn.x, cos_dir, vIn.y * sin_dir);\n" + << "\t\treal_t local_amp = ampL * sin(fma(d_along_dir, " << scaledfreq << ", freqL + " << phaseshift << "));\n" + << "\t\treal_t x = fma(local_amp, cos_tot, vIn.x);\n" + << "\t\treal_t y = fma(local_amp, sin_tot, vIn.y);\n" + << "\t\td_along_dir = fma(vIn.x, " << cosdir2 << ", vIn.y * " << sindir2 << ");\n" + << "\t\tdirL = " << dir2 << " + Modulate(" << d2m << ", " << d2mfreq << ", d_along_dir);\n" + << "\t\tangleL = " << angle2 << " + Modulate(" << t2m << ", " << t2mfreq << ", d_along_dir);\n" + << "\t\tfreqL = Modulate(" << f2m << ", " << f2mfreq << ", d_along_dir) / Zeps(" << freq2 << ");\n" + << "\t\tampL = fma(" << amp2 << ", Modulate(" << a2m << ", " << a2mfreq << ", d_along_dir), " << amp2 << ");\n" + << "\t\ttotal_angle = angleL + dirL;\n" + << "\t\tcos_dir = cos(dirL);\n" + << "\t\tsin_dir = sin(dirL);\n" + << "\t\tcos_tot = cos(total_angle);\n" + << "\t\tsin_tot = sin(total_angle);\n" + << "\t\td_along_dir = fma(vIn.x, cos_dir, vIn.y * sin_dir);\n" + << "\t\tlocal_amp = ampL * sin(fma(d_along_dir, " << scaledfreq2 << ", freqL + " << phaseshift2 << "));\n" + << "\t\tx += local_amp * cos_tot;\n" + << "\t\ty += local_amp * sin_tot;\n" + << "\n" + << "\t\tvOut.x = " << weight << " * x;\n" + << "\t\tvOut.y = " << weight << " * y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_CosDir = std::cos(m_Dir); + m_SinDir = std::sin(m_Dir); + m_ScaledFreq = m_Freq * M_2PI; + m_PhaseShift = M_2PI * m_Phase / Zeps(m_Freq); + m_CosDir2 = std::cos(m_Dir2); + m_SinDir2 = std::sin(m_Dir2); + m_ScaledFreq2 = m_Freq2 * M_2PI; + m_PhaseShift2 = M_2PI * m_Phase2 / Zeps(m_Freq2); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sqr", "Modulate" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Dir, prefix + "vibration2_dir", 0, eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "vibration2_angle", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Freq, prefix + "vibration2_freq", 1)); + m_Params.push_back(ParamWithName(&m_Amp, prefix + "vibration2_amp", T(0.25))); + m_Params.push_back(ParamWithName(&m_Phase, prefix + "vibration2_phase", 0, eParamType::REAL_CYCLIC, 0, 1)); + m_Params.push_back(ParamWithName(&m_Dir2, prefix + "vibration2_dir2", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Angle2, prefix + "vibration2_angle2", T(M_PI_2), eParamType::REAL_CYCLIC, 0, M_2PI)); + m_Params.push_back(ParamWithName(&m_Freq2, prefix + "vibration2_freq2", 1)); + m_Params.push_back(ParamWithName(&m_Amp2, prefix + "vibration2_amp2", T(0.25))); + m_Params.push_back(ParamWithName(&m_Phase2, prefix + "vibration2_phase2", 0, eParamType::REAL_CYCLIC, 0, 1)); + m_Params.push_back(ParamWithName(&m_Dm, prefix + "vibration2_dm")); + m_Params.push_back(ParamWithName(&m_Dmfreq, prefix + "vibration2_dmfreq")); + m_Params.push_back(ParamWithName(&m_Tm , prefix + "vibration2_tm")); + m_Params.push_back(ParamWithName(&m_Tmfreq, prefix + "vibration2_tmfreq")); + m_Params.push_back(ParamWithName(&m_Fm , prefix + "vibration2_fm")); + m_Params.push_back(ParamWithName(&m_Fmfreq, prefix + "vibration2_fmfreq")); + m_Params.push_back(ParamWithName(&m_Am , prefix + "vibration2_am")); + m_Params.push_back(ParamWithName(&m_Amfreq, prefix + "vibration2_amfreq")); + m_Params.push_back(ParamWithName(&m_D2m , prefix + "vibration2_dm2")); + m_Params.push_back(ParamWithName(&m_D2mfreq, prefix + "vibration2_dmfreq2")); + m_Params.push_back(ParamWithName(&m_T2m , prefix + "vibration2_tm2")); + m_Params.push_back(ParamWithName(&m_T2mfreq, prefix + "vibration2_tmfreq2")); + m_Params.push_back(ParamWithName(&m_F2m , prefix + "vibration2_fm2")); + m_Params.push_back(ParamWithName(&m_F2mfreq, prefix + "vibration2_fmfreq2")); + m_Params.push_back(ParamWithName(&m_A2m , prefix + "vibration2_am2")); + m_Params.push_back(ParamWithName(&m_A2mfreq, prefix + "vibration2_amfreq2")); + m_Params.push_back(ParamWithName(true, &m_CosDir, prefix + "vibration2_cos_dir")); + m_Params.push_back(ParamWithName(true, &m_SinDir, prefix + "vibration2_sin_dir")); + m_Params.push_back(ParamWithName(true, &m_ScaledFreq, prefix + "vibration2_scaled_freq")); + m_Params.push_back(ParamWithName(true, &m_PhaseShift, prefix + "vibration2_phase_shift")); + m_Params.push_back(ParamWithName(true, &m_CosDir2, prefix + "vibration2_cos_dir2")); + m_Params.push_back(ParamWithName(true, &m_SinDir2, prefix + "vibration2_sin_dir2")); + m_Params.push_back(ParamWithName(true, &m_ScaledFreq2, prefix + "vibration2_scaled_freq2")); + m_Params.push_back(ParamWithName(true, &m_PhaseShift2, prefix + "vibration2_phase_shift2")); + } + +private: + T m_Dir; + T m_Angle; + T m_Freq; + T m_Amp; + T m_Phase; + T m_Dir2; + T m_Angle2; + T m_Freq2; + T m_Amp2; + T m_Phase2; + T m_Dm; + T m_Dmfreq; + T m_Tm; + T m_Tmfreq; + T m_Fm; + T m_Fmfreq; + T m_Am; + T m_Amfreq; + T m_D2m; + T m_D2mfreq; + T m_T2m; + T m_T2mfreq; + T m_F2m; + T m_F2mfreq; + T m_A2m; + T m_A2mfreq; + T m_CosDir; + T m_SinDir; + T m_ScaledFreq; + T m_PhaseShift; + T m_CosDir2; + T m_SinDir2; + T m_ScaledFreq2; + T m_PhaseShift2; +}; + +/// +/// arcsech. +/// By tatasz. +/// +template +class ArcsechVariation : public ParametricVariation +{ +public: + ArcsechVariation(T weight = 1.0) : ParametricVariation("arcsech", eVariationId::VAR_ARCSECH, weight) + { + Init(); + } + + PARVARCOPY(ArcsechVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + v2T z1(helper.In.x, helper.In.y); + v2T z = VarFuncs::RealDivComplex(1.0, z1); + v2T result = VarFuncs::ComplexMultReal(VarFuncs::ComplexLog(VarFuncs::ComplexPlusComplex(z, VarFuncs::ComplexMultComplex(VarFuncs::ComplexSqrt(VarFuncs::ComplexPlusReal(z, 1.0)), VarFuncs::ComplexSqrt(VarFuncs::ComplexMinusReal(z, 1.0))))), m_WeightInvPi); + 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 weightinvpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal2 z1 = (real2)(vIn.x, vIn.y);\n" + << "\t\treal2 z = RealDivComplex(1.0, z1);\n" + << "\t\treal2 result = ComplexMultReal(ComplexLog(ComplexPlusComplex(z,ComplexMultComplex(ComplexSqrt(ComplexPlusReal(z, 1.0)), ComplexSqrt(ComplexMinusReal(z, 1.0))))), " << weightinvpi << ");\n" + << "\n" + << "\t\tvOut.x = result.x;\n" + << "\t\tvOut.y = result.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_WeightInvPi = m_Weight * T(M_1_PI); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sign", "Hypot", "ComplexMultReal", "ComplexLog", "ComplexPlusReal", "ComplexPlusComplex", "ComplexMultComplex", "ComplexSqrt", "ComplexMinusReal", "RealDivComplex" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightInvPi, prefix + "arcsech_weight_inv_pi"));//Precalc. + } + +private: + T m_WeightInvPi;//Precalc only. +}; + +/// +/// arcsech2. +/// By tatasz. +/// +template +class Arcsech2Variation : public ParametricVariation +{ +public: + Arcsech2Variation(T weight = 1.0) : ParametricVariation("arcsech2", eVariationId::VAR_ARCSECH2, weight) + { + Init(); + } + + PARVARCOPY(Arcsech2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + v2T z1(helper.In.x, helper.In.y); + v2T z = VarFuncs::RealDivComplex(1.0, z1); + v2T result = VarFuncs::ComplexMultReal(VarFuncs::ComplexLog(VarFuncs::ComplexPlusComplex(z, VarFuncs::ComplexMultComplex(VarFuncs::ComplexSqrt(VarFuncs::ComplexPlusReal(z, 1.0)), VarFuncs::ComplexSqrt(VarFuncs::ComplexMinusReal(z, 1.0))))), m_WeightInvPi); + + if (result.y < 0) + { + helper.Out.x = result.x; + helper.Out.y = result.y + 1; + } + else + { + helper.Out.x = -result.x; + helper.Out.y = result.y - 1; + } + + 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 weightinvpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal2 z1 = (real2)(vIn.x, vIn.y);\n" + << "\t\treal2 z = RealDivComplex(1.0, z1);\n" + << "\t\treal2 result = ComplexMultReal(ComplexLog(ComplexPlusComplex(z,ComplexMultComplex(ComplexSqrt(ComplexPlusReal(z, 1.0)), ComplexSqrt(ComplexMinusReal(z, 1.0))))), " << weightinvpi << ");\n" + << "\n" + << "\t\tif (result.y < 0)\n" + << "\t\t{\n" + << "\t\t vOut.x = result.x;\n" + << "\t\t vOut.y = result.y + 1;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = -result.x;\n" + << "\t\t vOut.y = result.y - 1;\n" + << "\t\t}\n" + << "\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_WeightInvPi = m_Weight * T(M_1_PI) * 2; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Sign", "Hypot", "ComplexMultReal", "ComplexLog", "ComplexPlusReal", "ComplexPlusComplex", "ComplexMultComplex", "ComplexSqrt", "ComplexMinusReal", "RealDivComplex" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightInvPi, prefix + "arcsech2_weight_inv_pi"));//Precalc. + } + +private: + T m_WeightInvPi;//Precalc only. +}; + +/// +/// arcsinh. +/// By tatasz. +/// +template +class ArcsinhVariation : public ParametricVariation +{ +public: + ArcsinhVariation(T weight = 1.0) : ParametricVariation("arcsinh", eVariationId::VAR_ARCSINH, weight) + { + Init(); + } + + PARVARCOPY(ArcsinhVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + v2T z(helper.In.x, helper.In.y); + v2T result = VarFuncs::ComplexMultReal(VarFuncs::ComplexLog(VarFuncs::ComplexPlusComplex(z, VarFuncs::ComplexSqrt(VarFuncs::ComplexPlusReal(VarFuncs::ComplexMultComplex(z, z), 1.0)))), m_WeightInvPi); + 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 weightinvpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal2 z = (real2)(vIn.x, vIn.y);\n" + << "\t\treal2 result = ComplexMultReal(ComplexLog(ComplexPlusComplex(z, ComplexSqrt(ComplexPlusReal(ComplexMultComplex(z, z), 1.0)))), " << weightinvpi << ");\n" + << "\n" + << "\t\tvOut.x = result.x;\n" + << "\t\tvOut.y = result.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_WeightInvPi = m_Weight * T(M_2_PI); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Sign", "Hypot", "ComplexMultReal", "ComplexLog", "ComplexPlusReal", "ComplexPlusComplex", "ComplexMultComplex", "ComplexSqrt" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightInvPi, prefix + "arcsinh_weight_inv_pi"));//Precalc. + } + +private: + T m_WeightInvPi;//Precalc only. +}; + +/// +/// arctanh. +/// +template +class ArctanhVariation : public ParametricVariation +{ +public: + ArctanhVariation(T weight = 1.0) : ParametricVariation("arctanh", eVariationId::VAR_ARCTANH, weight) + { + Init(); + } + + PARVARCOPY(ArctanhVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + v2T z(helper.In.x, helper.In.y); + v2T zm(-helper.In.x, -helper.In.y); + v2T result = VarFuncs::ComplexMultReal(VarFuncs::ComplexLog(VarFuncs::ComplexDivComplex(VarFuncs::ComplexPlusReal(z, 1.0), VarFuncs::ComplexPlusReal(zm, 1.0))), m_WeightInvPi); + 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 weightinvpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal2 z = (real2)(vIn.x, vIn.y);\n" + << "\t\treal2 zm = (real2)(-vIn.x, -vIn.y);\n" + << "\t\treal2 result = ComplexMultReal(ComplexLog(ComplexDivComplex(ComplexPlusReal(z, 1.0), ComplexPlusReal(zm, 1.0))), " << weightinvpi << ");\n" + << "\n" + << "\t\tvOut.x = result.x;\n" + << "\t\tvOut.y = result.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_WeightInvPi = m_Weight * T(M_1_PI); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Sign", "Zeps", "ComplexMultReal", "ComplexLog", "ComplexPlusReal", "ComplexDivComplex" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(true, &m_WeightInvPi, prefix + "arctanh_weight_inv_pi"));//Precalc. + } + +private: + T m_WeightInvPi;//Precalc only. +}; + +/// +/// hex_truchet. +/// By tatasz. +/// +template +class HexTruchetVariation : public ParametricVariation +{ +public: + HexTruchetVariation(T weight = 1.0) : ParametricVariation("hex_truchet", eVariationId::VAR_HEX_TRUCHET, weight) + { + Init(); + } + + PARVARCOPY(HexTruchetVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = rand.Frand01() * M_2PI; + T r = std::sqrt(rand.Frand01() * m_MaxmMin + m_Min); + v2T xy; + + if (angle < 2.0943) + { + xy = v2T(1, T(0.5773)); + } + else + { + if (angle < 4.1887) + xy = v2T(-1, T(0.5773)); + else + xy = v2T(0, T(-1.1547)); + } + + T a = angle + T(2.6179); + T X = 2 * (Floor(rand.Frand01() * m_Sidem2p1) - m_Side); + T Y = 2 * (Floor(rand.Frand01() * m_Sidem2p1) - m_Side); + T xfinal = X + T(0.5) * Y; + T yfinal = T(0.8660) * Y; + T random = VarFuncs::HashShadertoy(X, Y, m_Seed); + T rotation = random < T(0.5) ? 0 : T(1.0471); + T a_final = a - rotation; + T cosa = std::cos(rotation); + T sina = std::sin(rotation); + v2T xy_final(xy.x * cosa + xy.y * sina, -xy.x * sina + xy.y * cosa); + helper.Out.x = (std::cos(a_final) * r + xy_final.x + xfinal) * m_Weight; + helper.Out.y = (std::sin(a_final) * r + xy_final.y + yfinal) * 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 size = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string side = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string onemsize = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mn = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string maxmmin = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sidem2p1 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t angle = MwcNext01(mwc) * M_2PI;\n" + << "\t\treal_t r = sqrt(fma(MwcNext01(mwc), " << maxmmin << ", " << mn << "));\n" + << "\t\treal2 xy;\n" + << "\n" + << "\t\tif (angle < 2.0943)\n" + << "\t\t{\n" + << "\t\t xy = (real2)(1.0, 0.5773);\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t if (angle < 4.1887)\n" + << "\t\t xy = (real2)(-1.0, 0.5773);\n" + << "\t\t else\n" + << "\t\t xy = (real2)(0.0, -1.1547);\n" + << "\t\t}\n" + << "\n" + << "\t\treal_t a = angle + 2.6179;\n" + << "\t\treal_t X = 2.0 * (floor(MwcNext01(mwc) * " << sidem2p1 << ") - " << side << ");\n" + << "\t\treal_t Y = 2.0 * (floor(MwcNext01(mwc) * " << sidem2p1 << ") - " << side << ");\n" + << "\t\treal_t xfinal = fma(0.5, Y, X);\n" + << "\t\treal_t yfinal = 0.8660 * Y;\n" + << "\t\treal_t random = HashShadertoy(X, Y, " << seed << ");\n" + << "\t\treal_t rotation = random < 0.5 ? 0.0 : 1.0471;\n" + << "\t\treal_t a_final = a - rotation;\n" + << "\t\treal_t cosa = cos(rotation);\n" + << "\t\treal_t sina = sin(rotation);\n" + << "\t\treal2 xy_final = (real2)(fma(xy.x, cosa, xy.y * sina), fma(-xy.x, sina, xy.y * cosa));\n" + << "\n" + << "\t\tvOut.x = fma(cos(a_final), r, xy_final.x + xfinal) * " << weight << ";\n" + << "\t\tvOut.y = fma(sin(a_final), r, xy_final.y + yfinal) * " << weight << ";\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_OnemSize = (1 - m_Size) * T(0.85); + m_Min = Sqr(T(0.15) + m_OnemSize * T(0.5)); + T mx = Sqr(1 - m_OnemSize * T(0.5)); + m_MaxmMin = mx - m_Min; + m_Sidem2p1 = m_Side * 2 + 1; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Size, prefix + "hex_truchet_size", 1, eParamType::REAL, -1, 1)); + m_Params.push_back(ParamWithName(&m_Side, prefix + "hex_truchet_side", 1)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "hex_truchet_seed", 1)); + m_Params.push_back(ParamWithName(true, &m_OnemSize, prefix + "hex_truchet_onemsize"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Min, prefix + "hex_truchet_min")); + m_Params.push_back(ParamWithName(true, &m_MaxmMin, prefix + "hex_truchet_maxmmin")); + m_Params.push_back(ParamWithName(true, &m_Sidem2p1, prefix + "hex_truchet_sidem2p1")); + } + +private: + T m_Size; + T m_Side; + T m_Seed; + T m_OnemSize;//Precalc only. + T m_Min; + T m_MaxmMin; + T m_Sidem2p1; +}; + +/// +/// hex_rand. +/// By tatasz. +/// +template +class HexRandVariation : public ParametricVariation +{ +public: + HexRandVariation(T weight = 1.0) : ParametricVariation("hex_rand", eVariationId::VAR_HEX_RAND, weight) + { + Init(); + } + + PARVARCOPY(HexRandVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T k = rand.Frand01() * 6; + auto int_angle = Floor(k); + T x = k - int_angle; + T z = std::sqrt(1 + x * x - x); + T angle_sign = T((int_angle - Floor(k / 2) * 2) == 1 ? 1 : -1); + T final_angle = T(2.0943951023931954923084289221863) * (int_angle / 2) + angle_sign * std::asin(T(0.86602540378443864676372317075294) * x / z) - T(M_PI_2); + T X = (floor(rand.Frand01() * m_X * 2) - m_X); + T Y = (floor(rand.Frand01() * m_Y * 2) - m_Y); + T xfinal = X + T(0.5) * Y; + T yfinal = Y * T(0.86602540378443864676372317075294); + T N = VarFuncs::HashShadertoy(yfinal, xfinal, m_Seed); + + if (N < m_Density) + { + T z_scaled = z * std::sqrt(rand.Frand01()) * T(1.1547005383792515290182975610039);//2 / sqrt(3) + T n = VarFuncs::HashShadertoy(xfinal, yfinal, m_Seed); + T R = m_SizeOver2 * z_scaled * std::pow(n, m_Power); + helper.Out.x = std::cos(final_angle) * R + xfinal * m_Weight; + helper.Out.y = std::sin(final_angle) * R + yfinal * 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 x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string size = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string density = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sizeover2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t k = MwcNext01(mwc) * 6;\n" + << "\t\tint int_angle = (int)floor(k);\n" + << "\t\treal_t x = k - int_angle;\n" + << "\t\treal_t z = sqrt(1 + x * x - x);\n" + << "\t\treal_t angle_sign = (int_angle - floor(k / 2) * 2) == 1 ? 1.0 : -1.0;\n" + << "\t\treal_t final_angle = 2.0943951023931954923084289221863 * (int_angle / 2) + angle_sign * asin(0.86602540378443864676372317075294 * x / z) - MPI2;\n" + << "\t\treal_t X = (floor(MwcNext01(mwc) * " << x << " * 2) - " << x << ");\n" + << "\t\treal_t Y = (floor(MwcNext01(mwc) * " << y << " * 2) - " << y << ");\n" + << "\t\treal_t xfinal = fma(0.5, Y, X);\n" + << "\t\treal_t yfinal = Y * 0.86602540378443864676372317075294;\n" + << "\t\treal_t N = HashShadertoy(yfinal, xfinal, " << seed << ");\n" + << "\n" + << "\t\tif (N < " << density << ")\n" + << "\t\t{\n" + << "\t\t real_t z_scaled = z * sqrt(MwcNext01(mwc)) * 1.1547005383792515290182975610039;\n" + << "\t\t real_t n = HashShadertoy(xfinal, yfinal, " << seed << ");\n" + << "\t\t real_t R = " << sizeover2 << " * z_scaled * pow(n, " << power << ");\n" + << "\t\t vOut.x = fma(cos(final_angle), R, xfinal) * " << weight << ";\n" + << "\t\t vOut.y = fma(sin(final_angle), R, yfinal) * " << weight << ";\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_SizeOver2 = m_Size * T(0.5); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "hex_rand_x", 10)); + m_Params.push_back(ParamWithName(&m_Y, prefix + "hex_rand_y", 10)); + m_Params.push_back(ParamWithName(&m_Size, prefix + "hex_rand_size", 1)); + m_Params.push_back(ParamWithName(&m_Power, prefix + "hex_rand_power", 1)); + m_Params.push_back(ParamWithName(&m_Density, prefix + "hex_rand_density", 1, eParamType::REAL, 0, 1)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "hex_rand_seed", 1)); + m_Params.push_back(ParamWithName(true, &m_SizeOver2, prefix + "hex_rand_size_over_2")); + } + +private: + T m_X; + T m_Y; + T m_Size; + T m_Power; + T m_Density; + T m_Seed; + T m_SizeOver2;//Precalc. +}; + +/// +/// smartshape. +/// By Zy0rg. +/// +template +class SmartshapeVariation : public ParametricVariation +{ +public: + SmartshapeVariation(T weight = 1.0) : ParametricVariation("smartshape", eVariationId::VAR_SMARTSHAPE, weight, true, true, false, false, true) + { + Init(); + } + + PARVARCOPY(SmartshapeVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T dang = (helper.m_PrecalcAtanyx + T(M_PI)) / m_Alpha; + T rad = helper.m_PrecalcSqrtSumSquares; + T zang1 = T(Floor(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; + + if (m_Comp == 1 && m_Distortion >= 1) + xang = std::atan(xang2 * m_AlphaCoeff) / m_Alpha; + else + xang = xang2; + + T coeff_1; + + if (m_Distortion == 0) + { + coeff_1 = 1; + } + else + { + T coeff0 = 1 / std::cos(xang * m_Alpha); + + if (m_Roundstr != 0) + { + T wwidth; + + if (m_Roundwidth != 1) + wwidth = std::exp(std::log(xang * 2) * m_Roundwidth) * m_RoundCoeff; + else + wwidth = xang * 2 * m_RoundCoeff; + + coeff_1 = std::abs((1 - wwidth) * coeff0 + wwidth); + } + else + coeff_1 = coeff0; + } + + T coeff; + + //for negative distortion and small values of coeff_1 + //this expression is numerically unstable + //double precision strongly recommended + if (m_Distortion != 1) + coeff = std::exp(std::log(coeff_1) * m_Distortion); + else + coeff = coeff_1; + + T ang = (zang + sign * xang) * m_Alpha - T(M_PI); + T temp = m_Weight * coeff * rad; + helper.Out.x = std::cos(ang) * temp; + helper.Out.y = std::sin(ang) * temp; + 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string roundstr = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string roundwidth = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string distortion = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string compensation = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string alpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string alphacoeff = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string roundcoeff = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string comp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t dang = (precalcAtanyx + MPI) / " << alpha << ";\n" + << "\t\treal_t rad = precalcSqrtSumSquares;\n" + << "\t\treal_t zang1 = floor(dang);\n" + << "\t\treal_t xang1 = dang - zang1;\n" + << "\t\treal_t xang2 = xang1 > 0.5 ? 1.0 - xang1 : xang1;\n" + << "\t\treal_t zang = xang1 > 0.5 ? zang1 + 1.0 : zang1;\n" + << "\t\treal_t sign = xang1 > 0.5 ? -1.0 : 1.0;\n" + << "\t\treal_t xang;\n" + << "\n" + << "\t\tif (" << comp << " == 1.0 && " << distortion << " >= 1.0)\n" + << "\t\t xang = atan(xang2 * " << alphacoeff << ") / " << alpha << ";\n" + << "\t\telse\n" + << "\t\t xang = xang2;\n" + << "\n" + << "\t\treal_t coeff_1;\n" + << "\n" + << "\t\tif (" << distortion << " == 0.0)\n" + << "\t\t{\n" + << "\t\t coeff_1 = 1.0;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t real_t coeff0 = 1.0 / cos(xang * " << alpha << ");\n" + << "\n" + << "\t\t if (" << roundstr << " != 0.0)\n" + << "\t\t {\n" + << "\t\t real_t wwidth;\n" + << "\t\t if (" << roundwidth << " != 1.0)\n" + << "\t\t wwidth = exp(log(xang * 2) * " << roundwidth << ") * " << roundcoeff << ";\n" + << "\t\t else\n" + << "\t\t wwidth = xang * 2 * " << roundcoeff << ";\n" + << "\n" + << "\t\t coeff_1 = fabs(fma(1.0 - wwidth, coeff0, wwidth));\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t coeff_1 = coeff0;\n" + << "\t\t}\n" + << "\n" + << "\t\treal_t coeff;\n" + << "\n" + << "\t\tif (" << distortion << " != 1.0)\n" + << "\t\t coeff = exp(log(coeff_1) * " << distortion << ");\n" + << "\t\telse\n" + << "\t\t coeff = coeff_1;\n" + << "\n" + << "\t\treal_t ang = fma(sign, xang, zang) * " << alpha << " - MPI;\n" + << "\t\treal_t temp = " << weight << " * coeff * rad;\n" + << "\t\tvOut.x = cos(ang) * temp;\n" + << "\t\tvOut.y = sin(ang) * temp;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_Alpha = T(M_2PI) / m_Power; + m_AlphaCoeff = std::tan(m_Alpha * T(0.5)) * 2; + m_RoundCoeff = m_Roundstr / std::sin(m_Alpha * T(0.5)) / m_Power * 2; + m_Comp = m_Compensation <= 0 ? T(0) : T(1); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "smartshape_power", 4, eParamType::REAL, 2)); + m_Params.push_back(ParamWithName(&m_Roundstr, prefix + "smartshape_roundstr")); + m_Params.push_back(ParamWithName(&m_Roundwidth, prefix + "smartshape_roundwidth", 1)); + m_Params.push_back(ParamWithName(&m_Distortion, prefix + "smartshape_distortion", 1)); + m_Params.push_back(ParamWithName(&m_Compensation, prefix + "smartshape_compensation", 1, eParamType::INTEGER, 0, 1)); + m_Params.push_back(ParamWithName(true, &m_Alpha, prefix + "smartshape_alpha"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_AlphaCoeff, prefix + "smartshape_alphacoeff")); + m_Params.push_back(ParamWithName(true, &m_RoundCoeff, prefix + "smartshape_roundcoeff")); + m_Params.push_back(ParamWithName(true, &m_Comp, prefix + "smartshape_comp")); + } + +private: + T m_Power; + T m_Roundstr; + T m_Roundwidth; + T m_Distortion; + T m_Compensation; + T m_Alpha;//Precalc. + T m_AlphaCoeff; + T m_RoundCoeff; + T m_Comp; +}; + +/// +/// squares. +/// By tatasz. +/// +template +class SquaresVariation : public ParametricVariation +{ +public: + SquaresVariation(T weight = 1.0) : ParametricVariation("squares", eVariationId::VAR_SQUARES, weight) + { + Init(); + } + + PARVARCOPY(SquaresVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& 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(helper.In.x / m_CellSize) + T(0.5)) * m_CellSize; + T Cy = (Floor(helper.In.y / m_CellSize) + T(0.5)) * m_CellSize; + T Lx = helper.In.x - Cx; + T Ly = helper.In.y - Cy; + T aLx = std::abs(T(Floor(Lx * m_Num * 2 / m_CellSize + T(0.5)))); + T aLy = std::abs(T(Floor(Ly * m_Num * 2 / m_CellSize + T(0.5)))); + T m = std::max(aLx, aLy); + T maxi = m_Max + Floor(VarFuncs::HashShadertoy(SQR(Cx), SQR(Cy), m_Seed) * (m_Num - m_Max)); + T level; + + if (m > maxi) + level = 0; + else if (m < m_Min) + level = 0; + else + level = m - m_Min; + + T angle; + + if (VarFuncs::HashShadertoy(SQR(Cx), SQR(Cy), m_ZeroSeed) < m_Zero) + angle = 0; + else + angle = level * T(M_PI_2); + + T c = std::cos(angle); + T s = std::sin(angle); + helper.Out.x = (Cx + Lx * c - Ly * s) * m_Weight; + helper.Out.y = (Cy + Lx * s + Ly * c) * 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 mn = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string num = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string zero = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string zeroseed = "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 / " << cellsize << ") + 0.5) * " << cellsize << ";\n" + << "\t\t real_t Cy = (floor(vIn.y / " << cellsize << ") + 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 aLx = fabs(floor(Lx * " << num << " * 2.0 / " << cellsize << " + 0.5));\n" + << "\t\t real_t aLy = fabs(floor(Ly * " << num << " * 2.0 / " << cellsize << " + 0.5));\n" + << "\t\t real_t m = max(aLx, aLy);\n" + << "\t\t real_t maxi = " << mx << " + floor(HashShadertoy(SQR(Cx), SQR(Cy), " << seed << ") * (" << num << " - " << mx << "));\n" + << "\t\t real_t level;\n" + << "\n" + << "\t\t if (m > maxi)\n" + << "\t\t level = 0.0;\n" + << "\t\t else if (m < " << mn << ")\n" + << "\t\t level = 0.0;\n" + << "\t\t else\n" + << "\t\t level = m - " << mn << ";\n" + << "\n" + << "\t\t real_t angle;\n" + << "\n" + << "\t\t if (HashShadertoy(SQR(Cx), SQR(Cy), " << zeroseed << ") < " << zero << ")\n" + << "\t\t angle = 0.0;\n" + << "\t\t else\n" + << "\t\t angle = level * MPI2;\n" + << "\n" + << "\t\t real_t c = cos(angle);\n" + << "\t\t real_t s = sin(angle);\n" + << "\n" + << "\t\t vOut.x = (Cx + Lx * c - Ly * s) * " << weight << ";\n" + << "\t\t vOut.y = (Cy + Lx * s + Ly * c) * " << weight << ";\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_CellSize, prefix + "squares_cellsize")); + m_Params.push_back(ParamWithName(&m_Min, prefix + "squares_min", 0, eParamType::INTEGER, 0)); + m_Params.push_back(ParamWithName(&m_Max, prefix + "squares_max", 10, eParamType::INTEGER, 0)); + m_Params.push_back(ParamWithName(&m_Num, prefix + "squares_num", 10)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "squares_seed", 1)); + m_Params.push_back(ParamWithName(&m_Zero, prefix + "squares_zero", T(0.5))); + m_Params.push_back(ParamWithName(&m_ZeroSeed, prefix + "squares_zero_seed", 1)); + } + +private: + T m_CellSize; + T m_Min; + T m_Max; + T m_Num; + T m_Seed; + T m_Zero; + T m_ZeroSeed; +}; + +/// +/// starblur2. +/// By Zy0rg. +/// +template +class Starblur2Variation : public ParametricVariation +{ +public: + Starblur2Variation(T weight = 1.0) : ParametricVariation("starblur2", eVariationId::VAR_STARBLUR2, weight) + { + Init(); + } + + PARVARCOPY(Starblur2Variation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T k = rand.Frand01() * m_Power2; + auto int_angle = Floor(k); + T f = k - int_angle; + T ff; + + if (m_Stripes > 0) + { + T fs = std::trunc(f * m_Stripes); + T dif; + + if (std::fmod(int_angle, T(2)) == 0) + dif = m_Width * (f * m_Stripes - fs); + else + dif = 1 - m_Width * (f * m_Stripes - fs); + + ff = (dif + fs) / m_Stripes; + } + else + ff = f; + + T x = ff * m_Length; + T z = std::sqrt(1 + x * x - 2 * x * m_CosAlpha); + T angle_sign = (int_angle - Floor(k / 2) * 2) == 1 ? T(1) : T(-1); + T final_angle = m_TwopiPower * int_angle + angle_sign * std::asin(m_SinAlpha * x / z) - T(M_PI_2); + T z_scaled = z * std::sqrt(rand.Frand01() * m_OnemHoleSq + m_HoleSq); + helper.Out.x = std::cos(final_angle) * z_scaled * m_Weight; + helper.Out.y = std::sin(final_angle) * z_scaled * 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 power = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string range = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string hole = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string stripes = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string width = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string alpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string length = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string holesq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string onemholesq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twopipower = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string power2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinalpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string cosalpha = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t k = MwcNext01(mwc) * " << power2 << ";\n" + << "\t\treal_t int_angle = floor(k);\n" + << "\t\treal_t f = k - int_angle;\n" + << "\t\treal_t ff;\n" + << "\n" + << "\t\tif (" << stripes << " > 0.0)\n" + << "\t\t{\n" + << "\t\t real_t fs = trunc(f * " << stripes << ");\n" + << "\t\t real_t dif;\n" + << "\n" + << "\t\t if (fmod(int_angle, 2.0) == 0)\n" + << "\t\t dif = " << width << " * fma(f, " << stripes << ", -fs);\n" + << "\t\t else\n" + << "\t\t dif = 1 - " << width << " * fma(f, " << stripes << ", -fs);\n" + << "\n" + << "\t\t ff = (dif + fs) / " << stripes << ";\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t ff = f;\n" + << "\n" + << "\t\treal_t x = ff * " << length << ";\n" + << "\t\treal_t z = sqrt(1 + x * x - 2.0 * x * " << cosalpha << ");\n" + << "\t\treal_t angle_sign = (int_angle - floor(k/2) * 2) == 1.0 ? 1.0 : -1.0;\n" + << "\t\treal_t final_angle = " << twopipower << " * int_angle + angle_sign * asin(" << sinalpha << " * x / z) - MPI2;\n" + << "\t\treal_t z_scaled = z * sqrt(fma(MwcNext01(mwc), " << onemholesq << ", " << holesq << "));\n" + << "\t\tvOut.x = cos(final_angle) * z_scaled * " << weight << ";\n" + << "\t\tvOut.y = sin(final_angle) * z_scaled * " << weight << ";\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T alpha = T(M_PI) / m_Power; + m_Length = std::sqrt(1 + m_Range * m_Range - 2 * m_Range * std::cos(alpha)); + m_Alpha = std::asin(std::sin(alpha) * m_Range / Zeps(m_Length)); + m_HoleSq = SQR(m_Hole); + m_OnemHoleSq = 1 - m_HoleSq; + m_TwopiPower = (M_2PI / m_Power) * T(0.5); + m_Power2 = m_Power * 2; + m_SinAlpha = std::sin(m_Alpha); + m_CosAlpha = std::cos(m_Alpha); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Power, prefix + "starblur2_power", 5)); + m_Params.push_back(ParamWithName(&m_Range, prefix + "starblur2_range", T(0.40162283177245455973959534526548))); + m_Params.push_back(ParamWithName(&m_Hole, prefix + "starblur2_hole", T(0.5), eParamType::REAL, 0, 1)); + m_Params.push_back(ParamWithName(&m_Stripes, prefix + "starblur2_stripes", 5, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Width, prefix + "starblur2_width", T(0.2))); + m_Params.push_back(ParamWithName(true, &m_Alpha, prefix + "starblur2_alpha"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_Length, prefix + "starblur2_length")); + m_Params.push_back(ParamWithName(true, &m_HoleSq, prefix + "starblur2_holesq")); + m_Params.push_back(ParamWithName(true, &m_OnemHoleSq, prefix + "starblur2_onem_holesq")); + m_Params.push_back(ParamWithName(true, &m_TwopiPower, prefix + "starblur2_twopi_power")); + m_Params.push_back(ParamWithName(true, &m_Power2, prefix + "starblur2_power2")); + m_Params.push_back(ParamWithName(true, &m_SinAlpha, prefix + "starblur2_sin_alpha")); + m_Params.push_back(ParamWithName(true, &m_CosAlpha, prefix + "starblur2_cos_alpha")); + } + +private: + T m_Power; + T m_Range; + T m_Hole; + T m_Stripes; + T m_Width; + T m_Alpha;//Precalc. + T m_Length; + T m_HoleSq; + T m_OnemHoleSq; + T m_TwopiPower; + T m_Power2; + T m_SinAlpha; + T m_CosAlpha; +}; + +/// +/// unicorngaloshen. +/// By tatasz and chaosfissure. +/// +template +class UnicornGaloshenVariation : public ParametricVariation +{ +public: + UnicornGaloshenVariation(T weight = 1.0) : ParametricVariation("unicorngaloshen", eVariationId::VAR_UNICORNGALOSHEN, weight) + { + Init(); + } + + PARVARCOPY(UnicornGaloshenVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T r = m_Weight / Zeps(std::sqrt((SQR(helper.In.y) * m_MultY) + (m_MultX * SQR(helper.In.x)))); + v2T factor; + + if (m_Sine <= 0) + { + factor.x = m_SinXAmp; + factor.y = m_SinYAmp; + } + else + { + v2T tmp_vec(1, 2); + v2T scalar_xy; + + if (m_Mode <= 0) + scalar_xy = v2T(helper.In.x, helper.In.y); + else if (m_Mode <= 1) + scalar_xy = v2T(std::exp(-helper.In.x), std::exp(-helper.In.y)); + else if (m_Mode <= 2) + scalar_xy = v2T(1 / Zeps(helper.In.x), 1 / Zeps(helper.In.y)); + else if (m_Mode <= 3) + scalar_xy = v2T(std::log(std::abs(helper.In.x)), m_SinYAmp * std::log(std::abs(helper.In.y))); + else + scalar_xy = v2T(std::atan2(helper.In.x, helper.In.y), std::atan2(helper.In.y, helper.In.x)); + + factor = tmp_vec + v2T(m_SinXAmp * std::sin(scalar_xy.x * m_SinXFreqPi), m_SinYAmp * std::sin(scalar_xy.y * m_SinYFreqPi));; + } + + helper.Out.x = factor.x * (helper.In.x - helper.In.y) * (helper.In.x + m_MultY * helper.In.y) * r; + helper.Out.y = factor.y * helper.In.x * helper.In.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 multx = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string multy = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sine = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinxamp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinxfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinyamp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinyfreq = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string mode = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinxfreqpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string sinyfreqpi = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t r = " << weight << " / Zeps(sqrt((SQR(vIn.y) * " << multy << ") + (" << multx << " * SQR(vIn.x))));\n" + << "\t\treal2 factor;\n" + << "\n" + << "\t\tif (" << sine << " <= 0)\n" + << "\t\t{\n" + << "\t\t factor.x = " << sinxamp << ";\n" + << "\t\t factor.y = " << sinyamp << ";\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t real2 tmp_vec = (real2)(1, 2);\n" + << "\t\t real2 scalar_xy;\n" + << "\n" + << "\t\t if (" << mode << " <= 0)\n" + << "\t\t scalar_xy = (real2)(vIn.x, vIn.y);\n" + << "\t\t else if (" << mode << " <= 1)\n" + << "\t\t scalar_xy = (real2)(exp(-vIn.x), exp(-vIn.y));\n" + << "\t\t else if (" << mode << " <= 2)\n" + << "\t\t scalar_xy = (real2)(1 / Zeps(vIn.x), 1 / Zeps(vIn.y));\n" + << "\t\t else if (" << mode << " <= 3)\n" + << "\t\t scalar_xy = (real2)(log(fabs(vIn.x)), " << sinyamp << " * log(fabs(vIn.y)));\n" + << "\t\t else\n" + << "\t\t scalar_xy = (real2)(atan2(vIn.x, vIn.y), atan2(vIn.y, vIn.x));\n" + << "\n" + << "\t\t factor = tmp_vec + (real2)(" << sinxamp << " * sin(scalar_xy.x * " << sinxfreqpi << "), " << sinyamp << " * sin(scalar_xy.y * " << sinyfreqpi << "));\n" + << "\t\t}\n" + << "\t\tvOut.x = factor.x * (vIn.x - vIn.y) * fma(" << multy << ", vIn.y, vIn.x) * r;\n" + << "\t\tvOut.y = factor.y * vIn.x * vIn.y * r;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T m_SinXFreqPi = T(M_PI) * m_SinXFreq; + T m_SinYFreqPi = T(M_PI) * m_SinYFreq; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_MultX, prefix + "unicorngaloshen_mult_x", 1)); + m_Params.push_back(ParamWithName(&m_MultY, prefix + "unicorngaloshen_mult_y", 1)); + m_Params.push_back(ParamWithName(&m_Sine, prefix + "unicorngaloshen_sine")); + m_Params.push_back(ParamWithName(&m_SinXAmp, prefix + "unicorngaloshen_sin_x_amplitude", 1)); + m_Params.push_back(ParamWithName(&m_SinXFreq, prefix + "unicorngaloshen_sin_x_freq", T(0.1))); + m_Params.push_back(ParamWithName(&m_SinYAmp, prefix + "unicorngaloshen_sin_y_amplitude", 2)); + m_Params.push_back(ParamWithName(&m_SinYFreq, prefix + "unicorngaloshen_sin_y_freq", T(0.2))); + m_Params.push_back(ParamWithName(&m_Mode, prefix + "unicorngaloshen_mode", 0, eParamType::INTEGER, 0, 4)); + m_Params.push_back(ParamWithName(true, &m_SinXFreqPi, prefix + "unicorngaloshen_sin_x_freq_pi")); + m_Params.push_back(ParamWithName(true, &m_SinYFreqPi, prefix + "unicorngaloshen_sin_y_freq_pi")); + } + +private: + T m_MultX; + T m_MultY; + T m_Sine; + T m_SinXAmp; + T m_SinXFreq; + T m_SinYAmp; + T m_SinYFreq; + T m_Mode; + T m_SinXFreqPi;//Precalc. + T m_SinYFreqPi; +}; + +/// +/// dragonfire. +/// By tatasz and chaosfissure. +/// +template +class DragonfireVariation : public ParametricVariation +{ +public: + DragonfireVariation(T weight = 1.0) : ParametricVariation("dragonfire", eVariationId::VAR_DRAGONFIRE, weight) + { + Init(); + } + + PARVARCOPY(DragonfireVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T exp_x = std::exp(helper.In.x) * m_C1; + T exp_nx = m_C2 / Zeps(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 + exp_nx - cos_y); + T newFX = (exp_x - exp_nx) * r; + T newFY = sin_y * r; + + if (m_FuzzyMode < 1) + { + helper.Out.x = newFX; + helper.Out.y = newFY; + } + else + { + T fuzzyX = std::cos(m_LogScalarFuzzy / Zeps(std::log(std::abs(newFX)))); + T fuzzyY = std::cos(m_LogScalarFuzzy / Zeps(std::log(std::abs(newFY)))); + v2T newXY; + + if (m_FuzzyMode < 2) + { + newXY.x = newFX + fuzzyX; + newXY.y = newFY + fuzzyY; + } + else if (m_FuzzyMode < 3) + { + T sinfx = std::sin(fuzzyX);//Duped in 2 and 3. + T sinfy = std::sin(fuzzyY); + newXY.x = newFX * sinfx; + newXY.y = newFY * sinfy; + } + else if (m_FuzzyMode < 4) + { + T sinfx = std::sin(fuzzyX); + T sinfy = std::sin(fuzzyY); + newXY.x = newFX * std::exp(sinfx); + newXY.y = newFY * std::exp(sinfy); + } + else if (m_FuzzyMode < 5) + { + T dirX = T(fuzzyX < 0 ? -1 : 1);//Duped in 4, 5, and 6. + T dirY = T(fuzzyY < 0 ? -1 : 1); + T fuzzyX1 = dirX * m_FuzzyRadius; + T fuzzyY1 = dirY * m_FuzzyRadius; + newXY.x = newFX + fuzzyX1; + newXY.y = newFY + fuzzyY1; + } + else if (m_FuzzyMode < 6) + { + T dirX = T(fuzzyX < 0 ? -1 : 1); + T dirY = T(fuzzyY < 0 ? -1 : 1); + T fuzzyX1 = dirX * m_FuzzyRadius; + T fuzzyY1 = dirY * m_FuzzyRadius; + newXY.x = newFX + std::exp(fuzzyX1); + newXY.y = newFY + std::exp(fuzzyY1); + } + else + { + T dirX = T(fuzzyX < 0 ? -1 : 1); + T dirY = T(fuzzyY < 0 ? -1 : 1); + T fuzzyX1 = dirX * m_FuzzyRadius; + T fuzzyY1 = dirY * m_FuzzyRadius; + newXY.x = newFX + std::exp(std::sin(fuzzyX1)); + newXY.y = newFY + std::exp(std::cos(fuzzyY1)); + } + + if (m_FuzzyInterpolationMode < 1) + { + helper.Out.x = newXY.x; + helper.Out.y = newXY.y; + } + else + { + helper.Out.x = newFX * m_1mVal + newXY.x * m_Val; + helper.Out.y = newFY * m_1mVal + newXY.y * m_Val; + } + } + + 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; + string mode = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string radius = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string interpmode = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string interppos = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string logscalar = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string adjustedscalar = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string val = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string onemval = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t exp_x = exp(vIn.x) * " << c1 << ";\n" + << "\t\treal_t exp_nx = " << c2 << " / Zeps(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 + exp_nx - cos_y);\n" + << "\t\treal_t newFX = (exp_x - exp_nx) * r;\n" + << "\t\treal_t newFY = sin_y * r;\n" + << "\n" + << "\t\tif (" << mode << " < 1)\n" + << "\t\t{\n" + << "\t\t vOut.x = newFX;\n" + << "\t\t vOut.y = newFY;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t real_t fuzzyX = cos(" << logscalar << " / Zeps(log(fabs(newFX))));\n" + << "\t\t real_t fuzzyY = cos(" << logscalar << " / Zeps(log(fabs(newFY))));\n" + << "\t\t real2 newXY;\n" + << "\n" + << "\t\t if (" << mode << " < 2)\n" + << "\t\t {\n" + << "\t\t newXY.x = newFX + fuzzyX;\n" + << "\t\t newXY.y = newFY + fuzzyY;\n" + << "\t\t }\n" + << "\t\t else if (" << mode << " < 3)\n" + << "\t\t {\n" + << "\t\t real_t sinfx = sin(fuzzyX);\n" + << "\t\t real_t sinfy = sin(fuzzyY);\n" + << "\t\t newXY.x = newFX * sinfx;\n" + << "\t\t newXY.y = newFY * sinfy;\n" + << "\t\t }\n" + << "\t\t else if (" << mode << " < 4)\n" + << "\t\t {\n" + << "\t\t real_t sinfx = sin(fuzzyX);\n" + << "\t\t real_t sinfy = sin(fuzzyY);\n" + << "\t\t newXY.x = newFX * exp(sinfx);\n" + << "\t\t newXY.y = newFY * exp(sinfy);\n" + << "\t\t }\n" + << "\t\t else if (" << mode << " < 5)\n" + << "\t\t {\n" + << "\t\t real_t dirX = fuzzyX < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t dirY = fuzzyY < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t fuzzyX1 = dirX * " << radius << ";\n" + << "\t\t real_t fuzzyY1 = dirY * " << radius << ";\n" + << "\t\t newXY.x = newFX + fuzzyX1;\n" + << "\t\t newXY.y = newFY + fuzzyY1;\n" + << "\t\t }\n" + << "\t\t else if (" << mode << " < 6)\n" + << "\t\t {\n" + << "\t\t real_t dirX = fuzzyX < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t dirY = fuzzyY < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t fuzzyX1 = dirX * " << radius << ";\n" + << "\t\t real_t fuzzyY1 = dirY * " << radius << ";\n" + << "\t\t newXY.x = newFX + exp(fuzzyX1);\n" + << "\t\t newXY.y = newFY + exp(fuzzyY1);\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t real_t dirX = fuzzyX < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t dirY = fuzzyY < 0.0 ? -1.0 : 1.0;\n" + << "\t\t real_t fuzzyX1 = dirX * " << radius << ";\n" + << "\t\t real_t fuzzyY1 = dirY * " << radius << ";\n" + << "\t\t newXY.x = newFX + exp(sin(fuzzyX1));\n" + << "\t\t newXY.y = newFY + exp(cos(fuzzyY1));\n" + << "\t\t }\n" + << "\n" + << "\t\t if (" << interpmode << " < 1)\n" + << "\t\t {\n" + << "\t\t vOut.x = newXY.x;\n" + << "\t\t vOut.y = newXY.y;\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t vOut.x = fma(newFX, " << onemval << ", newXY.x * " << val << ");\n" + << "\t\t vOut.y = fma(newFY, " << onemval << ", newXY.y * " << val << ");\n" + << "\t\t }\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + T pos_mpi = m_FuzzyInterpolationPosition * T(M_PI); + + if (m_FuzzyInterpolationMode < 2) + { + m_Val = m_FuzzyInterpolationPosition; + } + else + { + T trigPos; + + if (m_FuzzyInterpolationMode < 3) + trigPos = std::cos(pos_mpi); + else if (m_FuzzyInterpolationMode < 4) + trigPos = std::tan(pos_mpi); + else if (m_FuzzyInterpolationMode < 5) + trigPos = std::sinh(pos_mpi); + else + trigPos = std::asinh(pos_mpi); + + m_Val = (1 - trigPos) * m_AdjustedFuzzyScalar; + } + + m_1mVal = 1 - m_Val; + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_C1, prefix + "dragonfire_c1", T(0.5))); + m_Params.push_back(ParamWithName(&m_C2, prefix + "dragonfire_c2", T(0.25))); + m_Params.push_back(ParamWithName(&m_FuzzyMode, prefix + "dragonfire_fuzzyMode", 0, eParamType::INTEGER, 0, 7)); + m_Params.push_back(ParamWithName(&m_FuzzyRadius, prefix + "dragonfire_fuzzyRadius", 1)); + m_Params.push_back(ParamWithName(&m_FuzzyInterpolationMode, prefix + "dragonfire_fuzzyInterpolationMode", 0, eParamType::INTEGER, 0, 6)); + m_Params.push_back(ParamWithName(&m_FuzzyInterpolationPosition, prefix + "dragonfire_fuzzyInterpolationPosition", 1)); + m_Params.push_back(ParamWithName(&m_LogScalarFuzzy, prefix + "dragonfire_logScalarFuzzy", M_2PI)); + m_Params.push_back(ParamWithName(&m_AdjustedFuzzyScalar, prefix + "dragonfire_adjustedFuzzyScalar", T(0.5))); + m_Params.push_back(ParamWithName(true, &m_Val, prefix + "dragonfire_val"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_1mVal, prefix + "dragonfire_1m_val")); + } + +private: + T m_C1; + T m_C2; + T m_FuzzyMode; + T m_FuzzyRadius; + T m_FuzzyInterpolationMode; + T m_FuzzyInterpolationPosition; + T m_LogScalarFuzzy; + T m_AdjustedFuzzyScalar; + T m_Val;//Precalc. + T m_1mVal; +}; + +/// +/// truchet_glyph. +/// By tatasz and tyrantwave. +/// +template +class TruchetGlyphVariation : public ParametricVariation +{ +public: + TruchetGlyphVariation(T weight = 1.0) : ParametricVariation("Truchet_glyph", eVariationId::VAR_TRUCHET_GLYPH, weight) + { + Init(); + } + + PARVARCOPY(TruchetGlyphVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T x1 = helper.In.x * m_Scale; + T y1 = helper.In.y * m_Scale; + T intx = T(Floor(x1 + T(0.5))); + T inty = T(Floor(y1 + T(0.5))); + T r_x = x1 - intx; + T x = r_x < 0 ? 1 + r_x : r_x; + T r_y = y1 - inty; + T y = r_y < 0 ? 1 + r_y : r_y; + T tiletype; + + if (m_Seed == 0) + { + tiletype = 0; + } + else if (m_Seed == 1) + { + tiletype = 1; + } + else + { + T xrand = T(Floor(std::abs(helper.In.x) + T(0.5))); + T yrand = T(Floor(std::abs(helper.In.y) + T(0.5))); + T randint0 = VarFuncs::HashShadertoy(xrand, yrand, m_Seed); + T randint = fmod(randint0 * T(32747) + T(12345), T(65535)); + tiletype = fmod(randint, T(2)); + } + + v2T R; + T xval1 = tiletype < 1 ? x : x - 1; + T xval2 = tiletype < 1 ? x - 1 : x; + R = v2T(std::pow(std::pow(std::abs(xval1), m_N) + std::pow(std::abs(y), m_N), m_OneN), std::pow(std::pow(std::abs(xval2), m_N) + std::pow(std::abs(y - 1), m_N), m_OneN)); + T r00 = std::abs(R.x - T(0.5)) / m_Rmax; + T r11 = std::abs(R.y - T(0.5)) / m_Rmax; + v2T xy; + + if (r00 < 1) + xy = v2T(x + Floor(helper.In.x) * 2, y + Floor(helper.In.y) * 2); + else + xy = v2T(0, 0); + + T cost = std::cos(m_Rads); + T sint = std::sin(m_Rads); + T roundx = (Floor(helper.In.x / m_Amp) + T(0.5)) * m_Amp; + T roundy = (Floor(helper.In.y / m_Amp) + T(0.5)) * m_Amp; + T vx = helper.In.x - roundx; + T vy = helper.In.y - roundy; + T newx = cost * vx + sint * vy; + T newy = -sint * vx + cost * vy; + + if (std::abs(newx) + std::abs(newy) < m_HalfAmpMax) + { + if (r11 < 1) + { + helper.Out.x = xy.x + (x + Floor(helper.In.x) * 2) - helper.In.x; + helper.Out.y = xy.y + (y + Floor(helper.In.y) * 2) - helper.In.y; + } + else + { + helper.Out.x = xy.x - helper.In.x; + helper.Out.y = xy.y - helper.In.y; + } + } + else + { + helper.Out.x = helper.In.x; + helper.Out.y = 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 exponent = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string arcwidth = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string amp = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string max = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rmax = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string n = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string onen = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rads = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string halfampmax = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t x1 = vIn.x * " << scale << ";\n" + << "\t\treal_t y1 = vIn.y * " << scale << ";\n" + << "\t\treal_t intx = floor(x1 + 0.5);\n" + << "\t\treal_t inty = floor(y1 + 0.5);\n" + << "\t\treal_t r_x = x1 - intx;\n" + << "\t\treal_t x = r_x < 0 ? 1 + r_x : r_x;\n" + << "\t\treal_t r_y = y1 - inty;\n" + << "\t\treal_t y = r_y < 0 ? 1 + r_y : r_y;\n" + << "\t\treal_t tiletype;\n" + << "\n" + << "\t\tif (" << seed << " == 0)\n" + << "\t\t{\n" + << "\t\t tiletype = 0;\n" + << "\t\t}\n" + << "\t\telse if (" << seed << " == 1)\n" + << "\t\t{\n" + << "\t\t tiletype = 1;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t real_t xrand = floor(fabs(vIn.x) + 0.5);\n" + << "\t\t real_t yrand = floor(fabs(vIn.y) + 0.5);\n" + << "\t\t real_t randint0 = HashShadertoy(xrand, yrand, " << seed << ");\n" + << "\t\t real_t randint = fmod(fma(randint0, 32747.0, 12345.0), 65535.0);\n" + << "\t\t tiletype = fmod(randint, 2.0);\n" + << "\t\t}\n" + << "\n" + << "\t\treal_t xval1 = tiletype < 1 ? x : x - 1;\n" + << "\t\treal_t xval2 = tiletype < 1 ? x - 1 : x;\n" + << "\t\treal2 R = (real2)(pow(pow(fabs(xval1), " << n << ") + pow(fabs(y), " << n << "), " << onen << "), pow(pow(fabs(xval2), " << n << ") + pow(fabs(y - 1), " << n << "), " << onen << "));\n" + << "\t\treal_t r00 = fabs(R.x - 0.5) / " << rmax << ";\n" + << "\t\treal_t r11 = fabs(R.y - 0.5) / " << rmax << ";\n" + << "\t\treal2 xy;\n" + << "\n" + << "\t\tif (r00 < 1)\n" + << "\t\t xy = (real2)(fma(floor(vIn.x), 2.0, x), fma(floor(vIn.y), 2.0, y));\n" + << "\t\telse\n" + << "\t\t xy = (real2)(0.0, 0.0);\n" + << "\n" + << "\t\treal_t cost = cos(" << rads << ");\n" + << "\t\treal_t sint = sin(" << rads << ");\n" + << "\t\treal_t roundx = (floor(vIn.x / " << amp << ") + 0.5) * " << amp << ";\n" + << "\t\treal_t roundy = (floor(vIn.y / " << amp << ") + 0.5) * " << amp << ";\n" + << "\t\treal_t vx = vIn.x - roundx;\n" + << "\t\treal_t vy = vIn.y - roundy;\n" + << "\t\treal_t newx = fma(cost, vx, sint * vy);\n" + << "\t\treal_t newy = fma(-sint, vx, cost * vy);\n" + << "\n" + << "\t\tif (fabs(newx) + fabs(newy) < " << halfampmax << ")\n" + << "\t\t{\n" + << "\t\t if (r11 < 1)\n" + << "\t\t {\n" + << "\t\t vOut.x = xy.x + fma(floor(vIn.x), 2.0, x) - vIn.x;\n" + << "\t\t vOut.y = xy.y + fma(floor(vIn.y), 2.0, y) - vIn.y;\n" + << "\t\t }\n" + << "\t\t else\n" + << "\t\t {\n" + << "\t\t vOut.x = xy.x - vIn.x;\n" + << "\t\t vOut.y = xy.y - vIn.y;\n" + << "\t\t }\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = vIn.x;\n" + << "\t\t vOut.y = vIn.y;\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_N = Clamp(m_Exponent, T(0.001), T(2)); + T width = Clamp(m_ArcWidth, T(0.001), T(1)); + m_OneN = 1 / Zeps(m_N); + m_Rmax = Zeps(T(0.5) * (std::pow(T(2.0), m_OneN) - 1) * width); + m_Scale = 1 / m_Weight; + m_Rads = m_Angle * DEG_2_RAD_T; + m_HalfAmpMax = m_Amp * T(0.5) * m_Max; + m_Amp = Zeps(m_Amp); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps", "Fract", "HashShadertoy" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Exponent, prefix + "Truchet_glyph_exponent", 2, eParamType::REAL, 0, 2)); + m_Params.push_back(ParamWithName(&m_ArcWidth, prefix + "Truchet_glyph_arc_width", T(0.5))); + m_Params.push_back(ParamWithName(&m_Amp, prefix + "Truchet_glyph_amp", 6, eParamType::REAL_NONZERO, EPS)); + m_Params.push_back(ParamWithName(&m_Max, prefix + "Truchet_glyph_max", T(0.9), eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "Truchet_glyph_angle", 45)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "Truchet_glyph_seed", 1)); + m_Params.push_back(ParamWithName(true, &m_Rmax, prefix + "Truchet_glyph_rmax"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_N, prefix + "Truchet_glyph_n")); + m_Params.push_back(ParamWithName(true, &m_OneN, prefix + "Truchet_glyph_onen")); + m_Params.push_back(ParamWithName(true, &m_Scale, prefix + "Truchet_glyph_scale")); + m_Params.push_back(ParamWithName(true, &m_Rads, prefix + "Truchet_glyph_rads")); + m_Params.push_back(ParamWithName(true, &m_HalfAmpMax, prefix + "Truchet_glyph_half_amp_max")); + } + +private: + T m_Exponent; + T m_ArcWidth; + T m_Amp; + T m_Max; + T m_Angle; + T m_Seed; + T m_Rmax;//Precalc. + T m_N; + T m_OneN; + T m_Scale; + T m_Rads; + T m_HalfAmpMax; +}; + +/// +/// truchet_inv. +/// By tatasz and tyrantwave. +/// +template +class TruchetInvVariation : public ParametricVariation +{ +public: + TruchetInvVariation(T weight = 1.0) : ParametricVariation("Truchet_inv", eVariationId::VAR_TRUCHET_INV, weight) + { + Init(); + } + + PARVARCOPY(TruchetInvVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T x1 = helper.In.x * m_Scale; + T y1 = helper.In.y * m_Scale; + T intx = T(Floor(x1 + T(0.5))); + T inty = T(Floor(y1 + T(0.5))); + T r_x = x1 - intx; + T x = r_x < 0 ? 1 + r_x : r_x; + T r_y = y1 - inty; + T y = r_y < 0 ? 1 + r_y : r_y; + T tiletype; + + if (m_Seed == 0) + { + tiletype = 0; + } + else if (m_Seed == 1) + { + tiletype = 1; + } + else + { + T xrand = Floor(helper.In.x + T(0.5)) * m_Seed2; + T yrand = Floor(helper.In.y + T(0.5)) * m_Seed2; + T niter = xrand + yrand + xrand * yrand; + T randint0 = (niter + m_Seed) * m_Seed2Half; + T randint = fmod(randint0 * 32747 + 12345, T(65535)); + tiletype = fmod(randint, T(2)); + } + + T xval1 = tiletype < 1 ? x : x - 1; + T xval2 = tiletype < 1 ? x - 1 : x; + v2T R(std::pow(std::pow(std::abs(xval1), m_N) + std::pow(std::abs(y), m_N), m_OneN), std::pow(std::pow(std::abs(xval2), m_N) + std::pow(std::abs(y - 1), m_N), m_OneN)); + T r00 = std::abs(R.x - T(0.5)) / m_Rmax; + T r11 = std::abs(R.y - T(0.5)) / m_Rmax; + + if (r00 > 1 && r11 > 1) + { + helper.Out.x = (x + Floor(helper.In.x)) * m_Size; + helper.Out.y = (y + Floor(helper.In.y)) * m_Size; + } + else + { + helper.Out.x = 0; + helper.Out.y = 0; + } + + 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 exponent = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string arcwidth = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rot = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string size = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string rmax = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string n = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string onen = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed2 = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string seed2half = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string scale = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t x1 = vIn.x * " << scale << ";\n" + << "\t\treal_t y1 = vIn.y * " << scale << ";\n" + << "\t\treal_t intx = floor(x1 + 0.5);\n" + << "\t\treal_t inty = floor(y1 + 0.5);\n" + << "\t\treal_t r_x = x1 - intx;\n" + << "\t\treal_t x = r_x < 0 ? 1 + r_x : r_x;\n" + << "\t\treal_t r_y = y1 - inty;\n" + << "\t\treal_t y = r_y < 0 ? 1 + r_y : r_y;\n" + << "\t\treal_t tiletype;\n" + << "\n" + << "\t\tif (" << seed << " == 0)\n" + << "\t\t{\n" + << "\t\t tiletype = 0;\n" + << "\t\t}\n" + << "\t\telse if (" << seed << " == 1)\n" + << "\t\t{\n" + << "\t\t tiletype = 1;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\treal_t xrand = floor(vIn.x + 0.5) * " << seed2 << ";\n" + << "\t\treal_t yrand = floor(vIn.y + 0.5) * " << seed2 << ";\n" + << "\t\treal_t niter = xrand + yrand + xrand * yrand;\n" + << "\t\treal_t randint0 = (niter + " << seed << ") * " << seed2half << ";\n" + << "\t\treal_t randint = fmod(fma(randint0, 32747.0, 12345.0), 65535.0);\n" + << "\t\t tiletype = fmod(randint, 2.0);\n" + << "\t\t}\n" + << "\n" + << "\t\treal_t xval1 = tiletype < 1 ? x : x - 1;\n" + << "\t\treal_t xval2 = tiletype < 1 ? x - 1 : x;\n" + << "\t\treal2 R = (real2)(pow(pow(fabs(xval1), " << n << ") + pow(fabs(y), " << n << "), " << onen << "), pow(pow(fabs(xval2), " << n << ") + pow(fabs(y - 1), " << n << "), " << onen << "));\n" + << "\t\treal_t r00 = fabs(R.x - 0.5) / " << rmax << ";\n" + << "\t\treal_t r11 = fabs(R.y - 0.5) / " << rmax << ";\n" + << "\t\tif (r00 > 1 && r11 > 1)\n" + << "\t\t{\n" + << "\t\t vOut.x = (x + floor(vIn.x)) * " << size << ";\n" + << "\t\t vOut.y = (y + floor(vIn.y)) * " << size << ";\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 void Precalc() override + { + m_N = Clamp(m_Exponent, T(0.001), T(2)); + T width = Clamp(m_ArcWidth, T(0.001), T(1)); + m_Seed2 = std::sqrt(m_Seed * T(1.5)) / Zeps(m_Seed * T(0.5)) * T(0.25); + m_Seed2Half = m_Seed2 * T(0.5); + m_OneN = 1 / Zeps(m_N); + m_Rmax = Zeps(T(0.5) * (std::pow(T(2.0), m_OneN) - 1) * width); + m_Scale = (std::cos(m_Rot) + std::sin(m_Rot)) / m_Weight; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Exponent, prefix + "Truchet_inv_exponent", 2, eParamType::REAL, 0, 2)); + m_Params.push_back(ParamWithName(&m_ArcWidth, prefix + "Truchet_inv_arc_width", T(0.5))); + m_Params.push_back(ParamWithName(&m_Rot, prefix + "Truchet_inv_rotation")); + m_Params.push_back(ParamWithName(&m_Size, prefix + "Truchet_inv_size", 1, eParamType::REAL, 0)); + m_Params.push_back(ParamWithName(&m_Seed, prefix + "Truchet_inv_seed", 1)); + m_Params.push_back(ParamWithName(true, &m_Rmax, prefix + "Truchet_inv_rmax"));//Precalc. + m_Params.push_back(ParamWithName(true, &m_N, prefix + "Truchet_inv_n")); + m_Params.push_back(ParamWithName(true, &m_OneN, prefix + "Truchet_inv_onen")); + m_Params.push_back(ParamWithName(true, &m_Seed2, prefix + "Truchet_inv_seed2")); + m_Params.push_back(ParamWithName(true, &m_Seed2Half, prefix + "Truchet_inv_seed2_half")); + m_Params.push_back(ParamWithName(true, &m_Scale, prefix + "Truchet_inv_scale")); + } + +private: + T m_Exponent; + T m_ArcWidth; + T m_Rot; + T m_Size; + T m_Seed; + T m_Rmax;//Precalc. + T m_N; + T m_OneN; + T m_Width; + T m_Seed2; + T m_Seed2Half; + T m_Scale; +}; + +/// +/// henon. +/// By tyrantwave. +/// +template +class HenonVariation : public ParametricVariation +{ +public: + HenonVariation(T weight = 1.0) : ParametricVariation("henon", eVariationId::VAR_HENON, weight) + { + Init(); + } + + PARVARCOPY(HenonVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = (1 - (m_A * SQR(helper.In.x)) + helper.In.y) * m_Weight; + helper.Out.y = m_B * helper.In.x * 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 a = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string b = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = (1 - (" << a << " * SQR(vIn.x)) + vIn.y) * " << weight << ";\n" + << "\t\tvOut.y = " << b << " * vIn.x * " << weight << ";\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "henon_a", T(0.5))); + m_Params.push_back(ParamWithName(&m_B, prefix + "henon_b", 1)); + } + +private: + T m_A; + T m_B; +}; + +/// +/// lozi. +/// By tyrantwave. +/// +template +class LoziVariation : public ParametricVariation +{ +public: + LoziVariation(T weight = 1.0) : ParametricVariation("lozi", eVariationId::VAR_LOZI, weight) + { + Init(); + } + + PARVARCOPY(LoziVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + helper.Out.x = (1 - (m_A * std::abs(helper.In.x)) + helper.In.y) * m_Weight; + helper.Out.y = m_B * helper.In.x * 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 a = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string b = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tvOut.x = (1 - (" << a << " * fabs(vIn.x)) + vIn.y) * " << weight << ";\n" + << "\t\tvOut.y = " << b << " * vIn.x * " << weight << ";\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_A, prefix + "lozi_a", T(0.5))); + m_Params.push_back(ParamWithName(&m_B, prefix + "lozi_b", 1)); + } + +private: + T m_A; + T m_B; +}; + +/// +/// point_symmetry. +/// By Fractalthew. +/// +template +class PointSymmetryVariation : public ParametricVariation +{ +public: + PointSymmetryVariation(T weight = 1.0) : ParametricVariation("point_symmetry", eVariationId::VAR_POINT_SYMMETRY, weight) + { + Init(); + } + + PARVARCOPY(PointSymmetryVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T angle = Floor(rand.Frand01() * m_Order) * m_TwoPiDivOrder; + T dx = (helper.In.x - m_X) * m_Weight; + T dy = (helper.In.y - m_Y) * m_Weight; + T cosa = std::cos(angle); + T sina = std::sin(angle); + helper.Out.x = m_X + dx * cosa + dy * sina; + helper.Out.y = m_Y + dy * cosa - dx * sina; + 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 x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string order = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string twopidivorder = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t angle = floor(MwcNext01(mwc) * " << order << ") * " << twopidivorder << ";\n" + << "\t\treal_t dx = (vIn.x - " << x << ") * " << weight << ";\n" + << "\t\treal_t dy = (vIn.y - " << y << ") * " << weight << ";\n" + << "\t\treal_t cosa = cos(angle);\n" + << "\t\treal_t sina = sin(angle);\n" + << "\t\tvOut.x = " << x << " + dx * cosa + dy * sina;\n" + << "\t\tvOut.y = " << y << " + dy * cosa - dx * sina;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_TwoPiDivOrder = M_2PI / Zeps(m_Order); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "point_symmetry_centre_x", T(0.15))); + m_Params.push_back(ParamWithName(&m_Y, prefix + "point_symmetry_centre_y", T(0.5))); + m_Params.push_back(ParamWithName(&m_Order, prefix + "point_symmetry_order", 3)); + m_Params.push_back(ParamWithName(true, &m_TwoPiDivOrder, prefix + "point_symmetry_two_pi_div_order"));//Precalc. + } + +private: + T m_X; + T m_Y; + T m_Order; + T m_TwoPiDivOrder;//Precalc. +}; + +/// +/// d_spherical. +/// By tatasz. +/// +template +class DSphericalVariation : public ParametricVariation +{ +public: + DSphericalVariation(T weight = 1.0) : ParametricVariation("d_spherical", eVariationId::VAR_D_SPHERICAL, weight, true) + { + Init(); + } + + PARVARCOPY(DSphericalVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + if (rand.Frand01() < m_SphericalWeight) + { + T r = m_Weight / Zeps(helper.m_PrecalcSumSquares); + helper.Out.x = helper.In.x * r; + helper.Out.y = helper.In.y * r; + } + else + { + helper.Out.x = helper.In.x * m_Weight; + helper.Out.y = helper.In.y * 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 sphericalweight = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\tif (MwcNext01(mwc) < " << sphericalweight << ")\n" + << "\t\t{\n" + << "\t\t real_t r = " << weight << " / Zeps(precalcSumSquares);\n" + << "\t\t vOut.x = vIn.x * r;\n" + << "\t\t vOut.y = vIn.y * r;\n" + << "\t\t}\n" + << "\t\telse\n" + << "\t\t{\n" + << "\t\t vOut.x = vIn.x * " << weight << ";\n" + << "\t\t vOut.y = vIn.y * " << weight << ";\n" + << "\t\t}\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual vector OpenCLGlobalFuncNames() const override + { + return vector { "Zeps" }; + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_SphericalWeight, prefix + "d_spherical_weight", T(0.5))); + } + +private: + T m_SphericalWeight; +}; + +/// +/// modulusx. +/// By tatasz. +/// +template +class ModulusxVariation : public ParametricVariation +{ +public: + ModulusxVariation(T weight = 1.0) : ParametricVariation("modulusx", eVariationId::VAR_MODULUSX, weight) + { + Init(); + } + + PARVARCOPY(ModulusxVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T fx = std::fmod(helper.In.x + m_X + m_Shift, 2 * m_X); + + if (fx >= 0) + helper.Out.x = m_Weight * (fx - m_X); + else + helper.Out.x = m_Weight * (fx + m_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 x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t fx = fmod(vIn.x + " << x << " + " << shift << ", 2 * " << x << ");\n" + << "\n" + << "\t\tif (fx >= 0)\n" + << "\t\t vOut.x = " << weight << " * (fx - " << x << ");\n" + << "\t\telse\n" + << "\t\t vOut.x = " << weight << " * (fx + " << x << ");\n" + << "\n" + << "\t\tvOut.y = " << weight << " * vIn.y;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "modulusx_x", 1)); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "modulusx_shift")); + } + +private: + T m_X; + T m_Shift; +}; + +/// +/// modulusy. +/// By tatasz. +/// +template +class ModulusyVariation : public ParametricVariation +{ +public: + ModulusyVariation(T weight = 1.0) : ParametricVariation("modulusy", eVariationId::VAR_MODULUSY, weight) + { + Init(); + } + + PARVARCOPY(ModulusyVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T fy = std::fmod(helper.In.y + m_Y + m_Shift, 2 * m_Y); + + if (fy >= 0) + helper.Out.y = m_Weight * (fy - m_Y); + else + helper.Out.y = m_Weight * (fy + m_Y); + + helper.Out.x = m_Weight * helper.In.x; + 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 y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string shift = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t fy = fmod(vIn.y + " << y << " + " << shift << ", 2 * " << y << ");\n" + << "\n" + << "\t\tif (fy >= 0)\n" + << "\t\t vOut.y = " << weight << " * (fy - " << y << ");\n" + << "\t\telse\n" + << "\t\t vOut.y = " << weight << " * (fy + " << y << ");\n" + << "\n" + << "\t\tvOut.x = " << weight << " * vIn.x;\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Y, prefix + "modulusy_y", 1)); + m_Params.push_back(ParamWithName(&m_Shift, prefix + "modulusy_shift")); + } + +private: + T m_Y; + T m_Shift; +}; + +/// +/// rotate. +/// By tatasz. +/// +template +class RotateVariation : public ParametricVariation +{ +public: + RotateVariation(T weight = 1.0) : ParametricVariation("rotate", eVariationId::VAR_ROTATE, weight) + { + Init(); + } + + PARVARCOPY(RotateVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sn = std::sin(m_AngleRad); + T cs = std::cos(m_AngleRad); + helper.Out.x = m_Weight * (helper.In.x * cs - helper.In.y * sn); + helper.Out.y = m_Weight * (helper.In.x * sn + helper.In.y * cs); + 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 angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string anglerad = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t sn = sin(" << anglerad << ");\n" + << "\t\treal_t cs = cos(" << anglerad << ");\n" + << "\t\tvOut.x = " << weight << " * (vIn.x * cs - vIn.y * sn);\n" + << "\t\tvOut.y = " << weight << " * (vIn.x * sn + vIn.y * cs);\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_AngleRad = m_Angle / 180 * T(M_PI); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "rotate_angle")); + m_Params.push_back(ParamWithName(true, &m_AngleRad, prefix + "rotate_angle_rad")); + } + +private: + T m_Angle; + T m_AngleRad;//Precalc. +}; + +/// +/// shift. +/// By tatasz. +/// +template +class ShiftVariation : public ParametricVariation +{ +public: + ShiftVariation(T weight = 1.0) : ParametricVariation("shift", eVariationId::VAR_SHIFT, weight) + { + Init(); + } + + PARVARCOPY(ShiftVariation) + + virtual void Func(IteratorHelper& helper, Point& outPoint, QTIsaac& rand) override + { + T sn = std::sin(m_AngleRad); + T cs = std::cos(m_AngleRad); + helper.Out.x = m_Weight * (helper.In.x + cs * m_X - sn * m_Y); + helper.Out.y = m_Weight * (helper.In.y - cs * m_Y - sn * m_X); + 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 x = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string y = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string angle = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + string anglerad = "parVars[" + ToUpper(m_Params[i++].Name()) + index; + ss << "\t{\n" + << "\t\treal_t sn = sin(" << anglerad << ");\n" + << "\t\treal_t cs = cos(" << anglerad << ");\n" + << "\t\tvOut.x = " << weight << " * (vIn.x + cs * " << x << " - sn * " << y << ");\n" + << "\t\tvOut.y = " << weight << " * (vIn.y - cs * " << y << " - sn * " << x << ");\n" + << "\t\tvOut.z = " << DefaultZCl() + << "\t}\n"; + return ss.str(); + } + + virtual void Precalc() override + { + m_AngleRad = m_Angle / 180 * T(M_PI); + } + +protected: + void Init() + { + string prefix = Prefix(); + m_Params.clear(); + m_Params.push_back(ParamWithName(&m_X, prefix + "shift_x")); + m_Params.push_back(ParamWithName(&m_Y, prefix + "shift_y")); + m_Params.push_back(ParamWithName(&m_Angle, prefix + "shift_angle")); + m_Params.push_back(ParamWithName(true, &m_AngleRad, prefix + "shift_angle_rad")); + } + +private: + T m_X; + T m_Y; + T m_Angle; + T m_AngleRad;//Precalc. +}; + MAKEPREPOSTPARVAR(Splits3D, splits3D, SPLITS3D) MAKEPREPOSTPARVAR(Waves2B, waves2b, WAVES2B) MAKEPREPOSTPARVAR(JacCn, jac_cn, JAC_CN) @@ -2280,16 +6624,55 @@ MAKEPREPOSTPARVAR(LogDB, log_db, LOG_DB) MAKEPREPOSTPARVAR(CircleSplit, circlesplit, CIRCLESPLIT) MAKEPREPOSTVAR(Cylinder2, cylinder2, CYLINDER2) MAKEPREPOSTPARVAR(TileLog, tile_log, TILE_LOG) +MAKEPREPOSTPARVAR(TileHlp, tile_hlp, TILE_HLP) MAKEPREPOSTPARVAR(TruchetFill, Truchet_fill, TRUCHET_FILL) MAKEPREPOSTPARVAR(Waves2Radial, waves2_radial, WAVES2_RADIAL) MAKEPREPOSTVAR(Panorama1, panorama1, PANORAMA1) MAKEPREPOSTVAR(Panorama2, panorama2, PANORAMA2) -//MAKEPREPOSTPARVAR(Arcsinh, arcsinh, ARCSINH) MAKEPREPOSTPARVAR(Helicoid, helicoid, HELICOID) MAKEPREPOSTPARVAR(Helix, helix, HELIX) MAKEPREPOSTPARVARASSIGN(Sphereblur, sphereblur, SPHEREBLUR, eVariationAssignType::ASSIGNTYPE_SUM) MAKEPREPOSTPARVAR(Cpow3, cpow3, CPOW3) MAKEPREPOSTPARVARASSIGN(Concentric, concentric, CONCENTRIC, eVariationAssignType::ASSIGNTYPE_SUM) MAKEPREPOSTPARVAR(Hypercrop, hypercrop, HYPERCROP) +MAKEPREPOSTPARVAR(Hypershift, hypershift, HYPERSHIFT) MAKEPREPOSTPARVAR(Hypershift2, hypershift2, HYPERSHIFT2) +MAKEPREPOSTVAR(Lens, lens, LENS) +MAKEPREPOSTPARVAR(Projective, projective, PROJECTIVE) +MAKEPREPOSTPARVAR(DepthBlur, depth_blur, DEPTH_BLUR) +MAKEPREPOSTPARVAR(DepthBlur2, depth_blur2, DEPTH_BLUR2) +MAKEPREPOSTPARVAR(DepthGaussian, depth_gaussian, DEPTH_GAUSSIAN) +MAKEPREPOSTPARVAR(DepthGaussian2, depth_gaussian2, DEPTH_GAUSSIAN2) +MAKEPREPOSTPARVAR(DepthNgon, depth_ngon, DEPTH_NGON) +MAKEPREPOSTPARVAR(DepthNgon2, depth_ngon2, DEPTH_NGON2) +MAKEPREPOSTPARVAR(DepthSine, depth_sine, DEPTH_SINE) +MAKEPREPOSTPARVAR(DepthSine2, depth_sine2, DEPTH_SINE2) +MAKEPREPOSTPARVAR(CothSpiral, coth_spiral, COTH_SPIRAL) +MAKEPREPOSTPARVAR(Dust, dust, DUST) +MAKEPREPOSTPARVAR(Asteria, asteria, ASTERIA) +MAKEPREPOSTPARVAR(Pulse, pulse, PULSE) +MAKEPREPOSTPARVAR(Excinis, excinis, EXCINIS) +MAKEPREPOSTPARVAR(Vibration, vibration, VIBRATION) +MAKEPREPOSTPARVAR(Vibration2, vibration2, VIBRATION2) +MAKEPREPOSTPARVAR(Arcsech, arcsech, ARCSECH) +MAKEPREPOSTPARVAR(Arcsech2, arcsech2, ARCSECH2) +MAKEPREPOSTPARVAR(Arcsinh, arcsinh, ARCSINH) +MAKEPREPOSTPARVAR(Arctanh, arctanh, ARCTANH) +MAKEPREPOSTPARVAR(HexTruchet, hex_truchet, HEX_TRUCHET) +MAKEPREPOSTPARVAR(HexRand, hex_rand, HEX_RAND) +MAKEPREPOSTPARVAR(Smartshape, smartshape, SMARTSHAPE) +MAKEPREPOSTPARVAR(Squares, squares, SQUARES) +MAKEPREPOSTPARVAR(Starblur2, starblur2, STARBLUR2) +MAKEPREPOSTPARVAR(UnicornGaloshen, unicorngaloshen, UNICORNGALOSHEN) +MAKEPREPOSTPARVAR(Dragonfire, dragonfire, DRAGONFIRE) +MAKEPREPOSTPARVAR(TruchetGlyph, Truchet_glyph, TRUCHET_GLYPH) +MAKEPREPOSTPARVAR(TruchetInv, Truchet_inv, TRUCHET_INV) +MAKEPREPOSTPARVAR(Henon, henon, HENON) +MAKEPREPOSTPARVAR(Lozi, lozi, LOZI) +MAKEPREPOSTPARVAR(PointSymmetry, point_symmetry, POINT_SYMMETRY) +MAKEPREPOSTPARVAR(DSpherical, d_spherical, D_SPHERICAL) +MAKEPREPOSTPARVAR(Modulusx, modulusx, MODULUSX) +MAKEPREPOSTPARVAR(Modulusy, modulusy, MODULUSY) +MAKEPREPOSTPARVAR(Rotate, rotate, ROTATE) +MAKEPREPOSTPARVAR(Shift, shift, SHIFT) } diff --git a/Source/Ember/XmlToEmber.cpp b/Source/Ember/XmlToEmber.cpp index 61059b6..f757720 100644 --- a/Source/Ember/XmlToEmber.cpp +++ b/Source/Ember/XmlToEmber.cpp @@ -171,13 +171,75 @@ XmlToEmber::XmlToEmber() { "density", "randCubes_density" }, { "radius", "concentric_radius" }, //{ "density", "concentric_density" },//Can't have two, which means you can never properly paste from Apophysis with both of these in one xform. - { "R_blur", "concentric_R_blur" }, - { "Z_blur", "concentric_Z_blur" }, + { "r_blur", "concentric_R_blur" }, + { "z_blur", "concentric_Z_blur" }, { "angle", "pixel_flow_angle" }, { "len", "pixel_flow_len" }, { "width", "pixel_flow_width" }, + { "radial_gaussian_angle", "radial_blur_angle" }, //{ "seed", "pixel_flow_seed" },//randCubes above already uses "seed", but it's just for randomness, so it shouldn't matter. - { "enable_dc", "pixel_flow_enable_dc" } + { "enable_dc", "pixel_flow_enable_dc" }, + { "pr_a", "projective_A" }, + { "pr_b", "projective_B" }, + { "pr_c", "projective_C" }, + { "pr_a1", "projective_A1" }, + { "pr_b1", "projective_B1" }, + { "pr_c1", "projective_C1" }, + { "pr_a2", "projective_A2" }, + { "pr_b2", "projective_B2" }, + { "pr_c2", "projective_C2" }, + { "db_power", "depth_blur_power" }, + { "db_range", "depth_blur_range" }, + { "db_blur", "depth_blur_blur" }, + { "db_radius", "depth_blur_radius" }, + { "osco2_separation", "oscilloscope2_separation" }, + { "osco2_frequencyx", "oscilloscope2_frequencyx" }, + { "osco2_frequencyy", "oscilloscope2_frequencyy" }, + { "osco2_amplitude", "oscilloscope2_amplitude" }, + { "osco2_perturbation", "oscilloscope2_perturbation" }, + { "osco2_damping", "oscilloscope2_damping" }, + { "power", "scry2_power" }, + { "faber_w_angle", "w_angle" }, + { "faber_w_hypergon", "w_hypergon" }, + { "faber_w_hypergon_n", "w_hypergon_n" }, + { "faber_w_hypergon_r", "w_hypergon_r" }, + { "faber_w_star", "w_star" }, + { "faber_w_star_n", "w_star_n" }, + { "faber_w_star_slope", "w_star_slope" }, + { "faber_w_lituus", "w_lituus" }, + { "faber_w_lituus_a", "w_lituus_a" }, + { "faber_w_super", "w_super" }, + { "faber_w_super_m", "w_super_m" }, + { "faber_w_super_n1", "w_super_n1" }, + { "faber_w_super_n2", "w_super_n2" }, + { "faber_w_super_n3", "w_super_n3" }, + { "faber_x_hypergon", "x_hypergon" }, + { "faber_x_hypergon_n", "x_hypergon_n" }, + { "faber_x_hypergon_r", "x_hypergon_r" }, + { "faber_x_star", "x_star" }, + { "faber_x_star_n", "x_star_n" }, + { "faber_x_star_slope", "x_star_slope" }, + { "faber_x_lituus", "x_lituus" }, + { "faber_x_lituus_a", "x_lituus_a" }, + { "faber_x_super", "x_super" }, + { "faber_x_super_m", "x_super_m" }, + { "faber_x_super_n1", "x_super_n1" }, + { "faber_x_super_n2", "x_super_n2" }, + { "faber_x_super_n3", "x_super_n3" }, + { "sshape_power", "smartshape_power" }, + { "sshape_roundstr", "smartshape_roundstr" }, + { "sshape_roundwidth", "smartshape_roundwidth" }, + { "sshape_distortion", "smartshape_distortion" }, + { "sshape_compensation", "smartshape_compensation" }, + { "mult_x", "unicorngaloshen_mult_x" }, + { "mult_y", "unicorngaloshen_mult_y" }, + { "sine", "unicorngaloshen_sine" }, + { "sin_x_amplitude", "unicorngaloshen_sin_x_amplitude" }, + { "sin_x_freq", "unicorngaloshen_sin_x_freq" }, + { "sin_y_amplitude", "unicorngaloshen_sin_y_amplitude" }, + { "sin_y_freq", "unicorngaloshen_sin_y_freq" }, + { "mode", "unicorngaloshen_mode" }, + { "d_spher_weight", "d_spherical_weight" } }; m_FlattenNames = { @@ -278,6 +340,47 @@ XmlToEmber::XmlToEmber() "post_scrop_static" }; m_BadVariationNames.push_back(make_pair(make_pair(string("post_scrop"), string("post_smartcrop")), badParams)); + badParams = + { + "radial_gaussian_angle" + }; + m_BadVariationNames.push_back(make_pair(make_pair(string("radial_gaussian"), string("radial_blur")), badParams)); + badParams = + { + "faber_w_angle", + "faber_w_hypergon", + "faber_w_hypergon_n", + "faber_w_hypergon_r", + "faber_w_star", + "faber_w_star_n", + "faber_w_star_slope", + "faber_w_lituus", + "faber_w_lituus_a", + "faber_w_super", + "faber_w_super_m", + "faber_w_super_n1", + "faber_w_super_n2", + "faber_w_super_n3" + }; + m_BadVariationNames.push_back(make_pair(make_pair(string("faber_w"), string("w")), badParams)); + badParams = + { + "faber_x_angle", + "faber_x_hypergon", + "faber_x_hypergon_n", + "faber_x_hypergon_r", + "faber_x_star", + "faber_x_star_n", + "faber_x_star_slope", + "faber_x_lituus", + "faber_x_lituus_a", + "faber_x_super", + "faber_x_super_m", + "faber_x_super_n1", + "faber_x_super_n2", + "faber_x_super_n3" + }; + m_BadVariationNames.push_back(make_pair(make_pair(string("faber_x"), string("x")), badParams)); //Note that splits3D can't be done here because its param names are also used by splits. badParams.clear(); m_BadVariationNames.push_back(make_pair(make_pair(string("pre_blur"), string("pre_gaussian_blur")), badParams));//No other special params for these. @@ -334,9 +437,21 @@ bool XmlToEmber::Parse(byte* buf, const char* filename, C, Alloc>& e //What is the root node of the document? rootnode = xmlDocGetRootElement(doc); + //Scan for nodes, starting with this node. //t.Tic(); - ScanForEmberNodes(rootnode, filename, embers, useDefaults); + if (string(filename).empty()) + { + ScanForEmberNodes(rootnode, filename, embers, useDefaults); + + if (embers.empty()) + ScanForChaosNodes(rootnode, filename, embers, useDefaults); + } + else if (EndsWith(filename, ".chaos")) + ScanForChaosNodes(rootnode, filename, embers, useDefaults); + else + ScanForEmberNodes(rootnode, filename, embers, useDefaults); + xmlFreeDoc(doc); emberSize = embers.size(); auto first = embers.begin(); @@ -391,7 +506,6 @@ bool XmlToEmber::Parse(byte* buf, const char* filename, C, Alloc>& e return true; } - /// /// Parse the specified file and place the results in the container of embers passed in. /// This will strip out ampersands because the Xml parser can't handle them. @@ -422,7 +536,6 @@ bool XmlToEmber::Parse(const char* filename, C, Alloc>& embers, bool else return false; } - /// /// Thin wrapper around converting the string to a numeric value and return a bool indicating success. /// See error report for errors. @@ -447,7 +560,6 @@ bool XmlToEmber::Aton(const char* str, valT& val) return b; } - /// /// Scan the file for ember nodes, and parse them out into the container of embers. /// @@ -513,6 +625,836 @@ void XmlToEmber::ScanForEmberNodes(xmlNode* curNode, const char* parentFile, } } +/// +/// Helper function to verify that the name field of a node +/// matches the one passed in. +/// +/// The node whose name field will be inspected +/// The name string to compare against +/// The name value if they matched, else nullptr. +static const char* CheckNameVal(xmlNode* node, const char* name) +{ + if (auto att = node->properties) + { + if (!Compare(att->name, "name")) + { + if (auto attStr = XC(xmlGetProp(node, att->name))) + { + if (!Compare(attStr, name)) + { + return CCX(attStr); + } + } + } + } + + return nullptr; +}; + +/// +/// Helper function to verify that the name of a node +/// matches the one passed in. +/// +/// The node whose name will be inspected +/// The name string to compare against +/// The node if they matched, else nullptr. +static xmlNode* CheckNodeName(xmlNode* node, const char* name) +{ + if (!Compare(node->name, name)) + return node; + + return nullptr; +}; + +/// +/// Helper function to get the value of the name field of a node. +/// +/// The node whose name field will be returned +/// The name of the field whose value will be compared against. Default: "name". +/// The value of the name field if found, else nullptr. +static const char* GetNameVal(xmlNode* node, const char* name = "name") +{ + if (auto att = node->properties) + { + if (!Compare(att->name, name ? name : "name")) + { + if (auto attStr = XC(xmlGetProp(node, att->name))) + { + return CCX(attStr); + } + } + } + + return nullptr; +}; + +/// +/// Helper function to get the child of a node based on the value of its name field. +/// +/// The node whose children will be searched +/// The name string to compare the child nodes' name fields against +/// The child node if found, else nullptr. +static xmlNode* GetChildNode(xmlNode* node, const char* name) +{ + for (auto childNode = node->children; childNode; childNode = childNode->next) + { + if (childNode->type == XML_ELEMENT_NODE) + { + if (CheckNameVal(childNode, name)) + { + return childNode; + } + } + } + + return nullptr; +}; + +/// +/// Helper function to get the child of a node based on the name of the child node. +/// +/// The node whose children will be searched +/// The name string to compare the child nodes' name against +/// The child node if found, else nullptr. +static xmlNode* GetChildNodeByNodeName(xmlNode* node, const char* name) +{ + for (auto childNode = node->children; childNode; childNode = childNode->next) + { + if (childNode->type == XML_ELEMENT_NODE) + { + if (auto node = CheckNodeName(childNode, name)) + { + return node; + } + } + } + + return nullptr; +}; + +/// +/// Helper function to parse the content of a field of a node and convert the string into a value of type T and store in the passed in val parameter. +/// +/// The node whose property fieldname will be parsed +/// The name of the node's field to parse +/// The name of the property within the field +/// The storage location to store the parse and converted value in +/// True if the field and property were successfully found and parsed, else false. +template +template +bool XmlToEmber::ParseAndAssignContent(xmlNode* node, const char* fieldname, const char* fieldnameval, valT& val) +{ + bool ret = false; + + if (auto att = node->properties) + { + if (!Compare(att->name, fieldname)) + { + if (auto attStr = XC(xmlGetProp(node, att->name))) + { + if (!fieldnameval || !Compare(attStr, fieldnameval)) + { + if (auto cont = xmlNodeGetContent(node)) + { + istringstream istr(CCX(cont)); + istr >> val; + ret = !istr.bad() && !istr.fail();//Means the Compare() was right, and the conversion succeeded. + } + } + } + } + } + + return ret; +} + +/// +/// Special overload for string. +/// +/// The node whose property fieldname will be parsed +/// The name of the node's field to parse +/// The name of the property within the field +/// The storage location to store the parse and converted string in +/// True if the field and property were successfully found and parsed, else false. +template +bool XmlToEmber::ParseAndAssignContent(xmlNode* node, const char* fieldname, const char* fieldnameval, std::string& val) +{ + bool ret = false; + + if (auto att = node->properties) + { + if (!Compare(att->name, fieldname)) + { + if (auto attStr = XC(xmlGetProp(node, att->name))) + { + if (!fieldnameval || !Compare(attStr, fieldnameval)) + { + if (auto cont = xmlNodeGetContent(node)) + { + val = CX(cont); + return true; + } + } + } + } + } + + return ret; +} + +/// +/// Scan the file for chaos nodes from a .chaos file from Chaotica, and parse them out into the container of embers. +/// +/// The current node to parse +/// The full path and filename +/// The newly constructed embers based on what was parsed +/// True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. +template +template class C> +void XmlToEmber::ScanForChaosNodes(xmlNode* curNode, const char* parentFile, C, Alloc>& embers, bool useDefaults) +{ + bool parseEmberSuccess; + xmlNodePtr thisNode = nullptr; + const char* loc = __FUNCTION__; + string parentFileString = string(parentFile); + + //Loop over this level of elements. + for (thisNode = curNode; thisNode; thisNode = thisNode->next) + { + //Check to see if this element is a element. + if (thisNode->type == XML_ELEMENT_NODE && !Compare(thisNode->name, "IFS")) + { + Ember currentEmber;//Place this inside here so its constructor is called each time. + + //Useful for parsing templates when not every member should be set. + if (!useDefaults) + currentEmber.Clear(false); + + if (auto embername = GetNameVal(thisNode, "name")) + currentEmber.m_Name = embername; + + auto childNode = thisNode; + bool ret = true; + parseEmberSuccess = ParseEmberElementFromChaos(childNode, currentEmber); + + if (!parseEmberSuccess) + { + AddToReport(string(loc) + " : Error parsing ember element"); + return; + } + + if (!currentEmber.XformCount())//Ensure there is always at least one xform or else the renderer will crash when trying to render. + { + Xform xform; + currentEmber.AddXform(xform); + } + + currentEmber.CacheXforms(); + currentEmber.m_MinRadDE = currentEmber.m_MaxRadDE = 0;//Chaotica doesn't support density filtering. + currentEmber.m_Index = embers.size(); + currentEmber.m_FuseCount = 30;//Chaotica doesn't publish its fuse count, but the images appear like they were using a fuse count of at least 30. + currentEmber.m_ParentFilename = parentFileString; + embers.push_back(currentEmber); + } + else + { + //Check all of the children of this element. + ScanForChaosNodes(thisNode->children, parentFile, embers, useDefaults); + } + } +} + +/// +/// Parse an ember element from a .chaos file. +/// +/// The current node to parse +/// The newly constructed ember based on what was parsed +/// True if there were no errors, else false. +template +bool XmlToEmber::ParseEmberElementFromChaos(xmlNode* emberNode, Ember& currentEmber) +{ + bool fromEmber = false, ret = true; + const char* loc = __FUNCTION__; + int soloXform = -1; + size_t count = 0, index = 0; + T sensorWidth = 2; + xmlAttrPtr att; + currentEmber.m_Palette.Clear();//Wipe out the current palette. + att = emberNode->properties;//The top level element is a ember element, read the attributes of it and store them. + auto variationsfunc = [&](const string & prefix, const char* nodename, xmlNode * node, Xform& xf, std::vector& alliterweights) + { + if (auto transformsChildNode = GetChildNode(node, nodename)) + { + for (auto variationNode = transformsChildNode->children; variationNode; variationNode = variationNode->next) + { + if (variationNode->type == XML_ELEMENT_NODE && (!Compare(variationNode->name, "flam3_variation") || !Compare(variationNode->name, "transform"))) + { + auto variationNameNode = GetChildNode(variationNode, "variation_name"); + + if (!variationNameNode) + variationNameNode = GetChildNode(variationNode, "type_name"); + + if (variationNameNode) + { + std::string varname; + + if (ParseAndAssignContent(variationNameNode, "name", "variation_name", varname)) {} + else ParseAndAssignContent(variationNameNode, "name", "type_name", varname); + + if (!varname.empty()) + { + T weight = 1; + string corrvarname; + + if (varname != "mobius")//Chaotica actually gets this right, but Apophysis doesn't. + corrvarname = GetCorrectedVariationName(m_BadVariationNames, varname); + else + corrvarname = varname; + + auto corrwprefix = !StartsWith(corrvarname, prefix) ? prefix + corrvarname : corrvarname; + + if (auto var = m_VariationList->GetVariation(corrwprefix)) + { + auto vc = std::unique_ptr>(var->Copy()); + vc->m_Weight = 1; + auto varCopy = vc.get(); + + if (xf.AddVariation(varCopy)) + { + vc.release(); + + if (auto paramsNode = GetChildNodeByNodeName(variationNode, "params")) + { + auto parvar = dynamic_cast*>(varCopy); + + for (auto paramsChildNode = paramsNode->children; paramsChildNode; paramsChildNode = paramsChildNode->next) + { + if (paramsChildNode->type == XML_ELEMENT_NODE) + { + if (auto paramname = GetNameVal(paramsChildNode)) + { + T val = 1; + + if (auto paramCurveChildNode = GetChildNodeByNodeName(paramsChildNode, "curve")) + { + if (auto paramCurveValuesChildNode = GetChildNode(paramCurveChildNode, "values")) + { + if (auto paramCurveValuesContentChildNode = GetChildNodeByNodeName(paramCurveValuesChildNode, "values")) + { + if (paramCurveValuesContentChildNode->children) + { + string valstr = CCX(paramCurveValuesContentChildNode->children->content); + istringstream istr(valstr); + istr >> val; + varCopy->m_Weight = val; + } + } + } + } + else if (ParseAndAssignContent(paramsChildNode, "name", paramname, val)) + { + auto paramstr = GetCorrectedParamName(m_BadParamNames, ToLower(paramname).c_str()); + + if (paramname == varname)//Compare non corrected names. + { + varCopy->m_Weight = val; + } + else if (parvar) + { + paramstr = prefix + paramstr; + parvar->SetParamVal(paramstr.c_str(), val); + //if (!parvar->SetParamVal(paramstr.c_str(), val)) + // AddToReport(string(loc) + " : Failed to set parametric variation parameter " + paramstr); + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + auto xformfunc = [&](xmlNode * node, Xform& xf, std::vector& alliterweights) -> bool + { + bool found = false; + + if (auto transformChildNode = GetChildNodeByNodeName(node, "flam3_transform")) + { + found = true; + auto itername = GetNameVal(node, "name"); + xf.m_Name = itername; + + if (auto affineChildNode = GetChildNode(transformChildNode, "Pre affine")) + { + std::string offsetstr; + double xangle = 0, xlength = 1, yangle = 90, ylength = 1, xoffset = 0, yoffset = 0; + + if (auto xangleChildNode = GetChildNode(affineChildNode, "x_axis_angle")) + if (auto paramCurveChildNode = GetChildNodeByNodeName(xangleChildNode, "curve")) + { + if (auto paramCurveValuesChildNode = GetChildNode(paramCurveChildNode, "values")) + { + if (auto paramCurveValuesContentChildNode = GetChildNodeByNodeName(paramCurveValuesChildNode, "values")) + { + if (paramCurveValuesContentChildNode->children) + { + string valstr = CCX(paramCurveValuesContentChildNode->children->content); + istringstream istr(valstr); + istr >> xangle; + } + } + } + } + else + ParseAndAssignContent(xangleChildNode, "name", "x_axis_angle", xangle); + + if (auto xlengthChildNode = GetChildNode(affineChildNode, "x_axis_length")) + if (ParseAndAssignContent(xlengthChildNode, "name", "x_axis_length", xlength)) {} + + if (auto yangleChildNode = GetChildNode(affineChildNode, "y_axis_angle")) + if (auto paramCurveChildNode = GetChildNodeByNodeName(yangleChildNode, "curve")) + { + if (auto paramCurveValuesChildNode = GetChildNode(paramCurveChildNode, "values")) + { + if (auto paramCurveValuesContentChildNode = GetChildNodeByNodeName(paramCurveValuesChildNode, "values")) + { + if (paramCurveValuesContentChildNode->children) + { + string valstr = CCX(paramCurveValuesContentChildNode->children->content); + istringstream istr(valstr); + istr >> yangle; + } + } + } + } + else + ParseAndAssignContent(yangleChildNode, "name", "y_axis_angle", yangle); + + if (auto ylengthChildNode = GetChildNode(affineChildNode, "y_axis_length")) + if (ParseAndAssignContent(ylengthChildNode, "name", "y_axis_length", ylength)) {} + + if (auto offsetChildNode = GetChildNode(affineChildNode, "offset")) + if (ParseAndAssignContent(offsetChildNode, "name", "offset", offsetstr)) + { + istringstream istr(offsetstr); + istr >> xoffset >> yoffset; + } + + T x1 = T(xlength * std::cos(xangle * DEG_2_RAD)); + T y1 = T(xlength * std::sin(xangle * DEG_2_RAD)); + T x2 = T(ylength * std::cos(yangle * DEG_2_RAD)); + T y2 = T(ylength * std::sin(yangle * DEG_2_RAD)); + T o1 = T(xoffset); + T o2 = T(yoffset); + xf.m_Affine.A(x1); + xf.m_Affine.B(x2); + xf.m_Affine.C(o1); + xf.m_Affine.D(y1); + xf.m_Affine.E(y2); + xf.m_Affine.F(o2); + } + + if (auto affineChildNode = GetChildNode(transformChildNode, "Post affine")) + { + std::string offsetstr; + double xangle = 0, xlength = 1, yangle = 90, ylength = 1, xoffset = 0, yoffset = 0; + + if (auto xangleChildNode = GetChildNode(affineChildNode, "x_axis_angle")) + if (!ParseAndAssignContent(xangleChildNode, "name", "x_axis_angle", xangle)) + if (auto paramCurveChildNode = GetChildNodeByNodeName(affineChildNode, "curve")) + { + if (auto paramCurveValuesChildNode = GetChildNode(paramCurveChildNode, "values")) + { + if (auto paramCurveValuesContentChildNode = GetChildNodeByNodeName(paramCurveValuesChildNode, "values")) + { + if (paramCurveValuesContentChildNode->children) + { + string valstr = CCX(paramCurveValuesContentChildNode->children->content); + istringstream istr(valstr); + istr >> xangle; + } + } + } + } + + if (auto xlengthChildNode = GetChildNode(affineChildNode, "x_axis_length")) + if (ParseAndAssignContent(xlengthChildNode, "name", "x_axis_length", xlength)) {} + + if (auto yangleChildNode = GetChildNode(affineChildNode, "y_axis_angle")) + if (auto paramCurveChildNode = GetChildNodeByNodeName(yangleChildNode, "curve")) + { + if (auto paramCurveValuesChildNode = GetChildNode(paramCurveChildNode, "values")) + { + if (auto paramCurveValuesContentChildNode = GetChildNodeByNodeName(paramCurveValuesChildNode, "values")) + { + if (paramCurveValuesContentChildNode->children) + { + string valstr = CCX(paramCurveValuesContentChildNode->children->content); + istringstream istr(valstr); + istr >> yangle; + } + } + } + } + else + ParseAndAssignContent(yangleChildNode, "name", "y_axis_angle", yangle); + + if (auto ylengthChildNode = GetChildNode(affineChildNode, "y_axis_length")) + if (ParseAndAssignContent(ylengthChildNode, "name", "y_axis_length", ylength)) {} + + if (auto offsetChildNode = GetChildNode(affineChildNode, "offset")) + if (ParseAndAssignContent(offsetChildNode, "name", "offset", offsetstr)) + { + istringstream istr(offsetstr); + istr >> xoffset >> yoffset; + } + + T x1 = T(xlength * std::cos(xangle * DEG_2_RAD)); + T y1 = T(xlength * std::sin(xangle * DEG_2_RAD)); + T x2 = T(ylength * std::cos(yangle * DEG_2_RAD)); + T y2 = T(ylength * std::sin(yangle * DEG_2_RAD)); + T o1 = T(xoffset); + T o2 = T(yoffset); + xf.m_Post.A(x1); + xf.m_Post.B(x2); + xf.m_Post.C(o1); + xf.m_Post.D(y1); + xf.m_Post.E(y2); + xf.m_Post.F(o2); + } + + string prefix; + variationsfunc(prefix, "transforms", transformChildNode, xf, alliterweights); + prefix = "pre_"; + variationsfunc(prefix, "pre_transforms", transformChildNode, xf, alliterweights); + prefix = "post_"; + variationsfunc(prefix, "post_transforms", transformChildNode, xf, alliterweights); + } + + if (auto shaderChildNode = GetChildNodeByNodeName(node, "flam3_shader")) + { + T paletteIndex = 0, colorSpeed = 0.5, opacity = 1; + + if (auto paletteIndexChildNode = GetChildNode(shaderChildNode, "palette_index")) + if (ParseAndAssignContent(paletteIndexChildNode, "name", "palette_index", paletteIndex)) { xf.m_ColorX = xf.m_ColorY = paletteIndex; } + + if (auto colrSpeedChildNode = GetChildNode(shaderChildNode, "blend_speed")) + if (ParseAndAssignContent(colrSpeedChildNode, "name", "blend_speed", colorSpeed)) { xf.m_ColorSpeed = colorSpeed; } + + if (auto opacityChildNode = GetChildNode(shaderChildNode, "opacity")) + if (ParseAndAssignContent(opacityChildNode, "name", "opacity", opacity)) { xf.m_Opacity = opacity; } + } + + + if (auto weightsChildNode = GetChildNodeByNodeName(node, "weights_selector")) + { + T weight = 0; + std::string periterweights; + + if (auto baseWeightChildNode = GetChildNode(weightsChildNode, "base_weight")) + if (ParseAndAssignContent(baseWeightChildNode, "name", "base_weight", weight)) { xf.m_Weight = weight; } + + if (auto periterweightsChildNode = GetChildNode(weightsChildNode, "per_iterator_weights")) + { + for (auto iterweightChildNode = periterweightsChildNode->children; iterweightChildNode; iterweightChildNode = iterweightChildNode->next) + { + if (iterweightChildNode->type == XML_ELEMENT_NODE) + { + std::string iterweight; + + if (ParseAndAssignContent(iterweightChildNode, "name", nullptr, iterweight))//All of these subsequent nodes are for iter specific weights (xaos). + periterweights += iterweight + ' '; + } + } + } + + if (!periterweights.empty()) + alliterweights.push_back(Trim(periterweights)); + } + + return found; + }; + + if (att == nullptr) + { + AddToReport(string(loc) + " : element has no attributes"); + return false; + } + + auto childNode = emberNode->children; + + for (; childNode; childNode = childNode->next) + { + if (childNode->type == XML_ELEMENT_NODE) + { + if (!Compare(childNode->name, "imaging")) + { + std::string bgstr; + + for (auto imgChildNode = childNode->children; imgChildNode; imgChildNode = imgChildNode->next) + { + if (imgChildNode->type == XML_ELEMENT_NODE) + { + if (ParseAndAssignContent(imgChildNode, "name", "image_width", currentEmber.m_FinalRasW)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "image_height", currentEmber.m_FinalRasH)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "image_aa_level", currentEmber.m_Supersample)) { ClampRef(currentEmber.m_Supersample, size_t(1), size_t(4)); } + else if (ParseAndAssignContent(imgChildNode, "name", "image_quality", currentEmber.m_Quality)) { currentEmber.m_Quality = std::max(currentEmber.m_Quality, T(1)); } + else if (ParseAndAssignContent(imgChildNode, "name", "brightness", currentEmber.m_Brightness)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "flam3_gamma", currentEmber.m_Gamma)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "flam3_vibrancy", currentEmber.m_Vibrancy)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "flam3_highlight_power", currentEmber.m_HighlightPower)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "flam3_gamma_linear_threshold", currentEmber.m_GammaThresh)) {} + else if (ParseAndAssignContent(imgChildNode, "name", "background_colour", bgstr)) + { + istringstream is(bgstr); + is >> currentEmber.m_Background[0]//[0..1] + >> currentEmber.m_Background[1] + >> currentEmber.m_Background[2] + >> currentEmber.m_Background[3]; + } + } + } + + if (auto curvesnode = GetChildNodeByNodeName(childNode, "curves")) + { + T val = 0; + auto curvenodesfunc = [&](xmlNode * node, int index) + { + float x, y; + string knots, values; + vector vals; + + if (auto knotsnode = GetChildNode(node, "knots")) + if (auto knotvalsnode = GetChildNodeByNodeName(knotsnode, "values")) + if (knotvalsnode->children) + knots = CCX(knotvalsnode->children->content); + + if (auto valuesnode = GetChildNode(node, "values")) + if (auto valvalsnode = GetChildNodeByNodeName(valuesnode, "values")) + if (valvalsnode->children) + values = CCX(valvalsnode->children->content); + + istringstream kistr(knots); + istringstream vistr(values); + + while (kistr >> x && vistr >> y) + vals.push_back({ x, y }); + + if (index < currentEmber.m_Curves.m_Points.size() && vals.size() >= 2) + { + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + currentEmber.m_Curves.m_Points[index].clear(); + currentEmber.m_Curves.m_Points[index].push_back(vals[0]); + currentEmber.m_Curves.m_Points[index].push_back(vals[1]); + + for (size_t i = 2; i < vals.size(); i++) + if (vals[i] != currentEmber.m_Curves.m_Points[index][i - 1])//An attempt to remove duplicates. + currentEmber.m_Curves.m_Points[index].push_back(vals[i]); + } + }; + + if (auto overallnode = GetChildNode(curvesnode, "overall")) + curvenodesfunc(overallnode, 0); + + if (auto rednode = GetChildNode(curvesnode, "0")) + curvenodesfunc(rednode, 1); + + if (auto greennode = GetChildNode(curvesnode, "5")) + curvenodesfunc(greennode, 2); + + if (auto bluenode = GetChildNode(curvesnode, "10")) + curvenodesfunc(bluenode, 3); + } + } + else if (!Compare(childNode->name, "camera")) + { + std::string pos; + + for (auto camChildNode = childNode->children; camChildNode; camChildNode = camChildNode->next) + { + if (camChildNode->type == XML_ELEMENT_NODE) + { + if (ParseAndAssignContent(camChildNode, "name", "rotate", currentEmber.m_Rotate)) { currentEmber.m_Rotate = NormalizeDeg180(currentEmber.m_Rotate); } + else if (ParseAndAssignContent(camChildNode, "name", "sensor_width", sensorWidth)) { } + else if (ParseAndAssignContent(camChildNode, "name", "pos", pos)) + { + istringstream istr(pos); + istr >> currentEmber.m_CenterX >> currentEmber.m_CenterY; + currentEmber.m_RotCenterY = currentEmber.m_CenterY; + } + else + { + Xform finalXform; + std::vector alliterweights; + + if (xformfunc(childNode, finalXform, alliterweights))//Iter weights are unused in the final xform. + { + finalXform.m_Weight = 0; + finalXform.m_Animate = 0;//Do not animate final by default. + finalXform.m_ColorX = finalXform.m_ColorY = 0;//Chaotica does not support any kind of coloring for final xforms, opacity remains 1 though. + finalXform.m_ColorSpeed = 0; + currentEmber.SetFinalXform(finalXform); + } + } + } + } + } + else if (!Compare(childNode->name, "colouring")) + { + if (auto palettenode = GetChildNode(childNode, "flam3_palette")) + { + if (auto palettevalsnode = GetChildNodeByNodeName(palettenode, "values")) + { + int i = 0; + float r = 0, g = 0, b = 0; + auto colors = CCX(palettevalsnode->children->content); + istringstream istr(colors); + + while (istr >> r && istr >> g && istr >> b && i < COLORMAP_LENGTH) + { + currentEmber.m_Palette.m_Entries[i][0] = r; + currentEmber.m_Palette.m_Entries[i][1] = g; + currentEmber.m_Palette.m_Entries[i][2] = b; + currentEmber.m_Palette.m_Entries[i][3] = 1; + i++; + } + } + } + else + { + std::string huek, huev, satk, satv, valk, valv; + + if (auto huenode = GetChildNode(childNode, "hue")) + { + if (auto knotsnode = GetChildNode(huenode, "knots")) + if (auto knotvalsnode = GetChildNodeByNodeName(knotsnode, "values")) + if (knotvalsnode->children) + huek = CCX(knotvalsnode->children->content); + + if (auto valuesnode = GetChildNode(huenode, "values")) + if (auto valvalsnode = GetChildNodeByNodeName(valuesnode, "values")) + if (valvalsnode->children) + huev = CCX(valvalsnode->children->content); + } + + if (auto satnode = GetChildNode(childNode, "saturation")) + { + if (auto knotsnode = GetChildNode(satnode, "knots")) + if (auto knotvalsnode = GetChildNodeByNodeName(knotsnode, "values")) + if (knotvalsnode->children) + satk = CCX(knotvalsnode->children->content); + + if (auto valuesnode = GetChildNode(satnode, "values")) + if (auto valvalsnode = GetChildNodeByNodeName(valuesnode, "values")) + if (valvalsnode->children) + satv = CCX(valvalsnode->children->content); + } + + if (auto valnode = GetChildNode(childNode, "value")) + { + if (auto knotsnode = GetChildNode(valnode, "knots")) + if (auto knotvalsnode = GetChildNodeByNodeName(knotsnode, "values")) + if (knotvalsnode->children) + valk = CCX(knotvalsnode->children->content); + + if (auto valuesnode = GetChildNode(valnode, "values")) + if (auto valvalsnode = GetChildNodeByNodeName(valuesnode, "values")) + if (valvalsnode->children) + valv = CCX(valvalsnode->children->content); + } + + auto parsehsvfunc = [&](const std::string & knots, const std::string & vals, vector& vec) + { + istringstream kstr(knots); + istringstream vstr(vals); + float k, v; + vec.clear(); + vec.reserve(8); + + while (kstr >> k && vstr >> v) + { + vec.push_back({k, v}); + } + }; + vector hvec, svec, vvec; + parsehsvfunc(huek, huev, hvec); + parsehsvfunc(satk, satv, svec); + parsehsvfunc(valk, valv, vvec); + + if (huek.size() >= 2 && huev.size() >= 2 && + satk.size() >= 2 && satv.size() >= 2 && + valk.size() >= 2 && valv.size() >= 2) + { + Spline hspline(hvec); + Spline sspline(svec); + Spline vspline(vvec); + auto stepsize = (1.0f / (COLORMAP_LENGTH - 1)); + + for (auto palindex = 0; palindex < COLORMAP_LENGTH; palindex++) + { + float t = palindex * stepsize; + auto h = hspline.Interpolate(t); + auto s = sspline.Interpolate(t); + auto v = vspline.Interpolate(t); + float r, g, b; + Palette::HsvToRgb(float(h * 2 * M_PI), s, v, r, g, b); + currentEmber.m_Palette.m_Entries[palindex][0] = r; + currentEmber.m_Palette.m_Entries[palindex][1] = g; + currentEmber.m_Palette.m_Entries[palindex][2] = b; + currentEmber.m_Palette.m_Entries[palindex][3] = 1; + } + } + } + } + else if (!Compare(childNode->name, "node")) + { + if (auto nodename = CheckNameVal(childNode, "iterators")) + { + std::vector alliterweights; + + for (auto iterChildNode = childNode->children; iterChildNode; iterChildNode = iterChildNode->next) + { + if (iterChildNode->type == XML_ELEMENT_NODE && !Compare(iterChildNode->name, "iterator")) + { + Xform xf; + xformfunc(iterChildNode, xf, alliterweights); + currentEmber.AddXform(xf); + } + } + + if (!alliterweights.empty()) + { + size_t i = 0; + + while (auto xform = currentEmber.GetXform(i)) + { + if (i < alliterweights.size() && !alliterweights[i].empty()) + { + istringstream istr(alliterweights[i]); + T xaoselement = 0; + size_t j = 0; + + while (istr >> xaoselement) + xform->SetXaos(j++, xaoselement); + } + + i++; + } + } + } + } + } + } + + currentEmber.m_OrigPixPerUnit = currentEmber.m_PixelsPerUnit = currentEmber.m_FinalRasW / Zeps(sensorWidth); + return currentEmber.XformCount() > 0; +} + /// /// Parse an ember element. /// @@ -557,6 +1499,7 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber else if (ParseAndAssign(curAtt->name, attStr, "brightness", currentEmber.m_Brightness, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "gamma", currentEmber.m_Gamma, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "highlight_power", currentEmber.m_HighlightPower, ret)) {} + else if (ParseAndAssign(curAtt->name, attStr, "logscale_k2", currentEmber.m_K2, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "vibrancy", currentEmber.m_Vibrancy, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "estimator_radius", currentEmber.m_MaxRadDE, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "estimator_minimum", currentEmber.m_MinRadDE, ret)) {} @@ -575,6 +1518,7 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber else if (ParseAndAssign(curAtt->name, attStr, "temporal_samples", currentEmber.m_TemporalSamples, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "sub_batch_size", currentEmber.m_SubBatchSize, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "fuse", currentEmber.m_FuseCount, ret)) {} + else if (ParseAndAssign(curAtt->name, attStr, "rand_range", currentEmber.m_RandPointRange, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "soloxform", soloXform, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "new_linear", newLinear, ret)) {} //Parse more complicated reads that have multiple possible values. @@ -661,18 +1605,125 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber } else if (!Compare(curAtt->name, "curves")) { + auto splits = Split(attStr, ' '); istringstream is(attStr); for (i = 0; i < 4; i++) { + vector vals; + for (glm::length_t j = 0; j < 4; j++) { - is >> currentEmber.m_Curves.m_Points[i][j].x - >> currentEmber.m_Curves.m_Points[i][j].y - >> currentEmber.m_Curves.m_Weights[i][j]; + T w, x = 0, y = 0; + is >> x + >> y + >> w;//Weights appear to be unused. + vals.push_back({ Clamp(x, 0, 1), Clamp(y, 0, 1) }); } + + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + + if (vals[0] == v2F(0) && vals[1] == v2F(0)) + vals[1] = v2F(0.25); + + if (vals[2] == v2F(1) && vals[3] == v2F(1)) + vals[3] = v2F(0.75); + + currentEmber.m_Curves.m_Points[i] = vals; } } + else if (!Compare(curAtt->name, "overall_curve")) + { + cout << "found overall curves\n"; + auto splits = Split(attStr, ' '); + istringstream is(attStr); + vector vals; + T x = 0, y = 0; + + while (is >> x && is >> y)//No weights when using this format. + { + vals.push_back({ Clamp(x, 0, 1), Clamp(y, 0, 1) }); + } + + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + + if (vals[0] == v2F(0) && vals[1] == v2F(0)) + vals[1] = v2F(0.25); + + if (vals[2] == v2F(1) && vals[3] == v2F(1)) + vals[3] = v2F(0.75); + + currentEmber.m_Curves.m_Points[0] = vals; + } + else if (!Compare(curAtt->name, "red_curve")) + { + cout << "found red curves\n"; + auto splits = Split(attStr, ' '); + istringstream is(attStr); + vector vals; + T x = 0, y = 0; + + while (is >> x && is >> y)//No weights when using this format. + { + vals.push_back({ Clamp(x, 0, 1), Clamp(y, 0, 1) }); + } + + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + + if (vals[0] == v2F(0) && vals[1] == v2F(0)) + vals[1] = v2F(0.25); + + if (vals[2] == v2F(1) && vals[3] == v2F(1)) + vals[3] = v2F(0.75); + + currentEmber.m_Curves.m_Points[1] = vals; + } + else if (!Compare(curAtt->name, "green_curve")) + { + cout << "found green curves\n"; + auto splits = Split(attStr, ' '); + istringstream is(attStr); + vector vals; + T x = 0, y = 0; + + while (is >> x && is >> y)//No weights when using this format. + { + vals.push_back({ Clamp(x, 0, 1), Clamp(y, 0, 1) }); + } + + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + + if (vals[0] == v2F(0) && vals[1] == v2F(0)) + vals[1] = v2F(0.25); + + if (vals[2] == v2F(1) && vals[3] == v2F(1)) + vals[3] = v2F(0.75); + + currentEmber.m_Curves.m_Points[2] = vals; + } + else if (!Compare(curAtt->name, "blue_curve")) + { + cout << "found blue curves\n"; + auto splits = Split(attStr, ' '); + istringstream is(attStr); + vector vals; + T x = 0, y = 0; + + while (is >> x && is >> y)//No weights when using this format. + { + vals.push_back({ Clamp(x, 0, 1), Clamp(y, 0, 1) }); + } + + std::sort(vals.begin(), vals.end(), [&](auto & lhs, auto & rhs) { return lhs.x < rhs.x; }); + + if (vals[0] == v2F(0) && vals[1] == v2F(0)) + vals[1] = v2F(0.25); + + if (vals[2] == v2F(1) && vals[3] == v2F(1)) + vals[3] = v2F(0.75); + + currentEmber.m_Curves.m_Points[3] = vals; + } xmlFree(attStr); } @@ -1004,6 +2055,10 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_GAMMA_THRESH, motion); else if (!Compare(curAtt->name, "highlight_power")) ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_HIGHLIGHT_POWER, motion); + else if (!Compare(curAtt->name, "logscale_k2")) + ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_K2, motion); + else if (!Compare(curAtt->name, "rand_range")) + ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_RAND_RANGE, motion); else if (!Compare(curAtt->name, "vibrancy")) ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_VIBRANCY, motion); else if (!Compare(curAtt->name, "background")) @@ -1055,7 +2110,6 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber return true; } - /// /// Parse a floating point value from an xml attribute and add the value to a EmberMotion object /// @@ -1083,7 +2137,6 @@ bool XmlToEmber::AttToEmberMotionFloat(xmlAttrPtr att, const char* attStr, eE return r; } - /// /// Parse an xform element. /// @@ -1294,7 +2347,7 @@ bool XmlToEmber::ParseXform(xmlNode* childNode, Xform& xform, bool motion, for (curAtt = attPtr; curAtt; curAtt = curAtt->next) { //Only correct names if it came from an outside source. Names originating from this library are always considered correct. - string s = fromEmber ? string(CCX(curAtt->name)) : GetCorrectedParamName(m_BadParamNames, CCX(curAtt->name)); + string s = fromEmber ? string(CCX(curAtt->name)) : GetCorrectedParamName(m_BadParamNames, ToLower(CCX(curAtt->name)).c_str()); const char* name = s.c_str(); if (parVar->ContainsParam(name)) @@ -1304,9 +2357,8 @@ bool XmlToEmber::ParseXform(xmlNode* childNode, Xform& xform, bool motion, if (Aton(attStr, val)) { - parVar->SetParamVal(name, val); - //if (!parVar->SetParamVal(name, val)) - // AddToReport(string(loc) + " : Failed to set parametric variation parameter " + name); + if (!parVar->SetParamVal(name, val)) + AddToReport(string(loc) + " : Failed to set parametric variation parameter " + name); } else { @@ -1321,7 +2373,6 @@ bool XmlToEmber::ParseXform(xmlNode* childNode, Xform& xform, bool motion, return true; } - /// /// Some Apophysis plugins use an inconsistent naming scheme for the parametric variation variables. /// This function identifies and converts them to Ember's consistent naming convention. @@ -1339,7 +2390,6 @@ string XmlToEmber::GetCorrectedParamName(const unordered_map& else return name; } - /// /// Some Apophysis plugins use an inconsistent naming scheme for variation names. /// This function identifies and converts them to Ember's consistent naming convention. @@ -1347,7 +2397,7 @@ string XmlToEmber::GetCorrectedParamName(const unordered_map& /// by examining the rest of the xform for the existence of parameter names. /// /// The vector of corrected names to search -/// The current Xml node to check +/// The xml attribute pointer whose name member is the name of the variation to check /// The corrected name if one was found, else the passed in name. template string XmlToEmber::GetCorrectedVariationName(vector, vector>>& vec, xmlAttrPtr att) @@ -1373,6 +2423,25 @@ string XmlToEmber::GetCorrectedVariationName(vector return string(CCX(att->name)); } +/// +/// Some Apophysis plugins use an inconsistent naming scheme for variation names. +/// This function identifies and converts them to Ember's consistent naming convention. +/// It uses some additional intelligence to ensure the variation is the expected one, +/// by examining the rest of the xform for the existence of parameter names. +/// This overload is specifically for use when parsing .chaos files from Chaotica. +/// +/// The vector of corrected names to search +/// The name of the variation to check +/// The corrected name if one was found, else the passed in name. +template +string XmlToEmber::GetCorrectedVariationName(vector, vector>>& vec, const string& varname) +{ + for (auto& v : vec) + if (!_stricmp(v.first.first.c_str(), varname.c_str()))//Do case insensitive here. + return v.first.second; + + return varname; +} /// /// Determine if an Xml node contains a given tag. @@ -1394,7 +2463,6 @@ bool XmlToEmber::XmlContainsTag(xmlAttrPtr att, const char* name) return false; } - /// /// Parse hexadecimal colors. /// This can read RGB and RGBA, however only RGB will be stored. @@ -1434,7 +2502,6 @@ bool XmlToEmber::ParseHexColors(const char* colstr, Ember& ember, size_t n return length >= 256; } - /// /// Wrapper to parse a numeric Xml string value and convert it. /// @@ -1459,11 +2526,9 @@ bool XmlToEmber::ParseAndAssign(const xmlChar* name, const char* attStr, cons return ret; } - //This class had to be implemented in a cpp file because the compiler was breaking. //So the explicit instantiation must be declared here rather than in Ember.cpp where //all of the other classes are done. - #define EXPORT_XML_TO_EMBER(T) \ template EMBER_API class XmlToEmber; \ template EMBER_API bool XmlToEmber::Parse(byte*, const char*, list>&, bool); \ @@ -1471,9 +2536,7 @@ bool XmlToEmber::ParseAndAssign(const xmlChar* name, const char* attStr, cons template EMBER_API bool XmlToEmber::Parse(const char*, list>&, bool); \ template EMBER_API bool XmlToEmber::Parse(const char*, vector>&, bool); \ template EMBER_API bool XmlToEmber::Aton(const char*, size_t&); - EXPORT_XML_TO_EMBER(float) - #ifdef DO_DOUBLE EXPORT_XML_TO_EMBER(double) #endif diff --git a/Source/Ember/XmlToEmber.h b/Source/Ember/XmlToEmber.h index d64fdb2..2b72afd 100644 --- a/Source/Ember/XmlToEmber.h +++ b/Source/Ember/XmlToEmber.h @@ -4,6 +4,7 @@ #include "PaletteList.h" #include "VariationList.h" #include "Ember.h" +#include "Spline.h" #ifdef __APPLE__ #include @@ -33,7 +34,7 @@ private: }; /// -/// 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 class C> void ScanForEmberNodes(xmlNode* curNode, const char* parentFile, C, Alloc>& embers, bool useDefaults); + template class C> + void ScanForChaosNodes(xmlNode* curNode, const char* parentFile, C, Alloc>& embers, bool useDefaults); bool ParseEmberElement(xmlNode* emberNode, Ember& currentEmber); + bool ParseEmberElementFromChaos(xmlNode* emberNode, Ember& currentEmber); bool AttToEmberMotionFloat(xmlAttrPtr att, const char* attStr, eEmberMotionParam param, EmberMotion& motion); bool ParseXform(xmlNode* childNode, Xform& xform, bool motion, bool fromEmber); static string GetCorrectedParamName(const unordered_map& names, const char* name); static string GetCorrectedVariationName(vector, vector>>& vec, xmlAttrPtr att); + static string GetCorrectedVariationName(vector, vector>>& vec, const string& varname); static bool XmlContainsTag(xmlAttrPtr att, const char* name); bool ParseHexColors(const char* colstr, Ember& ember, size_t numColors, intmax_t chan); template bool ParseAndAssign(const xmlChar* name, const char* attStr, const char* str, valT& val, bool& b); + template + 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 m_BadParamNames; diff --git a/Source/EmberAnimate/EmberAnimate.cpp b/Source/EmberAnimate/EmberAnimate.cpp index 2e7de49..95acfd9 100644 --- a/Source/EmberAnimate/EmberAnimate.cpp +++ b/Source/EmberAnimate/EmberAnimate.cpp @@ -62,8 +62,11 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt) } for (auto& renderer : renderers) - if (auto rendererCL = dynamic_cast(renderer.get())) + if (auto rendererCL = dynamic_cast*>(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()); diff --git a/Source/EmberCL/DEOpenCLKernelCreator.cpp b/Source/EmberCL/DEOpenCLKernelCreator.cpp index 292bc21..f59bce1 100644 --- a/Source/EmberCL/DEOpenCLKernelCreator.cpp +++ b/Source/EmberCL/DEOpenCLKernelCreator.cpp @@ -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) { diff --git a/Source/EmberCL/EmberCLFunctions.h b/Source/EmberCL/EmberCLFunctions.h index 3c1ba6b..011561e 100644 --- a/Source/EmberCL/EmberCLFunctions.h +++ b/Source/EmberCL/EmberCLFunctions.h @@ -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" diff --git a/Source/EmberCL/EmberCLStructs.h b/Source/EmberCL/EmberCLStructs.h index b6a9257..5872c24 100644 --- a/Source/EmberCL/EmberCLStructs.h +++ b/Source/EmberCL/EmberCLStructs.h @@ -196,6 +196,7 @@ static const char* XformCLStructString = template 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" diff --git a/Source/EmberCL/FunctionMapper.cpp b/Source/EmberCL/FunctionMapper.cpp index 9a62a76..8653d3a 100644 --- a/Source/EmberCL/FunctionMapper.cpp +++ b/Source/EmberCL/FunctionMapper.cpp @@ -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" diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp index 9377e1a..d811e5b 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.cpp +++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp @@ -289,11 +289,11 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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::CreateIterKernelString(const Ember& 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 diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index 2a90744..0c34e62 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -34,6 +34,7 @@ RendererCL::RendererCL(const vector>& 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::Init(const vector>& 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::WriteRandomPoints(size_t device) } #endif +/// +/// Set the percentage of a sub batch that should be executed in each thread per kernel call. +/// +/// The percentage as a value from 0.01 to 1.0 +template +void RendererCL::SubBatchPercentPerThread(float f) +{ + m_SubBatchPercentPerThread = Clamp(f, 0.01f, 1.0f); +} + +/// +/// Get the percentage of a sub batch that should be executed in each thread per kernel call. +/// +/// The percentage as a value from 0.01 to 1.0 +template +float RendererCL::SubBatchPercentPerThread() const +{ + return m_SubBatchPercentPerThread; +} + /// /// Get the kernel string for the last built iter program. /// @@ -660,7 +681,7 @@ bool RendererCL::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::RunIter(size_t iterCount, size_t temporalSample, si vector threadVec; std::atomic atomLaunchesRan; std::atomic 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::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::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::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 void RendererCL::ConvertEmber(Ember& ember, EmberCL& emberCL, vector>& xformsCL) { memset(&emberCL, 0, sizeof(EmberCL));//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++) { diff --git a/Source/EmberCL/RendererCL.h b/Source/EmberCL/RendererCL.h index 6d76625..1a8c3bc 100644 --- a/Source/EmberCL/RendererCL.h +++ b/Source/EmberCL/RendererCL.h @@ -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 diff --git a/Source/EmberCommon/EmberOptions.h b/Source/EmberCommon/EmberOptions.h index 885bb56..0ef7f00 100644 --- a/Source/EmberCommon/EmberOptions.h +++ b/Source/EmberCommon/EmberOptions.h @@ -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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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= 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; diff --git a/Source/EmberRender/EmberRender.cpp b/Source/EmberRender/EmberRender.cpp index 8768318..5233de7 100644 --- a/Source/EmberRender/EmberRender.cpp +++ b/Source/EmberRender/EmberRender.cpp @@ -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(renderer.get())) + if (auto rendererCL = dynamic_cast*>(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(fullpath, opt.PalettePath()))//For any modern flames, the palette isn't used. This is for legacy purposes and should be removed. return false; diff --git a/Source/EmberTester/EmberTester.cpp b/Source/EmberTester/EmberTester.cpp index b632d10..a73b3f2 100644 --- a/Source/EmberTester/EmberTester.cpp +++ b/Source/EmberTester/EmberTester.cpp @@ -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; } diff --git a/Source/Fractorium/AboutDialog.ui b/Source/Fractorium/AboutDialog.ui index 5d472c2..30cb444 100644 --- a/Source/Fractorium/AboutDialog.ui +++ b/Source/Fractorium/AboutDialog.ui @@ -58,7 +58,7 @@ QFrame::NoFrame - <html><head/><body><p align="center">Fractorium 1.0.0.14</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><a href="http://fractorium.com"><span style=" text-decoration: underline; color:#0000ff;">fractorium.com</span></a></p></body></html> + <html><head/><body><p align="center">Fractorium 1.0.0.15</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><a href="http://fractorium.com"><span style=" text-decoration: underline; color:#0000ff;">fractorium.com</span></a></p></body></html> Qt::RichText @@ -104,7 +104,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.875pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.1pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Developers:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Lead: </span><a href="http://www.fractorium.com"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Matt Feemster</span></a><span style=" font-size:10pt;"><br />Contributors: </span><a href="http://blog.highlyillogical.org/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Simon Detheridge</span></a><span style=" font-size:10pt;">, </span><a href="https://www.deviantart.com/triptychaos"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Michel Mastriani.</span></a></p> <p style="-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;"><br /></p> @@ -114,8 +114,8 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Code and theory questions: </span><a href="https://github.com/scottdraves/flam3"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Erik Reckase</span></a><span style=" font-size:10pt;">, </span><a href="http://fractron9000.sourceforge.net/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Mike Thiesen</span></a><span style=" font-size:10pt;">, </span><a href="https://github.com/scottdraves/flam3"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Scott Draves</span></a><span style=" font-size:10pt;">, </span><a href="https://github.com/stevenrobertson/cuburn"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Steve Robertson</span></a><span style=" font-size:10pt;">, </span><a href="http://www.chaoticafractals.com/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Thomas Ludwig</span></a><span style=" font-size:10pt;">.</span></p> <p style="-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;"><br /></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Code Copied:</span></p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/scottdraves/flam3"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">flam3</span></a><span style=" font-size:10pt;">: Scott Draves, Erik Reckase (GPL v2)<br /></span><a href="http://github.com/stevenrobertson/cuburn"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">cuburn</span></a><span style=" font-size:10pt;">: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)<br /></span><a href="http://fractron9000.sourceforge.net"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Fractron 9000</span></a><span style=" font-size:10pt;">: Mike Thiesen (GPL)<br /></span><a href="http://sourceforge.net/projects/apophysis7x"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Apophysis</span></a><span style=" font-size:10pt;">: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)<br /></span><a href="http://jwildfire.org/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">JWildfire</span></a><span style=" font-size:10pt;">: Andreas Maschke (LGPL)<br />gradLib: Stian Broen<br />ColorPickerWidget: Etienne Moutot<br />Numerous Apophysis plugin developers (GPL)</span></p> -<p style="-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/scottdraves/flam3"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">flam3</span></a><span style=" font-size:10pt;">: Scott Draves, Erik Reckase (GPL v2)<br /></span><a href="http://github.com/stevenrobertson/cuburn"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">cuburn</span></a><span style=" font-size:10pt;">: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)<br /></span><a href="http://fractron9000.sourceforge.net"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Fractron 9000</span></a><span style=" font-size:10pt;">: Mike Thiesen (GPL)<br /></span><a href="http://sourceforge.net/projects/apophysis7x"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Apophysis</span></a><span style=" font-size:10pt;">: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)<br /></span><a href="http://jwildfire.org/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">JWildfire</span></a><span style=" font-size:10pt;">: Andreas Maschke (LGPL)<br />gradLib: Stian Broen<br />ColorPickerWidget: Etienne Moutot<br />Numerous Apophysis plugin developers (GPL)<br />Chaotica variations</span></p> +<p style="-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;"><br /></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Libraries Linked:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.qt.io/developers/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Qt</span></a><span style=" font-size:10pt;">: Digia Plc (GPL v3, LGPL v2)<br /></span><a href="http://g-truc.net"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">glm</span></a><span style=" font-size:10pt;">: Christophe Riccio (MIT License)<br /></span><a href="http://threadingbuildingblocks.org"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Threading Building Blocks</span></a><span style=" font-size:10pt;">: Intel Corporation (GPLv2)<br /></span><a href="http://libjpeg.sourceforge.net"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">libjpeg</span></a><span style=" font-size:10pt;">: Independent JPEG Group (Free Software License)<br /></span><a href="http://libpng.org"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">libpng</span></a><span style=" font-size:10pt;">: Glenn Randers-Pehrson et al (Libpng License)<br /></span><a href="http://xmlsoft.org"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">libxml2</span></a><span style=" font-size:10pt;">: Daniel Veillard (MIT License)<br /></span><a href="http://zlib.net"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">zlib</span></a><span style=" font-size:10pt;">: Jean-loup Gailly, Mark Adler (Zlib License)<br /></span><a href="http://burtleburtle.net/bob/cplus/isaac.hpp"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">QTIsaac</span></a><span style=" font-size:10pt;">: Robert J. Jenkins, Quinn Tyler Jackson (Public Domain)<br /></span><a href="http://cas.ee.ic.ac.uk/people/dt10/research/rngs-gpu-mwc64x.html"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">MWC64X Random Number Generator</span></a><span style=" font-size:10pt;">: David Thomas (Public Domain)<br /></span><a href="https://github.com/brofield/simpleopt"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">SimpleOpt</span></a><span style=" font-size:10pt;">: Brodie Thiesfield (MIT License)</span></p> <p style="-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;"><br /></p> diff --git a/Source/Fractorium/CurvesGraphicsView.cpp b/Source/Fractorium/CurvesGraphicsView.cpp index c923f8b..48796a6 100644 --- a/Source/Fractorium/CurvesGraphicsView.cpp +++ b/Source/Fractorium/CurvesGraphicsView.cpp @@ -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 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. /// /// The curve whose point value will be retrieved, 0-3. -/// The point within the curve whose value will be retrieved, 1-2. +/// The point within the curve whose value will be retrieved, 0-3. /// The position of the point. X,Y will each be within 0-1. 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. /// /// The curve whose point will be set, 0-3. -/// The point within the curve which will be set, 1-2 +/// The point within the curve which will be set, 0-3 /// The position to set the point to. X,Y will each be within 0-1. 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& 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& 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); +} + /// /// 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 /// The curve to set 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 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 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 vals; + vals.reserve(points.size()); + + for (auto& p : points) + vals.push_back({ p->pos().x(), p->pos().y() }); + Spline 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; + } } } } \ No newline at end of file diff --git a/Source/Fractorium/CurvesGraphicsView.h b/Source/Fractorium/CurvesGraphicsView.h index 9f4f6e3..de2cdb4 100644 --- a/Source/Fractorium/CurvesGraphicsView.h +++ b/Source/Fractorium/CurvesGraphicsView.h @@ -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& 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 m_AllP; + std::vector m_RedP; + std::vector m_GrnP; + std::vector m_BluP; QGraphicsLineItem* m_XLine; QGraphicsLineItem* m_YLine; - QPen* m_Pens[4]; + std::array m_Pens; QGraphicsScene m_Scene; QRectF m_OriginalRect; - std::pair m_Points[4]; + std::array, 4> m_Points; }; + /// /// 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: /// /// 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. /// /// Action is only taken if this value equals ItemPositionChange /// The new position. This will be clamped to the scene rect. diff --git a/Source/Fractorium/DoubleSpinBox.cpp b/Source/Fractorium/DoubleSpinBox.cpp index 578a717..86df80f 100644 --- a/Source/Fractorium/DoubleSpinBox.cpp +++ b/Source/Fractorium/DoubleSpinBox.cpp @@ -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(e)) { + e->accept(); return true; } } @@ -378,6 +387,31 @@ SpecialDoubleSpinBox::SpecialDoubleSpinBox(QWidget* p, int h, double step) { } +/// +/// 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. +/// +/// The event +void SpecialDoubleSpinBox::enterEvent(QEvent* e) +{ + this->setContextMenuPolicy(Qt::ActionsContextMenu); + DoubleSpinBox::enterEvent(e); +} + +/// +/// 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. +/// +/// The event +void SpecialDoubleSpinBox::leaveEvent(QEvent* e) +{ + this->setContextMenuPolicy(Qt::PreventContextMenu); + DoubleSpinBox::leaveEvent(e); +} + /// /// Event filter for taking special action on right click events. /// diff --git a/Source/Fractorium/DoubleSpinBox.h b/Source/Fractorium/DoubleSpinBox.h index b2d1151..80b6123 100644 --- a/Source/Fractorium/DoubleSpinBox.h +++ b/Source/Fractorium/DoubleSpinBox.h @@ -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; }; diff --git a/Source/Fractorium/FinalRenderDialog.cpp b/Source/Fractorium/FinalRenderDialog.cpp index 9d149e2..12bc489 100644 --- a/Source/Fractorium/FinalRenderDialog.cpp +++ b/Source/Fractorium/FinalRenderDialog.cpp @@ -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(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(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(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(ui.FinalRenderSizeTable, this, row, -1, m_WidthSpin, spinHeight, 10, std::numeric_limits::max(), 10, SIGNAL(valueChanged(int)), SLOT(OnWidthChanged(int)), true, 1920, 1920, 1920); + SetupSpinner(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(ui.FinalRenderSizeTable, this, row, -1, m_HeightSpin, spinHeight, 10, std::numeric_limits::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(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 1000, 1000, 1000); SetupSpinner (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(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) /// Ignored 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); + } +} + +/// +/// 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. +/// +/// Ignored +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()) {} } /// @@ -477,11 +527,38 @@ void FractoriumFinalRenderDialog::OnWidthScaleChanged(double d) /// Ignored 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); + } +} + +/// +/// 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. +/// +/// Ignored +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()) {} } /// @@ -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. /// /// The state of the radio button -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 ed; EmberFile 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(); diff --git a/Source/Fractorium/FinalRenderDialog.h b/Source/Fractorium/FinalRenderDialog.h index bd8b205..5c09661 100644 --- a/Source/Fractorium/FinalRenderDialog.h +++ b/Source/Fractorium/FinalRenderDialog.h @@ -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; diff --git a/Source/Fractorium/FinalRenderDialog.ui b/Source/Fractorium/FinalRenderDialog.ui index 6114a78..c5b2cad 100644 --- a/Source/Fractorium/FinalRenderDialog.ui +++ b/Source/Fractorium/FinalRenderDialog.ui @@ -418,11 +418,57 @@ + + + + + 0 + 0 + + + + + 220 + 0 + + + + + 300 + 16777215 + + + + <html><head/><body><p>The percentage of a sub batch to execute on each thread per kernel call when using OpenCL. Default: 0.025 (256 iters).</p><p>Increase this number for slightly faster render times.</p><p>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.</p></body></html> + + + OpenCL Sub Batch Percent Per Thread + + + 3 + + + 0.010000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.250000000000000 + + + Qt::Horizontal + + QSizePolicy::Preferred + 40 @@ -692,7 +738,7 @@ - + 0 @@ -890,6 +936,9 @@ Strips + + <html><head/><body><p>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.</p><p>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.</p><p>Use this sparingly since the number of iterations required are scaled by the value in this field.</p></body></html> + @@ -913,6 +962,9 @@ Iterations + + The total number of iterations that will be done to complete a single image + @@ -1203,13 +1255,6 @@ - - - TableWidget - QTableWidget -
TableWidget.h
-
-
FinalRenderEarlyClipCheckBox FinalRenderDoublePrecisionCheckBox @@ -1221,13 +1266,18 @@ FinalRenderDoSequenceCheckBox FinalRenderPng16BitCheckBox FinalRenderCurrentSpin - FinalRenderStopButton - FinalRenderStartButton + FinalRenderThreadCountSpin + FinalRenderThreadPriorityComboBox + FinalRenderOpenCLSubBatchPctSpin + FinalRenderApplyToAllCheckBox + FinalRenderKeepAspectCheckBox + FinalRenderScaleNoneRadioButton FinalRenderScaleWidthRadioButton FinalRenderScaleHeightRadioButton - FinalRenderScaleNoneRadioButton - FinalRenderKeepAspectCheckBox FinalRenderTextOutput + FinalRenderStartButton + FinalRenderPauseButton + FinalRenderStopButton FinalRenderCloseButton diff --git a/Source/Fractorium/FinalRenderEmberController.cpp b/Source/Fractorium/FinalRenderEmberController.cpp index ff6bd26..7f3e595 100644 --- a/Source/Fractorium/FinalRenderEmberController.cpp +++ b/Source/Fractorium/FinalRenderEmberController.cpp @@ -368,6 +368,7 @@ template void FinalRenderEmberController::CopyEmberFile(EmberFil /// Resets the rendering process. ///
/// The index in the file from which to retrieve the ember +/// Unused template void FinalRenderEmberController::SetEmber(size_t index, bool verbatim) { @@ -420,6 +421,7 @@ bool FinalRenderEmberController::Render() ///
/// The type of render to create /// The platform,device index pairs of the devices to use +/// Unused /// True if shared with OpenGL, else false. Always false in this case. /// True if nothing went wrong, else false. template @@ -477,7 +479,7 @@ bool FinalRenderEmberController::CreateRenderer(eRendererType renderType, con /// Note this is only called on the primary renderer. ///
/// The ember currently being rendered -/// An extra dummy parameter +/// An extra dummy parameter, unused. /// The progress fraction from 0-100 /// The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation. /// The estimated milliseconds to completion of the current stage @@ -527,17 +529,19 @@ void FinalRenderEmberController::SyncCurrentToGui() ///
/// Width override to use instead of scaling the original width /// Height override to use instead of scaling the original height +/// Whether to apply width adjustment to the ember +/// Whether to apply height adjustment to the ember template -void FinalRenderEmberController::SyncGuiToEmbers(size_t widthOverride, size_t heightOverride) +void FinalRenderEmberController::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::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*>(m_Renderer.get())) + rendererCL->SubBatchPercentPerThread(m_FinalRenderDialog->OpenCLSubBatchPct()); } else if (!m_Renderers.empty()) { @@ -566,6 +573,9 @@ bool FinalRenderEmberController::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*>(m_Renderers[i].get())) + rendererCL->SubBatchPercentPerThread(m_FinalRenderDialog->OpenCLSubBatchPct()); } } else @@ -583,19 +593,27 @@ bool FinalRenderEmberController::SyncGuiToRenderer() ///
/// Whether to update the scale values /// Whether to update the size suffix text +/// Whether to apply width value to the width scale spinner +/// Whether to apply height value to the height scale spinner template -void FinalRenderEmberController::SyncCurrentToSizeSpinners(bool scale, bool size) +void FinalRenderEmberController::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(m_Ember->m_FinalRasW) + ")"); - m_FinalRenderDialog->m_HeightScaleSpin->setSuffix(" (" + ToString(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::HandleFinishedProgress() ///
/// The ember currently being rendered /// The renderer stats -/// The timer which was started at the beginning of the render +/// The timer which was started at the beginning of the render template void FinalRenderEmberController::RenderComplete(Ember& ember, const EmberStats& stats, Timing& renderTimer) { @@ -845,6 +863,7 @@ void FinalRenderEmberController::RenderComplete(Ember& 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::RenderComplete(Ember& ember, const EmberS /// The ember whose values will be modified /// Width override to use instead of scaling the original width /// Height override to use instead of scaling the original height +/// Whether to use the computed/overridden width value, or use the existing value in the ember +/// Whether to use the computed/overridden height value, or use the existing value in the ember template -void FinalRenderEmberController::SyncGuiToEmber(Ember& ember, size_t widthOverride, size_t heightOverride) +void FinalRenderEmberController::SyncGuiToEmber(Ember& ember, size_t widthOverride, size_t heightOverride, bool dowidth, bool doheight) { size_t w; size_t h; @@ -879,8 +900,8 @@ void FinalRenderEmberController::SyncGuiToEmber(Ember& ember, size_t width h = ember.m_OrigFinalRasH * hScale; } - w = std::max(w, 10); - h = std::max(h, 10); + w = dowidth ? std::max(w, 10) : ember.m_FinalRasW; + h = doheight ? std::max(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::CheckMemory(const tuple 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 SyncAndComputeMemory() { return tuple(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 SyncAndComputeMemory() override; virtual double OriginalAspect() override { return double(m_Ember->m_OrigFinalRasW) / m_Ember->m_OrigFinalRasH; } @@ -141,7 +142,7 @@ protected: void SaveCurrentRender(Ember& ember, const EmberImageComments& comments, vector& pixels, size_t width, size_t height, bool png16Bit, bool transparency); void RenderComplete(Ember& ember); void RenderComplete(Ember& ember, const EmberStats& stats, Timing& renderTimer); - void SyncGuiToEmber(Ember& ember, size_t widthOverride = 0, size_t heightOverride = 0); + void SyncGuiToEmber(Ember& ember, size_t widthOverride = 0, size_t heightOverride = 0, bool dowidth = true, bool doheight = true); bool SyncGuiToRenderer(); void SetProgressComplete(int val); diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp index c2f7b7f..a8cda88 100644 --- a/Source/Fractorium/Fractorium.cpp +++ b/Source/Fractorium/Fractorium.cpp @@ -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(); } +/// +/// Return the URLs used to determine the icons that show up in the location bar in all file/folder dialogs. +/// +QList Fractorium::Urls() +{ + return m_Urls; +} + /// /// Set the coordinate text in the status bar. /// @@ -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); diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h index 1f808b4..5de0a75 100644 --- a/Source/Fractorium/Fractorium.h +++ b/Source/Fractorium/Fractorium.h @@ -99,6 +99,7 @@ public: bool DrawXforms(); bool DrawImage(); bool DrawGrid(); + QList 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 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 m_PreviewVec; shared_ptr m_Info; unique_ptr m_Controller; diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui index 05bdc6d..2c872a3 100644 --- a/Source/Fractorium/Fractorium.ui +++ b/Source/Fractorium/Fractorium.ui @@ -80,8 +80,8 @@ 0 0 - 1259 - 980 + 1305 + 985 @@ -132,7 +132,7 @@ - 0 + 2 5 @@ -173,7 +173,7 @@ 0 0 230 - 933 + 936 @@ -193,7 +193,7 @@ 0 - + 0 @@ -203,13 +203,13 @@ 0 - 88 + 112 16777215 - 88 + 112 @@ -300,6 +300,11 @@ Fuse Count + + + Rand Range + + Quality @@ -347,6 +352,19 @@ + + Rand Range + + + <html><head/><body><p>The positive and negative range in the x and y dimensions used for random point selection at the beginning of each sub batch.</p><p>This range is also used when reseting the point trajectory due to a bad point being calculated.</p><p>Larger numbers will usually have the effect of making the image look more spread out.</p></body></html> + + + + + 1 + + + Quality @@ -354,12 +372,12 @@ <html><head/><body><p>The number of iterations per pixel in the final output image. Keep this value low for a responsive UI while editing, then increase it when using the Final Render Dialog.</p><p>If this value is increased while a render is in progress, the updated value will be used once it finishes and it will pick up rendering where it left off.</p><p>This allows successive quality increases without restarting the render.</p><p>One way to increase the quality in this manner is to just type another digit in the field.</p><p>Decreases in quality will restart the process from the beginning.</p></body></html> - + 0 - + Supersample @@ -367,7 +385,7 @@ <html><head/><body><p>The value to multiply the dimensions of the histogram and density filter buffer by to help eliminate jagged lines.</p><p>During interactive editing, it should always be 1, and should only be increased when preparing for a final render. Values greater than one will significantly impact performance and will increase memory usage.</p><p>While a value of 2 offers some visual improvement, values greater than 2 usually don’t offer noticeable improvement.</p></body></html> - + 0 @@ -404,13 +422,13 @@ 0 - 22 + 19 16777215 - 22 + 19 @@ -485,13 +503,13 @@ 0 - 22 + 19 16777215 - 22 + 19 @@ -566,13 +584,13 @@ 0 - 22 + 19 16777215 - 22 + 19 @@ -672,13 +690,13 @@ 0 - 22 + 19 16777215 - 22 + 19 @@ -705,6 +723,9 @@ true + + false + 15 @@ -772,7 +793,7 @@ - + 0 @@ -782,13 +803,13 @@ 0 - 264 + 266 16777215 - 264 + 266 @@ -1104,7 +1125,7 @@ - + 0 @@ -1114,13 +1135,13 @@ 0 - 110 + 112 16777215 - 110 + 112 @@ -1303,8 +1324,8 @@ - - + + 0 @@ -1314,13 +1335,253 @@ 0 - 154 + 19 16777215 - 154 + 19 + + + + Qt::NoFocus + + + QFrame::Panel + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + false + + + 1 + + + true + + + 15 + + + false + + + 15 + + + true + + + false + + + 15 + + + false + + + 15 + + + + Animation + + + AlignCenter + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 0 + 90 + + + + + 16777215 + 90 + + + + Qt::NoFocus + + + QFrame::Panel + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + false + + + 2 + + + false + + + 145 + + + false + + + 35 + + + true + + + false + + + 22 + + + false + + + 22 + + + + Interpolation + + + + + Affine Interpolation + + + + + Temporal Filter Width + + + + + Temporal Filter Type + + + + + Field + + + + + + Interpolation + + + <html><head/><body><p>The method to use when interpolating flames during sequence generation. Linear uses basic linear interpolation when generating all of the steps between key frames, while Smooth uses log interpolation.</p><p>The first and last key frames in a sequence must use Linear.</p></body></html> + + + + + Affine Interpolation + + + <html><head/><body><p>The method to use when interpolating affine transforms during sequence generation.</p><p>Linear uses basic linear interpolation for each coefficient of affines, while Log converts to polar coordinates before interpolating.</p></body></html> + + + + + Temporal Filter Width + + + <html><head/><body><p>The width of the temporal filter used during animation.</p><p>When computing the temporal samples to render, boundary frames must be computed to know what to blend between. By default this is just the sequence frames before and after the one currently being rendered.</p><p>However, the time bounds of what’s being blended can be less than that, or even greater which means it will be blended across several sequence steps.</p><p>In practice, this will almost always have its default value of 1.</p></body></html> + + + + + Temporal Filter Type + + + <html><head/><body><p>The type of the temporal filter used during animation.</p><p>This is similar to the spatial filter in that the type can be chosen to produce different effects.</p></body></html> + + + + + + + + + 0 + 0 + + + + + 0 + 178 + + + + + 16777215 + 178 @@ -1435,6 +1696,11 @@ Highlight Power + + + K2 + + Background @@ -1522,10 +1788,10 @@ - Background + K2 - <html><head/><body><p>The background color of the image. Click the ... button to display a color chooser dialog.</p></body></html> + <html><head/><body><p>A multiplier used to compute the value which each RGB color component in the histogram is multipled by when converting histogram cells into viewable pixels. This functions as a secondary brightness adjustment.</p><p>The value is computed in the following manner: (brightness * log(1.0 + hitcount * k2)) / hitcount.</p><p>Leave as zero to use the default value.</p></body></html> @@ -1535,10 +1801,10 @@ - Palette Mode + Background - <html><head/><body><p>The mode used for palette indexing when accumulating to the histogram. Changing this rarely makes any noticeable difference in the final image.</p><p>Step: If the specified palette index is a fraction, round down to the nearest integer.</p><p>Linear: Blend the specified index with the one after it.</p></body></html> + <html><head/><body><p>The background color of the image. Click the ... button to display a color chooser dialog.</p></body></html> @@ -1546,257 +1812,17 @@ 0 - - - - - - - 0 - 0 - - - - - 0 - 22 - - - - - 16777215 - 22 - - - - Qt::NoFocus - - - QFrame::Panel - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - false - - - false - - - 1 - - - true - - - 15 - - - false - - - 15 - - - true - - - false - - - 15 - - - false - - - 15 - - + - Animation - - - AlignCenter - - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 5 - - - - - - - - - 0 - 0 - - - - - 0 - 110 - - - - - 16777215 - 110 - - - - Qt::NoFocus - - - QFrame::Panel - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QAbstractItemView::NoEditTriggers - - - false - - - QAbstractItemView::NoSelection - - - QAbstractItemView::ScrollPerPixel - - - QAbstractItemView::ScrollPerPixel - - - false - - - 2 - - - false - - - 145 - - - false - - - 35 - - - true - - - false - - - 22 - - - false - - - 22 - - - - Interpolation - - - - - Affine Interpolation - - - - - Temporal Samples - - - - - Temporal Filter Width - - - - - Temporal Filter Type - - - - - Field - - - - - - Interpolation + Palette Mode - <html><head/><body><p>The method to use when interpolating flames during sequence generation. Linear uses basic linear interpolation when generating all of the steps between key frames, while Smooth uses log interpolation.</p><p>The first and last key frames in a sequence must use Linear.</p></body></html> + <html><head/><body><p>The mode used for palette indexing when accumulating to the histogram. Changing this rarely makes any noticeable difference in the final image.</p><p>Step: If the specified palette index is a fraction, round down to the nearest integer.</p><p>Linear: Blend the specified index with the one after it.</p></body></html> - + - Affine Interpolation - - - <html><head/><body><p>The method to use when interpolating affine transforms during sequence generation.</p><p>Linear uses basic linear interpolation for each coefficient of affines, while Log converts to polar coordinates before interpolating.</p></body></html> - - - - - Temporal Samples - - - <html><head/><body><p>The number of temporal samples used to blend between sequence frames during animation.</p><p>Even after a sequence has been generated that produces a number of steps between key frames, when performing the animation render, each of those sequence steps is blended between the surrounding sequence steps.</p><p>Temporal samples is the number of blended steps between each sequence step that get combined into a single output frame.</p><p>Values between 100 and 1000 are often used. Higher values will produce more of a motion blurring effect when animating.</p><p>When rendering a single image, this value will always be set to 1 by Fractorium right before rendering regardless of the value set in the UI.</p></body></html> - - - - - Temporal Filter Width - - - <html><head/><body><p>The width of the temporal filter used during animation.</p><p>When computing the temporal samples to render, boundary frames must be computed to know what to blend between. By default this is just the sequence frames before and after the one currently being rendered.</p><p>However, the time bounds of what’s being blended can be less than that, or even greater which means it will be blended across several sequence steps.</p><p>In practice, this will almost always have its default value of 1.</p></body></html> - - - - - Temporal Filter Type - - - <html><head/><body><p>The type of the temporal filter used during animation.</p><p>This is similar to the spatial filter in that the type can be chosen to produce different effects.</p></body></html> + 0 @@ -1811,16 +1837,22 @@ - 530 + 550 0 240 881 + + + 0 + 0 + + 240 - 200 + 392 @@ -1836,7 +1868,13 @@ Xaos - + + + 0 + 0 + + + 4 @@ -1853,10 +1891,7 @@ 4 - - - 4 - + QLayout::SetDefaultConstraint @@ -1866,7 +1901,29 @@ 0 - + + 4 + + + + + Qt::StrongFocus + + + QAbstractSpinBox::NoButtons + + + Xforms + + + 1 + + + 9999999 + + + + Set all xaos values in all xforms to 1 @@ -1885,33 +1942,7 @@ - - - - <html><head/><body><p>Set all xaos values to a random decimal value between 0 and 3, inclusive.</p></body></html> - - - Random Xaos - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - + Add N new xforms with all to/from xaos values to each other set to 1, and the remainder set to 0 @@ -1922,21 +1953,22 @@ - - - Qt::StrongFocus + + + <html><head/><body><p>Set all xaos values to a random decimal value between 0 and 3, inclusive.</p></body></html> - - QAbstractSpinBox::NoButtons + + Random Xaos - - Xforms + + + + + + Switch the row and column positions of the values in the xaos table - - 1 - - - 9999999 + + Transpose Xaos @@ -2028,7 +2060,7 @@ false - false + true false @@ -2056,14 +2088,208 @@ + + + + + 0 + 0 + + + + + 0 + 150 + + + + + 16777215 + 16777215 + + + + + true + + + + Qt::NoFocus + + + + + + QFrame::Panel + + + QFrame::Plain + + + 1 + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustToContents + + + false + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + false + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + true + + + Qt::SolidLine + + + false + + + true + + + 1 + + + 0 + + + true + + + false + + + 35 + + + 35 + + + false + + + true + + + false + + + 22 + + + 22 + + + + + + + + + 0 + 67 + + + + Qt::NoFocus + + + QFrame::Panel + + + QFrame::Plain + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + false + + + true + + + 35 + + + false + + + 35 + + + 22 + + + false + + + 22 + + + - 770 - 0 + 800 + 10 295 700 @@ -2117,7 +2343,7 @@ 0 0 285 - 673 + 675 @@ -2153,7 +2379,7 @@ - + 2 @@ -2803,7 +3029,7 @@ 0 0 291 - 874 + 876 @@ -3074,9 +3300,9 @@ - + - + 2 0 @@ -3084,13 +3310,13 @@ 0 - 44 + 42 16777215 - 44 + 42 @@ -3099,7 +3325,7 @@ - Qt::StrongFocus + Qt::NoFocus false @@ -3283,7 +3509,7 @@ 6 - + 0 @@ -3566,7 +3792,7 @@ - + 0 @@ -3601,19 +3827,19 @@ - + <html><head/><body><p>Set all xform color speed values to 0 or 1, alternating</p></body></html> - Toggle Color Speed + Toggle Color Speeds - + 0 @@ -3903,7 +4129,7 @@ 6 - + 2 @@ -4758,7 +4984,7 @@ 6 - + true @@ -6034,7 +6260,7 @@ 0 0 267 - 653 + 676 @@ -6164,7 +6390,7 @@ 0 0 291 - 854 + 856 @@ -6743,7 +6969,7 @@ - + 0 @@ -7042,7 +7268,7 @@ 0 0 1712 - 21 + 20 @@ -7273,8 +7499,8 @@ 0 0 - 442 - 587 + 407 + 541 diff --git a/Source/Fractorium/FractoriumCommon.h b/Source/Fractorium/FractoriumCommon.h index ce8d84a..6a0e7e0 100644 --- a/Source/Fractorium/FractoriumCommon.h +++ b/Source/Fractorium/FractoriumCommon.h @@ -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" diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index e494818..5a975a7 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -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() diff --git a/Source/Fractorium/FractoriumInfo.cpp b/Source/Fractorium/FractoriumInfo.cpp index b305ab3..53722f6 100644 --- a/Source/Fractorium/FractoriumInfo.cpp +++ b/Source/Fractorium/FractoriumInfo.cpp @@ -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()); diff --git a/Source/Fractorium/FractoriumMenus.cpp b/Source/Fractorium/FractoriumMenus.cpp index 5b77550..96a83a5 100644 --- a/Source/Fractorium/FractoriumMenus.cpp +++ b/Source/Fractorium/FractoriumMenus.cpp @@ -60,7 +60,7 @@ void FractoriumEmberController::NewFlock(size_t count) m_EmberFile.Clear(); m_EmberFile.m_Filename = EmberFile::DefaultFilename(); vector filteredVariations; - vector& filteredVariationsRef = m_FilteredVariations; + vector* filteredVariationsRef = &m_FilteredVariations; auto& deviceNames = OpenCLInfo::Instance()->AllDeviceNames(); for (auto& dev : deviceNames) @@ -70,15 +70,18 @@ void FractoriumEmberController::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(QTIsaac::LockedFrand(-2, 2)), 0, 8); + m_SheepTools->Random(ember, *filteredVariationsRef, static_cast(QTIsaac::LockedFrand(-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::ClearFlame() } } + m_Ember.m_Curves.Init(); FillXforms(); + FillCurvesControl(); }); } diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp index 0db8054..66cc524 100644 --- a/Source/Fractorium/FractoriumPalette.cpp +++ b/Source/Fractorium/FractoriumPalette.cpp @@ -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 void FractoriumEmberController::SetBasePaletteAndAdjust(const Palette& 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() /// Ignored 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::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::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) ///
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. ///
-/// The curve index, 0-1/ +/// The curve index, 0-3/ /// The point index within the selected curve, 1-2. /// The new coordinate of the point in terms of the curves control rect. template @@ -614,6 +620,49 @@ void FractoriumEmberController::ColorCurveChanged(int curveIndex, int pointIn void Fractorium::OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point) { m_Controller->ColorCurveChanged(curveIndex, pointIndex, point); } +/// +/// 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. +/// +/// The curve index./ +/// The point index within the selected curve. +template +void FractoriumEmberController::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); } + +/// +/// 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. +/// +/// The curve index./ +/// The point to add to the selected curve. +template +void FractoriumEmberController::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); } + /// /// 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 void FractoriumEmberController::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(); } diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index eaeddf6..1a83846 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -22,13 +22,21 @@ void Fractorium::InitParamsUI() SetFixedTableHeader(ui.IterationTableHeader->horizontalHeader()); SetFixedTableHeader(ui.AnimationTableHeader->horizontalHeader()); //Color. - SetupSpinner(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(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(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(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(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(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(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(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(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(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(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 (table, this, row, 1, m_HeightSpin, spinHeight, 10, 2048, 50, SIGNAL(valueChanged(int)), SLOT(OnHeightChanged(int)), true, height(), height(), height()); SetupSpinner(table, this, row, 1, m_CenterXSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterXChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_CenterYSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterYChanged(double)), true, 0, 0, 0); - SetupSpinner(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240); + SetupSpinner(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240); SetupSpinner(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 25, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_RotateSpin, spinHeight, -180, 180, 10, SIGNAL(valueChanged(double)), SLOT(OnRotateChanged(double)), true, 0, 0, 0); SetupSpinner(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(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::FilterTypes(); SetupCombo(table, this, row, 1, m_SpatialFilterTypeCombo, comboVals, SIGNAL(currentIndexChanged(const QString&)), SLOT(OnSpatialFilterTypeComboCurrentIndexChanged(const QString&))); + m_SpatialFilterTypeCombo->SetCurrentIndexStealth(0); SetupSpinner(table, this, row, 1, m_DEFilterMinRadiusSpin, spinHeight, 0, 25, 1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterMinRadiusWidthChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_DEFilterMaxRadiusSpin, spinHeight, 0, 25, 1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterMaxRadiusWidthChanged(double)), true, 0.0, 9.0, 0); SetupSpinner(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( table, this, row, 1, m_SbsSpin, spinHeight, 1000, 100000, 100, SIGNAL(valueChanged(int)), SLOT(OnSbsChanged(int)), true, DEFAULT_SBS, DEFAULT_SBS, DEFAULT_SBS); - SetupSpinner( table, this, row, 1, m_FuseSpin, spinHeight, 1, 1000, 5, SIGNAL(valueChanged(int)), SLOT(OnFuseChanged(int)), true, 15, 15, 15); - SetupSpinner(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, quality, 10, 10); - SetupSpinner( table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 1, 1, 1); + SetupSpinner( table, this, row, 1, m_SbsSpin, spinHeight, 1000, 100000, 100, SIGNAL(valueChanged(int)), SLOT(OnSbsChanged(int)), true, DEFAULT_SBS, DEFAULT_SBS, DEFAULT_SBS); + SetupSpinner( table, this, row, 1, m_FuseSpin, spinHeight, 1, 1000, 5, SIGNAL(valueChanged(int)), SLOT(OnFuseChanged(int)), true, 15, 100, 15); + SetupSpinner(table, this, row, 1, m_RandRangeSpin, spinHeight, 0.01, 1000, 0.1, SIGNAL(valueChanged(double)), SLOT(OnRandRangeChanged(double)), true, 1, 10, 1); + SetupSpinner(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, quality, 10, 10); + SetupSpinner( 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( table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 1, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000); SetupSpinner(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1); comboVals = TemporalFilterCreator::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::BrightnessChanged(double d) ember.m_Brightness = d; }, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll()); } + void Fractorium::OnBrightnessChanged(double d) { m_Controller->BrightnessChanged(d); } /// @@ -203,6 +217,22 @@ template void FractoriumEmberController::HighlightPowerChanged(d } void Fractorium::OnHighlightPowerChanged(double d) { m_Controller->HighlightPowerChanged(d); } +/// +/// 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. +/// +/// The k2 value +template void FractoriumEmberController::K2Changed(double d) +{ + UpdateAll([&](Ember& 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); } + /// /// Show the color selection dialog. /// Called when background color button is clicked. @@ -223,7 +253,7 @@ void Fractorium::OnBackgroundColorButtonClicked(bool checked) template void FractoriumEmberController::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 void FractoriumEmberController::SbsChanged(int d) } void Fractorium::OnSbsChanged(int d) { m_Controller->SbsChanged(d); } +/// +/// 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. +/// +/// The sub batch size value to set +template void FractoriumEmberController::RandRangeChanged(double d) +{ + UpdateAll([&](Ember& ember, bool isMain) + { + ember.m_RandPointRange = d; + }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); +} + +void Fractorium::OnRandRangeChanged(double d) { m_Controller->RandRangeChanged(d); } + /// /// 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::InterpTypeChanged(int i) void Fractorium::OnInterpTypeComboCurrentIndexChanged(int index) { m_Controller->InterpTypeChanged(index); } -/// -/// 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. -/// -/// The temporal samples value -template -void FractoriumEmberController::TemporalSamplesChanged(int i) -{ - UpdateAll([&](Ember& 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); } - /// /// 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::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::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::ParamsToEmber(Ember& 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::ParamsToEmber(Ember& 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(); diff --git a/Source/Fractorium/FractoriumRender.cpp b/Source/Fractorium/FractoriumRender.cpp index 81a267d..09f2f52 100644 --- a/Source/Fractorium/FractoriumRender.cpp +++ b/Source/Fractorium/FractoriumRender.cpp @@ -587,6 +587,9 @@ bool FractoriumEmberController::CreateRenderer(eRendererType renderType, cons if (m_Fractorium->m_QualitySpin->value() < val) m_Fractorium->m_QualitySpin->setValue(val); + + if (auto rendererCL = dynamic_cast*>(m_Renderer.get())) + rendererCL->SubBatchPercentPerThread(float(s->OpenCLSubBatchPct())); } else { diff --git a/Source/Fractorium/FractoriumSettings.cpp b/Source/Fractorium/FractoriumSettings.cpp index 552733c..d2f924f 100644 --- a/Source/Fractorium/FractoriumSettings.cpp +++ b/Source/Fractorium/FractoriumSettings.cpp @@ -55,6 +55,16 @@ void FractoriumSettings::EnsureDefaults() FinalThreadPriority(Clamp(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. /// -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 FractoriumSettings::Devices() { return value(DEVICES).toList(); } -void FractoriumSettings::Devices(const QList& devices) { setValue(DEVICES, devices); } +QList FractoriumSettings::Devices() { return value(DEVICES).toList(); } +void FractoriumSettings::Devices(const QList& 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); } /// /// Sequence generation settings. @@ -253,62 +266,65 @@ void FractoriumSettings::VarFilterNonparam(int i) { setValue(VARFILTERNONPARAM, /// Final render settings. /// -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 FractoriumSettings::FinalDevices() { return value(FINALDEVICES).toList(); } -void FractoriumSettings::FinalDevices(const QList& devices) { setValue(FINALDEVICES, devices); } +QList FractoriumSettings::FinalDevices() { return value(FINALDEVICES).toList(); } +void FractoriumSettings::FinalDevices(const QList& 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)); } /// /// Xml file saving settings. diff --git a/Source/Fractorium/FractoriumSettings.h b/Source/Fractorium/FractoriumSettings.h index 438cd0d..1004781 100644 --- a/Source/Fractorium/FractoriumSettings.h +++ b/Source/Fractorium/FractoriumSettings.h @@ -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); diff --git a/Source/Fractorium/FractoriumToolbar.cpp b/Source/Fractorium/FractoriumToolbar.cpp index c8f8385..8cd5a7a 100644 --- a/Source/Fractorium/FractoriumToolbar.cpp +++ b/Source/Fractorium/FractoriumToolbar.cpp @@ -128,6 +128,8 @@ void Fractorium::OnActionStartStopRenderer(bool checked) /// Check state, show editor if true, else hide. void Fractorium::OnActionDrawXforms(bool checked) { + m_Settings->ShowXforms(checked); + if (!ui.ActionDrawImage->isChecked() && !ui.ActionDrawXforms->isChecked()) ui.ActionDrawImage->setChecked(true); diff --git a/Source/Fractorium/FractoriumXaos.cpp b/Source/Fractorium/FractoriumXaos.cpp index f04be8c..0d819e2 100644 --- a/Source/Fractorium/FractoriumXaos.cpp +++ b/Source/Fractorium/FractoriumXaos.cpp @@ -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); } /// @@ -49,6 +53,62 @@ void FractoriumEmberController::FillXaos() m_Fractorium->ui.XaosTableView->resizeColumnsToContents(); } +/// +/// Fill the xaos table with the xaos values applied to the xform weights from the ember. +/// +template +void FractoriumEmberController::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(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(); +} + /// /// Set the xaos value. /// Called when any xaos spinner is changed. @@ -68,7 +128,10 @@ void FractoriumEmberController::XaosChanged(int x, int y, double val) if (auto xform = m_Ember.GetXform(x)) if (!IsClose(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(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(); + for (auto& it : widgetList) + it->setEnabled(true); + + widgetList = ui.XaosAppliedTableView->findChildren(); + for (auto& it : widgetList) it->setEnabled(true); } @@ -128,6 +208,7 @@ void FractoriumEmberController::ClearXaos() { Update([&] { m_Ember.ClearXaos(); }); FillXaos(); + FillAppliedXaos(); } void Fractorium::OnClearXaosButtonClicked(bool checked) { m_Controller->ClearXaos(); } @@ -143,21 +224,21 @@ void FractoriumEmberController::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(0, 3)); - } + if (m_Rand.RandBit()) + xform->SetXaos(j, T(m_Rand.RandBit())); + else + xform->SetXaos(j, TruncPrecision(m_Rand.Frand(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. /// /// The number of new xforms to add to create the layer template @@ -186,6 +268,41 @@ void FractoriumEmberController::AddLayer(int xforms) void Fractorium::OnAddLayerButtonClicked(bool checked) { m_Controller->AddLayer(ui.AddLayerSpinBox->value()); } +/// +/// Flip the row and column values of the xaos table. +/// Resets the rendering process. +/// +template +void FractoriumEmberController::TransposeXaos() +{ + Update([&] + { + size_t i = 0, j = 0; + vector> tempxaos; + tempxaos.reserve(m_Ember.XformCount()); + + while (auto xform = m_Ember.GetXform(i++)) + { + vector 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(); } + /// /// 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(); } /// @@ -218,6 +336,33 @@ void Fractorium::OnXaosColDoubleClicked(int logicalIndex) ui.XaosTableView->resizeRowsToContents(); ui.XaosTableView->resizeColumnsToContents(); + m_Controller->FillAppliedXaos(); +} + +/// +/// 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. +/// +/// The value of the xaos table horizontal scroll bar +void Fractorium::OnXaosHScrollValueChanged(int value) +{ + ui.XaosDistVizTableWidget->horizontalScrollBar()->setValue(value); + ui.XaosAppliedTableView->horizontalScrollBar()->setValue(value); +} + +/// +/// 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. +/// +/// The value of the xaos table vertical scroll bar +void Fractorium::OnXaosVScrollValueChanged(int value) +{ + ui.XaosDistVizTableWidget->verticalScrollBar()->setValue(value); + ui.XaosAppliedTableView->verticalScrollBar()->setValue(value); } template class FractoriumEmberController; diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp index c5a7396..0010fac 100644 --- a/Source/Fractorium/FractoriumXforms.cpp +++ b/Source/Fractorium/FractoriumXforms.cpp @@ -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::XformWeightChanged(double d) xform->m_Weight = d; }, eXformUpdate::UPDATE_SELECTED_EXCEPT_FINAL); SetNormalizedWeightText(CurrentXform()); + FillAppliedXaos(); } + void Fractorium::OnXformWeightChanged(double d) { m_Controller->XformWeightChanged(d); } + /// /// Equalize the weights of all xforms in the ember. /// @@ -393,8 +395,11 @@ void FractoriumEmberController::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(); } + /// /// Set the name of the current xform. /// Update the corresponding xform checkbox text with the name. diff --git a/Source/Fractorium/FractoriumXformsAffine.cpp b/Source/Fractorium/FractoriumXformsAffine.cpp index 6a752c0..e2fb48d 100644 --- a/Source/Fractorium/FractoriumXformsAffine.cpp +++ b/Source/Fractorium/FractoriumXformsAffine.cpp @@ -667,9 +667,9 @@ void FractoriumEmberController::FillAffineWithXform(Xform* 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::Hypot(affine.D(), affine.A())); spinners[4]->SetValueStealth(VarFuncs::Hypot(affine.E(), affine.B())); spinners[5]->SetValueStealth(VarFuncs::Hypot(affine.F(), affine.C())); diff --git a/Source/Fractorium/FractoriumXformsColor.cpp b/Source/Fractorium/FractoriumXformsColor.cpp index cbe3533..1713636 100644 --- a/Source/Fractorium/FractoriumXformsColor.cpp +++ b/Source/Fractorium/FractoriumXformsColor.cpp @@ -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(ui.XformColorIndexTable, this, row, 1, m_XformColorIndexSpin, spinHeight, 0, 1, 0.01, SIGNAL(valueChanged(double)), SLOT(OnXformColorIndexChanged(double)), false, 0, 1, 0); SetupSpinner(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(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. /// template -void FractoriumEmberController::ToggleColorSpeedButtonClicked() +void FractoriumEmberController::ToggleColorSpeedsButtonClicked() { char ch = 1; UpdateXform([&](Xform* 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(); } /// /// Set the color speed of the selected xforms. diff --git a/Source/Fractorium/OptionsDialog.cpp b/Source/Fractorium/OptionsDialog.cpp index b52c33e..10432f9 100644 --- a/Source/Fractorium/OptionsDialog.cpp +++ b/Source/Fractorium/OptionsDialog.cpp @@ -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); diff --git a/Source/Fractorium/OptionsDialog.ui b/Source/Fractorium/OptionsDialog.ui index 222d0ce..c8f4a03 100644 --- a/Source/Fractorium/OptionsDialog.ui +++ b/Source/Fractorium/OptionsDialog.ui @@ -248,7 +248,7 @@ - + OpenCL Filtering @@ -292,7 +292,42 @@ + + + + <html><head/><body><p>The default quality per device to use for the interactive renderer when using OpenCL.</p><p>30 is a good number for this, but you can use a larger value if you have a faster GPU.</p></body></html> + + + OpenCL Quality + + + 1 + + + 99999 + + + 30 + + + + + + <html><head/><body><p>The number of ~8M iteration chunks ran using OpenCL in interactive mode for each mouse movement.</p><p>Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.</p></body></html> + + + OpenCL Chunks per Mouse Movement + + + 1 + + + 100 + + + + CPU Filtering @@ -339,69 +374,13 @@ - - - - The number of ~8M iteration chunks ran using OpenCL -in interactive mode for each mouse movement - - - OpenCL Sub Batch - - - 1 - - - 100 - - - - - - - <html><head/><body><p>The default quality to use for the interactive renderer when using OpenCL.</p><p>30 is a good number for this, but you can use a larger value if you have a faster GPU.</p></body></html> - - - OpenCL Quality - - - 1 - - - 99999 - - - 30 - - - - - - - <html><head/><body><p>The default quality to use for the interactive renderer when using the CPU.</p><p>10 is a good number for this, but you can use a larger value if you have a faster system.</p></body></html> - - - CPU Quality - - - 1 - - - 99999 - - - 10 - - - - The number of 10,000 iteration chunks ran per thread on the CPU -in interactive mode for each mouse movement + <html><head/><body><p>The number of ~10,000 iteration chunks ran per thread on the CPU in interactive mode for each mouse movement.</p><p>Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.</p><p>The number of iterations done in each chunk is controlled by the Sub Batch Size field in the Flame tab.</p></body></html> - CPU Sub Batch + CPU Chunks per Mouse Movement 1 @@ -411,6 +390,22 @@ in interactive mode for each mouse movement + + + + <html><head/><body><p>The number of threads to use with CPU rendering.</p><p>Decrease for more responsive editing, increase for better performance.</p></body></html> + + + Threads + + + 1 + + + 64 + + + @@ -427,19 +422,47 @@ in interactive mode for each mouse movement - - + + - <html><head/><body><p>The number of threads to use with CPU rendering.</p><p>Decrease for more responsive editing, increase for better performance.</p></body></html> + <html><head/><body><p>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).</p><p>Increase this number for a higher quality image on each mouse movement, at the expense of responsiveness.</p><p>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.</p></body></html> - Threads + OpenCL Sub Batch Percent Per Thread + + + 3 + + + 0.010000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.025000000000000 + + + + + + + <html><head/><body><p>The default quality to use for the interactive renderer when using the CPU.</p><p>10 is a good number for this, but you can use a larger value if you have a faster system.</p></body></html> + + + CPU Quality 1 - 64 + 99999 + + + 10 @@ -538,7 +561,7 @@ in interactive mode for each mouse movement 6 - + 0 @@ -731,7 +754,7 @@ in interactive mode for each mouse movement 6 - + 0 @@ -922,13 +945,6 @@ in interactive mode for each mouse movement - - - TableWidget - QTableWidget -
TableWidget.h
-
-
EarlyClipCheckBox OpenCLCheckBox @@ -946,8 +962,9 @@ in interactive mode for each mouse movement CpuSubBatchSpin RandomCountSpin OpenCLQualitySpin - OpenCLSubBatchSpin + OpenCLSubBatchPctSpin CpuQualitySpin + OpenCLSubBatchSpin CpuFilteringLogRadioButton CpuFilteringDERadioButton OpenCLFilteringLogRadioButton diff --git a/Source/Fractorium/PaletteEditor.ui b/Source/Fractorium/PaletteEditor.ui index bf4ea7c..d6f21d2 100644 --- a/Source/Fractorium/PaletteEditor.ui +++ b/Source/Fractorium/PaletteEditor.ui @@ -231,8 +231,11 @@ 0 + + true + - QAbstractSpinBox::NoButtons + QAbstractSpinBox::UpDownArrows diff --git a/Source/Fractorium/PaletteEditor/PaletteEditor.cpp b/Source/Fractorium/PaletteEditor/PaletteEditor.cpp index 4aa8617..2e5ebd6 100644 --- a/Source/Fractorium/PaletteEditor/PaletteEditor.cpp +++ b/Source/Fractorium/PaletteEditor/PaletteEditor.cpp @@ -1,13 +1,11 @@ #include "FractoriumPch.h" #include "PaletteEditor.h" +#include "Fractorium.h" /// /// 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. /// -/// A reference to an existing palette list, gotten from the main window. /// The parent widget 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(parent())->Urls()); } if (m_FileDialog->exec() == QDialog::Accepted) diff --git a/Source/Fractorium/QssDialog.cpp b/Source/Fractorium/QssDialog.cpp index 57bb08c..39d8a2b 100644 --- a/Source/Fractorium/QssDialog.cpp +++ b/Source/Fractorium/QssDialog.cpp @@ -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(parent())->Urls()); } #endif diff --git a/Source/Fractorium/SpinBox.cpp b/Source/Fractorium/SpinBox.cpp index 90387a8..5b34297 100644 --- a/Source/Fractorium/SpinBox.cpp +++ b/Source/Fractorium/SpinBox.cpp @@ -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(e)) - { + + e->accept(); return true; } } + else if (dynamic_cast(e)) + { + e->accept(); + return true; + } } return QSpinBox::eventFilter(o, e); diff --git a/Source/Fractorium/TableWidget.h b/Source/Fractorium/TableWidget.h index d1d165f..7d25751 100644 --- a/Source/Fractorium/TableWidget.h +++ b/Source/Fractorium/TableWidget.h @@ -7,20 +7,8 @@ ///
/// -/// 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. /// class TableWidget : public QTableWidget { @@ -45,20 +33,15 @@ signals: protected: /// - /// 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. /// /// The object sending the event /// The event - /// True if mouse wheel, else return the result of calling the base fucntion. + /// The result of calling the base fucntion. 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(e)) { diff --git a/Source/Fractorium/TwoButtonComboWidget.h b/Source/Fractorium/TwoButtonComboWidget.h index 4d46536..e165d16 100644 --- a/Source/Fractorium/TwoButtonComboWidget.h +++ b/Source/Fractorium/TwoButtonComboWidget.h @@ -1,6 +1,7 @@ #pragma once #include "FractoriumPch.h" +#include "SpinBox.h" #include "DoubleSpinBox.h" /// @@ -114,7 +115,42 @@ public: QPushButton* m_Button; }; -class SpinnerLabelButtonWidget : public QWidget +class SpinnerLabelWidget : public QWidget +{ + Q_OBJECT + +public: + /// + /// 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. + /// + /// The pre-created DoubleSpinBox + /// The height of the label + /// The parent widget + 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: /// The height of the button /// The parent widget 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: + /// + /// Constructor that passes the parent to the base, then creates a QHBoxLayout, + /// and adds the passed in DoubleSpinBox and SpinBox to the layout. + /// + /// The pre-created DoubleSpinBox + /// The pre-created SpinBox + /// The parent widget + 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; };