mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-02-01 10:30:08 -05:00
Merge branch 'master' into travis
This commit is contained in:
commit
fc7923e8af
@ -271,6 +271,7 @@
|
||||
<ClInclude Include="..\..\..\Source\Ember\CarToRas.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\Curves.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\EmberDefines.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\EmberMotion.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\EmberPch.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\Ember.h" />
|
||||
<ClInclude Include="..\..\..\Source\Ember\DensityFilter.h" />
|
||||
|
@ -113,6 +113,9 @@
|
||||
<ClInclude Include="..\..\..\Source\Ember\Curves.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\Source\Ember\EmberMotion.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\Source\Ember\DllMain.cpp">
|
||||
|
@ -52,5 +52,6 @@ HEADERS += \
|
||||
../../../Source/Ember/Variations05.h \
|
||||
../../../Source/Ember/VariationsDC.h \
|
||||
../../../Source/Ember/Xform.h \
|
||||
../../../Source/Ember/XmlToEmber.h
|
||||
../../../Source/Ember/XmlToEmber.h \
|
||||
../../../Source/Ember/EmberMotion.h
|
||||
|
||||
|
@ -24,6 +24,7 @@ template<> unique_ptr<QTIsaac<ISAAC_SIZE, ISAAC_INT>> QTIsaac<ISAAC_SIZE, ISAAC_
|
||||
#include "VariationList.h"
|
||||
#include "Affine2D.h"
|
||||
#include "Xform.h"
|
||||
#include "EmberMotion.h"
|
||||
#include "EmberToXml.h"
|
||||
#include "XmlToEmber.h"
|
||||
#include "SpatialFilter.h"
|
||||
@ -65,6 +66,8 @@ uint Timing::m_ProcessorCount;
|
||||
template EMBER_API class StandardIterator<T>; \
|
||||
template EMBER_API class XaosIterator<T>; \
|
||||
template EMBER_API class Xform<T>; \
|
||||
template EMBER_API class MotionParam<T>; \
|
||||
template EMBER_API class EmberMotion<T>; \
|
||||
template EMBER_API class IteratorHelper<T>; \
|
||||
template EMBER_API class Variation<T>; \
|
||||
template EMBER_API class ParamWithName<T>; \
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "PaletteList.h"
|
||||
#include "SpatialFilter.h"
|
||||
#include "TemporalFilter.h"
|
||||
#include "EmberMotion.h"
|
||||
|
||||
/// <summary>
|
||||
/// Ember class.
|
||||
@ -183,6 +184,8 @@ public:
|
||||
if (ember.m_Edits != nullptr)
|
||||
m_Edits = xmlCopyDoc(ember.m_Edits, 1);
|
||||
|
||||
CopyVec(m_EmberMotionElements, ember.m_EmberMotionElements);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -472,6 +475,8 @@ public:
|
||||
{
|
||||
for (size_t i = 0; i < TotalXformCount(); i++)
|
||||
GetTotalXform(i)->DeleteMotionElements();
|
||||
|
||||
m_EmberMotionElements.clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1285,6 +1290,83 @@ public:
|
||||
point.m_Z -= m_CamZPos;
|
||||
}
|
||||
|
||||
#define APP_FMP(x) x += param.second * Interpolater<T>::MotionFuncs(motion.m_MotionFunc, motion.m_MotionFreq * (blend + motion.m_MotionOffset))
|
||||
|
||||
/// <summary>
|
||||
/// Update ember parameters based on stored motion elements
|
||||
/// </summary>
|
||||
/// <param name="blend">The time percentage value which dictates how much of a percentage of 360 degrees it should be rotated and the time position for the motion elements</param>
|
||||
void ApplyFlameMotion(T blend)
|
||||
{
|
||||
for (size_t i = 0; i < m_EmberMotionElements.size(); ++i)
|
||||
{
|
||||
auto& motion = m_EmberMotionElements[i];
|
||||
|
||||
for (size_t j = 0; j < motion.m_MotionParams.size(); ++j)
|
||||
{
|
||||
auto& param = motion.m_MotionParams[j];
|
||||
|
||||
switch (param.first)
|
||||
{
|
||||
case FLAME_MOTION_ZOOM:
|
||||
APP_FMP(m_Zoom);
|
||||
break;
|
||||
case FLAME_MOTION_ZPOS:
|
||||
APP_FMP(m_CamZPos);
|
||||
break;
|
||||
case FLAME_MOTION_PERSPECTIVE:
|
||||
APP_FMP(m_CamPerspective);
|
||||
break;
|
||||
case FLAME_MOTION_YAW:
|
||||
APP_FMP(m_CamYaw);
|
||||
break;
|
||||
case FLAME_MOTION_PITCH:
|
||||
APP_FMP(m_CamPitch);
|
||||
break;
|
||||
case FLAME_MOTION_DEPTH_BLUR:
|
||||
APP_FMP(m_CamDepthBlur);
|
||||
break;
|
||||
case FLAME_MOTION_CENTER_X:
|
||||
APP_FMP(m_CenterX);
|
||||
break;
|
||||
case FLAME_MOTION_CENTER_Y:
|
||||
APP_FMP(m_CenterY);
|
||||
break;
|
||||
case FLAME_MOTION_ROTATE:
|
||||
APP_FMP(m_Rotate);
|
||||
break;
|
||||
case FLAME_MOTION_HUE:
|
||||
APP_FMP(m_Hue);
|
||||
break;
|
||||
case FLAME_MOTION_BRIGHTNESS:
|
||||
APP_FMP(m_Brightness);
|
||||
break;
|
||||
case FLAME_MOTION_GAMMA:
|
||||
APP_FMP(m_Gamma);
|
||||
break;
|
||||
case FLAME_MOTION_GAMMA_THRESH:
|
||||
APP_FMP(m_GammaThresh);
|
||||
break;
|
||||
case FLAME_MOTION_HIGHLIGHT_POWER:
|
||||
APP_FMP(m_HighlightPower);
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_R:
|
||||
APP_FMP(m_Background.r);
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_G:
|
||||
APP_FMP(m_Background.g);
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_B:
|
||||
APP_FMP(m_Background.b);
|
||||
break;
|
||||
case FLAME_MOTION_VIBRANCY:
|
||||
APP_FMP(m_Vibrancy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear this ember and set to either reasonable or unreasonable default values.
|
||||
/// </summary>
|
||||
@ -1683,6 +1765,9 @@ public:
|
||||
//The 0-based position of this ember in the file it was contained in.
|
||||
size_t m_Index;
|
||||
|
||||
//The list of motion elements for the top-level flame params
|
||||
vector<EmberMotion<T>> m_EmberMotionElements;
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// The type of scaling used when resizing.
|
||||
|
@ -114,10 +114,32 @@ enum eInterp : uint { EMBER_INTERP_LINEAR = 0, EMBER_INTERP_SMOOTH = 1 };
|
||||
enum eAffineInterp : uint { INTERP_LINEAR = 0, INTERP_LOG = 1, INTERP_COMPAT = 2, INTERP_OLDER = 3 };
|
||||
enum ePaletteMode : uint { PALETTE_STEP = 0, PALETTE_LINEAR = 1 };
|
||||
enum ePaletteInterp : uint { INTERP_HSV = 0, INTERP_SWEEP = 1 };
|
||||
enum eMotion : uint { MOTION_SIN = 1, MOTION_TRIANGLE = 2, MOTION_HILL = 3 };
|
||||
enum eMotion : uint { MOTION_SIN = 1, MOTION_TRIANGLE = 2, MOTION_HILL = 3, MOTION_SAW = 4 };
|
||||
enum eProcessAction : uint { NOTHING = 0, ACCUM_ONLY = 1, FILTER_AND_ACCUM = 2, KEEP_ITERATING = 3, FULL_RENDER = 4 };
|
||||
enum eProcessState : uint { NONE = 0, ITER_STARTED = 1, ITER_DONE = 2, FILTER_DONE = 3, ACCUM_DONE = 4 };
|
||||
enum eInteractiveFilter : uint { FILTER_LOG = 0, FILTER_DE = 1 };
|
||||
enum eScaleType : uint { SCALE_NONE = 0, SCALE_WIDTH = 1, SCALE_HEIGHT = 2 };
|
||||
enum eRenderStatus : uint { RENDER_OK = 0, RENDER_ERROR = 1, RENDER_ABORT = 2 };
|
||||
enum eEmberMotionParam : uint
|
||||
{
|
||||
FLAME_MOTION_NONE = 0,
|
||||
FLAME_MOTION_ZOOM = 1,
|
||||
FLAME_MOTION_ZPOS = 2,
|
||||
FLAME_MOTION_PERSPECTIVE = 3,
|
||||
FLAME_MOTION_YAW = 4,
|
||||
FLAME_MOTION_PITCH = 5,
|
||||
FLAME_MOTION_DEPTH_BLUR = 6,
|
||||
FLAME_MOTION_CENTER_X = 7,
|
||||
FLAME_MOTION_CENTER_Y = 8,
|
||||
FLAME_MOTION_ROTATE = 9,
|
||||
FLAME_MOTION_HUE = 10,
|
||||
FLAME_MOTION_BRIGHTNESS = 11,
|
||||
FLAME_MOTION_GAMMA = 12,
|
||||
FLAME_MOTION_GAMMA_THRESH = 13,
|
||||
FLAME_MOTION_HIGHLIGHT_POWER = 14,
|
||||
FLAME_MOTION_BACKGROUND_R = 15,
|
||||
FLAME_MOTION_BACKGROUND_G = 16,
|
||||
FLAME_MOTION_BACKGROUND_B = 17,
|
||||
FLAME_MOTION_VIBRANCY = 18
|
||||
};
|
||||
}
|
||||
|
@ -221,6 +221,9 @@ public:
|
||||
|
||||
os << "\">\n";
|
||||
|
||||
for (i = 0; i < ember.m_EmberMotionElements.size(); ++i)
|
||||
os << " " << ToString(ember.m_EmberMotionElements[i]);
|
||||
|
||||
//This is a grey area, what to do about symmetry to avoid duplicating the symmetry xforms when reading back?//TODO//BUG.
|
||||
//if (ember.m_Symmetry)
|
||||
// os << " <symmetry kind=\"" << ember.m_Symmetry << "\"/>\n";
|
||||
@ -488,6 +491,11 @@ private:
|
||||
os << "motion_function=\"triangle\" ";
|
||||
else if (xform.m_MotionFunc== MOTION_HILL)
|
||||
os << "motion_function=\"hill\" ";
|
||||
else if (xform.m_MotionFunc== MOTION_SAW)
|
||||
os << "motion_function=\"saw\" ";
|
||||
|
||||
if (xform.m_MotionOffset != 0)
|
||||
os << "motion_offset=\"" << xform.m_MotionOffset << "\" ";
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -717,6 +725,114 @@ private:
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a FlameMotion element to an xml string
|
||||
/// </summary>
|
||||
/// <param name="motion">The FlameMotion object to convert to XML</param>
|
||||
string ToString(const EmberMotion<T>& motion)
|
||||
{
|
||||
ostringstream os;
|
||||
os << "<flame_motion motion_frequency=\"" << motion.m_MotionFreq << "\" ";
|
||||
|
||||
if (motion.m_MotionOffset > 0)
|
||||
os << "motion_offset=\"" << motion.m_MotionOffset << "\" ";
|
||||
|
||||
os << "motion_func=";
|
||||
|
||||
switch (motion.m_MotionFunc)
|
||||
{
|
||||
case MOTION_SIN:
|
||||
os << "\"sin\"";
|
||||
break;
|
||||
case MOTION_HILL:
|
||||
os << "\"hill\"";
|
||||
break;
|
||||
case MOTION_TRIANGLE:
|
||||
os << "\"triangle\"";
|
||||
break;
|
||||
case MOTION_SAW:
|
||||
os << "\"saw\"";
|
||||
break;
|
||||
}
|
||||
|
||||
T r = 0.0;
|
||||
T g = 0.0;
|
||||
T b = 0.0;
|
||||
T cx = 0.0;
|
||||
T cy = 0.0;
|
||||
|
||||
for (int i = 0; i < motion.m_MotionParams.size(); ++i)
|
||||
{
|
||||
switch(motion.m_MotionParams[i].first)
|
||||
{
|
||||
case FLAME_MOTION_ZOOM:
|
||||
os << " zoom=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_ZPOS:
|
||||
os << " cam_zpos=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_PERSPECTIVE:
|
||||
os << " cam_persp=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_YAW:
|
||||
os << " cam_yaw=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_PITCH:
|
||||
os << " cam_pitch=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_DEPTH_BLUR:
|
||||
os << " cam_dof=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_CENTER_X:
|
||||
cx = motion.m_MotionParams[i].second;
|
||||
break;
|
||||
case FLAME_MOTION_CENTER_Y:
|
||||
cy = motion.m_MotionParams[i].second;
|
||||
break;
|
||||
case FLAME_MOTION_ROTATE:
|
||||
os << " rotate=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_HUE:
|
||||
os << " hue=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_BRIGHTNESS:
|
||||
os << " brightness=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_GAMMA:
|
||||
os << " gamma=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_GAMMA_THRESH:
|
||||
os << " gamma_threshold=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_HIGHLIGHT_POWER:
|
||||
os << " highlight_power=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_R:
|
||||
r = motion.m_MotionParams[i].second;
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_G:
|
||||
g = motion.m_MotionParams[i].second;
|
||||
break;
|
||||
case FLAME_MOTION_BACKGROUND_B:
|
||||
b = motion.m_MotionParams[i].second;
|
||||
break;
|
||||
case FLAME_MOTION_VIBRANCY:
|
||||
os << " vibrancy=\"" << motion.m_MotionParams[i].second << "\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r != 0.0 || g != 0.0 || b != 0.0)
|
||||
os << " background=\"" << r << " " << g << " " << b << "\"";
|
||||
|
||||
if (cx != 0.0 || cy != 0.0)
|
||||
os << " center=\"" << cx << " " << cy << "\"";
|
||||
|
||||
os << "/>\n";
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void AddFilenameWithoutAmpersand(xmlNodePtr node, string& filename)
|
||||
{
|
||||
if (filename.find_first_of('&') != std::string::npos)
|
||||
|
@ -883,10 +883,14 @@ public:
|
||||
|
||||
return fr;
|
||||
}
|
||||
else//MOTION_HILL
|
||||
else if (funcNum == MOTION_HILL)
|
||||
{
|
||||
return ((1 - cos(T(2.0) * T(M_PI) * timeVal)) * T(0.5));
|
||||
}
|
||||
else //MOTION_SAW
|
||||
{
|
||||
return (T(2.0) * fmod(timeVal - T(0.5), T(1.0)) - T(1.0));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -196,6 +196,10 @@ public:
|
||||
/// <summary>
|
||||
/// Member-wise constructor.
|
||||
/// </summary>
|
||||
/// <param name="rr">The red value, either 0-1 or 0-255.</param>
|
||||
/// <param name="gg">The green value, either 0-1 or 0-255.</param>
|
||||
/// <param name="bb">The blue value, either 0-1 or 0-255.</param>
|
||||
/// <param name="aa">The alpha value, either 0-1 or 0-255.</param>
|
||||
Color(T rr, T gg, T bb, T aa)
|
||||
: v4T(rr, gg, bb, aa)
|
||||
{
|
||||
|
@ -1010,11 +1010,11 @@ public:
|
||||
|
||||
if (!xform1->m_Motion.empty())
|
||||
xform2->ApplyMotion(*xform1, blend);
|
||||
|
||||
xform2->DeleteMotionElements();
|
||||
}
|
||||
|
||||
rotated.ApplyFlameMotion(blend);
|
||||
rotated.RotateAffines(-blend * 360);//Rotate the affines.
|
||||
rotated.DeleteMotionElements();//Delete all motion elements from the looped ember, at the xform level and at the parent ember level.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -165,6 +165,7 @@ public:
|
||||
m_Wind[1] = T(xform.m_Wind[1]);
|
||||
m_MotionFreq = xform.m_MotionFreq;
|
||||
m_MotionFunc = xform.m_MotionFunc;
|
||||
m_MotionOffset = xform.m_MotionOffset;
|
||||
|
||||
ClearAndDeleteVariations();
|
||||
|
||||
@ -234,6 +235,7 @@ public:
|
||||
m_Wind[0] = 0;
|
||||
m_Wind[1] = 0;
|
||||
m_MotionFreq = 0;
|
||||
m_MotionOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -262,6 +264,7 @@ public:
|
||||
m_Wind[0] = EMPTYFIELD;
|
||||
m_Wind[1] = EMPTYFIELD;
|
||||
m_MotionFreq = EMPTYFIELD;
|
||||
m_MotionOffset = EMPTYFIELD;
|
||||
}
|
||||
|
||||
m_MotionFunc = MOTION_SIN;
|
||||
@ -716,7 +719,7 @@ public:
|
||||
do \
|
||||
{ \
|
||||
if (currentMot.x != EMPTYFIELD) \
|
||||
x += currentMot.x * Interpolater<T>::MotionFuncs(func, freq * blend); \
|
||||
x += currentMot.x * Interpolater<T>::MotionFuncs(func, freq * (blend + offset)); \
|
||||
} while (0)
|
||||
|
||||
/// <summary>
|
||||
@ -731,8 +734,9 @@ public:
|
||||
{
|
||||
//Original only pulls these from the first motion xform which is a bug. Want to pull it from each one.
|
||||
Xform<T>& currentMot = xform.m_Motion[i];
|
||||
intmax_t freq = currentMot.m_MotionFreq;
|
||||
T freq = currentMot.m_MotionFreq;
|
||||
eMotion func = currentMot.m_MotionFunc;
|
||||
T offset = currentMot.m_MotionOffset;
|
||||
|
||||
//Clamp these to the appropriate range after all are applied.
|
||||
APPMOT(m_Weight);
|
||||
@ -753,13 +757,13 @@ public:
|
||||
if (!var)//It wasn't present, so add it and set the weight.
|
||||
{
|
||||
Variation<T>* newVar = motVar->Copy();
|
||||
newVar->m_Weight = motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * blend);
|
||||
newVar->m_Weight = motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + offset));
|
||||
AddVariation(newVar);
|
||||
var = newVar;//Use this below for params.
|
||||
}
|
||||
else//It was present, so apply the motion func to the weight.
|
||||
{
|
||||
var->m_Weight += motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * blend);
|
||||
var->m_Weight += motVar->m_Weight * Interpolater<T>::MotionFuncs(func, freq * (blend + offset));
|
||||
}
|
||||
|
||||
//At this point, we've added if needed, or just applied the motion func to the weight.
|
||||
@ -773,7 +777,7 @@ public:
|
||||
for (size_t k = 0; k < motParVar->ParamCount(); k++)
|
||||
{
|
||||
if (!motParams[k].IsPrecalc())
|
||||
*(params[k].Param()) += motParams[k].ParamVal() * Interpolater<T>::MotionFuncs(func, freq * blend);
|
||||
*(params[k].Param()) += motParams[k].ParamVal() * Interpolater<T>::MotionFuncs(func, freq * (blend + offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1157,6 +1161,7 @@ public:
|
||||
ss << "Wind: " << m_Wind[0] << ", " << m_Wind[1] << endl;
|
||||
ss << "Motion Frequency: " << m_MotionFreq << endl;
|
||||
ss << "Motion Func: " << m_MotionFunc << endl;
|
||||
ss << "Motion Offset: " << m_MotionOffset << endl;
|
||||
|
||||
const_cast<Xform<T>*>(this)->AllVarsFunc([&] (vector<Variation<T>*>& variations, bool& keepGoing)
|
||||
{
|
||||
@ -1232,7 +1237,8 @@ public:
|
||||
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_Wind[2];
|
||||
eMotion m_MotionFunc;
|
||||
intmax_t m_MotionFreq;
|
||||
T m_MotionFreq;
|
||||
T m_MotionOffset;
|
||||
vector<Xform<T>> m_Motion;
|
||||
string m_Name;
|
||||
|
||||
|
@ -253,8 +253,9 @@ public:
|
||||
/// <param name="buf">The buffer to parse</param>
|
||||
/// <param name="filename">Full path and filename, optionally empty</param>
|
||||
/// <param name="embers">The newly constructed embers based on what was parsed</param>
|
||||
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.</param>
|
||||
/// <returns>True if there were no errors, else false.</returns>
|
||||
bool Parse(byte* buf, const char* filename, vector<Ember<T>>& embers)
|
||||
bool Parse(byte* buf, const char* filename, vector<Ember<T>>& embers, bool useDefaults = true)
|
||||
{
|
||||
char* bn;
|
||||
const char* xmlPtr;
|
||||
@ -286,7 +287,7 @@ public:
|
||||
//Scan for <flame> nodes, starting with this node.
|
||||
//t.Tic();
|
||||
bn = basename(const_cast<char*>(filename));
|
||||
ScanForEmberNodes(rootnode, bn, embers);
|
||||
ScanForEmberNodes(rootnode, bn, embers, useDefaults);
|
||||
xmlFreeDoc(doc);
|
||||
emberSize = embers.size();
|
||||
//t.Toc("ScanForEmberNodes");
|
||||
@ -337,8 +338,9 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="filename">Full path and filename</param>
|
||||
/// <param name="embers">The newly constructed embers based on what was parsed</param>
|
||||
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.</param>
|
||||
/// <returns>True if there were no errors, else false.</returns>
|
||||
bool Parse(const char* filename, vector<Ember<T>>& embers)
|
||||
bool Parse(const char* filename, vector<Ember<T>>& embers, bool useDefaults = true)
|
||||
{
|
||||
const char* loc = __FUNCTION__;
|
||||
string buf;
|
||||
@ -353,7 +355,7 @@ public:
|
||||
if (ReadFile(filename, buf))
|
||||
{
|
||||
std::replace(buf.begin(), buf.end(), '&', '+');
|
||||
return Parse(reinterpret_cast<byte*>(const_cast<char*>(buf.data())), filename, embers);
|
||||
return Parse(reinterpret_cast<byte*>(const_cast<char*>(buf.data())), filename, embers, useDefaults);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -488,7 +490,8 @@ private:
|
||||
/// <param name="curNode">The current node to parse</param>
|
||||
/// <param name="parentFile">The full path and filename</param>
|
||||
/// <param name="embers">The newly constructed embers based on what was parsed</param>
|
||||
void ScanForEmberNodes(xmlNode* curNode, char* parentFile, vector<Ember<T>>& embers)
|
||||
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present.</param>
|
||||
void ScanForEmberNodes(xmlNode* curNode, char* parentFile, vector<Ember<T>>& embers, bool useDefaults)
|
||||
{
|
||||
bool parseEmberSuccess;
|
||||
xmlNodePtr thisNode = nullptr;
|
||||
@ -504,6 +507,10 @@ private:
|
||||
{
|
||||
Ember<T> currentEmber;//Place this inside here so its constructor is called each time.
|
||||
|
||||
//Useful for parsing templates when not every member should be set.
|
||||
if (!useDefaults)
|
||||
currentEmber.Clear(false);
|
||||
|
||||
parseEmberSuccess = ParseEmberElement(thisNode, currentEmber);
|
||||
|
||||
if (!parseEmberSuccess)
|
||||
@ -532,7 +539,7 @@ private:
|
||||
else
|
||||
{
|
||||
//Check all of the children of this element.
|
||||
ScanForEmberNodes(thisNode->children, parentFile, embers);
|
||||
ScanForEmberNodes(thisNode->children, parentFile, embers, useDefaults);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -971,7 +978,7 @@ private:
|
||||
if (theXform)
|
||||
{
|
||||
//Check for non-zero motion params.
|
||||
if (theXform->m_MotionFreq != 0)//Original checked for motion func being non-zero, but it was set to MOTION_SIN (1) in Xform::Init(), so don't check for 0 here.
|
||||
if (fabs(theXform->m_MotionFreq) > 0.0)//Original checked for motion func being non-zero, but it was set to MOTION_SIN (1) in Xform::Init(), so don't check for 0 here.
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : Motion parameters should not be specified in regular, non-motion xforms");
|
||||
}
|
||||
@ -998,6 +1005,117 @@ private:
|
||||
editNode = xmlCopyNode(childNode, 1);
|
||||
xmlDocSetRootElement(currentEmber.m_Edits, editNode);
|
||||
}
|
||||
else if (!Compare(childNode->name, "flame_motion"))
|
||||
{
|
||||
EmberMotion<T> motion;
|
||||
|
||||
att = childNode->properties;
|
||||
|
||||
if (att == nullptr)
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : <flame_motion> element has no attributes");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (curAtt = att; curAtt; curAtt = curAtt->next)
|
||||
{
|
||||
attStr = reinterpret_cast<char*>(xmlGetProp(childNode, curAtt->name));
|
||||
|
||||
if (ParseAndAssignFloat(curAtt->name, attStr, "motion_frequency", motion.m_MotionFreq, ret)) { }
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "motion_offset", motion.m_MotionOffset, ret)) { }
|
||||
else if (!Compare(curAtt->name, "motion_function"))
|
||||
{
|
||||
string func(attStr);
|
||||
|
||||
if (func == "sin")
|
||||
motion.m_MotionFunc = MOTION_SIN;
|
||||
else if (func == "triangle")
|
||||
motion.m_MotionFunc = MOTION_TRIANGLE;
|
||||
else if (func == "hill")
|
||||
motion.m_MotionFunc = MOTION_HILL;
|
||||
else if (func == "saw")
|
||||
motion.m_MotionFunc = MOTION_SAW;
|
||||
else
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : invalid flame motion function " + func);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!Compare(curAtt->name, "zoom"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_ZOOM, motion);
|
||||
else if (!Compare(curAtt->name, "cam_zpos"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_ZPOS, motion);
|
||||
else if (!Compare(curAtt->name, "cam_persp"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_PERSPECTIVE, motion);
|
||||
else if (!Compare(curAtt->name, "cam_yaw"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_YAW, motion);
|
||||
else if (!Compare(curAtt->name, "cam_pitch"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_PITCH, motion);
|
||||
else if (!Compare(curAtt->name, "cam_dof"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_DEPTH_BLUR, motion);
|
||||
else if (!Compare(curAtt->name, "rotate"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_ROTATE, motion);
|
||||
else if (!Compare(curAtt->name, "hue"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_HUE, motion);
|
||||
else if (!Compare(curAtt->name, "brightness"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_BRIGHTNESS, motion);
|
||||
else if (!Compare(curAtt->name, "gamma"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_GAMMA, motion);
|
||||
else if (!Compare(curAtt->name, "gamma_threshold"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_GAMMA_THRESH, motion);
|
||||
else if (!Compare(curAtt->name, "highlight_power"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_HIGHLIGHT_POWER, motion);
|
||||
else if (!Compare(curAtt->name, "vibrancy"))
|
||||
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_VIBRANCY, motion);
|
||||
else if (!Compare(curAtt->name, "background"))
|
||||
{
|
||||
double r, g, b;
|
||||
|
||||
if (sscanf_s(attStr, "%lf %lf %lf", &r, &g, &b) != 3)
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : Invalid flame motion background attribute " + string(attStr));
|
||||
xmlFree(attStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(FLAME_MOTION_BACKGROUND_R, T(r)));
|
||||
|
||||
if (g != 0)
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(FLAME_MOTION_BACKGROUND_G, T(g)));
|
||||
|
||||
if (b != 0)
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(FLAME_MOTION_BACKGROUND_B, T(b)));
|
||||
}
|
||||
else if (!Compare(curAtt->name, "center"))
|
||||
{
|
||||
double cx, cy;
|
||||
|
||||
if (sscanf_s(attStr, "%lf %lf", &cx, &cy) != 2)
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : Invalid flame motion center attribute " + string(attStr));
|
||||
xmlFree(attStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cx != 0)
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(FLAME_MOTION_CENTER_X, T(cx)));
|
||||
|
||||
if (cy != 0)
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(FLAME_MOTION_CENTER_Y, T(cy)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : Unknown flame motion attribute " + string(CCX(curAtt->name)));
|
||||
xmlFree(attStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
xmlFree(attStr);
|
||||
}
|
||||
|
||||
currentEmber.m_EmberMotionElements.push_back(motion);
|
||||
}
|
||||
}
|
||||
|
||||
//if (!newLinear)
|
||||
@ -1010,6 +1128,33 @@ private:
|
||||
return m_ErrorReport.empty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a floating point value from an xml attribute and add the value to a EmberMotion object
|
||||
/// </summary>
|
||||
/// <param name="att">The current attribute</param>
|
||||
/// <param name="attStr">The attribute value to parse</param>
|
||||
/// <param name="param">The flame motion parameter type</param>
|
||||
/// <param name="motion">The flame motion element to add the parameter to</param>
|
||||
/// <returns>True if there were no errors, else false.</returns>
|
||||
bool AttToEmberMotionFloat(xmlAttrPtr att, const char* attStr, eEmberMotionParam param, EmberMotion<T>& motion)
|
||||
{
|
||||
const char* loc = __FUNCTION__;
|
||||
bool r = false;
|
||||
T val = 0.0;
|
||||
|
||||
if (Atof(attStr, val))
|
||||
{
|
||||
motion.m_MotionParams.push_back(MotionParam<T>(param, val));
|
||||
r = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ErrorReport.push_back(string(loc) + " : Failed to parse float value for flame motion attribute \"" + string(CCX(att->name)) + "\" : " + string(attStr));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an xform element.
|
||||
/// </summary>
|
||||
@ -1047,9 +1192,8 @@ private:
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "animate", xform.m_Animate, success)) { }
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "opacity", xform.m_Opacity, success)) { }
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "var_color", xform.m_DirectColor, success)) { }
|
||||
|
||||
//Parse simple int reads.
|
||||
else if (ParseAndAssignInt(curAtt->name, attStr, "motion_frequency", xform.m_MotionFreq, success)) { }
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "motion_frequency", xform.m_MotionFreq, success)) { }
|
||||
else if (ParseAndAssignFloat(curAtt->name, attStr, "motion_offset", xform.m_MotionOffset, success)) { }
|
||||
|
||||
//Parse more complicated reads that have multiple possible values.
|
||||
else if (!Compare(curAtt->name, "name"))
|
||||
@ -1073,6 +1217,8 @@ private:
|
||||
xform.m_MotionFunc = MOTION_TRIANGLE;
|
||||
else if (!_stricmp("hill", attStr))
|
||||
xform.m_MotionFunc = MOTION_HILL;
|
||||
else if (!_stricmp("saw", attStr))
|
||||
xform.m_MotionFunc = MOTION_SAW;
|
||||
else
|
||||
{
|
||||
xform.m_MotionFunc = MOTION_SIN;
|
||||
|
@ -81,11 +81,12 @@ private:
|
||||
/// <param name="parser">The parser to use</param>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="embers">Storage for the embers read from the file</param>
|
||||
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.</param>
|
||||
/// <returns>True if success, else false.</returns>
|
||||
template <typename T>
|
||||
static bool ParseEmberFile(XmlToEmber<T>& parser, string filename, vector<Ember<T>>& embers)
|
||||
static bool ParseEmberFile(XmlToEmber<T>& parser, string filename, vector<Ember<T>>& embers, bool useDefaults = true)
|
||||
{
|
||||
if (!parser.Parse(filename.c_str(), embers))
|
||||
if (!parser.Parse(filename.c_str(), embers, useDefaults))
|
||||
{
|
||||
cout << "Error parsing flame file " << filename << ", returning without executing." << endl;
|
||||
return false;
|
||||
|
@ -76,7 +76,6 @@ enum eOptionIDs
|
||||
OPT_SYMMETRY,
|
||||
OPT_SHEEP_GEN,
|
||||
OPT_SHEEP_ID,
|
||||
OPT_LOOPS,
|
||||
OPT_REPEAT,
|
||||
OPT_TRIES,
|
||||
OPT_MAX_XFORMS,
|
||||
@ -93,6 +92,7 @@ enum eOptionIDs
|
||||
OPT_OFFSETX,
|
||||
OPT_OFFSETY,
|
||||
OPT_USEMEM,
|
||||
OPT_LOOPS,
|
||||
|
||||
OPT_ISAAC_SEED,//String value args.
|
||||
OPT_IN,
|
||||
@ -357,7 +357,6 @@ public:
|
||||
INITUINTOPTION(Frame, Eou(OPT_ANIM_GENOME, OPT_FRAME, _T("--frame"), 0, SO_REQ_SEP, "\t--frame=<val> Synonym for \"time\".\n"));
|
||||
INITUINTOPTION(Dtime, Eou(OPT_USE_ANIMATE, OPT_DTIME, _T("--dtime"), 1, SO_REQ_SEP, "\t--dtime=<val> Time between frames [default: 1].\n"));
|
||||
INITUINTOPTION(Frames, Eou(OPT_USE_GENOME, OPT_NFRAMES, _T("--nframes"), 20, SO_REQ_SEP, "\t--nframes=<val> Number of frames for each stage of the animation [default: 20].\n"));
|
||||
INITUINTOPTION(Loops, Eou(OPT_USE_GENOME, OPT_LOOPS, _T("--loops"), 1, SO_REQ_SEP, "\t--loops=<val> Number of times to rotate each control point in sequence [default: 1].\n"));
|
||||
INITUINTOPTION(Repeat, Eou(OPT_USE_GENOME, OPT_REPEAT, _T("--repeat"), 1, SO_REQ_SEP, "\t--repeat=<val> Number of new flames to create. Ignored if sequence, inter or rotate were specified [default: 1].\n"));
|
||||
INITUINTOPTION(Tries, Eou(OPT_USE_GENOME, OPT_TRIES, _T("--tries"), 10, SO_REQ_SEP, "\t--tries=<val> Number times to try creating a flame that meets the specified constraints. Ignored if sequence, inter or rotate were specified [default: 10].\n"));
|
||||
INITUINTOPTION(MaxXforms, Eou(OPT_USE_GENOME, OPT_MAX_XFORMS, _T("--maxxforms"), UINT_MAX, SO_REQ_SEP, "\t--maxxforms=<val> The maximum number of xforms allowed in the final output.\n"));
|
||||
@ -376,6 +375,7 @@ public:
|
||||
INITDOUBLEOPTION(OffsetX, Eod(OPT_USE_GENOME, OPT_OFFSETX, _T("--offsetx"), 0.0, SO_REQ_SEP, "\t--offsetx=<val> Amount to jitter each flame horizontally when applying genome tools [default: 0].\n"));
|
||||
INITDOUBLEOPTION(OffsetY, Eod(OPT_USE_GENOME, OPT_OFFSETY, _T("--offsety"), 0.0, SO_REQ_SEP, "\t--offsety=<val> Amount to jitter each flame vertically when applying genome tools [default: 0].\n"));
|
||||
INITDOUBLEOPTION(UseMem, Eod(OPT_USE_RENDER, OPT_USEMEM, _T("--use_mem"), 0.0, SO_REQ_SEP, "\t--use_mem=<val> Number of bytes of memory to use [default: max system memory].\n"));
|
||||
INITDOUBLEOPTION(Loops, Eod(OPT_USE_GENOME, OPT_LOOPS, _T("--loops"), 1.0, SO_REQ_SEP, "\t--loops=<val> Number of times to rotate each control point in sequence [default: 1].\n"));
|
||||
|
||||
//String.
|
||||
INITSTRINGOPTION(IsaacSeed, Eos(OPT_USE_ALL, OPT_ISAAC_SEED, _T("--isaac_seed"), "", SO_REQ_SEP, "\t--isaac_seed=<val> Character-based seed for the random number generator [default: random].\n"));
|
||||
@ -487,7 +487,6 @@ public:
|
||||
PARSEUINTOPTION(OPT_TIME, Time);
|
||||
PARSEUINTOPTION(OPT_DTIME, Dtime);
|
||||
PARSEUINTOPTION(OPT_NFRAMES, Frames);
|
||||
PARSEUINTOPTION(OPT_LOOPS, Loops);
|
||||
PARSEUINTOPTION(OPT_REPEAT, Repeat);
|
||||
PARSEUINTOPTION(OPT_TRIES, Tries);
|
||||
PARSEUINTOPTION(OPT_MAX_XFORMS, MaxXforms);
|
||||
@ -503,6 +502,7 @@ public:
|
||||
PARSEDOUBLEOPTION(OPT_OFFSETX, OffsetX);
|
||||
PARSEDOUBLEOPTION(OPT_OFFSETY, OffsetY);
|
||||
PARSEDOUBLEOPTION(OPT_USEMEM, UseMem);
|
||||
PARSEDOUBLEOPTION(OPT_LOOPS, Loops);
|
||||
|
||||
PARSESTRINGOPTION(OPT_ISAAC_SEED, IsaacSeed);//String args.
|
||||
PARSESTRINGOPTION(OPT_IN, Input);
|
||||
@ -703,7 +703,6 @@ public:
|
||||
EmberOptionEntry<uint> Time;
|
||||
EmberOptionEntry<uint> Dtime;
|
||||
EmberOptionEntry<uint> Frames;
|
||||
EmberOptionEntry<uint> Loops;
|
||||
EmberOptionEntry<uint> Repeat;
|
||||
EmberOptionEntry<uint> Tries;
|
||||
EmberOptionEntry<uint> MaxXforms;
|
||||
@ -719,6 +718,7 @@ public:
|
||||
EmberOptionEntry<double> OffsetX;
|
||||
EmberOptionEntry<double> OffsetY;
|
||||
EmberOptionEntry<double> UseMem;
|
||||
EmberOptionEntry<double> Loops;
|
||||
|
||||
EmberOptionEntry<string> IsaacSeed;//Value string.
|
||||
EmberOptionEntry<string> Input;
|
||||
|
@ -239,7 +239,7 @@ bool EmberGenome(EmberOptions& opt)
|
||||
|
||||
if (opt.TemplateFile() != "")
|
||||
{
|
||||
if (!ParseEmberFile(parser, opt.TemplateFile(), templateEmbers))
|
||||
if (!ParseEmberFile(parser, opt.TemplateFile(), templateEmbers, false))//Do not use defaults here to ensure only present fields get used when applying the template.
|
||||
return false;
|
||||
|
||||
if (templateEmbers.size() > 1)
|
||||
@ -382,9 +382,9 @@ bool EmberGenome(EmberOptions& opt)
|
||||
|
||||
for (i = 0; i < embers.size(); i++)
|
||||
{
|
||||
if (opt.Loops())
|
||||
if (opt.Loops() > 0)
|
||||
{
|
||||
for (frame = 0; frame < opt.Frames(); frame++)
|
||||
for (frame = 0; frame < round(T(opt.Frames()) * opt.Loops()); frame++)
|
||||
{
|
||||
blend = T(frame) / T(opt.Frames());
|
||||
tools.Spin(embers[i], pTemplate, result, frameCount++, blend);//Result is cleared and reassigned each time inside of Spin().
|
||||
@ -394,12 +394,23 @@ bool EmberGenome(EmberOptions& opt)
|
||||
|
||||
if (i < embers.size() - 1)
|
||||
{
|
||||
vector<Ember<T>> interpEmbers;
|
||||
|
||||
interpEmbers.push_back(embers[i]);
|
||||
interpEmbers.push_back(embers[i + 1]);
|
||||
|
||||
if (opt.Loops() > 0)
|
||||
{
|
||||
//We might have looped a non-integral number of times, so store the last result as our flame to interpolate from.
|
||||
interpEmbers[i] = result;
|
||||
}
|
||||
|
||||
for (frame = 0; frame < opt.Frames(); frame++)
|
||||
{
|
||||
seqFlag = (frame == 0 || frame == opt.Frames() - 1);
|
||||
blend = frame / T(opt.Frames());
|
||||
result.Clear();
|
||||
tools.SpinInter(&embers[i], pTemplate, result, frameCount++, seqFlag, blend);
|
||||
tools.SpinInter(&interpEmbers[i], pTemplate, result, frameCount++, seqFlag, blend);
|
||||
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ Fractorium::Fractorium(QWidget* p)
|
||||
InitXaosUI();
|
||||
InitPaletteUI();
|
||||
InitLibraryUI();
|
||||
InitInfoUI();
|
||||
InitMenusUI();
|
||||
|
||||
//This will init the controller and fill in the variations and palette tables with template specific instances
|
||||
@ -175,6 +176,7 @@ Fractorium::Fractorium(QWidget* p)
|
||||
ui.XformPaletteRefTable->setStyleSheet("QTableWidget::item { padding: 0px; border: none; margin: 0px; }");
|
||||
ui.PaletteAdjustTable->setStyleSheet("QTableWidget::item { padding: 1px; }");//Need this to avoid covering the top border pixel with the spinners.
|
||||
ui.statusBar->setStyleSheet("QStatusBar QLabel { padding-left: 2px; padding-right: 2px; }");
|
||||
ui.XaosTableView->setStyleSheet("QTableView { margin: 1px}");
|
||||
|
||||
//setStyleSheet("QGroupBox { border: 2px solid gray; border-radius: 3px; } ");
|
||||
|
||||
@ -747,7 +749,11 @@ void Fractorium::SetTabOrders()
|
||||
w = SetTabOrder(this, w, ui.PaletteFilterClearButton);
|
||||
w = SetTabOrder(this, w, ui.PaletteListTable);
|
||||
|
||||
w = SetTabOrder(this, ui.InfoBoundsGroupBox, ui.InfoBoundsFrame);//Info.
|
||||
|
||||
w = SetTabOrder(this, ui.SummaryTableWidget, ui.SummaryTreeWidget);//Info summary.
|
||||
|
||||
w = SetTabOrder(this, ui.InfoBoundsGroupBox, ui.InfoBoundsFrame);//Info bounds.
|
||||
|
||||
w = SetTabOrder(this, w, ui.InfoBoundsTable);
|
||||
w = SetTabOrder(this, w, ui.InfoFileOpeningGroupBox);
|
||||
w = SetTabOrder(this, w, ui.InfoFileOpeningTextEdit);
|
||||
|
@ -142,9 +142,6 @@ public slots:
|
||||
void OnActionAbout(bool checked);//Help.
|
||||
|
||||
//Toolbar.
|
||||
void OnSaveCurrentAsXmlButtonClicked(bool checked);
|
||||
void OnSaveEntireFileAsXmlButtonClicked(bool checked);
|
||||
void OnSaveCurrentToOpenedFileButtonClicked(bool checked);
|
||||
|
||||
//Library.
|
||||
void OnEmberTreeItemChanged(QTreeWidgetItem* item, int col);
|
||||
@ -275,6 +272,10 @@ public slots:
|
||||
void OnPaletteFilterClearButtonClicked(bool checked);
|
||||
void OnPaletteHeaderSectionClicked(int col);
|
||||
|
||||
//Info.
|
||||
void OnSummaryTableHeaderResized(int logicalIndex, int oldSize, int newSize);
|
||||
void OnSummaryTreeHeaderSectionClicked(int logicalIndex);
|
||||
|
||||
//Rendering/progress.
|
||||
void StartRenderTimer();
|
||||
void IdleTimer();
|
||||
@ -311,6 +312,7 @@ private:
|
||||
void InitXaosUI();
|
||||
void InitPaletteUI();
|
||||
void InitLibraryUI();
|
||||
void InitInfoUI();
|
||||
void SetTabOrders();
|
||||
|
||||
void ToggleTableRow(QTableView* table, int logicalIndex);
|
||||
@ -342,10 +344,13 @@ private:
|
||||
//Palette.
|
||||
void ResetPaletteControls();
|
||||
void SetPaletteFileComboIndex(const string& filename);
|
||||
void SetPaletteTableItem(QPixmap* pixmap, QTableWidget* table, QTableWidgetItem* item, int row, int col);
|
||||
|
||||
//Info.
|
||||
void FillSummary();
|
||||
void UpdateHistogramBounds();
|
||||
void ErrorReportToQTextEdit(const vector<string>& errors, QTextEdit* textEdit, bool clear = true);
|
||||
void SetTableWidgetBackgroundColor();
|
||||
|
||||
//Rendering/progress.
|
||||
bool CreateRendererFromOptions();
|
||||
@ -441,6 +446,14 @@ private:
|
||||
SpinBox* m_PaletteBlurSpin;
|
||||
SpinBox* m_PaletteFrequencySpin;
|
||||
|
||||
//Info.
|
||||
QTableWidgetItem* m_InfoNameItem;
|
||||
QTableWidgetItem* m_InfoPaletteItem;
|
||||
QTableWidgetItem* m_Info3dItem;
|
||||
QTableWidgetItem* m_InfoXaosItem;
|
||||
QTableWidgetItem* m_InfoXformCountItem;
|
||||
QTableWidgetItem* m_InfoFinalXformItem;
|
||||
|
||||
//Files.
|
||||
QFileDialog* m_FileDialog;
|
||||
QFileDialog* m_FolderDialog;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -111,3 +111,78 @@ static bool Exists(const QString& s)
|
||||
{
|
||||
return s != "" && QDir(s).exists();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a color to one that is displayable on any background.
|
||||
/// </summary>
|
||||
/// <param name="color">The color to convert</param>
|
||||
/// <returns>The converted color</returns>
|
||||
static QColor VisibleColor(const QColor& color)
|
||||
{
|
||||
int threshold = 105;
|
||||
int delta = (color.red() * 0.299) + //Magic numbers gotten from a Stack Overflow post.
|
||||
(color.green() * 0.587) +
|
||||
(color.blue() * 0.114);
|
||||
|
||||
QColor textColor = (255 - delta < threshold) ? QColor(0, 0, 0) : QColor(255, 255, 255);
|
||||
return textColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether an xform in an ember is linked to any other xform
|
||||
/// in the ember.
|
||||
/// </summary>
|
||||
/// <param name="ember">The ember which contains the xform</param>
|
||||
/// <param name="xform">The xform to inspect</param>
|
||||
/// <returns>The index of the xform that the xform argument is linked to, else -1</returns>
|
||||
template <typename T>
|
||||
static intmax_t IsXformLinked(Ember<T>& ember, Xform<T>* xform)
|
||||
{
|
||||
auto count = ember.XformCount();
|
||||
auto index = ember.GetXformIndex(xform);
|
||||
intmax_t linked = -1;
|
||||
size_t toOneCount = 0;
|
||||
size_t toZeroCount = 0;
|
||||
size_t toOneIndex = 0;
|
||||
size_t fromOneCount = 0;
|
||||
size_t fromZeroCount = 0;
|
||||
size_t fromOneIndex = 0;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
for (auto i = 0; i < count; i++)
|
||||
{
|
||||
if (xform->Xaos(i) == 0)
|
||||
toZeroCount++;
|
||||
else if (xform->Xaos(i) == 1)
|
||||
{
|
||||
toOneIndex = i;
|
||||
toOneCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((toZeroCount == (count - 1)) && toOneCount == 1)
|
||||
{
|
||||
for (auto i = 0; i < count; i++)
|
||||
{
|
||||
if (auto fromXform = ember.GetXform(i))
|
||||
{
|
||||
if (fromXform->Xaos(toOneIndex) == 0)
|
||||
fromZeroCount++;
|
||||
else if (fromXform->Xaos(toOneIndex) == 1)
|
||||
{
|
||||
fromOneIndex = i;
|
||||
fromOneCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((fromZeroCount == (count - 1)) && fromOneCount == 1)
|
||||
{
|
||||
linked = toOneIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return linked;
|
||||
}
|
@ -217,6 +217,7 @@ template <typename T>
|
||||
void FractoriumEmberController<T>::Update(std::function<void (void)> func, bool updateRender, eProcessAction action)
|
||||
{
|
||||
func();
|
||||
FillSummary();
|
||||
|
||||
if (updateRender)
|
||||
UpdateRender(action);
|
||||
@ -294,6 +295,8 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
|
||||
break;
|
||||
}
|
||||
|
||||
FillSummary();
|
||||
|
||||
if (updateRender)
|
||||
UpdateRender(action);
|
||||
}
|
||||
@ -305,6 +308,7 @@ void FractoriumEmberController<T>::UpdateXform(std::function<void(Xform<T>*)> fu
|
||||
/// Resets the rendering process.
|
||||
/// </summary>
|
||||
/// <param name="ember">The ember to set as the current</param>
|
||||
/// <param name="verbatim">If true, do not overwrite temporal samples, quality or supersample value, else overwrite.</param>
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool verbatim)
|
||||
@ -335,6 +339,7 @@ void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool v
|
||||
m_GLController->ResetMouseState();
|
||||
FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo.
|
||||
FillParamTablesAndPalette();
|
||||
FillSummary();
|
||||
|
||||
//If a resize happened, this won't do anything because the new size is not reflected in the scroll area yet.
|
||||
//However, it will have been taken care of in SyncSizes() in that case, so it's ok.
|
||||
|
@ -178,7 +178,7 @@ public:
|
||||
virtual void XformColorSpeedChanged(double d) { }
|
||||
virtual void XformOpacityChanged(double d) { }
|
||||
virtual void XformDirectColorChanged(double d) { }
|
||||
void SetPaletteRefTable(QPixmap* pixmap);
|
||||
virtual QColor ColorIndexToQColor(double d) { return QColor(); }
|
||||
|
||||
//Xforms Variations.
|
||||
virtual void SetupVariationTree() { }
|
||||
@ -199,11 +199,12 @@ public:
|
||||
virtual bool FillPaletteTable(const string& s) { return false; }
|
||||
virtual void ApplyPaletteToEmber() { }
|
||||
virtual void PaletteAdjust() { }
|
||||
virtual QRgb GetQRgbFromPaletteIndex(uint i) { return QRgb(); }
|
||||
virtual void PaletteCellClicked(int row, int col) { }
|
||||
QImage& FinalPaletteImage() { return m_FinalPaletteImage; }
|
||||
|
||||
//Info.
|
||||
|
||||
virtual void FillSummary() { }
|
||||
|
||||
//Rendering/progress.
|
||||
virtual bool Render() { return false; }
|
||||
virtual bool CreateRenderer(eRendererType renderType, uint platform, uint device, bool shared = true) { return false; }
|
||||
@ -413,6 +414,7 @@ public:
|
||||
virtual void XformColorSpeedChanged(double d) override;
|
||||
virtual void XformOpacityChanged(double d) override;
|
||||
virtual void XformDirectColorChanged(double d) override;
|
||||
virtual QColor ColorIndexToQColor(double d) override;
|
||||
void FillColorWithXform(Xform<T>* xform);
|
||||
|
||||
//Xforms Variations.
|
||||
@ -433,10 +435,10 @@ public:
|
||||
virtual bool FillPaletteTable(const string& s) override;
|
||||
virtual void ApplyPaletteToEmber() override;
|
||||
virtual void PaletteAdjust() override;
|
||||
virtual QRgb GetQRgbFromPaletteIndex(uint i) override { return QRgb(); }
|
||||
virtual void PaletteCellClicked(int row, int col) override;
|
||||
|
||||
//Info.
|
||||
virtual void FillSummary() override;
|
||||
|
||||
//Rendering/progress.
|
||||
virtual bool Render() override;
|
||||
|
@ -1,6 +1,219 @@
|
||||
#include "FractoriumPch.h"
|
||||
#include "Fractorium.h"
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the info UI.
|
||||
/// </summary>
|
||||
void Fractorium::InitInfoUI()
|
||||
{
|
||||
auto treeHeader = ui.SummaryTreeWidget->header();
|
||||
auto tableHeader = ui.SummaryTableWidget->horizontalHeader();
|
||||
|
||||
treeHeader->setVisible(true);
|
||||
treeHeader->setSectionsClickable(true);
|
||||
treeHeader->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
connect(treeHeader, SIGNAL(sectionClicked(int)), this, SLOT(OnSummaryTreeHeaderSectionClicked(int)), Qt::QueuedConnection);
|
||||
connect(tableHeader, SIGNAL(sectionResized(int, int, int)), this, SLOT(OnSummaryTableHeaderResized(int, int, int)), Qt::QueuedConnection);
|
||||
SetFixedTableHeader(ui.SummaryTableWidget->verticalHeader());
|
||||
|
||||
ui.SummaryTableWidget->setItem(0, 0, m_InfoNameItem = new QTableWidgetItem(""));
|
||||
ui.SummaryTableWidget->setItem(1, 0, m_InfoPaletteItem = new QTableWidgetItem(""));
|
||||
ui.SummaryTableWidget->setItem(2, 0, m_Info3dItem = new QTableWidgetItem(""));
|
||||
ui.SummaryTableWidget->setItem(3, 0, m_InfoXaosItem = new QTableWidgetItem(""));
|
||||
ui.SummaryTableWidget->setItem(4, 0, m_InfoXformCountItem = new QTableWidgetItem(""));
|
||||
ui.SummaryTableWidget->setItem(5, 0, m_InfoFinalXformItem = new QTableWidgetItem(""));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the palette cell of the summary table is resized in response
|
||||
/// to a resizing of the Info dock.
|
||||
/// </summary>
|
||||
/// <param name="logicalIndex">Ignored</param>
|
||||
/// <param name="oldSize">Ignored</param>
|
||||
/// <param name="newSize">Ignored</param>
|
||||
void Fractorium::OnSummaryTableHeaderResized(int logicalIndex, int oldSize, int newSize)
|
||||
{
|
||||
QPixmap pixmap = QPixmap::fromImage(m_Controller->FinalPaletteImage());//Create a QPixmap out of the QImage.
|
||||
SetPaletteTableItem(&pixmap, ui.SummaryTableWidget, m_InfoPaletteItem, 1, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expand or collapse the summary tree depending on the column index clicked.
|
||||
/// 0: collapse, 1: expand.
|
||||
/// </summary>
|
||||
/// <param name="logicalIndex">The column which was clicked</param>
|
||||
void Fractorium::OnSummaryTreeHeaderSectionClicked(int logicalIndex)
|
||||
{
|
||||
auto tree = ui.SummaryTreeWidget;
|
||||
|
||||
if (logicalIndex)
|
||||
tree->expandAll();
|
||||
else
|
||||
tree->collapseAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the summary tree with values from the current ember.
|
||||
/// This is meant to be a rough summary by containing only the most relevant
|
||||
/// values from the ember.
|
||||
/// It's also meant to be used in a fire-and-forget way. Once the tree is filled
|
||||
/// individual nodes are never referenced again.
|
||||
/// The entire tree is cleared and refilled for every field change.
|
||||
/// This would seem inefficient, but it appears to update with no flicker.
|
||||
/// If this ever presents a problem in the future, revisit with a more
|
||||
/// intelligent design.
|
||||
/// </summary>
|
||||
template <typename T>
|
||||
void FractoriumEmberController<T>::FillSummary()
|
||||
{
|
||||
int p = 3;
|
||||
int vp = 4;
|
||||
int vlen = 7;
|
||||
char pc = 'f';
|
||||
size_t x = 0, total = m_Ember.TotalXformCount();
|
||||
Xform<T>* xform = nullptr;
|
||||
QColor color;
|
||||
auto table = m_Fractorium->ui.SummaryTableWidget;
|
||||
auto tree = m_Fractorium->ui.SummaryTreeWidget;
|
||||
QVariantList states;
|
||||
QTreeWidgetItemIterator it(tree);
|
||||
|
||||
while (*it)
|
||||
{
|
||||
if (!(*it)->parent())//Top level only.
|
||||
states += (*it)->isExpanded();
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
tree->blockSignals(true);
|
||||
tree->clear();
|
||||
m_Fractorium->m_InfoNameItem->setText(m_Ember.m_Name.c_str());
|
||||
m_Fractorium->m_Info3dItem->setText(m_Ember.ProjBits() ? "Yes" : "No");
|
||||
m_Fractorium->m_InfoXaosItem->setText(m_Ember.XaosPresent() ? "Yes" : "No");
|
||||
m_Fractorium->m_InfoXformCountItem->setText(QString::number(m_Ember.XformCount()));
|
||||
m_Fractorium->m_InfoFinalXformItem->setText(m_Ember.UseFinalXform() ? "Yes" : "No");
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage(m_FinalPaletteImage);//Create a QPixmap out of the QImage.
|
||||
QSize size(table->columnWidth(0), table->rowHeight(1) + 1);
|
||||
m_Fractorium->m_InfoPaletteItem->setData(Qt::DecorationRole, pixmap.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
|
||||
for (x = 0; x < total && (xform = m_Ember.GetTotalXform(x)); x++)
|
||||
{
|
||||
size_t i = 0;
|
||||
QString as = "Pre";
|
||||
auto item1 = new QTreeWidgetItem(tree);
|
||||
intmax_t linkedIndex = IsXformLinked(m_Ember, xform);
|
||||
QString linked = (linkedIndex != -1) ? (" Linked to " + QString::number(linkedIndex + 1)) : "";
|
||||
auto index = m_Ember.GetXformIndex(xform);
|
||||
m_Ember.CalcNormalizedWeights(m_NormalizedWeights);
|
||||
|
||||
if (!m_Ember.IsFinalXform(xform) && index != -1)
|
||||
{
|
||||
item1->setText(0, "Xform " +
|
||||
QString::number(x + 1) +
|
||||
" (" + QLocale::system().toString(xform->m_Weight, pc, p) + ") (" +
|
||||
QLocale::system().toString(double(m_NormalizedWeights[index]), pc, p) + ") " +
|
||||
linked);
|
||||
}
|
||||
else
|
||||
item1->setText(0, "Final xform");
|
||||
|
||||
item1->setText(1, xform->m_Name.c_str());
|
||||
|
||||
auto affineItem = new QTreeWidgetItem(item1);
|
||||
affineItem->setText(0, "Affine");
|
||||
|
||||
if (xform->m_Affine.IsZero())
|
||||
as += " Empty";
|
||||
else if (xform->m_Affine.IsID())
|
||||
as += " ID";
|
||||
|
||||
if (xform->HasPost())
|
||||
{
|
||||
as += ", Post";
|
||||
|
||||
if (xform->m_Post.IsZero())
|
||||
as += " Empty";//Don't need to check further for IsID() because post is not included if it's ID.
|
||||
}
|
||||
|
||||
affineItem->setText(1, as);
|
||||
|
||||
auto colorIndexItem = new QTreeWidgetItem(item1);
|
||||
colorIndexItem->setText(0, "Color index");
|
||||
colorIndexItem->setText(1, QLocale::system().toString(xform->m_ColorX, pc, p));
|
||||
color = ColorIndexToQColor(xform->m_ColorX);
|
||||
color.setAlphaF(xform->m_Opacity);
|
||||
colorIndexItem->setBackgroundColor(1, color);
|
||||
colorIndexItem->setTextColor(1, VisibleColor(color));
|
||||
|
||||
auto colorSpeedItem = new QTreeWidgetItem(item1);
|
||||
colorSpeedItem->setText(0, "Color speed");
|
||||
colorSpeedItem->setText(1, QLocale::system().toString(xform->m_ColorSpeed, pc, p));
|
||||
|
||||
auto opacityItem = new QTreeWidgetItem(item1);
|
||||
opacityItem->setText(0, "Opacity");
|
||||
opacityItem->setText(1, QLocale::system().toString(xform->m_Opacity, pc, p));
|
||||
|
||||
auto dcItem = new QTreeWidgetItem(item1);
|
||||
dcItem->setText(0, "Direct color");
|
||||
dcItem->setText(1, QLocale::system().toString(xform->m_DirectColor, pc, p));
|
||||
|
||||
while (auto var = xform->GetVariation(i++))
|
||||
{
|
||||
auto vitem = new QTreeWidgetItem(item1);
|
||||
|
||||
vitem->setText(0, QString::fromStdString(var->Name()));
|
||||
vitem->setText(1, QLocale::system().toString(var->m_Weight, pc, vp).rightJustified(vlen, ' '));
|
||||
|
||||
if (auto parVar = dynamic_cast<ParametricVariation<T>*>(var))
|
||||
{
|
||||
auto params = parVar->Params();
|
||||
|
||||
for (auto j = 0; j < parVar->ParamCount(); j++)
|
||||
{
|
||||
if (!params[j].IsPrecalc())
|
||||
{
|
||||
auto pitem = new QTreeWidgetItem(vitem);
|
||||
|
||||
pitem->setText(0, params[j].Name().c_str());
|
||||
pitem->setText(1, QLocale::system().toString(params[j].ParamVal(), pc, vp).rightJustified(vlen, ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto item2 = new QTreeWidgetItem(tree);//Empty item in between xforms.
|
||||
}
|
||||
|
||||
QTreeWidgetItemIterator it2(tree);
|
||||
|
||||
if (!states.isEmpty())
|
||||
{
|
||||
while (*it2)
|
||||
{
|
||||
if (!(*it2)->parent())//Top level only.
|
||||
{
|
||||
if (!states.isEmpty())
|
||||
(*it2)->setExpanded(states.takeFirst().toBool());
|
||||
else
|
||||
(*it2)->setExpanded(true);//Expand any remainder when going from lesser to greater number of xforms.
|
||||
}
|
||||
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
else
|
||||
tree->expandAll();
|
||||
|
||||
tree->blockSignals(false);
|
||||
}
|
||||
|
||||
void Fractorium::FillSummary()
|
||||
{
|
||||
m_Controller->FillSummary();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the histogram bounds display labels.
|
||||
/// This shows the user the actual bounds of what's
|
||||
@ -54,3 +267,9 @@ void Fractorium::ErrorReportToQTextEdit(const vector<string>& errors, QTextEdit*
|
||||
for (auto& error : errors)
|
||||
QMetaObject::invokeMethod(textEdit, "append", Qt::QueuedConnection, Q_ARG(const QString&, QString::fromStdString(error) + "\n"));
|
||||
}
|
||||
|
||||
template class FractoriumEmberController<float>;
|
||||
|
||||
#ifdef DO_DOUBLE
|
||||
template class FractoriumEmberController<double>;
|
||||
#endif
|
||||
|
@ -226,8 +226,9 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
|
||||
m_Ember.m_Name = newName;
|
||||
m_LastSaveCurrent = "";//Reset will force the dialog to show on the next save current since the user probably wants a different name.
|
||||
}
|
||||
|
||||
|
||||
tree->blockSignals(false);
|
||||
FillSummary();
|
||||
}
|
||||
else if (QTreeWidgetItem* parentItem = dynamic_cast<QTreeWidgetItem*>(item))
|
||||
{
|
||||
|
@ -192,7 +192,7 @@ void FractoriumEmberController<T>::UpdateAdjustedPaletteGUI(Palette<T>& palette)
|
||||
memcpy(m_FinalPaletteImage.scanLine(0), v.data(), v.size() * sizeof(v[0]));//Memcpy the data in.
|
||||
QPixmap pixmap = QPixmap::fromImage(m_FinalPaletteImage);//Create a QPixmap out of the QImage.
|
||||
previewPaletteItem->setData(Qt::DecorationRole, pixmap.scaled(QSize(pixmap.width(), palettePreviewTable->rowHeight(0) + 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));//Set the pixmap on the palette tab.
|
||||
SetPaletteRefTable(&pixmap);//Set the palette ref table on the xforms | color tab.
|
||||
m_Fractorium->SetPaletteTableItem(&pixmap, m_Fractorium->ui.XformPaletteRefTable, m_Fractorium->m_PaletteRefItem, 0, 0);//Set the palette ref table on the xforms | color tab.
|
||||
|
||||
QTableWidgetItem* previewNameItem = palettePreviewTable->item(0, 0);
|
||||
previewNameItem->setText(paletteName);//Finally, set the name of the palette to be both the text and the tooltip.
|
||||
|
@ -183,13 +183,7 @@ void FractoriumEmberController<T>::BackgroundChanged(const QColor& color)
|
||||
QString g = ToString(color.green());
|
||||
QString b = ToString(color.blue());
|
||||
|
||||
int threshold = 105;
|
||||
int delta = (color.red() * 0.299) + //Magic numbers gotten from a Stack Overflow post.
|
||||
(color.green() * 0.587) +
|
||||
(color.blue() * 0.114);
|
||||
|
||||
QColor textColor = (255 - delta < threshold) ? QColor(0, 0, 0) : QColor(255, 255, 255);
|
||||
colorTable->item(itemRow, 1)->setTextColor(textColor);
|
||||
colorTable->item(itemRow, 1)->setTextColor(VisibleColor(color));
|
||||
colorTable->item(itemRow, 1)->setText("rgb(" + r + ", " + g + ", " + b + ")");
|
||||
|
||||
//Color is 0-255, normalize to 0-1.
|
||||
|
@ -6,16 +6,5 @@
|
||||
/// </summary>
|
||||
void Fractorium::InitToolbarUI()
|
||||
{
|
||||
//These aren't menus but duplicate menu functionality in a pseudo-toolbar.
|
||||
connect(ui.SaveCurrentAsXmlButton, SIGNAL(clicked(bool)), this, SLOT(OnSaveCurrentAsXmlButtonClicked(bool)), Qt::QueuedConnection);
|
||||
connect(ui.SaveEntireFileAsXmlButton, SIGNAL(clicked(bool)), this, SLOT(OnSaveEntireFileAsXmlButtonClicked(bool)), Qt::QueuedConnection);
|
||||
connect(ui.SaveCurrentToOpenedFileButton, SIGNAL(clicked(bool)), this, SLOT(OnSaveCurrentToOpenedFileButtonClicked(bool)), Qt::QueuedConnection);
|
||||
//Empty for the moment, all functionality is handled in the designer.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrappers around calls to menu items.
|
||||
/// </summary>
|
||||
|
||||
void Fractorium::OnSaveCurrentAsXmlButtonClicked(bool checked) { OnActionSaveCurrentAsXml(checked); }
|
||||
void Fractorium::OnSaveEntireFileAsXmlButtonClicked(bool checked) { OnActionSaveEntireFileAsXml(checked); }
|
||||
void Fractorium::OnSaveCurrentToOpenedFileButtonClicked(bool checked) { OnActionSaveCurrentToOpenedFile(checked); }
|
||||
|
@ -150,8 +150,8 @@ void Fractorium::InitXformsAffineUI()
|
||||
|
||||
//Further, the size of the dock widget won't be properly adjusted until the xforms tab is shown.
|
||||
//So show it here and it will be switched back in Fractorium's constructor.
|
||||
//ui.ParamsTabWidget->setCurrentIndex(2);
|
||||
//ui.DockWidget->update();
|
||||
//ui.ParamsTabWidget->setCurrentIndex(2);
|
||||
//ui.DockWidget->update();
|
||||
#endif
|
||||
|
||||
//Placing pointers to the spin boxes in arrays makes them easier to access in various places.
|
||||
|
@ -142,7 +142,9 @@ void Fractorium::OnSoloXformCheckBoxStateChanged(int state)
|
||||
/// <param name="newSize">Ignored</param>
|
||||
void Fractorium::OnXformRefPaletteResized(int logicalIndex, int oldSize, int newSize)
|
||||
{
|
||||
m_Controller->SetPaletteRefTable(nullptr);
|
||||
QPixmap pixmap = QPixmap::fromImage(m_Controller->FinalPaletteImage());
|
||||
|
||||
SetPaletteTableItem(&pixmap, ui.XformPaletteRefTable, m_PaletteRefItem, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -194,6 +196,25 @@ void Fractorium::OnCurvesRedRadioButtonToggled(bool checked) { if (checked) ui
|
||||
void Fractorium::OnCurvesGreenRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::GREEN); }
|
||||
void Fractorium::OnCurvesBlueRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::BLUE); }
|
||||
|
||||
/// <summary>
|
||||
/// Look up the passed in index in the current ember's palette
|
||||
/// and return the QColor equivalent.
|
||||
/// </summary>
|
||||
/// <param name="d">The palette index to look up, 0-1.</param>
|
||||
/// <returns>The palette color at the given index as a QColor</returns>
|
||||
template <typename T>
|
||||
QColor FractoriumEmberController<T>::ColorIndexToQColor(double d)
|
||||
{
|
||||
v4T entry = m_Ember.m_Palette[Clamp<int>(d * COLORMAP_LENGTH_MINUS_1, 0, m_Ember.m_Palette.Size())];
|
||||
|
||||
entry.r *= 255;
|
||||
entry.g *= 255;
|
||||
entry.b *= 255;
|
||||
|
||||
QRgb rgb = uint(entry.r) << 16 | uint(entry.g) << 8 | uint(entry.b);
|
||||
return QColor::fromRgb(rgb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the selected xforms color index to the passed in value.
|
||||
/// Set the color cell in the palette ref table.
|
||||
@ -207,14 +228,7 @@ void FractoriumEmberController<T>::SetCurrentXformColorIndex(double d, bool upda
|
||||
xform->m_ColorX = Clamp<T>(d, 0, 1);
|
||||
|
||||
//Grab the current color from the index and assign it to the first cell of the first table.
|
||||
v4T entry = m_Ember.m_Palette[Clamp<int>(d * COLORMAP_LENGTH_MINUS_1, 0, m_Ember.m_Palette.Size())];
|
||||
|
||||
entry.r *= 255;
|
||||
entry.g *= 255;
|
||||
entry.b *= 255;
|
||||
|
||||
QRgb rgb = uint(entry.r) << 16 | uint(entry.g) << 8 | uint(entry.b);
|
||||
m_Fractorium->ui.XformColorIndexTable->item(0, 0)->setBackgroundColor(QColor::fromRgb(rgb));
|
||||
m_Fractorium->ui.XformColorIndexTable->item(0, 0)->setBackgroundColor(ColorIndexToQColor(xform->m_ColorX)/*QColor::fromRgb(rgb)*/);
|
||||
}, eXformUpdate::UPDATE_SELECTED, updateRender);
|
||||
}
|
||||
|
||||
@ -257,22 +271,19 @@ void FractoriumEmberController<T>::FillColorWithXform(Xform<T>* xform)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the palette reference table to the passed in pixmap
|
||||
/// Set the cell at the row and column in the passed in table to the passed in pixmap.
|
||||
/// </summary>
|
||||
/// <param name="pixmap">The pixmap</param>
|
||||
void FractoriumEmberControllerBase::SetPaletteRefTable(QPixmap* pixmap)
|
||||
/// <param name="pixmap">The pixmap to assign</param>
|
||||
/// <param name="table">The table whose cell will be filled with the image</param>
|
||||
/// <param name="item">The QTableWidgetItem in the cell</param>
|
||||
/// <param name="row">The row of the cell</param>
|
||||
/// <param name="col">The column of the cell</param>
|
||||
void Fractorium::SetPaletteTableItem(QPixmap* pixmap, QTableWidget* table, QTableWidgetItem* item, int row, int col)
|
||||
{
|
||||
QSize size(m_Fractorium->ui.XformPaletteRefTable->columnWidth(0), m_Fractorium->ui.XformPaletteRefTable->rowHeight(0) + 1);
|
||||
|
||||
if (pixmap)
|
||||
{
|
||||
m_Fractorium->m_PaletteRefItem->setData(Qt::DecorationRole, pixmap->scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
else if (!m_FinalPaletteImage.isNull())
|
||||
{
|
||||
QPixmap pixTemp = QPixmap::fromImage(m_FinalPaletteImage);
|
||||
|
||||
m_Fractorium->m_PaletteRefItem->setData(Qt::DecorationRole, pixTemp.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
QSize size(table->columnWidth(col), table->rowHeight(row) + 1);
|
||||
item->setData(Qt::DecorationRole, pixmap->scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@ void FractoriumEmberController<T>::VariationSpinBoxValueChanged(double d)//Would
|
||||
{
|
||||
if (xformParVar->SetParamVal(sender->ParamName().c_str(), d))
|
||||
{
|
||||
FillSummary();
|
||||
UpdateRender();
|
||||
}
|
||||
}
|
||||
@ -203,6 +204,7 @@ void FractoriumEmberController<T>::VariationSpinBoxValueChanged(double d)//Would
|
||||
}
|
||||
}
|
||||
|
||||
FillSummary();
|
||||
UpdateRender();
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>347</height>
|
||||
<height>368</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -19,13 +19,13 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>347</height>
|
||||
<height>368</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>347</height>
|
||||
<height>368</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
Loading…
Reference in New Issue
Block a user