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
Copyright (C) 2008 by Art Tevs (LGPL)