--User changes

-Users can now specify animation params on a per flame basis.
 --These get saved with the flame file.
 -Allow for rotating xforms around the world origin during animation.
 -Make the Clear Flame menu item be more comprehensive in how it clears a flame out.

--Bug fixes
 -Fix an extremely rare possible memory leak when using motion during animation, which is never used in Fractorium.
 -Do not skip to the current flame index, or attach a prefix in the Final Render Dialog when rendering an animation sequence.

--Code changes
 -Place all animation params in Ember.
This commit is contained in:
Person 2024-03-16 10:15:51 -06:00
parent 26e075def5
commit a0a205edd8
22 changed files with 864 additions and 857 deletions

1
.gitignore vendored
View File

@ -262,3 +262,4 @@ Builds/include/GL
/Builds/QtCreator/Ember/.qtc_clangd/compile_commands.json /Builds/QtCreator/Ember/.qtc_clangd/compile_commands.json
/Builds/QtCreator/Fractorium/.qtc_clangd/compile_commands.json /Builds/QtCreator/Fractorium/.qtc_clangd/compile_commands.json
.DS_Store .DS_Store
/.vs/VSWorkspaceState.json

View File

@ -124,19 +124,19 @@
<File Id="libxml2.dll" Source="$(var.SolutionDir)..\..\..\Bin\$(var.Platform)\Release\libxml2.dll" KeyPath="yes" Checksum="yes" ProcessorArchitecture="x64" ReadOnly="yes" /> <File Id="libxml2.dll" Source="$(var.SolutionDir)..\..\..\Bin\$(var.Platform)\Release\libxml2.dll" KeyPath="yes" Checksum="yes" ProcessorArchitecture="x64" ReadOnly="yes" />
</Component> </Component>
<Component Id="msvcp140.dll" Guid="8f1ffde7-c1bd-45fb-8bc8-26dde552eafd"> <Component Id="msvcp140.dll" Guid="8f1ffde7-c1bd-45fb-8bc8-26dde552eafd">
<File Id="msvcp140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33130\x64\Microsoft.VC143.CRT\msvcp140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="msvcp140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT\msvcp140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" />
</Component> </Component>
<Component Id="vcruntime140.dll" Guid="50c9bc27-c547-4a03-9f6c-cd416f449dd8"> <Component Id="vcruntime140.dll" Guid="50c9bc27-c547-4a03-9f6c-cd416f449dd8">
<File Id="vcruntime140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33130\x64\Microsoft.VC143.CRT\vcruntime140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="vcruntime140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT\vcruntime140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" />
</Component> </Component>
<Component Id="vcruntime140_1.dll" Guid="a02507f8-326b-45b2-b734-e5091921559f"> <Component Id="vcruntime140_1.dll" Guid="a02507f8-326b-45b2-b734-e5091921559f">
<File Id="vcruntime140_1.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33130\x64\Microsoft.VC143.CRT\vcruntime140_1.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="vcruntime140_1.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT\vcruntime140_1.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" />
</Component> </Component>
<Component Id="vccorlib140.dll" Guid="affe33e7-1e64-4bb0-a062-2b56f77459b4"> <Component Id="vccorlib140.dll" Guid="affe33e7-1e64-4bb0-a062-2b56f77459b4">
<File Id="vccorlib140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33130\x64\Microsoft.VC143.CRT\vccorlib140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="vccorlib140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT\vccorlib140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" />
</Component> </Component>
<Component Id="concrt140.dll" Guid="7fb716a1-1b4f-42fb-89c7-4d216ebd6e2e"> <Component Id="concrt140.dll" Guid="7fb716a1-1b4f-42fb-89c7-4d216ebd6e2e">
<File Id="concrt140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33130\x64\Microsoft.VC143.CRT\concrt140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="concrt140.dll" Source="$(var.DevEnvDir)..\..\VC\Redist\MSVC\14.38.33135\x64\Microsoft.VC143.CRT\concrt140.dll" KeyPath="yes" Checksum="yes" ReadOnly="yes" />
</Component> </Component>
<Component Id="flam3palettes.xml" Guid="d3adb0bb-14ef-4923-99d9-a5784b7ef04e"> <Component Id="flam3palettes.xml" Guid="d3adb0bb-14ef-4923-99d9-a5784b7ef04e">
<File Id="flam3palettes.xml" Source="$(var.SolutionDir)..\..\..\Data\flam3-palettes.xml" KeyPath="yes" Checksum="yes" ReadOnly="yes" /> <File Id="flam3palettes.xml" Source="$(var.SolutionDir)..\..\..\Data\flam3-palettes.xml" KeyPath="yes" Checksum="yes" ReadOnly="yes" />

View File

@ -163,6 +163,14 @@ public:
m_CurveDE = static_cast<T>(ember.m_CurveDE); m_CurveDE = static_cast<T>(ember.m_CurveDE);
m_SpatialFilterType = ember.m_SpatialFilterType; m_SpatialFilterType = ember.m_SpatialFilterType;
m_SpatialFilterRadius = static_cast<T>(ember.m_SpatialFilterRadius); m_SpatialFilterRadius = static_cast<T>(ember.m_SpatialFilterRadius);
m_Stagger = ember.m_Stagger;
m_Rotations = ember.m_Rotations;
m_SecondsPerRotation = ember.m_SecondsPerRotation;
m_RotateXformsCw = ember.m_RotateXformsCw;
m_BlendSeconds = ember.m_BlendSeconds;
m_RotationsPerBlend = ember.m_RotationsPerBlend;
m_BlendRotateXformsCw = ember.m_BlendRotateXformsCw;
m_Linear = ember.m_Linear;
m_TemporalFilterType = ember.m_TemporalFilterType; m_TemporalFilterType = ember.m_TemporalFilterType;
m_TemporalFilterExp = static_cast<T>(ember.m_TemporalFilterExp); m_TemporalFilterExp = static_cast<T>(ember.m_TemporalFilterExp);
m_TemporalFilterWidth = static_cast<T>(ember.m_TemporalFilterWidth); m_TemporalFilterWidth = static_cast<T>(ember.m_TemporalFilterWidth);
@ -171,6 +179,7 @@ public:
m_Name = ember.m_Name; m_Name = ember.m_Name;
m_ParentFilename = ember.m_ParentFilename; m_ParentFilename = ember.m_ParentFilename;
m_Index = ember.m_Index; m_Index = ember.m_Index;
//m_Animations = ember.m_Animations;
m_ScaleType = ember.ScaleType(); m_ScaleType = ember.ScaleType();
m_Palette = ember.m_Palette; m_Palette = ember.m_Palette;
m_Curves = ember.m_Curves; m_Curves = ember.m_Curves;
@ -193,6 +202,7 @@ public:
{ {
m_FinalXform.m_Motion.clear(); m_FinalXform.m_Motion.clear();
m_FinalXform.m_Animate = 0; m_FinalXform.m_Animate = 0;
m_FinalXform.m_AnimateOrigin = 0;
m_FinalXform.m_ColorSpeed = 0; m_FinalXform.m_ColorSpeed = 0;
} }
@ -303,6 +313,7 @@ public:
ember.m_FinalXform.m_Affine.MakeID(); ember.m_FinalXform.m_Affine.MakeID();
ember.m_FinalXform.m_Post.MakeID(); ember.m_FinalXform.m_Post.MakeID();
ember.m_FinalXform.m_Animate = 0; ember.m_FinalXform.m_Animate = 0;
ember.m_FinalXform.m_AnimateOrigin = 0;
ember.m_FinalXform.m_ColorSpeed = 0; ember.m_FinalXform.m_ColorSpeed = 0;
ember.m_FinalXform.m_Motion.clear(); ember.m_FinalXform.m_Motion.clear();
ember.m_FinalXform.ClearAndDeleteVariations(); ember.m_FinalXform.ClearAndDeleteVariations();
@ -925,11 +936,12 @@ public:
} }
} }
InterpXform<&Xform<T>::m_Weight> (thisXform, i, embers, coefs, size); InterpXform<&Xform<T>::m_Weight> (thisXform, i, embers, coefs, size);
InterpXform<&Xform<T>::m_ColorX> (thisXform, i, embers, coefs, size); InterpXform<&Xform<T>::m_ColorX> (thisXform, i, embers, coefs, size);
InterpXform<&Xform<T>::m_ColorSpeed>(thisXform, i, embers, coefs, size); InterpXform<&Xform<T>::m_ColorSpeed> (thisXform, i, embers, coefs, size);
InterpXform<&Xform<T>::m_Opacity> (thisXform, i, embers, coefs, size); InterpXform<&Xform<T>::m_Opacity> (thisXform, i, embers, coefs, size);
InterpXform<&Xform<T>::m_Animate> (thisXform, i, embers, coefs, size); InterpXform<&Xform<T>::m_Animate> (thisXform, i, embers, coefs, size);
InterpXform<&Xform<T>::m_AnimateOrigin> (thisXform, i, embers, coefs, size);
ClampGte0Ref(thisXform->m_Weight); ClampGte0Ref(thisXform->m_Weight);
ClampRef<T>(thisXform->m_ColorX, 0, 1); ClampRef<T>(thisXform->m_ColorX, 0, 1);
ClampRef<T>(thisXform->m_ColorSpeed, -1, 1); ClampRef<T>(thisXform->m_ColorSpeed, -1, 1);
@ -1077,15 +1089,17 @@ public:
while (auto xform = GetTotalXform(i++))//Flam3 only allowed animation with normal xforms. This has been changed to allow animations of final xforms. while (auto xform = GetTotalXform(i++))//Flam3 only allowed animation with normal xforms. This has been changed to allow animations of final xforms.
{ {
//Don't rotate xforms with animate set to 0.
if (xform->m_Animate == 0)
continue;
//Assume that if there are no variations, then it's a padding xform. //Assume that if there are no variations, then it's a padding xform.
if (xform->Empty() && m_AffineInterp != eAffineInterp::AFFINE_INTERP_LOG) if (xform->Empty() && m_AffineInterp != eAffineInterp::AFFINE_INTERP_LOG)
continue; continue;
xform->m_Affine.Rotate(angle * DEG_2_RAD_T); //Don't rotate xforms with animate set to 0.
if (xform->m_Animate != 0)
xform->m_Affine.Rotate(angle * DEG_2_RAD_T);
if (xform->m_AnimateOrigin != 0)
xform->m_Affine.RotateTrans(angle * DEG_2_RAD_T);
//Don't rotate post. //Don't rotate post.
} }
} }
@ -1139,6 +1153,7 @@ public:
m_Xforms[i].m_Weight = 1; m_Xforms[i].m_Weight = 1;
m_Xforms[i].m_ColorSpeed = 0; m_Xforms[i].m_ColorSpeed = 0;
m_Xforms[i].m_Animate = 0; m_Xforms[i].m_Animate = 0;
m_Xforms[i].m_AnimateOrigin = 0;
m_Xforms[i].m_ColorX = 1; m_Xforms[i].m_ColorX = 1;
m_Xforms[i].m_ColorY = 1;//Added in case 2D palette support is ever added. m_Xforms[i].m_ColorY = 1;//Added in case 2D palette support is ever added.
m_Xforms[i].m_Affine.A(-1); m_Xforms[i].m_Affine.A(-1);
@ -1162,6 +1177,7 @@ public:
m_Xforms[i].m_Weight = 1; m_Xforms[i].m_Weight = 1;
m_Xforms[i].m_ColorSpeed = 0; m_Xforms[i].m_ColorSpeed = 0;
m_Xforms[i].m_Animate = 0; m_Xforms[i].m_Animate = 0;
m_Xforms[i].m_AnimateOrigin = 0;
m_Xforms[i].m_ColorX = m_Xforms[i].m_ColorY = (sym < 3) ? 0 : (static_cast<T>(k - 1) / static_cast<T>(sym - 2));//Added Y. m_Xforms[i].m_ColorX = m_Xforms[i].m_ColorY = (sym < 3) ? 0 : (static_cast<T>(k - 1) / static_cast<T>(sym - 2));//Added Y.
m_Xforms[i].m_Affine.A(Round6(std::cos(k * a))); m_Xforms[i].m_Affine.A(Round6(std::cos(k * a)));
m_Xforms[i].m_Affine.D(Round6(std::sin(k * a))); m_Xforms[i].m_Affine.D(Round6(std::sin(k * a)));
@ -1409,6 +1425,10 @@ public:
APP_FMP(m_BlurCurve); APP_FMP(m_BlurCurve);
break; break;
case eEmberMotionParam::FLAME_MOTION_SCALE:
APP_FMP(m_Zoom);
break;
case eEmberMotionParam::FLAME_MOTION_NONE: case eEmberMotionParam::FLAME_MOTION_NONE:
default: default:
break; break;
@ -1445,8 +1465,8 @@ public:
m_HighlightPower = 1; m_HighlightPower = 1;
m_K2 = 0; m_K2 = 0;
m_Background.Reset(); m_Background.Reset();
m_FinalRasW = 100; m_FinalRasW = 1920;
m_FinalRasH = 100; m_FinalRasH = 1080;
m_Supersample = 1; m_Supersample = 1;
m_SpatialFilterRadius = static_cast<T>(0.5); m_SpatialFilterRadius = static_cast<T>(0.5);
m_Zoom = 0; m_Zoom = 0;
@ -1470,11 +1490,19 @@ public:
m_TemporalSamples = 100; m_TemporalSamples = 100;
m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER; m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER;
m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG; m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG;
m_PaletteMode = ePaletteMode::PALETTE_LINEAR;
m_Interp = eInterp::EMBER_INTERP_SMOOTH;
m_Stagger = 0;
m_Rotations = 1;
m_SecondsPerRotation = 3;
m_RotateXformsCw = false;
m_BlendSeconds = 3;
m_RotationsPerBlend = 0;
m_BlendRotateXformsCw = false;
m_Linear = false;
m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER; m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
m_TemporalFilterWidth = 1; m_TemporalFilterWidth = 1;
m_TemporalFilterExp = 1; m_TemporalFilterExp = 1;
m_PaletteMode = ePaletteMode::PALETTE_LINEAR;
m_Interp = eInterp::EMBER_INTERP_SMOOTH;
} }
else else
{ {
@ -1507,11 +1535,19 @@ public:
m_TemporalSamples = 0; m_TemporalSamples = 0;
m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER; m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER;
m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG; m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG;
m_PaletteMode = ePaletteMode::PALETTE_STEP;
m_Interp = eInterp::EMBER_INTERP_LINEAR;
m_Stagger = 999999;
m_Rotations = 999999;
m_SecondsPerRotation = 999999;
m_RotateXformsCw = false;
m_BlendSeconds = 999999;
m_RotationsPerBlend = 999999;
m_BlendRotateXformsCw = false;
m_Linear = false;
m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER; m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
m_TemporalFilterWidth = -1; m_TemporalFilterWidth = -1;
m_TemporalFilterExp = -999; m_TemporalFilterExp = -999;
m_PaletteMode = ePaletteMode::PALETTE_STEP;
m_Interp = eInterp::EMBER_INTERP_LINEAR;
} }
m_Xforms.clear(); m_Xforms.clear();
@ -1578,6 +1614,13 @@ public:
<< "DE Curve: " << m_CurveDE << "\n" << "DE Curve: " << m_CurveDE << "\n"
<< "Spatial Filter Type: " << m_SpatialFilterType << "\n" << "Spatial Filter Type: " << m_SpatialFilterType << "\n"
<< "Spatial Filter Radius: " << m_SpatialFilterRadius << "\n" << "Spatial Filter Radius: " << m_SpatialFilterRadius << "\n"
<< "Stagger: " << m_Stagger << "\n"
<< "Rotations: " << m_Rotations << "\n"
<< "Seconds Per Rotation: " << m_SecondsPerRotation << "\n"
<< "Rotate Xforms Clockwise: " << m_RotateXformsCw << "\n"
<< "Blend Seconds: " << m_BlendSeconds << "\n"
<< "Rotations Per Blend: " << m_RotationsPerBlend << "\n"
<< "Blend Rotate Xforms Clockwise: " << m_BlendRotateXformsCw << "\n"
<< "Temporal Filter Type: " << m_TemporalFilterType << "\n" << "Temporal Filter Type: " << m_TemporalFilterType << "\n"
<< "Temporal Filter Width: " << m_TemporalFilterWidth << "\n" << "Temporal Filter Width: " << m_TemporalFilterWidth << "\n"
<< "Temporal Filter Exp: " << m_TemporalFilterExp << "\n" << "Temporal Filter Exp: " << m_TemporalFilterExp << "\n"
@ -1754,20 +1797,6 @@ public:
//Xml field: "palette_interpolation". //Xml field: "palette_interpolation".
ePaletteInterp m_PaletteInterp = ePaletteInterp::INTERP_HSV; ePaletteInterp m_PaletteInterp = ePaletteInterp::INTERP_HSV;
//Temporal Filter.
//Only used if temporal filter type is exp, else unused.
//Xml field: "temporal_filter_exp".
T m_TemporalFilterExp = 1;
//The width of the temporal filter.
//Xml field: "temporal_filter_width".
T m_TemporalFilterWidth = 1;
//The type of the temporal filter: Gaussian, Box or Exp.
//Xml field: "temporal_filter_type".
eTemporalFilterType m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
//Density Estimation Filter. //Density Estimation Filter.
//The minimum radius of the DE filter. //The minimum radius of the DE filter.
@ -1825,6 +1854,30 @@ public:
//The 0-based position of this ember in the file it was contained in. //The 0-based position of this ember in the file it was contained in.
size_t m_Index = 0; size_t m_Index = 0;
//The parameters for animating.
double m_Stagger = 0;
double m_Rotations = 1;
double m_SecondsPerRotation = 3;
bool m_RotateXformsCw = false;
double m_BlendSeconds = 3;
size_t m_RotationsPerBlend = 0;//Could this ever be double?
bool m_BlendRotateXformsCw = false;
bool m_Linear = false;
//Temporal Filter.
//Only used if temporal filter type is exp, else unused.
//Xml field: "temporal_filter_exp".
T m_TemporalFilterExp = 1;
//The width of the temporal filter.
//Xml field: "temporal_filter_width".
T m_TemporalFilterWidth = 1;
//The type of the temporal filter: Gaussian, Box or Exp.
//Xml field: "temporal_filter_type".
eTemporalFilterType m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
//The list of motion elements for the top-level flame params //The list of motion elements for the top-level flame params
vector<EmberMotion<T>> m_EmberMotionElements; vector<EmberMotion<T>> m_EmberMotionElements;

