0.4.1.1 Beta 08/03/2014

--Bug Fixes
Spatial filter would not be correctly recreated on subsequent runs of
differing supersample values during final render.
Fix DCBubble, Funnel, SphericalN,
Wrong logic with some usage of DO_DOUBLE. Only relevant for testing.
Use uint64 for iters/sec calculation on final render dialog. int was
overflowing on extremely fast GPU renders.

--Code Changes
Make density, spatial and temporal filters preserve the values they were
created with. This helps in determining when a new instance is needed.
Better NULL checks when copying embers and xforms.
Rename members in FractoriumEmberControllerBase.h to omit duplicating
the members declared in the base.
This commit is contained in:
mfeemster 2014-08-03 16:16:10 -07:00
parent 152318a567
commit 570d3bcf1d
21 changed files with 135 additions and 80 deletions

View File

@ -6,7 +6,7 @@
<ProductVersion>3.7</ProductVersion> <ProductVersion>3.7</ProductVersion>
<ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid> <ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<OutputName>Fractorium_Beta_0.4.1.0</OutputName> <OutputName>Fractorium_Beta_0.4.1.1</OutputName>
<OutputType>Package</OutputType> <OutputType>Package</OutputType>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath> <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath> <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ProductVersion="0.4.1.0" ?> <?define ProductVersion="0.4.1.1" ?>
<?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?> <?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?>
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?> <?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
<?define Manufacturer="Fractorium"?> <?define Manufacturer="Fractorium"?>
@ -13,7 +13,7 @@
<!-- <!--
Change this for every release. Change this for every release.
--> -->
<?define ProductCode="{11E92742-0C6F-4FBB-9F24-5B94984AFCC9}"?> <?define ProductCode="{478E2A85-97E3-4F2D-90AE-6509209D9240}"?>
<Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)"> <Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package <Package

Binary file not shown.

View File

@ -1,4 +1,15 @@
0.4.0.9 Beta 07/29/2014 0.4.1.1 Beta 08/03/2014
--Bug Fixes
Spatial filter would not be correctly recreated on subsequent runs of differing supersample values during final render.
Fix DCBubble, Funnel, SphericalN,
Wrong logic with some usage of DO_DOUBLE. Only relevant for testing.
--Code Changes
Make density, spatial and temporal filters preserve the values they were created with. This helps in determining when a new instance is needed.
Better NULL checks when copying embers and xforms.
Rename members in FractoriumEmberControllerBase.h to omit duplicating the members declared in the base.
0.4.1.0 Beta 07/29/2014
--Bug Fixes --Bug Fixes
Final render dialog didn't create the renderer properly on first run when more than one platform was present. Final render dialog didn't create the renderer properly on first run when more than one platform was present.

View File

@ -312,6 +312,7 @@ public:
inline T MinRad() const { return m_MinRad; } inline T MinRad() const { return m_MinRad; }
inline T MaxRad() const { return m_MaxRad; } inline T MaxRad() const { return m_MaxRad; }
inline T Curve() const { return m_Curve; } inline T Curve() const { return m_Curve; }
inline unsigned int Supersample() const { return m_Supersample; }
inline unsigned int KernelSize() const { return m_KernelSize; } inline unsigned int KernelSize() const { return m_KernelSize; }
inline unsigned int MaxFilterIndex() const { return m_MaxFilterIndex; } inline unsigned int MaxFilterIndex() const { return m_MaxFilterIndex; }
inline unsigned int MaxFilteredCounts() const { return m_MaxFilteredCounts; } inline unsigned int MaxFilteredCounts() const { return m_MaxFilteredCounts; }

View File

@ -143,10 +143,13 @@ public:
for (unsigned int i = 0; i < ember.XformCount(); i++) for (unsigned int i = 0; i < ember.XformCount(); i++)
{ {
Xform<T> xform = *ember.GetXform(i);//Will call assignment operator to convert between types T and U. if (Xform<U>* p = ember.GetXform(i))
{
Xform<T> xform = *p;//Will call assignment operator to convert between types T and U.
AddXform(xform); AddXform(xform);
} }
}
Xform<T> finalXform = *ember.FinalXform();//Will call assignment operator to convert between types T and U. Xform<T> finalXform = *ember.FinalXform();//Will call assignment operator to convert between types T and U.

View File

@ -25,7 +25,7 @@ namespace EmberNs
extern void sincos(double x, double *s, double *c); extern void sincos(double x, double *s, double *c);
#endif #endif
#define EMBER_VERSION "0.4.1.0" #define EMBER_VERSION "0.4.1.1"
#define EPS6 T(1e-6) #define EPS6 T(1e-6)
#define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way. #define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
#define ISAAC_SIZE 4 #define ISAAC_SIZE 4

View File

