2014-07-08 03:11:14 -04:00
# pragma once
# include "VariationList.h"
2014-09-01 00:25:15 -04:00
# include "Interpolate.h"
2014-07-08 03:11:14 -04:00
/// <summary>
/// Xform class.
/// </summary>
namespace EmberNs
{
/// <summary>
/// Xform and Variation need each other, but each can't include the other.
/// So Xform includes this file, and Ember is declared as a forward declaration here.
/// </summary>
template < typename T > class Ember ;
/// <summary>
/// If both polymorphism and templating are needed, uncomment this, fill it out and derive from it.
/// </summary>
//class EMBER_API XformBase
//{
//};
/// <summary>
/// An xform is a pre affine transform, a list of variations, and an optional final affine transform.
/// This is what gets applied to a point for each iteration.
/// Template argument expected to be float or double.
/// </summary>
template < typename T >
class EMBER_API Xform
{
public :
/// <summary>
2015-03-25 23:47:57 -04:00
/// Default constructor which calls Init() to set default or out of bounds values.
/// When useDefaults is true, Pre and post affine are defaulted to the identity matrix.
2014-07-08 03:11:14 -04:00
/// </summary>
2015-03-25 23:47:57 -04:00
/// <param name="useDefaults">Use reasonable default if true, else use out of bounds values.</param>
Xform ( bool useDefaults = true )
2014-07-08 03:11:14 -04:00
{
2015-03-25 23:47:57 -04:00
Init ( useDefaults ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Constructor that takes default arguments. Mostly used for testing.
/// Post affine is defaulted to the identity matrix.
/// </summary>
/// <param name="density">The probability that this xform is chosen</param>
/// <param name="colorX">The color index</param>
/// <param name="colorSpeed">The color speed</param>
/// <param name="opacity">The opacity</param>
/// <param name="a">The a value of the pre affine transform</param>
/// <param name="d">The d value of the pre affine transform</param>
/// <param name="b">The b value of the pre affine transform</param>
/// <param name="e">The e value of the pre affine transform</param>
/// <param name="c">The c value of the pre affine transform</param>
/// <param name="f">The f value of the pre affine transform</param>
/// <param name="pa">The a value of the post affine transform. Default: 1.</param>
/// <param name="pd">The d value of the post affine transform. Default: 0.</param>
/// <param name="pb">The b value of the post affine transform. Default: 0.</param>
/// <param name="pe">The e value of the post affine transform. Default: 1.</param>
/// <param name="pc">The c value of the post affine transform. Default: 0.</param>
/// <param name="pf">The f value of the post affine transform. Default: 0.</param>
Xform ( T weight , T colorX , T colorSpeed , T opacity ,
T a , T d , T b , T e , T c , T f ,
T pa = 1 ,
T pd = 0 ,
T pb = 0 ,
T pe = 1 ,
T pc = 0 ,
T pf = 0 )
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
{
Init ( ) ;
m_Weight = weight ;
m_ColorX = colorX ;
m_ColorSpeed = colorSpeed ;
m_Opacity = opacity ;
m_Affine . A ( a ) ;
m_Affine . B ( b ) ;
m_Affine . C ( c ) ;
m_Affine . D ( d ) ;
m_Affine . E ( e ) ;
m_Affine . F ( f ) ;
m_Post . A ( pa ) ;
m_Post . B ( pb ) ;
m_Post . C ( pc ) ;
m_Post . D ( pd ) ;
m_Post . E ( pe ) ;
m_Post . F ( pf ) ;
m_HasPost = ! m_Post . IsID ( ) ;
m_HasPreOrRegularVars = PreVariationCount ( ) > 0 | | VariationCount ( ) > 0 ;
CacheColorVals ( ) ; //Init already called this, but must call again since color was assigned above.
}
/// <summary>
/// Default copy constructor.
/// </summary>
/// <param name="xform">The Xform object to copy</param>
Xform ( const Xform < T > & xform )
2014-09-10 01:41:26 -04:00
: m_ParentEmber ( nullptr ) //Hack.
2014-07-08 03:11:14 -04:00
{
Xform < T > : : operator = < T > ( xform ) ;
}
/// <summary>
/// Copy constructor to copy an Xform object of type U.
/// </summary>
/// <param name="xform">The Xform object to copy</param>
template < typename U >
Xform ( const Xform < U > & xform )
2014-09-10 01:41:26 -04:00
: m_ParentEmber ( nullptr ) //Hack.
2014-07-08 03:11:14 -04:00
{
Xform < T > : : operator = < U > ( xform ) ;
}
/// <summary>
/// Deletes each element of the variation vector and clears it.
/// </summary>
~ Xform ( )
{
ClearAndDeleteVariations ( ) ;
}
/// <summary>
/// Default assignment operator.
/// </summary>
/// <param name="xform">The Xform object to copy</param>
Xform < T > & operator = ( const Xform < T > & xform )
{
if ( this ! = & xform )
Xform < T > : : operator = < T > ( xform ) ;
return * this ;
}
/// <summary>
/// Assignment operator to assign a Xform object of type U.
/// This will delete all of the variations in the vector
/// and repopulate it with copes of the variation in xform's vector.
/// All other values are assigned directly.
/// </summary>
/// <param name="xform">The Xform object to copy.</param>
/// <returns>Reference to updated self</returns>
template < typename U >
Xform < T > & operator = ( const Xform < U > & xform )
{
m_Affine = xform . m_Affine ;
m_Post = xform . m_Post ;
m_Weight = T ( xform . m_Weight ) ;
m_ColorX = T ( xform . m_ColorX ) ;
m_ColorY = T ( xform . m_ColorY ) ;
m_DirectColor = T ( xform . m_DirectColor ) ;
m_ColorSpeed = T ( xform . m_ColorSpeed ) ;
m_Animate = T ( xform . m_Animate ) ;
m_Opacity = T ( xform . m_Opacity ) ;
CacheColorVals ( ) ;
m_HasPost = xform . HasPost ( ) ;
m_HasPreOrRegularVars = xform . PreVariationCount ( ) > 0 | | xform . VariationCount ( ) > 0 ;
m_Wind [ 0 ] = T ( xform . m_Wind [ 0 ] ) ;
m_Wind [ 1 ] = T ( xform . m_Wind [ 1 ] ) ;
m_MotionFreq = xform . m_MotionFreq ;
m_MotionFunc = xform . m_MotionFunc ;
ClearAndDeleteVariations ( ) ;
//Must manually add them via the AddVariation() function so that
//the variation's m_IndexInXform member gets properly set to this.
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < xform . TotalVariationCount ( ) ; i + + )
2014-07-08 03:11:14 -04:00
{
2014-09-10 01:41:26 -04:00
Variation < T > * var = nullptr ;
2014-08-03 19:16:10 -04:00
if ( Variation < U > * varOrig = xform . GetVariation ( i ) )
{
varOrig - > Copy ( var ) ; //Will convert from type U to type T.
AddVariation ( var ) ; //Will internally call SetPrecalcFlags().
}
2014-07-08 03:11:14 -04:00
}
if ( TotalVariationCount ( ) = = 0 )
SetPrecalcFlags ( ) ;
//If this xform was already part of a different ember, then do not assign, else do.
if ( ! m_ParentEmber & & ( typeid ( T ) = = typeid ( U ) ) )
2014-12-07 03:59:26 -05:00
m_ParentEmber = reinterpret_cast < Ember < T > * > ( xform . ParentEmber ( ) ) ;
2014-07-08 03:11:14 -04:00
CopyVec < T , U > ( m_Xaos , xform . XaosVec ( ) ) ;
CopyVec ( m_Motion , xform . m_Motion ) ;
m_Name = xform . m_Name ;
return * this ;
}
/// <summary>
/// Init default values.
2015-03-25 23:47:57 -04:00
/// Non default values are used to signify an uninitialized state. This is useful for
/// doing motion interpolation where we don't want to apply motion to all fields. By setting
/// unreasonable values before parsing, then only assigning the ones the motion tags specified,
/// it is clear which fields are intended to have motion applied to them.
2014-07-08 03:11:14 -04:00
/// </summary>
2015-03-25 23:47:57 -04:00
/// <param name="useDefaults">Use reasonable default if true, else use out of bounds values.</param>
void Init ( bool useDefaults = true )
2014-07-08 03:11:14 -04:00
{
2014-10-14 11:53:15 -04:00
static size_t count = 0 ;
2014-07-08 03:11:14 -04:00
2015-03-25 23:47:57 -04:00
if ( useDefaults )
{
m_Weight = 0 ;
m_ColorSpeed = T ( 0.5 ) ;
m_Animate = 1 ;
m_ColorX = T ( count & 1 ) ;
m_ColorY = 0 ;
m_DirectColor = 1 ;
m_Opacity = 1 ;
m_Affine . A ( 1 ) ;
m_Affine . B ( 0 ) ;
m_Affine . C ( 0 ) ;
m_Affine . D ( 0 ) ;
m_Affine . E ( 1 ) ;
m_Affine . F ( 0 ) ;
m_Post . A ( 1 ) ;
m_Post . B ( 0 ) ;
m_Post . C ( 0 ) ;
m_Post . D ( 0 ) ;
m_Post . E ( 1 ) ;
m_Post . F ( 0 ) ;
m_Wind [ 0 ] = 0 ;
m_Wind [ 1 ] = 0 ;
m_MotionFreq = 0 ;
}
else
{
m_Weight = EMPTYFIELD ;
m_ColorSpeed = EMPTYFIELD ;
m_Animate = EMPTYFIELD ;
m_ColorX = EMPTYFIELD ;
m_ColorY = EMPTYFIELD ;
m_DirectColor = EMPTYFIELD ;
m_Opacity = EMPTYFIELD ;
m_Affine . A ( EMPTYFIELD ) ;
m_Affine . B ( EMPTYFIELD ) ;
m_Affine . C ( EMPTYFIELD ) ;
m_Affine . D ( EMPTYFIELD ) ;
m_Affine . E ( EMPTYFIELD ) ;
m_Affine . F ( EMPTYFIELD ) ;
m_Post . A ( EMPTYFIELD ) ;
m_Post . B ( EMPTYFIELD ) ;
m_Post . C ( EMPTYFIELD ) ;
m_Post . D ( EMPTYFIELD ) ;
m_Post . E ( EMPTYFIELD ) ;
m_Post . F ( EMPTYFIELD ) ;
m_Wind [ 0 ] = EMPTYFIELD ;
m_Wind [ 1 ] = EMPTYFIELD ;
m_MotionFreq = EMPTYFIELD ;
}
2014-07-08 03:11:14 -04:00
m_MotionFunc = MOTION_SIN ;
m_Motion . clear ( ) ;
m_NeedPrecalcSumSquares = false ;
m_NeedPrecalcSqrtSumSquares = false ;
m_NeedPrecalcAngles = false ;
m_NeedPrecalcAtanXY = false ;
m_NeedPrecalcAtanYX = false ;
m_HasPost = false ;
m_HasPreOrRegularVars = false ;
2014-09-10 01:41:26 -04:00
m_ParentEmber = nullptr ;
2014-07-08 03:11:14 -04:00
m_PreVariations . reserve ( MAX_VARS_PER_XFORM ) ;
m_Variations . reserve ( MAX_VARS_PER_XFORM ) ;
m_PostVariations . reserve ( MAX_VARS_PER_XFORM ) ;
CacheColorVals ( ) ;
count + + ;
}
/// <summary>
/// Add a pointer to a variation which will be deleted on destruction so the caller should not delete.
/// This checks if the total number of variations is less than or equal to MAX_VARS_PER_XFORM.
/// It also checks if the variation is already present, in which case it doesn't add.
/// If add, set all precalcs.
/// </summary>
/// <param name="variation">Pointer to a varation to add</param>
/// <returns>True if the successful, else false.</returns>
bool AddVariation ( Variation < T > * variation )
{
2014-09-10 01:41:26 -04:00
if ( variation & & ( GetVariationById ( variation - > VariationId ( ) ) = = nullptr ) )
2014-07-08 03:11:14 -04:00
{
string name = variation - > Name ( ) ;
bool pre = name . find ( " pre_ " ) = = 0 ;
bool post = name . find ( " post_ " ) = = 0 ;
vector < Variation < T > * > * vec ;
if ( pre )
vec = & m_PreVariations ;
else if ( post )
vec = & m_PostVariations ;
else
vec = & m_Variations ;
if ( vec - > size ( ) < MAX_VARS_PER_XFORM )
{
vec - > push_back ( variation ) ;
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
//Flatten must always be last.
for ( size_t i = 0 ; i < vec - > size ( ) ; i + + )
{
if ( ( i ! = vec - > size ( ) - 1 ) & & ( ( * vec ) [ i ] - > Name ( ) . find ( " flatten " ) ! = string : : npos ) )
{
std : : swap ( ( * vec ) [ i ] , ( * vec ) [ vec - > size ( ) - 1 ] ) ;
break ;
}
}
2014-07-08 03:11:14 -04:00
SetPrecalcFlags ( ) ;
return true ;
}
}
return false ;
}
/// <summary>
/// Get a pointer to the variation at the specified index.
/// </summary>
/// <param name="index">The index in the list to retrieve</param>
2014-09-10 01:41:26 -04:00
/// <returns>A pointer to the variation at the index if in range, else nullptr.</returns>
2014-07-08 03:11:14 -04:00
Variation < T > * GetVariation ( size_t index ) const
{
size_t count = 0 ;
2014-09-10 01:41:26 -04:00
Variation < T > * var = nullptr ;
2014-07-08 03:11:14 -04:00
const_cast < Xform < T > * > ( this ) - > AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < variations . size ( ) ; i + + , count + + )
2014-07-08 03:11:14 -04:00
{
if ( count = = index )
{
var = variations [ i ] ;
keepGoing = false ;
break ;
}
}
} ) ;
return var ;
}
/// <summary>
/// Get a pointer to the variation with the specified ID.
/// </summary>
/// <param name="id">The ID to search for</param>
2014-09-10 01:41:26 -04:00
/// <returns>A pointer to the variation if found, else nullptr.</returns>
2014-07-08 03:11:14 -04:00
Variation < T > * GetVariationById ( eVariationId id ) const
{
2014-09-10 01:41:26 -04:00
Variation < T > * var = nullptr ;
2014-07-08 03:11:14 -04:00
const_cast < Xform < T > * > ( this ) - > AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2015-05-03 20:13:14 -04:00
for ( auto v : variations )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
if ( v ! = nullptr & & v - > VariationId ( ) = = id )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
var = v ;
2014-07-08 03:11:14 -04:00
keepGoing = false ;
break ;
}
}
} ) ;
return var ;
}
/// <summary>
/// Get a pointer to the variation with the specified name.
/// </summary>
/// <param name="name">The name to search for</param>
2014-09-10 01:41:26 -04:00
/// <returns>A pointer to the variation if found, else nullptr.</returns>
2014-10-14 11:53:15 -04:00
Variation < T > * GetVariationByName ( const string & name ) const
2014-07-08 03:11:14 -04:00
{
2014-09-10 01:41:26 -04:00
Variation < T > * var = nullptr ;
2014-07-08 03:11:14 -04:00
const_cast < Xform < T > * > ( this ) - > AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2015-05-03 20:13:14 -04:00
for ( auto v : variations )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
if ( v ! = nullptr & & v - > Name ( ) = = name )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
var = v ;
2014-07-08 03:11:14 -04:00
keepGoing = false ;
break ;
}
}
} ) ;
return var ;
}
/// <summary>
/// Get the index in the list of the variation pointer.
/// Note this is searching for the exact pointer address and not the name or ID of the variation.
/// </summary>
/// <param name="var">A pointer to the variation to search for</param>
/// <returns>The index of the variation if found, else -1</returns>
2014-10-14 11:53:15 -04:00
intmax_t GetVariationIndex ( Variation < T > * var ) const
2014-07-08 03:11:14 -04:00
{
2014-10-14 11:53:15 -04:00
intmax_t count = 0 , index = - 1 ;
2014-07-08 03:11:14 -04:00
const_cast < Xform < T > * > ( this ) - > AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < variations . size ( ) ; i + + , count + + )
2014-07-08 03:11:14 -04:00
{
if ( variations [ i ] = = var )
{
index = count ;
keepGoing = false ;
break ;
}
}
} ) ;
return index ;
}
/// <summary>
/// Delete the variation with the matching ID.
/// Update precalcs if deletion successful.
/// </summary>
/// <param name="id">The ID to search for</param>
/// <returns>True if deletion successful, else false.</returns>
bool DeleteVariationById ( eVariationId id )
{
bool found = false ;
AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < variations . size ( ) ; i + + )
2014-07-08 03:11:14 -04:00
{
2014-09-10 01:41:26 -04:00
if ( variations [ i ] ! = nullptr & & variations [ i ] - > VariationId ( ) = = id )
2014-07-08 03:11:14 -04:00
{
delete variations [ i ] ;
variations . erase ( variations . begin ( ) + i ) ;
found = true ;
}
}
} ) ;
if ( found )
SetPrecalcFlags ( ) ;
return found ;
}
/// <summary>
/// Delete the motion elements.
/// </summary>
void DeleteMotionElements ( )
{
m_Motion . clear ( ) ;
}
/// <summary>
/// Delete all variations, clear the list and update precalc flags.
/// </summary>
void ClearAndDeleteVariations ( )
{
AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing ) { ClearVec < Variation < T > > ( variations ) ; } ) ;
SetPrecalcFlags ( ) ;
}
/// <summary>
/// Reset this xform to be totally empty by clearing all variations, resetting both affines to the
/// identity matrix, clearing xaos, color, visibility, wind, animate and setting name
/// to the empty string.
2014-09-10 01:41:26 -04:00
/// Note that this also sets the parent ember to nullptr, so if this xform is reused after calling Clear(),
2014-07-08 03:11:14 -04:00
/// the caller must reset the parent ember to whatever ember they add it to again.
/// </summary>
void Clear ( )
{
ClearAndDeleteVariations ( ) ;
DeleteMotionElements ( ) ;
m_Affine . MakeID ( ) ;
m_Post . MakeID ( ) ;
m_Xaos . clear ( ) ;
2014-09-10 01:41:26 -04:00
m_ParentEmber = nullptr ;
2014-07-08 03:11:14 -04:00
m_ColorSpeedCache = 0 ;
m_OneMinusColorCache = 0 ;
m_VizAdjusted = 0 ;
m_Animate = 0 ;
m_Wind [ 0 ] = 0 ;
m_Wind [ 1 ] = 0 ;
m_Name = " " ;
}
/// <summary>
/// Compute color cache values: color speed, one minus color speed and adjusted visibility.
/// </summary>
void CacheColorVals ( )
{
//Figure out which is right. //TODO.
//m_ColorSpeedCache = m_ColorX * (1 - m_ColorSpeed) / 2;//Apo style.
//m_OneMinusColorCache = (1 + m_ColorSpeed) / 2;
m_ColorSpeedCache = m_ColorSpeed * m_ColorX ; //Flam3 style.
m_OneMinusColorCache = T ( 1.0 ) - m_ColorSpeed ;
m_VizAdjusted = AdjustOpacityPercentage ( m_Opacity ) ;
}
/// <summary>
/// Return the xaos value at the specified index.
/// If the index is out of range, return 1.
/// This has the convenient effect that xaos is not present
/// by default and only has a value if explicitly added.
/// </summary>
/// <param name="i">The xaos index to retrieve</param>
/// <returns>The value at the index if in range, else 1.</returns>
T Xaos ( size_t i ) const
{
return i < m_Xaos . size ( ) ? m_Xaos [ i ] : 1 ;
}
/// <summary>
/// Set the xaos value for a given xform index.
/// If the index is out of range, a 1 value will be added
/// to the xaos vector repeatedly until it's one less than the
/// requested index in length, then finally add the specified value.
/// </summary>
/// <param name="i">The index to set</param>
/// <param name="val">The xaos value to set it to</param>
2014-10-14 11:53:15 -04:00
void SetXaos ( size_t i , T val )
2014-07-08 03:11:14 -04:00
{
if ( i < m_Xaos . size ( ) )
{
m_Xaos [ i ] = val ;
}
else
{
while ( m_Xaos . size ( ) < = i )
m_Xaos . push_back ( 1 ) ;
m_Xaos [ i ] = val ;
}
}
/// <summary>
/// Determine if any xaos value in the vector up to the xform count
/// of the parent ember is anything other than 1.
/// </summary>
/// <returns>True if found, else false.</returns>
bool XaosPresent ( ) const
{
if ( m_ParentEmber )
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < m_Xaos . size ( ) ; i + + )
2014-07-08 03:11:14 -04:00
if ( i < m_ParentEmber - > XformCount ( ) )
if ( ! IsClose < T > ( m_Xaos [ i ] , 1 ) )
return true ; //If at least one entry is not equal to 1, then xaos is present.
return false ;
}
/// <summary>
/// Truncate the xaos vector to match the xform count of the parent ember.
/// </summary>
void TruncateXaos ( )
{
if ( m_ParentEmber )
while ( m_Xaos . size ( ) > m_ParentEmber - > XformCount ( ) )
m_Xaos . pop_back ( ) ;
}
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
/// <summary>
/// Remove all xaos from this xform.
/// </summary>
void ClearXaos ( )
{
m_Xaos . clear ( ) ;
}
/// <summary>
/// Normalize the variation weights.
/// </summary>
void NormalizeVariationWeights ( )
{
AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
T norm = 0 ;
2015-05-03 20:13:14 -04:00
for ( auto var : variations ) norm + = var - > m_Weight ;
for ( auto var : variations ) var - > m_Weight / = norm ;
2014-07-08 03:11:14 -04:00
} ) ;
}
/// <summary>
/// Applies this xform to the point passed in and saves the result in the out point.
/// It's important to understand what happens here since it's the inner core of the algorithm.
/// See the internal comments for step by step details.
/// </summary>
/// <param name="inPoint">The initial point from the previous iteration</param>
/// <param name="outPoint">The output point</param>
/// <param name="rand">The random context to use</param>
/// <returns>True if a bad value was calculated, else false.</returns>
bool Apply ( Point < T > * inPoint , Point < T > * outPoint , QTIsaac < ISAAC_SIZE , ISAAC_INT > & rand )
{
size_t i ;
//This must be local, rather than a member, because this function can be called
//from multiple threads. If it were a member, they'd be clobbering each others' values.
IteratorHelper < T > iterHelper ;
//Calculate the color coordinate/index in the palette to look up later when accumulating the output point
//to the histogram. Calculate this value by interpolating between the index value of the
//last iteration with the one specified in this xform. Note that some cached values are used
//to reduce the amount of processing.
outPoint - > m_VizAdjusted = m_VizAdjusted ;
iterHelper . m_Color . x = outPoint - > m_ColorX = m_ColorSpeedCache + ( m_OneMinusColorCache * inPoint - > m_ColorX ) ;
if ( m_HasPreOrRegularVars )
{
//Compute the pre affine portion of the transform.
//These x, y values are what get passed to the variations below.
//Note that they are not changed after this, except in the case of pre_ variations.
iterHelper . m_TransX = ( m_Affine . A ( ) * inPoint - > m_X ) + ( m_Affine . B ( ) * inPoint - > m_Y ) + m_Affine . C ( ) ;
iterHelper . m_TransY = ( m_Affine . D ( ) * inPoint - > m_X ) + ( m_Affine . E ( ) * inPoint - > m_Y ) + m_Affine . F ( ) ;
iterHelper . m_TransZ = inPoint - > m_Z ;
//Apply pre_ variations, these don't affect outPoint, only iterHelper.m_TransX, Y, Z.
for ( i = 0 ; i < PreVariationCount ( ) ; i + + )
{
iterHelper . In . x = iterHelper . m_TransX ; //Read must be done before every pre variation because transX/Y are changing.
iterHelper . In . y = iterHelper . m_TransY ;
iterHelper . In . z = iterHelper . m_TransZ ;
2014-09-01 00:25:15 -04:00
m_PreVariations [ i ] - > PrecalcHelper ( iterHelper , inPoint ) ; //Apply per-variation precalc, the second parameter is unused for pre variations.
2014-07-08 03:11:14 -04:00
m_PreVariations [ i ] - > Func ( iterHelper , * outPoint , rand ) ;
WritePre ( iterHelper , m_PreVariations [ i ] - > AssignType ( ) ) ;
}
if ( VariationCount ( ) > 0 )
{
//The original calculates sumsq and sumsqrt every time, regardless if they're used or not.
//With Precalc(), only calculate those values if they're needed.
Precalc ( iterHelper ) ; //Only need per-xform precalc with regular variations.
iterHelper . In . x = iterHelper . m_TransX ; //Only need to read once with regular variations, because transX/Y are fixed.
iterHelper . In . y = iterHelper . m_TransY ;
iterHelper . In . z = iterHelper . m_TransZ ;
//Since these get summed, initialize them to zero.
outPoint - > m_X = outPoint - > m_Y = outPoint - > m_Z = 0 ;
//Apply variations to the transformed points, accumulating each time, and store the final value in outPoint.
//Using a virtual function is about 3% faster than using a large case statement like the original did.
//Although research says that using virtual functions is slow, experience says otherwise. They execute
//with the exact same speed as both regular and static member functions.
for ( i = 0 ; i < VariationCount ( ) ; i + + )
{
m_Variations [ i ] - > Func ( iterHelper , * outPoint , rand ) ;
outPoint - > m_X + = iterHelper . Out . x ;
outPoint - > m_Y + = iterHelper . Out . y ;
outPoint - > m_Z + = iterHelper . Out . z ;
}
}
else //Only pre variations are present, no regular ones, so assign the affine transformed points directly to the output points.
{
outPoint - > m_X = iterHelper . m_TransX ;
outPoint - > m_Y = iterHelper . m_TransY ;
outPoint - > m_Z = iterHelper . m_TransZ ;
}
}
2014-11-03 02:16:34 -05:00
//Return the affine transformed points if no variations are present.
//Note this differs from flam3, which would just return zero in that scenario.
2014-07-08 03:11:14 -04:00
else
{
//There are no variations, so the affine transformed points can be assigned directly to the output points.
T inX = inPoint - > m_X ;
outPoint - > m_X = ( m_Affine . A ( ) * inX ) + ( m_Affine . B ( ) * inPoint - > m_Y ) + m_Affine . C ( ) ;
outPoint - > m_Y = ( m_Affine . D ( ) * inX ) + ( m_Affine . E ( ) * inPoint - > m_Y ) + m_Affine . F ( ) ;
outPoint - > m_Z = inPoint - > m_Z ;
}
//Apply post variations, these will modify outPoint.
for ( i = 0 ; i < PostVariationCount ( ) ; i + + )
{
iterHelper . In . x = outPoint - > m_X ; //Read must be done before every post variation because the out point is changing.
iterHelper . In . y = outPoint - > m_Y ;
iterHelper . In . z = outPoint - > m_Z ;
2014-09-01 00:25:15 -04:00
m_PostVariations [ i ] - > PrecalcHelper ( iterHelper , outPoint ) ; //Apply per-variation precalc.
2014-07-08 03:11:14 -04:00
m_PostVariations [ i ] - > Func ( iterHelper , * outPoint , rand ) ;
WritePost ( iterHelper , * outPoint , m_PostVariations [ i ] - > AssignType ( ) ) ;
}
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
//Optionally apply the post affine transform if it's present.
if ( m_HasPost )
{
T postX = outPoint - > m_X ;
outPoint - > m_X = ( m_Post . A ( ) * postX ) + ( m_Post . B ( ) * outPoint - > m_Y ) + m_Post . C ( ) ;
outPoint - > m_Y = ( m_Post . D ( ) * postX ) + ( m_Post . E ( ) * outPoint - > m_Y ) + m_Post . F ( ) ;
}
outPoint - > m_ColorX = outPoint - > m_ColorX + m_DirectColor * ( iterHelper . m_Color . x - outPoint - > m_ColorX ) ;
//Has the trajectory of x or y gone either to infinity, or too close to zero?
return BadVal ( outPoint - > m_X ) | | BadVal ( outPoint - > m_Y ) /* || BadVal(outPoint->m_Z)*/ ;
}
//Why are we not using template with member var addr as arg here?//TODO
2015-03-25 23:47:57 -04:00
# define APPMOT(x) \
do \
{ \
if ( currentMot . x ! = EMPTYFIELD ) \
x + = currentMot . x * Interpolater < T > : : MotionFuncs ( func , freq * blend ) ; \
} while ( 0 )
2014-07-08 03:11:14 -04:00
/// <summary>
/// Apply the motion functions from the passed in xform to this xform.
/// </summary>
/// <param name="xform">The xform containing the motion functions</param>
/// <param name="blend">The time blending value 0-1</param>
void ApplyMotion ( Xform < T > & xform , T blend )
{
//Loop over the motion elements and add their contribution to the original vals.
2014-10-14 11:53:15 -04:00
for ( size_t i = 0 ; i < xform . m_Motion . size ( ) ; i + + )
2014-09-10 01:41:26 -04:00
{
2014-07-08 03:11:14 -04:00
//Original only pulls these from the first motion xform which is a bug. Want to pull it from each one.
2015-03-25 23:47:57 -04:00
Xform < T > & currentMot = xform . m_Motion [ i ] ;
intmax_t freq = currentMot . m_MotionFreq ;
eMotion func = currentMot . m_MotionFunc ;
2014-07-08 03:11:14 -04:00
//Clamp these to the appropriate range after all are applied.
APPMOT ( m_Weight ) ;
APPMOT ( m_ColorX ) ;
//APPMOT(m_ColorY);
2014-09-10 01:41:26 -04:00
APPMOT ( m_DirectColor ) ;
APPMOT ( m_Opacity ) ;
2014-07-08 03:11:14 -04:00
APPMOT ( m_ColorSpeed ) ;
APPMOT ( m_Animate ) ;
2014-09-10 01:41:26 -04:00
2015-03-25 23:47:57 -04:00
for ( size_t j = 0 ; j < currentMot . TotalVariationCount ( ) ; j + + ) //For each variation in the motion xform.
2014-07-08 03:11:14 -04:00
{
2015-03-25 23:47:57 -04:00
Variation < T > * motVar = currentMot . GetVariation ( j ) ; //Get the variation, which may or may not be present in this xform.
2014-07-08 03:11:14 -04:00
ParametricVariation < T > * motParVar = dynamic_cast < ParametricVariation < T > * > ( motVar ) ;
Variation < T > * var = GetVariationById ( motVar - > VariationId ( ) ) ; //See if the variation in the motion xform was present in the xform.
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 ) ;
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 ) ;
}
//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.
2014-09-10 01:41:26 -04:00
if ( motParVar ! = nullptr )
2014-07-08 03:11:14 -04:00
{
2015-06-28 20:48:26 -04:00
auto parVar = dynamic_cast < ParametricVariation < T > * > ( var ) ;
auto params = parVar - > Params ( ) ;
auto motParams = motParVar - > Params ( ) ;
2014-07-08 03:11:14 -04:00
2014-10-14 11:53:15 -04:00
for ( size_t k = 0 ; k < motParVar - > ParamCount ( ) ; k + + )
2014-07-08 03:11:14 -04:00
{
if ( ! motParams [ k ] . IsPrecalc ( ) )
* ( params [ k ] . Param ( ) ) + = motParams [ k ] . ParamVal ( ) * Interpolater < T > : : MotionFuncs ( func , freq * blend ) ;
}
}
}
2014-10-14 11:53:15 -04:00
for ( glm : : length_t j = 0 ; j < 2 ; j + + )
2014-07-08 03:11:14 -04:00
{
2014-10-14 11:53:15 -04:00
for ( glm : : length_t k = 0 ; k < 3 ; k + + )
2014-07-08 03:11:14 -04:00
{
APPMOT ( m_Affine . m_Mat [ j ] [ k ] ) ;
APPMOT ( m_Post . m_Mat [ j ] [ k ] ) ;
}
}
}
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
//Make sure certain params are within reasonable bounds.
ClampRef < T > ( m_ColorX , 0 , 1 ) ;
//ClampRef<T>(m_ColorY, 0, 1);
ClampRef < T > ( m_DirectColor , 0 , 1 ) ;
ClampRef < T > ( m_Opacity , 0 , 1 ) ; //Original didn't clamp these, but do it here for correctness.
2015-03-25 23:47:57 -04:00
ClampRef < T > ( m_ColorSpeed , - 1 , 1 ) ;
2014-07-08 03:11:14 -04:00
ClampGte0Ref < T > ( m_Weight ) ;
}
/// <summary>
/// Accessors.
/// The precalc flags are duplicated in each variation. Each value here
/// is true if any of the variations need it precalculated.
/// </summary>
2014-10-14 11:53:15 -04:00
inline bool NeedPrecalcSumSquares ( ) const { return m_NeedPrecalcSumSquares ; }
2014-07-08 03:11:14 -04:00
inline bool NeedPrecalcSqrtSumSquares ( ) const { return m_NeedPrecalcSqrtSumSquares ; }
2014-10-14 11:53:15 -04:00
inline bool NeedPrecalcAngles ( ) const { return m_NeedPrecalcAngles ; }
inline bool NeedPrecalcAtanXY ( ) const { return m_NeedPrecalcAtanXY ; }
inline bool NeedPrecalcAtanYX ( ) const { return m_NeedPrecalcAtanYX ; }
2014-07-08 03:11:14 -04:00
inline bool NeedAnyPrecalc ( ) const { return NeedPrecalcSumSquares ( ) | | NeedPrecalcSqrtSumSquares ( ) | | NeedPrecalcAngles ( ) | | NeedPrecalcAtanXY ( ) | | NeedPrecalcAtanYX ( ) ; }
bool HasPost ( ) const { return m_HasPost ; }
2014-10-14 11:53:15 -04:00
size_t PreVariationCount ( ) const { return m_PreVariations . size ( ) ; }
size_t VariationCount ( ) const { return m_Variations . size ( ) ; }
size_t PostVariationCount ( ) const { return m_PostVariations . size ( ) ; }
size_t TotalVariationCount ( ) const { return PreVariationCount ( ) + VariationCount ( ) + PostVariationCount ( ) ; }
2014-07-08 03:11:14 -04:00
bool Empty ( ) const { return TotalVariationCount ( ) = = 0 & & m_Affine . IsID ( ) ; } //Use this instead of padding like the original did.
T VizAdjusted ( ) const { return m_VizAdjusted ; }
T ColorSpeedCache ( ) const { return m_ColorSpeedCache ; }
T OneMinusColorCache ( ) const { return m_OneMinusColorCache ; }
const vector < T > & XaosVec ( ) const { return m_Xaos ; }
Ember < T > * ParentEmber ( ) const { return m_ParentEmber ; }
void ParentEmber ( Ember < T > * ember ) { m_ParentEmber = ember ; }
2015-06-29 23:13:53 -04:00
intmax_t IndexInParentEmber ( ) const { return m_ParentEmber ? m_ParentEmber - > GetTotalXformIndex ( const_cast < Xform < T > * > ( this ) ) : - 1 ; }
2014-07-08 03:11:14 -04:00
/// <summary>
/// Set the precalc flags based on whether any variation in the vector needs them.
/// Also call Precalc() virtual function on each variation, which will setup any needed
/// precalcs in parametric variations.
/// Set the parent xform of each variation to this.
/// </summary>
void SetPrecalcFlags ( )
{
m_NeedPrecalcSumSquares = false ;
m_NeedPrecalcSqrtSumSquares = false ;
m_NeedPrecalcAngles = false ;
m_NeedPrecalcAtanXY = false ;
m_NeedPrecalcAtanYX = false ;
m_HasPost = ! m_Post . IsID ( ) ;
m_HasPreOrRegularVars = PreVariationCount ( ) > 0 | | VariationCount ( ) > 0 ;
//Only set precalcs for regular variations, they work differently for pre and post.
2015-05-03 20:13:14 -04:00
for ( auto var : m_Variations )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
if ( var - > NeedPrecalcSumSquares ( ) )
2014-07-08 03:11:14 -04:00
m_NeedPrecalcSumSquares = true ;
2015-05-03 20:13:14 -04:00
if ( var - > NeedPrecalcSqrtSumSquares ( ) )
2014-07-08 03:11:14 -04:00
m_NeedPrecalcSqrtSumSquares = true ;
2015-05-03 20:13:14 -04:00
if ( var - > NeedPrecalcAngles ( ) )
2014-07-08 03:11:14 -04:00
m_NeedPrecalcAngles = true ;
2015-05-03 20:13:14 -04:00
if ( var - > NeedPrecalcAtanXY ( ) )
2014-07-08 03:11:14 -04:00
m_NeedPrecalcAtanXY = true ;
2015-05-03 20:13:14 -04:00
if ( var - > NeedPrecalcAtanYX ( ) )
2014-07-08 03:11:14 -04:00
m_NeedPrecalcAtanYX = true ;
}
AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2015-05-03 20:13:14 -04:00
for ( auto var : variations )
2014-07-08 03:11:14 -04:00
{
2015-05-03 20:13:14 -04:00
var - > ParentXform ( this ) ;
var - > Precalc ( ) ;
2014-07-08 03:11:14 -04:00
}
} ) ;
}
/// <summary>
/// Based on the precalc flags determined in SetPrecalcFlags(), do the appropriate precalcs.
/// </summary>
/// <param name="helper">The iterator helper to store the precalculated values in</param>
void Precalc ( IteratorHelper < T > & helper )
{
if ( m_NeedPrecalcSumSquares )
{
helper . m_PrecalcSumSquares = SQR ( helper . m_TransX ) + SQR ( helper . m_TransY ) ;
if ( m_NeedPrecalcSqrtSumSquares )
{
2015-04-13 07:32:58 -04:00
helper . m_PrecalcSqrtSumSquares = std : : sqrt ( helper . m_PrecalcSumSquares ) ;
2014-07-08 03:11:14 -04:00
if ( m_NeedPrecalcAngles )
{
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
helper . m_PrecalcSina = helper . m_TransX / Zeps ( helper . m_PrecalcSqrtSumSquares ) ;
helper . m_PrecalcCosa = helper . m_TransY / Zeps ( helper . m_PrecalcSqrtSumSquares ) ;
2014-07-08 03:11:14 -04:00
}
}
}
if ( m_NeedPrecalcAtanXY )
helper . m_PrecalcAtanxy = atan2 ( helper . m_TransX , helper . m_TransY ) ;
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
if ( m_NeedPrecalcAtanYX )
helper . m_PrecalcAtanyx = atan2 ( helper . m_TransY , helper . m_TransX ) ;
}
2014-09-10 01:41:26 -04:00
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
/// <summary>
2014-11-04 20:38:20 -05:00
/// Flatten this xform by adding a flatten variation if none is present, and if none of the
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
/// variations or parameters in the vector are present.
/// </summary>
2014-11-04 20:38:20 -05:00
/// <param name="names">Vector of variation and parameter names that inhibit flattening</param>
/// <returns>True if flatten was added, false if it already was present or if at least one of the specified variations or parameters were present.</returns>
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
bool Flatten ( vector < string > & names )
{
bool shouldFlatten = true ;
2014-09-10 01:41:26 -04:00
if ( GetVariationById ( VAR_FLATTEN ) = = nullptr )
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2015-05-03 20:13:14 -04:00
for ( auto var : variations )
//for (size_t i = 0; i < variations.size(); i++)
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
if ( var - > m_Weight ! = 0 ) //This should never happen, but just to be safe.
{
2014-11-04 20:38:20 -05:00
if ( FindIf ( names , [ & ] ( const string & s ) - > bool { return ! _stricmp ( s . c_str ( ) , var - > Name ( ) . c_str ( ) ) ; } ) ) //If any variation is present, don't flatten.
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
shouldFlatten = false ;
keepGoing = false ;
break ;
}
}
//Now traverse the parameters for this variation.
2014-11-04 20:38:20 -05:00
if ( ParametricVariation < T > * parVar = dynamic_cast < ParametricVariation < T > * > ( var ) ) //If any parametric variation parameter is present and non-zero, don't flatten.
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
2015-05-03 20:13:14 -04:00
for ( auto & s : names )
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
if ( parVar - > GetParamVal ( s . c_str ( ) ) ! = 0 )
{
shouldFlatten = false ;
keepGoing = false ;
2015-05-03 20:13:14 -04:00
break ;
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
}
2015-05-03 20:13:14 -04:00
}
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
}
}
} ) ;
2014-11-04 20:38:20 -05:00
if ( shouldFlatten ) //Flatten was not present and neither was any variation name or parameter in the list.
Numerous fixes
0.4.0.5 Beta 07/18/2014
--User Changes
Allow for vibrancy values > 1.
Add flatten and unflatten menu items.
Automatically flatten like Apophysis does.
Add plugin and new_linear tags to Xml to be compatible with Apophysis.
--Bug Fixes
Fix blur, blur3d, bubble, cropn, cross, curl, curl3d, epispiral, ho,
julia3d, julia3dz, loonie, mirror_x, mirror_y, mirror_z, rotate_x,
sinusoidal, spherical, spherical3d, stripes.
Unique filename on final render was completely broken.
Two severe OpenCL bugs. Random seeds were biased and fusing was being
reset too often leading to results that differ from the CPU.
Subtle, but sometimes severe bug in the setup of the xaos weights.
Use properly defined epsilon by getting the value from
std::numeric_limits, rather than hard coding 1e-6 or 1e-10.
Omit incorrect usage of epsilon everywhere. It should not be
automatically added to denominators. Rather, it should only be used if
the denominator is zero.
Force final render progress bars to 100 on completion. Sometimes they
didn't seem to make it there.
Make variation name and params comparisons be case insensitive.
--Code Changes
Make ForEach and FindIf wrappers around std::for_each and std::find_if.
2014-07-19 02:33:18 -04:00
{
Variation < T > * var = new FlattenVariation < T > ( ) ;
if ( AddVariation ( var ) )
{
return true ;
}
else
{
delete var ;
return false ;
}
}
}
return false ;
}
2014-07-08 03:11:14 -04:00
/// <summary>
/// Generate the OpenCL string for reading input values to
/// be passed to a variation.
/// </summary>
/// <param name="varType">Type of the variation these values will be passed to.</param>
/// <returns>The OpenCL string</returns>
string ReadOpenCLString ( eVariationType varType )
{
string s ;
switch ( varType )
{
case VARTYPE_REG :
case VARTYPE_PRE :
s =
" \t vIn.x = transX; \n "
" \t vIn.y = transY; \n "
" \t vIn.z = transZ; \n " ;
break ;
case VARTYPE_POST :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
s =
" \t vIn.x = outPoint->m_X; \n "
" \t vIn.y = outPoint->m_Y; \n "
" \t vIn.z = outPoint->m_Z; \n " ;
break ;
}
return s ;
}
/// <summary>
/// Assing output values from the result of a pre variation.
/// </summary>
/// <param name="helper">The helper to store the output values in</param>
/// <param name="assignType">The type of assignment this variation uses, assign or sum.</param>
inline void WritePre ( IteratorHelper < T > & helper , eVariationAssignType assignType )
{
switch ( assignType )
{
case ASSIGNTYPE_SET :
{
helper . m_TransX = helper . Out . x ;
helper . m_TransY = helper . Out . y ;
helper . m_TransZ = helper . Out . z ;
break ;
}
case ASSIGNTYPE_SUM :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
{
helper . m_TransX + = helper . Out . x ;
helper . m_TransY + = helper . Out . y ;
helper . m_TransZ + = helper . Out . z ;
break ;
}
}
}
/// <summary>
/// Assing output values from the result of a post variation.
/// </summary>
/// <param name="helper">The helper to store the output values in</param>
/// <param name="assignType">The type of assignment this variation uses, assign or sum.</param>
inline void WritePost ( IteratorHelper < T > & helper , Point < T > & outPoint , eVariationAssignType assignType )
{
switch ( assignType )
{
case ASSIGNTYPE_SET :
{
outPoint . m_X = helper . Out . x ;
outPoint . m_Y = helper . Out . y ;
outPoint . m_Z = helper . Out . z ;
break ;
}
case ASSIGNTYPE_SUM :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
{
outPoint . m_X + = helper . Out . x ;
outPoint . m_Y + = helper . Out . y ;
outPoint . m_Z + = helper . Out . z ;
break ;
}
}
}
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
/// <summary>
/// Generate the OpenCL string for writing output values from a call to a variation.
/// </summary>
/// <param name="varType">The type of variation these values were calculated from, pre, reg or post.</param>
/// <param name="assignType">The type of assignment used by the variation these values were calculated from, assign or sum.</param>
/// <returns>The OpenCL string</returns>
string WriteOpenCLString ( eVariationType varType , eVariationAssignType assignType )
{
string s ;
switch ( varType )
{
case VARTYPE_REG :
{
s =
" \t outPoint->m_X += vOut.x; \n "
" \t outPoint->m_Y += vOut.y; \n "
" \t outPoint->m_Z += vOut.z; \n " ;
break ;
}
case VARTYPE_PRE :
{
switch ( assignType )
{
case ASSIGNTYPE_SET :
{
s =
" \t transX = vOut.x; \n "
" \t transY = vOut.y; \n "
" \t transZ = vOut.z; \n " ;
break ;
}
case ASSIGNTYPE_SUM :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
{
s =
" \t transX += vOut.x; \n "
" \t transY += vOut.y; \n "
" \t transZ += vOut.z; \n " ;
break ;
}
}
break ;
}
case VARTYPE_POST :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
{
switch ( assignType )
{
case ASSIGNTYPE_SET :
{
s =
" \t outPoint->m_X = vOut.x; \n "
" \t outPoint->m_Y = vOut.y; \n "
" \t outPoint->m_Z = vOut.z; \n " ;
break ;
}
case ASSIGNTYPE_SUM :
2014-09-10 01:41:26 -04:00
default :
2014-07-08 03:11:14 -04:00
{
s =
" \t outPoint->m_X += vOut.x; \n "
" \t outPoint->m_Y += vOut.y; \n "
" \t outPoint->m_Z += vOut.z; \n " ;
break ;
}
}
break ;
}
}
return s ;
}
/// <summary>
/// Return a string representation of this xform.
/// It will include all pre affine values, and optionally post affine values if present.
/// Various variables, all variations as strings and xaos values if present.
/// </summary>
/// <returns>The string representation of this xform</returns>
string ToString ( ) const
{
ostringstream ss ;
ss < < " A: " < < m_Affine . A ( ) < < " "
< < " B: " < < m_Affine . B ( ) < < " "
< < " C: " < < m_Affine . C ( ) < < " "
< < " D: " < < m_Affine . D ( ) < < " "
< < " E: " < < m_Affine . E ( ) < < " "
< < " F: " < < m_Affine . F ( ) < < " " < < endl ;
if ( m_HasPost )
{
ss < < " Post A: " < < m_Post . A ( ) < < " "
< < " Post B: " < < m_Post . B ( ) < < " "
< < " Post C: " < < m_Post . C ( ) < < " "
< < " Post D: " < < m_Post . D ( ) < < " "
< < " Post E: " < < m_Post . E ( ) < < " "
< < " Post F: " < < m_Post . F ( ) < < " " < < endl ;
}
ss < < " Weight: " < < m_Weight < < endl ;
ss < < " ColorX: " < < m_ColorX < < endl ;
ss < < " ColorY: " < < m_ColorY < < endl ;
ss < < " Direct Color: " < < m_DirectColor < < endl ;
ss < < " Color Speed: " < < m_ColorSpeed < < endl ;
ss < < " Animate: " < < m_Animate < < endl ;
ss < < " Opacity: " < < m_Opacity < < endl ;
ss < < " Viz Adjusted: " < < m_VizAdjusted < < endl ;
ss < < " Wind: " < < m_Wind [ 0 ] < < " , " < < m_Wind [ 1 ] < < endl ;
ss < < " Motion Frequency: " < < m_MotionFreq < < endl ;
ss < < " Motion Func: " < < m_MotionFunc < < endl ;
const_cast < Xform < T > * > ( this ) - > AllVarsFunc ( [ & ] ( vector < Variation < T > * > & variations , bool & keepGoing )
{
2015-05-03 20:13:14 -04:00
for ( auto var : variations )
ss < < var - > ToString ( ) < < endl ;
2014-07-08 03:11:14 -04:00
ss < < endl ;
} ) ;
if ( XaosPresent ( ) )
{
2015-05-03 20:13:14 -04:00
for ( auto xaos : m_Xaos )
ss < < xaos < < " " ;
2014-07-08 03:11:14 -04:00
ss < < endl ;
}
return ss . str ( ) ;
}
/// <summary>
/// Members are listed in the exact order they are used in Apply() to make them
/// as cache efficient as possible. Not all are public, so there is repeated public/private
/// access specifiers.
/// </summary>
private :
bool m_HasPreOrRegularVars ; //Whethere there are any pre or regular variations present.
T m_VizAdjusted ; //Adjusted visibility for better transitions.
public :
//Color coordinates for this function. This is the index into the palette used to look up a color and add to the histogram for each iter.
//The original only allows for an x coord. Will eventually allow for a y coord like Fractron for 2D palettes.
T m_ColorX , m_ColorY ;
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
private :
T m_ColorSpeedCache ; //Cache of m_ColorSpeed * m_ColorX. Need to recalc cache values whenever anything relating to color is set. Made private because one affects the other.
T m_OneMinusColorCache ; //Cache of 1 - m_ColorSpeedCache.
public :
//Coefficients for the affine portion of the transform.
//Discussed on page 3 of the paper:
//Fi(x, y) = (aix + biy + ci, dix + eiy + fi)
Affine2D < T > m_Affine ;
private :
vector < Variation < T > * > m_PreVariations ; //The list of pre variations to call when applying this xform.
vector < Variation < T > * > m_Variations ; //The list of variations to call when applying this xform.
bool m_HasPost ; //Whether a post affine transform is present.
public :
//Coefficients for the affine portion of the post transform.
//Discussed on page 5 of the paper:
//Pi(x, y) = (α ix + βiy + γ i, δix + ǫiy + ζi).
Affine2D < T > m_Post ;
private :
vector < Variation < T > * > m_PostVariations ; //The list of post variations to call when applying this xform.
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
public :
T m_DirectColor ; //Used with direct color variations.
//Probability that this function is chosen. Can be greater than 1.
//Discussed on page 4 of the paper:
//Probability wi.
T m_Weight ;
2014-09-10 01:41:26 -04:00
2014-07-08 03:11:14 -04:00
//Scaling factor on color added to current iteration, also known as color weight. Normally defaults to 0.5.
//Discussed on page 9 of the paper with a hard coded default value of 0.5:
//C = (C + Ci) * 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_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 ;
2014-10-14 11:53:15 -04:00
intmax_t m_MotionFreq ;
2014-07-08 03:11:14 -04:00
vector < Xform < T > > m_Motion ;
string m_Name ;
private :
/// <summary>
/// Perform an operation on all variation vectors.
/// The operation is supplied in the func parameter.
/// To stop performing the operation on vectors after the current one,
/// set the keepGoing parameter to false;
/// </summary>
/// <param name="func">The function to call for each variation vector.</param>
void AllVarsFunc ( std : : function < void ( vector < Variation < T > * > & , bool & ) > func )
{
bool keepGoing = true ;
func ( m_PreVariations , keepGoing ) ;
if ( keepGoing )
func ( m_Variations , keepGoing ) ;
if ( keepGoing )
func ( m_PostVariations , keepGoing ) ;
}
/// <summary>
/// Adjust opacity.
/// </summary>
/// <param name="in">The opacity to adjust, range 0-1.</param>
/// <returns>The adjusted opacity</returns>
static T AdjustOpacityPercentage ( T in )
{
if ( in = = 0 )
return 0 ;
else
return pow ( T ( 10.0 ) , - log ( T ( 1.0 ) / T ( in ) ) / log ( T ( 2 ) ) ) ;
}
vector < T > m_Xaos ; //Xaos vector which affects the probability that this xform is chosen. Usually empty.
Ember < T > * m_ParentEmber ; //The parent ember that contains this xform.
bool m_NeedPrecalcSumSquares ; //Whether any variation uses the precalc sum squares value in its calculations.
bool m_NeedPrecalcSqrtSumSquares ; //Whether any variation uses the sqrt precalc sum squares value in its calculations.
bool m_NeedPrecalcAngles ; //Whether any variation uses the precalc sin and cos values in its calculations.
bool m_NeedPrecalcAtanXY ; //Whether any variation uses the precalc atan XY value in its calculations.
bool m_NeedPrecalcAtanYX ; //Whether any variation uses the precalc atan YX value in its calculations.
} ;
2014-09-10 01:41:26 -04:00
}