View File

@ -169,7 +169,8 @@ enum class eEmberMotionParam : et//These must remain in this order forever.
FLAME_MOTION_BACKGROUND_G, FLAME_MOTION_BACKGROUND_G,
FLAME_MOTION_BACKGROUND_B, FLAME_MOTION_BACKGROUND_B,
FLAME_MOTION_VIBRANCY, FLAME_MOTION_VIBRANCY,
FLAME_MOTION_BLUR_CURVE FLAME_MOTION_BLUR_CURVE,
FLAME_MOTION_SCALE
}; };
/// <summary> /// <summary>

View File

@ -158,6 +158,14 @@ string EmberToXml<T>::ToString(Ember<T>& ember, const string& extraAttributes, s
os << " cam_pitch=\"" << ember.m_CamPitch << "\""; os << " cam_pitch=\"" << ember.m_CamPitch << "\"";
os << " cam_dof=\"" << ember.m_CamDepthBlur << "\""; os << " cam_dof=\"" << ember.m_CamDepthBlur << "\"";
os << " blur_curve=\"" << ember.m_BlurCurve << "\""; os << " blur_curve=\"" << ember.m_BlurCurve << "\"";
os << " stagger=\"" << ember.m_Stagger << "\"";
os << " rotations=\"" << ember.m_Rotations << "\"";
os << " seconds_per_rotation=\"" << ember.m_SecondsPerRotation << "\"";
os << " rotate_xforms_cw=\"" << ember.m_RotateXformsCw << "\"";
os << " blend_seconds=\"" << ember.m_BlendSeconds << "\"";
os << " rotations_per_blend=\"" << ember.m_RotationsPerBlend << "\"";
os << " blend_rotate_xforms_cw=\"" << ember.m_BlendRotateXformsCw << "\"";
os << " linear_blend=\"" << ember.m_Linear << "\"";
if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP) if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP)
os << " palette_mode=\"step\""; os << " palette_mode=\"step\"";
@ -544,6 +552,7 @@ string EmberToXml<T>::ToString(Xform<T>& xform, size_t xformCount, bool isFinal,
std::replace(s.begin(), s.end(), ' ', '_'); std::replace(s.begin(), s.end(), ' ', '_');
os << "name=\"" << s << "\" ";//Flam3 didn't do this, but Apo does. os << "name=\"" << s << "\" ";//Flam3 didn't do this, but Apo does.
os << "animate=\"" << xform.m_Animate << "\" ";//Flam3 only did this for non-final. Ember supports animating final. os << "animate=\"" << xform.m_Animate << "\" ";//Flam3 only did this for non-final. Ember supports animating final.
os << "animate_origin=\"" << xform.m_AnimateOrigin << "\" ";
} }
//Variation writing order differs slightly from the original to make it a bit more readable. //Variation writing order differs slightly from the original to make it a bit more readable.
@ -872,6 +881,10 @@ string EmberToXml<T>::ToString(const EmberMotion<T>& motion)
os << " vibrancy=\"" << motion.m_MotionParams[i].second << "\""; os << " vibrancy=\"" << motion.m_MotionParams[i].second << "\"";
break; break;
case eEmberMotionParam::FLAME_MOTION_SCALE:
os << " scale=\"" << motion.m_MotionParams[i].second << "\"";
break;
case eEmberMotionParam::FLAME_MOTION_NONE: case eEmberMotionParam::FLAME_MOTION_NONE:
default: default:
break; break;

View File

@ -832,8 +832,10 @@ public:
//If this is an asymmetric case, store the NON-symmetric angle //If this is an asymmetric case, store the NON-symmetric angle
//Check them pairwise and store the reference angle in the second //Check them pairwise and store the reference angle in the second
//to avoid overwriting if asymmetric on both sides. //to avoid overwriting if asymmetric on both sides.
sym0 = (embers[k - 1].GetXform(xfi)->m_Animate == 0 || (embers[k - 1].GetXform(xfi)->Empty() && padSymFlag)); auto xfk = embers[k].GetXform(xfi);
sym1 = (embers[k ].GetXform(xfi)->m_Animate == 0 || (embers[k ].GetXform(xfi)->Empty() && padSymFlag)); auto xfkm1 = embers[k - 1].GetXform(xfi);
sym0 = ((xfkm1->m_Animate == 0 && xfkm1->m_AnimateOrigin == 0) || (xfkm1->Empty() && padSymFlag));
sym1 = ((xfk->m_Animate == 0 && xfk->m_AnimateOrigin == 0) || (xfk->Empty() && padSymFlag));
if (sym1 && !sym0) if (sym1 && !sym0)
embers[k].GetXform(xfi)->m_Wind[col] = cxang[k - 1][col] + 2 * T(M_PI); embers[k].GetXform(xfi)->m_Wind[col] = cxang[k - 1][col] + 2 * T(M_PI);

View File