@ -263,12 +263,12 @@ bool Renderer<T, bucketT>::CreateTemporalFilter(bool& newAlloc)
newAlloc = false; newAlloc = false;
//Use intelligent testing so it isn't created every time a new ember is passed in. //Use intelligent testing so it isn't created every time a new ember is passed in.
if ((m_TemporalFilter.get() == NULL) || if ((!m_TemporalFilter.get()) ||
(m_Ember.m_Passes != m_LastEmber.m_Passes) || (m_Ember.m_Passes != m_TemporalFilter->Passes()) ||
(m_Ember.m_TemporalSamples != m_LastEmber.m_TemporalSamples) || (m_Ember.m_TemporalSamples != m_TemporalFilter->TemporalSamples()) ||
(m_Ember.m_TemporalFilterType != m_TemporalFilter->FilterType()) || (m_Ember.m_TemporalFilterType != m_TemporalFilter->FilterType()) ||
(m_Ember.m_TemporalFilterWidth != m_LastEmber.m_TemporalFilterWidth) || (m_Ember.m_TemporalFilterWidth != m_TemporalFilter->FilterWidth()) ||
(m_Ember.m_TemporalFilterExp != m_LastEmber.m_TemporalFilterExp)) (m_Ember.m_TemporalFilterExp != m_TemporalFilter->FilterExp()))
{ {
m_TemporalFilter = auto_ptr<TemporalFilter<T>>( m_TemporalFilter = auto_ptr<TemporalFilter<T>>(
TemporalFilterCreator<T>::Create(m_Ember.m_TemporalFilterType, m_Ember.m_Passes, m_Ember.m_TemporalSamples, m_Ember.m_TemporalFilterWidth, m_Ember.m_TemporalFilterExp)); TemporalFilterCreator<T>::Create(m_Ember.m_TemporalFilterType, m_Ember.m_Passes, m_Ember.m_TemporalSamples, m_Ember.m_TemporalFilterWidth, m_Ember.m_TemporalFilterExp));
@ -296,11 +296,11 @@ bool Renderer<T, bucketT>::PrepFinalAccumVector(vector<unsigned char>& pixels)
if (m_ReclaimOnResize) if (m_ReclaimOnResize)
{ {
if (pixels.size() != size) if (pixels.size() != size)
{
pixels.resize(size); pixels.resize(size);
if (m_ReclaimOnResize)
pixels.shrink_to_fit(); pixels.shrink_to_fit();
} }
}
else else
{ {
if (pixels.size() < size) if (pixels.size() < size)
@ -850,11 +850,11 @@ bool Renderer<T, bucketT>::CreateDEFilter(bool& newAlloc)
if (m_Ember.m_MaxRadDE > 0) if (m_Ember.m_MaxRadDE > 0)
{ {
//Use intelligent testing so it isn't created every time a new ember is passed in. //Use intelligent testing so it isn't created every time a new ember is passed in.
if ((m_DensityFilter.get() == NULL) || if ((!m_DensityFilter.get()) ||
(m_Ember.m_MinRadDE != m_DensityFilter->MinRad()) || (m_Ember.m_MinRadDE != m_DensityFilter->MinRad()) ||
(m_Ember.m_MaxRadDE != m_DensityFilter->MaxRad()) || (m_Ember.m_MaxRadDE != m_DensityFilter->MaxRad()) ||
(m_Ember.m_CurveDE != m_DensityFilter->Curve()) || (m_Ember.m_CurveDE != m_DensityFilter->Curve()) ||
(m_Ember.m_Supersample != m_LastEmber.m_Supersample)) (m_Ember.m_Supersample != m_DensityFilter->Supersample()))
{ {
m_DensityFilter = auto_ptr<DensityFilter<T>>(new DensityFilter<T>(m_Ember.m_MinRadDE, m_Ember.m_MaxRadDE, m_Ember.m_CurveDE, m_Ember.m_Supersample)); m_DensityFilter = auto_ptr<DensityFilter<T>>(new DensityFilter<T>(m_Ember.m_MinRadDE, m_Ember.m_MaxRadDE, m_Ember.m_CurveDE, m_Ember.m_Supersample));
newAlloc = true; newAlloc = true;
@ -889,10 +889,10 @@ bool Renderer<T, bucketT>::CreateSpatialFilter(bool& newAlloc)
newAlloc = false; newAlloc = false;
//Use intelligent testing so it isn't created every time a new ember is passed in. //Use intelligent testing so it isn't created every time a new ember is passed in.
if ((m_SpatialFilter.get() == NULL) || if ((!m_SpatialFilter.get()) ||
(m_Ember.m_SpatialFilterType != m_SpatialFilter->FilterType()) || (m_Ember.m_SpatialFilterType != m_SpatialFilter->FilterType()) ||
(m_Ember.m_SpatialFilterRadius != m_SpatialFilter->FilterRadius()) || (m_Ember.m_SpatialFilterRadius != m_SpatialFilter->FilterRadius()) ||
(m_Ember.m_Supersample != m_LastEmber.m_Supersample) || (m_Ember.m_Supersample != m_SpatialFilter->Supersample()) ||
(m_PixelAspectRatio != m_SpatialFilter->PixelAspectRatio())) (m_PixelAspectRatio != m_SpatialFilter->PixelAspectRatio()))
{ {
m_SpatialFilter = auto_ptr<SpatialFilter<T>>( m_SpatialFilter = auto_ptr<SpatialFilter<T>>(
@ -1007,7 +1007,7 @@ void Renderer<T, bucketT>::ThreadCount(unsigned int threads, const char* seedStr
#ifdef ISAAC_FLAM3_DEBUG #ifdef ISAAC_FLAM3_DEBUG
QTIsaac<ISAAC_SIZE, ISAAC_INT> isaac(0, 0, 0, seeds); QTIsaac<ISAAC_SIZE, ISAAC_INT> isaac(0, 0, 0, seeds);
#else #else
QTIsaac<ISAAC_SIZE, ISAAC_INT> isaac(newSize, newSize * newSize, newSize * newSize * newSize, seeds); QTIsaac<ISAAC_SIZE, ISAAC_INT> isaac(newSize, newSize * 2, newSize * 3, seeds);
#endif #endif
m_Rand.push_back(isaac); m_Rand.push_back(isaac);

View File

@ -40,9 +40,13 @@ public:
{ {
unsigned int i, steps = passes * temporalSamples; unsigned int i, steps = passes * temporalSamples;
m_Passes = passes;
m_TemporalSamples = temporalSamples;
m_FilterWidth = filterWidth;
m_Deltas.resize(steps); m_Deltas.resize(steps);
m_Filter.resize(steps); m_Filter.resize(steps);
m_FilterType = filterType; m_FilterType = filterType;
m_FilterExp = 1;
if (steps == 1) if (steps == 1)
{ {
@ -83,6 +87,10 @@ public:
{ {
if (this != &filter) if (this != &filter)
{ {
m_Passes = filter.m_Passes;
m_TemporalSamples = filter.m_TemporalSamples;
m_FilterWidth = filter.m_FilterWidth;
m_FilterExp = filter.m_FilterExp;
m_SumFilt = filter.m_SumFilt; m_SumFilt = filter.m_SumFilt;
m_Deltas = filter.m_Deltas; m_Deltas = filter.m_Deltas;
m_Filter = filter.m_Filter; m_Filter = filter.m_Filter;
@ -127,6 +135,10 @@ public:
/// Accessors. /// Accessors.
/// </summary> /// </summary>
size_t Size() const { return m_Filter.size(); } size_t Size() const { return m_Filter.size(); }
unsigned int Passes() const { return m_Passes; }
unsigned int TemporalSamples() const { return m_TemporalSamples; }
T FilterWidth() const { return m_FilterWidth; }
T FilterExp() const { return m_FilterExp; }
T SumFilt() const { return m_SumFilt; } T SumFilt() const { return m_SumFilt; }
T* Deltas() { return &m_Deltas[0]; } T* Deltas() { return &m_Deltas[0]; }
T* Filter() { return &m_Filter[0]; } T* Filter() { return &m_Filter[0]; }
@ -151,6 +163,10 @@ protected:
} }
T m_SumFilt;//The sum of all filter values. T m_SumFilt;//The sum of all filter values.
T m_FilterWidth;
T m_FilterExp;
unsigned int m_Passes;
unsigned int m_TemporalSamples;
vector<T> m_Deltas;//Delta vector. vector<T> m_Deltas;//Delta vector.
vector<T> m_Filter;//Filter vector. vector<T> m_Filter;//Filter vector.
eTemporalFilterType m_FilterType;//The type of filter this is. eTemporalFilterType m_FilterType;//The type of filter this is.
@ -192,6 +208,7 @@ public:
maxFilt = m_Filter[i]; maxFilt = m_Filter[i];
} }
m_FilterExp = filterExp;
FinishFilter(maxFilt); FinishFilter(maxFilt);
} }
} }

View File

@ -20,7 +20,7 @@ public:
void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
{ {
T temp = 1 / cos(helper.In.y) + m_Effect * T(M_PI); T temp = 1 / Zeps(cos(helper.In.y)) + m_Effect * T(M_PI);
helper.Out.x = m_Weight * (tanh(helper.In.x) * temp); helper.Out.x = m_Weight * (tanh(helper.In.x) * temp);
helper.Out.y = m_Weight * (tanh(helper.In.y) * temp); helper.Out.y = m_Weight * (tanh(helper.In.y) * temp);
@ -36,7 +36,7 @@ public:
string effect = "parVars[" + ToUpper(m_Params[i++].Name()) + index; string effect = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n" ss << "\t{\n"
<< "\t\treal_t temp = 1 / cos(vIn.y) + " << effect << " * M_PI;\n" << "\t\treal_t temp = 1 / Zeps(cos(vIn.y)) + " << effect << " * M_PI;\n"
<< "\n" << "\n"
<< "\t\tvOut.x = xform->m_VariationWeights[" << varIndex << "] * (tanh(vIn.x) * temp);\n" << "\t\tvOut.x = xform->m_VariationWeights[" << varIndex << "] * (tanh(vIn.x) * temp);\n"
<< "\t\tvOut.y = xform->m_VariationWeights[" << varIndex << "] * (tanh(vIn.y) * temp);\n" << "\t\tvOut.y = xform->m_VariationWeights[" << varIndex << "] * (tanh(vIn.y) * temp);\n"
@ -276,11 +276,9 @@ public:
void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
{ {
T r = pow(helper.m_PrecalcSqrtSumSquares, m_Dist); T r = Zeps(pow(helper.m_PrecalcSqrtSumSquares, m_Dist));
int n = Floor<T>(m_Power * rand.Frand01<T>()); int n = Floor<T>(m_Power * rand.Frand01<T>());
T alpha = helper.m_PrecalcAtanyx + n * M_2PI / Floor<T>(m_Power); T alpha = helper.m_PrecalcAtanyx + n * M_2PI / Zeps<T>((T)Floor<T>(m_Power));
//int n = (int)floor(m_Power * rand.Frand01<T>());
//T alpha = helper.m_PrecalcAtanyx + n * M_2PI / floor(m_Power);
T sina = sin(alpha); T sina = sin(alpha);
T cosa = cos(alpha); T cosa = cos(alpha);
@ -299,9 +297,9 @@ public:
string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index; string dist = "parVars[" + ToUpper(m_Params[i++].Name()) + index;
ss << "\t{\n" ss << "\t{\n"
<< "\t\treal_t r = pow(precalcSqrtSumSquares, " << dist << ");\n" << "\t\treal_t r = Zeps(pow(precalcSqrtSumSquares, " << dist << "));\n"
<< "\t\tint n = floor(" << power << " * MwcNext01(mwc));\n" << "\t\tint n = floor(" << power << " * MwcNext01(mwc));\n"
<< "\t\treal_t alpha = precalcAtanyx + n * M_2PI / floor(" << power << ");\n" << "\t\treal_t alpha = precalcAtanyx + n * M_2PI / Zeps(floor(" << power << "));\n"
<< "\t\treal_t sina = sin(alpha);\n" << "\t\treal_t sina = sin(alpha);\n"
<< "\t\treal_t cosa = cos(alpha);\n" << "\t\treal_t cosa = cos(alpha);\n"
<< "\n" << "\n"

View File

@ -23,7 +23,7 @@ public:
void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand) void Func(IteratorHelper<T>& helper, Point<T>& outPoint, QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand)
{ {
T r = helper.m_PrecalcSumSquares; T r = helper.m_PrecalcSumSquares;
T r4_1 = r / 4 + 1; T r4_1 = Zeps(r / 4 + 1);
r4_1 = m_Weight / r4_1; r4_1 = m_Weight / r4_1;
helper.Out.x = r4_1 * helper.In.x; helper.Out.x = r4_1 * helper.In.x;
@ -49,7 +49,7 @@ public:
ss << "\t{\n" ss << "\t{\n"
<< "\t\treal_t r = precalcSumSquares;\n" << "\t\treal_t r = precalcSumSquares;\n"
<< "\t\treal_t r4_1 = r / 4 + 1;\n" << "\t\treal_t r4_1 = Zeps(r / 4 + 1);\n"
<< "\t\tr4_1 = xform->m_VariationWeights[" << varIndex << "] / r4_1;\n" << "\t\tr4_1 = xform->m_VariationWeights[" << varIndex << "] / r4_1;\n"
<< "\n" << "\n"
<< "\t\tvOut.x = r4_1 * vIn.x;\n" << "\t\tvOut.x = r4_1 * vIn.x;\n"

View File

@ -172,9 +172,12 @@ public:
{ {
Variation<T>* var = NULL; Variation<T>* var = NULL;
xform.GetVariation(i)->Copy(var);//Will convert from type U to type T. if (Variation<U>* varOrig = xform.GetVariation(i))
{
varOrig->Copy(var);//Will convert from type U to type T.
AddVariation(var);//Will internally call SetPrecalcFlags(). AddVariation(var);//Will internally call SetPrecalcFlags().
} }
}
if (TotalVariationCount() == 0) if (TotalVariationCount() == 0)
SetPrecalcFlags(); SetPrecalcFlags();

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,0 FILEVERSION 0,4,1,1
PRODUCTVERSION 0,4,1,0 PRODUCTVERSION 0,4,1,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as animations with motion blur" VALUE "FileDescription", "Renders fractal flames as animations with motion blur"
VALUE "FileVersion", "0.4.1.0" VALUE "FileVersion", "0.4.1.1"
VALUE "InternalName", "EmberAnimate.rc" VALUE "InternalName", "EmberAnimate.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberAnimate.rc" VALUE "OriginalFilename", "EmberAnimate.rc"
VALUE "ProductName", "Ember Animate" VALUE "ProductName", "Ember Animate"
VALUE "ProductVersion", "0.4.1.0" VALUE "ProductVersion", "0.4.1.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -49,7 +49,7 @@ RendererCL<T>::RendererCL(unsigned int platform, unsigned int device, bool share
m_PaletteFormat.image_channel_order = CL_RGBA; m_PaletteFormat.image_channel_order = CL_RGBA;
m_PaletteFormat.image_channel_data_type = CL_FLOAT; m_PaletteFormat.image_channel_data_type = CL_FLOAT;
m_FinalFormat.image_channel_order = CL_RGBA; m_FinalFormat.image_channel_order = CL_RGBA;
m_FinalFormat.image_channel_data_type = CL_UNORM_INT8;//Change if this ever supports 2BPP outputs for PNG. m_FinalFormat.image_channel_data_type = CL_UNORM_INT8;//Change if this ever supports 2BPC outputs for PNG.
Init(platform, device, shared, outputTexID);//Init OpenCL upon construction and create programs that will not change. Init(platform, device, shared, outputTexID);//Init OpenCL upon construction and create programs that will not change.
} }

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,0 FILEVERSION 0,4,1,1
PRODUCTVERSION 0,4,1,0 PRODUCTVERSION 0,4,1,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Manipulates fractal flames parameter files" VALUE "FileDescription", "Manipulates fractal flames parameter files"
VALUE "FileVersion", "0.4.1.0" VALUE "FileVersion", "0.4.1.1"
VALUE "InternalName", "EmberGenome.rc" VALUE "InternalName", "EmberGenome.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberGenome.rc" VALUE "OriginalFilename", "EmberGenome.rc"
VALUE "ProductName", "Ember Genome" VALUE "ProductName", "Ember Genome"
VALUE "ProductVersion", "0.4.1.0" VALUE "ProductVersion", "0.4.1.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -49,8 +49,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,4,1,0 FILEVERSION 0,4,1,1
PRODUCTVERSION 0,4,1,0 PRODUCTVERSION 0,4,1,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -67,12 +67,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Open Source" VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as single images" VALUE "FileDescription", "Renders fractal flames as single images"
VALUE "FileVersion", "0.4.1.0" VALUE "FileVersion", "0.4.1.1"
VALUE "InternalName", "EmberRender.rc" VALUE "InternalName", "EmberRender.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3" VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberRender.rc" VALUE "OriginalFilename", "EmberRender.rc"
VALUE "ProductName", "Ember Render" VALUE "ProductName", "Ember Render"
VALUE "ProductVersion", "0.4.1.0" VALUE "ProductVersion", "0.4.1.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -1074,6 +1074,28 @@ bool TestVarAssignVals()
return success; return success;
} }
bool TestZepsFloor()
{
bool success = true;
VariationList<float> vlf;
vector<string> zeps;
zeps.push_back("Zeps(floor");
for (size_t i = 0; i < vlf.Size(); i++)
{
Variation<float>* var = vlf.GetVariation(i);
if (SearchVar(var, zeps, false))
{
cout << "Variation " << var->Name() << " contains Zeps(floor()). This is fine for the GPU, but ensure the CPU uses Zeps<T>((T)Floor<T>())." << endl;
success = false;
}
}
return success;
}
bool TestConstants() bool TestConstants()
{ {
bool success = true; bool success = true;
@ -1864,6 +1886,10 @@ int _tmain(int argc, _TCHAR* argv[])
TestVarAssignVals(); TestVarAssignVals();
t.Toc("TestVarAssignVals()"); t.Toc("TestVarAssignVals()");
t.Tic();
TestZepsFloor();
t.Toc("TestZepsFloor()");
t.Tic(); t.Tic();
TestConstants(); TestConstants();
t.Toc("TestConstants()"); t.Toc("TestConstants()");

View File

@ -52,7 +52,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Fractorium 0.4.1.0 Beta&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Matt Feemster&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Fractorium 0.4.1.1 Beta&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Matt Feemster&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="textFormat"> <property name="textFormat">
<enum>Qt::RichText</enum> <enum>Qt::RichText</enum>

View File

@ -83,16 +83,16 @@ template<typename T>
FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderDialog* finalRender) FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderDialog* finalRender)
: FinalRenderEmberControllerBase(finalRender) : FinalRenderEmberControllerBase(finalRender)
{ {
m_PreviewRenderer = auto_ptr<EmberNs::Renderer<T, T>>(new EmberNs::Renderer<T, T>()); m_FinalPreviewRenderer = auto_ptr<EmberNs::Renderer<T, T>>(new EmberNs::Renderer<T, T>());
m_PreviewRenderer->Callback(NULL); m_FinalPreviewRenderer->Callback(NULL);
m_PreviewRenderer->NumChannels(4); m_FinalPreviewRenderer->NumChannels(4);
m_PreviewRenderer->ReclaimOnResize(true); m_FinalPreviewRenderer->ReclaimOnResize(true);
m_PreviewRenderFunc = [&]() m_FinalPreviewRenderFunc = [&]()
{ {
m_PreviewCs.Enter();//Thread prep. m_PreviewCs.Enter();//Thread prep.
m_PreviewRun = true; m_PreviewRun = true;
m_PreviewRenderer->Abort(); m_FinalPreviewRenderer->Abort();
QLabel* widget = m_FinalRender->ui.FinalRenderPreviewLabel; QLabel* widget = m_FinalRender->ui.FinalRenderPreviewLabel;
unsigned int maxDim = 100u; unsigned int maxDim = 100u;
@ -106,21 +106,20 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_PreviewEmber = m_Ember; m_PreviewEmber = m_Ember;
m_PreviewEmber.m_Quality = 100; m_PreviewEmber.m_Quality = 100;
m_PreviewEmber.m_Supersample = 1;
m_PreviewEmber.m_TemporalSamples = 1; m_PreviewEmber.m_TemporalSamples = 1;
m_PreviewEmber.m_FinalRasW = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasW)); m_PreviewEmber.m_FinalRasW = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasW));
m_PreviewEmber.m_FinalRasH = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasH)); m_PreviewEmber.m_FinalRasH = min(maxDim, unsigned int(scalePercentage * m_Ember.m_FinalRasH));
m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember.m_PixelsPerUnit; m_PreviewEmber.m_PixelsPerUnit = scalePercentage * m_Ember.m_PixelsPerUnit;
while (!m_PreviewRenderer->Aborted() || m_PreviewRenderer->InRender()) while (!m_FinalPreviewRenderer->Aborted() || m_FinalPreviewRenderer->InRender())
QApplication::processEvents(); QApplication::processEvents();
m_PreviewRenderer->EarlyClip(m_FinalRender->EarlyClip()); m_FinalPreviewRenderer->EarlyClip(m_FinalRender->EarlyClip());
m_PreviewRenderer->YAxisUp(m_FinalRender->YAxisUp()); m_FinalPreviewRenderer->YAxisUp(m_FinalRender->YAxisUp());
m_PreviewRenderer->Transparency(m_FinalRender->Transparency()); m_FinalPreviewRenderer->Transparency(m_FinalRender->Transparency());
m_PreviewRenderer->SetEmber(m_PreviewEmber); m_FinalPreviewRenderer->SetEmber(m_PreviewEmber);
if (m_PreviewRenderer->Run(m_PreviewFinalImage) == RENDER_OK) if (m_FinalPreviewRenderer->Run(m_PreviewFinalImage) == RENDER_OK)
{ {
QImage image(m_PreviewEmber.m_FinalRasW, m_PreviewEmber.m_FinalRasH, QImage::Format_RGBA8888);//The label wants RGBA. QImage image(m_PreviewEmber.m_FinalRasW, m_PreviewEmber.m_FinalRasH, QImage::Format_RGBA8888);//The label wants RGBA.
memcpy(image.scanLine(0), m_PreviewFinalImage.data(), m_PreviewFinalImage.size() * sizeof(m_PreviewFinalImage[0]));//Memcpy the data in. memcpy(image.scanLine(0), m_PreviewFinalImage.data(), m_PreviewFinalImage.size() * sizeof(m_PreviewFinalImage[0]));//Memcpy the data in.
@ -135,7 +134,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
//The main rendering function which will be called in a Qt thread. //The main rendering function which will be called in a Qt thread.
//A backup Xml is made before the rendering process starts just in case it crashes before finishing. //A backup Xml is made before the rendering process starts just in case it crashes before finishing.
//If it finishes successfully, delete the backup file. //If it finishes successfully, delete the backup file.
m_RenderFunc = [&]() m_FinalRenderFunc = [&]()
{ {
size_t i; size_t i;
@ -243,6 +242,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_Ember.m_TemporalSamples = 1; m_Ember.m_TemporalSamples = 1;
m_Renderer->SetEmber(m_Ember); m_Renderer->SetEmber(m_Ember);
m_PureIterTime = 0; m_PureIterTime = 0;
memset(m_FinalImage.data(), 0, m_FinalImage.size() * sizeof(m_FinalImage[0]));
m_RenderTimer.Tic();//Toc() is called in the progress function. m_RenderTimer.Tic();//Toc() is called in the progress function.
if (m_Renderer->Run(m_FinalImage) != RENDER_OK) if (m_Renderer->Run(m_FinalImage) != RENDER_OK)
@ -266,6 +266,7 @@ template <typename T> void FinalRenderEmberController<T>::SetEmber(const Ember<f
template <typename T> void FinalRenderEmberController<T>::CopyEmber(Ember<float>& ember) { ember = m_Ember; } template <typename T> void FinalRenderEmberController<T>::CopyEmber(Ember<float>& ember) { ember = m_Ember; }
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile) { m_EmberFile = emberFile; } template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile) { emberFile = m_EmberFile; } template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile) { emberFile = m_EmberFile; }
template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<float>& ember) { m_OriginalEmber = ember; }
template <typename T> double FinalRenderEmberController<T>::OriginalAspect() { return double(m_OriginalEmber.m_OrigFinalRasW) / m_OriginalEmber.m_OrigFinalRasH; } template <typename T> double FinalRenderEmberController<T>::OriginalAspect() { return double(m_OriginalEmber.m_OrigFinalRasW) / m_OriginalEmber.m_OrigFinalRasH; }
#ifdef DO_DOUBLE #ifdef DO_DOUBLE
template <typename T> void FinalRenderEmberController<T>::SetEmber(const Ember<double>& ember, bool verbatim) { m_Ember = ember; } template <typename T> void FinalRenderEmberController<T>::SetEmber(const Ember<double>& ember, bool verbatim) { m_Ember = ember; }
@ -273,8 +274,6 @@ template <typename T> void FinalRenderEmberController<T>::CopyEmber(Ember<double
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile) { m_EmberFile = emberFile; } template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile) { m_EmberFile = emberFile; }
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile) { emberFile = m_EmberFile; } template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile) { emberFile = m_EmberFile; }
template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<double>& ember) { m_OriginalEmber = ember; } template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<double>& ember) { m_OriginalEmber = ember; }
#else
template <typename T> void FinalRenderEmberController<T>::SetOriginalEmber(Ember<float>& ember) { m_OriginalEmber = ember; }
#endif #endif
/// <summary> /// <summary>
@ -313,7 +312,7 @@ int FinalRenderEmberController<T>::ProgressFunc(Ember<T>& ember, void* foo, doub
QFileInfo original(filename); QFileInfo original(filename);
EmberStats stats = m_Renderer->Stats(); EmberStats stats = m_Renderer->Stats();
QString iters = QLocale(QLocale::English).toString(stats.m_Iters); QString iters = QLocale(QLocale::English).toString(stats.m_Iters);
QString itersPerSec = QLocale(QLocale::English).toString(int(stats.m_Iters / (m_PureIterTime / 1000.0))); QString itersPerSec = QLocale(QLocale::English).toString(unsigned __int64(stats.m_Iters / (m_PureIterTime / 1000.0)));
if (m_GuiState.m_DoAll && m_EmberFile.m_Embers.size() > 1) if (m_GuiState.m_DoAll && m_EmberFile.m_Embers.size() > 1)
filename = original.absolutePath() + QDir::separator() + m_GuiState.m_Prefix + QString::fromStdString(m_EmberFile.m_Embers[m_FinishedImageCount].m_Name) + m_GuiState.m_Suffix + "." + m_GuiState.m_DoAllExt; filename = original.absolutePath() + QDir::separator() + m_GuiState.m_Prefix + QString::fromStdString(m_EmberFile.m_Embers[m_FinishedImageCount].m_Name) + m_GuiState.m_Suffix + "." + m_GuiState.m_DoAllExt;
@ -409,7 +408,7 @@ bool FinalRenderEmberController<T>::Render()
//parallel iteration loops inside of the CPU renderer to finish. The result is that //parallel iteration loops inside of the CPU renderer to finish. The result is that
//the renderer ends up using ThreadCount - 1 to iterate, instead of ThreadCount. //the renderer ends up using ThreadCount - 1 to iterate, instead of ThreadCount.
//By using a Qt thread here, and tbb inside the renderer, all cores can be maxed out. //By using a Qt thread here, and tbb inside the renderer, all cores can be maxed out.
m_Result = QtConcurrent::run(m_RenderFunc); m_Result = QtConcurrent::run(m_FinalRenderFunc);
m_Settings->sync(); m_Settings->sync();
return true; return true;
} }
@ -469,7 +468,7 @@ bool FinalRenderEmberController<T>::CreateRenderer(eRendererType renderType, uns
m_Renderer->Callback(this); m_Renderer->Callback(this);
m_Renderer->NumChannels(channels); m_Renderer->NumChannels(channels);
m_Renderer->ReclaimOnResize(false); m_Renderer->ReclaimOnResize(true);
m_Renderer->EarlyClip(m_FinalRender->EarlyClip()); m_Renderer->EarlyClip(m_FinalRender->EarlyClip());
m_Renderer->YAxisUp(m_FinalRender->YAxisUp()); m_Renderer->YAxisUp(m_FinalRender->YAxisUp());
m_Renderer->ThreadCount(m_FinalRender->ThreadCount()); m_Renderer->ThreadCount(m_FinalRender->ThreadCount());
@ -506,9 +505,9 @@ unsigned __int64 FinalRenderEmberController<T>::SyncAndComputeMemory()
m_Renderer->NumChannels(channels); m_Renderer->NumChannels(channels);
m_Renderer->ComputeBounds(); m_Renderer->ComputeBounds();
CancelPreviewRender(); CancelPreviewRender();
//m_PreviewResult = QtConcurrent::run(m_PreviewRenderFunc); //m_FinalPreviewResult = QtConcurrent::run(m_PreviewRenderFunc);
//while (!m_PreviewResult.isRunning()) { QApplication::processEvents(); }//Wait for it to start up. //while (!m_FinalPreviewResult.isRunning()) { QApplication::processEvents(); }//Wait for it to start up.
m_PreviewRenderFunc(); m_FinalPreviewRenderFunc();
return m_Renderer->MemoryRequired(true); return m_Renderer->MemoryRequired(true);
} }
@ -536,11 +535,11 @@ void FinalRenderEmberController<T>::ResetProgress(bool total)
template <typename T> template <typename T>
void FinalRenderEmberController<T>::CancelPreviewRender() void FinalRenderEmberController<T>::CancelPreviewRender()
{ {
m_PreviewRenderer->Abort(); m_FinalPreviewRenderer->Abort();
while (m_PreviewRenderer->InRender()) { QApplication::processEvents(); } while (m_FinalPreviewRenderer->InRender()) { QApplication::processEvents(); }
while (m_PreviewRun) { QApplication::processEvents(); } while (m_PreviewRun) { QApplication::processEvents(); }
while (m_PreviewResult.isRunning()) { QApplication::processEvents(); } while (m_FinalPreviewResult.isRunning()) { QApplication::processEvents(); }
} }
/// <summary> /// <summary>

View File

@ -61,10 +61,9 @@ public:
virtual unsigned __int64 SyncAndComputeMemory() { return 0; } virtual unsigned __int64 SyncAndComputeMemory() { return 0; }
virtual QString Name() const { return ""; } virtual QString Name() const { return ""; }
virtual void ResetProgress(bool total = true) { } virtual void ResetProgress(bool total = true) { }
virtual void SetOriginalEmber(Ember<float>& ember) { }
#ifdef DO_DOUBLE #ifdef DO_DOUBLE
virtual void SetOriginalEmber(Ember<double>& ember) { } virtual void SetOriginalEmber(Ember<double>& ember) { }
#else
virtual void SetOriginalEmber(Ember<float>& ember) { }
#endif #endif
virtual double OriginalAspect() { return 1; } virtual double OriginalAspect() { return 1; }
@ -79,10 +78,9 @@ protected:
double m_PureIterTime; double m_PureIterTime;
QFuture<void> m_Result; QFuture<void> m_Result;
QFuture<void> m_PreviewResult; QFuture<void> m_FinalPreviewResult;
std::function<void (void)> m_RenderFunc; std::function<void (void)> m_FinalRenderFunc;
std::function<void (void)> m_PreviewRenderFunc; std::function<void (void)> m_FinalPreviewRenderFunc;
vector<unsigned char> m_PreviewFinalImage;
FractoriumSettings* m_Settings; FractoriumSettings* m_Settings;
FractoriumFinalRenderDialog* m_FinalRender; FractoriumFinalRenderDialog* m_FinalRender;
@ -108,14 +106,13 @@ public:
virtual void CopyEmber(Ember<float>& ember); virtual void CopyEmber(Ember<float>& ember);
virtual void SetEmberFile(const EmberFile<float>& emberFile); virtual void SetEmberFile(const EmberFile<float>& emberFile);
virtual void CopyEmberFile(EmberFile<float>& emberFile); virtual void CopyEmberFile(EmberFile<float>& emberFile);
virtual void SetOriginalEmber(Ember<float>& ember);
#ifdef DO_DOUBLE #ifdef DO_DOUBLE
virtual void SetEmber(const Ember<double>& ember, bool verbatim = false); virtual void SetEmber(const Ember<double>& ember, bool verbatim = false);
virtual void CopyEmber(Ember<double>& ember); virtual void CopyEmber(Ember<double>& ember);
virtual void SetEmberFile(const EmberFile<double>& emberFile); virtual void SetEmberFile(const EmberFile<double>& emberFile);
virtual void CopyEmberFile(EmberFile<double>& emberFile); virtual void CopyEmberFile(EmberFile<double>& emberFile);
virtual void SetOriginalEmber(Ember<double>& ember); virtual void SetOriginalEmber(Ember<double>& ember);
#else
virtual void SetOriginalEmber(Ember<float>& ember);
#endif #endif
virtual double OriginalAspect(); virtual double OriginalAspect();
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs); virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs);
@ -135,7 +132,7 @@ protected:
Ember<T> m_PreviewEmber; Ember<T> m_PreviewEmber;
EmberFile<T> m_EmberFile; EmberFile<T> m_EmberFile;
EmberToXml<T> m_XmlWriter; EmberToXml<T> m_XmlWriter;
auto_ptr<EmberNs::Renderer<T, T>> m_PreviewRenderer; auto_ptr<EmberNs::Renderer<T, T>> m_FinalPreviewRenderer;
}; };
template class FinalRenderEmberController<float>; template class FinalRenderEmberController<float>;

Binary file not shown.