diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs index 524b061..ed64ad0 100644 --- a/Builds/MSVC/Installer/Product.wxs +++ b/Builds/MSVC/Installer/Product.wxs @@ -13,7 +13,7 @@ - + + /// Assign values to the cached half width/height fields. + /// This is only done manually here and is used when rendering strips + /// because a cached copy of these is required because the real values + /// change with the assignment of each temporary strip ember object. + /// + /// The cached value equal to half of the cartesian width of the x plane + /// The cached value equal to half of the cartesian width of the y plane + void UpdateCachedHalf(T x, T y) + { + m_CachedCarHalfX = x; + m_CachedCarHalfY = y; + } + /// /// Convert a cartesian x, y coordinate to a raster x, y coordinate. /// This will flip the Y coordinate, so points that hit the bottom of the cartesian plane will @@ -237,6 +251,8 @@ public: inline T PadCarUrY() const { return m_PadCarUrY; } inline T CarHalfX() const { return m_CarHalfX; } inline T CarHalfY() const { return m_CarHalfY; } + inline T CachedCarHalfX() const { return m_CachedCarHalfX; } + inline T CachedCarHalfY() const { return m_CachedCarHalfY; } inline T CarCenterX() const { return m_CarCenterX; } inline T CarCenterY() const { return m_CarCenterY; } @@ -251,6 +267,7 @@ private: T m_CarLlX, m_CarLlY, m_CarUrX, m_CarUrY;//The bounds of the cartesian plane. T m_PadCarLlX, m_PadCarLlY, m_PadCarUrX, m_PadCarUrY;//The bounds of the cartesian plane padded by one raster row and column on each side. T m_CarHalfX, m_CarHalfY;//The distance from the center of the of the cartesian plane to the edges. + T m_CachedCarHalfX, m_CachedCarHalfY;//The cahced distance from the center of the of the cartesian plane to the edges, needed when rendering strips. T m_CarCenterX, m_CarCenterY;//The center of the cartesian plane. }; } diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index c44b1be..482aec7 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -1238,8 +1238,8 @@ public: z = m_CamMat[1][2] * point.m_Y + m_CamMat[2][2] * z; zr = Zeps(1 - m_CamPerspective * z); sincos(t, &dsin, &dcos); - T prcx = point.m_X / ctr.CarHalfX(); - T prcy = y / ctr.CarHalfY(); + T prcx = point.m_X / ctr.CachedCarHalfX(); + T prcy = y / ctr.CachedCarHalfY(); T dist = VarFuncs::Hypot(prcx, prcy) * 10; T scale = m_BlurCurve ? (Sqr(dist) / (4 * m_BlurCurve)) : T(1); T dr = rand.Frand01() * (m_BlurCoef * scale) * z; @@ -1262,8 +1262,8 @@ public: T y = m_CamMat[0][1] * point.m_X + m_CamMat[1][1] * point.m_Y + m_CamMat[2][1] * z; z = m_CamMat[0][2] * point.m_X + m_CamMat[1][2] * point.m_Y + m_CamMat[2][2] * z; T zr = Zeps(1 - m_CamPerspective * z); - T prcx = x / ctr.CarHalfX(); - T prcy = y / ctr.CarHalfY(); + T prcx = x / ctr.CachedCarHalfX(); + T prcy = y / ctr.CachedCarHalfY(); T dist = VarFuncs::Hypot(prcx, prcy) * 10; T scale = m_BlurCurve ? (Sqr(dist) / (4 * m_BlurCurve)) : T(1); T dr = rand.Frand01() * (m_BlurCoef * scale) * z; diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index 3867eb9..209b14f 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -43,6 +43,7 @@ void Renderer::AddEmber(Ember& ember) if (m_Embers.size() == 1) m_Ember = m_Embers[0]; }, eProcessAction::FULL_RENDER); + Prepare(); } /// @@ -73,6 +74,21 @@ bool Renderer::AssignIterator() /// Virtual processing functions overriden from RendererBase. /// +/// +/// Prepare values for the filters, bounds, quality and camera. +/// +template +void Renderer::Prepare() +{ + bool b = false; + CreateSpatialFilter(b); + CreateTemporalFilter(b); + ComputeBounds(); + ComputeQuality(); + ComputeCamera(); + m_CarToRas.UpdateCachedHalf(m_CarToRas.CarHalfX(), m_CarToRas.CarHalfY()); +} + /// /// Compute the bounds of the histogram and density filtering buffers. /// These are affected by the final requested dimensions, spatial and density @@ -156,14 +172,7 @@ void Renderer::SetEmber(const Ember& ember, eProcessAction action }, action); if (prep) - { - bool b = false; - CreateSpatialFilter(b); - CreateTemporalFilter(b); - ComputeBounds(); - ComputeQuality(); - ComputeCamera(); - } + Prepare(); } /// @@ -183,7 +192,9 @@ void Renderer::SetEmber(const C& embers) if (!m_Embers.empty()) m_Ember = m_Embers[0]; + }, eProcessAction::FULL_RENDER); + Prepare();//Always prepare with a collection. } /// @@ -204,7 +215,9 @@ void Renderer::MoveEmbers(vector>& embers) if (!m_Embers.empty()) m_Ember = m_Embers[0]; + }, eProcessAction::FULL_RENDER); + Prepare(); } template @@ -217,7 +230,9 @@ void Renderer::SetExternalEmbersPointer(vector>* embers) if (!m_EmbersP->empty()) m_Ember = (*m_EmbersP)[0]; + }, eProcessAction::FULL_RENDER); + Prepare(); } /// @@ -511,6 +526,7 @@ eRenderStatus Renderer::Run(vector& finalImage, double time, si { ComputeQuality(); ComputeCamera(); + //m_CarToRas.UpdateCachedHalf(m_CarToRas.CarHalfX(), m_CarToRas.CarHalfY()); MakeDmap(colorScalar);//For each temporal sample, the palette m_Dmap needs to be re-created with color scalar. 1 if no temporal samples. } diff --git a/Source/Ember/Renderer.h b/Source/Ember/Renderer.h index c654ac1..538b197 100644 --- a/Source/Ember/Renderer.h +++ b/Source/Ember/Renderer.h @@ -55,6 +55,7 @@ public: bool AssignIterator(); //Virtual processing functions overriden from RendererBase. + virtual void Prepare() override; virtual void ComputeBounds() override; virtual void ComputeQuality() override; virtual void ComputeCamera() override; diff --git a/Source/Ember/RendererBase.h b/Source/Ember/RendererBase.h index 06ae94f..976b989 100644 --- a/Source/Ember/RendererBase.h +++ b/Source/Ember/RendererBase.h @@ -121,6 +121,7 @@ public: virtual bool CreateDEFilter(bool& newAlloc) = 0; virtual bool CreateSpatialFilter(bool& newAlloc) = 0; virtual bool CreateTemporalFilter(bool& newAlloc) = 0; + virtual void Prepare() = 0; virtual void ComputeBounds() = 0; virtual void ComputeQuality() = 0; virtual void ComputeCamera() = 0; diff --git a/Source/Ember/SheepTools.h b/Source/Ember/SheepTools.h index c87f196..3588517 100644 --- a/Source/Ember/SheepTools.h +++ b/Source/Ember/SheepTools.h @@ -850,7 +850,7 @@ public: adjustedEmber.m_FinalRasH = static_cast(std::ceil(ember.m_FinalRasH * scalar)); adjustedEmber.m_PixelsPerUnit *= scalar; adjustedEmber.m_TemporalSamples = 1; - m_Renderer->SetEmber(adjustedEmber); + m_Renderer->SetEmber(adjustedEmber, eProcessAction::FULL_RENDER, true); m_Renderer->EarlyClip(true); if (m_Renderer->Run(m_FinalImage) != eRenderStatus::RENDER_OK) diff --git a/Source/Ember/SpatialFilter.h b/Source/Ember/SpatialFilter.h index a0fffe1..616676d 100644 --- a/Source/Ember/SpatialFilter.h +++ b/Source/Ember/SpatialFilter.h @@ -229,14 +229,19 @@ private: for (i = 0; i < m_Filter.size(); i++) t += m_Filter[i]; - if (t == 0.0) + if (t == 0.0 || std::isinf(t) || std::isnan(t) || !std::isnormal(t)) return false; - t = T(1.0) / t; + t = T(1.0 / t); for (i = 0; i < m_Filter.size(); i++) + { m_Filter[i] *= t; + if (std::isinf(t) || std::isnan(t) || !std::isnormal(t)) + return false; + } + return true; } @@ -271,9 +276,9 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { - return std::exp(-2 * t * t) * std::sqrt(2 / T(M_PI)); + return T(std::exp(-2 * t * t) * std::sqrt(2 / M_PI)); } }; @@ -300,13 +305,13 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < 0) t = -t; if (t < 1) - return ((T(2.0) * t - T(3.0)) * t * t + T(1.0)); + return T((2.0 * t - 3.0) * t * t + 1.0); return 0; } @@ -334,7 +339,7 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if ((t > T(-0.5)) && (t <= T(0.5))) return 1; @@ -365,7 +370,7 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < 0) t = -t; @@ -399,19 +404,19 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { //box (*) box (*) box. if (t < 0) t = -t; if (t < T(0.5)) - return (T(0.75) - (t * t)); + return T(0.75 - (t * t)); if (t < T(1.5)) { - t = (t - T(1.5)); - return (T(0.5) * (t * t)); + t = T(t - 1.5); + return T(0.5 * (t * t)); } return 0; @@ -440,7 +445,7 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { //box (*) box (*) box (*) box. T tt; @@ -451,12 +456,12 @@ public: if (t < 1) { tt = t * t; - return ((T(0.5) * tt * t) - tt + (T(2.0) / T(3.0))); + return T((0.5 * tt * t) - tt + (2.0 / 3.0)); } else if (t < 2) { t = 2 - t; - return ((T(1.0) / T(6.0)) * (t * t * t)); + return T((1.0 / 6.0) * (t * t * t)); } return 0; @@ -485,7 +490,7 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < 0) t = -t; @@ -519,7 +524,7 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < 0) t = -t; @@ -553,28 +558,28 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { T tt = t * t; - const T b = T(1) / T(3); - const T c = T(1) / T(3); + const T b = T(1.0 / 3.0); + const T c = T(1.0 / 3.0); if (t < 0) t = -t; if (t < 1) { - t = (((T(12.0) - T(9.0) * b - T(6.0) * c) * (t * tt)) - + ((T(-18.0) + T(12.0) * b + T(6.0) * c) * tt) - + (T(6.0) - 2 * b)); + t = T(((12.0 - 9.0 * b - 6.0 * c) * (t * tt)) + + ((-18.0 + 12.0 * b + 6.0 * c) * tt) + + (6.0 - 2 * b)); return t / 6; } else if (t < 2) { - t = (((T(-1.0) * b - T(6.0) * c) * (t * tt)) - + ((T(6.0) * b + T(30.0) * c) * tt) - + ((T(-12.0) * b - T(48.0) * c) * t) - + (T(8.0) * b + 24 * c)); + t = T(((-1.0 * b - 6.0 * c) * (t * tt)) + + ((6.0 * b + 30.0 * c) * tt) + + ((-12.0 * b - 48.0 * c) * t) + + (8.0 * b + 24 * c)); return t / 6; } @@ -604,9 +609,9 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { - return (T(0.42) + T(0.5) * std::cos(T(M_PI) * t) + T(0.08) * std::cos(2 * T(M_PI) * t)); + return T(0.42 + 0.5 * std::cos(M_PI * t) + 0.08 * std::cos(2 * M_PI * t)); } }; @@ -632,22 +637,22 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < 0) return 0; if (t < -1) - return T(0.5) * (4 + t * (8 + t * (5 + t))); + return T(0.5 * (4 + t * (8 + t * (5 + t)))); if (t < 0) - return T(0.5) * (2 + t * t * (-5 - 3 * t)); + return T(0.5 * (2 + t * t * (-5 - 3 * t))); if (t < 1) - return T(0.5) * (2 + t * t * (-5 + 3 * t)); + return T(0.5 * (2 + t * t * (-5 + 3 * t))); if (t < 2) - return T(0.5) * (4 + t * (-8 + t * (5 - t))); + return T(0.5 * (4 + t * (-8 + t * (5 - t)))); return 0; } @@ -675,9 +680,9 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { - return T(0.54) + T(0.46) * std::cos(T(M_PI) * t); + return T(0.54 + 0.46 * std::cos(M_PI * t)); } }; @@ -703,9 +708,9 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { - return T(0.5) + T(0.5) * std::cos(T(M_PI) * t); + return T(0.5 + 0.5 * std::cos(M_PI * t)); } }; @@ -731,19 +736,19 @@ public: /// /// The value to apply the filter to /// The filtered value - virtual T Filter(T t) const + virtual T Filter(T t) const override { if (t < -1.5) return 0.0; if (t < -0.5) - return T(0.5) * (t + T(1.5)) * (t + T(1.5)); + return T(0.5 * (t + 1.5) * (t + 1.5)); if (t < 0.5) - return T(0.75) - (t * t); + return T(0.75 - (t * t)); if (t < 1.5) - return T(0.5) * (t - T(1.5)) * (t - T(1.5)); + return T(0.5 * (t - 1.5) * (t - 1.5)); return 0; } diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index fbb8e9b..6fc36b1 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -1884,8 +1884,8 @@ void RendererCL::ConvertCarToRas(const CarToRas& carToRas) m_CarToRasCL.m_CarLlY = carToRas.CarLlY(); m_CarToRasCL.m_CarUrX = carToRas.CarUrX(); m_CarToRasCL.m_CarUrY = carToRas.CarUrY(); - m_CarToRasCL.m_CarHalfX = carToRas.CarHalfX(); - m_CarToRasCL.m_CarHalfY = carToRas.CarHalfY(); + m_CarToRasCL.m_CarHalfX = carToRas.CachedCarHalfX(); + m_CarToRasCL.m_CarHalfY = carToRas.CachedCarHalfY(); m_CarToRasCL.m_CarCenterX = carToRas.CarCenterX(); m_CarToRasCL.m_CarCenterY = carToRas.CarCenterY(); } diff --git a/Source/EmberCommon/EmberCommon.h b/Source/EmberCommon/EmberCommon.h index 710764e..2b3f523 100644 --- a/Source/EmberCommon/EmberCommon.h +++ b/Source/EmberCommon/EmberCommon.h @@ -597,6 +597,9 @@ static vector>> CreateRenderers(eRendererType rend /// /// Perform a render which allows for using strips or not. /// If an error occurs while rendering any strip, the rendering process stops. +/// Note this must be called after SetEmber(ember, eProcessAction::FULL_RENDER, true) is called on the renderer. +/// The last parameter to SetEmber must be true to compute the camera, because is caches certain values that need to be +/// retained between strips. /// /// The renderer to use /// The ember to render diff --git a/Source/EmberGenome/EmberGenome.cpp b/Source/EmberGenome/EmberGenome.cpp index 3023261..5008489 100644 --- a/Source/EmberGenome/EmberGenome.cpp +++ b/Source/EmberGenome/EmberGenome.cpp @@ -781,7 +781,7 @@ bool EmberGenome(int argc, _TCHAR* argv[], EmberOptions& opt) orig.m_Edits = emberToXml.CreateNewEditdoc(aselp0, aselp1, os.str(), opt.Nick(), opt.Url(), opt.Id(), opt.Comment(), opt.SheepGen(), opt.SheepId()); save = orig; SetDefaultTestValues(orig); - renderer->SetEmber(orig); + renderer->SetEmber(orig, eProcessAction::FULL_RENDER, true); if (renderer->Run(finalImage) != eRenderStatus::RENDER_OK) { diff --git a/Source/EmberRender/EmberRender.cpp b/Source/EmberRender/EmberRender.cpp index c1fedb5..5efe75e 100644 --- a/Source/EmberRender/EmberRender.cpp +++ b/Source/EmberRender/EmberRender.cpp @@ -219,7 +219,7 @@ bool EmberRender(int argc, _TCHAR* argv[], EmberOptions& opt) } stats.Clear(); - renderer->SetEmber(ember); + renderer->SetEmber(ember, eProcessAction::FULL_RENDER, true); renderer->PrepFinalAccumVector(finalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run(). if (opt.Strips() > 1) diff --git a/Source/EmberTester/EmberTester.cpp b/Source/EmberTester/EmberTester.cpp index 6e17a15..6f3d661 100644 --- a/Source/EmberTester/EmberTester.cpp +++ b/Source/EmberTester/EmberTester.cpp @@ -1745,7 +1745,7 @@ bool TestAllVarsCLBuild(size_t platform, size_t device, bool printSuccess = true for (auto& it : embers) { - renderer.SetEmber(it); + renderer.SetEmber(it, eProcessAction::FULL_RENDER, true); //if (platform != 0 && // ((it.GetXform(0)->GetVariationById(eVariationId::VAR_SYNTH) != nullptr) ||//Nvidia OpenCL driver crashes when building too many synths. diff --git a/Source/Fractorium/FinalRenderEmberController.cpp b/Source/Fractorium/FinalRenderEmberController.cpp index b3b966e..91aab97 100644 --- a/Source/Fractorium/FinalRenderEmberController.cpp +++ b/Source/Fractorium/FinalRenderEmberController.cpp @@ -267,7 +267,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD Output("Image " + ToString(m_FinishedImageCount.load() + 1) + ":\n" + ComposePath(QString::fromStdString(it.m_Name))); it.m_TemporalSamples = 1;//No temporal sampling. - m_Renderer->SetEmber(it); + m_Renderer->SetEmber(it, eProcessAction::FULL_RENDER, true); m_Renderer->PrepFinalAccumVector(m_FinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run(). m_Stats.Clear(); m_RenderTimer.Tic();//Toc() is called in RenderComplete(). @@ -298,7 +298,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD m_ImageCount = 1; m_Ember->m_TemporalSamples = 1; m_Fractorium->m_Controller->ParamsToEmber(*m_Ember, true);//Update color and filter params from the main window controls, which only affect the filter and/or final accumulation stage. - m_Renderer->SetEmber(*m_Ember, isBump ? eProcessAction::KEEP_ITERATING : eProcessAction::FULL_RENDER); + m_Renderer->SetEmber(*m_Ember, isBump ? eProcessAction::KEEP_ITERATING : eProcessAction::FULL_RENDER, true); m_Renderer->PrepFinalAccumVector(m_FinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run(). m_Stats.Clear(); Output(ComposePath(QString::fromStdString(m_Ember->m_Name))); @@ -1130,7 +1130,7 @@ void FinalRenderPreviewRenderer::PreviewRenderFunc(uint start, uint end) m_PreviewRenderer.EarlyClip(d->EarlyClip()); m_PreviewRenderer.YAxisUp(d->YAxisUp()); m_PreviewRenderer.Callback(nullptr); - m_PreviewRenderer.SetEmber(m_PreviewEmber); + m_PreviewRenderer.SetEmber(m_PreviewEmber, eProcessAction::FULL_RENDER, true); m_PreviewRenderer.PrepFinalAccumVector(m_PreviewFinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run(). auto strips = VerifyStrips(m_PreviewEmber.m_FinalRasH, d->Strips(), [&](const string & s) {}, [&](const string & s) {}, [&](const string & s) {}); diff --git a/Source/Fractorium/FractoriumEmberController.cpp b/Source/Fractorium/FractoriumEmberController.cpp index 2547fbb..f3f0c07 100644 --- a/Source/Fractorium/FractoriumEmberController.cpp +++ b/Source/Fractorium/FractoriumEmberController.cpp @@ -391,7 +391,7 @@ void TreePreviewRenderer::PreviewRenderFunc(uint start, uint end) m_PreviewEmber.m_TemporalSamples = 1; m_PreviewEmber.m_Quality = 25; m_PreviewEmber.m_Supersample = 1; - m_PreviewRenderer.SetEmber(m_PreviewEmber); + m_PreviewRenderer.SetEmber(m_PreviewEmber, eProcessAction::FULL_RENDER, true); if (m_PreviewRenderer.Run(m_PreviewFinalImage) == eRenderStatus::RENDER_OK) { diff --git a/Source/Fractorium/FractoriumRender.cpp b/Source/Fractorium/FractoriumRender.cpp index 75d097e..a756b7a 100644 --- a/Source/Fractorium/FractoriumRender.cpp +++ b/Source/Fractorium/FractoriumRender.cpp @@ -373,7 +373,7 @@ bool FractoriumEmberController::Render() } i = 0; - m_Renderer->SetEmber(m_Ember, action); + m_Renderer->SetEmber(m_Ember, action, true); if (solo != -1) while (auto xform = m_Ember.GetTotalXform(i, forceFinal)) diff --git a/Source/Fractorium/Main.cpp b/Source/Fractorium/Main.cpp index 8988a87..2042b4e 100644 --- a/Source/Fractorium/Main.cpp +++ b/Source/Fractorium/Main.cpp @@ -8,9 +8,9 @@ /// void ExportUserData() { - auto exec = new QProcess(); - exec->setWorkingDirectory(QCoreApplication::applicationDirPath()); - exec->start("/bin/sh", QStringList() << "fractorium-sh"); + auto exec = new QProcess(); + exec->setWorkingDirectory(QCoreApplication::applicationDirPath()); + exec->start("/bin/sh", QStringList() << "fractorium-sh"); } #endif @@ -56,8 +56,8 @@ int main(int argc, char* argv[]) Fractorium w; w.show(); #ifdef __APPLE__ - // exporting user data - ExportUserData(); + // exporting user data + ExportUserData(); #endif a.installEventFilter(&w); rv = a.exec(); diff --git a/debian/changelog b/debian/changelog index 09485b7..83610be 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +fractorium (1.0.0.19d-0ubuntu1) bionic; urgency=low + + * release 1.0.0.19 + + -- Matt Feemster Wed, 18 Mar 2020 19:25:25 -0700 + fractorium (1.0.0.19c-0ubuntu1) bionic; urgency=low * release 1.0.0.19