@ -656,6 +656,7 @@ public:
xform->m_ColorY = m_Rand.Frand01<T>();//Will need to update this if 2D coordinates are ever supported. xform->m_ColorY = m_Rand.Frand01<T>();//Will need to update this if 2D coordinates are ever supported.
xform->m_ColorSpeed = T(0.5); xform->m_ColorSpeed = T(0.5);
xform->m_Animate = 1; xform->m_Animate = 1;
xform->m_AnimateOrigin = T(m_Rand.RandBit());
xform->m_Affine.A(m_Rand.Frand11<T>()); xform->m_Affine.A(m_Rand.Frand11<T>());
xform->m_Affine.B(m_Rand.Frand11<T>()); xform->m_Affine.B(m_Rand.Frand11<T>());
xform->m_Affine.C(m_Rand.Frand11<T>()); xform->m_Affine.C(m_Rand.Frand11<T>());
@ -865,8 +866,8 @@ public:
{ {
auto& p = m_FinalImage[i]; auto& p = m_FinalImage[i];
m_Hist[static_cast<size_t>((p.r * res) + m_Hist[static_cast<size_t>((p.r * res) +
(p.g * res) * res + (p.g * res) * res +
(p.b * res) * res * res)]++;//A specific histogram index representing the sum of R,G,B values. (p.b * res) * res * res)]++;//A specific histogram index representing the sum of R,G,B values.
} }
for (i = 0; i < res3; i++) for (i = 0; i < res3; i++)

View File

@ -154,6 +154,7 @@ public:
m_DirectColor = static_cast<T>(xform.m_DirectColor); m_DirectColor = static_cast<T>(xform.m_DirectColor);
m_ColorSpeed = static_cast<T>(xform.m_ColorSpeed); m_ColorSpeed = static_cast<T>(xform.m_ColorSpeed);
m_Animate = static_cast<T>(xform.m_Animate); m_Animate = static_cast<T>(xform.m_Animate);
m_AnimateOrigin = static_cast<T>(xform.m_AnimateOrigin);
m_Opacity = static_cast<T>(xform.m_Opacity); m_Opacity = static_cast<T>(xform.m_Opacity);
CacheColorVals(); CacheColorVals();
m_HasPre = xform.HasPre(); m_HasPre = xform.HasPre();
@ -209,6 +210,7 @@ public:
m_Weight = 0; m_Weight = 0;
m_ColorSpeed = static_cast<T>(0.5); m_ColorSpeed = static_cast<T>(0.5);
m_Animate = 1; m_Animate = 1;
m_AnimateOrigin = 0;
m_ColorX = static_cast<T>(count & 1); m_ColorX = static_cast<T>(count & 1);
m_ColorY = 0; m_ColorY = 0;
m_DirectColor = 1; m_DirectColor = 1;
@ -235,6 +237,7 @@ public:
m_Weight = EMPTYFIELD; m_Weight = EMPTYFIELD;
m_ColorSpeed = EMPTYFIELD; m_ColorSpeed = EMPTYFIELD;
m_Animate = EMPTYFIELD; m_Animate = EMPTYFIELD;
m_AnimateOrigin = EMPTYFIELD;
m_ColorX = EMPTYFIELD; m_ColorX = EMPTYFIELD;
m_ColorY = EMPTYFIELD; m_ColorY = EMPTYFIELD;
m_DirectColor = EMPTYFIELD; m_DirectColor = EMPTYFIELD;
@ -547,6 +550,7 @@ public:
m_OneMinusColorCache = 0; m_OneMinusColorCache = 0;
m_Opacity = 1; m_Opacity = 1;
m_Animate = 0; m_Animate = 0;
m_AnimateOrigin = 0;
m_Wind[0] = 0; m_Wind[0] = 0;
m_Wind[1] = 0; m_Wind[1] = 0;
m_Name = ""; m_Name = "";
@ -800,6 +804,7 @@ public:
APPMOT(m_Opacity); APPMOT(m_Opacity);
APPMOT(m_ColorSpeed); APPMOT(m_ColorSpeed);
APPMOT(m_Animate); APPMOT(m_Animate);
APPMOT(m_AnimateOrigin);
for (size_t j = 0; j < currentMot.TotalVariationCount(); j++)//For each variation in the motion xform. for (size_t j = 0; j < currentMot.TotalVariationCount(); j++)//For each variation in the motion xform.
{ {
@ -811,8 +816,11 @@ public:
{ {
Variation<T>* newVar = motVar->Copy(); Variation<T>* newVar = motVar->Copy();
newVar->m_Weight = motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + cleanOffset)); newVar->m_Weight = motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + cleanOffset));
AddVariation(newVar);
var = newVar;//Use this below for params. if (AddVariation(newVar))
var = newVar;//Use this below for params.
else
delete newVar;
} }
else//It was present, so apply the motion func to the weight. else//It was present, so apply the motion func to the weight.
{ {
@ -821,7 +829,7 @@ public:
//At this point, we've added if needed, or just applied the motion func to the weight. //At this point, we've added if needed, or just applied the motion func to the weight.
//Now apply the motion func to the params if needed. //Now apply the motion func to the params if needed.
if (motParVar) if (var && motParVar)
{ {
auto parVar = dynamic_cast<ParametricVariation<T>*>(var); auto parVar = dynamic_cast<ParametricVariation<T>*>(var);
auto params = parVar->Params(); auto params = parVar->Params();
@ -1213,7 +1221,8 @@ public:
ss << "\nColorY: " << m_ColorY; ss << "\nColorY: " << m_ColorY;
ss << "\nDirect Color: " << m_DirectColor; ss << "\nDirect Color: " << m_DirectColor;
ss << "\nColor Speed: " << m_ColorSpeed; ss << "\nColor Speed: " << m_ColorSpeed;
ss << "\nAnimate: " << m_Animate; ss << "\nAnimate Local Rotation: " << m_Animate;
ss << "\nAnimate Origin Rotation: " << m_AnimateOrigin;
ss << "\nOpacity: " << m_Opacity; ss << "\nOpacity: " << m_Opacity;
ss << "\nWind: " << m_Wind[0] << ", " << m_Wind[1]; ss << "\nWind: " << m_Wind[0] << ", " << m_Wind[1];
ss << "\nMotion Frequency: " << m_MotionFreq; ss << "\nMotion Frequency: " << m_MotionFreq;
@ -1290,7 +1299,8 @@ public:
//C = (C + Ci) * m_ColorSpeed. //C = (C + Ci) * m_ColorSpeed.
T m_ColorSpeed; T m_ColorSpeed;
T m_Opacity;//How much of this xform is seen. Range: 0.0 (invisible) - 1.0 (totally visible). T m_Opacity;//How much of this xform is seen. Range: 0.0 (invisible) - 1.0 (totally visible).
T m_Animate;//Whether or not this xform rotates during animation. 0 means stationary, > 0 means rotate. Use T instead of bool so it can be interpolated. T m_Animate;//Whether or not this xform rotates around its center during animation. 0 means stationary, > 0 means rotate. Use T instead of bool so it can be interpolated.
T m_AnimateOrigin;//Same, but rotate around the global origin.
T m_Wind[2]; T m_Wind[2];
eMotion m_MotionFunc; eMotion m_MotionFunc;
T m_MotionFreq; T m_MotionFreq;

View File

@ -1389,6 +1389,7 @@ bool XmlToEmber<T>::ParseEmberElementFromChaos(xmlNode* emberNode, Ember<T>& cur
{ {
finalXform.m_Weight = 0; finalXform.m_Weight = 0;
finalXform.m_Animate = 0;//Do not animate final by default. finalXform.m_Animate = 0;//Do not animate final by default.
finalXform.m_AnimateOrigin = 0;
finalXform.m_ColorX = finalXform.m_ColorY = 0;//Chaotica does not support any kind of coloring for final xforms, opacity remains 1 though. 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; finalXform.m_ColorSpeed = 0;
currentEmber.SetFinalXform(finalXform); currentEmber.SetFinalXform(finalXform);
@ -1615,6 +1616,14 @@ bool XmlToEmber<T>::ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber
else if (ParseAndAssign(curAtt->name, attStr, "rand_range", currentEmber.m_RandPointRange, 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, "soloxform", soloXform, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "new_linear", newLinear, ret)) {} else if (ParseAndAssign(curAtt->name, attStr, "new_linear", newLinear, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "stagger", currentEmber.m_Stagger, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "rotations", currentEmber.m_Rotations, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "seconds_per_rotation", currentEmber.m_SecondsPerRotation, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "rotate_xforms_cw", currentEmber.m_RotateXformsCw, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "blend_seconds", currentEmber.m_BlendSeconds, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "rotations_per_blend", currentEmber.m_RotationsPerBlend, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "blend_rotate_xforms_cw", currentEmber.m_BlendRotateXformsCw, ret)) {}
else if (ParseAndAssign(curAtt->name, attStr, "linear_blend", currentEmber.m_Linear, ret)) {}
//Parse more complicated reads that have multiple possible values. //Parse more complicated reads that have multiple possible values.
else if (!Compare(curAtt->name, "interpolation")) else if (!Compare(curAtt->name, "interpolation"))
{ {
@ -1818,6 +1827,9 @@ bool XmlToEmber<T>::ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber
currentEmber.m_Curves.m_Points[3] = vals; currentEmber.m_Curves.m_Points[3] = vals;
} }
else if (!Compare(curAtt->name, "animations"))
{
}
xmlFree(attStr); xmlFree(attStr);
} }
@ -2023,6 +2035,7 @@ bool XmlToEmber<T>::ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber
{ {
Xform<T> finalXform; Xform<T> finalXform;
finalXform.m_Animate = 0;//Do not animate final by default. finalXform.m_Animate = 0;//Do not animate final by default.
finalXform.m_AnimateOrigin = 0;
if (!ParseXform(childNode, finalXform, false, fromEmber)) if (!ParseXform(childNode, finalXform, false, fromEmber))
{ {
@ -2148,6 +2161,8 @@ bool XmlToEmber<T>::ParseEmberElement(xmlNode* emberNode, Ember<T>& currentEmber
ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_RAND_RANGE, motion); ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_RAND_RANGE, motion);
else if (!Compare(curAtt->name, "vibrancy")) else if (!Compare(curAtt->name, "vibrancy"))
ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_VIBRANCY, motion); ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_VIBRANCY, motion);
else if (!Compare(curAtt->name, "scale"))
ret = ret && AttToEmberMotionFloat(att, attStr, eEmberMotionParam::FLAME_MOTION_SCALE, motion);
else if (!Compare(curAtt->name, "background")) else if (!Compare(curAtt->name, "background"))
{ {
double r = 0, g = 0, b = 0; double r = 0, g = 0, b = 0;
@ -2258,6 +2273,7 @@ bool XmlToEmber<T>::ParseXform(xmlNode* childNode, Xform<T>& xform, bool motion,
if (ParseAndAssign(curAtt->name, attStr, "weight", xform.m_Weight, success)) {} if (ParseAndAssign(curAtt->name, attStr, "weight", xform.m_Weight, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "color_speed", xform.m_ColorSpeed, success)) {} else if (ParseAndAssign(curAtt->name, attStr, "color_speed", xform.m_ColorSpeed, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "animate", xform.m_Animate, success)) {} else if (ParseAndAssign(curAtt->name, attStr, "animate", xform.m_Animate, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "animate_origin", xform.m_AnimateOrigin, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "opacity", xform.m_Opacity, success)) {} else if (ParseAndAssign(curAtt->name, attStr, "opacity", xform.m_Opacity, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "var_color", xform.m_DirectColor, success)) {} else if (ParseAndAssign(curAtt->name, attStr, "var_color", xform.m_DirectColor, success)) {}
else if (ParseAndAssign(curAtt->name, attStr, "motion_frequency", xform.m_MotionFreq, success)) {} else if (ParseAndAssign(curAtt->name, attStr, "motion_frequency", xform.m_MotionFreq, success)) {}
@ -2275,6 +2291,7 @@ bool XmlToEmber<T>::ParseXform(xmlNode* childNode, Xform<T>& xform, bool motion,
Aton(attStr, temp); Aton(attStr, temp);
xform.m_ColorSpeed = (1 - temp) / 2; xform.m_ColorSpeed = (1 - temp) / 2;
xform.m_Animate = T(temp > 0 ? 0 : 1); xform.m_Animate = T(temp > 0 ? 0 : 1);
//Ignore m_AnimateOrigin because it's new and symmetry is a legacy setting.
} }
else if (!Compare(curAtt->name, "motion_function")) else if (!Compare(curAtt->name, "motion_function"))
{ {

View File

@ -455,6 +455,8 @@ bool EmberGenome(int argc, _TCHAR* argv[], EmberOptions& opt)
return true; return true;
} }
//Note that in Fractorium, the sequence is created from the params stored in the flame file.
//Here, it's done using the values passed on the command line, which will override the values in the file.
if (opt.Sequence() != "") if (opt.Sequence() != "")
{ {
Ember<T> result; Ember<T> result;

View File

@ -932,7 +932,8 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
if (CreateControllerFromGUI(true))//Create controller if it does not exist, or if it does and the renderer is not running. if (CreateControllerFromGUI(true))//Create controller if it does not exist, or if it does and the renderer is not running.
{ {
const auto index = static_cast<int>(m_Fractorium->m_Controller->Index()) + 1; //If animating, then always start at 0 because the entire sequence usually needs to be rendered and if they need to start at a specific frame, they can use the Start At checkbox.
const auto index = m_FromSequence ? 0 : static_cast<int>(m_Fractorium->m_Controller->Index()) + 1;
#ifdef DO_DOUBLE #ifdef DO_DOUBLE
Ember<double> ed; Ember<double> ed;
EmberFile<double> efi; EmberFile<double> efi;
@ -976,7 +977,7 @@ void FractoriumFinalRenderDialog::showEvent(QShowEvent* e)
ui.FinalRenderDoAllCheckBox->setChecked(true); ui.FinalRenderDoAllCheckBox->setChecked(true);
//ui.FinalRenderDoSequenceCheckBox->setChecked(true); //ui.FinalRenderDoSequenceCheckBox->setChecked(true);
ui.FinalRenderApplyToAllCheckBox->setChecked(true); ui.FinalRenderApplyToAllCheckBox->setChecked(true);
m_PrefixEdit->setText(firstfile + "_"); //m_PrefixEdit->setText(firstfile + "_");
} }
ui.FinalRenderTextOutput->clear(); ui.FinalRenderTextOutput->clear();

View File

@ -1240,6 +1240,14 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_SupersampleSpin); w = SetTabOrder(this, w, m_SupersampleSpin);
w = SetTabOrder(this, w, m_InterpTypeCombo);//Flame animation. w = SetTabOrder(this, w, m_InterpTypeCombo);//Flame animation.
w = SetTabOrder(this, w, m_AffineInterpTypeCombo); w = SetTabOrder(this, w, m_AffineInterpTypeCombo);
w = SetTabOrder(this, w, m_RotationsSpin);
w = SetTabOrder(this, w, m_SecondsPerRotationSpin);
w = SetTabOrder(this, w, m_RotateXformsDirCombo);
w = SetTabOrder(this, w, m_BlendSecondsSpin);
w = SetTabOrder(this, w, m_RotationsPerBlendSpin);
w = SetTabOrder(this, w, m_BlendXformsRotateDirCombo);
w = SetTabOrder(this, w, m_BlendInterpTypeCombo);
w = SetTabOrder(this, w, m_StaggerSpin);
w = SetTabOrder(this, w, m_TemporalFilterWidthSpin); w = SetTabOrder(this, w, m_TemporalFilterWidthSpin);
w = SetTabOrder(this, w, m_TemporalFilterTypeCombo); w = SetTabOrder(this, w, m_TemporalFilterTypeCombo);
w = SetTabOrder(this, w, m_TemporalFilterExpSpin); w = SetTabOrder(this, w, m_TemporalFilterExpSpin);
@ -1249,24 +1257,6 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, ui.SequenceStartFlameSpinBox); w = SetTabOrder(this, w, ui.SequenceStartFlameSpinBox);
w = SetTabOrder(this, w, ui.SequenceStopFlameSpinBox); w = SetTabOrder(this, w, ui.SequenceStopFlameSpinBox);
w = SetTabOrder(this, w, ui.SequenceAllButton); w = SetTabOrder(this, w, ui.SequenceAllButton);
w = SetTabOrder(this, w, ui.SequenceRandomizeStaggerCheckBox);
w = SetTabOrder(this, w, ui.SequenceStaggerSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomStaggerMaxSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomizeRotationsCheckBox);
w = SetTabOrder(this, w, ui.SequenceRotationsSpinBox);
w = SetTabOrder(this, w, ui.SequenceRotationsCWCheckBox);
w = SetTabOrder(this, w, ui.SequenceRandomRotationsMaxSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomizeFramesPerRotCheckBox);
w = SetTabOrder(this, w, ui.SequenceFramesPerRotSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomFramesPerRotMaxSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomizeBlendFramesCheckBox);
w = SetTabOrder(this, w, ui.SequenceBlendFramesSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomBlendMaxFramesSpinBox);
w = SetTabOrder(this, w, ui.SequenceRandomizeRotationsPerBlendCheckBox);
w = SetTabOrder(this, w, ui.SequenceRotationsPerBlendSpinBox);
w = SetTabOrder(this, w, ui.SequenceRotationsPerBlendCWCheckBox);
w = SetTabOrder(this, w, ui.SequenceRotationsPerBlendMaxSpinBox);
w = SetTabOrder(this, w, ui.SequenceLinearCheckBox);
w = SetTabOrder(this, w, ui.SequenceAnimationFpsSpinBox); w = SetTabOrder(this, w, ui.SequenceAnimationFpsSpinBox);
w = SetTabOrder(this, w, ui.SequenceGenerateButton); w = SetTabOrder(this, w, ui.SequenceGenerateButton);
w = SetTabOrder(this, w, ui.SequenceRenderButton); w = SetTabOrder(this, w, ui.SequenceRenderButton);

View File

@ -210,23 +210,8 @@ public slots:
void OnSequenceOpenButtonClicked(bool checked); void OnSequenceOpenButtonClicked(bool checked);
void OnSequenceAnimateButtonClicked(bool checked); void OnSequenceAnimateButtonClicked(bool checked);
void OnSequenceClearButtonClicked(bool checked); void OnSequenceClearButtonClicked(bool checked);
void OnSequenceRandomizeStaggerCheckBoxStateChanged(int state);
void OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int state);
void OnSequenceRandomizeRotationsCheckBoxStateChanged(int state);
void OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int state);
void OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int state);
void OnSequenceStaggerSpinBoxChanged(double d);
void OnSequenceRandomStaggerMaxSpinBoxChanged(double d);
void OnSequenceStartFlameSpinBoxChanged(int d); void OnSequenceStartFlameSpinBoxChanged(int d);
void OnSequenceStopFlameSpinBoxChanged(int d); void OnSequenceStopFlameSpinBoxChanged(int d);
void OnSequenceFramesPerRotSpinBoxChanged(int d);
void OnSequenceRandomFramesPerRotMaxSpinBoxChanged(int d);
void OnSequenceRotationsSpinBoxChanged(double d);
void OnSequenceRandomRotationsMaxSpinBoxChanged(double d);
void OnSequenceBlendFramesSpinBoxChanged(int d);
void OnSequenceRandomBlendMaxFramesSpinBoxChanged(int d);
void OnSequenceRandomRotationsPerBlendSpinBoxChanged(int d);
void OnSequenceRandomRotationsPerBlendMaxSpinBoxChanged(int d);
//Params. //Params.
void OnBrightnessChanged(double d);//Color. void OnBrightnessChanged(double d);//Color.
@ -265,6 +250,14 @@ public slots:
void OnRandRangeChanged(double d); void OnRandRangeChanged(double d);
void OnQualityChanged(double d); void OnQualityChanged(double d);
void OnSupersampleChanged(int d); void OnSupersampleChanged(int d);
void OnRotationsChanged(double d);
void OnSecondsPerRotationChanged(double d);
void OnRotateXformsDirComboCurrentIndexChanged(int index);
void OnBlendSecondsChanged(double d);
void OnRotationsPerBlendChanged(int d);
void OnBlendXformsRotateDirComboCurrentIndexChanged(int index);
void OnBlendInterpTypeComboCurrentIndexChanged(int index);
void OnStaggerChanged(double d);
void OnAffineInterpTypeComboCurrentIndexChanged(int index); void OnAffineInterpTypeComboCurrentIndexChanged(int index);
void OnInterpTypeComboCurrentIndexChanged(int index); void OnInterpTypeComboCurrentIndexChanged(int index);
void OnExpChanged(double d); void OnExpChanged(double d);
@ -280,7 +273,8 @@ public slots:
void OnXformWeightChanged(double d); void OnXformWeightChanged(double d);
void OnEqualWeightButtonClicked(bool checked); void OnEqualWeightButtonClicked(bool checked);
void OnXformNameChanged(const QString& s); void OnXformNameChanged(const QString& s);
void OnXformAnimateCheckBoxStateChanged(int state); void OnXformAnimateLocalRotationCheckBoxStateChanged(int state);
void OnXformAnimateOriginRotationCheckBoxStateChanged(int state);
//Xforms Affine. //Xforms Affine.
void OnPreAffineRowDoubleClicked(int logicalIndex); void OnPreAffineRowDoubleClicked(int logicalIndex);
@ -523,8 +517,6 @@ private:
DoubleSpinBox* m_BlurCurveSpin; DoubleSpinBox* m_BlurCurveSpin;
DoubleSpinBox* m_SpatialFilterWidthSpin;//Filter. DoubleSpinBox* m_SpatialFilterWidthSpin;//Filter.
StealthComboBox* m_SpatialFilterTypeCombo; StealthComboBox* m_SpatialFilterTypeCombo;
DoubleSpinBox* m_TemporalFilterWidthSpin;
StealthComboBox* m_TemporalFilterTypeCombo;
DoubleSpinBox* m_DEFilterMinRadiusSpin; DoubleSpinBox* m_DEFilterMinRadiusSpin;
DoubleSpinBox* m_DEFilterMaxRadiusSpin; DoubleSpinBox* m_DEFilterMaxRadiusSpin;
DoubleSpinBox* m_DECurveSpin; DoubleSpinBox* m_DECurveSpin;
@ -533,8 +525,18 @@ private:
DoubleSpinBox* m_RandRangeSpin; DoubleSpinBox* m_RandRangeSpin;
DoubleSpinBox* m_QualitySpin; DoubleSpinBox* m_QualitySpin;
SpinBox* m_SupersampleSpin; SpinBox* m_SupersampleSpin;
StealthComboBox* m_InterpTypeCombo;//Animation.
StealthComboBox* m_AffineInterpTypeCombo; StealthComboBox* m_AffineInterpTypeCombo;
StealthComboBox* m_InterpTypeCombo; DoubleSpinBox* m_RotationsSpin;
DoubleSpinBox* m_SecondsPerRotationSpin;
StealthComboBox* m_RotateXformsDirCombo;
DoubleSpinBox* m_BlendSecondsSpin;
SpinBox* m_RotationsPerBlendSpin;
StealthComboBox* m_BlendXformsRotateDirCombo;
StealthComboBox* m_BlendInterpTypeCombo;
DoubleSpinBox* m_StaggerSpin;
DoubleSpinBox* m_TemporalFilterWidthSpin;
StealthComboBox* m_TemporalFilterTypeCombo;
DoubleSpinBox* m_TemporalFilterExpSpin; DoubleSpinBox* m_TemporalFilterExpSpin;
//Xforms. //Xforms.

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1709</width> <width>2048</width>
<height>1054</height> <height>1270</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -77,8 +77,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1277</width> <width>1687</width>
<height>985</height> <height>1201</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -105,7 +105,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>240</width> <width>240</width>
<height>981</height> <height>2000</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -170,7 +170,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>230</width> <width>230</width>
<height>926</height> <height>1945</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
@ -1345,18 +1345,21 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>112</height> <height>288</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>16777215</width> <width>16777215</width>
<height>112</height> <height>288</height>
</size> </size>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip">
<string/>
</property>
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::Panel</enum> <enum>QFrame::Panel</enum>
</property> </property>
@ -1387,6 +1390,9 @@
<property name="cornerButtonEnabled"> <property name="cornerButtonEnabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="rowCount">
<number>13</number>
</property>
<property name="columnCount"> <property name="columnCount">
<number>2</number> <number>2</number>
</property> </property>
@ -1427,6 +1433,49 @@
<string>Affine Interpolation</string> <string>Affine Interpolation</string>
</property> </property>
</row> </row>
<row>
<property name="text">
<string>Rotations</string>
</property>
</row>
<row>
<property name="text">
<string>Seconds/Rotation</string>
</property>
</row>
<row>
<property name="text">
<string>Rotate Xforms Dir</string>
</property>
<property name="toolTip">
<string/>
</property>
</row>
<row>
<property name="text">
<string>Blend Seconds</string>
</property>
</row>
<row>
<property name="text">
<string>Rotations/Blend</string>
</property>
</row>
<row>
<property name="text">
<string>Blend Rotate Xforms Dir</string>
</property>
</row>
<row>
<property name="text">
<string>Blend Interpolation</string>
</property>
</row>
<row>
<property name="text">
<string>Stagger</string>
</property>
</row>
<row> <row>
<property name="text"> <property name="text">
<string>Temporal Filter Width</string> <string>Temporal Filter Width</string>
@ -1466,29 +1515,108 @@
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<property name="text"> <property name="text">
<string>Temporal Filter Width</string> <string>Rotations</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The width of the temporal filter used during animation.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;However, the time bounds of whats being blended can be less than that, or even greater which means it will be blended across several sequence steps.&lt;/p&gt;&lt;p&gt;In practice, this will almost always have its default value of 1.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of times the xforms of a keyframe will do a 360 degree rotation before moving on to the next interpolation step. Note that only xforms which have the animate flag set to true will be rotated.&lt;/p&gt;&lt;p&gt;Set to 0 to omit rotation before interpolating.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<property name="text"> <property name="text">
<string>Temporal Filter Type</string> <string>Seconds/Rotation</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The type of the temporal filter used during animation.&lt;/p&gt;&lt;p&gt;The filter is an array of values equal in length to the temporal samples used during animation.&lt;/p&gt;&lt;p&gt;For each temporal step used to create motion blur between sequence frames, the palette will be multiplied by the value in the filter array at that same step position.&lt;/p&gt;&lt;p&gt;Box: All filter elements are 1, which means the palette is unchanged from its original values.&lt;/p&gt;&lt;p&gt;Gaussian: The filter values follow the shape of a Gaussian distribution: starting close to zero, increasing up to 1 at the halfway point, then falling back down to zero. This can cause the output to be darker than the original keyframes since almost every filter value is less than 1, which might not be desirable.&lt;/p&gt;&lt;p&gt;Exp: Use an exponent to shape the filter values. A value of 0 sets all filter values to 1, making it the equivalent of Box. For Exp values other than 1, the output will usually be darker than the original keyframes since almost every filter value is less than 1, which might not be desirable.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of seconds each rotation tales tp complete. Larger values give slower movement.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<property name="text">
<string>Rotate Xforms Dir</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Direction of loop rotation. Clockwise vs. counter clockwise.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="5" column="0">
<property name="text">
<string>Blend Seconds</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of seconds taken to interpolate from one keyframe to the next. Larger values give slower movement.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="5" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="6" column="0">
<property name="text">
<string>Rotations/Blend</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of times the xforms will do a 360 degree rotation while interpolating from one keyframe to the next. Note that only xforms which have the animate flag set to true will be rotated.&lt;/p&gt;&lt;p&gt;Set to 0 to omit rotation while interpolating.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="6" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="7" column="0">
<property name="text">
<string>Blend Rotate Xforms Dir</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Direction of rotation during interpolation. Clockwise vs. counter clockwise.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="8" column="0">
<property name="text">
<string>Blend Interpolation</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The method used to compute the blending distance for each step between keyframes.&lt;/p&gt;&lt;p&gt;Linear: Each step will be a linear interpolation. This option is the equivalend of the --unsmoother flag in EmberGenome.&lt;/p&gt;&lt;p&gt;Log: Steps in the beginning and end of the interpolation between keyframes will be smaller and those in the middle will be larger. This has the effect of slowing down the beginning and end portions, and speeding up the middle.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="9" column="0">
<property name="text">
<string>Stagger</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A decimal number between 0 and 1 which governs the xform interpolation behavior like so:&lt;/p&gt;&lt;p&gt; 0 (default): xforms will interpolate all at once.&lt;/p&gt;&lt;p&gt; 0.5: the interpolation of each xform is staggered so that when the first xform is half done, the second one starts, and so on.&lt;/p&gt;&lt;p&gt; 1: each xform interpolates consecutively with no overlap.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="9" column="1">
<property name="text">
<string/>
</property>
</item>
<item row="10" column="0">
<property name="text">
<string>Temporal Filter Width</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The width of the temporal filter used during animation when Render as Animation Sequence is checked. This increases rendering time and is usually not needed when rendering at a higher frame rate such as 60fps.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;However, the time bounds of whats being blended can be less than that, or even greater which means it will be blended across several sequence steps.&lt;/p&gt;&lt;p&gt;In practice, this will almost always have its default value of 1.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="11" column="0">
<property name="text">
<string>Temporal Filter Type</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The type of the temporal filter used during animation when Render as Animation Sequence is checked. This increases rendering time and is usually not needed when rendering at a higher frame rate such as 60fps.&lt;/p&gt;&lt;p&gt;The filter is an array of values equal in length to the temporal samples used during animation.&lt;/p&gt;&lt;p&gt;For each temporal step used to create motion blur between sequence frames, the palette will be multiplied by the value in the filter array at that same step position.&lt;/p&gt;&lt;p&gt;Box: All filter elements are 1, which means the palette is unchanged from its original values.&lt;/p&gt;&lt;p&gt;Gaussian: The filter values follow the shape of a Gaussian distribution: starting close to zero, increasing up to 1 at the halfway point, then falling back down to zero. This can cause the output to be darker than the original keyframes since almost every filter value is less than 1, which might not be desirable.&lt;/p&gt;&lt;p&gt;Exp: Use an exponent to shape the filter values. A value of 0 sets all filter values to 1, making it the equivalent of Box. For Exp values other than 1, the output will usually be darker than the original keyframes since almost every filter value is less than 1, which might not be desirable.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</item>
<item row="12" column="0">
<property name="text"> <property name="text">
<string>Temporal Exp Value</string> <string>Temporal Exp Value</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The exponent value when using the Exp temporal filter type.&lt;/p&gt;&lt;p&gt;0: The value for every temporal sample is 1, which makes this equivalent to the Box filter.&lt;/p&gt;&lt;p&gt;0.5: Convex curve from 0 to 1.&lt;/p&gt;&lt;p&gt;1: Straight line from 0 to 1.&lt;/p&gt;&lt;p&gt;&amp;gt; 1: Concave curve from 0 to 1, with a more gradual onset the larger the value is.&lt;/p&gt;&lt;p&gt;Otherwise unused.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The exponent value when using the Exp temporal filter type when Render as Animation Sequence is checked. This increases rendering time and is usually not needed when rendering at a higher frame rate such as 60fps.&lt;/p&gt;&lt;p&gt;0: The value for every temporal sample is 1, which makes this equivalent to the Box filter.&lt;/p&gt;&lt;p&gt;0.5: Convex curve from 0 to 1.&lt;/p&gt;&lt;p&gt;1: Straight line from 0 to 1.&lt;/p&gt;&lt;p&gt;&amp;gt; 1: Concave curve from 0 to 1, with a more gradual onset the larger the value is.&lt;/p&gt;&lt;p&gt;Otherwise unused.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</item> </item>
<item row="4" column="1"> <item row="12" column="1">
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -1880,7 +2008,7 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>310</width> <width>310</width>
<height>444</height> <height>445</height>
</size> </size>
</property> </property>
<property name="floating"> <property name="floating">
@ -2034,7 +2162,7 @@
<number>0</number> <number>0</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>2</number> <number>3</number>
</property> </property>
<item> <item>
<widget class="QRadioButton" name="XaosPasteNoneRadio"> <widget class="QRadioButton" name="XaosPasteNoneRadio">
@ -2407,7 +2535,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>860</x> <x>860</x>
<y>10</y> <y>0</y>
<width>295</width> <width>295</width>
<height>761</height> <height>761</height>
</rect> </rect>
@ -3095,7 +3223,7 @@
<x>240</x> <x>240</x>
<y>0</y> <y>0</y>
<width>301</width> <width>301</width>
<height>901</height> <height>981</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -3150,7 +3278,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>291</width> <width>291</width>
<height>869</height> <height>949</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_16"> <layout class="QVBoxLayout" name="verticalLayout_16">
@ -3547,13 +3675,59 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="AnimateXformCheckBox"> <widget class="QGroupBox" name="XformsAnimationGroupBox">
<property name="toolTip"> <property name="sizePolicy">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rotate this xform during the rotation phase when creating a sequence for animation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="text"> <property name="minimumSize">
<string>Animate</string> <size>
<width>0</width>
<height>0</height>
</size>
</property> </property>
<property name="title">
<string>Animation</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="AnimateXformLocalRotationCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rotate this xform around its local center during the rotation phase when creating a sequence for animation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Local rotation</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="AnimateXformOriginRotationCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rotate this xform around the world center during the rotation phase when creating a sequence for animation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Origin rotation</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
@ -6265,7 +6439,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>269</width> <width>269</width>
<height>650</height> <height>706</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -6325,7 +6499,7 @@
<widget class="QDockWidget" name="InfoDockWidget"> <widget class="QDockWidget" name="InfoDockWidget">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1020</x> <x>1160</x>
<y>0</y> <y>0</y>
<width>301</width> <width>301</width>
<height>881</height> <height>881</height>
@ -7272,7 +7446,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1709</width> <width>2048</width>
<height>22</height> <height>22</height>
</rect> </rect>
</property> </property>
@ -7511,8 +7685,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>418</width> <width>347</width>
<height>631</height> <height>742</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -7521,7 +7695,7 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_10" stretch="3,0,8,0"> <layout class="QVBoxLayout" name="verticalLayout_10" stretch="0,0,0,8,0">
<property name="spacing"> <property name="spacing">
<number>4</number> <number>4</number>
</property> </property>
@ -7542,162 +7716,6 @@
<property name="spacing"> <property name="spacing">
<number>4</number> <number>4</number>
</property> </property>
<item row="1" column="2">
<widget class="QPushButton" name="SequenceAllButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>33</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="SequenceRandomStaggerMaxSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Stagger max: </string>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="SequenceRandomizeRotationsCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="SequenceStaggerSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A decimal number between 0 and 1 which governs the xform interpolation behavior like so:&lt;/p&gt;&lt;p&gt; 0 (default): xforms will interpolate all at once.&lt;/p&gt;&lt;p&gt; 0.5: the interpolation of each xform is staggered so that when the first xform is half done, the second one starts, and so on.&lt;/p&gt;&lt;p&gt; 1: each xform interpolates consecutively with no overlap.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Stagger: </string>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="SequenceRandomizeRotationsPerBlendCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="0" alignment="Qt::AlignLeft">
<widget class="QCheckBox" name="SequenceRandomizeBlendFramesCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QGridLayout" name="SequenceRotationsGridLayout" rowstretch="0" columnstretch="2,1" columnminimumwidth="0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="SequenceRotationsSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of times the xforms of a keyframe will do a 360 degree rotation before moving on to the next interpolation step. Note that only xforms which have the animate flag set to true will be rotated.&lt;/p&gt;&lt;p&gt;Set to 0 to omit rotation before interpolating.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Rotations: </string>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>3.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="SequenceRotationsCWCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Direction of loop rotation. Clockwise vs. counter clockwise.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>CW</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QSpinBox" name="SequenceStartFlameSpinBox"> <widget class="QSpinBox" name="SequenceStartFlameSpinBox">
<property name="sizePolicy"> <property name="sizePolicy">
@ -7729,103 +7747,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="1" column="2">
<widget class="QSpinBox" name="SequenceRandomFramesPerRotMaxSpinBox"> <widget class="QPushButton" name="SequenceAllButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Frames per rot max: </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QSpinBox" name="SequenceRotationsPerBlendMaxSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Rot per blend max: </string>
</property>
<property name="minimum">
<number>0</number>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QGridLayout" name="SequenceBlendRotationsGridLayout" columnstretch="2,1">
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QSpinBox" name="SequenceRotationsPerBlendSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>95</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of times the xforms will do a 360 degree rotation while interpolating from one keyframe to the next. Note that only xforms which have the animate flag set to true will be rotated.&lt;/p&gt;&lt;p&gt;Set to 0 to omit rotation while interpolating.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Rot per blend: </string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="SequenceRotationsPerBlendCWCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Direction of rotation during interpolation. Clockwise vs. counter clockwise.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>CW</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="SequenceRandomizeFramesPerRotCheckBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>33</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -7836,174 +7768,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string/> <string>All</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="SequenceStopFlameSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The 0-based index of the last flame in the file to end the sequence on&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Stop flame: </string>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QDoubleSpinBox" name="SequenceRandomRotationsMaxSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Rotations max: </string>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>3.000000000000000</double>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QSpinBox" name="SequenceRandomBlendMaxFramesSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Blend frames max: </string>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>120</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="SequenceStopPreviewsButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Stop Previews</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="SequenceBlendFramesSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of frames used to interpolate from one keyframe to the next. Larger values give slower movement.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="suffix">
<string/>
</property>
<property name="prefix">
<string>Blend frames: </string>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>120</number>
</property>
</widget>
</item>
<item row="2" column="0" alignment="Qt::AlignLeft">
<widget class="QCheckBox" name="SequenceRandomizeStaggerCheckBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check any checkbox to have the value corresponding to its row be randomly selected between the values of first and second controls on that row&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Random</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="SequenceFramesPerRotSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of frames for each rotation specified by Rotations. Larger values give slower movement.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Frames per rot: </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>30</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="SequenceStartPreviewsButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Start Previews</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -8038,17 +7803,81 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="1" column="1">
<widget class="QCheckBox" name="SequenceLinearCheckBox"> <widget class="QSpinBox" name="SequenceStopFlameSpinBox">
<property name="toolTip"> <property name="sizePolicy">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The method used to compute the blending distance for each step between keyframes.&lt;/p&gt;&lt;p&gt;Checked: Each step will be a linear interpolation.&lt;/p&gt;&lt;p&gt;Unchecked: Steps in the beginning and end of the interpolation between keyframes will be smaller and those in the middle will be larger. This has the effect of slowing down the beginning and end portions, and speeding up the middle.&lt;/p&gt;&lt;p&gt;This option is the equivalend of the --unsmoother flag in EmberGenome.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="text"> <property name="maximumSize">
<string>Linear</string> <size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The 0-based index of the last flame in the file to end the sequence on&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="prefix">
<string>Stop flame: </string>
</property>
<property name="maximum">
<number>999999999</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="0" column="2">
<widget class="QPushButton" name="SequenceStopPreviewsButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Stop Previews</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="SequenceStartPreviewsButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Start Previews</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="SequenceFpsGridLayout" columnstretch="4,6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="spacing">
<number>4</number>
</property>
<item row="0" column="1">
<widget class="QProgressBar" name="SequenceProgressBar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QSpinBox" name="SequenceAnimationFpsSpinBox"> <widget class="QSpinBox" name="SequenceAnimationFpsSpinBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -8057,7 +7886,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of frames per second for preview animation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The number of frames per second in the animation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="buttonSymbols"> <property name="buttonSymbols">
<enum>QAbstractSpinBox::NoButtons</enum> <enum>QAbstractSpinBox::NoButtons</enum>
@ -8069,23 +7898,16 @@
<string>Animation FPS: </string> <string>Animation FPS: </string>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>10</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>200</number> <number>240</number>
</property> </property>
<property name="value"> <property name="value">
<number>30</number> <number>30</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="2">
<widget class="QProgressBar" name="SequenceProgressBar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@ -21,7 +21,6 @@ FractoriumEmberControllerBase::FractoriumEmberControllerBase(Fractorium* fractor
m_AnimateTimer = make_unique<QTimer>(m_Fractorium); m_AnimateTimer = make_unique<QTimer>(m_Fractorium);
m_AnimateTimer->stop(); m_AnimateTimer->stop();
m_Fractorium->connect(m_RenderRestartTimer.get(), &QTimer::timeout, [&]() { m_Fractorium->StartRenderTimer(false); });//It's ok to pass false for the first shot because creating the controller will start the preview renders. m_Fractorium->connect(m_RenderRestartTimer.get(), &QTimer::timeout, [&]() { m_Fractorium->StartRenderTimer(false); });//It's ok to pass false for the first shot because creating the controller will start the preview renders.
// XXX: why not SLOT(SequenceAnimateNextFrame())?
m_Fractorium->connect(m_AnimateTimer.get(), &QTimer::timeout, [&]() { SequenceAnimateNextFrame(); }); m_Fractorium->connect(m_AnimateTimer.get(), &QTimer::timeout, [&]() { SequenceAnimateNextFrame(); });
} }

View File

@ -160,6 +160,7 @@ public:
virtual void VibrancyChanged(double d) { } virtual void VibrancyChanged(double d) { }
virtual void HighlightPowerChanged(double d) { } virtual void HighlightPowerChanged(double d) { }
virtual void K2Changed(double d) { } virtual void K2Changed(double d) { }
virtual void BackgroundChanged(const QColor& color) { }
virtual void PaletteModeChanged(uint i) { } virtual void PaletteModeChanged(uint i) { }
virtual void WidthChanged(uint i) { } virtual void WidthChanged(uint i) { }
virtual void HeightChanged(uint i) { } virtual void HeightChanged(uint i) { }
@ -177,8 +178,6 @@ public:
virtual void BlurCurveChanged(double d) { } virtual void BlurCurveChanged(double d) { }
virtual void SpatialFilterWidthChanged(double d) { } virtual void SpatialFilterWidthChanged(double d) { }
virtual void SpatialFilterTypeChanged(const QString& text) { } virtual void SpatialFilterTypeChanged(const QString& text) { }
virtual void TemporalFilterWidthChanged(double d) { }
virtual void TemporalFilterTypeChanged(const QString& text) { }
virtual void DEFilterMinRadiusWidthChanged(double d) { } virtual void DEFilterMinRadiusWidthChanged(double d) { }
virtual void DEFilterMaxRadiusWidthChanged(double d) { } virtual void DEFilterMaxRadiusWidthChanged(double d) { }
virtual void DEFilterCurveWidthChanged(double d) { } virtual void DEFilterCurveWidthChanged(double d) { }
@ -187,21 +186,30 @@ public:
virtual void RandRangeChanged(double d) { } virtual void RandRangeChanged(double d) { }
virtual void QualityChanged(double d) { } virtual void QualityChanged(double d) { }
virtual void SupersampleChanged(int d) { } virtual void SupersampleChanged(int d) { }
virtual void AffineInterpTypeChanged(int i) { }
virtual void InterpTypeChanged(int i) { } virtual void InterpTypeChanged(int i) { }
virtual void BackgroundChanged(const QColor& color) { } virtual void AffineInterpTypeChanged(int i) { }
virtual void RotationsChanged(double d) { }
virtual void SecondsPerRotationChanged(double d) { }
virtual void RotateXformsDirChanged(uint i) { }
virtual void BlendSecondsChanged(double d) { };
virtual void RotationsPerBlendChanged(uint i) { };
virtual void BlendXformsRotateDirChanged(uint i) { }
virtual void BlendInterpTypeChanged(uint i) { };
virtual void StaggerChanged(double d) { };
virtual void TemporalFilterWidthChanged(double d) { }
virtual void TemporalFilterTypeChanged(const QString& text) { }
virtual void ExpChanged(double d) { }
virtual void ClearColorCurves(int i) { } virtual void ClearColorCurves(int i) { }
virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { } virtual void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) { }
virtual void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) { } virtual void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) { }
virtual void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) { } virtual void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) { }
virtual void ExpChanged(double d) { }
//Xforms. //Xforms.
virtual void CurrentXformComboChanged(int index) { } virtual void CurrentXformComboChanged(int index) { }
virtual void XformWeightChanged(double d) { } virtual void XformWeightChanged(double d) { }
virtual void EqualizeWeights() { } virtual void EqualizeWeights() { }
virtual void XformNameChanged(const QString& s) { } virtual void XformNameChanged(const QString& s) { }
virtual void XformAnimateChanged(int state) { } virtual void XformAnimateChangedHelper(int state, bool local) { }
virtual void FillXforms(int index = 0) { } virtual void FillXforms(int index = 0) { }
virtual void UpdateXformName(int index) { } virtual void UpdateXformName(int index) { }
@ -463,6 +471,7 @@ public:
void VibrancyChanged(double d) override; void VibrancyChanged(double d) override;
void HighlightPowerChanged(double d) override; void HighlightPowerChanged(double d) override;
void K2Changed(double d) override; void K2Changed(double d) override;
void BackgroundChanged(const QColor& col) override;
void PaletteModeChanged(uint i) override; void PaletteModeChanged(uint i) override;
void WidthChanged(uint i) override; void WidthChanged(uint i) override;
void HeightChanged(uint i) override; void HeightChanged(uint i) override;
@ -480,8 +489,6 @@ public:
void BlurCurveChanged(double d) override; void BlurCurveChanged(double d) override;
void SpatialFilterWidthChanged(double d) override; void SpatialFilterWidthChanged(double d) override;
void SpatialFilterTypeChanged(const QString& text) override; void SpatialFilterTypeChanged(const QString& text) override;
void TemporalFilterWidthChanged(double d) override;
void TemporalFilterTypeChanged(const QString& text) override;
void DEFilterMinRadiusWidthChanged(double d) override; void DEFilterMinRadiusWidthChanged(double d) override;
void DEFilterMaxRadiusWidthChanged(double d) override; void DEFilterMaxRadiusWidthChanged(double d) override;
void DEFilterCurveWidthChanged(double d) override; void DEFilterCurveWidthChanged(double d) override;
@ -490,21 +497,30 @@ public:
void RandRangeChanged(double d) override; void RandRangeChanged(double d) override;
void QualityChanged(double d) override; void QualityChanged(double d) override;
void SupersampleChanged(int d) override; void SupersampleChanged(int d) override;
void AffineInterpTypeChanged(int index) override;
void InterpTypeChanged(int index) override; void InterpTypeChanged(int index) override;
void BackgroundChanged(const QColor& col) override; void AffineInterpTypeChanged(int index) override;
void RotationsChanged(double d) override;
void SecondsPerRotationChanged(double d) override;
void RotateXformsDirChanged(uint i) override;
void BlendSecondsChanged(double d) override;
void RotationsPerBlendChanged(uint i) override;
void BlendXformsRotateDirChanged(uint i) override;
void BlendInterpTypeChanged(uint i) override;
void StaggerChanged(double d) override;
void TemporalFilterWidthChanged(double d) override;
void TemporalFilterTypeChanged(const QString& text) override;
void ExpChanged(double d) override;
void ClearColorCurves(int i) override; void ClearColorCurves(int i) override;
void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override; void ColorCurveChanged(int curveIndex, int pointInxed, const QPointF& point) override;
void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) override; void ColorCurvesPointAdded(size_t curveIndex, const QPointF& point) override;
void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) override; void ColorCurvesPointRemoved(size_t curveIndex, int pointIndex) override;
void ExpChanged(double d) override;
//Xforms. //Xforms.
void CurrentXformComboChanged(int index) override; void CurrentXformComboChanged(int index) override;
void XformWeightChanged(double d) override; void XformWeightChanged(double d) override;
void EqualizeWeights() override; void EqualizeWeights() override;
void XformNameChanged(const QString& s) override; void XformNameChanged(const QString& s) override;
void XformAnimateChanged(int state) override; void XformAnimateChangedHelper(int state, bool local) override;
void FillXforms(int index = 0) override; void FillXforms(int index = 0) override;
void UpdateXformName(int index) override; void UpdateXformName(int index) override;
void FillWithXform(Xform<T>* xform); void FillWithXform(Xform<T>* xform);

