diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs
index c0950c6..524b061 100644
--- a/Builds/MSVC/Installer/Product.wxs
+++ b/Builds/MSVC/Installer/Product.wxs
@@ -371,8 +371,8 @@
-
-
+
+
diff --git a/Builds/QtCreator/Fractorium/Fractorium.pro b/Builds/QtCreator/Fractorium/Fractorium.pro
index 08da4bd..63dec28 100644
--- a/Builds/QtCreator/Fractorium/Fractorium.pro
+++ b/Builds/QtCreator/Fractorium/Fractorium.pro
@@ -241,6 +241,7 @@ examples.path = $$SHARE_INSTALL_DIR/examples
examples.files += \
$$ASSETS_DIR/examples/b33rheart_examples.flame \
$$ASSETS_DIR/examples/b33rheart_sierpinski.flame \
+ $$ASSETS_DIR/examples/c-91_examples.flame \
$$ASSETS_DIR/examples/pillemaster_hexagonal_tilings.flame \
$$ASSETS_DIR/examples/plangkye_examples.flame \
$$ASSETS_DIR/examples/tatasz_examples.flame \
diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h
index 08ab7ac..8af5f08 100644
--- a/Source/Ember/Ember.h
+++ b/Source/Ember/Ember.h
@@ -126,7 +126,6 @@ public:
m_CamMat = ember.m_CamMat;
m_CenterX = T(ember.m_CenterX);
m_CenterY = T(ember.m_CenterY);
- m_RotCenterY = T(ember.m_RotCenterY);
m_Rotate = T(ember.m_Rotate);
m_Brightness = T(ember.m_Brightness);
m_Gamma = T(ember.m_Gamma);
@@ -783,7 +782,6 @@ public:
InterpX::m_CamMat>(embers, coefs, size);
InterpT<&Ember::m_CenterX>(embers, coefs, size);
InterpT<&Ember::m_CenterY>(embers, coefs, size);
- InterpT<&Ember::m_RotCenterY>(embers, coefs, size);
InterpT<&Ember::m_Rotate>(embers, coefs, size);
InterpT<&Ember::m_Brightness>(embers, coefs, size);
InterpT<&Ember::m_Gamma>(embers, coefs, size);
@@ -1405,7 +1403,6 @@ public:
m_Palette.m_Index = -1;
m_CenterX = 0;
m_CenterY = 0;
- m_RotCenterY = 0;
m_Gamma = 4;
m_Vibrancy = 1;
m_Brightness = 4;
@@ -1540,7 +1537,6 @@ public:
<< "Depth Blur: " << m_CamDepthBlur << "\n"
<< "CenterX: " << m_CenterX << "\n"
<< "CenterY: " << m_CenterY << "\n"
- << "RotCenterY: " << m_RotCenterY << "\n"
<< "Rotate: " << m_Rotate << "\n"
<< "Brightness: " << m_Brightness << "\n"
<< "Gamma: " << m_Gamma << "\n"
@@ -1681,7 +1677,6 @@ public:
//Xml field: "center".
T m_CenterX = 0;
T m_CenterY = 0;
- T m_RotCenterY = 0;
//Rotate the camera by this many degrees. Since this is a camera rotation, the final output image will be rotated counter-clockwise.
//Xml field: "rotate".
diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp
index eeb9387..becc656 100644
--- a/Source/Ember/Renderer.cpp
+++ b/Source/Ember/Renderer.cpp
@@ -1526,10 +1526,10 @@ void Renderer::Accumulate(QTIsaac& rand, Poin
{
if (Rotate() != 0)
{
- T p00 = p.m_X - CenterX();
- T p11 = p.m_Y - m_Ember.m_RotCenterY;
- p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + CenterX();
- p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_RotCenterY;
+ T p00 = p.m_X - m_Ember.m_CenterX;
+ T p11 = p.m_Y - m_Ember.m_CenterY;
+ p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + m_Ember.m_CenterX;
+ p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_CenterY;
}
//Checking this first before converting gives better performance than converting and checking a single value, which the original did.
@@ -1599,10 +1599,10 @@ void Renderer::Accumulate(QTIsaac& rand, Poin
{
if (Rotate() != 0)
{
- T p00 = p.m_X - CenterX();
- T p11 = p.m_Y - m_Ember.m_RotCenterY;
- p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + CenterX();
- p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_RotCenterY;
+ T p00 = p.m_X - m_Ember.m_CenterX;
+ T p11 = p.m_Y - m_Ember.m_CenterY;
+ p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + m_Ember.m_CenterX;
+ p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_CenterY;
}
if (m_CarToRas.InBounds(p))
diff --git a/Source/Ember/XmlToEmber.cpp b/Source/Ember/XmlToEmber.cpp
index eba3c40..02d4a6e 100644
--- a/Source/Ember/XmlToEmber.cpp
+++ b/Source/Ember/XmlToEmber.cpp
@@ -1379,7 +1379,6 @@ bool XmlToEmber::ParseEmberElementFromChaos(xmlNode* emberNode, Ember& cur
istringstream istr(pos);
istr >> currentEmber.m_CenterX >> currentEmber.m_CenterY;
currentEmber.m_CenterY *= -1;
- currentEmber.m_RotCenterY = currentEmber.m_CenterY;
}
else
{
@@ -1669,7 +1668,6 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber
{
istringstream is(attStr);
is >> currentEmber.m_CenterX >> currentEmber.m_CenterY;
- currentEmber.m_RotCenterY = currentEmber.m_CenterY;
}
else if (!Compare(curAtt->name, "filter_shape"))
{
diff --git a/Source/EmberCL/EmberCLFunctions.h b/Source/EmberCL/EmberCLFunctions.h
index d3097a7..0cfa88d 100644
--- a/Source/EmberCL/EmberCLFunctions.h
+++ b/Source/EmberCL/EmberCLFunctions.h
@@ -3,6 +3,8 @@
#include "EmberCLPch.h"
#include "EmberCLStructs.h"
+#define USEFMA 1
+
///
/// OpenCL global function strings.
///
@@ -185,13 +187,21 @@ static const char* RandFunctionString =
"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"
+#ifdef USEFMA
" return fma(f, upper - lower, lower);\n"
+#else
+ " return (f * (upper - lower) + lower);\n"
+#endif
"}\n"
"\n"
"inline real_t MwcNextNeg1Pos1(uint2* s)\n"
"{\n"
" real_t f = (real_t)MwcNext(s) / (real_t)UINT_MAX;\n"
+#ifdef USEFMA
" return fma(f, (real_t)2.0, (real_t)-1.0);\n"
+#else
+ " return (f * (real_t)2.0 + (real_t)-1.0);\n"
+#endif
"}\n"
"\n"
"inline real_t MwcNext0505(uint2* s)\n"
@@ -218,7 +228,11 @@ static const char* AddToAccumWithCheckFunctionString =
static const char* CarToRasFunctionString =
"inline void CarToRasConvertPointToSingle(__constant CarToRasCL* carToRas, Point* point, uint* singleBufferIndex)\n"
"{\n"
+#ifdef USEFMA
" *singleBufferIndex = (uint)fma(carToRas->m_PixPerImageUnitW, point->m_X, carToRas->m_RasLlX) + (carToRas->m_RasWidth * (uint)fma(carToRas->m_PixPerImageUnitH, point->m_Y, carToRas->m_RasLlY));\n"
+#else
+ " *singleBufferIndex = (uint)(carToRas->m_PixPerImageUnitW * point->m_X + carToRas->m_RasLlX) + (carToRas->m_RasWidth * (uint)(carToRas->m_PixPerImageUnitH * point->m_Y + carToRas->m_RasLlY));\n"
+#endif
"}\n"
"\n"
"inline bool CarToRasInBounds(__constant CarToRasCL* carToRas, Point* point)\n"
diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp
index 0693e52..5c238eb 100644
--- a/Source/EmberCL/IterOpenCLKernelCreator.cpp
+++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp
@@ -172,7 +172,11 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
if (needPrecalcAtanYX)
xformFuncs << "\treal_t precalcAtanyx;\n";
+#ifdef USEFMA
xformFuncs << "\treal_t tempColor = outPoint->m_ColorX = fma(xform->m_OneMinusColorCache, inPoint->m_ColorX, xform->m_ColorSpeedCache);\n\n";
+#else
+ xformFuncs << "\treal_t tempColor = outPoint->m_ColorX = (xform->m_OneMinusColorCache * inPoint->m_ColorX + xform->m_ColorSpeedCache);\n\n";
+#endif
if (optAffine && xform->m_Affine.IsID())
{
@@ -182,9 +186,15 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
}
else
{
+#ifdef USEFMA
xformFuncs <<
" transX = fma(xform->m_A, inPoint->m_X, fma(xform->m_B, inPoint->m_Y, xform->m_C));\n" <<
" transY = fma(xform->m_D, inPoint->m_X, fma(xform->m_E, inPoint->m_Y, xform->m_F));\n";
+#else
+ xformFuncs <<
+ " transX = xform->m_A * inPoint->m_X + (xform->m_B * inPoint->m_Y + xform->m_C);\n" <<
+ " transY = xform->m_D * inPoint->m_X + (xform->m_E * inPoint->m_Y + xform->m_F);\n";
+#endif
}
xformFuncs << " transZ = inPoint->m_Z;\n";
@@ -289,11 +299,20 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
"\n\t//Apply post affine transform.\n"
"\treal_t tempX = outPoint->m_X;\n"
"\n"
+#ifdef USEFMA
"\toutPoint->m_X = fma(xform->m_PostA, tempX, fma(xform->m_PostB, outPoint->m_Y, xform->m_PostC));\n" <<
"\toutPoint->m_Y = fma(xform->m_PostD, tempX, fma(xform->m_PostE, outPoint->m_Y, xform->m_PostF));\n";
+#else
+ "\toutPoint->m_X = (xform->m_PostA * tempX + (xform->m_PostB * outPoint->m_Y + xform->m_PostC));\n" <<
+ "\toutPoint->m_Y = (xform->m_PostD * tempX + (xform->m_PostE * outPoint->m_Y + xform->m_PostF));\n";
+#endif
}
+#ifdef USEFMA
xformFuncs << "\toutPoint->m_ColorX = fma(xform->m_DirectColor, (outPoint->m_ColorX - tempColor), tempColor);\n";
+#else
+ xformFuncs << "\toutPoint->m_ColorX = (xform->m_DirectColor * (outPoint->m_ColorX - tempColor) + tempColor);\n";
+#endif
xformFuncs << "\n";
xformFuncs << "\tif (isnan(outPoint->m_ColorX))\n";
xformFuncs << "\t outPoint->m_ColorX = 0.0; \n";
@@ -365,16 +384,16 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
" uint threadsMinus1 = NTHREADS - 1;\n"
" VariationState varState;\n"
"\n";
+#ifndef STRAIGHT_RAND
if (ember.XformCount() > 1)
{
os <<
-#ifndef STRAIGHT_RAND
" __local Point swap[NTHREADS];\n"
" __local uint xfsel[NWARPS];\n";
-#endif
}
+#endif
os <<
" iPaletteCoord.y = 0;\n"
"\n"
@@ -418,7 +437,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
os <<
"\n"
" if (THREAD_ID_Y == 0 && THREAD_ID_X < NWARPS)\n"
- " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ";\n"//It's faster to do the & here ahead of time than every time an xform is looked up to use inside the loop.
+ " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u;\n"//It's faster to do the & here ahead of time than every time an xform is looked up to use inside the loop.
"\n";
#endif
}
@@ -429,7 +448,9 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
}
os <<
+#ifndef STRAIGHT_RAND
" barrier(CLK_LOCAL_MEM_FENCE);\n"
+#endif
"\n"
" for (i = 0; i < itersToDo; i++)\n"
" {\n"
@@ -447,16 +468,16 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
{
os <<
#ifdef STRAIGHT_RAND
- " secondPoint.m_LastXfUsed = xformDistributions[(MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ") + (" << CHOOSE_XFORM_GRAIN << " * (firstPoint.m_LastXfUsed + 1u))];\n\n";
+ " secondPoint.m_LastXfUsed = xformDistributions[(MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u) + (" << CHOOSE_XFORM_GRAIN << "u * (firstPoint.m_LastXfUsed + 1u))];\n\n";
#else
- " secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y] + (" << CHOOSE_XFORM_GRAIN << " * (firstPoint.m_LastXfUsed + 1u))];\n\n";//Partial cuburn hybrid.
+ " secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y] + (" << CHOOSE_XFORM_GRAIN << "u * (firstPoint.m_LastXfUsed + 1u))];\n\n";//Partial cuburn hybrid.
#endif
}
else
{
os <<
#ifdef STRAIGHT_RAND
- " secondPoint.m_LastXfUsed = xformDistributions[MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "];\n\n";//For testing, using straight rand flam4/fractron style instead of cuburn.
+ " secondPoint.m_LastXfUsed = xformDistributions[MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u];\n\n";//For testing, using straight rand flam4/fractron style instead of cuburn.
#else
" secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y]];\n\n";
#endif
@@ -531,7 +552,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
"\n"
//Populate randomized xform index buffer with new random values.
" if (THREAD_ID_Y == 0 && THREAD_ID_X < NWARPS)\n"
- " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ";\n"
+ " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u;\n"
"\n"
" barrier(CLK_LOCAL_MEM_FENCE);\n"
//Another thread will have written to this thread's location, so read the new value and use it for accumulation below.
@@ -565,12 +586,14 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
" i = 0;\n"
" fuse = false;\n"
" itersToDo = iterCount;\n";
+#ifndef STRAIGHT_RAND
if (ember.XformCount() > 1)
os <<
" barrier(CLK_LOCAL_MEM_FENCE);\n"//Sort of seems necessary, sort of doesn't. Makes no speed difference.
;
+#endif
os <<
" }\n"
;
@@ -616,19 +639,40 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
if (doAccum)
{
+ if (optAffine && AnyZeroOpacity(ember))
+ {
+ os <<
+ " if (xforms[secondPoint.m_LastXfUsed].m_Opacity != (real_t)(0.0))\n";
+ }
+
+ os <<
+ " {\n";
+
+ //Add this point to the appropriate location in the histogram.
+ if (optAffine && ember.m_Rotate == 0)
+ {
+ os <<
+ " if (CarToRasInBounds(carToRas, &secondPoint))\n"
+ " {\n"
+ " CarToRasConvertPointToSingle(carToRas, &secondPoint, &histIndex);\n";
+ }
+ else
+ {
+ os <<
+ " p00 = secondPoint.m_X - ember->m_CenterX;\n"
+ " p01 = secondPoint.m_Y - ember->m_CenterY;\n"
+ " tempPoint.m_X = fma(p00, ember->m_RotA, fma(p01, ember->m_RotB, ember->m_CenterX));\n"
+ " tempPoint.m_Y = fma(p00, ember->m_RotD, fma(p01, ember->m_RotE, ember->m_CenterY));\n"
+ "\n"
+ " if (CarToRasInBounds(carToRas, &tempPoint))\n"
+ " {\n"
+ " CarToRasConvertPointToSingle(carToRas, &tempPoint, &histIndex);\n";
+ }
+
os <<
- " p00 = secondPoint.m_X - ember->m_CenterX;\n"
- " p01 = secondPoint.m_Y - ember->m_CenterY;\n"
- " tempPoint.m_X = fma(p00, ember->m_RotA, fma(p01, ember->m_RotB, ember->m_CenterX));\n"
- " tempPoint.m_Y = fma(p00, ember->m_RotD, fma(p01, ember->m_RotE, ember->m_CenterY));\n"
"\n"
- //Add this point to the appropriate location in the histogram.
- " if (CarToRasInBounds(carToRas, &tempPoint))\n"
- " {\n"
- " CarToRasConvertPointToSingle(carToRas, &tempPoint, &histIndex);\n"
- "\n"
- " if (histIndex < histSize)\n"//Provides an extra level of safety and makes no speed difference.
- " {\n";
+ " if (histIndex < histSize)\n"//Provides an extra level of safety and makes no speed difference.
+ " {\n";
//Basic texture index interoplation does not produce identical results
//to the CPU. So the code here must explicitly do the same thing and not
@@ -636,57 +680,62 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember,
if (ember.m_PaletteMode == ePaletteMode::PALETTE_LINEAR)
{
os <<
- " real_t colorIndexFrac;\n"
- " real_t colorIndex = secondPoint.m_ColorX * ember->m_Psm1;\n"
- " int intColorIndex;\n"
- " float4 palColor2;\n"
+ " real_t colorIndexFrac;\n"
+ " real_t colorIndex = secondPoint.m_ColorX * ember->m_Psm1;\n"
+ " int intColorIndex;\n"
+ " float4 palColor2;\n"
"\n"
- " if (colorIndex < 0)\n"
- " {\n"
- " intColorIndex = 0;\n"
- " colorIndexFrac = 0;\n"
- " }\n"
- " else if (colorIndex >= ember->m_Psm1)\n"
- " {\n"
- " intColorIndex = (int)ember->m_Psm2;\n"
- " colorIndexFrac = 1.0;\n"
- " }\n"
- " else\n"
- " {\n"
- " intColorIndex = (int)colorIndex;\n"
- " colorIndexFrac = colorIndex - intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1.
- " }\n"
+ " if (colorIndex < 0)\n"
+ " {\n"
+ " intColorIndex = 0;\n"
+ " colorIndexFrac = 0;\n"
+ " }\n"
+ " else if (colorIndex >= ember->m_Psm1)\n"
+ " {\n"
+ " intColorIndex = (int)ember->m_Psm2;\n"
+ " colorIndexFrac = 1.0;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " intColorIndex = (int)colorIndex;\n"
+ " colorIndexFrac = colorIndex - intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1.
+ " }\n"
"\n"
- " iPaletteCoord.x = intColorIndex;\n"//Palette operations are strictly float because OpenCL does not support dp64 textures.
- " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"
- " iPaletteCoord.x += 1;\n"
- " palColor2 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"
- " palColor1 = fma(palColor2, (float)colorIndexFrac, palColor1 * (1.0f - (float)colorIndexFrac));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile.
+ " iPaletteCoord.x = intColorIndex;\n"//Palette operations are strictly float because OpenCL does not support dp64 textures.
+ " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"
+ " iPaletteCoord.x += 1;\n"
+ " palColor2 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"
+#ifdef USEFMA
+ " palColor1 = fma(palColor2, (float)colorIndexFrac, palColor1 * (1.0f - (float)colorIndexFrac));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile.
+#else
+ " palColor1 = (palColor2 * (float)colorIndexFrac + (palColor1 * (1.0f - (float)colorIndexFrac)));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile.
+#endif
}
else if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP)
{
os <<
- " iPaletteCoord.x = (int)(secondPoint.m_ColorX * ember->m_Psm1);\n"
- " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n";
+ " iPaletteCoord.x = (int)(secondPoint.m_ColorX * ember->m_Psm1);\n"
+ " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n";
}
if (lockAccum)
{
os <<
- " AtomicAdd(&(histogram[histIndex].m_Reals[0]), palColor1.x * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"//Always apply opacity, even though it's usually 1.
- " AtomicAdd(&(histogram[histIndex].m_Reals[1]), palColor1.y * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"
- " AtomicAdd(&(histogram[histIndex].m_Reals[2]), palColor1.z * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"
- " AtomicAdd(&(histogram[histIndex].m_Reals[3]), palColor1.w * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";
+ " AtomicAdd(&(histogram[histIndex].m_Reals[0]), palColor1.x * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"//Always apply opacity, even though it's usually 1.
+ " AtomicAdd(&(histogram[histIndex].m_Reals[1]), palColor1.y * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"
+ " AtomicAdd(&(histogram[histIndex].m_Reals[2]), palColor1.z * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"
+ " AtomicAdd(&(histogram[histIndex].m_Reals[3]), palColor1.w * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";
}
else
{
os <<
- " histogram[histIndex].m_Real4 += (palColor1 * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";//real_bucket_t should always be float.
+ " histogram[histIndex].m_Real4 += (palColor1 * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";//real_bucket_t should always be float.
}
os <<
- " }\n"//histIndex < histSize.
- " }\n"//CarToRasInBounds.
+ " }\n"//histIndex < histSize.
+ " }\n"//CarToRasInBounds.
+ " }\n"//Opacity != 0.
"\n";
os <<
" barrier(CLK_GLOBAL_MEM_FENCE);\n";//Barrier every time, whether or not the point was in bounds, else artifacts will occur when doing strips.
@@ -973,6 +1022,24 @@ string IterOpenCLKernelCreator::VariationStateInitString(const Ember& embe
return os.str();
}
+
+///
+/// Determine whether the passed in ember has at least one xform with an opacity of 0.
+///
+/// The first ember to compare
+/// True if at least one xform had an opacity of 0, else false
+template
+bool IterOpenCLKernelCreator::AnyZeroOpacity(const Ember& ember)
+{
+ size_t i = 0;
+
+ while (auto xform = ember.GetXform(i++))
+ if (xform->m_Opacity == 0)
+ return true;
+
+ return false;
+}
+
///
/// Determine whether the two embers passed in differ enough
/// to require a rebuild of the iteration code.
@@ -1017,6 +1084,14 @@ bool IterOpenCLKernelCreator::IsBuildRequired(const Ember& ember1, const E
if (ember1.ProjBits() != ember2.ProjBits())
return true;
+ if (optAffine &&
+ ((ember1.m_Rotate == 0) ^ (ember2.m_Rotate == 0)))
+ return true;
+
+ if (optAffine &&
+ (AnyZeroOpacity(ember1) != AnyZeroOpacity(ember2)))
+ return true;
+
for (i = 0; i < xformCount; i++)
{
auto xform1 = ember1.GetTotalXform(i);
@@ -1124,7 +1199,7 @@ string IterOpenCLKernelCreator::CreateProjectionString(const Ember& ember)
" real_t prcx = (x - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n"
" real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n"
" real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n"
- " real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
+ " real_t scale = ember->m_BlurCurve != (real_t)(0.0) ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
" real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n"
"\n"
" dsin = sin(t);\n"
@@ -1152,7 +1227,7 @@ string IterOpenCLKernelCreator::CreateProjectionString(const Ember& ember)
" real_t prcx = (secondPoint.m_X - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n"
" real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n"
" real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n"
- " real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
+ " real_t scale = ember->m_BlurCurve != (real_t)(0.0) ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n"
" real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n"
"\n"
" secondPoint.m_X = fma(dr, dcos, secondPoint.m_X) / zr;\n"
diff --git a/Source/EmberCL/IterOpenCLKernelCreator.h b/Source/EmberCL/IterOpenCLKernelCreator.h
index 6fdb4eb..e0f4026 100644
--- a/Source/EmberCL/IterOpenCLKernelCreator.h
+++ b/Source/EmberCL/IterOpenCLKernelCreator.h
@@ -36,6 +36,7 @@ public:
static void SharedDataIndexDefines(const Ember& ember, pair>& params, bool doVals = true, bool doString = true);
static string VariationStateString(const Ember& ember);
static string VariationStateInitString(const Ember& ember);
+ static bool AnyZeroOpacity(const Ember& ember);
static bool IsBuildRequired(const Ember& ember1, const Ember& ember2, bool optAffine);
private:
diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp
index 16f194a..a95fa63 100644
--- a/Source/EmberCL/RendererCL.cpp
+++ b/Source/EmberCL/RendererCL.cpp
@@ -1836,8 +1836,8 @@ void RendererCL::ConvertEmber(Ember& ember, EmberCL& emberCL,
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_CenterX = ember.m_CenterX;
+ emberCL.m_CenterY = ember.m_CenterY;
emberCL.m_RotA = m_RotMat.A();
emberCL.m_RotB = m_RotMat.B();
emberCL.m_RotD = m_RotMat.D();
diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp
index fe538e0..e70b687 100644
--- a/Source/Fractorium/FractoriumParams.cpp
+++ b/Source/Fractorium/FractoriumParams.cpp
@@ -369,7 +369,7 @@ template void FractoriumEmberController::CenterYChanged(double d
{
UpdateAll([&](Ember& ember, bool isMain)
{
- ember.m_CenterY = ember.m_RotCenterY = d;
+ ember.m_CenterY = d;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
}
void Fractorium::OnCenterYChanged(double d) { m_Controller->CenterYChanged(d); }
@@ -772,7 +772,7 @@ void FractoriumEmberController::SetCenter(double x, double y)
UpdateAll([&](Ember& ember, bool isMain)
{
ember.m_CenterX = x;
- ember.m_CenterY = ember.m_RotCenterY = y;
+ ember.m_CenterY = y;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
m_Fractorium->m_CenterXSpin->SetValueStealth(x);//Don't trigger a redraw twice.
m_Fractorium->m_CenterYSpin->SetValueStealth(y);
@@ -873,7 +873,7 @@ void FractoriumEmberController::ParamsToEmberPrivate(Ember& ember, bool im
ember.m_FinalRasW = m_Fractorium->m_WidthSpin->value();//Geometry.
ember.m_FinalRasH = m_Fractorium->m_HeightSpin->value();
ember.m_CenterX = m_Fractorium->m_CenterXSpin->value();
- ember.m_CenterY = ember.m_RotCenterY = m_Fractorium->m_CenterYSpin->value();
+ ember.m_CenterY = m_Fractorium->m_CenterYSpin->value();
ember.m_PixelsPerUnit = m_Fractorium->m_ScaleSpin->value();
ember.m_Zoom = m_Fractorium->m_ZoomSpin->value();
ember.m_Rotate = m_Fractorium->m_RotateSpin->value();
diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp
index af29a35..889893b 100644
--- a/Source/Fractorium/GLWidget.cpp
+++ b/Source/Fractorium/GLWidget.cpp
@@ -891,7 +891,7 @@ void GLEmberController::MousePress(QMouseEvent* e)
m_DragState = eDragState::DragNone;
}
}
- else if (e->button() == Qt::MiddleButton || (e->button() == Qt::RightButton && e->modifiers() & Qt::ShiftModifier))//Middle button or right button with shift key, do whole image translation.
+ else if (e->button() == Qt::MiddleButton || (e->button() == Qt::RightButton && e->modifiers() & Qt::ShiftModifier))//Middle button or right button with shift key, do whole image translation.
{
m_CenterDownX = ember->m_CenterX;//Capture where the center of the image is because this value will change when panning.
m_CenterDownY = ember->m_CenterY;
@@ -1043,7 +1043,7 @@ void GLEmberController::MouseMove(QMouseEvent* e)
v2T v1(x, y);
v2T v2 = rotMat.TransformVector(v1);
ember->m_CenterX = v2.x;
- ember->m_CenterY = ember->m_RotCenterY = v2.y;
+ ember->m_CenterY = v2.y;
m_FractoriumEmberController->SetCenter(ember->m_CenterX, ember->m_CenterY);//Will restart the rendering process.
}
else if (m_DragState == eDragState::DragRotateScale)//Rotating and scaling the whole image.
diff --git a/archive/build_linux.sh b/archive/build_linux.sh
index 71b3818..bcb09af 100755
--- a/archive/build_linux.sh
+++ b/archive/build_linux.sh
@@ -185,7 +185,7 @@ mv rpmbuild/RPMS/x86_64/* ./
emberVersion=$(grep '#define EMBER_VERSION' ../Source/Ember/EmberDefines.h | sed 's/^.*EMBER_VERSION "\([^"]\+\)".*/\1/')
-mv Fractorium.deb Fractorium-$emberVersion-.x86_64.deb
+mv Fractorium.deb Fractorium-$emberVersion.x86_64.deb
mv Fractorium-$emberVersion-1.x86_64.rpm Fractorium-$emberVersion.x86_64.rpm
echo ""