2014-07-08 03:11:14 -04:00
# include "FractoriumPch.h"
# include "Fractorium.h"
/// <summary>
/// Initialize the library tree UI.
/// </summary>
void Fractorium : : InitLibraryUI ( )
{
2016-04-03 21:55:12 -04:00
ui . LibraryTree - > SetMainWindow ( this ) ;
2016-06-11 22:01:19 -04:00
ui . SequenceStaggerSpinBox - > setValue ( m_Settings - > Stagger ( ) ) ;
ui . SequenceRandomStaggerMaxSpinBox - > setValue ( m_Settings - > StaggerMax ( ) ) ;
2016-06-11 20:47:03 -04:00
ui . SequenceFramesPerRotSpinBox - > setValue ( m_Settings - > FramesPerRot ( ) ) ;
ui . SequenceRandomFramesPerRotMaxSpinBox - > setValue ( m_Settings - > FramesPerRotMax ( ) ) ;
ui . SequenceRotationsSpinBox - > setValue ( m_Settings - > Rotations ( ) ) ;
ui . SequenceRandomRotationsMaxSpinBox - > setValue ( m_Settings - > RotationsMax ( ) ) ;
ui . SequenceBlendFramesSpinBox - > setValue ( m_Settings - > BlendFrames ( ) ) ;
ui . SequenceRandomBlendMaxFramesSpinBox - > setValue ( m_Settings - > BlendFramesMax ( ) ) ;
connect ( ui . LibraryTree , SIGNAL ( itemChanged ( QTreeWidgetItem * , int ) ) , this , SLOT ( OnEmberTreeItemChanged ( QTreeWidgetItem * , int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . LibraryTree , SIGNAL ( itemDoubleClicked ( QTreeWidgetItem * , int ) ) , this , SLOT ( OnEmberTreeItemDoubleClicked ( QTreeWidgetItem * , int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . LibraryTree , SIGNAL ( itemActivated ( QTreeWidgetItem * , int ) ) , this , SLOT ( OnEmberTreeItemDoubleClicked ( QTreeWidgetItem * , int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceTree , SIGNAL ( itemChanged ( QTreeWidgetItem * , int ) ) , this , SLOT ( OnSequenceTreeItemChanged ( QTreeWidgetItem * , int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceStartPreviewsButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceStartPreviewsButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceStopPreviewsButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceStopPreviewsButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceAllButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceAllButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceGenerateButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceGenerateButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRenderButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceRenderButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceSaveButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceSaveButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceOpenButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( OnSequenceOpenButtonClicked ( bool ) ) , Qt : : QueuedConnection ) ;
2016-06-11 22:01:19 -04:00
connect ( ui . SequenceRandomizeStaggerCheckBox , SIGNAL ( stateChanged ( int ) ) , this , SLOT ( OnSequenceRandomizeStaggerCheckBoxStateChanged ( int ) ) , Qt : : QueuedConnection ) ;
2016-06-11 20:47:03 -04:00
connect ( ui . SequenceRandomizeFramesPerRotCheckBox , SIGNAL ( stateChanged ( int ) ) , this , SLOT ( OnSequenceRandomizeFramesPerRotCheckBoxStateChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomizeRotationsCheckBox , SIGNAL ( stateChanged ( int ) ) , this , SLOT ( OnSequenceRandomizeRotationsCheckBoxStateChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomizeBlendFramesCheckBox , SIGNAL ( stateChanged ( int ) ) , this , SLOT ( OnSequenceRandomizeBlendFramesCheckBoxStateChanged ( int ) ) , Qt : : QueuedConnection ) ;
2016-06-11 22:01:19 -04:00
connect ( ui . SequenceStaggerSpinBox , SIGNAL ( valueChanged ( double ) ) , this , SLOT ( OnSequenceStaggerSpinBoxChanged ( double ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomStaggerMaxSpinBox , SIGNAL ( valueChanged ( double ) ) , this , SLOT ( OnSequenceRandomStaggerMaxSpinBoxChanged ( double ) ) , Qt : : QueuedConnection ) ;
2016-06-11 20:47:03 -04:00
connect ( ui . SequenceStartFlameSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceStartFlameSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceStopFlameSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceStopFlameSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceFramesPerRotSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceFramesPerRotSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomFramesPerRotMaxSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceRandomFramesPerRotMaxSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRotationsSpinBox , SIGNAL ( valueChanged ( double ) ) , this , SLOT ( OnSequenceRotationsSpinBoxChanged ( double ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomRotationsMaxSpinBox , SIGNAL ( valueChanged ( double ) ) , this , SLOT ( OnSequenceRandomRotationsMaxSpinBoxChanged ( double ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceBlendFramesSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceBlendFramesSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
connect ( ui . SequenceRandomBlendMaxFramesSpinBox , SIGNAL ( valueChanged ( int ) ) , this , SLOT ( OnSequenceRandomBlendMaxFramesSpinBoxChanged ( int ) ) , Qt : : QueuedConnection ) ;
2015-03-21 18:27:37 -04:00
}
/// <summary>
/// Get the index of the currently selected ember in the library tree.
/// </summary>
/// <returns>A pair containing the index of the item clicked and a pointer to the item</param>
pair < size_t , QTreeWidgetItem * > Fractorium : : GetCurrentEmberIndex ( )
{
2016-02-13 20:24:51 -05:00
int index = 0 ;
2015-03-21 18:27:37 -04:00
QTreeWidgetItem * item = nullptr ;
2016-02-12 00:38:21 -05:00
auto tree = ui . LibraryTree ;
2015-03-21 18:27:37 -04:00
2016-02-12 00:38:21 -05:00
if ( auto top = tree - > topLevelItem ( 0 ) )
2015-03-21 18:27:37 -04:00
{
for ( int i = 0 ; i < top - > childCount ( ) ; i + + ) //Iterate through all of the children, which will represent the open embers.
{
item = top - > child ( index ) ;
if ( item & & ! item - > isSelected ( ) )
index + + ;
else
break ;
}
}
2016-02-12 00:38:21 -05:00
return make_pair ( index , item ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Slot function to be called via QMetaObject::invokeMethod() to update preview images in the preview thread.
/// </summary>
/// <param name="item">The item double clicked on</param>
/// <param name="v">The vector holding the RGBA bitmap</param>
2014-12-11 00:50:15 -05:00
/// <param name="w">The width of the bitmap</param>
/// <param name="h">The height of the bitmap</param>
void Fractorium : : SetLibraryTreeItemData ( EmberTreeWidgetItemBase * item , vector < byte > & v , uint w , uint h )
2014-07-08 03:11:14 -04:00
{
2014-12-11 00:50:15 -05:00
item - > SetImage ( v , w , h ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Set all libary tree entries to the name of the corresponding ember they represent.
2016-04-03 21:55:12 -04:00
/// Set all libary tree entries to point to the underlying ember they represent.
2014-07-08 03:11:14 -04:00
/// </summary>
template < typename T >
2016-04-03 21:55:12 -04:00
void FractoriumEmberController < T > : : SyncLibrary ( eLibraryUpdate update )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
auto it = m_EmberFile . m_Embers . begin ( ) ;
2016-02-12 00:38:21 -05:00
auto tree = m_Fractorium - > ui . LibraryTree ;
2014-07-08 03:11:14 -04:00
tree - > blockSignals ( true ) ;
2016-02-12 00:38:21 -05:00
if ( auto top = tree - > topLevelItem ( 0 ) )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
for ( int i = 0 ; i < top - > childCount ( ) & & it ! = m_EmberFile . m_Embers . end ( ) ; + + i , + + it ) //Iterate through all of the children, which will represent the open embers.
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
if ( auto item = dynamic_cast < EmberTreeWidgetItem < T > * > ( top - > child ( i ) ) ) //Cast the child widget to the EmberTreeWidgetItem type.
{
if ( update & eLibraryUpdate : : INDEX )
it - > m_Index = i ;
2015-03-21 18:27:37 -04:00
2016-04-03 21:55:12 -04:00
if ( update & eLibraryUpdate : : NAME )
item - > setText ( 0 , QString : : fromStdString ( it - > m_Name ) ) ;
2015-03-21 18:27:37 -04:00
2016-04-03 21:55:12 -04:00
if ( update & eLibraryUpdate : : POINTER )
item - > SetEmberPointer ( & ( * it ) ) ;
}
2015-03-21 18:27:37 -04:00
}
}
tree - > blockSignals ( false ) ;
}
2014-07-08 03:11:14 -04:00
/// <summary>
/// Fill the library tree with the names of the embers in the
/// currently opened file.
/// Start preview render thread.
/// </summary>
/// <param name="selectIndex">After the tree is filled, select this index. Pass -1 to omit selecting an index.</param>
template < typename T >
void FractoriumEmberController < T > : : FillLibraryTree ( int selectIndex )
{
2016-04-03 21:55:12 -04:00
uint size = 64 ;
uint i = 0 ;
2016-02-12 00:38:21 -05:00
auto tree = m_Fractorium - > ui . LibraryTree ;
2014-12-06 00:05:09 -05:00
vector < byte > v ( size * size * 4 ) ;
2016-06-11 20:47:03 -04:00
StopAllPreviewRenderers ( ) ;
2014-07-08 03:11:14 -04:00
tree - > clear ( ) ;
QCoreApplication : : flush ( ) ;
tree - > blockSignals ( true ) ;
2016-02-12 00:38:21 -05:00
auto fileItem = new QTreeWidgetItem ( tree ) ;
2014-07-08 03:11:14 -04:00
QFileInfo info ( m_EmberFile . m_Filename ) ;
fileItem - > setText ( 0 , info . fileName ( ) ) ;
fileItem - > setToolTip ( 0 , m_EmberFile . m_Filename ) ;
2016-04-03 21:55:12 -04:00
fileItem - > setFlags ( Qt : : ItemIsEnabled | Qt : : ItemIsEditable | Qt : : ItemIsSelectable | Qt : : ItemIsDropEnabled ) ;
2014-07-08 03:11:14 -04:00
2016-04-03 21:55:12 -04:00
for ( auto & it : m_EmberFile . m_Embers )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
auto emberItem = new EmberTreeWidgetItem < T > ( & it , fileItem ) ;
2014-07-08 03:11:14 -04:00
2016-04-03 21:55:12 -04:00
if ( it . m_Name . empty ( ) )
emberItem - > setText ( 0 , ToString ( i + + ) ) ;
2014-07-08 03:11:14 -04:00
else
2016-04-03 21:55:12 -04:00
emberItem - > setText ( 0 , it . m_Name . c_str ( ) ) ;
2014-07-08 03:11:14 -04:00
emberItem - > setToolTip ( 0 , emberItem - > text ( 0 ) ) ;
emberItem - > SetImage ( v , size , size ) ;
}
tree - > blockSignals ( false ) ;
if ( selectIndex ! = - 1 )
2016-02-12 00:38:21 -05:00
if ( auto top = tree - > topLevelItem ( 0 ) )
if ( auto emberItem = dynamic_cast < EmberTreeWidgetItem < T > * > ( top - > child ( selectIndex ) ) )
2014-07-08 03:11:14 -04:00
emberItem - > setSelected ( true ) ;
2016-06-11 20:47:03 -04:00
m_Fractorium - > SyncFileCountToSequenceCount ( ) ;
2014-07-08 03:11:14 -04:00
QCoreApplication : : flush ( ) ;
2016-06-11 20:47:03 -04:00
RenderLibraryPreviews ( 0 , uint ( m_EmberFile . Size ( ) ) ) ;
2016-02-12 00:38:21 -05:00
tree - > expandAll ( ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Update the library tree with the newly added embers (most likely from pasting) and
/// only render previews for the new ones, without clearing the entire tree.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : UpdateLibraryTree ( )
{
2016-04-03 21:55:12 -04:00
uint size = 64 ;
2014-12-06 00:05:09 -05:00
vector < byte > v ( size * size * 4 ) ;
2016-04-03 21:55:12 -04:00
auto tree = m_Fractorium - > ui . LibraryTree ;
2014-07-08 03:11:14 -04:00
2016-02-12 00:38:21 -05:00
if ( auto top = tree - > topLevelItem ( 0 ) )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
int origChildCount = top - > childCount ( ) ;
int i = origChildCount ;
2014-07-08 03:11:14 -04:00
tree - > blockSignals ( true ) ;
2016-04-03 21:55:12 -04:00
for ( auto it = Advance ( m_EmberFile . m_Embers . begin ( ) , i ) ; it ! = m_EmberFile . m_Embers . end ( ) ; + + it )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
auto emberItem = new EmberTreeWidgetItem < T > ( & ( * it ) , top ) ;
2014-07-08 03:11:14 -04:00
2016-04-03 21:55:12 -04:00
if ( it - > m_Name . empty ( ) )
emberItem - > setText ( 0 , ToString ( i + + ) ) ;
2014-07-08 03:11:14 -04:00
else
2016-04-03 21:55:12 -04:00
emberItem - > setText ( 0 , it - > m_Name . c_str ( ) ) ;
2014-07-08 03:11:14 -04:00
emberItem - > setToolTip ( 0 , emberItem - > text ( 0 ) ) ;
emberItem - > SetImage ( v , size , size ) ;
}
2016-04-03 21:55:12 -04:00
//When adding elements, ensure all indices are sequential.
SyncLibrary ( eLibraryUpdate : : INDEX ) ;
2016-06-11 20:47:03 -04:00
m_Fractorium - > SyncFileCountToSequenceCount ( ) ;
2014-07-08 03:11:14 -04:00
tree - > blockSignals ( false ) ;
2016-06-11 20:47:03 -04:00
RenderLibraryPreviews ( origChildCount , uint ( m_EmberFile . Size ( ) ) ) ;
2014-07-08 03:11:14 -04:00
}
}
/// <summary>
/// Copy the text of the item which was changed to the name of the current ember.
/// Ensure all names are unique in the opened file.
/// This seems to be called spuriously, so we do a check inside to make sure
/// the text was actually changed.
/// We also have to wrap the dynamic_cast call in a try/catch block because this can
/// be called on a widget that has already been deleted.
/// </summary>
/// <param name="item">The libary tree item changed</param>
/// <param name="col">The column clicked, ignored.</param>
template < typename T >
void FractoriumEmberController < T > : : EmberTreeItemChanged ( QTreeWidgetItem * item , int col )
{
try
{
2016-02-12 00:38:21 -05:00
auto tree = m_Fractorium - > ui . LibraryTree ;
2016-04-03 21:55:12 -04:00
if ( auto emberItem = dynamic_cast < EmberTreeWidgetItem < T > * > ( item ) )
2014-07-08 03:11:14 -04:00
{
--User changes
-Add new variations: bubbleT3D, crob, hexaplay3D, hexcrop, hexes, hexnix3D, loonie2, loonie3, nBlur, octapol and synth.
-Allow for pre/post versions of dc_bubble, dc_cylinder and dc_linear whereas before they were omitted.
-When saving a file with multiple embers in it, detect if time values are all the same and if so, start them at zero and increment by 1 for each ember.
-Allow for numerous quality increases to be coalesced into one. It will pick up at the end of the current render.
-Show selection highlight on variations tree in response to mouse hover. This makes it easier to see for which variation or param the current mouse wheel action will apply.
-Make default temporal samples be 100, whereas before it was 1000 which was overkill.
-Require the shift key to be held with delete for deleting an ember to prevent it from triggering when the user enters delete in the edit box.
-This wasn't otherwise fixable without writing a lot more code.
--Bug fixes
-EmberGenome was crashing when generating a sequence from a source file with more than 2 embers in it.
-EmberGenome was improperly handling the first frame of a merge after the last frame of the loop.
-These bugs were due to a previous commit. Revert parts of that commit.
-Prevent a zoom value of less than 0 when reading from xml.
-Slight optimization of the crescents, and mask variations, if the compiler wasn't doing it already.
-Unique file naming was broken because it was looking for _# and the default names ended with -#.
-Disallow renaming of an ember in the library tree to an empty string.
-Severe bug that prevented some variations from being read correctly from params generated outside this program.
-Severe OpenCL randomization bug. The first x coordinates of the first points in the first kernel call of the first ember of a render since the OpenCL renderer object was created were not random and were mostly -1.
-Severe bug when populating xform selection distributions that could sometimes cause a crash due to roundoff error. Fix by using double.
-Limit the max number of variations in a random ember to MAX_CL_VARS, which is 8. This ensures they'll look the same on CPU and GPU.
-Prevent user from saving stylesheet to default.qss, it's a special reserved filename.
--Code changes
-Generalize using the running sum output point inside of a variation for all cases: pre, reg and post.
-Allow for array variables in variations where the address of each element is stored in m_Params.
-Qualify all math functions with std::
-No longer use our own Clamp() in OpenCL, instead use the standard clamp().
-Redesign how functions are used in the variations OpenCL code.
-Add tests to EmberTester to verify some of the new functionality.
-Place more const and override qualifiers on functions where appropriate.
-Add a global rand with a lock to be used very sparingly.
-Use a map instead of a vector for bad param names in Xml parsing.
-Prefix affine interpolation mode defines with "AFFINE_" to make their purpose more clear.
-Allow for variations that change state during iteration by sending a separate copy of the ember to each rendering thread.
-Implement this same functionality with a local struct in OpenCL. It's members are the total of all variables that need to change state within an ember.
-Add Contains() function to Utils.h.
-EmberRender: print names of kernels being printed with --dump_kernel option.
-Clean up EmberTester to handle some of the recent changes.
-Fix various casts.
-Replace % 2 with & 1, even though the compiler was likely doing this already.
-Add new file Variations06.h to accommodate new variations.
-General cleanup.
2015-11-22 17:15:07 -05:00
if ( emberItem - > text ( 0 ) . isEmpty ( ) ) //Prevent empty string.
{
emberItem - > UpdateEditText ( ) ;
return ;
}
2014-07-08 03:11:14 -04:00
string oldName = emberItem - > GetEmber ( ) - > m_Name ; //First preserve the previous name.
tree - > blockSignals ( true ) ;
emberItem - > UpdateEmberName ( ) ; //Copy edit text to the ember's name variable.
m_EmberFile . MakeNamesUnique ( ) ; //Ensure all names remain unique.
2016-04-03 21:55:12 -04:00
SyncLibrary ( eLibraryUpdate : : NAME ) ; //Copy all ember names to the tree items since some might have changed to be made unique.
2014-07-08 03:11:14 -04:00
string newName = emberItem - > GetEmber ( ) - > m_Name ; //Get the new, final, unique name.
2016-04-03 21:55:12 -04:00
if ( m_EmberFilePointer = = emberItem - > GetEmber ( ) & & oldName ! = newName ) //If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
2014-07-08 03:11:14 -04:00
{
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.
}
2015-07-15 23:27:32 -04:00
2014-07-08 03:11:14 -04:00
tree - > blockSignals ( false ) ;
}
2015-07-23 21:16:36 -04:00
else if ( auto parentItem = dynamic_cast < QTreeWidgetItem * > ( item ) )
2014-07-08 03:11:14 -04:00
{
QString text = parentItem - > text ( 0 ) ;
if ( text ! = " " )
{
m_EmberFile . m_Filename = text ;
m_LastSaveAll = " " ; //Reset will force the dialog to show on the next save all since the user probably wants a different name.
}
}
}
2016-02-12 00:38:21 -05:00
catch ( const std : : exception & e )
2014-07-08 03:11:14 -04:00
{
qDebug ( ) < < " FractoriumEmberController<T>::EmberTreeItemChanged() : Exception thrown: " < < e . what ( ) ;
}
}
void Fractorium : : OnEmberTreeItemChanged ( QTreeWidgetItem * item , int col ) { m_Controller - > EmberTreeItemChanged ( item , col ) ; }
/// <summary>
/// Set the current ember to the selected item.
/// Clears the undo state.
/// Resets the rendering process.
/// Called when the user double clicks on a library tree item.
2015-08-10 23:10:23 -04:00
/// This will get called twice for some reason, and there's no way to prevent it.
/// Doesn't seem to cause any problems.
2014-07-08 03:11:14 -04:00
/// </summary>
/// <param name="item">The item double clicked on</param>
/// <param name="col">The column clicked, ignored.</param>
template < typename T >
void FractoriumEmberController < T > : : EmberTreeItemDoubleClicked ( QTreeWidgetItem * item , int col )
{
2016-02-12 00:38:21 -05:00
if ( auto emberItem = dynamic_cast < EmberTreeWidgetItem < T > * > ( item ) )
2014-07-08 03:11:14 -04:00
{
2016-04-03 21:55:12 -04:00
//qDebug() << "Setting current ember to: " << QString::fromStdString(emberItem->GetEmber()->m_Name);
2014-07-08 03:11:14 -04:00
ClearUndo ( ) ;
2016-04-13 23:59:57 -04:00
SetEmber ( * emberItem - > GetEmber ( ) , false , true ) ;
2014-07-08 03:11:14 -04:00
}
}
void Fractorium : : OnEmberTreeItemDoubleClicked ( QTreeWidgetItem * item , int col ) { m_Controller - > EmberTreeItemDoubleClicked ( item , col ) ; }
2016-04-03 21:55:12 -04:00
/// <summary>
/// Move a library item at one index to the next index.
/// </summary>
/// <param name="startRow">The index of the source item to move</param>
/// <param name="destRow">The destination index to move the item to</param>
template < typename T >
void FractoriumEmberController < T > : : MoveLibraryItems ( int startRow , int destRow )
{
int i = 0 ;
auto tree = m_Fractorium - > ui . LibraryTree ;
auto top = tree - > topLevelItem ( 0 ) ;
auto b = m_EmberFile . m_Embers . begin ( ) ;
auto s = Advance ( b , startRow ) ;
auto d = Advance ( b , destRow ) ;
m_EmberFile . m_Embers . splice ( d , m_EmberFile . m_Embers , s ) ;
SyncLibrary ( eLibraryUpdate : : INDEX ) ; //Only indices need syncing.
}
2015-03-21 18:27:37 -04:00
/// <summary>
/// Delete the currently selected item in the tree.
/// Note this is not necessarilly the current ember, it's just the item
/// in the tree that is selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
template < typename T >
void FractoriumEmberController < T > : : Delete ( const pair < size_t , QTreeWidgetItem * > & p )
{
if ( m_EmberFile . Delete ( p . first ) )
{
delete p . second ;
2016-04-03 21:55:12 -04:00
SyncLibrary ( eLibraryUpdate : : INDEX ) ;
2016-06-11 20:47:03 -04:00
m_Fractorium - > SyncFileCountToSequenceCount ( ) ;
2015-03-21 18:27:37 -04:00
}
//If there is now only one item left and it wasn't selected, select it.
2016-04-03 21:55:12 -04:00
if ( auto top = m_Fractorium - > ui . LibraryTree - > topLevelItem ( 0 ) )
2015-03-21 18:27:37 -04:00
if ( top - > childCount ( ) = = 1 )
if ( auto item = dynamic_cast < EmberTreeWidgetItem < T > * > ( top - > child ( 0 ) ) )
if ( item - > GetEmber ( ) - > m_Name ! = m_Ember . m_Name )
EmberTreeItemDoubleClicked ( top - > child ( 0 ) , 0 ) ;
}
/// <summary>
/// Called when the user presses and releases the delete key while the library tree has the focus,
/// and an item is selected.
/// </summary>
/// <param name="p">A pair containing the index of the item clicked and a pointer to the item</param>
void Fractorium : : OnDelete ( const pair < size_t , QTreeWidgetItem * > & p )
{
m_Controller - > Delete ( p ) ;
}
2014-07-08 03:11:14 -04:00
/// <summary>
/// Stop the preview renderer if it's already running.
/// Clear all of the existing preview images, then start the preview rendering thread.
/// Optionally only render previews for a subset of all open embers.
/// </summary>
/// <param name="start">The 0-based index to start rendering previews for</param>
/// <param name="end">The 0-based index which is one beyond the last ember to render a preview for</param>
template < typename T >
2016-06-11 20:47:03 -04:00
void FractoriumEmberController < T > : : RenderPreviews ( QTreeWidget * tree , TreePreviewRenderer < T > * renderer , EmberFile < T > & file , uint start , uint end )
2014-07-08 03:11:14 -04:00
{
2016-06-11 20:47:03 -04:00
renderer - > Stop ( ) ;
2014-07-08 03:11:14 -04:00
if ( start = = UINT_MAX & & end = = UINT_MAX )
{
tree - > blockSignals ( true ) ;
2016-02-12 00:38:21 -05:00
if ( auto top = tree - > topLevelItem ( 0 ) )
2014-07-08 03:11:14 -04:00
{
int childCount = top - > childCount ( ) ;
2016-04-03 21:55:12 -04:00
vector < byte > emptyPreview ( PREVIEW_SIZE * PREVIEW_SIZE * 4 ) ;
2014-07-08 03:11:14 -04:00
for ( int i = 0 ; i < childCount ; i + + )
2016-06-11 20:47:03 -04:00
if ( auto treeItem = dynamic_cast < EmberTreeWidgetItemBase * > ( top - > child ( i ) ) )
2014-07-08 03:11:14 -04:00
treeItem - > SetImage ( emptyPreview , PREVIEW_SIZE , PREVIEW_SIZE ) ;
}
tree - > blockSignals ( false ) ;
2016-06-11 20:47:03 -04:00
renderer - > Render ( 0 , uint ( file . Size ( ) ) ) ;
2014-07-08 03:11:14 -04:00
}
else
2016-06-11 20:47:03 -04:00
renderer - > Render ( start , end ) ;
}
/// <summary>
/// Wrapper around calling RenderPreviews with the appropriate values passed in for the previews in the main library tree.
/// </summary>
/// <param name="start">The 0-based index to start rendering previews for</param>
/// <param name="end">The 0-based index which is one beyond the last ember to render a preview for</param>
template < typename T >
void FractoriumEmberController < T > : : RenderLibraryPreviews ( uint start , uint end )
{
RenderPreviews ( m_Fractorium - > ui . LibraryTree , m_LibraryPreviewRenderer . get ( ) , m_EmberFile , start , end ) ;
2014-07-08 03:11:14 -04:00
}
2016-06-11 20:47:03 -04:00
template < typename T >
void FractoriumEmberController < T > : : StopLibraryPreviewRender ( ) { m_LibraryPreviewRenderer - > Stop ( ) ; }
2014-07-08 03:11:14 -04:00
/// <summary>
2016-06-11 20:47:03 -04:00
/// Thing wrapper around StopLibraryPreviewRender() and StopSequencePreviewRender() to stop both preview renderers.
2014-07-08 03:11:14 -04:00
/// </summary>
template < typename T >
2016-06-11 20:47:03 -04:00
void FractoriumEmberController < T > : : StopAllPreviewRenderers ( )
2014-07-08 03:11:14 -04:00
{
2016-06-11 20:47:03 -04:00
StopLibraryPreviewRender ( ) ;
StopSequencePreviewRender ( ) ;
}
/// <summary>
/// Fill the sequence tree with the names of the embers in the
/// currently generated sequence.
/// Start the sequence preview render thread.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : FillSequenceTree ( )
{
uint size = 64 ;
uint i = 0 ;
auto tree = m_Fractorium - > ui . SequenceTree ;
vector < byte > v ( size * size * 4 ) ;
m_SequencePreviewRenderer - > Stop ( ) ;
tree - > clear ( ) ;
QCoreApplication : : flush ( ) ;
tree - > blockSignals ( true ) ;
auto fileItem = new QTreeWidgetItem ( tree ) ;
QFileInfo info ( m_SequenceFile . m_Filename ) ;
fileItem - > setText ( 0 , info . fileName ( ) ) ;
fileItem - > setToolTip ( 0 , m_SequenceFile . m_Filename ) ;
fileItem - > setFlags ( Qt : : ItemIsEnabled | Qt : : ItemIsEditable | Qt : : ItemIsSelectable ) ;
2014-07-08 03:11:14 -04:00
2016-06-11 20:47:03 -04:00
for ( auto & it : m_SequenceFile . m_Embers )
{
auto emberItem = new EmberTreeWidgetItemBase ( fileItem ) ;
2016-02-12 00:38:21 -05:00
2016-06-11 20:47:03 -04:00
if ( it . m_Name . empty ( ) )
emberItem - > setText ( 0 , ToString ( i + + ) ) ;
else
emberItem - > setText ( 0 , it . m_Name . c_str ( ) ) ;
2014-07-08 03:11:14 -04:00
2016-06-11 20:47:03 -04:00
emberItem - > setFlags ( Qt : : ItemIsEnabled | Qt : : ItemIsSelectable ) ;
emberItem - > setToolTip ( 0 , emberItem - > text ( 0 ) ) ;
emberItem - > SetImage ( v , size , size ) ;
}
2014-07-08 03:11:14 -04:00
2016-06-11 20:47:03 -04:00
tree - > blockSignals ( false ) ;
2014-07-08 03:11:14 -04:00
QCoreApplication : : flush ( ) ;
2016-06-11 20:47:03 -04:00
RenderSequencePreviews ( 0 , uint ( m_SequenceFile . Size ( ) ) ) ;
tree - > expandAll ( ) ;
}
/// <summary>
/// Copy the text of the root item to the name of the sequence file.
/// Called whenever the text of the root item is changed.
/// </summary>
/// <param name="item">The root sequence tree item which changed</param>
/// <param name="col">The column clicked, ignored.</param>
template < typename T >
void FractoriumEmberController < T > : : SequenceTreeItemChanged ( QTreeWidgetItem * item , int col )
{
2016-06-13 19:33:51 -04:00
if ( item = = m_Fractorium - > ui . SequenceTree - > topLevelItem ( 0 ) )
2016-06-11 20:47:03 -04:00
{
2016-06-13 19:33:51 -04:00
QString text = item - > text ( 0 ) ;
2016-06-11 20:47:03 -04:00
if ( text ! = " " )
m_SequenceFile . m_Filename = text ;
}
}
void Fractorium : : OnSequenceTreeItemChanged ( QTreeWidgetItem * item , int col ) { m_Controller - > SequenceTreeItemChanged ( item , col ) ; }
/// <summary>
/// Wrapper around calling RenderPreviews with the appropriate values passed in for the previews in the sequence tree.
/// Called when Render Previews is clicked.
/// </summary>
/// <param name="start">Ignored, render all.</param>
/// <param name="end">Ignored, render all.</param>
template < typename T >
void FractoriumEmberController < T > : : RenderSequencePreviews ( uint start , uint end ) { RenderPreviews ( m_Fractorium - > ui . SequenceTree , m_SequencePreviewRenderer . get ( ) , m_SequenceFile , start , end ) ; }
void Fractorium : : OnSequenceStartPreviewsButtonClicked ( bool checked ) { m_Controller - > RenderSequencePreviews ( ) ; }
/// <summary>
/// Stop rendering the sequence previews.
/// Called when Stop Previews is clicked.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : StopSequencePreviewRender ( ) { m_SequencePreviewRenderer - > Stop ( ) ; }
void Fractorium : : OnSequenceStopPreviewsButtonClicked ( bool checked ) { m_Controller - > StopSequencePreviewRender ( ) ; }
/// <summary>
/// Set the start and stop spin boxes to 0 and the length of the ember file minus 1, respectively.
/// Called whenever the count of the current file changes or when All is clicked.
/// </summary>
void Fractorium : : SyncFileCountToSequenceCount ( )
{
if ( auto top = ui . LibraryTree - > topLevelItem ( 0 ) )
{
int count = top - > childCount ( ) - 1 ;
ui . SequenceStartFlameSpinBox - > setMinimum ( 0 ) ;
ui . SequenceStartFlameSpinBox - > setMaximum ( count ) ;
ui . SequenceStartFlameSpinBox - > setValue ( 0 ) ;
ui . SequenceStopFlameSpinBox - > setMinimum ( 0 ) ;
ui . SequenceStopFlameSpinBox - > setMaximum ( count ) ;
ui . SequenceStopFlameSpinBox - > setValue ( count ) ;
}
}
void Fractorium : : OnSequenceAllButtonClicked ( bool checked ) { SyncFileCountToSequenceCount ( ) ; }
/// <summary>
/// Generate an animation sequence and place it in the sequence tree. This code is
/// mostly similar to that of EmberGenome.
/// It differs in a few ways:
/// The number of frames used in a rotation and in blending can differ. In EmberGenome, they are the same.
/// The number of rotations, frames used in rotations and frames used in blending can all be randomized.
/// Called when the Generate button is clicked.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : SequenceGenerateButtonClicked ( )
{
StopAllPreviewRenderers ( ) ;
SaveCurrentToOpenedFile ( false ) ;
Ember < T > result ;
auto & ui = m_Fractorium - > ui ;
auto s = m_Fractorium - > m_Settings ;
bool randStagger = ui . SequenceRandomizeStaggerCheckBox - > isChecked ( ) ;
bool randFramesRot = ui . SequenceRandomizeFramesPerRotCheckBox - > isChecked ( ) ;
bool randRot = ui . SequenceRandomizeRotationsCheckBox - > isChecked ( ) ;
bool randBlend = ui . SequenceRandomizeBlendFramesCheckBox - > isChecked ( ) ;
2016-06-11 22:01:19 -04:00
double stagger = ui . SequenceStaggerSpinBox - > value ( ) ;
double staggerMax = ui . SequenceRandomStaggerMaxSpinBox - > value ( ) ;
2016-06-11 20:47:03 -04:00
double rots = ui . SequenceRotationsSpinBox - > value ( ) ;
double rotsMax = ui . SequenceRandomRotationsMaxSpinBox - > value ( ) ;
int framesPerRot = ui . SequenceFramesPerRotSpinBox - > value ( ) ;
int framesPerRotMax = ui . SequenceRandomFramesPerRotMaxSpinBox - > value ( ) ;
int framesBlend = ui . SequenceBlendFramesSpinBox - > value ( ) ;
int framesBlendMax = ui . SequenceRandomBlendMaxFramesSpinBox - > value ( ) ;
size_t start = ui . SequenceStartFlameSpinBox - > value ( ) ;
size_t stop = ui . SequenceStopFlameSpinBox - > value ( ) ;
size_t startCount = ui . SequenceStartCountSpinBox - > value ( ) ;
size_t keyFrames = ( stop - start ) + 1 ;
size_t frameCount = 0 ;
double frames = 0 ;
vector < pair < size_t , size_t > > devices ; //Dummy.
EmberReport emberReport ;
ostringstream os ;
string palettePath =
# ifdef _WIN32
" ./flam3-palettes.xml " ;
# else
" ~/.config/fractorium " ;
# endif
SheepTools < T , float > tools ( palettePath , EmberCommon : : CreateRenderer < T > ( eRendererType : : CPU_RENDERER , devices , false , 0 , emberReport ) ) ;
tools . SetSpinParams ( true ,
2016-06-11 22:01:19 -04:00
stagger , //Will be set again below if random is used.
2016-06-11 20:47:03 -04:00
0 ,
0 ,
s - > Nick ( ) . toStdString ( ) ,
s - > Url ( ) . toStdString ( ) ,
s - > Id ( ) . toStdString ( ) ,
" " ,
0 ,
0 ) ;
if ( randFramesRot )
frames = ui . SequenceRandomFramesPerRotMaxSpinBox - > value ( ) ;
else
frames = ui . SequenceFramesPerRotSpinBox - > value ( ) ;
if ( randRot )
frames * = ui . SequenceRandomRotationsMaxSpinBox - > value ( ) ;
else
frames * = ui . SequenceRotationsSpinBox - > value ( ) ;
if ( randBlend )
frames + = ui . SequenceRandomBlendMaxFramesSpinBox - > value ( ) ;
else
frames + = ui . SequenceBlendFramesSpinBox - > value ( ) ;
frames * = keyFrames ;
frames + = startCount ;
os < < setfill ( ' 0 ' ) < < setprecision ( 0 ) < < fixed ;
m_SequenceFile . Clear ( ) ;
m_SequenceFile . m_Filename = EmberFile < T > : : DefaultFilename ( " Sequence_ " ) ;
double blend ;
size_t frame ;
Ember < T > embers [ 2 ] ; //Spin needs contiguous array below, and this will also get modified, so a copy is needed to avoid modifying the embers in the original file.
auto padding = streamsize ( std : : log10 ( frames ) ) + 1 ;
auto it = Advance ( m_EmberFile . m_Embers . begin ( ) , start ) ;
for ( size_t i = start ; i < = stop & & it ! = m_EmberFile . m_Embers . end ( ) ; i + + , + + it )
{
double rotations = randRot ? m_Rand . Frand < double > ( rots , rotsMax ) : rots ;
embers [ 0 ] = * it ;
if ( rotations > 0 )
{
double rotFrames = randFramesRot ? m_Rand . Frand < double > ( framesPerRot , framesPerRotMax ) : framesPerRot ;
size_t roundFrames = size_t ( std : : round ( rotFrames * rotations ) ) ;
for ( frame = 0 ; frame < roundFrames ; frame + + )
{
blend = frame / rotFrames ;
tools . Spin ( embers [ 0 ] , nullptr , result , startCount + frameCount + + , blend ) ; //Result is cleared and reassigned each time inside of Spin().
FormatName ( result , os , padding ) ;
m_SequenceFile . m_Embers . push_back ( result ) ;
}
//The loop above will have rotated just shy of a complete rotation.
//Rotate the next step and save in result, but do not print.
//result will be the starting point for the interp phase below.
frame = roundFrames ;
blend = frame / rotFrames ;
tools . Spin ( embers [ 0 ] , nullptr , result , startCount + frameCount , blend ) ; //Do not increment frameCount here.
FormatName ( result , os , padding ) ;
}
if ( i < stop )
{
if ( rotations > 0 ) //Store the last result as the flame to interpolate from. This applies for whole or fractional values of opt.Loops().
embers [ 0 ] = result ;
auto it2 = it ; //Need a quick temporary to avoid modifying it which is used in the loop.
embers [ 1 ] = * ( + + it2 ) ; //Get the next ember to be used with blending below.
size_t blendFrames = randBlend ? m_Rand . Frand < double > ( framesBlend , framesBlendMax ) : framesBlend ;
2016-06-11 22:01:19 -04:00
if ( randStagger )
tools . Stagger ( m_Rand . Frand < double > ( stagger , staggerMax ) ) ;
2016-06-11 20:47:03 -04:00
for ( frame = 0 ; frame < blendFrames ; frame + + )
{
bool seqFlag = frame = = 0 | | ( frame = = blendFrames - 1 ) ;
blend = frame / double ( blendFrames ) ;
result . Clear ( ) ;
tools . SpinInter ( & embers [ 0 ] , nullptr , result , startCount + frameCount + + , seqFlag , blend ) ;
FormatName ( result , os , padding ) ;
m_SequenceFile . m_Embers . push_back ( result ) ;
}
}
}
it = Advance ( m_EmberFile . m_Embers . begin ( ) , stop ) ;
tools . Spin ( * it , nullptr , result , startCount + frameCount , 0 ) ;
FormatName ( result , os , padding ) ;
m_SequenceFile . m_Embers . push_back ( result ) ;
FillSequenceTree ( ) ; //The sequence has been generated, now create preview thumbnails.
}
void Fractorium : : OnSequenceGenerateButtonClicked ( bool checked ) { m_Controller - > SequenceGenerateButtonClicked ( ) ; }
/// <summary>
/// Show the final render dialog and load the sequence into it.
/// This will automatically check the Render All and Render as Animation sequence checkboxes.
/// Called when the Render Sequence button is clicked.
/// </summary>
/// <param name="checked">Ignored.</param>
void Fractorium : : OnSequenceRenderButtonClicked ( bool checked )
{
//First completely stop what the current rendering process is doing.
m_Controller - > DeleteRenderer ( ) ; //Delete the renderer, but not the controller.
m_Controller - > StopAllPreviewRenderers ( ) ;
m_Controller - > SaveCurrentToOpenedFile ( false ) ; //Save whatever was edited back to the current open file.
m_RenderStatusLabel - > setText ( " Renderer stopped. " ) ;
m_FinalRenderDialog - > Show ( true ) ; //Show with a bool specifying that it came from the sequence generator.
}
/// <summary>
/// Save the sequence to a file.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : SequenceSaveButtonClicked ( )
{
auto s = m_Fractorium - > m_Settings ;
QString filename = m_Fractorium - > SetupSaveXmlDialog ( m_SequenceFile . m_Filename ) ;
if ( filename ! = " " )
{
EmberToXml < T > writer ;
QFileInfo fileInfo ( filename ) ;
2016-06-13 19:33:51 -04:00
for ( auto & ember : m_SequenceFile . m_Embers )
ApplyXmlSavingTemplate ( ember ) ;
2016-06-11 20:47:03 -04:00
if ( writer . Save ( filename . toStdString ( ) . c_str ( ) , m_SequenceFile . m_Embers , 0 , true , true ) )
s - > SaveFolder ( fileInfo . canonicalPath ( ) ) ;
else
m_Fractorium - > ShowCritical ( " Save Failed " , " Could not save sequence file, try saving to a different folder. " ) ;
}
}
void Fractorium : : OnSequenceSaveButtonClicked ( bool checked ) { m_Controller - > SequenceSaveButtonClicked ( ) ; }
/// <summary>
/// Open one or more sequence file, concatenate them all, place them in the sequence
/// tree and begin rendering the sequence previews.
/// </summary>
template < typename T >
void FractoriumEmberController < T > : : SequenceOpenButtonClicked ( )
{
m_SequencePreviewRenderer - > Stop ( ) ;
auto filenames = m_Fractorium - > SetupOpenXmlDialog ( ) ;
if ( ! filenames . empty ( ) )
{
size_t i ;
EmberFile < T > emberFile ;
XmlToEmber < T > parser ;
vector < Ember < T > > embers ;
vector < string > errors ;
emberFile . m_Filename = filenames [ 0 ] ;
for ( auto & filename : filenames )
{
embers . clear ( ) ;
if ( parser . Parse ( filename . toStdString ( ) . c_str ( ) , embers ) & & ! embers . empty ( ) )
{
for ( i = 0 ; i < embers . size ( ) ; i + + )
if ( embers [ i ] . m_Name = = " " | | embers [ i ] . m_Name = = " No name " ) //Ensure it has a name.
embers [ i ] . m_Name = ToString < qulonglong > ( i ) . toStdString ( ) ;
emberFile . m_Embers . insert ( emberFile . m_Embers . end ( ) , embers . begin ( ) , embers . end ( ) ) ;
errors = parser . ErrorReport ( ) ;
}
else
{
errors = parser . ErrorReport ( ) ;
m_Fractorium - > ShowCritical ( " Open Failed " , " Could not open sequence file, see info tab for details. " ) ;
}
if ( ! errors . empty ( ) )
m_Fractorium - > ErrorReportToQTextEdit ( errors , m_Fractorium - > ui . InfoFileOpeningTextEdit , false ) ; //Concat errors from all files.
}
if ( emberFile . Size ( ) > 0 ) //Ensure at least something was read.
{
emberFile . MakeNamesUnique ( ) ;
m_SequenceFile = std : : move ( emberFile ) ; //Move the temp to avoid creating dupes because we no longer need it.
FillSequenceTree ( ) ;
}
}
}
void Fractorium : : OnSequenceOpenButtonClicked ( bool checked ) { m_Controller - > SequenceOpenButtonClicked ( ) ; }
2016-06-11 22:01:19 -04:00
void Fractorium : : OnSequenceRandomizeStaggerCheckBoxStateChanged ( int state ) { ui . SequenceRandomStaggerMaxSpinBox - > setEnabled ( state ) ; }
2016-06-11 20:47:03 -04:00
void Fractorium : : OnSequenceRandomizeFramesPerRotCheckBoxStateChanged ( int state ) { ui . SequenceRandomFramesPerRotMaxSpinBox - > setEnabled ( state ) ; }
void Fractorium : : OnSequenceRandomizeRotationsCheckBoxStateChanged ( int state ) { ui . SequenceRandomRotationsMaxSpinBox - > setEnabled ( state ) ; }
void Fractorium : : OnSequenceRandomizeBlendFramesCheckBoxStateChanged ( int state ) { ui . SequenceRandomBlendMaxFramesSpinBox - > setEnabled ( state ) ; }
/// <summary>
/// Constrain all min/max spinboxes.
/// </summary>
2016-06-11 22:01:19 -04:00
void Fractorium : : OnSequenceStaggerSpinBoxChanged ( double d ) { if ( ui . SequenceRandomizeStaggerCheckBox - > isChecked ( ) ) ConstrainLow ( ui . SequenceStaggerSpinBox , ui . SequenceRandomStaggerMaxSpinBox ) ; }
void Fractorium : : OnSequenceRandomStaggerMaxSpinBoxChanged ( double d ) { ConstrainHigh ( ui . SequenceStaggerSpinBox , ui . SequenceRandomStaggerMaxSpinBox ) ; }
void Fractorium : : OnSequenceStartFlameSpinBoxChanged ( int d ) { ConstrainLow ( ui . SequenceStartFlameSpinBox , ui . SequenceStopFlameSpinBox ) ; }
void Fractorium : : OnSequenceStopFlameSpinBoxChanged ( int d ) { ConstrainHigh ( ui . SequenceStartFlameSpinBox , ui . SequenceStopFlameSpinBox ) ; }
void Fractorium : : OnSequenceFramesPerRotSpinBoxChanged ( int d ) { if ( ui . SequenceRandomizeFramesPerRotCheckBox - > isChecked ( ) ) ConstrainLow ( ui . SequenceFramesPerRotSpinBox , ui . SequenceRandomFramesPerRotMaxSpinBox ) ; }
2016-06-11 20:47:03 -04:00
void Fractorium : : OnSequenceRandomFramesPerRotMaxSpinBoxChanged ( int d ) { ConstrainHigh ( ui . SequenceFramesPerRotSpinBox , ui . SequenceRandomFramesPerRotMaxSpinBox ) ; }
2016-06-11 22:01:19 -04:00
void Fractorium : : OnSequenceRotationsSpinBoxChanged ( double d ) { if ( ui . SequenceRandomizeRotationsCheckBox - > isChecked ( ) ) ConstrainLow ( ui . SequenceRotationsSpinBox , ui . SequenceRandomRotationsMaxSpinBox ) ; }
2016-06-11 20:47:03 -04:00
void Fractorium : : OnSequenceRandomRotationsMaxSpinBoxChanged ( double d ) { ConstrainHigh ( ui . SequenceRotationsSpinBox , ui . SequenceRandomRotationsMaxSpinBox ) ; }
2016-06-11 22:01:19 -04:00
void Fractorium : : OnSequenceBlendFramesSpinBoxChanged ( int d ) { if ( ui . SequenceRandomizeBlendFramesCheckBox - > isChecked ( ) ) ConstrainLow ( ui . SequenceBlendFramesSpinBox , ui . SequenceRandomBlendMaxFramesSpinBox ) ; }
void Fractorium : : OnSequenceRandomBlendMaxFramesSpinBoxChanged ( int d ) { ConstrainHigh ( ui . SequenceBlendFramesSpinBox , ui . SequenceRandomBlendMaxFramesSpinBox ) ; }
2016-06-11 20:47:03 -04:00
/// <summary>
/// Save all sequence settings to match the values in the controls.
/// </summary>
void Fractorium : : SyncSequenceSettings ( )
{
2016-06-11 22:01:19 -04:00
m_Settings - > Stagger ( ui . SequenceStaggerSpinBox - > value ( ) ) ;
m_Settings - > StaggerMax ( ui . SequenceRandomStaggerMaxSpinBox - > value ( ) ) ;
2016-06-11 20:47:03 -04:00
m_Settings - > FramesPerRot ( ui . SequenceFramesPerRotSpinBox - > value ( ) ) ;
m_Settings - > FramesPerRotMax ( ui . SequenceRandomFramesPerRotMaxSpinBox - > value ( ) ) ;
m_Settings - > Rotations ( ui . SequenceRotationsSpinBox - > value ( ) ) ;
m_Settings - > RotationsMax ( ui . SequenceRandomRotationsMaxSpinBox - > value ( ) ) ;
m_Settings - > BlendFrames ( ui . SequenceBlendFramesSpinBox - > value ( ) ) ;
m_Settings - > BlendFramesMax ( ui . SequenceRandomBlendMaxFramesSpinBox - > value ( ) ) ;
2014-07-08 03:11:14 -04:00
}
2014-12-11 00:50:15 -05:00
template class FractoriumEmberController < float > ;
# ifdef DO_DOUBLE
2016-02-12 00:38:21 -05:00
template class FractoriumEmberController < double > ;
2014-12-11 00:50:15 -05:00
# endif