View File

@ -8,63 +8,21 @@ void Fractorium::InitLibraryUI()
{ {
ui.LibraryTree->SetMainWindow(this); ui.LibraryTree->SetMainWindow(this);
//Making the TreeItemChanged() events use a direct connection is absolutely critical. //Making the TreeItemChanged() events use a direct connection is absolutely critical.
connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::DirectConnection); connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::DirectConnection);
connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection); connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection); connect(ui.LibraryTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.SequenceTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnSequenceTreeItemChanged(QTreeWidgetItem*, int)), Qt::DirectConnection); connect(ui.SequenceTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnSequenceTreeItemChanged(QTreeWidgetItem*, int)), Qt::DirectConnection);
connect(ui.SequenceStartPreviewsButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceStartPreviewsButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceStartPreviewsButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceStartPreviewsButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceStopPreviewsButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceStopPreviewsButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceStopPreviewsButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceStopPreviewsButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceAllButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceAllButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceAllButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceAllButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceGenerateButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceGenerateButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceGenerateButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceGenerateButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceRenderButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceRenderButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceRenderButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceRenderButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceAnimateButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceAnimateButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceAnimateButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceAnimateButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceClearButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceClearButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceClearButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceClearButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceSaveButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceSaveButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceSaveButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceSaveButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceOpenButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceOpenButtonClicked(bool)), Qt::QueuedConnection); connect(ui.SequenceOpenButton, SIGNAL(clicked(bool)), this, SLOT(OnSequenceOpenButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeStaggerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeStaggerCheckBoxStateChanged(int)), Qt::QueuedConnection); connect(ui.SequenceStartFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStartFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeFramesPerRotCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int)), Qt::QueuedConnection); connect(ui.SequenceStopFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStopFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeRotationsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeRotationsCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeBlendFramesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomizeRotationsPerBlendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStaggerSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceStaggerSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomStaggerMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomStaggerMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceStartFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStartFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceStopFlameSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceStopFlameSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceFramesPerRotSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceFramesPerRotSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomFramesPerRotMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomFramesPerRotMaxSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRotationsSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRotationsSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceRandomRotationsMaxSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSequenceRandomRotationsMaxSpinBoxChanged(double)), Qt::QueuedConnection);
connect(ui.SequenceBlendFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceBlendFramesSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRandomBlendMaxFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomBlendMaxFramesSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRotationsPerBlendSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomRotationsPerBlendSpinBoxChanged(int)), Qt::QueuedConnection);
connect(ui.SequenceRotationsPerBlendMaxSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSequenceRandomRotationsPerBlendMaxSpinBoxChanged(int)), Qt::QueuedConnection);
//Stagger
ui.SequenceStaggerSpinBox->setValue(m_Settings->Stagger());//Lower.
ui.SequenceStaggerSpinBox->setMaximum(std::numeric_limits<int>::max());//Lower max = upper.
ui.SequenceRandomStaggerMaxSpinBox->setValue(m_Settings->StaggerMax());//Upper.
ui.SequenceRandomStaggerMaxSpinBox->setMinimum(m_Settings->Stagger());//Upper min = lower max.
//Frames per rotation.
ui.SequenceFramesPerRotSpinBox->setValue(m_Settings->FramesPerRot());//Lower.
ui.SequenceFramesPerRotSpinBox->setMaximum(std::numeric_limits<int>::max());//Lower max = upper.
ui.SequenceRandomFramesPerRotMaxSpinBox->setValue(m_Settings->FramesPerRotMax());//Upper.
ui.SequenceRandomFramesPerRotMaxSpinBox->setMinimum(m_Settings->FramesPerRot());//Upper min = lower max.
//Rotations.
ui.SequenceRotationsSpinBox->setValue(m_Settings->Rotations());//Lower.
ui.SequenceRotationsSpinBox->setMaximum(std::numeric_limits<int>::max());//Lower max = upper.
ui.SequenceRandomRotationsMaxSpinBox->setValue(m_Settings->RotationsMax());//Upper.
ui.SequenceRandomRotationsMaxSpinBox->setMinimum(m_Settings->Rotations());//Upper min = lower max.
//Blend frames.
ui.SequenceBlendFramesSpinBox->setValue(m_Settings->BlendFrames());//Lower.
ui.SequenceBlendFramesSpinBox->setMaximum(std::numeric_limits<int>::max());//Lower max = upper.
ui.SequenceRandomBlendMaxFramesSpinBox->setValue(m_Settings->BlendFramesMax());//Upper.
ui.SequenceRandomBlendMaxFramesSpinBox->setMinimum(m_Settings->BlendFrames());//Upper min = lower max.
//Rotations per blend.
ui.SequenceRotationsPerBlendSpinBox->setValue(m_Settings->RotationsPerBlend());//Lower.
ui.SequenceRotationsPerBlendSpinBox->setMaximum(std::numeric_limits<int>::max());//Lower max = upper.
ui.SequenceRotationsPerBlendMaxSpinBox->setValue(m_Settings->RotationsPerBlendMax());//Upper.
ui.SequenceRotationsPerBlendMaxSpinBox->setMinimum(m_Settings->RotationsPerBlend());//Upper min = lower max.
//Linear.
ui.SequenceLinearCheckBox->setChecked(m_Settings->Linear());
//Animation FPS. //Animation FPS.
ui.SequenceAnimationFpsSpinBox->setValue(m_Settings->AnimationFps()); ui.SequenceAnimationFpsSpinBox->setValue(m_Settings->AnimationFps());
} }
@ -597,7 +555,6 @@ void FractoriumEmberController<T>::RenderSequencePreviews(uint start, uint end)
{ {
RenderPreviews(m_Fractorium->ui.SequenceTree, m_SequencePreviewRenderer.get(), m_SequenceFile, start, end); RenderPreviews(m_Fractorium->ui.SequenceTree, m_SequencePreviewRenderer.get(), m_SequenceFile, start, end);
} }
void Fractorium::OnSequenceStartPreviewsButtonClicked(bool checked) { m_Controller->RenderSequencePreviews(); } void Fractorium::OnSequenceStartPreviewsButtonClicked(bool checked) { m_Controller->RenderSequencePreviews(); }
/// <summary> /// <summary>
@ -630,7 +587,6 @@ void Fractorium::SyncFileCountToSequenceCount()
ui.SequenceStopFlameSpinBox->setValue(count); ui.SequenceStopFlameSpinBox->setValue(count);
} }
} }
void Fractorium::OnSequenceAllButtonClicked(bool checked) { SyncFileCountToSequenceCount(); } void Fractorium::OnSequenceAllButtonClicked(bool checked) { SyncFileCountToSequenceCount(); }
/// <summary> /// <summary>
@ -649,36 +605,13 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
Ember<T> result; Ember<T> result;
auto& ui = m_Fractorium->ui; auto& ui = m_Fractorium->ui;
auto s = m_Fractorium->m_Settings; auto s = m_Fractorium->m_Settings;
//Bools for determining whether to use hard coded vs. random values.
const bool randStagger = ui.SequenceRandomizeStaggerCheckBox->isChecked();
const bool randFramesRot = ui.SequenceRandomizeFramesPerRotCheckBox->isChecked();
const bool randRot = ui.SequenceRandomizeRotationsCheckBox->isChecked();
const bool randBlend = ui.SequenceRandomizeBlendFramesCheckBox->isChecked();
const bool randBlendRot = ui.SequenceRandomizeRotationsPerBlendCheckBox->isChecked();
//The direction to rotate the loops.
const bool loopsCw = ui.SequenceRotationsCWCheckBox->isChecked();
const bool loopsBlendCw = ui.SequenceRotationsPerBlendCWCheckBox->isChecked();
//Whether to stagger, default is 1 which means no stagger.
const double stagger = ui.SequenceStaggerSpinBox->value();
const double staggerMax = ui.SequenceRandomStaggerMaxSpinBox->value();
//Rotations on keyframes.
const double rots = ui.SequenceRotationsSpinBox->value();
const double rotsMax = ui.SequenceRandomRotationsMaxSpinBox->value();
//Number of frames it takes to rotate a keyframe.
const int framesPerRot = ui.SequenceFramesPerRotSpinBox->value();
const int framesPerRotMax = ui.SequenceRandomFramesPerRotMaxSpinBox->value();
//Number of frames it takes to interpolate.
const int framesBlend = ui.SequenceBlendFramesSpinBox->value();
const int framesBlendMax = ui.SequenceRandomBlendMaxFramesSpinBox->value();
//Number of rotations performed during interpolation. //Number of rotations performed during interpolation.
const int rotsPerBlend = ui.SequenceRotationsPerBlendSpinBox->value();
const int rotsPerBlendMax = ui.SequenceRotationsPerBlendMaxSpinBox->value();
const size_t start = ui.SequenceStartFlameSpinBox->value(); const size_t start = ui.SequenceStartFlameSpinBox->value();
const size_t stop = ui.SequenceStopFlameSpinBox->value(); const size_t stop = ui.SequenceStopFlameSpinBox->value();
const size_t startCount = ui.SequenceStartCountSpinBox->value(); const size_t startCount = ui.SequenceStartCountSpinBox->value();
const bool linear = ui.SequenceLinearCheckBox->isChecked();
const size_t keyFrames = (stop - start) + 1; const size_t keyFrames = (stop - start) + 1;
size_t frameCount = 0; size_t frameCount = 0;
size_t fps = ui.SequenceAnimationFpsSpinBox->value();
double frames = 0; double frames = 0;
vector<pair<size_t, size_t>> devices;//Dummy. vector<pair<size_t, size_t>> devices;//Dummy.
EmberReport emberReport; EmberReport emberReport;
@ -691,54 +624,24 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
return; return;
} }
if (!randRot && !randBlend) SheepTools<T, float> tools(palettePath, EmberCommon::CreateRenderer<T>(eRendererType::CPU_RENDERER, devices, false, 0, emberReport));
auto it = Advance(m_EmberFile.m_Embers.begin(), start);
for (size_t i = start; i <= stop && it != m_EmberFile.m_Embers.end(); i++, ++it)
{ {
if ((!rots || !framesPerRot) && !framesBlend) if ((!it->m_Rotations || !it->m_SecondsPerRotation) && !it->m_BlendSeconds)
{ {
QMessageBox::critical(m_Fractorium, "Animation sequence parameters error", QMessageBox::critical(m_Fractorium, "Animation sequence parameters error",
"Rotations and Frames per rot, or blend frames must be positive and non-zero"); "Rotations and seconds per rotation, or blend seconds must be positive and non-zero");
return; return;
} }
//if (framesPerRot > 1 && !rots)//Because framesPerRot control has a min value of 1, check greater than 1. Also don't need to check the inverse like in EmberGenome. frames += fps * it->m_SecondsPerRotation * it->m_Rotations;
//{
//QMessageBox::critical(m_Fractorium, "Animation sequence parameters error", if (i < stop)
// "Frames per rot cannot be greater than one while Rotations is zero. Setting it to 1."); frames += fps * it->m_BlendSeconds;
//ui.SequenceFramesPerRotSpinBox->setValue(1);
//return;
//}
} }
SheepTools<T, float> tools(palettePath, EmberCommon::CreateRenderer<T>(eRendererType::CPU_RENDERER, devices, false, 0, emberReport));
tools.SetSpinParams(!linear,
stagger,//Will be set again below if random is used.
0,
0,
s->Nick().toStdString(),
s->Url().toStdString(),
s->Id().toStdString(),
"",
0,
0);
if (randFramesRot)
frames = ui.SequenceRandomFramesPerRotMaxSpinBox->value();
else if (rots)
frames = ui.SequenceFramesPerRotSpinBox->value();
else
frames = 1;
if (randRot)
frames *= ui.SequenceRandomRotationsMaxSpinBox->value();
else
frames *= ui.SequenceRotationsSpinBox->value();
if (randBlend)
frames += ui.SequenceRandomBlendMaxFramesSpinBox->value();
else
frames += ui.SequenceBlendFramesSpinBox->value();
frames *= keyFrames;
frames += startCount; frames += startCount;
os << setfill('0') << setprecision(0) << fixed; os << setfill('0') << setprecision(0) << fixed;
m_SequenceFile.Clear(); m_SequenceFile.Clear();
@ -747,16 +650,38 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
size_t frame; size_t frame;
Ember<T> embers[2];//Spin needs contiguous array below, and this will also get modified, so a copy is needed to avoid modifying the embers in the original file. Ember<T> embers[2];//Spin needs contiguous array below, and this will also get modified, so a copy is needed to avoid modifying the embers in the original file.
const auto padding = streamsize(std::log10(frames)) + 1; const auto padding = streamsize(std::log10(frames)) + 1;
auto it = Advance(m_EmberFile.m_Embers.begin(), start); auto lastLoopsBlendCw = false;
it = Advance(m_EmberFile.m_Embers.begin(), start);
for (size_t i = start; i <= stop && it != m_EmberFile.m_Embers.end(); i++, ++it) for (size_t i = start; i <= stop && it != m_EmberFile.m_Embers.end(); i++, ++it)
{ {
const auto rotations = randRot ? m_Rand.Frand<double>(rots, rotsMax) : rots; //The direction to rotate the loops.
const auto loopsCw = it->m_RotateXformsCw;//ui.SequenceRotationsCWCheckBox->isChecked();
const auto loopsBlendCw = it->m_BlendRotateXformsCw;//ui.SequenceRotationsPerBlendCWCheckBox->isChecked();
//Whether to stagger, default is 1 which means no stagger.
const auto stagger = it->m_Stagger;//ui.SequenceStaggerSpinBox->value();
//Rotations on keyframes.
const auto rotations = it->m_Rotations;
//Number of frames it takes to rotate a keyframe.
const auto rotFrames = fps * (double)it->m_SecondsPerRotation;
//Number of frames it takes to interpolate.
const auto framesBlend = fps * it->m_BlendSeconds;
const auto rotsPerBlend = it->m_RotationsPerBlend;
const auto linear = it->m_Linear;
tools.SetSpinParams(!linear,
stagger,//Will be set again below if random is used.
0,
0,
s->Nick().toStdString(),
s->Url().toStdString(),
s->Id().toStdString(),
"",
0,
0);
embers[0] = *it; embers[0] = *it;
if (rotations > 0) if (rotations > 0)
{ {
const auto rotFrames = randFramesRot ? m_Rand.Frand<double>(framesPerRot, framesPerRotMax) : framesPerRot;
const auto roundFrames = size_t(std::round(rotFrames * rotations)); const auto roundFrames = size_t(std::round(rotFrames * rotations));
for (frame = 0; frame < roundFrames; frame++) for (frame = 0; frame < roundFrames; frame++)
@ -783,32 +708,29 @@ void FractoriumEmberController<T>::SequenceGenerateButtonClicked()
auto it2 = it;//Need a quick temporary to avoid modifying it, which is used in the loop. auto it2 = it;//Need a quick temporary to avoid modifying it, which is used in the loop.
embers[1] = *(++it2);//Get the next ember to be used with blending below. embers[1] = *(++it2);//Get the next ember to be used with blending below.
const auto blendFrames = randBlend ? m_Rand.Frand<double>(framesBlend, framesBlendMax) : framesBlend; const auto d = double(rotsPerBlend);
const auto d = randBlendRot ? m_Rand.Frand<double>(rotsPerBlend, rotsPerBlendMax) : double(rotsPerBlend);
const auto rpb = size_t(std::round(d)); const auto rpb = size_t(std::round(d));
if (randStagger) for (frame = 0; frame < framesBlend; frame++)
tools.Stagger(m_Rand.Frand<double>(stagger, staggerMax));
for (frame = 0; frame < blendFrames; frame++)
{ {
const auto seqFlag = frame == 0 || (frame == blendFrames - 1); const auto seqFlag = frame == 0 || (frame == framesBlend - 1);
blend = frame / double(blendFrames); blend = frame / framesBlend;
result.Clear(); result.Clear();
tools.SpinInter(&embers[0], nullptr, result, startCount + frameCount++, seqFlag, blend, rpb, loopsBlendCw); tools.SpinInter(&embers[0], nullptr, result, startCount + frameCount++, seqFlag, blend, rpb, loopsBlendCw);
FormatName(result, os, padding); FormatName(result, os, padding);
m_SequenceFile.m_Embers.push_back(result); m_SequenceFile.m_Embers.push_back(result);
} }
} }
lastLoopsBlendCw = loopsBlendCw;
} }
it = Advance(m_EmberFile.m_Embers.begin(), stop); it = Advance(m_EmberFile.m_Embers.begin(), stop);
tools.Spin(*it, nullptr, result, startCount + frameCount, 0, loopsBlendCw); tools.Spin(*it, nullptr, result, startCount + frameCount, 0, lastLoopsBlendCw);
FormatName(result, os, padding); FormatName(result, os, padding);
m_SequenceFile.m_Embers.push_back(result); m_SequenceFile.m_Embers.push_back(result);
FillSequenceTree();//The sequence has been generated, now create preview thumbnails. FillSequenceTree();//The sequence has been generated, now create preview thumbnails.
} }
void Fractorium::OnSequenceGenerateButtonClicked(bool checked) { m_Controller->SequenceGenerateButtonClicked(); } void Fractorium::OnSequenceGenerateButtonClicked(bool checked) { m_Controller->SequenceGenerateButtonClicked(); }
/// <summary> /// <summary>
@ -886,7 +808,6 @@ void FractoriumEmberController<T>::SequenceAnimateButtonClicked()
} }
} }
} }
void Fractorium::OnSequenceAnimateButtonClicked(bool checked) { m_Controller->SequenceAnimateButtonClicked(); } void Fractorium::OnSequenceAnimateButtonClicked(bool checked) { m_Controller->SequenceAnimateButtonClicked(); }
/// <summary> /// <summary>
@ -898,7 +819,6 @@ void FractoriumEmberController<T>::SequenceClearButtonClicked()
m_SequencePreviewRenderer->Stop(); m_SequencePreviewRenderer->Stop();
m_Fractorium->ui.SequenceTree->clear(); m_Fractorium->ui.SequenceTree->clear();
} }
void Fractorium::OnSequenceClearButtonClicked(bool checked) { m_Controller->SequenceClearButtonClicked(); } void Fractorium::OnSequenceClearButtonClicked(bool checked) { m_Controller->SequenceClearButtonClicked(); }
/// <summary> /// <summary>
@ -924,7 +844,6 @@ void FractoriumEmberController<T>::SequenceSaveButtonClicked()
m_Fractorium->ShowCritical("Save Failed", "Could not save sequence file, try saving to a different folder."); m_Fractorium->ShowCritical("Save Failed", "Could not save sequence file, try saving to a different folder.");
} }
} }
void Fractorium::OnSequenceSaveButtonClicked(bool checked) { m_Controller->SequenceSaveButtonClicked(); } void Fractorium::OnSequenceSaveButtonClicked(bool checked) { m_Controller->SequenceSaveButtonClicked(); }
/// <summary> /// <summary>
@ -977,79 +896,19 @@ void FractoriumEmberController<T>::SequenceOpenButtonClicked()
} }
} }
} }
void Fractorium::OnSequenceOpenButtonClicked(bool checked) { m_Controller->SequenceOpenButtonClicked(); } void Fractorium::OnSequenceOpenButtonClicked(bool checked) { m_Controller->SequenceOpenButtonClicked(); }
/// <summary>
/// Constrain all min/max spinboxes when the max spinboxes are enabled/disabled via the random checkbox.
/// </summary>
void Fractorium::OnSequenceRandomizeStaggerCheckBoxStateChanged(int state)
{
ui.SequenceRandomStaggerMaxSpinBox->setMinimum(ui.SequenceStaggerSpinBox->value());
ui.SequenceStaggerSpinBox->setMaximum(state ? ui.SequenceRandomStaggerMaxSpinBox->value() : std::numeric_limits<int>::max());
ui.SequenceRandomStaggerMaxSpinBox->setEnabled(state);
}
void Fractorium::OnSequenceRandomizeFramesPerRotCheckBoxStateChanged(int state)
{
ui.SequenceRandomFramesPerRotMaxSpinBox->setMinimum(ui.SequenceFramesPerRotSpinBox->value());
ui.SequenceFramesPerRotSpinBox->setMaximum(state ? ui.SequenceRandomFramesPerRotMaxSpinBox->value() : std::numeric_limits<int>::max());
ui.SequenceRandomFramesPerRotMaxSpinBox->setEnabled(state);
}
void Fractorium::OnSequenceRandomizeRotationsCheckBoxStateChanged(int state)
{
ui.SequenceRandomRotationsMaxSpinBox->setMinimum(ui.SequenceRotationsSpinBox->value());
ui.SequenceRotationsSpinBox->setMaximum(state ? ui.SequenceRandomRotationsMaxSpinBox->value() : std::numeric_limits<int>::max());
ui.SequenceRandomRotationsMaxSpinBox->setEnabled(state);
}
void Fractorium::OnSequenceRandomizeBlendFramesCheckBoxStateChanged(int state)
{
ui.SequenceRandomBlendMaxFramesSpinBox->setMinimum(ui.SequenceBlendFramesSpinBox->value());
ui.SequenceBlendFramesSpinBox->setMaximum(state ? ui.SequenceRandomBlendMaxFramesSpinBox->value() : std::numeric_limits<int>::max());
ui.SequenceRandomBlendMaxFramesSpinBox->setEnabled(state);
}
void Fractorium::OnSequenceRandomizeRotationsPerBlendCheckBoxStateChanged(int state)
{
ui.SequenceRotationsPerBlendMaxSpinBox->setMinimum(ui.SequenceRotationsPerBlendSpinBox->value());
ui.SequenceRotationsPerBlendSpinBox->setMaximum(state ? ui.SequenceRotationsPerBlendMaxSpinBox->value() : std::numeric_limits<int>::max());
ui.SequenceRotationsPerBlendMaxSpinBox->setEnabled(state);
}
/// <summary> /// <summary>
/// Constrain all min/max spinboxes. /// Constrain all min/max spinboxes.
/// </summary> /// </summary>
void Fractorium::OnSequenceStaggerSpinBoxChanged(double d) { if (ui.SequenceRandomizeStaggerCheckBox->isChecked()) ui.SequenceRandomStaggerMaxSpinBox->setMinimum(d); } void Fractorium::OnSequenceStartFlameSpinBoxChanged(int d) { ui.SequenceStopFlameSpinBox->setMinimum(d); }
void Fractorium::OnSequenceRandomStaggerMaxSpinBoxChanged(double d) { if (ui.SequenceRandomStaggerMaxSpinBox->hasFocus()) ui.SequenceStaggerSpinBox->setMaximum(d); } void Fractorium::OnSequenceStopFlameSpinBoxChanged(int d) { if (ui.SequenceStopFlameSpinBox->hasFocus()) ui.SequenceStartFlameSpinBox->setMaximum(d); }
void Fractorium::OnSequenceStartFlameSpinBoxChanged(int d) { ui.SequenceStopFlameSpinBox->setMinimum(d); }
void Fractorium::OnSequenceStopFlameSpinBoxChanged(int d) { if (ui.SequenceStopFlameSpinBox->hasFocus()) ui.SequenceStartFlameSpinBox->setMaximum(d); }
void Fractorium::OnSequenceFramesPerRotSpinBoxChanged(int d) { if (ui.SequenceRandomizeFramesPerRotCheckBox->isChecked()) ui.SequenceRandomFramesPerRotMaxSpinBox->setMinimum(d); }
void Fractorium::OnSequenceRandomFramesPerRotMaxSpinBoxChanged(int d) { if (ui.SequenceRandomFramesPerRotMaxSpinBox->hasFocus()) ui.SequenceFramesPerRotSpinBox->setMaximum(d); }
void Fractorium::OnSequenceRotationsSpinBoxChanged(double d) { if (ui.SequenceRandomizeRotationsCheckBox->isChecked()) ui.SequenceRandomRotationsMaxSpinBox->setMinimum(d); }
void Fractorium::OnSequenceRandomRotationsMaxSpinBoxChanged(double d) { if (ui.SequenceRandomRotationsMaxSpinBox->hasFocus()) ui.SequenceRotationsSpinBox->setMaximum(d); }
void Fractorium::OnSequenceBlendFramesSpinBoxChanged(int d) { if (ui.SequenceRandomizeBlendFramesCheckBox->isChecked()) ui.SequenceRandomBlendMaxFramesSpinBox->setMinimum(d); }
void Fractorium::OnSequenceRandomBlendMaxFramesSpinBoxChanged(int d) { if (ui.SequenceRandomBlendMaxFramesSpinBox->hasFocus()) ui.SequenceBlendFramesSpinBox->setMaximum(d); }
void Fractorium::OnSequenceRandomRotationsPerBlendSpinBoxChanged(int d) { if (ui.SequenceRandomizeRotationsPerBlendCheckBox->isChecked()) ui.SequenceRotationsPerBlendMaxSpinBox->setMinimum(d); }
void Fractorium::OnSequenceRandomRotationsPerBlendMaxSpinBoxChanged(int d) { if (ui.SequenceRotationsPerBlendMaxSpinBox->hasFocus()) ui.SequenceRotationsPerBlendSpinBox->setMaximum(d); }
/// <summary> /// <summary>
/// Save all sequence settings to match the values in the controls. /// Save all sequence settings to match the values in the controls.
/// </summary> /// </summary>
void Fractorium::SyncSequenceSettings() void Fractorium::SyncSequenceSettings()
{ {
m_Settings->Stagger(ui.SequenceStaggerSpinBox->value());
m_Settings->StaggerMax(ui.SequenceRandomStaggerMaxSpinBox->value());
m_Settings->FramesPerRot(ui.SequenceFramesPerRotSpinBox->value());
m_Settings->FramesPerRotMax(ui.SequenceRandomFramesPerRotMaxSpinBox->value());
m_Settings->Rotations(ui.SequenceRotationsSpinBox->value());
m_Settings->RotationsMax(ui.SequenceRandomRotationsMaxSpinBox->value());
m_Settings->BlendFrames(ui.SequenceBlendFramesSpinBox->value());
m_Settings->BlendFramesMax(ui.SequenceRandomBlendMaxFramesSpinBox->value());
m_Settings->RotationsPerBlend(ui.SequenceRotationsPerBlendSpinBox->value());
m_Settings->RotationsPerBlendMax(ui.SequenceRotationsPerBlendMaxSpinBox->value());
m_Settings->Linear(ui.SequenceLinearCheckBox->isChecked());
m_Settings->AnimationFps(ui.SequenceAnimationFpsSpinBox->value()); m_Settings->AnimationFps(ui.SequenceAnimationFpsSpinBox->value());
} }

