#pragma once #include "Ember.h" #include "Iterator.h" #include "Utils.h" #include "SpatialFilter.h" #include "DensityFilter.h" #include "TemporalFilter.h" #include "Interpolate.h" #include "CarToRas.h" #include "EmberToXml.h" /// /// Renderer, RenderCallback and EmberStats classes. /// namespace EmberNs { /// /// Function pointers present a major restriction when dealing /// with member functions, and that is they can only point to /// static ones. So instead of a straight function pointer, use /// a callback class with a single virtual callback /// member function. /// Template argument expected to be float or double. /// class EMBER_API RenderCallback { public: /// /// Virtual destructor to ensure anything declared in derived classes gets cleaned up. /// virtual ~RenderCallback() { } /// /// Empty progress function to be implemented in derived classes to take action on progress updates. /// /// The ember currently being rendered /// An extra dummy parameter /// The progress fraction from 0-100 /// The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation. /// The estimated milliseconds to completion of the current stage /// Override should return 0 if an abort is requested, else 1 to continue rendering virtual int ProgressFunc(Ember& ember, void* foo, double fraction, int stage, double etaMs) { return 0; } virtual int ProgressFunc(Ember& ember, void* foo, double fraction, int stage, double etaMs) { return 0; } }; /// /// Render statistics for the number of iterations ran, /// number of bad values calculated during iteration, and /// the total time for the entire render from the start of /// iteration to the end of final accumulation. /// class EMBER_API EmberStats { public: /// /// Constructor which sets all values to 0. /// EmberStats() { Clear(); } void Clear() { m_Iters = 0; m_Badvals = 0; m_IterMs = 0; m_RenderMs = 0; } unsigned __int64 m_Iters, m_Badvals; double m_IterMs, m_RenderMs; }; /// /// The types of available renderers. /// Add more in the future as different rendering methods are experimented with. /// Possible values might be: CPU+OpenGL, Particle, Inverse. /// enum eRendererType { CPU_RENDERER, OPENCL_RENDERER }; /// /// A base class with virtual functions to allow both templating and polymorphism to work together. /// Derived classes will implement all of these functions. /// Note that functions which return a decimal number use the most precise type, double. /// class EMBER_API RendererBase : public EmberReport { public: RendererBase() { } virtual ~RendererBase() { } virtual void SetEmber(Ember& ember, eProcessAction action = FULL_RENDER) { } virtual void SetEmber(vector>& embers) { } virtual void SetEmber(Ember& ember, eProcessAction action = FULL_RENDER) { } virtual void SetEmber(vector>& embers) { } virtual void Callback(RenderCallback* callback) { } virtual bool CreateSpatialFilter(bool& newAlloc) { return false; } virtual bool CreateTemporalFilter(bool& newAlloc) { return false; } virtual void ComputeBounds() { } virtual bool Ok() const { return false; } virtual void Reset() { } virtual void EnterRender() { } virtual void LeaveRender() { } virtual void EnterFinalAccum() { } virtual void LeaveFinalAccum() { } virtual void EnterResize() { } virtual void LeaveResize() { } virtual void Abort() { } virtual bool Aborted() { return false; } virtual bool InRender() { return false; } virtual bool InFinalAccum() { return false; } virtual unsigned int NumChannels() const { return 0; } virtual void NumChannels(unsigned int numChannels) { } virtual eRendererType RendererType() const { return CPU_RENDERER; } virtual void ReclaimOnResize(bool reclaimOnResize) { } virtual bool EarlyClip() const { return false; } virtual void EarlyClip(bool earlyClip) { } virtual bool YAxisUp() const { return false; } virtual void YAxisUp(bool yup) { } virtual void ThreadCount(unsigned int threads, const char* seedString = NULL) { } virtual void Transparency(bool transparency) { } virtual void InteractiveFilter(eInteractiveFilter filter) { } virtual unsigned int FinalRasW() const { return 0; } virtual unsigned int FinalRasH() const { return 0; } virtual unsigned int SuperRasW() const { return 0; } virtual unsigned int SuperRasH() const { return 0; } virtual unsigned int FinalBufferSize() const { return 0; } virtual unsigned int GutterWidth() const { return 0; } virtual double ScaledQuality() const { return 0; } virtual double LowerLeftX(bool gutter = true) const { return 0; } virtual double LowerLeftY(bool gutter = true) const { return 0; } virtual double UpperRightX(bool gutter = true) const { return 0; } virtual double UpperRightY(bool gutter = true) const { return 0; } virtual unsigned __int64 MemoryRequired(bool includeFinal) { return 0; } virtual unsigned __int64 MemoryAvailable() { return 0; } virtual bool PrepFinalAccumVector(vector& pixels) { return false; } virtual eProcessState ProcessState() const { return NONE; } virtual eProcessAction ProcessAction() const { return NOTHING; } virtual EmberStats Stats() const { EmberStats stats; return stats; } virtual eRenderStatus Run(vector& finalImage, double time = 0, unsigned int subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) { return RENDER_ERROR; } virtual EmberImageComments ImageComments(unsigned int printEditDepth = 0, bool intPalette = false, bool hexPalette = true) { EmberImageComments comments; return comments; } virtual DensityFilterBase* GetDensityFilter() { return NULL; } }; /// /// Renderer is the main class where all of the execution takes place. /// It is intended that the program have one instance of it that it /// keeps around for its duration. After a user sets up an ember, it's passed /// in to be rendered. /// This class derives from EmberReport, so the caller is able /// to retrieve a text dump of error information if any errors occur. /// The final image output vector is also passed in because the calling code has more /// use for it than this class does. /// Several functions are made virtual and have a default CPU-based implementation /// that roughly matches what flam3 did. However they can be overriden in derived classes /// to provide alternative rendering implementations, such as using the GPU. /// Since this is a templated class, it's supposed to be entirely implemented in this .h file. /// However, VC++ 2010 has very crippled support for lambdas, which Renderer makes use of. /// If too many lambdas are used in a .h file, it will crash the compiler when another library /// tries to link to it. To work around the bug, only declarations are here and all implementations /// are in the .cpp file. It's unclear at what point it starts/stops working. But it seems that once /// enough code is placed in the .h file, the compiler crashes. So for the sake of consistency, everything /// is moved to the .cpp, even simple getters. One drawback however, is that the class must be /// explicitly exported at the bottom of the file. /// Also, despite explicitly doing this, the compiler throws a C4661 warning /// for every single function in this class, saying it can't find the implementation. This warning /// can be safely ignored. /// Template argument T expected to be float or double. /// Template argument bucketT was originally used to experiment with different types for the histogram, however /// the only types that work are float and double, so it's useless and should always match what T is. /// Mismatched types between T and bucketT are undefined. /// template class EMBER_API Renderer : public RendererBase { public: Renderer(); virtual ~Renderer(); virtual void ComputeBounds(); void ComputeCamera(); void ChangeVal(std::function func, eProcessAction action); virtual void SetEmber(Ember& ember, eProcessAction action = FULL_RENDER); virtual void SetEmber(vector>& embers); void AddEmber(Ember& ember); bool CreateTemporalFilter(bool& newAlloc); bool AssignIterator(); virtual bool PrepFinalAccumVector(vector& pixels); virtual eRenderStatus Run(vector& finalImage, double time = 0, unsigned int subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0); virtual EmberImageComments ImageComments(unsigned int printEditDepth = 0, bool intPalette = false, bool hexPalette = true); virtual unsigned __int64 MemoryRequired(bool includeFinal); //Virtual functions to be overriden in derived renderers that use the GPU. virtual unsigned __int64 MemoryAvailable(); virtual void Reset(); virtual bool Ok() const; virtual bool CreateDEFilter(bool& newAlloc); virtual bool CreateSpatialFilter(bool& newAlloc); virtual unsigned int SubBatchSize() const; virtual void SubBatchSize(unsigned int sbs); virtual unsigned int NumChannels() const; virtual void NumChannels(unsigned int numChannels); virtual eRendererType RendererType() const; virtual unsigned int ThreadCount() const; virtual void ThreadCount(unsigned int threads, const char* seedString = NULL); virtual void Callback(RenderCallback* callback); protected: //Virtual functions to be overriden in derived renderers that use the GPU, but not accessed outside. virtual void MakeDmap(T colorScalar); virtual bool Alloc(); virtual bool ResetBuckets(bool resetHist = true, bool resetAccum = true); virtual eRenderStatus LogScaleDensityFilter(); virtual eRenderStatus GaussianDensityFilter(); virtual eRenderStatus AccumulatorToFinalImage(vector& pixels, size_t finalOffset); virtual eRenderStatus AccumulatorToFinalImage(unsigned char* pixels, size_t finalOffset); virtual EmberStats Iterate(unsigned __int64 iterCount, unsigned int pass, unsigned int temporalSample); public: //Accessors for render properties. vector> RandVec(); bool RandVec(vector>& randVec); inline bool LockAccum() const; void LockAccum(bool lockAccum); virtual bool EarlyClip() const; virtual void EarlyClip(bool earlyClip); virtual bool YAxisUp() const; virtual void YAxisUp(bool yup); inline bool InsertPalette() const; void InsertPalette(bool insertPalette); inline bool ReclaimOnResize() const; virtual void ReclaimOnResize(bool reclaimOnResize); inline bool Transparency() const; virtual void Transparency(bool transparency); inline unsigned int BytesPerChannel() const; void BytesPerChannel(unsigned int bytesPerChannel); inline T PixelAspectRatio() const; void PixelAspectRatio(T pixelAspectRatio); inline eInteractiveFilter InteractiveFilter() const; virtual void InteractiveFilter(eInteractiveFilter filter); //Threading control. virtual void EnterRender(); virtual void LeaveRender(); virtual void EnterFinalAccum(); virtual void LeaveFinalAccum(); virtual void EnterResize(); virtual void LeaveResize(); virtual void Abort(); virtual bool Aborted(); virtual bool InRender(); virtual bool InFinalAccum(); //Renderer properties, getters only. virtual unsigned int SuperRasW() const; virtual unsigned int SuperRasH() const; inline unsigned int SuperSize() const; virtual unsigned int FinalBufferSize() const; inline unsigned int FinalRowSize() const; inline unsigned int FinalDimensions() const; inline unsigned int PixelSize() const; virtual unsigned int GutterWidth() const; inline unsigned int DensityFilterOffset() const; virtual double ScaledQuality() const; inline T Scale() const; inline T PixelsPerUnitX() const; inline T PixelsPerUnitY() const; virtual double LowerLeftX(bool gutter = true) const; virtual double LowerLeftY(bool gutter = true) const; virtual double UpperRightX(bool gutter = true) const; virtual double UpperRightY(bool gutter = true) const; inline T K1() const; inline T K2() const; inline unsigned __int64 TotalIterCount() const; inline unsigned __int64 ItersPerTemporalSample() const; virtual eProcessState ProcessState() const; virtual eProcessAction ProcessAction() const; virtual EmberStats Stats() const; inline const CarToRas* CoordMap() const; inline glm::detail::tvec4* HistBuckets(); inline glm::detail::tvec4* AccumulatorBuckets(); inline SpatialFilter* GetSpatialFilter(); inline TemporalFilter* GetTemporalFilter(); virtual DensityFilter* GetDensityFilter(); //Ember wrappers, getters only. inline bool XaosPresent(); virtual inline unsigned int FinalRasW() const; virtual inline unsigned int FinalRasH() const; inline unsigned int Supersample() const; inline unsigned int Passes() const; inline unsigned int TemporalSamples() const; inline unsigned int PaletteIndex() const; inline T Time() const; inline T Quality() const; inline T SpatialFilterRadius() const; inline T PixelsPerUnit() const; inline T Zoom() const; inline T CenterX() const; inline T CenterY() const; inline T Rotate() const; inline T Hue() const; inline T Brightness() const; inline T Contrast() const; inline T Gamma() const; inline T Vibrancy() const; inline T GammaThresh() const; inline T HighlightPower() const; inline Color Background() const; inline const Xform* Xforms() const; inline Xform* NonConstXforms(); inline unsigned int XformCount() const; inline const Xform* FinalXform() const; inline Xform* NonConstFinalXform(); inline bool UseFinalXform() const; inline const Palette* GetPalette() const; inline ePaletteMode PaletteMode() const; //Iterator wrappers. const unsigned char* XformDistributions() const; const unsigned int XformDistributionsSize() const; Point* Samples(unsigned int threadIndex) const; void* m_ProgressParameter; protected: //Non-virtual functions that might be needed by a derived class. void PrepFinalAccumVals(Color& background, T& g, T& linRange, T& vibrancy); private: //Miscellaneous functions used only in this class. void Accumulate(Point* samples, unsigned int sampleCount, const Palette* palette); inline void AddToAccum(const glm::detail::tvec4& bucket, int i, int ii, int j, int jj); template void GammaCorrection(glm::detail::tvec4& bucket, Color& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels); protected: bool m_EarlyClip; bool m_YAxisUp; bool m_Transparency; unsigned int m_SuperRasW; unsigned int m_SuperRasH; unsigned int m_SuperSize; unsigned int m_GutterWidth; unsigned int m_DensityFilterOffset; unsigned int m_NumChannels; unsigned int m_BytesPerChannel; unsigned int m_SubBatchSize; unsigned int m_ThreadsToUse; T m_ScaledQuality; T m_Scale; T m_PixelsPerUnitX; T m_PixelsPerUnitY; T m_PixelAspectRatio; T m_LowerLeftX; T m_LowerLeftY; T m_UpperRightX; T m_UpperRightY; T m_K1; T m_K2; T m_Vibrancy;//Accumulate these after each temporal sample. T m_Gamma; Color m_Background; Affine2D m_RotMat; volatile bool m_Abort; bool m_LockAccum; bool m_InRender; bool m_InFinalAccum; bool m_InsertPalette; bool m_ReclaimOnResize; unsigned int m_VibGamCount; unsigned int m_LastPass; unsigned int m_LastTemporalSample; unsigned __int64 m_LastIter; double m_LastIterPercent; eProcessAction m_ProcessAction; eProcessState m_ProcessState; eInteractiveFilter m_InteractiveFilter; EmberStats m_Stats; Ember m_Ember; Ember m_TempEmber; Ember m_LastEmber; vector> m_Embers; CarToRas m_CarToRas; RenderCallback* m_Callback; Iterator* m_Iterator; auto_ptr> m_StandardIterator; auto_ptr> m_XaosIterator; Palette m_Dmap; vector> m_HistBuckets; vector> m_AccumulatorBuckets; auto_ptr> m_SpatialFilter; auto_ptr> m_TemporalFilter; auto_ptr> m_DensityFilter; vector>> m_Samples; vector m_SubBatch; vector m_BadVals; vector> m_Rand; tbb::task_group m_TaskGroup; CriticalSection m_RenderingCs, m_AccumCs, m_FinalAccumCs, m_ResizeCs; Timing m_RenderTimer, m_IterTimer, m_ProgressTimer; EmberToXml m_EmberToXml; }; //This class had to be implemented in a cpp file because the compiler was breaking. //So the explicit instantiation must be declared here rather than in Ember.cpp where //all of the other classes are done. template EMBER_API class Renderer; #ifdef DO_DOUBLE template EMBER_API class Renderer; #endif }