diff --git a/Builds/MSVC/VS2013/Ember.vcxproj b/Builds/MSVC/VS2013/Ember.vcxproj index d841392..51e8293 100644 --- a/Builds/MSVC/VS2013/Ember.vcxproj +++ b/Builds/MSVC/VS2013/Ember.vcxproj @@ -64,8 +64,7 @@ Default EmberPch.h Precise - /bigobj - %(AdditionalOptions) + /bigobj %(AdditionalOptions) true false true @@ -93,8 +92,7 @@ Speed EmberPch.h true - /bigobj - %(AdditionalOptions) + /bigobj %(AdditionalOptions) Precise true false diff --git a/Data/dark.qss b/Data/dark.qss index b215a6b..39bc746 100644 --- a/Data/dark.qss +++ b/Data/dark.qss @@ -553,12 +553,17 @@ QTableWidget#XformWeightNameTable border-left: 1px solid gray; } -QTableWidget#SummaryTable, -QTableWidget#PaletteListTable +QTableWidget#SummaryTable { border-left: 1px solid gray; } +/*Normally doesn't matter, but when a palette file doesn't have enough palettes in it to fill the whole table, it looks funny without a border*/ +QTableWidget#PaletteListTable +{ + border: 1px solid gray; +} + QTableWidget#SummaryTable QHeaderView::section::vertical { background-color: darkgray; diff --git a/Source/Ember/DensityFilter.h b/Source/Ember/DensityFilter.h index a22cf73..042a1ad 100644 --- a/Source/Ember/DensityFilter.h +++ b/Source/Ember/DensityFilter.h @@ -319,8 +319,8 @@ public: virtual intmax_t FilterWidth() const override { return m_FilterWidth; } inline size_t BufferSize() const { return m_Widths.size(); } inline size_t CoefsSizeBytes() const { return BufferSize() * m_KernelSize * sizeof(T); } - inline size_t WidthsSizeBytes() const { return BufferSize() * sizeof(T); } - inline size_t CoefsIndicesSizeBytes() const { return (m_CoefIndices.size() * sizeof(m_CoefIndices[0])); } + inline size_t WidthsSizeBytes() const { return SizeOf(m_Widths); } + inline size_t CoefsIndicesSizeBytes() const { return SizeOf(m_CoefIndices); } inline const T* Coefs() const { return m_Coefs.data(); } inline const T* Widths() const { return m_Widths.data(); } inline const uint* CoefIndices() const { return m_CoefIndices.data(); } diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index 2a8a6de..9643b21 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -1524,8 +1524,8 @@ public: /// /// Accessors. /// - inline const Xform* Xforms() const { return &m_Xforms[0]; } - inline Xform* NonConstXforms() { return &m_Xforms[0]; } + inline const Xform* Xforms() const { return m_Xforms.data(); } + inline Xform* NonConstXforms() { return m_Xforms.data(); } inline size_t XformCount() const { return m_Xforms.size(); } inline const Xform* FinalXform() const { return &m_FinalXform; } inline Xform* NonConstFinalXform() { return &m_FinalXform; } diff --git a/Source/Ember/Iterator.h b/Source/Ember/Iterator.h index 83d6809..b6a2cc0 100644 --- a/Source/Ember/Iterator.h +++ b/Source/Ember/Iterator.h @@ -68,7 +68,7 @@ public: /// /// Accessors. /// - const byte* XformDistributions() const { return m_XformDistributions.empty() ? nullptr : &m_XformDistributions[0]; } + const byte* XformDistributions() const { return m_XformDistributions.empty() ? nullptr : m_XformDistributions.data(); } size_t XformDistributionsSize() const { return m_XformDistributions.size(); } /// @@ -308,9 +308,9 @@ public: Point tempPoint, p1; auto xforms = ember.NonConstXforms(); - if (ember.ProjBits()) + if (ember.ProjBits())//No xaos, 3D. { - if (ember.UseFinalXform()) + if (ember.UseFinalXform())//No xaos, 3D, final. { p1 = samples[0]; @@ -332,7 +332,7 @@ public: ember.Proj(samples[i], rand); } } - else + else//No xaos, 3D, no final. { p1 = samples[0]; @@ -355,9 +355,9 @@ public: } } } - else + else//No xaos, no 3D. { - if (ember.UseFinalXform()) + if (ember.UseFinalXform())//No xaos, no 3D, final. { p1 = samples[0]; @@ -377,7 +377,7 @@ public: DoFinalXform(ember, p1, samples + i, rand); } } - else + else//No xaos, no 3D, no final. { p1 = samples[0]; @@ -475,9 +475,9 @@ public: Point tempPoint, p1; auto xforms = ember.NonConstXforms(); - if (ember.ProjBits()) + if (ember.ProjBits())//Xaos, 3D. { - if (ember.UseFinalXform()) + if (ember.UseFinalXform())//Xaos, 3D, final. { p1 = samples[0]; @@ -506,7 +506,7 @@ public: lastXformUsed = xformIndex + 1;//Store the last used transform. } } - else + else//Xaos, 3D, no final. { p1 = samples[0]; @@ -536,9 +536,9 @@ public: } } } - else + else//Xaos, no 3D. { - if (ember.UseFinalXform()) + if (ember.UseFinalXform())//Xaos, no 3D, final. { p1 = samples[0]; @@ -565,7 +565,7 @@ public: lastXformUsed = xformIndex + 1;//Store the last used transform. } } - else + else//Xaos, no 3D, no final. { p1 = samples[0]; diff --git a/Source/Ember/Palette.h b/Source/Ember/Palette.h index 8346213..6bab110 100644 --- a/Source/Ember/Palette.h +++ b/Source/Ember/Palette.h @@ -47,44 +47,47 @@ public: if (xmlPaletteEntries) { - memcpy(&m_Entries[0], xmlPaletteEntries, Size() * sizeof(m_Entries[0])); + memcpy(m_Entries.data(), xmlPaletteEntries, SizeOf(m_Entries)); + //memcpy(&m_Entries[0], xmlPaletteEntries, Size() * sizeof(m_Entries[0])); } else//They passed in null, so just fill with hard coded values so they at least have something. { //Palette 15 used in the test ember file. - byte palette15[COLORMAP_LENGTH * 4] = { -0x00, 0xda, 0xde, 0xbc, 0x00, 0xee, 0xe6, 0xc5, 0x00, 0xee, 0xf2, 0xce, 0x00, 0xee, 0xf2, 0xcf, 0x00, 0xe6, 0xee, 0xe1, 0x00, 0xea, 0xee, 0xd8, 0x00, 0xf2, 0xf1, 0xeb, 0x00, 0xf2, 0xf5, 0xd8, -0x00, 0xe6, 0xf2, 0xce, 0x00, 0xde, 0xea, 0xc5, 0x00, 0xd6, 0xda, 0xc6, 0x00, 0xce, 0xd2, 0xbc, 0x00, 0xc2, 0xca, 0xa9, 0x00, 0xbe, 0xca, 0xa0, 0x00, 0xce, 0xd6, 0xaa, 0x00, 0xde, 0xe2, 0xc5, -0x00, 0xea, 0xed, 0xce, 0x00, 0xea, 0xf2, 0xc5, 0x00, 0xde, 0xe2, 0xc5, 0x00, 0xc2, 0xca, 0xaa, 0x00, 0xae, 0xbe, 0xaa, 0x00, 0xa5, 0xb2, 0x96, 0x00, 0xa2, 0xa9, 0x8d, 0x00, 0x96, 0xa2, 0x84, -0x00, 0x8d, 0x8d, 0x7a, 0x00, 0x85, 0x89, 0x71, 0x00, 0x85, 0x8d, 0x71, 0x00, 0x85, 0x85, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, 0x00, 0x65, 0x6d, 0x55, -0x00, 0x4d, 0x5d, 0x42, 0x00, 0x34, 0x40, 0x25, 0x00, 0x30, 0x40, 0x25, 0x00, 0x30, 0x38, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x2c, 0x34, 0x1c, 0x00, 0x24, 0x2c, 0x12, 0x00, 0x24, 0x24, 0x00, -0x00, 0x24, 0x2c, 0x09, 0x00, 0x28, 0x34, 0x09, 0x00, 0x38, 0x40, 0x12, 0x00, 0x30, 0x40, 0x1c, 0x00, 0x40, 0x50, 0x2f, 0x00, 0x55, 0x69, 0x42, 0x00, 0x65, 0x75, 0x55, 0x00, 0x6c, 0x7d, 0x5e, -0x00, 0x74, 0x8d, 0x71, 0x00, 0x74, 0x89, 0x84, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x78, 0x8d, 0x84, 0x00, 0x79, 0x89, 0x7a, 0x00, 0x79, 0x85, 0x71, 0x00, 0x75, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, -0x00, 0x6c, 0x71, 0x5e, 0x00, 0x6d, 0x70, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x69, 0x71, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x71, 0x55, -0x00, 0x65, 0x71, 0x55, 0x00, 0x69, 0x6d, 0x55, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x6c, 0x67, 0x00, 0x6c, 0x6c, 0x5e, 0x00, 0x71, 0x71, 0x5e, -0x00, 0x79, 0x79, 0x67, 0x00, 0x81, 0x85, 0x71, 0x00, 0x7d, 0x91, 0x71, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x79, 0x92, 0x84, 0x00, 0x78, 0x92, 0x8d, -0x00, 0x78, 0x8d, 0x8d, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x74, 0x92, 0x84, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x6c, 0x85, 0x67, 0x00, 0x64, 0x79, 0x5e, 0x00, 0x59, 0x69, 0x4b, 0x00, 0xaa, 0x57, 0x00, -0x00, 0x38, 0x44, 0x1c, 0x00, 0x30, 0x3c, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x34, 0x40, 0x25, 0x00, 0x50, 0x61, 0x4b, 0x00, 0x5d, 0x6d, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x60, 0x71, 0x5e, -0x00, 0x60, 0x75, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x71, 0x79, 0x67, 0x00, 0x70, 0x79, 0x67, 0x00, 0x6c, 0x7d, 0x67, 0x00, 0x68, 0x79, 0x67, -0x00, 0x6c, 0x79, 0x67, 0x00, 0x6c, 0x75, 0x67, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x75, 0x79, 0x5e, 0x00, 0x75, 0x7d, 0x5e, 0x00, 0x81, 0x8d, 0x5e, 0x00, 0x8d, 0x92, 0x5e, -0x00, 0x8d, 0x92, 0x67, 0x00, 0x9a, 0x9a, 0x71, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa1, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x92, 0x67, 0x00, 0x81, 0x85, 0x5e, -0x00, 0x7d, 0x7d, 0x55, 0x00, 0x69, 0x79, 0x4b, 0x00, 0x61, 0x6d, 0x42, 0x00, 0x44, 0x4c, 0x25, 0x00, 0x38, 0x44, 0x1c, 0x00, 0x40, 0x51, 0x25, 0x00, 0x45, 0x4d, 0x25, 0x00, 0x71, 0x6d, 0x42, -0x00, 0x79, 0x7d, 0x4b, 0x00, 0x81, 0x7d, 0x55, 0x00, 0x79, 0x79, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x7d, 0x55, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x65, 0x79, 0x54, 0x00, 0x68, 0x79, 0x5e, -0x00, 0x64, 0x79, 0x67, 0x00, 0x64, 0x79, 0x67, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x64, 0x6c, 0x5e, 0x00, 0x65, 0x6d, 0x55, 0x00, 0x4d, 0x58, 0x42, 0x00, 0x34, 0x40, 0x25, -0x00, 0x2c, 0x38, 0x1c, 0x00, 0x20, 0x28, 0x1c, 0x00, 0x1c, 0x14, 0x09, 0x00, 0x18, 0x18, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x0c, 0x18, 0x00, 0x00, 0x1c, 0x28, 0x09, -0x00, 0x24, 0x30, 0x12, 0x00, 0x3c, 0x44, 0x25, 0x00, 0x5d, 0x65, 0x55, 0x00, 0x75, 0x79, 0x55, 0x00, 0x85, 0x89, 0x5e, 0x00, 0x89, 0x91, 0x71, 0x00, 0x96, 0xa2, 0x71, 0x00, 0x9a, 0xa2, 0x7a, -0x00, 0x9e, 0xaa, 0x7a, 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xae, 0x71, 0x00, 0xa6, 0xaa, 0x7a, 0x00, 0xa2, 0xaa, 0x7a, 0x00, 0xa1, 0xa5, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x85, 0x96, 0x7a, -0x00, 0x81, 0x92, 0x7a, 0x00, 0x78, 0x92, 0x7a, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x75, 0x8d, 0x7a, 0x00, 0x70, 0x81, 0x67, 0x00, 0x7d, 0x7d, 0x67, 0x00, 0x89, 0x89, 0x67, 0x00, 0x92, 0x9a, 0x71, -0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xb6, 0x84, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xb6, 0xba, 0x97, 0x00, 0xc2, 0xca, 0x97, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xaa, 0xb2, 0x8d, -0x00, 0xa2, 0xae, 0x84, 0x00, 0x9a, 0xa6, 0x7a, 0x00, 0x92, 0x9e, 0x7a, 0x00, 0x85, 0x9a, 0x7a, 0x00, 0x7d, 0x96, 0x7a, 0x00, 0x7d, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x84, -0x00, 0x81, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x8d, 0x9a, 0x84, 0x00, 0x92, 0x96, 0x84, -0x00, 0x9e, 0xa9, 0x84, 0x00, 0xae, 0xb2, 0x84, 0x00, 0xaa, 0xba, 0x84, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb6, 0xc2, 0xa0, 0x00, 0xc6, 0xca, 0xa0, 0x00, 0xc6, 0xce, 0xaa, 0x00, 0xd6, 0xda, 0xb3, -0x00, 0xda, 0xe2, 0xc5, 0x00, 0xd2, 0xd6, 0xbc, 0x00, 0xbe, 0xc2, 0xa0, 0x00, 0xaa, 0xb6, 0x8d, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x89, 0x71, 0x00, 0x81, 0x7d, 0x67, -0x00, 0x7d, 0x7d, 0x67, 0x00, 0x81, 0x78, 0x67, 0x00, 0x7d, 0x7d, 0x5e, 0x00, 0x79, 0x79, 0x5e, 0x00, 0x79, 0x81, 0x5e, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x81, 0x67, -0x00, 0x81, 0x89, 0x71, 0x00, 0x85, 0x91, 0x7a, 0x00, 0x89, 0x92, 0x7a, 0x00, 0x96, 0x9d, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x92, 0x96, 0x84, 0x00, 0x96, 0x9a, 0x8d, 0x00, 0x92, 0x92, 0x84, -0x00, 0x89, 0x91, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x74, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x78, 0x96, 0x97, 0x00, 0x81, 0x96, 0x8d, -0x00, 0x81, 0x96, 0x8d, 0x00, 0x81, 0x9a, 0x8d, 0x00, 0x85, 0x9a, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x8d, 0xa2, 0x97, 0x00, 0x95, 0xa2, 0x97, 0x00, 0x8d, 0xa2, 0x97, -0x00, 0x96, 0xa6, 0x8d, 0x00, 0x9a, 0xa1, 0x8d, 0x00, 0x9e, 0xa9, 0x84, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0xa2, 0xa5, 0x71, 0x00, 0x9e, 0xa6, 0x71, 0x00, 0x9a, 0xa6, 0x71, 0x00, 0x95, 0x9d, 0x71 }; + byte palette15[COLORMAP_LENGTH * 4] = + { + 0x00, 0xda, 0xde, 0xbc, 0x00, 0xee, 0xe6, 0xc5, 0x00, 0xee, 0xf2, 0xce, 0x00, 0xee, 0xf2, 0xcf, 0x00, 0xe6, 0xee, 0xe1, 0x00, 0xea, 0xee, 0xd8, 0x00, 0xf2, 0xf1, 0xeb, 0x00, 0xf2, 0xf5, 0xd8, + 0x00, 0xe6, 0xf2, 0xce, 0x00, 0xde, 0xea, 0xc5, 0x00, 0xd6, 0xda, 0xc6, 0x00, 0xce, 0xd2, 0xbc, 0x00, 0xc2, 0xca, 0xa9, 0x00, 0xbe, 0xca, 0xa0, 0x00, 0xce, 0xd6, 0xaa, 0x00, 0xde, 0xe2, 0xc5, + 0x00, 0xea, 0xed, 0xce, 0x00, 0xea, 0xf2, 0xc5, 0x00, 0xde, 0xe2, 0xc5, 0x00, 0xc2, 0xca, 0xaa, 0x00, 0xae, 0xbe, 0xaa, 0x00, 0xa5, 0xb2, 0x96, 0x00, 0xa2, 0xa9, 0x8d, 0x00, 0x96, 0xa2, 0x84, + 0x00, 0x8d, 0x8d, 0x7a, 0x00, 0x85, 0x89, 0x71, 0x00, 0x85, 0x8d, 0x71, 0x00, 0x85, 0x85, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, 0x00, 0x65, 0x6d, 0x55, + 0x00, 0x4d, 0x5d, 0x42, 0x00, 0x34, 0x40, 0x25, 0x00, 0x30, 0x40, 0x25, 0x00, 0x30, 0x38, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x2c, 0x34, 0x1c, 0x00, 0x24, 0x2c, 0x12, 0x00, 0x24, 0x24, 0x00, + 0x00, 0x24, 0x2c, 0x09, 0x00, 0x28, 0x34, 0x09, 0x00, 0x38, 0x40, 0x12, 0x00, 0x30, 0x40, 0x1c, 0x00, 0x40, 0x50, 0x2f, 0x00, 0x55, 0x69, 0x42, 0x00, 0x65, 0x75, 0x55, 0x00, 0x6c, 0x7d, 0x5e, + 0x00, 0x74, 0x8d, 0x71, 0x00, 0x74, 0x89, 0x84, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x78, 0x8d, 0x84, 0x00, 0x79, 0x89, 0x7a, 0x00, 0x79, 0x85, 0x71, 0x00, 0x75, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, + 0x00, 0x6c, 0x71, 0x5e, 0x00, 0x6d, 0x70, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x69, 0x71, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x71, 0x55, + 0x00, 0x65, 0x71, 0x55, 0x00, 0x69, 0x6d, 0x55, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x6c, 0x67, 0x00, 0x6c, 0x6c, 0x5e, 0x00, 0x71, 0x71, 0x5e, + 0x00, 0x79, 0x79, 0x67, 0x00, 0x81, 0x85, 0x71, 0x00, 0x7d, 0x91, 0x71, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x79, 0x92, 0x84, 0x00, 0x78, 0x92, 0x8d, + 0x00, 0x78, 0x8d, 0x8d, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x74, 0x92, 0x84, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x6c, 0x85, 0x67, 0x00, 0x64, 0x79, 0x5e, 0x00, 0x59, 0x69, 0x4b, 0x00, 0xaa, 0x57, 0x00, + 0x00, 0x38, 0x44, 0x1c, 0x00, 0x30, 0x3c, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x34, 0x40, 0x25, 0x00, 0x50, 0x61, 0x4b, 0x00, 0x5d, 0x6d, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x60, 0x71, 0x5e, + 0x00, 0x60, 0x75, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x71, 0x79, 0x67, 0x00, 0x70, 0x79, 0x67, 0x00, 0x6c, 0x7d, 0x67, 0x00, 0x68, 0x79, 0x67, + 0x00, 0x6c, 0x79, 0x67, 0x00, 0x6c, 0x75, 0x67, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x75, 0x79, 0x5e, 0x00, 0x75, 0x7d, 0x5e, 0x00, 0x81, 0x8d, 0x5e, 0x00, 0x8d, 0x92, 0x5e, + 0x00, 0x8d, 0x92, 0x67, 0x00, 0x9a, 0x9a, 0x71, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa1, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x92, 0x67, 0x00, 0x81, 0x85, 0x5e, + 0x00, 0x7d, 0x7d, 0x55, 0x00, 0x69, 0x79, 0x4b, 0x00, 0x61, 0x6d, 0x42, 0x00, 0x44, 0x4c, 0x25, 0x00, 0x38, 0x44, 0x1c, 0x00, 0x40, 0x51, 0x25, 0x00, 0x45, 0x4d, 0x25, 0x00, 0x71, 0x6d, 0x42, + 0x00, 0x79, 0x7d, 0x4b, 0x00, 0x81, 0x7d, 0x55, 0x00, 0x79, 0x79, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x7d, 0x55, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x65, 0x79, 0x54, 0x00, 0x68, 0x79, 0x5e, + 0x00, 0x64, 0x79, 0x67, 0x00, 0x64, 0x79, 0x67, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x64, 0x6c, 0x5e, 0x00, 0x65, 0x6d, 0x55, 0x00, 0x4d, 0x58, 0x42, 0x00, 0x34, 0x40, 0x25, + 0x00, 0x2c, 0x38, 0x1c, 0x00, 0x20, 0x28, 0x1c, 0x00, 0x1c, 0x14, 0x09, 0x00, 0x18, 0x18, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x0c, 0x18, 0x00, 0x00, 0x1c, 0x28, 0x09, + 0x00, 0x24, 0x30, 0x12, 0x00, 0x3c, 0x44, 0x25, 0x00, 0x5d, 0x65, 0x55, 0x00, 0x75, 0x79, 0x55, 0x00, 0x85, 0x89, 0x5e, 0x00, 0x89, 0x91, 0x71, 0x00, 0x96, 0xa2, 0x71, 0x00, 0x9a, 0xa2, 0x7a, + 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xae, 0x71, 0x00, 0xa6, 0xaa, 0x7a, 0x00, 0xa2, 0xaa, 0x7a, 0x00, 0xa1, 0xa5, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x85, 0x96, 0x7a, + 0x00, 0x81, 0x92, 0x7a, 0x00, 0x78, 0x92, 0x7a, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x75, 0x8d, 0x7a, 0x00, 0x70, 0x81, 0x67, 0x00, 0x7d, 0x7d, 0x67, 0x00, 0x89, 0x89, 0x67, 0x00, 0x92, 0x9a, 0x71, + 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xb6, 0x84, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xb6, 0xba, 0x97, 0x00, 0xc2, 0xca, 0x97, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xaa, 0xb2, 0x8d, + 0x00, 0xa2, 0xae, 0x84, 0x00, 0x9a, 0xa6, 0x7a, 0x00, 0x92, 0x9e, 0x7a, 0x00, 0x85, 0x9a, 0x7a, 0x00, 0x7d, 0x96, 0x7a, 0x00, 0x7d, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x84, + 0x00, 0x81, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x8d, 0x9a, 0x84, 0x00, 0x92, 0x96, 0x84, + 0x00, 0x9e, 0xa9, 0x84, 0x00, 0xae, 0xb2, 0x84, 0x00, 0xaa, 0xba, 0x84, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb6, 0xc2, 0xa0, 0x00, 0xc6, 0xca, 0xa0, 0x00, 0xc6, 0xce, 0xaa, 0x00, 0xd6, 0xda, 0xb3, + 0x00, 0xda, 0xe2, 0xc5, 0x00, 0xd2, 0xd6, 0xbc, 0x00, 0xbe, 0xc2, 0xa0, 0x00, 0xaa, 0xb6, 0x8d, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x89, 0x71, 0x00, 0x81, 0x7d, 0x67, + 0x00, 0x7d, 0x7d, 0x67, 0x00, 0x81, 0x78, 0x67, 0x00, 0x7d, 0x7d, 0x5e, 0x00, 0x79, 0x79, 0x5e, 0x00, 0x79, 0x81, 0x5e, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x81, 0x67, + 0x00, 0x81, 0x89, 0x71, 0x00, 0x85, 0x91, 0x7a, 0x00, 0x89, 0x92, 0x7a, 0x00, 0x96, 0x9d, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x92, 0x96, 0x84, 0x00, 0x96, 0x9a, 0x8d, 0x00, 0x92, 0x92, 0x84, + 0x00, 0x89, 0x91, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x74, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x78, 0x96, 0x97, 0x00, 0x81, 0x96, 0x8d, + 0x00, 0x81, 0x96, 0x8d, 0x00, 0x81, 0x9a, 0x8d, 0x00, 0x85, 0x9a, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x8d, 0xa2, 0x97, 0x00, 0x95, 0xa2, 0x97, 0x00, 0x8d, 0xa2, 0x97, + 0x00, 0x96, 0xa6, 0x8d, 0x00, 0x9a, 0xa1, 0x8d, 0x00, 0x9e, 0xa9, 0x84, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0xa2, 0xa5, 0x71, 0x00, 0x9e, 0xa6, 0x71, 0x00, 0x9a, 0xa6, 0x71, 0x00, 0x95, 0x9d, 0x71 + }; for (size_t i = 0; i < size; i++) { @@ -147,7 +150,6 @@ public: m_Name = palette.m_Name; m_Filename = palette.m_Filename; CopyVec(m_Entries, palette.m_Entries); - return *this; } @@ -167,7 +169,7 @@ public: /// The address of the first element in the color entries vector inline v4T* operator() (void) { - return &m_Entries[0]; + return m_Entries.data(); } /// @@ -212,15 +214,12 @@ public: { size_t ii = (i * 256) / COLORMAP_LENGTH; T rgb[3], hsv[3]; - rgb[0] = m_Entries[ii].r; rgb[1] = m_Entries[ii].g; rgb[2] = m_Entries[ii].b; - RgbToHsv(rgb, hsv); hsv[0] += hue * T(6.0); HsvToRgb(hsv, rgb); - //Alpha serves as merely a hit counter that gets incremented by 1 each time, see Renderer::Accumulate() for its usage. //Removing it saves no memory since it's 16 byte aligned. This also means alpha is not used. palette[i].r = rgb[0]; @@ -275,7 +274,6 @@ public: for (size_t i = 0; i < Size(); i++) { size_t ii = (i * 256) / COLORMAP_LENGTH; - rgb[0] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].r;//Rotation. rgb[1] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].g; rgb[2] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].b; @@ -289,7 +287,6 @@ public: rgb[0] = Clamp(((rgb[0] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1);//Contrast. rgb[1] = Clamp(((rgb[1] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1); rgb[2] = Clamp(((rgb[2] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1); - //Alpha serves as merely a hit counter that gets incremented by 1 each time, see Renderer::Accumulate() for its usage. //Removing it saves no memory since it's 16 byte aligned. palette[i].r = rgb[0]; @@ -305,7 +302,6 @@ public: for (int i = 0; i < 256; i++) { int n = -1; - rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; @@ -395,10 +391,8 @@ public: static void RgbToHsv(T r, T g, T b, T& h, T& s, T& v) { T max, min, del, rc, gc, bc; - max = std::max(std::max(r, g), b);//Compute maximum of r, g, b. min = std::min(std::min(r, g), b);//Compute minimum of r, g, b. - del = max - min; v = max; s = (max != 0) ? (del / max) : 0; @@ -461,11 +455,17 @@ public: switch (j) { case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + default: r = v; g = t; b = p; break; } } diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index 5025960..ab87d37 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -81,25 +81,31 @@ bool Renderer::AssignIterator() template void Renderer::ComputeBounds() { - size_t maxDEFilterWidth = 0; + //size_t maxDEFilterWidth = 0; //Use type T to account for negative numbers which will occur with a larger supersample and smaller filter width. //The final value will be of type size_t. - m_GutterWidth = size_t(ClampGte((T(m_SpatialFilter->FinalFilterWidth()) - T(Supersample())) / 2, 0)); - - //Check the size of the density estimation filter. - //If the radius of the density estimation filter is greater than the - //gutter width, have to pad with more. Otherwise, use the same value. - for (auto& ember : m_Embers) - maxDEFilterWidth = std::max(size_t(ceil(ember.m_MaxRadDE) * m_Ember.m_Supersample), maxDEFilterWidth); - - //Need an extra ss = (int)floor(m_Supersample / 2.0) of pixels so that a local iteration count for DE can be determined.//SMOULDER - if (maxDEFilterWidth > 0) - maxDEFilterWidth += size_t(Floor(m_Ember.m_Supersample / T(2))); - + //m_GutterWidth = size_t(ClampGte((T(m_SpatialFilter->FinalFilterWidth()) - T(Supersample())) / 2, 0)); + // + ////Check the size of the density estimation filter. + ////If the radius of the density estimation filter is greater than the + ////gutter width, have to pad with more. Otherwise, use the same value. + //for (auto& ember : m_Embers) + // maxDEFilterWidth = std::max(size_t(ceil(ember.m_MaxRadDE) * m_Ember.m_Supersample), maxDEFilterWidth); + // + ////Need an extra ss = (int)floor(m_Supersample / 2.0) of pixels so that a local iteration count for DE can be determined.//SMOULDER + //if (maxDEFilterWidth > 0) + // maxDEFilterWidth += size_t(Floor(m_Ember.m_Supersample / T(2))); //To have a fully present set of pixels for the spatial filter, must //add the DE filter width to the spatial filter width.//SMOULDER - m_DensityFilterOffset = maxDEFilterWidth; - m_GutterWidth += m_DensityFilterOffset; + //m_DensityFilterOffset = maxDEFilterWidth; + //m_GutterWidth += m_DensityFilterOffset; + // + //Original did a lot of work to compute a gutter that changes size based on various parameters, which seems to be of no benefit. + //It also prevents the renderer from only performing filtering or final accum based on a filter parameter change, since that + //change may have changed the gutter. + //By using a fixed gutter, a filter change can be applied without fully restarting iteration. + //m_GutterWidth = 10; + m_GutterWidth = 10 * Supersample();//Should be enough to fully accommodate most spatial and density filter widths. m_SuperRasW = (Supersample() * FinalRasW()) + (2 * m_GutterWidth); m_SuperRasH = (Supersample() * FinalRasH()) + (2 * m_GutterWidth); m_SuperSize = m_SuperRasW * m_SuperRasH; @@ -401,10 +407,12 @@ eRenderStatus Renderer::Run(vector& finalImage, double time, s if (m_InsertPalette && BytesPerChannel() == 1) m_TempEmber = m_Ember; - //Field would go here, however Ember omits it. Would need temps for width and height if ever implemented. - CreateSpatialFilter(newFilterAlloc); - CreateTemporalFilter(newFilterAlloc); - ComputeBounds(); + if (!resume)//Only need to create this when starting a new render. + { + CreateSpatialFilter(newFilterAlloc);//Will be checked and recreated again if necessary right before final output. + CreateTemporalFilter(newFilterAlloc);//But create here just to ensure allocation succeeded. + ComputeBounds(); + } if (m_SpatialFilter.get() == nullptr || m_TemporalFilter.get() == nullptr) { @@ -423,7 +431,7 @@ eRenderStatus Renderer::Run(vector& finalImage, double time, s if (!resume) ResetBuckets(true, false);//Only reset hist here and do accum when needed later on. - deTime = T(time) + m_TemporalFilter->Deltas()[0]; + deTime = T(time) + *m_TemporalFilter->Deltas(); //Interpolate and get an ember for DE purposes. //Additional interpolation will be done in the temporal samples loop. @@ -436,7 +444,7 @@ eRenderStatus Renderer::Run(vector& finalImage, double time, s ClampGteRef(m_Ember.m_MaxRadDE, 0); ClampGteRef(m_Ember.m_MaxRadDE, m_Ember.m_MinRadDE); - if (!CreateDEFilter(newFilterAlloc)) + if (!CreateDEFilter(newFilterAlloc))//Will be checked and recreated again if necessary right before density filtering. { AddToReport("Density filter creation failed, aborting.\n"); success = eRenderStatus::RENDER_ERROR; @@ -564,6 +572,11 @@ FilterAndAccum: ResetBuckets(false, true);//Only the histogram was reset above, now reset the density filtering buffer. //t.Tic(); + //Make sure a density filter was created with the latest values. + ClampGteRef(m_Ember.m_MinRadDE, 0); + ClampGteRef(m_Ember.m_MaxRadDE, 0); + ClampGteRef(m_Ember.m_MaxRadDE, m_Ember.m_MinRadDE); + CreateDEFilter(newFilterAlloc); //Apply appropriate filter if iterating is complete. if (filterAndAccumOnly || temporalSample >= TemporalSamples()) @@ -615,6 +628,7 @@ AccumOnly: //Make sure a filter has been created. CreateSpatialFilter(newFilterAlloc); + m_DensityFilterOffset = m_GutterWidth - size_t(Clamp((T(m_SpatialFilter->FinalFilterWidth()) - T(Supersample())) / 2, 0, T(m_GutterWidth))); m_CurvesSet = m_Ember.m_Curves.CurvesSet(); //Color curves must be re-calculated as well. @@ -868,7 +882,12 @@ eRenderStatus Renderer::LogScaleDensityFilter(bool forceOutput) bucketT logScale = (m_K1 * std::log(1 + m_HistBuckets[i].a * m_K2)) / m_HistBuckets[i].a; //Original did a temporary assignment, then *= logScale, then passed the result to bump_no_overflow(). //Combine here into one operation for a slight speedup. - m_AccumulatorBuckets[i] = m_HistBuckets[i] * logScale; + //Vectorized version: + bucketT* __restrict hist = glm::value_ptr(m_HistBuckets[i]);//Vectorizer can't tell these point to different locations. + bucketT* __restrict acc = glm::value_ptr(m_AccumulatorBuckets[i]); + + for (size_t v = 0; v < 4; v++) + acc[v] = hist[v] * logScale; } } } @@ -1073,6 +1092,7 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t EnterFinalAccum(); //Timing t(4); + bool doAlpha = NumChannels() > 3; size_t filterWidth = m_SpatialFilter->FinalFilterWidth(); bucketT g, linRange, vibrancy; Color background; @@ -1085,11 +1105,13 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t { parallel_for(size_t(0), m_SuperRasH, [&] (size_t j) { - size_t rowStart = j * m_SuperRasW;//Pull out of inner loop for optimization. + auto rowStart = m_AccumulatorBuckets.data() + (j * m_SuperRasW);//Pull out of inner loop for optimization. + auto rowEnd = rowStart + m_SuperRasW; - for (size_t i = 0; i < m_SuperRasW && !m_Abort; i++) + while (rowStart < rowEnd && !m_Abort)//Use the pointer itself as the offset to save an extra addition per iter. { - GammaCorrection(m_AccumulatorBuckets[i + rowStart], background, g, linRange, vibrancy, true, false, &(m_AccumulatorBuckets[i + rowStart][0]));//Write back in place. + GammaCorrection(*rowStart, background, g, linRange, vibrancy, true, false, glm::value_ptr(*rowStart));//Write back in place. + rowStart++; } }); } @@ -1109,32 +1131,33 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t Color newBucket; size_t pixelsRowStart = (m_YAxisUp ? ((FinalRasH() - j) - 1) : j) * FinalRowSize();//Pull out of inner loop for optimization. size_t y = m_DensityFilterOffset + (j * Supersample());//Start at the beginning row of each super sample block. - glm::uint16* p16; + size_t clampedFilterH = std::min(filterWidth, m_SuperRasH - y);//Make sure the filter doesn't go past the bottom of the gutter. for (size_t i = 0; i < FinalRasW(); i++, pixelsRowStart += PixelSize()) { size_t ii, jj; size_t x = m_DensityFilterOffset + (i * Supersample());//Start at the beginning column of each super sample block. + size_t clampedFilterW = std::min(filterWidth, m_SuperRasW - x);//Make sure the filter doesn't go past the right of the gutter. newBucket.Clear(); //Original was iterating column-wise, which is slow. //Here, iterate one row at a time, giving a 10% speed increase. - for (jj = 0; jj < filterWidth; jj++) + for (jj = 0; jj < clampedFilterH; jj++) { - size_t filterKRowIndex = jj * filterWidth; + size_t filterKRowIndex = jj * filterWidth;//Use the full, non-clamped width to get the filter value. size_t accumRowIndex = (y + jj) * m_SuperRasW;//Pull out of inner loop for optimization. - for (ii = 0; ii < filterWidth; ii++) + for (ii = 0; ii < clampedFilterW; ii++) { //Need to dereference the spatial filter pointer object to use the [] operator. Makes no speed difference. - bucketT k = ((*m_SpatialFilter)[ii + filterKRowIndex]); - newBucket += (m_AccumulatorBuckets[(x + ii) + accumRowIndex] * k); + bucketT k = ((*m_SpatialFilter)[filterKRowIndex + ii]); + newBucket += (m_AccumulatorBuckets[accumRowIndex + (x + ii)] * k); } } if (BytesPerChannel() == 2) { - p16 = reinterpret_cast(pixels + pixelsRowStart); + auto p16 = reinterpret_cast(pixels + pixelsRowStart); if (EarlyClip()) { @@ -1149,7 +1172,7 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t p16[1] = glm::uint16(Clamp(newBucket.g, 0, 255) * bucketT(256)); p16[2] = glm::uint16(Clamp(newBucket.b, 0, 255) * bucketT(256)); - if (NumChannels() > 3) + if (doAlpha) { if (Transparency()) p16[3] = byte(Clamp(newBucket.a, 0, 1) * bucketT(65535.0)); @@ -1159,7 +1182,7 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t } else { - GammaCorrection(*(reinterpret_cast*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, p16); + GammaCorrection(*(reinterpret_cast*>(&newBucket)), background, g, linRange, vibrancy, doAlpha, true, p16); } } else @@ -1177,7 +1200,7 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t pixels[pixelsRowStart + 1] = byte(Clamp(newBucket.g, 0, 255)); pixels[pixelsRowStart + 2] = byte(Clamp(newBucket.b, 0, 255)); - if (NumChannels() > 3) + if (doAlpha) { if (Transparency()) pixels[pixelsRowStart + 3] = byte(Clamp(newBucket.a, 0, 1) * bucketT(255.0)); @@ -1187,13 +1210,13 @@ eRenderStatus Renderer::AccumulatorToFinalImage(byte* pixels, size_t } else { - GammaCorrection(*(reinterpret_cast*>(&newBucket)), background, g, linRange, vibrancy, NumChannels() > 3, true, pixels + pixelsRowStart); + GammaCorrection(*(reinterpret_cast*>(&newBucket)), background, g, linRange, vibrancy, doAlpha, true, pixels + pixelsRowStart); } } } }); - //Insert the palette into the image for debugging purposes. Only works with 8bpc. + //Insert the palette into the image for debugging purposes. Only works with 8bpc and is not implemented on the GPU. if (m_InsertPalette && BytesPerChannel() == 1) { size_t i, j, ph = 100; @@ -1625,7 +1648,7 @@ void Renderer::GammaCorrection(tvec4& bucket ClampRef(alpha, 0, 1); } - Palette::template CalcNewRgb(&bucket[0], ls, HighlightPower(), newRgb); + Palette::template CalcNewRgb(glm::value_ptr(bucket), ls, HighlightPower(), newRgb); for (glm::length_t rgbi = 0; rgbi < 3; rgbi++) { diff --git a/Source/Ember/TemporalFilter.h b/Source/Ember/TemporalFilter.h index 9582754..8315fb1 100644 --- a/Source/Ember/TemporalFilter.h +++ b/Source/Ember/TemporalFilter.h @@ -144,8 +144,8 @@ public: T FilterWidth() const { return m_FilterWidth; } T FilterExp() const { return m_FilterExp; } T SumFilt() const { return m_SumFilt; } - T* Deltas() { return &m_Deltas[0]; } - T* Filter() { return &m_Filter[0]; } + T* Deltas() { return m_Deltas.data(); } + T* Filter() { return m_Filter.data(); } eTemporalFilterType FilterType() const { return m_FilterType; } protected: diff --git a/Source/Ember/Utils.h b/Source/Ember/Utils.h index 2e1e97f..f90a75a 100644 --- a/Source/Ember/Utils.h +++ b/Source/Ember/Utils.h @@ -59,7 +59,7 @@ static inline bool Contains(c& container, const T& val) /// The vector to compute the size of /// The size of one element times the length. template -static inline size_t SizeOf(vector& vec) +static inline size_t SizeOf(const vector& vec) { return sizeof(vec[0]) * vec.size(); } diff --git a/Source/Ember/Variation.h b/Source/Ember/Variation.h index 8c0e4c2..94218af 100644 --- a/Source/Ember/Variation.h +++ b/Source/Ember/Variation.h @@ -2033,7 +2033,7 @@ public: /// /// Accessors. /// - const ParamWithName* Params() const { return &m_Params[0]; } + const ParamWithName* Params() const { return m_Params.data(); } size_t ParamCount() const { return m_Params.size(); } const vector>& ParamsVec() const { return m_Params; } diff --git a/Source/Ember/Variations06.h b/Source/Ember/Variations06.h index a628682..f57f286 100644 --- a/Source/Ember/Variations06.h +++ b/Source/Ember/Variations06.h @@ -3938,14 +3938,13 @@ public: T xi, yi, zi; int iMode = int(m_Mode); - //Extremely strange usage, where a post variation wants the original affine transformed points. if (m_Static > 1) { xi = helper.In.x; yi = helper.In.y; zi = helper.In.z; } - else + else//Extremely strange usage, where a post variation wants the original affine transformed points. { xi = helper.m_TransX; yi = helper.m_TransY; @@ -4021,7 +4020,7 @@ public: if (m_Roundstr != 0) { T wwidth = ((m_Roundwidth != 1) ? std::exp(std::log(xang * 2) * m_Roundwidth) : (xang * 2)) * m_RoundCoeff; - coeff = abs((1 - wwidth) * coeff + wwidth); + coeff = std::abs((1 - wwidth) * coeff + wwidth); } if (m_Distortion != 1) @@ -4369,6 +4368,7 @@ public: m_X = m_Y = m_Z = m_C = 0; } + protected: void Init() { diff --git a/Source/Ember/XmlToEmber.h b/Source/Ember/XmlToEmber.h index 7043dfb..1dbbdf1 100644 --- a/Source/Ember/XmlToEmber.h +++ b/Source/Ember/XmlToEmber.h @@ -559,6 +559,7 @@ private: else if (ParseAndAssign(curAtt->name, attStr, "scale", currentEmber.m_PixelsPerUnit, ret)) { currentEmber.m_OrigPixPerUnit = currentEmber.m_PixelsPerUnit; } else if (ParseAndAssign(curAtt->name, attStr, "rotate", currentEmber.m_Rotate, ret)) { } else if (ParseAndAssign(curAtt->name, attStr, "zoom", currentEmber.m_Zoom, ret)) { ClampGteRef(currentEmber.m_Zoom, 0); } + else if (ParseAndAssign(curAtt->name, attStr, "cam_zoom", currentEmber.m_Zoom, ret)) { ClampGteRef(currentEmber.m_Zoom, 0); }//JWildfire uses cam_zoom. else if (ParseAndAssign(curAtt->name, attStr, "filter", currentEmber.m_SpatialFilterRadius, ret)) { } else if (ParseAndAssign(curAtt->name, attStr, "temporal_filter_width", currentEmber.m_TemporalFilterWidth, ret)) { } else if (ParseAndAssign(curAtt->name, attStr, "temporal_filter_exp", currentEmber.m_TemporalFilterExp, ret)) { } @@ -1253,9 +1254,15 @@ private: if (auto var = m_VariationList.GetVariation(s)) { - auto varCopy = var->Copy(); - Aton(attStr, varCopy->m_Weight); - xform.AddVariation(varCopy); + T weight = 0; + Aton(attStr, weight); + + if (!IsNearZero(weight))//Having a variation with zero weight makes no sense, so guard against it. + { + auto varCopy = var->Copy(); + varCopy->m_Weight = weight; + xform.AddVariation(varCopy); + } } //else diff --git a/Source/EmberCL/FinalAccumOpenCLKernelCreator.cpp b/Source/EmberCL/FinalAccumOpenCLKernelCreator.cpp index 7236a8d..a595d41 100644 --- a/Source/EmberCL/FinalAccumOpenCLKernelCreator.cpp +++ b/Source/EmberCL/FinalAccumOpenCLKernelCreator.cpp @@ -32,7 +32,7 @@ FinalAccumOpenCLKernelCreator::FinalAccumOpenCLKernelCreator(bool doublePrecisio /// Kernel source and entry point properties, getters only. /// -const string& FinalAccumOpenCLKernelCreator::GammaCorrectionWithAlphaCalcKernel() const { return m_GammaCorrectionWithAlphaCalcKernel; } +const string& FinalAccumOpenCLKernelCreator::GammaCorrectionWithAlphaCalcKernel() const { return m_GammaCorrectionWithAlphaCalcKernel; } const string& FinalAccumOpenCLKernelCreator::GammaCorrectionWithAlphaCalcEntryPoint() const { return m_GammaCorrectionWithAlphaCalcEntryPoint; } const string& FinalAccumOpenCLKernelCreator::GammaCorrectionWithoutAlphaCalcKernel() const { return m_GammaCorrectionWithoutAlphaCalcKernel; } const string& FinalAccumOpenCLKernelCreator::GammaCorrectionWithoutAlphaCalcEntryPoint() const { return m_GammaCorrectionWithoutAlphaCalcEntryPoint; } @@ -231,6 +231,8 @@ string FinalAccumOpenCLKernelCreator::CreateFinalAccumKernelString(bool earlyCli "\n" " uint accumX = spatialFilter->m_DensityFilterOffset + (GLOBAL_ID_X * spatialFilter->m_Supersample);\n" " uint accumY = spatialFilter->m_DensityFilterOffset + (GLOBAL_ID_Y * spatialFilter->m_Supersample);\n" + " uint clampedFilterH = min((uint)spatialFilter->m_FilterWidth, spatialFilter->m_SuperRasH - accumY);" + " uint clampedFilterW = min((uint)spatialFilter->m_FilterWidth, spatialFilter->m_SuperRasW - accumX);" " int2 finalCoord;\n" " finalCoord.x = GLOBAL_ID_X;\n" " finalCoord.y = (int)((spatialFilter->m_YAxisUp == 1) ? ((spatialFilter->m_FinalRasH - GLOBAL_ID_Y) - 1) : GLOBAL_ID_Y);\n" @@ -241,15 +243,15 @@ string FinalAccumOpenCLKernelCreator::CreateFinalAccumKernelString(bool earlyCli " real4reals_bucket newBucket;\n" " newBucket.m_Real4 = 0;\n" "\n" - " for (jj = 0; jj < spatialFilter->m_FilterWidth; jj++)\n" + " for (jj = 0; jj < clampedFilterH; jj++)\n" " {\n" - " filterKRowIndex = jj * spatialFilter->m_FilterWidth;\n" + " filterKRowIndex = jj * spatialFilter->m_FilterWidth;\n"//Use the full, non-clamped width to get the filter value. "\n" - " for (ii = 0; ii < spatialFilter->m_FilterWidth; ii++)\n" + " for (ii = 0; ii < clampedFilterW; ii++)\n" " {\n" - " real_bucket_t k = filterCoefs[ii + filterKRowIndex];\n" + " real_bucket_t k = filterCoefs[filterKRowIndex + ii];\n" "\n" - " accumBucket = accumulator + (accumX + ii) + ((accumY + jj) * spatialFilter->m_SuperRasW);\n" + " accumBucket = accumulator + ((accumY + jj) * spatialFilter->m_SuperRasW) + (accumX + ii);\n" " newBucket.m_Real4 += (k * accumBucket->m_Real4);\n" " }\n" " }\n" @@ -268,12 +270,12 @@ string FinalAccumOpenCLKernelCreator::CreateFinalAccumKernelString(bool earlyCli if (alphaCalc) os << " finalColor.m_Float4.w = (float)newBucket.m_Real4.w * 255.0f;\n"; else - os << " finalColor.m_Float4.w = 255;\n"; + os << " finalColor.m_Float4.w = 255.0f;\n"; } } else { - //Late clip, so must gamma correct from the temp new bucket to temp float4. + //Late clip, so must gamma correct from the temp newBucket to temp finalColor float4. if (m_DoublePrecision) { os << diff --git a/Source/Fractorium/AboutDialog.ui b/Source/Fractorium/AboutDialog.ui index e78207f..ea1916e 100644 --- a/Source/Fractorium/AboutDialog.ui +++ b/Source/Fractorium/AboutDialog.ui @@ -58,7 +58,7 @@ QFrame::NoFrame - <html><head/><body><p align="center"><br/>Fractorium 0.9.9.4 Beta</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><span style=" font-size:10pt;">Lead: Matt Feemster<br/>Contributors: Simon Detheridge</span></p></body></html> + <html><head/><body><p align="center"><br/>Fractorium 0.9.9.5 Beta</p><p align="center"><span style=" font-size:10pt;">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.</span></p><p align="center"><span style=" font-size:10pt;">Lead: Matt Feemster<br/>Contributors: Simon Detheridge</span></p></body></html> Qt::RichText @@ -122,7 +122,7 @@ QFrame::NoFrame - <html><head/><body><p><a href="http://code.google.com/p/flam3"><span style=" text-decoration: underline; color:#0000ff;">flam3</span></a>: Scott Draves, Erik Reckase (GPL v2)<br/><a href="http://github.com/stevenrobertson/cuburn"><span style=" text-decoration: underline; color:#0000ff;">cuburn</span></a>: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)<br/><a href="http://fractron9000.sourceforge.net"><span style=" text-decoration: underline; color:#0000ff;">Fractron 9000</span></a>: Mike Thiesen (GPL)<br/><a href="http://sourceforge.net/projects/apophysis7x"><span style=" text-decoration: underline; color:#0000ff;">Apophysis</span></a>: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)<br/><a href="http://jwildfire.org/"><span style=" text-decoration: underline; color:#0000ff;">JWildfire</span></a>: Andreas Maschke (LGPL)<br/>Numerous Apophysis plugin developers (GPL)</p></body></html> + <html><head/><body><p><a href="https://github.com/scottdraves/flam3"><span style=" text-decoration: underline; color:#0000ff;">flam3</span></a>: Scott Draves, Erik Reckase (GPL v2)<br/><a href="http://github.com/stevenrobertson/cuburn"><span style=" text-decoration: underline; color:#0000ff;">cuburn</span></a>: Steven Robertson, Michael Semeniuk, Matthew Znoj, Nicolas Mejia (GPL v3)<br/><a href="http://fractron9000.sourceforge.net"><span style=" text-decoration: underline; color:#0000ff;">Fractron 9000</span></a>: Mike Thiesen (GPL)<br/><a href="http://sourceforge.net/projects/apophysis7x"><span style=" text-decoration: underline; color:#0000ff;">Apophysis</span></a>: Mark Townsend, Ronald Hordijk, Peter Sdobnov, Piotr Borys, Georg Kiehne (GPL)<br/><a href="http://jwildfire.org/"><span style=" text-decoration: underline; color:#0000ff;">JWildfire</span></a>: Andreas Maschke (LGPL)<br/>Numerous Apophysis plugin developers (GPL)</p></body></html> Qt::RichText @@ -177,7 +177,7 @@ QFrame::NoFrame - <html><head/><body><p><a href="http://qt-project.org"><span style=" text-decoration: underline; color:#0000ff;">Qt</span></a>: Digia Plc (GPL v3, LGPL v2)<br/><a href="http://g-truc.net"><span style=" text-decoration: underline; color:#0000ff;">glm</span></a>: Christophe Riccio (MIT License)<br/><a href="http://threadingbuildingblocks.org"><span style=" text-decoration: underline; color:#0000ff;">Threading Building Blocks</span></a>: Intel Corporation (GPLv2)<br/><a href="http://libjpeg.sourceforge.net"><span style=" text-decoration: underline; color:#0000ff;">libjpeg</span></a>: Independent JPEG Group (Free Software License)<br/><a href="http://libpng.org"><span style=" text-decoration: underline; color:#0000ff;">libpng</span></a>: Glenn Randers-Pehrson et al (Libpng License)<br/><a href="http://xmlsoft.org"><span style=" text-decoration: underline; color:#0000ff;">libxml2</span></a>: Daniel Veillard (MIT License)<br/><a href="http://zlib.net"><span style=" text-decoration: underline; color:#0000ff;">zlib</span></a>: Jean-loup Gailly, Mark Adler (Zlib License)<br/><a href="http://burtleburtle.net/bob/rand/isaac.html"><span style=" text-decoration: underline; color:#0000ff;">QTIsaac</span></a>: Robert J. Jenkins, Quinn Tyler Jackson (Public Domain)<br/><a href="http://cas.ee.ic.ac.uk/people/dt10/index.html"><span style=" text-decoration: underline; color:#0000ff;">MWC64X Random Number Generator</span></a>: David Thomas (Public Domain)<br/><a href="http://code.jellycan.com/simpleopt/"><span style=" text-decoration: underline; color:#0000ff;">SimpleOpt</span></a>: Brodie Thiesfield (MIT License)</p></body></html> + <html><head/><body><p><a href="http://www.qt.io/developers/"><span style=" text-decoration: underline; color:#0000ff;">Qt</span></a>: Digia Plc (GPL v3, LGPL v2)<br/><a href="http://g-truc.net"><span style=" text-decoration: underline; color:#0000ff;">glm</span></a>: Christophe Riccio (MIT License)<br/><a href="http://threadingbuildingblocks.org"><span style=" text-decoration: underline; color:#0000ff;">Threading Building Blocks</span></a>: Intel Corporation (GPLv2)<br/><a href="http://libjpeg.sourceforge.net"><span style=" text-decoration: underline; color:#0000ff;">libjpeg</span></a>: Independent JPEG Group (Free Software License)<br/><a href="http://libpng.org"><span style=" text-decoration: underline; color:#0000ff;">libpng</span></a>: Glenn Randers-Pehrson et al (Libpng License)<br/><a href="http://xmlsoft.org"><span style=" text-decoration: underline; color:#0000ff;">libxml2</span></a>: Daniel Veillard (MIT License)<br/><a href="http://zlib.net"><span style=" text-decoration: underline; color:#0000ff;">zlib</span></a>: Jean-loup Gailly, Mark Adler (Zlib License)<br/><a href="http://burtleburtle.net/bob/cplus/isaac.hpp"><span style=" text-decoration: underline; color:#0000ff;">QTIsaac</span></a>: Robert J. Jenkins, Quinn Tyler Jackson (Public Domain)<br/><a href="http://cas.ee.ic.ac.uk/people/dt10/research/rngs-gpu-mwc64x.html"><span style=" text-decoration: underline; color:#0000ff;">MWC64X Random Number Generator</span></a>: David Thomas (Public Domain)<br/><a href="https://github.com/brofield/simpleopt"><span style=" text-decoration: underline; color:#0000ff;">SimpleOpt</span></a>: Brodie Thiesfield (MIT License)</p></body></html> Qt::RichText diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp index 81d59a0..eff02fa 100644 --- a/Source/Fractorium/Fractorium.cpp +++ b/Source/Fractorium/Fractorium.cpp @@ -105,7 +105,7 @@ Fractorium::Fractorium(QWidget* p) #endif m_Controller = unique_ptr(new FractoriumEmberController(this)); - m_Controller->SetupVariationTree(); + m_Controller->SetupVariationsTree(); m_Controller->FilteredVariations(); if (m_Info->Ok() && m_Settings->OpenCL() && m_QualitySpin->value() < (30 * m_Settings->Devices().size())) @@ -424,7 +424,7 @@ void Fractorium::dropEvent(QDropEvent* e) { QStringList filenames; Qt::KeyboardModifiers mod = e->keyboardModifiers(); - bool append = mod.testFlag(Qt::ControlModifier) ? true : false; + bool append = mod.testFlag(Qt::ControlModifier) ? false : true; if (e->mimeData()->hasUrls()) { diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui index 15536b0..825de2b 100644 --- a/Source/Fractorium/Fractorium.ui +++ b/Source/Fractorium/Fractorium.ui @@ -1892,14 +1892,14 @@ 770 0 - 240 + 255 881 - 240 - 498 + 255 + 617 @@ -1925,7 +1925,7 @@ 4 - + @@ -2010,7 +2010,7 @@ - + 5 @@ -2058,7 +2058,7 @@ - + Qt::StrongFocus @@ -2119,7 +2119,7 @@ Name - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -2127,7 +2127,7 @@ Palette - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -2335,6 +2335,137 @@ + + + + + 0 + 0 + + + + Reset Curves + + + + + + + + 0 + 0 + + + + + 245 + 245 + + + + + 245 + 245 + + + + true + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + 219 + 219 + 219 + + + + + + 0.000000000000000 + 0.000000000000000 + 245.000000000000000 + 245.000000000000000 + + + + QGraphicsView::NoAnchor + + + QGraphicsView::FullViewportUpdate + + + + + + + Curve + + + + 4 + + + 6 + + + 2 + + + 0 + + + 6 + + + + + All + + + true + + + + + + + Red + + + + + + + Green + + + + + + + Blue + + + + + + @@ -2746,12 +2877,12 @@ - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -2934,7 +3065,7 @@ - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -3247,7 +3378,7 @@ - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -3279,134 +3410,6 @@ - - - - - 0 - 0 - - - - - 245 - 245 - - - - - 245 - 245 - - - - true - - - false - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - 219 - 219 - 219 - - - - - - 0.000000000000000 - 0.000000000000000 - 245.000000000000000 - 245.000000000000000 - - - - QGraphicsView::NoAnchor - - - QGraphicsView::FullViewportUpdate - - - - - - - Curve - - - - 6 - - - 2 - - - 6 - - - 6 - - - - - All - - - true - - - - - - - Red - - - - - - - Green - - - - - - - Blue - - - - - - - - - - - 0 - 0 - - - - Reset Curves - - - @@ -5237,6 +5240,9 @@ QAbstractItemView::NoEditTriggers + + false + QAbstractItemView::SingleSelection @@ -5247,7 +5253,7 @@ 12 - false + true true @@ -5552,7 +5558,7 @@ - 1010 + 1020 0 301 881 @@ -5662,7 +5668,7 @@ QTabWidget::Triangular - 1 + 0 @@ -5861,7 +5867,7 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::SingleSelection true @@ -5869,11 +5875,14 @@ true + + false + 2 - false + true false @@ -6351,7 +6360,7 @@ - AlignLeft|AlignVCenter + AlignLeading|AlignVCenter @@ -6713,7 +6722,7 @@ - toolBar + Toolbar true @@ -7202,10 +7211,10 @@ :/Fractorium/Icons/control-stop-square.png:/Fractorium/Icons/control-stop-square.png - Stop Renderer + Stop renderer - Stop Renderer + Stop renderer Ctrl+P diff --git a/Source/Fractorium/FractoriumEmberController.cpp b/Source/Fractorium/FractoriumEmberController.cpp index 551bf45..ee4996c 100644 --- a/Source/Fractorium/FractoriumEmberController.cpp +++ b/Source/Fractorium/FractoriumEmberController.cpp @@ -364,6 +364,7 @@ void FractoriumEmberController::SetEmberPrivate(const Ember& ember, bool v m_GLController->ResetMouseState(); FillXforms();//Must do this first because the palette setup in FillParamTablesAndPalette() uses the xforms combo. FillParamTablesAndPalette(); + FillCurvesControl(); FillSummary(); //If a resize happened, this won't do anything because the new size is not reflected in the scroll area yet. diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index 03d51ae..5711a0c 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -186,7 +186,7 @@ public: //Xforms Variations. virtual void Filter(const QString& text) { } - virtual void SetupVariationTree() { } + virtual void SetupVariationsTree() { } virtual void ClearVariationsTree() { } virtual void VariationSpinBoxValueChanged(double d) { } virtual void FilteredVariations() { } @@ -431,7 +431,7 @@ public: //Xforms Variations. virtual void Filter(const QString& text) override; - virtual void SetupVariationTree() override; + virtual void SetupVariationsTree() override; virtual void ClearVariationsTree() override; virtual void VariationSpinBoxValueChanged(double d) override; virtual void FilteredVariations() override; diff --git a/Source/Fractorium/FractoriumInfo.cpp b/Source/Fractorium/FractoriumInfo.cpp index 504bd0a..3d4a103 100644 --- a/Source/Fractorium/FractoriumInfo.cpp +++ b/Source/Fractorium/FractoriumInfo.cpp @@ -101,7 +101,7 @@ void FractoriumEmberController::FillSummary() item1->setText(0, "Xform " + QString::number(x + 1) + " (" + QLocale::system().toString(xform->m_Weight, pc, p) + ") (" + - QLocale::system().toString(double(m_NormalizedWeights[index]), pc, p) + ") " + + QLocale::system().toString(double(m_NormalizedWeights[index]), pc, p) + ")" + linked); } else diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp index d816cdc..b2667fc 100644 --- a/Source/Fractorium/FractoriumPalette.cpp +++ b/Source/Fractorium/FractoriumPalette.cpp @@ -39,6 +39,12 @@ void Fractorium::InitPaletteUI() paletteTable->setColumnWidth(1, 260);//256 plus small margin on each side. paletteTable->horizontalHeader()->setSectionsClickable(true); connect(paletteTable->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(OnPaletteHeaderSectionClicked(int)), Qt::QueuedConnection); + connect(ui.ResetCurvesButton, SIGNAL(clicked(bool)), this, SLOT(OnResetCurvesButtonClicked(bool)), Qt::QueuedConnection); + connect(ui.CurvesView, SIGNAL(PointChangedSignal(int, int, const QPointF&)), this, SLOT(OnCurvesPointChanged(int, int, const QPointF&)), Qt::QueuedConnection); + connect(ui.CurvesAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesAllRadioButtonToggled(bool)), Qt::QueuedConnection); + connect(ui.CurvesRedRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesRedRadioButtonToggled(bool)), Qt::QueuedConnection); + connect(ui.CurvesGreenRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesGreenRadioButtonToggled(bool)), Qt::QueuedConnection); + connect(ui.CurvesBlueRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesBlueRadioButtonToggled(bool)), Qt::QueuedConnection); } /// @@ -379,6 +385,75 @@ void Fractorium::SetPaletteFileComboIndex(const string& filename) ui.PaletteFilenameCombo->setCurrentText(QFileInfo(QString::fromStdString(filename)).fileName()); } +/// +/// Reset the color curve values in the current ember to their default state and also update the curves control. +/// Called when ResetCurvesButton is clicked. +/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip. +/// +template +void FractoriumEmberController::ClearColorCurves() +{ + Update([&] + { + m_Ember.m_Curves.Init(); + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); + FillCurvesControl(); +} + +void Fractorium::OnResetCurvesButtonClicked(bool checked) { m_Controller->ClearColorCurves(); } + +/// +/// Set the coordinate of the curve point. +/// Called when the position of any of the points in the curves editor is is changed. +/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip. +/// +/// The curve index, 0-1/ +/// The point index within the selected curve, 1-2. +/// The new coordinate of the point in terms of the curves control rect. +template +void FractoriumEmberController::ColorCurveChanged(int curveIndex, int pointIndex, const QPointF& point) +{ + Update([&] + { + m_Ember.m_Curves.m_Points[curveIndex][pointIndex].x = point.x(); + m_Ember.m_Curves.m_Points[curveIndex][pointIndex].y = point.y(); + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); +} + +void Fractorium::OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point) { m_Controller->ColorCurveChanged(curveIndex, pointIndex, point); } + +/// +/// Set the top most points in the curves control, which makes it easier to +/// select a point by putting it on top of all the others. +/// Called when the any of the curve color radio buttons are toggled. +/// +/// The curve index, 0-1/ +void Fractorium::OnCurvesAllRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::ALL); } +void Fractorium::OnCurvesRedRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::RED); } +void Fractorium::OnCurvesGreenRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::GREEN); } +void Fractorium::OnCurvesBlueRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::BLUE); } + +/// +/// Set the points in the curves control to the values of the curve points in the current ember. +/// +template +void FractoriumEmberController::FillCurvesControl() +{ + m_Fractorium->ui.CurvesView->blockSignals(true); + + for (auto i = 0; i < 4; i++) + { + for (auto j = 1; j < 3; j++)//Only do middle points. + { + QPointF point(m_Ember.m_Curves.m_Points[i][j].x, m_Ember.m_Curves.m_Points[i][j].y); + m_Fractorium->ui.CurvesView->Set(i, j, point); + } + } + + m_Fractorium->ui.CurvesView->blockSignals(false); + m_Fractorium->ui.CurvesView->update(); +} + template class FractoriumEmberController; #ifdef DO_DOUBLE diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index 0151656..3107f31 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -47,7 +47,7 @@ void Fractorium::InitParamsUI() SetupSpinner(table, this, row, 1, m_CenterXSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterXChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_CenterYSpin, spinHeight, -dmax, dmax, 0.05, SIGNAL(valueChanged(double)), SLOT(OnCenterYChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_ScaleSpin, spinHeight, 10, dmax, 20, SIGNAL(valueChanged(double)), SLOT(OnScaleChanged(double)), true, 240, 240, 240); - SetupSpinner(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 100, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0); + SetupSpinner(table, this, row, 1, m_ZoomSpin, spinHeight, 0, 25, 0.2, SIGNAL(valueChanged(double)), SLOT(OnZoomChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_RotateSpin, spinHeight, -180, 180, 10, SIGNAL(valueChanged(double)), SLOT(OnRotateChanged(double)), true, 0, 0, 0); SetupSpinner(table, this, row, 1, m_ZPosSpin, spinHeight, -1000, 1000, 1, SIGNAL(valueChanged(double)), SLOT(OnZPosChanged(double)), true, 0, 1, 0); SetupSpinner(table, this, row, 1, m_PerspectiveSpin, spinHeight, -500, 500, 0.01, SIGNAL(valueChanged(double)), SLOT(OnPerspectiveChanged(double)), true, 0, 1, 0); @@ -63,7 +63,7 @@ void Fractorium::InitParamsUI() //Filter. row = 0; table = ui.FilterTable; - SetupSpinner(table, this, row, 1, m_SpatialFilterWidthSpin, spinHeight, 0.1, 10, 0.1, SIGNAL(valueChanged(double)), SLOT(OnSpatialFilterWidthChanged(double)), true, 1.0, 1.0, 1.0); + SetupSpinner(table, this, row, 1, m_SpatialFilterWidthSpin, spinHeight, 0.1, 2, 0.1, SIGNAL(valueChanged(double)), SLOT(OnSpatialFilterWidthChanged(double)), true, 1.0, 1.0, 1.0); comboVals = SpatialFilterCreator::FilterTypes(); SetupCombo(table, this, row, 1, m_SpatialFilterTypeCombo, comboVals, SIGNAL(currentIndexChanged(const QString&)), SLOT(OnSpatialFilterTypeComboCurrentIndexChanged(const QString&))); SetupSpinner(table, this, row, 1, m_DEFilterMinRadiusSpin, spinHeight, 0, 25, 1, SIGNAL(valueChanged(double)), SLOT(OnDEFilterMinRadiusWidthChanged(double)), true, 0, 0, 0); @@ -116,7 +116,7 @@ void Fractorium::OnBrightnessChanged(double d) { m_Controller->BrightnessChanged /// else if early clip is true, filter and accum, else final accum only. /// /// The gamma value -template void FractoriumEmberController::GammaChanged(double d) { Update([&] { m_Ember.m_Gamma = d; }, true, m_Ember.m_TemporalSamples > 1 ? eProcessAction::FULL_RENDER : (m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY)); } +template void FractoriumEmberController::GammaChanged(double d) { Update([&] { m_Ember.m_Gamma = d; }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); } void Fractorium::OnGammaChanged(double d) { m_Controller->GammaChanged(d); } /// @@ -125,7 +125,7 @@ void Fractorium::OnGammaChanged(double d) { m_Controller->GammaChanged(d); } /// Resets the rendering process to the final accumulation stage. /// /// The gamma threshold -template void FractoriumEmberController::GammaThresholdChanged(double d) { Update([&] { m_Ember.m_GammaThresh = d; }, true, m_Ember.m_TemporalSamples > 1 ? eProcessAction::FULL_RENDER : (m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY)); } +template void FractoriumEmberController::GammaThresholdChanged(double d) { Update([&] { m_Ember.m_GammaThresh = d; }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); } void Fractorium::OnGammaThresholdChanged(double d) { m_Controller->GammaThresholdChanged(d); } /// @@ -134,7 +134,7 @@ void Fractorium::OnGammaThresholdChanged(double d) { m_Controller->GammaThreshol /// Resets the rendering process to the final accumulation stage if temporal samples is 1, else full reset. /// /// The vibrancy -template void FractoriumEmberController::VibrancyChanged(double d) { Update([&] { m_Ember.m_Vibrancy = d; }, true, m_Ember.m_TemporalSamples > 1 ? eProcessAction::FULL_RENDER : (m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY)); } +template void FractoriumEmberController::VibrancyChanged(double d) { Update([&] { m_Ember.m_Vibrancy = d; }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); } void Fractorium::OnVibrancyChanged(double d) { m_Controller->VibrancyChanged(d); } /// @@ -143,7 +143,7 @@ void Fractorium::OnVibrancyChanged(double d) { m_Controller->VibrancyChanged(d); /// Resets the rendering process to the final accumulation stage. /// /// The highlight power -template void FractoriumEmberController::HighlightPowerChanged(double d) { Update([&] { m_Ember.m_HighlightPower = d; }, true, m_Ember.m_TemporalSamples > 1 ? eProcessAction::FULL_RENDER : (m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY)); } +template void FractoriumEmberController::HighlightPowerChanged(double d) { Update([&] { m_Ember.m_HighlightPower = d; }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); } void Fractorium::OnHighlightPowerChanged(double d) { m_Controller->HighlightPowerChanged(d); } /// @@ -286,19 +286,33 @@ void Fractorium::OnDepthBlurChanged(double d) { m_Controller->DepthBlurChanged(d /// /// Set the spatial filter width. /// Called when the spatial filter width spinner is changed. -/// Resets the rendering process. +/// Resets the rendering process to density filtering if early clip is used, else to final accumulation. /// /// The spatial filter width -template void FractoriumEmberController::SpatialFilterWidthChanged(double d) { Update([&] { m_Ember.m_SpatialFilterRadius = d; }); }//Must fully reset because it's used to create bounds. +template void FractoriumEmberController::SpatialFilterWidthChanged(double d) +{ + Update([&] + { + m_Ember.m_SpatialFilterRadius = d; + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); +} + void Fractorium::OnSpatialFilterWidthChanged(double d) { m_Controller->SpatialFilterWidthChanged(d); } /// /// Set the spatial filter type. /// Called when the spatial filter type combo box index is changed. -/// Resets the rendering process. +/// Resets the rendering process to density filtering if early clip is used, else to final accumulation. /// /// The spatial filter type -template void FractoriumEmberController::SpatialFilterTypeChanged(const QString& text) { Update([&] { m_Ember.m_SpatialFilterType = SpatialFilterCreator::FromString(text.toStdString()); }); }//Must fully reset because it's used to create bounds. +template void FractoriumEmberController::SpatialFilterTypeChanged(const QString& text) +{ + Update([&] + { + m_Ember.m_SpatialFilterType = SpatialFilterCreator::FromString(text.toStdString()); + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); +} + void Fractorium::OnSpatialFilterTypeComboCurrentIndexChanged(const QString& text) { m_Controller->SpatialFilterTypeChanged(text); } /// @@ -323,54 +337,61 @@ void Fractorium::OnTemporalFilterTypeComboCurrentIndexChanged(const QString& tex /// /// Set the density estimation filter min radius value. -/// Resets the rendering process. +/// Resets the rendering process to density filtering. /// /// The min radius value template void FractoriumEmberController::DEFilterMinRadiusWidthChanged(double d) { + if (m_Fractorium->m_DEFilterMinRadiusSpin->value() > m_Fractorium->m_DEFilterMaxRadiusSpin->value()) + { + m_Fractorium->m_DEFilterMinRadiusSpin->SetValueStealth(m_Fractorium->m_DEFilterMaxRadiusSpin->value()); + return; + } + Update([&] { - if (m_Fractorium->m_DEFilterMinRadiusSpin->value() > m_Fractorium->m_DEFilterMaxRadiusSpin->value()) - { - m_Fractorium->m_DEFilterMinRadiusSpin->setValue(m_Fractorium->m_DEFilterMaxRadiusSpin->value() - 1); - return; - } - m_Ember.m_MinRadDE = d; - }); + }, true, eProcessAction::FILTER_AND_ACCUM); } void Fractorium::OnDEFilterMinRadiusWidthChanged(double d) { m_Controller->DEFilterMinRadiusWidthChanged(d); } /// /// Set the density estimation filter max radius value. -/// Resets the rendering process. +/// Resets the rendering process to density filtering. /// /// The max radius value template void FractoriumEmberController::DEFilterMaxRadiusWidthChanged(double d) { + if (m_Fractorium->m_DEFilterMaxRadiusSpin->value() < m_Fractorium->m_DEFilterMinRadiusSpin->value()) + { + m_Fractorium->m_DEFilterMaxRadiusSpin->SetValueStealth(m_Fractorium->m_DEFilterMinRadiusSpin->value()); + return; + } + Update([&] { - if (m_Fractorium->m_DEFilterMaxRadiusSpin->value() < m_Fractorium->m_DEFilterMinRadiusSpin->value()) - { - m_Fractorium->m_DEFilterMaxRadiusSpin->setValue(m_Fractorium->m_DEFilterMinRadiusSpin->value() + 1); - return; - } - m_Ember.m_MaxRadDE = d; - }); + }, true, eProcessAction::FILTER_AND_ACCUM); } void Fractorium::OnDEFilterMaxRadiusWidthChanged(double d) { m_Controller->DEFilterMaxRadiusWidthChanged(d); } /// /// Set the density estimation filter curve value. -/// Resets the rendering process. +/// Resets the rendering process to density filtering. /// /// The curve value -template void FractoriumEmberController::DEFilterCurveWidthChanged(double d) { Update([&] { m_Ember.m_CurveDE = d; }); } +template void FractoriumEmberController::DEFilterCurveWidthChanged(double d) +{ + Update([&] + { + m_Ember.m_CurveDE = d; + }, true, eProcessAction::FILTER_AND_ACCUM); +} + void Fractorium::OnDEFilterCurveWidthChanged(double d) { m_Controller->DEFilterCurveWidthChanged(d); } /// diff --git a/Source/Fractorium/FractoriumRender.cpp b/Source/Fractorium/FractoriumRender.cpp index 5ef2c11..fdd0fc8 100644 --- a/Source/Fractorium/FractoriumRender.cpp +++ b/Source/Fractorium/FractoriumRender.cpp @@ -377,7 +377,7 @@ bool FractoriumEmberController::Render() //Change later if better values can be derived/observed. if (m_Renderer->RendererType() == eRendererType::OPENCL_RENDERER) { - if (m_SubBatchCount < (4 * m_Devices.size()))//More than 3 with OpenCL gives a sluggish UI. + if (m_SubBatchCount < (4 * m_Devices.size()))//More than 4 with OpenCL gives a sluggish UI. m_SubBatchCount += m_Devices.size(); } else diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp index db81a4d..c7fbee4 100644 --- a/Source/Fractorium/FractoriumXforms.cpp +++ b/Source/Fractorium/FractoriumXforms.cpp @@ -338,6 +338,7 @@ void FractoriumEmberController::XformNameChanged(int row, int col) xform->m_Name = m_Fractorium->ui.XformWeightNameTable->item(row, col)->text().toStdString(); XformCheckboxAt(index, [&](QCheckBox * checkbox) { checkbox->setText(MakeXformCaption(index)); }); }, eXformUpdate::UPDATE_CURRENT, false); + FillSummary();//Manually update because this does not trigger a render, which is where this would normally be called. } void Fractorium::OnXformNameChanged(int row, int col) { m_Controller->XformNameChanged(row, col); } diff --git a/Source/Fractorium/FractoriumXformsColor.cpp b/Source/Fractorium/FractoriumXformsColor.cpp index 37dfcf0..53f0a50 100644 --- a/Source/Fractorium/FractoriumXformsColor.cpp +++ b/Source/Fractorium/FractoriumXformsColor.cpp @@ -23,12 +23,6 @@ void Fractorium::InitXformsColorUI() m_XformDirectColorSpin->setDecimals(3); connect(ui.XformColorScroll, SIGNAL(valueChanged(int)), this, SLOT(OnXformScrollColorIndexChanged(int)), Qt::QueuedConnection); connect(ui.SoloXformCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSoloXformCheckBoxStateChanged(int)), Qt::QueuedConnection); - connect(ui.ResetCurvesButton, SIGNAL(clicked(bool)), this, SLOT(OnResetCurvesButtonClicked(bool)), Qt::QueuedConnection); - connect(ui.CurvesView, SIGNAL(PointChangedSignal(int, int, const QPointF&)), this, SLOT(OnCurvesPointChanged(int, int, const QPointF&)), Qt::QueuedConnection); - connect(ui.CurvesAllRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesAllRadioButtonToggled(bool)), Qt::QueuedConnection); - connect(ui.CurvesRedRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesRedRadioButtonToggled(bool)), Qt::QueuedConnection); - connect(ui.CurvesGreenRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesGreenRadioButtonToggled(bool)), Qt::QueuedConnection); - connect(ui.CurvesBlueRadio, SIGNAL(toggled(bool)), this, SLOT(OnCurvesBlueRadioButtonToggled(bool)), Qt::QueuedConnection); } /// @@ -147,54 +141,6 @@ void Fractorium::OnXformRefPaletteResized(int logicalIndex, int oldSize, int new SetPaletteTableItem(&pixmap, ui.XformPaletteRefTable, m_PaletteRefItem, 0, 0); } -/// -/// Reset the color curve values in the current ember to their default state and also update the curves control. -/// Called when ResetCurvesButton is clicked. -/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip. -/// -template -void FractoriumEmberController::ClearColorCurves() -{ - Update([&] - { - m_Ember.m_Curves.Init(); - }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); - FillCurvesControl(); -} - -void Fractorium::OnResetCurvesButtonClicked(bool checked) { m_Controller->ClearColorCurves(); } - -/// -/// Set the coordinate of the curve point. -/// Called when the position of any of the points in the curves editor is is changed. -/// Resets the rendering process at either ACCUM_ONLY by default, or FILTER_AND_ACCUM when using early clip. -/// -/// The curve index, 0-1/ -/// The point index within the selected curve, 1-2. -/// The new coordinate of the point in terms of the curves control rect. -template -void FractoriumEmberController::ColorCurveChanged(int curveIndex, int pointIndex, const QPointF& point) -{ - Update([&] - { - m_Ember.m_Curves.m_Points[curveIndex][pointIndex].x = point.x(); - m_Ember.m_Curves.m_Points[curveIndex][pointIndex].y = point.y(); - }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); -} - -void Fractorium::OnCurvesPointChanged(int curveIndex, int pointIndex, const QPointF& point) { m_Controller->ColorCurveChanged(curveIndex, pointIndex, point); } - -/// -/// Set the top most points in the curves control, which makes it easier to -/// select a point by putting it on top of all the others. -/// Called when the any of the curve color radio buttons are toggled. -/// -/// The curve index, 0-1/ -void Fractorium::OnCurvesAllRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::ALL); } -void Fractorium::OnCurvesRedRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::RED); } -void Fractorium::OnCurvesGreenRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::GREEN); } -void Fractorium::OnCurvesBlueRadioButtonToggled(bool checked) { if (checked) ui.CurvesView->SetTop(CurveIndex::BLUE); } - /// /// Look up the passed in index in the current ember's palette /// and return the QColor equivalent. @@ -212,27 +158,6 @@ QColor FractoriumEmberController::ColorIndexToQColor(double d) return QColor::fromRgb(rgb); } -/// -/// Set the points in the curves control to the values of the curve points in the current ember. -/// -template -void FractoriumEmberController::FillCurvesControl() -{ - m_Fractorium->ui.CurvesView->blockSignals(true); - - for (auto i = 0; i < 4; i++) - { - for (auto j = 1; j < 3; j++)//Only do middle points. - { - QPointF point(m_Ember.m_Curves.m_Points[i][j].x, m_Ember.m_Curves.m_Points[i][j].y); - m_Fractorium->ui.CurvesView->Set(i, j, point); - } - } - - m_Fractorium->ui.CurvesView->blockSignals(false); - m_Fractorium->ui.CurvesView->update(); -} - /// /// Set the color index, speed and opacity spinners with the values of the passed in xform. /// Set the cells of the palette ref table as well. @@ -245,7 +170,6 @@ void FractoriumEmberController::FillColorWithXform(Xform* xform) m_Fractorium->m_XformColorSpeedSpin->SetValueStealth(xform->m_ColorSpeed); m_Fractorium->m_XformOpacitySpin->SetValueStealth(xform->m_Opacity); m_Fractorium->m_XformDirectColorSpin->SetValueStealth(xform->m_DirectColor); - FillCurvesControl(); m_Fractorium->OnXformColorIndexChanged(xform->m_ColorX, false);//Had to call stealth before to avoid doing an update, now manually update related controls, still without doing an update. } diff --git a/Source/Fractorium/FractoriumXformsVariations.cpp b/Source/Fractorium/FractoriumXformsVariations.cpp index 65fa502..e4acdda 100644 --- a/Source/Fractorium/FractoriumXformsVariations.cpp +++ b/Source/Fractorium/FractoriumXformsVariations.cpp @@ -97,7 +97,7 @@ void FractoriumEmberController::FilteredVariations() /// Called upon initialization, or controller type change. /// template -void FractoriumEmberController::SetupVariationTree() +void FractoriumEmberController::SetupVariationsTree() { T fMin = TLOW; T fMax = TMAX; diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp index 1592f22..026ed1d 100644 --- a/Source/Fractorium/GLWidget.cpp +++ b/Source/Fractorium/GLWidget.cpp @@ -43,7 +43,7 @@ void GLWidget::InitGL() SetDimensions(w, h); m_Fractorium->m_WidthSpin->setValue(w); m_Fractorium->m_HeightSpin->setValue(h); - //Start with a flock of 10 random embers. Can't do this until now because the window wasn't maximized yet, so the sizes would have been off. + //Start with a flock of random embers. Can't do this until now because the window wasn't maximized yet, so the sizes would have been off. m_Fractorium->OnActionNewFlock(false); m_Fractorium->m_Controller->DelayedStartRenderTimer(); m_Init = true; diff --git a/Source/Fractorium/OptionsDialog.ui b/Source/Fractorium/OptionsDialog.ui index bce1238..df2852d 100644 --- a/Source/Fractorium/OptionsDialog.ui +++ b/Source/Fractorium/OptionsDialog.ui @@ -155,7 +155,7 @@ <html><head/><body><p>Checked: show all xforms while dragging.</p><p>Unchecked: only show current xform while dragging.</p></body></html> - Show All Xforms + Show All Xforms While Dragging @@ -421,7 +421,7 @@ in interactive mode for each mouse movement true - Xml Saving + Xml Render Values @@ -614,7 +614,7 @@ in interactive mode for each mouse movement true - Identity + Xml Identity Values