View File

@ -1008,22 +1008,16 @@ void FractoriumEmberController<T>::ClearFlame()
{ {
Update([&]() Update([&]()
{ {
while (m_Ember.TotalXformCount() > 1) Xform<T> newXform;
m_Ember.DeleteTotalXform(m_Ember.TotalXformCount() - 1); newXform.m_Weight = 0.25;
newXform.m_ColorX = m_Rand.Frand01<T>();
if (m_Ember.XformCount() == 1) newXform.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
{ m_Ember.Clear();
if (auto xform = m_Ember.GetXform(0)) m_Ember.AddXform(newXform);
{ FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
xform->Clear(); FillParamTablesAndPalette();
xform->AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
xform->ParentEmber(&m_Ember);
}
}
m_Ember.m_Curves.Init();
FillXforms();
FillCurvesControl(); FillCurvesControl();
FillSummary();
}); });
} }

View File

@ -9,7 +9,8 @@ void Fractorium::InitParamsUI()
int row = 0; int row = 0;
int spinHeight = 20; int spinHeight = 20;
double dmax = numeric_limits<double>::max(); double dmax = numeric_limits<double>::max();
vector<string> comboVals; int imax = numeric_limits<int>::max();
vector<string> comboVals, llComboVals;
QTableWidget* table = ui.ColorTable; QTableWidget* table = ui.ColorTable;
//Because QTableWidget does not allow for a single title bar/header //Because QTableWidget does not allow for a single title bar/header
//at the top of a multi-column table, the workaround hack is to just //at the top of a multi-column table, the workaround hack is to just
@ -118,15 +119,29 @@ void Fractorium::InitParamsUI()
comboVals.clear(); comboVals.clear();
comboVals.push_back("Linear"); comboVals.push_back("Linear");
comboVals.push_back("Log"); comboVals.push_back("Log");
SetupCombo( table, this, row, 1, m_AffineInterpTypeCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnAffineInterpTypeComboCurrentIndexChanged(int))); llComboVals = comboVals;
SetupCombo(table, this, row, 1, m_AffineInterpTypeCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnAffineInterpTypeComboCurrentIndexChanged(int)));
m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(eAffineInterp::AFFINE_INTERP_LOG)); m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(eAffineInterp::AFFINE_INTERP_LOG));
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1, 1, 1); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_RotationsSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnRotationsChanged(double)), true, 1.0, 1.0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_SecondsPerRotationSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnSecondsPerRotationChanged(double)), true, 1.0, 1.0, 0);
comboVals.clear();
comboVals.push_back("Cw");
comboVals.push_back("Ccw");
SetupCombo(table, this, row, 1, m_RotateXformsDirCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnRotateXformsDirComboCurrentIndexChanged(int)));
m_RotateXformsDirCombo->SetCurrentIndexStealth(0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_BlendSecondsSpin, spinHeight, 0, dmax, 1, SIGNAL(valueChanged(double)), SLOT(OnBlendSecondsChanged(double)), true, 1.0, 1.0, 0);
SetupSpinner<SpinBox, int>( table, this, row, 1, m_RotationsPerBlendSpin, spinHeight, 0, imax, 1, SIGNAL(valueChanged(int)), SLOT(OnRotationsPerBlendChanged(int)), true, 0, 1, 0);
SetupCombo(table, this, row, 1, m_BlendXformsRotateDirCombo, comboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnBlendXformsRotateDirComboCurrentIndexChanged(int)));
m_BlendXformsRotateDirCombo->SetCurrentIndexStealth(0);
SetupCombo(table, this, row, 1, m_BlendInterpTypeCombo, llComboVals, SIGNAL(currentIndexChanged(int)), SLOT(OnBlendInterpTypeComboCurrentIndexChanged(int)));
m_BlendInterpTypeCombo->SetCurrentIndexStealth(1);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_StaggerSpin, spinHeight, 0, 1, 0.1, SIGNAL(valueChanged(double)), SLOT(OnStaggerChanged(double)), true, 0, 1.0, 0);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterWidthSpin, spinHeight, 1, 10, 1, SIGNAL(valueChanged(double)), SLOT(OnTemporalFilterWidthChanged(double)), true, 1, 1, 1);
comboVals = TemporalFilterCreator<float>::FilterTypes(); comboVals = TemporalFilterCreator<float>::FilterTypes();
SetupCombo( table, this, row, 1, m_TemporalFilterTypeCombo, comboVals, SIGNAL(currentTextChanged(const QString&)), SLOT(OnTemporalFilterTypeComboCurrentIndexChanged(const QString&))); SetupCombo(table, this, row, 1, m_TemporalFilterTypeCombo, comboVals, SIGNAL(currentTextChanged(const QString&)), SLOT(OnTemporalFilterTypeComboCurrentIndexChanged(const QString&)));
m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(eTemporalFilterType::BOX_TEMPORAL_FILTER)); m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(eTemporalFilterType::BOX_TEMPORAL_FILTER));
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterExpSpin, spinHeight, 0, 5, 0.1, SIGNAL(valueChanged(double)), SLOT(OnExpChanged(double)), true, 1, 1, 0); SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_TemporalFilterExpSpin, spinHeight, 0, 5, 0.1, SIGNAL(valueChanged(double)), SLOT(OnExpChanged(double)), true, 1, 1, 0);
//
AddSizePreset("HD", 1920, 1080); AddSizePreset("HD", 1920, 1080);
AddSizePreset("QHD", 2560, 1440); AddSizePreset("QHD", 2560, 1440);
AddSizePreset("4K UHD", 3840, 2160); AddSizePreset("4K UHD", 3840, 2160);
@ -198,7 +213,7 @@ bool Fractorium::ApplyAll()
/// <summary> /// <summary>
/// Set the brightness to be used for calculating K1 and K2 for filtering and final accum. /// Set the brightness to be used for calculating K1 and K2 for filtering and final accum.
/// Called when brightness spinner is changed. /// Called when the brightness spinner is changed.
/// Resets the rendering process to the filtering stage. /// Resets the rendering process to the filtering stage.
/// </summary> /// </summary>
/// <param name="d">The brightness</param> /// <param name="d">The brightness</param>
@ -210,12 +225,11 @@ void FractoriumEmberController<T>::BrightnessChanged(double d)
ember.m_Brightness = d; ember.m_Brightness = d;
}, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll()); }, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll());
} }
void Fractorium::OnBrightnessChanged(double d) { m_Controller->BrightnessChanged(d); } void Fractorium::OnBrightnessChanged(double d) { m_Controller->BrightnessChanged(d); }
/// <summary> /// <summary>
/// Set the gamma to be used for final accum. /// Set the gamma to be used for final accum.
/// Called when gamma spinner is changed. /// Called when the gamma spinner is changed.
/// Resets the rendering process if temporal samples is greater than 1, /// Resets the rendering process if temporal samples is greater than 1,
/// else if early clip is true, filter and accum, else final accum only. /// else if early clip is true, filter and accum, else final accum only.
/// </summary> /// </summary>
@ -231,7 +245,7 @@ void Fractorium::OnGammaChanged(double d) { m_Controller->GammaChanged(d); }
/// <summary> /// <summary>
/// Set the gamma threshold to be used for final accum. /// Set the gamma threshold to be used for final accum.
/// Called when gamma threshold spinner is changed. /// Called when the gamma threshold spinner is changed.
/// Resets the rendering process to the final accumulation stage. /// Resets the rendering process to the final accumulation stage.
/// </summary> /// </summary>
/// <param name="d">The gamma threshold</param> /// <param name="d">The gamma threshold</param>
@ -246,7 +260,7 @@ void Fractorium::OnGammaThresholdChanged(double d) { m_Controller->GammaThreshol
/// <summary> /// <summary>
/// Set the vibrancy to be used for final accum. /// Set the vibrancy to be used for final accum.
/// Called when vibrancy spinner is changed. /// Called when the vibrancy spinner is changed.
/// Resets the rendering process to the final accumulation stage if temporal samples is 1, else full reset. /// Resets the rendering process to the final accumulation stage if temporal samples is 1, else full reset.
/// </summary> /// </summary>
/// <param name="d">The vibrancy</param> /// <param name="d">The vibrancy</param>
@ -261,7 +275,7 @@ void Fractorium::OnVibrancyChanged(double d) { m_Controller->VibrancyChanged(d);
/// <summary> /// <summary>
/// Set the highlight power to be used for final accum. /// Set the highlight power to be used for final accum.
/// Called when highlight power spinner is changed. /// Called when the highlight power spinner is changed.
/// Resets the rendering process to the final accumulation stage. /// Resets the rendering process to the final accumulation stage.
/// </summary> /// </summary>
/// <param name="d">The highlight power</param> /// <param name="d">The highlight power</param>
@ -276,7 +290,7 @@ void Fractorium::OnHighlightPowerChanged(double d) { m_Controller->HighlightPowe
/// <summary> /// <summary>
/// Set the k2 brightness value to be used for final accum. /// Set the k2 brightness value to be used for final accum.
/// Called when k2 is changed. /// Called when the k2 spinner is changed.
/// Resets the rendering process to the final accumulation stage. /// Resets the rendering process to the final accumulation stage.
/// </summary> /// </summary>
/// <param name="d">The k2 value</param> /// <param name="d">The k2 value</param>
@ -287,12 +301,11 @@ template <typename T> void FractoriumEmberController<T>::K2Changed(double d)
ember.m_K2 = d; ember.m_K2 = d;
}, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll()); }, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll());
} }
void Fractorium::OnK2Changed(double d) { m_Controller->K2Changed(d); } void Fractorium::OnK2Changed(double d) { m_Controller->K2Changed(d); }
/// <summary> /// <summary>
/// Show the color selection dialog. /// Show the color selection dialog.
/// Called when background color button is clicked. /// Called when the background color button is clicked.
/// </summary> /// </summary>
/// <param name="checked">Ignored</param> /// <param name="checked">Ignored</param>
void Fractorium::OnBackgroundColorButtonClicked(bool checked) void Fractorium::OnBackgroundColorButtonClicked(bool checked)
@ -326,12 +339,11 @@ void FractoriumEmberController<T>::BackgroundChanged(const QColor& color)
ember.m_Background.b = color.blue() / 255.0; ember.m_Background.b = color.blue() / 255.0;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
} }
void Fractorium::OnColorSelected(const QColor& color) { m_Controller->BackgroundChanged(color); } void Fractorium::OnColorSelected(const QColor& color) { m_Controller->BackgroundChanged(color); }
/// <summary> /// <summary>
/// Set the palette index interpolation mode. /// Set the palette index interpolation mode.
/// Called when palette mode combo box index is changed. /// Called when the palette mode combo box index is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="index">The index of the palette mode combo box</param> /// <param name="index">The index of the palette mode combo box</param>
@ -361,7 +373,6 @@ template <typename T> void FractoriumEmberController<T>::WidthChanged(uint i)
ember.m_FinalRasW = i; ember.m_FinalRasW = i;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
} }
void Fractorium::OnWidthChanged(int i) { m_Controller->WidthChanged(i); } void Fractorium::OnWidthChanged(int i) { m_Controller->WidthChanged(i); }
/// <summary> /// <summary>
@ -377,7 +388,6 @@ template <typename T> void FractoriumEmberController<T>::HeightChanged(uint i)
ember.m_FinalRasH = i; ember.m_FinalRasH = i;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
} }
void Fractorium::OnHeightChanged(int i) { m_Controller->HeightChanged(i); } void Fractorium::OnHeightChanged(int i) { m_Controller->HeightChanged(i); }
/// <summary> /// <summary>
@ -476,7 +486,7 @@ void Fractorium::OnCenterYChanged(double d) { m_Controller->CenterYChanged(d); }
/// Set the scale (pixels per unit) value of the image. /// Set the scale (pixels per unit) value of the image.
/// Note this will not increase the number of iters ran, but will degrade quality. /// Note this will not increase the number of iters ran, but will degrade quality.
/// To preserve quality, but exponentially increase iters, use zoom. /// To preserve quality, but exponentially increase iters, use zoom.
/// Called when scale spinner is changed. /// Called when the scale spinner is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The scale value</param> /// <param name="d">The scale value</param>
@ -493,7 +503,7 @@ void Fractorium::OnScaleChanged(double d) { m_Controller->ScaleChanged(d); }
/// Set the zoom value of the image. /// Set the zoom value of the image.
/// Note this will increase the number of iters ran exponentially. /// Note this will increase the number of iters ran exponentially.
/// To zoom in without increasing iters, but sacrifice quality, use scale. /// To zoom in without increasing iters, but sacrifice quality, use scale.
/// Called when zoom spinner is changed. /// Called when the zoom spinner is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The zoom value</param> /// <param name="d">The zoom value</param>
@ -508,10 +518,10 @@ void Fractorium::OnZoomChanged(double d) { m_Controller->ZoomChanged(d); }
/// <summary> /// <summary>
/// Set the angular rotation of the image. /// Set the angular rotation of the image.
/// Called when rotate spinner is changed. /// Called when the rotate spinner is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The rotation in angles</param> /// <param name="d">The rotation in degrees</param>
template <typename T> void FractoriumEmberController<T>::RotateChanged(double d) template <typename T> void FractoriumEmberController<T>::RotateChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -519,11 +529,14 @@ template <typename T> void FractoriumEmberController<T>::RotateChanged(double d)
ember.m_Rotate = d; ember.m_Rotate = d;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
} }
void Fractorium::OnRotateChanged(double d) void Fractorium::OnRotateChanged(double d) { m_Controller->RotateChanged(d); }
{
m_Controller->RotateChanged(d); // d is ever between -180 and +180
}
/// <summary>
/// Set the 3D z position of the image.
/// Called when the 3D zpos spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D zpos in world space units</param>
template <typename T> void FractoriumEmberController<T>::ZPosChanged(double d) template <typename T> void FractoriumEmberController<T>::ZPosChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -533,6 +546,12 @@ template <typename T> void FractoriumEmberController<T>::ZPosChanged(double d)
} }
void Fractorium::OnZPosChanged(double d) { m_Controller->ZPosChanged(d); } void Fractorium::OnZPosChanged(double d) { m_Controller->ZPosChanged(d); }
/// <summary>
/// Set the 3D persepctive of the image.
/// Called when the 3D persepctive spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D perspective in world space units</param>
template <typename T> void FractoriumEmberController<T>::PerspectiveChanged(double d) template <typename T> void FractoriumEmberController<T>::PerspectiveChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -542,6 +561,12 @@ template <typename T> void FractoriumEmberController<T>::PerspectiveChanged(doub
} }
void Fractorium::OnPerspectiveChanged(double d) { m_Controller->PerspectiveChanged(d); } void Fractorium::OnPerspectiveChanged(double d) { m_Controller->PerspectiveChanged(d); }
/// <summary>
/// Set the 3D pitch of the image.
/// Called when the 3D pitch spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D pitch in degrees</param>
template <typename T> void FractoriumEmberController<T>::PitchChanged(double d) template <typename T> void FractoriumEmberController<T>::PitchChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -551,6 +576,12 @@ template <typename T> void FractoriumEmberController<T>::PitchChanged(double d)
} }
void Fractorium::OnPitchChanged(double d) { m_Controller->PitchChanged(d); } void Fractorium::OnPitchChanged(double d) { m_Controller->PitchChanged(d); }
/// <summary>
/// Set the 3D yaw of the image.
/// Called when the 3D yaw spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D yaw in degrees</param>
template <typename T> void FractoriumEmberController<T>::YawChanged(double d) template <typename T> void FractoriumEmberController<T>::YawChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -560,6 +591,12 @@ template <typename T> void FractoriumEmberController<T>::YawChanged(double d)
} }
void Fractorium::OnYawChanged(double d) { m_Controller->YawChanged(d); } void Fractorium::OnYawChanged(double d) { m_Controller->YawChanged(d); }
/// <summary>
/// Set the 3D depth blur of the image.
/// Called when the 3D depth blur spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D depth blur</param>
template <typename T> void FractoriumEmberController<T>::DepthBlurChanged(double d) template <typename T> void FractoriumEmberController<T>::DepthBlurChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -569,6 +606,12 @@ template <typename T> void FractoriumEmberController<T>::DepthBlurChanged(double
} }
void Fractorium::OnDepthBlurChanged(double d) { m_Controller->DepthBlurChanged(d); } void Fractorium::OnDepthBlurChanged(double d) { m_Controller->DepthBlurChanged(d); }
/// <summary>
/// Set the 3D blur curve used to calculate the 3D depth blur of the image.
/// Called when the blur curve spinner is changed.
/// Resets the rendering process.
/// </summary>
/// <param name="d">The 3D blur curve</param>
template <typename T> void FractoriumEmberController<T>::BlurCurveChanged(double d) template <typename T> void FractoriumEmberController<T>::BlurCurveChanged(double d)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
@ -595,7 +638,6 @@ template <typename T> void FractoriumEmberController<T>::SpatialFilterWidthChang
ember.m_SpatialFilterRadius = d; ember.m_SpatialFilterRadius = d;
}, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll()); }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll());
} }
void Fractorium::OnSpatialFilterWidthChanged(double d) { m_Controller->SpatialFilterWidthChanged(d); } void Fractorium::OnSpatialFilterWidthChanged(double d) { m_Controller->SpatialFilterWidthChanged(d); }
/// <summary> /// <summary>
@ -611,7 +653,6 @@ template <typename T> void FractoriumEmberController<T>::SpatialFilterTypeChange
ember.m_SpatialFilterType = SpatialFilterCreator<T>::FromString(text.toStdString()); ember.m_SpatialFilterType = SpatialFilterCreator<T>::FromString(text.toStdString());
}, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll()); }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll());
} }
void Fractorium::OnSpatialFilterTypeComboCurrentIndexChanged(const QString& text) { m_Controller->SpatialFilterTypeChanged(text); } void Fractorium::OnSpatialFilterTypeComboCurrentIndexChanged(const QString& text) { m_Controller->SpatialFilterTypeChanged(text); }
/// <summary> /// <summary>
@ -672,7 +713,6 @@ template <typename T> void FractoriumEmberController<T>::DEFilterCurveWidthChang
ember.m_CurveDE = d; ember.m_CurveDE = d;
}, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll()); }, true, eProcessAction::FILTER_AND_ACCUM, m_Fractorium->ApplyAll());
} }
void Fractorium::OnDEFilterCurveWidthChanged(double d) { m_Controller->DEFilterCurveWidthChanged(d); } void Fractorium::OnDEFilterCurveWidthChanged(double d) { m_Controller->DEFilterCurveWidthChanged(d); }
/// <summary> /// <summary>
@ -707,7 +747,6 @@ template <typename T> void FractoriumEmberController<T>::RandRangeChanged(double
ember.m_RandPointRange = d; ember.m_RandPointRange = d;
}, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll());
} }
void Fractorium::OnRandRangeChanged(double d) { m_Controller->RandRangeChanged(d); } void Fractorium::OnRandRangeChanged(double d) { m_Controller->RandRangeChanged(d); }
/// <summary> /// <summary>
@ -758,6 +797,35 @@ template <typename T> void FractoriumEmberController<T>::SupersampleChanged(int
} }
void Fractorium::OnSupersampleChanged(int d) { m_Controller->SupersampleChanged(d); } void Fractorium::OnSupersampleChanged(int d) { m_Controller->SupersampleChanged(d); }
/// <summary>
/// Set the interpolation type.
/// Does not reset anything because this is only used for animation.
/// Called when the interp type combo box index is changed.
/// </summary>
/// <param name="i">The index</param>
template <typename T>
void FractoriumEmberController<T>::InterpTypeChanged(int i)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
eInterp interp;
if (i == 0)
interp = eInterp::EMBER_INTERP_LINEAR;
else if (i == 1)
interp = eInterp::EMBER_INTERP_SMOOTH;
else
interp = eInterp::EMBER_INTERP_LINEAR;
ember.m_Interp = interp;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_Interp = interp;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnInterpTypeComboCurrentIndexChanged(int index) { m_Controller->InterpTypeChanged(index); }
/// <summary> /// <summary>
/// Set the affine interpolation type. /// Set the affine interpolation type.
/// Does not reset anything because this is only used for animation. /// Does not reset anything because this is only used for animation.
@ -786,38 +854,159 @@ void FractoriumEmberController<T>::AffineInterpTypeChanged(int i)
m_EmberFilePointer->m_AffineInterp = interp; m_EmberFilePointer->m_AffineInterp = interp;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll()); }, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
} }
void Fractorium::OnAffineInterpTypeComboCurrentIndexChanged(int index) { m_Controller->AffineInterpTypeChanged(index); } void Fractorium::OnAffineInterpTypeComboCurrentIndexChanged(int index) { m_Controller->AffineInterpTypeChanged(index); }
/// <summary> /// <summary>
/// Set the interpolation type. /// Set the rotations to be used in animation.
/// Called when the rotations spinner is changed.
/// Does not reset anything because this is only used for animation. /// Does not reset anything because this is only used for animation.
/// Called when the interp type combo box index is changed.
/// </summary> /// </summary>
/// <param name="i">The index</param> /// <param name="d">The number of rotations to perform in a loop</param>
template <typename T> template <typename T> void FractoriumEmberController<T>::RotationsChanged(double d)
void FractoriumEmberController<T>::InterpTypeChanged(int i)
{ {
UpdateAll([&](Ember<T>& ember, bool isMain) UpdateAll([&](Ember<T>& ember, bool isMain)
{ {
eInterp interp; ember.m_Rotations = d;
if (i == 0)
interp = eInterp::EMBER_INTERP_LINEAR;
else if (i == 1)
interp = eInterp::EMBER_INTERP_SMOOTH;
else
interp = eInterp::EMBER_INTERP_LINEAR;
ember.m_Interp = interp;
if (!m_Fractorium->ApplyAll()) if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer) if (m_EmberFilePointer)
m_EmberFilePointer->m_Interp = interp; m_EmberFilePointer->m_Rotations = d;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll()); }, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
} }
void Fractorium::OnRotationsChanged(double d) { m_Controller->RotationsChanged(d); }
void Fractorium::OnInterpTypeComboCurrentIndexChanged(int index) { m_Controller->InterpTypeChanged(index); } /// <summary>
/// Set the seconds each loop rotation takes in animation.
/// Called when the seconds per rotation spinner is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The number of seconds each loop rotation should take</param>
template <typename T> void FractoriumEmberController<T>::SecondsPerRotationChanged(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_SecondsPerRotation = d;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_SecondsPerRotation = d;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnSecondsPerRotationChanged(double d) { m_Controller->SecondsPerRotationChanged(d); }
/// <summary>
/// Set the direction loop rotations rotate in animation.
/// Called when the xforms rotation direction combobox index is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The index</param>
template <typename T> void FractoriumEmberController<T>::RotateXformsDirChanged(uint d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_RotateXformsCw = d == 0;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_RotateXformsCw = ember.m_RotateXformsCw;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnRotateXformsDirComboCurrentIndexChanged(int i) { m_Controller->RotateXformsDirChanged(i); }
/// <summary>
/// Set the seconds each blend takes in animation.
/// Called when the blend seconds spinner is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The number of seconds each blend should take</param>
template <typename T> void FractoriumEmberController<T>::BlendSecondsChanged(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_BlendSeconds = d;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_BlendSeconds = ember.m_BlendSeconds;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnBlendSecondsChanged(double d) { m_Controller->BlendSecondsChanged(d); }
/// <summary>
/// Set the rotations each blend performs in animation.
/// Called when the rotations per blend spinner is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The number of rotations each blend should perform</param>
template <typename T> void FractoriumEmberController<T>::RotationsPerBlendChanged(uint d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_RotationsPerBlend = d;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_RotationsPerBlend = d;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnRotationsPerBlendChanged(int d) { m_Controller->RotationsPerBlendChanged(d); }
/// <summary>
/// Set the direction blend rotations rotate in animation.
/// Called when the blend xforms rotation direction combobox index is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The index</param>
template <typename T> void FractoriumEmberController<T>::BlendXformsRotateDirChanged(uint d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_BlendRotateXformsCw = d == 0;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_BlendRotateXformsCw = ember.m_BlendRotateXformsCw;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnBlendXformsRotateDirComboCurrentIndexChanged(int i) { m_Controller->BlendXformsRotateDirChanged(i); }
/// <summary>
/// Set the blend interpolation type in animation.
/// Called when the blend interpolation type combobox index is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The index</param>
template <typename T> void FractoriumEmberController<T>::BlendInterpTypeChanged(uint d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_Linear = d == 0;
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_Linear = ember.m_Linear;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnBlendInterpTypeComboCurrentIndexChanged(int i) { m_Controller->BlendInterpTypeChanged(i); }
/// <summary>
/// Set the stagger amount in animation.
/// Called when the stagger spinner is changed.
/// Does not reset anything because this is only used for animation.
/// </summary>
/// <param name="d">The amount to stagger the blending of xforms</param>
template <typename T> void FractoriumEmberController<T>::StaggerChanged(double d)
{
UpdateAll([&](Ember<T>& ember, bool isMain)
{
ember.m_Stagger = Clamp(d, 0.0, 1.0);
if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer)
m_EmberFilePointer->m_Stagger = ember.m_Stagger;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}
void Fractorium::OnStaggerChanged(double d) { m_Controller->StaggerChanged(d); }
/// <summary> /// <summary>
/// Set the temporal filter width to be used with animation. /// Set the temporal filter width to be used with animation.
@ -878,7 +1067,6 @@ void FractoriumEmberController<T>::ExpChanged(double d)
m_EmberFilePointer->m_TemporalFilterExp = d; m_EmberFilePointer->m_TemporalFilterExp = d;
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll()); }, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
} }
void Fractorium::OnExpChanged(double d) { m_Controller->ExpChanged(d); } void Fractorium::OnExpChanged(double d) { m_Controller->ExpChanged(d); }
/// <summary> /// <summary>
@ -932,9 +1120,6 @@ void FractoriumEmberController<T>::FillParamTablesAndPalette()
m_Fractorium->m_BlurCurveSpin->SetValueStealth(m_Ember.m_BlurCurve); m_Fractorium->m_BlurCurveSpin->SetValueStealth(m_Ember.m_BlurCurve);
m_Fractorium->m_SpatialFilterWidthSpin->SetValueStealth(m_Ember.m_SpatialFilterRadius);//Filter. m_Fractorium->m_SpatialFilterWidthSpin->SetValueStealth(m_Ember.m_SpatialFilterRadius);//Filter.
m_Fractorium->m_SpatialFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_SpatialFilterType)); m_Fractorium->m_SpatialFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_SpatialFilterType));
m_Fractorium->m_TemporalFilterWidthSpin->SetValueStealth(m_Ember.m_TemporalFilterWidth);
m_Fractorium->m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_TemporalFilterType));
m_Fractorium->m_TemporalFilterExpSpin->SetValueStealth(m_Ember.m_TemporalFilterExp);
m_Fractorium->m_DEFilterMinRadiusSpin->SetValueStealth(m_Ember.m_MinRadDE); m_Fractorium->m_DEFilterMinRadiusSpin->SetValueStealth(m_Ember.m_MinRadDE);
m_Fractorium->m_DEFilterMaxRadiusSpin->SetValueStealth(m_Ember.m_MaxRadDE); m_Fractorium->m_DEFilterMaxRadiusSpin->SetValueStealth(m_Ember.m_MaxRadDE);
m_Fractorium->m_DECurveSpin->SetValueStealth(m_Ember.m_CurveDE); m_Fractorium->m_DECurveSpin->SetValueStealth(m_Ember.m_CurveDE);
@ -943,8 +1128,19 @@ void FractoriumEmberController<T>::FillParamTablesAndPalette()
m_Fractorium->m_RandRangeSpin->SetValueStealth(m_Ember.m_RandPointRange); m_Fractorium->m_RandRangeSpin->SetValueStealth(m_Ember.m_RandPointRange);
m_Fractorium->m_QualitySpin->SetValueStealth(m_Ember.m_Quality); m_Fractorium->m_QualitySpin->SetValueStealth(m_Ember.m_Quality);
m_Fractorium->m_SupersampleSpin->SetValueStealth(m_Ember.m_Supersample); m_Fractorium->m_SupersampleSpin->SetValueStealth(m_Ember.m_Supersample);
m_Fractorium->m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_AffineInterp));
m_Fractorium->m_InterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_Interp)); m_Fractorium->m_InterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_Interp));
m_Fractorium->m_AffineInterpTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_AffineInterp));
m_Fractorium->m_RotationsSpin->SetValueStealth(m_Ember.m_Rotations);
m_Fractorium->m_SecondsPerRotationSpin->SetValueStealth(m_Ember.m_SecondsPerRotation);
m_Fractorium->m_RotateXformsDirCombo->SetCurrentIndexStealth(m_Ember.m_RotateXformsCw ? 0 : 1);
m_Fractorium->m_BlendSecondsSpin->SetValueStealth(m_Ember.m_BlendSeconds);
m_Fractorium->m_RotationsPerBlendSpin->SetValueStealth(m_Ember.m_RotationsPerBlend);
m_Fractorium->m_BlendXformsRotateDirCombo->SetCurrentIndexStealth(m_Ember.m_BlendRotateXformsCw ? 0 : 1);
m_Fractorium->m_BlendInterpTypeCombo->SetCurrentIndexStealth(m_Ember.m_Linear ? 0 : 1);
m_Fractorium->m_StaggerSpin->SetValueStealth(m_Ember.m_Stagger);
m_Fractorium->m_TemporalFilterWidthSpin->SetValueStealth(m_Ember.m_TemporalFilterWidth);
m_Fractorium->m_TemporalFilterTypeCombo->SetCurrentIndexStealth(static_cast<int>(m_Ember.m_TemporalFilterType));
m_Fractorium->m_TemporalFilterExpSpin->SetValueStealth(m_Ember.m_TemporalFilterExp);
auto temp = m_Ember.m_Palette.m_Filename; auto temp = m_Ember.m_Palette.m_Filename;
if (temp.get()) if (temp.get())
@ -986,9 +1182,6 @@ void FractoriumEmberController<T>::ParamsToEmberPrivate(Ember<U>& ember, bool im
if (imageParamsOnly) if (imageParamsOnly)
return; return;
ember.m_TemporalFilterWidth = m_Fractorium->m_TemporalFilterWidthSpin->value();
ember.m_TemporalFilterType = static_cast<eTemporalFilterType>(m_Fractorium->m_TemporalFilterTypeCombo->currentIndex());
ember.m_TemporalFilterExp = m_Fractorium->m_TemporalFilterExpSpin->value();
const auto color = m_Fractorium->ui.ColorTable->item(5, 1)->background(); const auto color = m_Fractorium->ui.ColorTable->item(5, 1)->background();
ember.m_Background.r = color.color().red() / 255.0; ember.m_Background.r = color.color().red() / 255.0;
ember.m_Background.g = color.color().green() / 255.0; ember.m_Background.g = color.color().green() / 255.0;
@ -1012,8 +1205,19 @@ void FractoriumEmberController<T>::ParamsToEmberPrivate(Ember<U>& ember, bool im
ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value(); ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value();
ember.m_Quality = m_Fractorium->m_QualitySpin->value(); ember.m_Quality = m_Fractorium->m_QualitySpin->value();
ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value(); ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();
ember.m_AffineInterp = static_cast<eAffineInterp>(m_Fractorium->m_AffineInterpTypeCombo->currentIndex());
ember.m_Interp = static_cast<eInterp>(m_Fractorium->m_InterpTypeCombo->currentIndex()); ember.m_Interp = static_cast<eInterp>(m_Fractorium->m_InterpTypeCombo->currentIndex());
ember.m_AffineInterp = static_cast<eAffineInterp>(m_Fractorium->m_AffineInterpTypeCombo->currentIndex());
ember.m_Rotations = m_Fractorium->m_RotationsSpin->value();
ember.m_SecondsPerRotation = m_Fractorium->m_SecondsPerRotationSpin->value();
ember.m_RotateXformsCw = m_Fractorium->m_RotateXformsDirCombo->currentIndex() == 0;
ember.m_BlendSeconds = m_Fractorium->m_BlendSecondsSpin->value();
ember.m_RotationsPerBlend = m_Fractorium->m_RotationsPerBlendSpin->value();
ember.m_BlendRotateXformsCw = m_Fractorium->m_BlendXformsRotateDirCombo->currentIndex() == 0;
ember.m_Linear = m_Fractorium->m_BlendInterpTypeCombo->currentIndex() == 0;
ember.m_Stagger = m_Fractorium->m_StaggerSpin->value();
ember.m_TemporalFilterWidth = m_Fractorium->m_TemporalFilterWidthSpin->value();
ember.m_TemporalFilterType = static_cast<eTemporalFilterType>(m_Fractorium->m_TemporalFilterTypeCombo->currentIndex());
ember.m_TemporalFilterExp = m_Fractorium->m_TemporalFilterExpSpin->value();
ember.SyncSize(); ember.SyncSize();
} }

