Unit.h

00001 /***************************************************************************
00002  *   Copyright (c) 2008   Art Tevs                                         *
00003  *                                                                         *
00004  *   This library is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU Lesser General Public License as        *
00006  *   published by the Free Software Foundation; either version 3 of        *
00007  *   the License, or (at your option) any later version.                   *
00008  *                                                                         *
00009  *   This library is distributed in the hope that it will be useful,       *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00012  *   GNU Lesse General Public License for more details.                    *
00013  *                                                                         *
00014  *   The full license is in LICENSE file included with this distribution.  *
00015  ***************************************************************************/
00016 
00017 #ifndef _C_UNIT_H_
00018 #define _C_UNIT_H_
00019 
00020 
00021 //-------------------------------------------------------------------------
00022 // Includes
00023 //-------------------------------------------------------------------------
00024 #include <osg/Texture>
00025 #include <osg/Geode>
00026 #include <osg/Geometry>
00027 #include <osg/BufferObject>
00028 #include <osg/FrameBufferObject>
00029 
00030 #include <osgPPU/Export.h>
00031 #include <osgPPU/ColorAttribute.h>
00032 
00033 #define OSGPPU_VIEWPORT_WIDTH_UNIFORM "osgppu_ViewportWidth"
00034 #define OSGPPU_VIEWPORT_HEIGHT_UNIFORM "osgppu_ViewportHeight"
00035 #define OSGPPU_VIEWPORT_INV_WIDTH_UNIFORM "osgppu_InvViewportWidth"
00036 #define OSGPPU_VIEWPORT_INV_HEIGHT_UNIFORM "osgppu_InvViewportHeight"
00037 
00038 namespace osgPPU
00039 {
00040 
00041 // Forward declaration to simplify the work
00042 class Processor;
00043 class Visitor;
00044 
00045 //! Abstract base class of any unit
00046 /**
00047  * Units represents renderable units of the osgPPU library.
00048  * Each unit has its own functionality. Units can be setted up
00049  * as a graph, where child units always get as input the output of the
00050  * parental units. Units has to be a subgraph of the Processor otherwise
00051  * the rendering wouldn't work, because processor do setup the units in a proper way.
00052  *
00053  **/
00054 class OSGPPU_EXPORT Unit : public osg::Group {
00055     public:
00056 
00057         META_Node(osgPPU, Unit);
00058 
00059         typedef std::map<int, osg::ref_ptr<osg::Texture> > TextureMap;
00060         typedef std::vector<unsigned int> IgnoreInputList;
00061         typedef std::map<osg::ref_ptr<Unit>, std::pair<std::string, unsigned int> > InputToUniformMap;
00062         typedef std::map<int, osg::ref_ptr<osg::PixelDataBufferObject> > PixelDataBufferObjectMap;
00063 
00064         /**
00065         * Empty constructor. The unit will be initialized with default values.
00066         **/
00067         Unit();
00068 
00069         /**
00070          * Copy constructor.
00071         **/
00072         Unit(const Unit&, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
00073 
00074         /**
00075         * Release used memory by the ppu.
00076         **/
00077         virtual ~Unit();
00078 
00079         /**
00080         * Set an input from the given parent to be linked with the given
00081         * uniform name. This is required to automatically setup uniforms for
00082         * input textures of the assigned shader, which is based on the index
00083         * of the given parent unit in the parent list.
00084         * The type of the given uniform will be equivalent to the type of the
00085         * input texture (e.g. SAMPLER_2D = Texture2D).
00086         * @param parent Pointer to the parent which output to use
00087         * @param uniform Name of the uniform to use to bind the texture to
00088         * @param add if true will add the given parent to the parent list
00089         *             (same as calling parent->addChild()) [default=false]
00090         * @return true if uniform is set or false otherwise
00091         **/
00092         bool setInputToUniform(Unit* parent, const std::string& uniform, bool add = false);
00093 
00094         /**
00095         * Set input texture of this unit as uniform of this unit.
00096         * @param index Input texture index to be used as input
00097         * @param uniform Name of the uniform
00098         **/
00099         bool setInputToUniform(int index, const std::string& uniform);
00100 
00101         /**
00102         * Remove an assigned parent output uniform. @see assignParentToUniform()
00103         * @param uniform Name of the uniform
00104         * @param del Should this unit be removed from the child list of the parent
00105         * connected with the given uniform [default=false]
00106         **/
00107         void removeInputToUniform(const std::string& uniform, bool del = false);
00108 
00109         /**
00110         * Remove an assigned parent output uniform. @see assignParentToUniform()
00111         * @param parent Pointer to the parent node
00112         * @param del Should this unit be removed from the child list of this parent [default=false]
00113         **/
00114         void removeInputToUniform(Unit* parent, bool del = false);
00115 
00116         /**
00117         * Get the map which maps uniform to input units
00118         **/
00119         inline const InputToUniformMap& getInputToUniformMap() const { return mInputToUniformMap; }
00120 
00121         /**
00122          * Return an input texture of a certain index.
00123          * @param inputIndex Index of the input texture (index is equal to the texture unit)
00124         **/
00125         inline osg::Texture* getInputTexture(int inputIndex) { return mInputTex[inputIndex].get(); }
00126 
00127         /**
00128         * Return complete index to texture mapping
00129         **/
00130         const TextureMap& getInputTextureMap() const {return mInputTex;}
00131 
00132         /**
00133         * Get output texture of certain MRT index.
00134         * NOTE: If you haven't initialized the Unit before calling this method
00135         * it might end up in a NULL as output texture. For this purpose do use
00136         * the getOrCreateOutputTexture().
00137         **/
00138         inline osg::Texture* getOutputTexture(int mrt = 0) { return mOutputTex[mrt].get(); }
00139 
00140         /**
00141         * Return an output texture of the certain MRT index.
00142         * If there is no output texture for that index is specified, then
00143         * it will be allocated. The method should be overwriten by the derived
00144         * Units if they use any Output texture. Otherwise the result is always
00145         * the same as from getOutputTexture().
00146         **/
00147         virtual osg::Texture* getOrCreateOutputTexture(int mrt = 0) { return getOutputTexture(mrt); }
00148 
00149         /**
00150         * Get mrt index to texture mapping
00151         **/
00152         inline const TextureMap& getOutputTextureMap() const {return mOutputTex;}
00153 
00154         /**
00155         * If you like that a unit doesn't use a certain input you can specify its index here.
00156         * This allows to place units on certain positions in the unit graph without using its
00157         * parents as inputs.
00158         **/
00159         void setIgnoreInput(unsigned int index, bool b = true);
00160 
00161         /**
00162         * Get input ignorance map which list all indices of input data which are ignored
00163         **/
00164         const IgnoreInputList& getIgnoreInputList() const { return mIgnoreList; }
00165 
00166         /**
00167         * Check whenever the input of the given index is ignored or not
00168         **/
00169         bool getIgnoreInput(unsigned int index) const;
00170 
00171         /**
00172         * Initialze the unit. This method should be overwritten by the
00173         * derived classes to support non-standard initialization routines.
00174         * If an unit is marked as dirty this method will be used to resetup the unit.
00175         * Hence do provide a "reinitialable"-code here ;-)
00176         **/
00177         virtual void init();
00178 
00179         /**
00180         * Update the unit. Call this method every time you want to update
00181         * the unit. It is a good idea to call this method every frame otherwise
00182         * the behaviour of the unit might be unpredictable.
00183         **/
00184         virtual void update();
00185 
00186         /**
00187         * Set viewport which is used for this Unit while rendering. Setting any viewport will force it
00188         * to be used. If no viewport is set, then either input texture size is used as viewport or 
00189         * processors camera viewport is used as input. 
00190         **/
00191         void setViewport(osg::Viewport* vp);
00192 
00193         /**
00194         * Get viewport of this unit
00195         **/
00196         inline osg::Viewport* getViewport() const { return mViewport.get(); }
00197 
00198         /**
00199          * Activate or deactive the ppu. An active ppu is updated during the update
00200          * of the post processor.
00201          * @param b True to activate, false to deactive
00202         **/
00203         inline void setActive(bool b) { mbActive = b; }
00204 
00205         /**
00206         * Check if the Unit's active flag
00207         **/
00208         inline bool getActive() const { return mbActive; }
00209 
00210         /**
00211          * Change drawing position and size of this ppu by using the
00212          * new frustum planes in the orthogonal projection matrix.
00213          * This changes the projection matrix,
00214          * therefor it is better not to change this parameters until you really
00215          * need this. If you just want to place the ppu on another position, then just
00216          * play with the viewport.
00217         **/
00218         void setRenderingFrustum(float left, float top, float right, float bottom);
00219 
00220         /**
00221         * Set index of an input texture which size is used as reference
00222         * for the viewport size. The viewport size will be changed according
00223         * to the texture size. If you change the input texture the size will
00224         * be also changed. Specify -1 if you do not want to have this behaviour.
00225         * If -1, then by next change of the input texture the viewport size
00226         * will not be changed.
00227         **/
00228         void setInputTextureIndexForViewportReference(int index);
00229 
00230         /**
00231         * Get index of the input texture which dimension is used for setting up the viewport.
00232         **/
00233         inline int getInputTextureIndexForViewportReference() const { return mInputTexIndexForViewportReference; }
00234 
00235         /**
00236         * Mark this unit as dirty. This will force it to resetup its data
00237         * on next update. Also every child unit will be marked as dirty. This yields of
00238         * reinitialization of children units on next update method too.
00239         **/
00240         virtual void dirty();
00241 
00242         /**
00243         * Checks whenever the unit is marked as dirty or not.
00244         **/
00245         inline bool isDirty() const { return mbDirty; }
00246 
00247         /**
00248         * Get geode to which the unit's drawables are attached. The geodes
00249         * are used to render the unit.
00250         **/
00251         osg::Geode* getGeode() { return mGeode.get(); }
00252         const osg::Geode* getGeode() const { return mGeode.get(); }
00253 
00254         /**
00255         * Setup children nodes if they are connected by a barrier node.
00256         * This method don't need to be called outside of the unit. The method
00257         * is placed here to allow acess to it from the derived units.
00258         **/
00259         void setupBlockedChildren();
00260 
00261         /**
00262         * Set a new color attribute for this unit. This will replace the color attribute
00263         * if it is already set. The color attribute can be used to bind a color to
00264         * an unit. Very useful for blending units.
00265         **/
00266         void setColorAttribute(ColorAttribute* ca);
00267 
00268         /**
00269         * Get current color attribute of the unit.
00270         **/
00271         ColorAttribute* getColorAttribute() { return mColorAttribute.get(); }
00272         const ColorAttribute* getColorAttribute() const { return mColorAttribute.get(); }
00273 
00274         /**
00275         * Return a PixelDataBufferObject associated with the input texture. 
00276         * If using of pbos is deactivated, then undefined result might be given back. 
00277         **/
00278         inline const osg::PixelDataBufferObject* getInputPBO(int inputIndex) { return mInputPBO[inputIndex].get(); }
00279         inline const osg::PixelDataBufferObject* getOutputPBO(int mrt) { return mOutputPBO[mrt].get(); }
00280 
00281         const PixelDataBufferObjectMap& getInputPBOMap() const { return mInputPBO; }
00282         const PixelDataBufferObjectMap& getOutputPBOMap() const { return mOutputPBO; }
00283 
00284         /**
00285         * Specify a flag whenever input textures have to be mapped to the input PixelDataBufferObjects.
00286         * If enabled, data from the input texture will be written to the according input PBO on
00287         * each apply. This gives you the possibility of using the data stored in the buffer externally.
00288         * NOTE: A PixelDataBufferObject resides also on the GPU as the texture does. Hence reading/writing
00289         *       of data in/to PBO isn't that costly, because data is copied in the video memory.
00290         **/
00291         void setUsePBOForInputTexture(int index);
00292         inline bool getUsePBOForInputTexture(int index) { return mInputPBO[index].valid(); }
00293 
00294         void setUsePBOForOutputTexture(int mrt);
00295         inline bool getUsePBOForOutputTexture(int mrt) { return mOutputPBO[mrt].valid(); }
00296 
00297         /** 
00298         * Push current FBO, so that it can safely be overwritten.
00299         * Derived classes and its subclasses get use of this method.
00300         **/
00301         inline void pushFrameBufferObject(osg::State& state)
00302         {
00303             GLint fbo = 0;
00304             glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo);
00305             mPushedFBO[state.getContextID()] = fbo;
00306         }
00307 
00308         /** 
00309         * Restore last used FrameBufferObject back. This will restore
00310         * the FBO pushed before with pushFrameBufferObject method.
00311         **/
00312         inline void popFrameBufferObject(osg::State& state)
00313         {
00314             osg::FBOExtensions* ext = osg::FBOExtensions::instance(state.getContextID(), true);
00315                         ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mPushedFBO[state.getContextID()]);
00316         }
00317 
00318         /**
00319         * A notify callback can be used by anyone in order to be informed when a unit 
00320         * is doing special operations, i.e. rendering.
00321         * Mostly this is used to be able to react on actions of a unit.
00322         **/
00323         struct NotifyCallback : public virtual osg::Object
00324         {
00325                 META_Object (osgPPU, NotifyCallback);
00326 
00327                 NotifyCallback(){}
00328                 
00329                 NotifyCallback(const NotifyCallback&, const osg::CopyOp&){}
00330 
00331                 virtual void operator()(osg::RenderInfo&, const Unit*) const{};
00332         };
00333 
00334         /**
00335         * Set before rendering notify callback. Callback is executed before main 
00336         * drawable of a unit is drawed.
00337         **/
00338         inline void setBeginDrawCallback(NotifyCallback* cb) { _notifyBeginDrawCallback = cb; }
00339         inline NotifyCallback* getBeginDrawCallback() { return _notifyBeginDrawCallback; }
00340         inline const NotifyCallback* getBeginDrawCallback() const { return _notifyBeginDrawCallback; }
00341 
00342         /**
00343         * Set after rendering notify callback. Callback is executed after main 
00344         * drawable of a unit is drawed.
00345         **/
00346         inline void setEndDrawCallback(NotifyCallback* cb) { _notifyEndDrawCallback = cb; }
00347         inline NotifyCallback* getEndDrawCallback() { return _notifyEndDrawCallback; }
00348         inline const NotifyCallback* getEndDrawCallback() const { return _notifyEndDrawCallback; }
00349 
00350     protected:
00351 
00352         /**
00353         * This draw callback is used to setup correct drawing
00354         * of the unit's drawable. The callback is setted up automatically,
00355         * hence you don't need to do anything.
00356         **/
00357         class DrawCallback : public osg::Drawable::DrawCallback
00358         {
00359             public:
00360                 DrawCallback(Unit* parent) : osg::Drawable::DrawCallback(), _parent(parent) {}
00361                 ~DrawCallback() {}
00362 
00363                 inline void setParent(Unit* parent) { _parent = parent; }
00364                 inline Unit* getParent() { return _parent; }
00365                 inline const Unit* getParent() const { return _parent; }
00366                 void drawImplementation (osg::RenderInfo& ri, const osg::Drawable* dr) const;
00367 
00368             private:
00369                 Unit* _parent;
00370         };
00371 
00372         /**
00373         * Simple draw callback, which just do nothing. It will be executed by every unit 
00374         * even which just bypass the data. This is needed in order to be able to catch up
00375         * the moment when a unit is to be computing the output. So virtually speaking
00376         * every unit does compute the output, however only UnitInOut do really render something
00377         * the rest just do nothing.
00378         **/
00379         struct EmptyDrawCallback : public osg::Drawable::DrawCallback
00380         {
00381             EmptyDrawCallback(Unit* parent) : osg::Drawable::DrawCallback(), _parent(parent) {}
00382             void drawImplementation (osg::RenderInfo& ri, const osg::Drawable* dr) const;
00383 
00384             Unit* _parent;
00385         };
00386 
00387         /**
00388         * Use this method in the derived classes to implement and update some unit
00389         * specific uniforms. The base class do only update uniforms like viewport size
00390         * or, if defined, input texture indices.
00391         **/
00392         virtual void updateUniforms();
00393 
00394         /**
00395         * Setup the input textures based on the parents. Each unit has to setup its
00396         * input textures properly. This method do scan for all parents up to the Processor
00397         * and use the output textures of that parents units and the processor as
00398         * input to this unit. Call this method from derived units to setup inputs properly.
00399         **/
00400         virtual void setupInputsFromParents();
00401 
00402         //! Method to let the unit know that the rendering will now beginns, if returned false, then drawable is not rendered
00403         virtual bool  noticeBeginRendering (osg::RenderInfo&, const osg::Drawable* ) { return true; }
00404 
00405         //! Let the unit know that the drawing is done.
00406         virtual void  noticeFinishRendering(osg::RenderInfo&, const osg::Drawable* ) {};
00407 
00408         //! Notice underlying classes, that viewport size is changed
00409         virtual void noticeChangeViewport() {}
00410 
00411         //! Notice derived classes, when input texture has changed.
00412         virtual void noticeChangeInput() {}
00413 
00414         //! Assign the input texture to the quad object
00415         virtual void assignInputTexture();
00416 
00417         //! Assign currently choosen viewport to the stateset
00418         virtual void assignViewport();
00419 
00420         //! Assign input/output PBOs to according textures
00421         virtual void assignInputPBO();
00422 
00423         //! Helper function to create screen sized quads
00424         osg::Drawable* createTexturedQuadDrawable(const osg::Vec3& corner = osg::Vec3(0,0,0),const osg::Vec3& widthVec=osg::Vec3(1,0,0),const osg::Vec3& heightVec=osg::Vec3(0,1,0), float l=0.0, float b=0.0, float r=1.0, float t=1.0);
00425 
00426                 //! Traverse the unit
00427                 virtual void traverse(osg::NodeVisitor& nv);
00428 
00429         //! Input texture
00430         TextureMap  mInputTex;
00431 
00432         //! Output textures
00433         TextureMap  mOutputTex;
00434 
00435         //! Input pbos of the textures
00436         PixelDataBufferObjectMap mInputPBO;
00437 
00438         //! Output pbos of the textures
00439         PixelDataBufferObjectMap mOutputPBO;
00440 
00441         //! List of ignored inputs
00442         IgnoreInputList mIgnoreList;
00443 
00444         //! Map of the uniform to parent links
00445         InputToUniformMap mInputToUniformMap;
00446 
00447         //! Here we store a screen sized quad, so it can be used for rendering
00448         osg::ref_ptr<osg::Drawable> mDrawable;
00449 
00450         //! Projection matrix of the ppu (default: 2D ortho view)
00451         osg::ref_ptr<osg::RefMatrix> sProjectionMatrix;
00452 
00453         //! Modelview matrix of the ppu (default: identity matrix)
00454         osg::ref_ptr<osg::RefMatrix> sModelviewMatrix;
00455 
00456         //! Store here the viewport of the camera, to which one this PPUs are applied
00457         osg::ref_ptr<osg::Viewport> mViewport;
00458 
00459         //! This geode is used to setup the unit's drawable
00460         osg::ref_ptr<osg::Geode> mGeode;
00461 
00462         //! Color attribute for fast direct access
00463         osg::ref_ptr<ColorAttribute> mColorAttribute;
00464 
00465         //! Is the unit dirty
00466         bool mbDirty;
00467 
00468         //! Index of the input texture which size is used as viewport
00469         int mInputTexIndexForViewportReference;
00470 
00471         //! Pushed FBOs
00472         mutable osg::buffered_value<GLuint> mPushedFBO;
00473                                 
00474     private:
00475         bool mbActive;
00476 
00477         // Separate both folowing variables to allow update and cull traversal in different threads
00478         bool mbUpdateTraversed; // requires to check whenever unit was already traversed by update visitor
00479         bool mbCullTraversed; // requires to check whenever unit was already traversed by cull visitor
00480 
00481         void printDebugInfo(const osg::Drawable* dr);
00482         osg::ref_ptr<NotifyCallback> _notifyBeginDrawCallback;
00483         osg::ref_ptr<NotifyCallback> _notifyEndDrawCallback;
00484 
00485         // it is good to have friends
00486         friend class Processor;
00487         friend class Pipeline;
00488         friend class CleanUpdateTraversedVisitor;
00489         friend class CleanCullTraversedVisitor;
00490         friend class SetMaximumInputsVisitor;
00491 };
00492 
00493 };
00494 
00495 #endif

Back to Homepage of osgPPU

Copyright (C) 2008 by Art Tevs (LGPL)