View File

@ -8,14 +8,15 @@ void Fractorium::InitXformsUI()
{ {
const int spinHeight = 20; const int spinHeight = 20;
auto row = 0; auto row = 0;
connect(ui.AddXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.AddXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.AddLinkedXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddLinkedXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.AddLinkedXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddLinkedXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.DuplicateXformButton, SIGNAL(clicked(bool)), this, SLOT(OnDuplicateXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.DuplicateXformButton, SIGNAL(clicked(bool)), this, SLOT(OnDuplicateXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.ClearXformButton, SIGNAL(clicked(bool)), this, SLOT(OnClearXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.ClearXformButton, SIGNAL(clicked(bool)), this, SLOT(OnClearXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.DeleteXformButton, SIGNAL(clicked(bool)), this, SLOT(OnDeleteXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.DeleteXformButton, SIGNAL(clicked(bool)), this, SLOT(OnDeleteXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.AddFinalXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddFinalXformButtonClicked(bool)), Qt::QueuedConnection); connect(ui.AddFinalXformButton, SIGNAL(clicked(bool)), this, SLOT(OnAddFinalXformButtonClicked(bool)), Qt::QueuedConnection);
connect(ui.CurrentXformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentXformComboChanged(int)), Qt::QueuedConnection); connect(ui.CurrentXformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentXformComboChanged(int)), Qt::QueuedConnection);
connect(ui.AnimateXformCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnXformAnimateCheckBoxStateChanged(int)), Qt::QueuedConnection); connect(ui.AnimateXformLocalRotationCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnXformAnimateLocalRotationCheckBoxStateChanged(int)), Qt::QueuedConnection);
connect(ui.AnimateXformOriginRotationCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnXformAnimateOriginRotationCheckBoxStateChanged(int)), Qt::QueuedConnection);
SetFixedTableHeader(ui.XformWeightNameTable->horizontalHeader(), QHeaderView::ResizeToContents); SetFixedTableHeader(ui.XformWeightNameTable->horizontalHeader(), QHeaderView::ResizeToContents);
//Use SetupSpinner() just to create the spinner, but use col of -1 to prevent it from being added to the table. //Use SetupSpinner() just to create the spinner, but use col of -1 to prevent it from being added to the table.
SetupSpinner<DoubleSpinBox, double>(ui.XformWeightNameTable, this, row, -1, m_XformWeightSpin, spinHeight, 0, 1000, 0.05, SIGNAL(valueChanged(double)), SLOT(OnXformWeightChanged(double)), false, 0, 1, 0); SetupSpinner<DoubleSpinBox, double>(ui.XformWeightNameTable, this, row, -1, m_XformWeightSpin, spinHeight, 0, 1000, 0.05, SIGNAL(valueChanged(double)), SLOT(OnXformWeightChanged(double)), false, 0, 1, 0);
@ -438,6 +439,7 @@ void FractoriumEmberController<T>::AddFinalXform()
{ {
auto& final = m_Ember.m_CachedFinal; auto& final = m_Ember.m_CachedFinal;
final.m_Animate = 0; final.m_Animate = 0;
final.m_AnimateOrigin = 0;
if (final.Empty()) if (final.Empty())
final.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));//Just a placeholder so other parts of the code don't see it as being empty. final.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));//Just a placeholder so other parts of the code don't see it as being empty.
@ -451,7 +453,7 @@ void FractoriumEmberController<T>::AddFinalXform()
void Fractorium::OnAddFinalXformButtonClicked(bool checked) { m_Controller->AddFinalXform(); } void Fractorium::OnAddFinalXformButtonClicked(bool checked) { m_Controller->AddFinalXform(); }
/// <summary> /// <summary>
/// Set the weight of the selected xforms. /// Set the weight of the selected xforms.
/// Called when weight spinner changes. /// Called when the weight spinner changes.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The weight</param> /// <param name="d">The weight</param>
@ -518,8 +520,9 @@ void Fractorium::OnXformNameChanged(const QString& s)
/// Called when the user toggles the animate xform checkbox. /// Called when the user toggles the animate xform checkbox.
/// </summary> /// </summary>
/// <param name="state">1 for checked, else false</param> /// <param name="state">1 for checked, else false</param>
/// <param name="local">true to rotate around the local center, else rotate around the origin</param>
template <typename T> template <typename T>
void FractoriumEmberController<T>::XformAnimateChanged(int state) void FractoriumEmberController<T>::XformAnimateChangedHelper(int state, bool local)
{ {
T animate = state > 0 ? 1 : 0; T animate = state > 0 ? 1 : 0;
UpdateXform([&](Xform<T>* xform, size_t xfindex, size_t selIndex) UpdateXform([&](Xform<T>* xform, size_t xfindex, size_t selIndex)
@ -532,26 +535,40 @@ void FractoriumEmberController<T>::XformAnimateChanged(int state)
if (ember.UseFinalXform()) if (ember.UseFinalXform())
{ {
auto xform = ember.NonConstFinalXform(); auto xform = ember.NonConstFinalXform();
xform->m_Animate = animate;
if (local)
xform->m_Animate = animate;
else
xform->m_AnimateOrigin = animate;
} }
if (!m_Fractorium->ApplyAll()) if (!m_Fractorium->ApplyAll())
if (m_EmberFilePointer && m_EmberFilePointer->UseFinalXform()) if (m_EmberFilePointer && m_EmberFilePointer->UseFinalXform())
m_EmberFilePointer->NonConstFinalXform()->m_Animate = animate; if (local)
m_EmberFilePointer->NonConstFinalXform()->m_Animate = animate;
else
m_EmberFilePointer->NonConstFinalXform()->m_AnimateOrigin = animate;
} }
else//Current was not final, so apply to other embers which have a non-final xform at this index. else//Current was not final, so apply to other embers which have a non-final xform at this index.
{ {
if (auto xform = ember.GetXform(xfindex)) if (auto xform = ember.GetXform(xfindex))
xform->m_Animate = animate; if (local)
xform->m_Animate = animate;
else
xform->m_AnimateOrigin = animate;
if (!m_Fractorium->ApplyAll() && m_EmberFilePointer) if (!m_Fractorium->ApplyAll() && m_EmberFilePointer)
if (auto xform = m_EmberFilePointer->GetXform(xfindex)) if (auto xform = m_EmberFilePointer->GetXform(xfindex))
xform->m_Animate = animate; if (local)
xform->m_Animate = animate;
else
xform->m_AnimateOrigin = animate;
} }
}, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll()); }, false, eProcessAction::NOTHING, m_Fractorium->ApplyAll());
}, eXformUpdate::UPDATE_SELECTED, false); }, eXformUpdate::UPDATE_SELECTED, false);
} }
void Fractorium::OnXformAnimateCheckBoxStateChanged(int state) { m_Controller->XformAnimateChanged(state); } void Fractorium::OnXformAnimateLocalRotationCheckBoxStateChanged(int state) { m_Controller->XformAnimateChangedHelper(state, true); }
void Fractorium::OnXformAnimateOriginRotationCheckBoxStateChanged(int state) { m_Controller->XformAnimateChangedHelper(state, false); }
/// <summary> /// <summary>
/// Fill all GUI widgets with values from the passed in xform. /// Fill all GUI widgets with values from the passed in xform.
@ -562,9 +579,12 @@ void FractoriumEmberController<T>::FillWithXform(Xform<T>* xform)
{ {
m_Fractorium->m_XformWeightSpin->SetValueStealth(xform->m_Weight); m_Fractorium->m_XformWeightSpin->SetValueStealth(xform->m_Weight);
SetNormalizedWeightText(xform); SetNormalizedWeightText(xform);
m_Fractorium->ui.AnimateXformCheckBox->blockSignals(true); m_Fractorium->ui.AnimateXformLocalRotationCheckBox->blockSignals(true);
m_Fractorium->ui.AnimateXformCheckBox->setChecked(xform->m_Animate > 0 ? true : false); m_Fractorium->ui.AnimateXformLocalRotationCheckBox->setChecked(xform->m_Animate > 0 ? true : false);
m_Fractorium->ui.AnimateXformCheckBox->blockSignals(false); m_Fractorium->ui.AnimateXformLocalRotationCheckBox->blockSignals(false);
m_Fractorium->ui.AnimateXformOriginRotationCheckBox->blockSignals(true);
m_Fractorium->ui.AnimateXformOriginRotationCheckBox->setChecked(xform->m_AnimateOrigin > 0 ? true : false);
m_Fractorium->ui.AnimateXformOriginRotationCheckBox->blockSignals(false);
if (const auto item = m_Fractorium->ui.XformWeightNameTable->item(0, 1)) if (const auto item = m_Fractorium->ui.XformWeightNameTable->item(0, 1))
{ {

View File

@ -36,7 +36,7 @@ void Fractorium::InitXformsColorUI()
/// <summary> /// <summary>
/// Set the color index of the selected xforms. /// Set the color index of the selected xforms.
/// Update the color index scrollbar to match. /// Update the color index scrollbar to match.
/// Called when spinner in the color index cell in the palette ref table is changed. /// Called when the spinner in the color index cell in the palette ref table is changed.
/// Optionally resets the rendering process. /// Optionally resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The color index, 0-1/</param> /// <param name="d">The color index, 0-1/</param>
@ -83,7 +83,7 @@ void Fractorium::OnXformColorIndexChanged(double d, bool updateRender, bool upda
/// <summary> /// <summary>
/// Set the color index of the current xform. /// Set the color index of the current xform.
/// Will trigger an update which will cause the color index cell in the palette ref table to match. /// Will trigger an update which will cause the color index cell in the palette ref table to match.
/// Called when color index scrollbar is changed. /// Called when the color index scrollbar is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The color index, 0-1.</param> /// <param name="d">The color index, 0-1.</param>
@ -148,7 +148,7 @@ void Fractorium::OnToggleColorSpeedsButtonClicked(bool b) { m_Controller->Toggle
/// <summary> /// <summary>
/// Set the color speed of the selected xforms. /// Set the color speed of the selected xforms.
/// Called when xform color speed spinner is changed. /// Called when the xform color speed spinner is changed.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="d">The color speed, -1-1.</param> /// <param name="d">The color speed, -1-1.</param>
@ -168,7 +168,7 @@ void Fractorium::OnXformOpacityChanged(double d) { m_Controller->XformOpacityCha
/// <summary> /// <summary>
/// Set the direct color percentage of the selected xforms. /// Set the direct color percentage of the selected xforms.
/// Called when xform direct color spinner is changed. /// Called when the xform direct color spinner is changed.
/// Note this only affects xforms that include a dc_ variation. /// Note this only affects xforms that include a dc_ variation.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
@ -184,7 +184,7 @@ void Fractorium::OnXformDirectColorChanged(double d) { m_Controller->XformDirect
/// set to zero while rendering so that only the effect of current xform is visible. /// set to zero while rendering so that only the effect of current xform is visible.
/// This will not permanently alter the opacities of ember, as the temporary opacity values will be applied /// This will not permanently alter the opacities of ember, as the temporary opacity values will be applied
/// right before rendering and reset right after. /// right before rendering and reset right after.
/// Called when solo xform check box is checked. /// Called when the solo xform check box is checked.
/// Resets the rendering process. /// Resets the rendering process.
/// </summary> /// </summary>
/// <param name="state">The state of the checkbox</param> /// <param name="state">The state of the checkbox</param>

View File

@ -407,7 +407,7 @@ QIcon FractoriumEmberController<T>::MakeVariationIcon(const Variation<T>* var)
/// <summary> /// <summary>
/// Change the sorting to be either by variation ID, or by weight. /// Change the sorting to be either by variation ID, or by weight.
/// If sorting by variation ID, repeated clicks will alternate ascending or descending. /// If sorting by variation ID, repeated clicks will alternate ascending or descending.
/// Called when user clicks the tree headers. /// Called when the user clicks the tree headers.
/// </summary> /// </summary>
/// <param name="logicalIndex">Column index of the header clicked. Sort by name if 0, sort by weight if 1.</param> /// <param name="logicalIndex">Column index of the header clicked. Sort by name if 0, sort by weight if 1.</param>
void Fractorium::OnTreeHeaderSectionClicked(int logicalIndex) void Fractorium::OnTreeHeaderSectionClicked(int logicalIndex)
@ -435,7 +435,7 @@ void Fractorium::OnVariationsFilterLineEditTextChanged(const QString& text)
/// <summary> /// <summary>
/// Clear the variation name filter, which will display all variations. /// Clear the variation name filter, which will display all variations.
/// Called when clear variations filter button is clicked. /// Called when the clear variations filter button is clicked.
/// </summary> /// </summary>
/// <param name="checked">Ignored</param> /// <param name="checked">Ignored</param>
void Fractorium::OnVariationsFilterClearButtonClicked(bool checked) void Fractorium::OnVariationsFilterClearButtonClicked(bool checked)