1 /*------------------------------------------------------------------------------------- 2 Copyright (c) 2006 John Judnich 3 4 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 5 Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 6 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 7 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 8 3. This notice may not be removed or altered from any source distribution. 9 -------------------------------------------------------------------------------------*/ 10 11 //StaticBillboardSet.h 12 //Provides a method of displaying billboards faster than Ogre's built-in BillboardSet 13 //functions by taking advantage of the static nature of tree billboards (note: 14 //StaticBillboardSet does not allow billboards to be moved or deleted individually in 15 //real-time) 16 //------------------------------------------------------------------------------------- 17 18 #ifndef __StaticBillboardSet_H__ 19 #define __StaticBillboardSet_H__ 20 21 #include <OgrePrerequisites.h> 22 #include <OgreRoot.h> 23 #include <OgreRenderSystem.h> 24 #include <OgreVector3.h> 25 #include <OgreMesh.h> 26 #include <OgreMaterial.h> 27 #include <OgreBillboard.h> 28 #include <OgreBillboardSet.h> 29 #include <OgreMaterialManager.h> 30 #include <OgreSceneNode.h> 31 #include <OgreStringConverter.h> 32 33 namespace Forests 34 { 35 36 class SBMaterialRef; 37 typedef std::map<Ogre::Material*, SBMaterialRef*> SBMaterialRefList; 38 39 /** Different methods used to render billboards. This can be supplied as a parameter 40 to the StaticBillboardSet constructor to manually select how you want billboards 41 rendered (although in almost all cases BB_METHOD_ACCELERATED is the best choice).*/ 42 enum BillboardMethod 43 { 44 /** This mode accelerates the performance of billboards by using vertex shaders 45 to keep billboards facing the camera. Note: If the computer's hardware is not 46 capable of vertex shaders, it will automatically fall back to BB_METHOD_COMPATIBLE 47 mode.*/ 48 BB_METHOD_ACCELERATED = 1, 49 50 /** Unlike BB_METHOD_ACCELERATED, this does not use vertex shaders to align 51 billboards to the camera. This is more compatible with old video cards, 52 although it can result in poor performance with high amounts of billboards.*/ 53 BB_METHOD_COMPATIBLE = 0 54 }; 55 56 57 //-------------------------------------------------------------------------- 58 /// A faster alternative to Ogre's built-in BillboardSet class. 59 /// 60 /// This class provides a method of displaying billboards faster than Ogre's built-in 61 /// BillboardSet functions by taking advantage of the static nature of tree billboards. 62 /// However, if your video card does not support vertex shaders, using this class over 63 /// Ogre's built-in Billboard class will have no performance benefit. 64 /// 65 /// @note StaticBillboardSet does not allow billboards to be moved or deleted individually in real-time 66 class StaticBillboardSet 67 { 68 //----------------------------------------------------------------------------- 69 //Internal class - do not use 70 class StaticBillboard 71 { 72 public: 73 // Constructor StaticBillboard(const Ogre::Vector3 & pos,float xScale,float yScale,const Ogre::ColourValue & clr,Ogre::uint16 texcrdIndexU,Ogre::uint16 texcrdIndexV)74 StaticBillboard(const Ogre::Vector3 &pos, float xScale, float yScale, 75 const Ogre::ColourValue &clr, Ogre::uint16 texcrdIndexU, Ogre::uint16 texcrdIndexV) : 76 xPos((float)pos.x), yPos((float)pos.y), zPos((float)pos.z), xScaleHalf(0.5f * xScale), yScaleHalf(0.5f * yScale), 77 texcoordIndexU(texcrdIndexU), texcoordIndexV(texcrdIndexV) 78 { 79 Ogre::Root::getSingletonPtr()->getRenderSystem()->convertColourValue(clr, &color); 80 } 81 82 83 // SVA mem friendly aligment 84 float xPos, yPos, zPos; 85 //float xScale, yScale; 86 float xScaleHalf, yScaleHalf; 87 Ogre::uint32 color; 88 Ogre::uint16 texcoordIndexU, texcoordIndexV; 89 }; 90 91 public: 92 /** 93 \brief Initializes a StaticBillboardSet object. 94 \param mgr The SceneManager to be used to display the billboards. 95 \param method The method used when rendering billboards. See the BillboardMethod 96 documentation for more information. In almost all cases, this should be set to 97 BB_METHOD_ACCELERATED for optimal speed and efficiency. 98 */ 99 StaticBillboardSet(Ogre::SceneManager *mgr, Ogre::SceneNode *rootSceneNode, BillboardMethod method = BB_METHOD_ACCELERATED); 100 ~StaticBillboardSet(); 101 102 /** 103 \brief Adds a billboard to the StaticBillboardSet at the specified position. 104 \param position The desired position of the billboard. 105 \param xScale The width scale of the billboard. 106 \param yScale The height scale of the billboard. 107 \param texcoordIndex The texture tile this billboard will use. This value shoud be 108 0..n, where n is the number of slices set with setTextureSlices() 109 110 The texcoordIndex option is only applicable if you have used setTextureSlices() 111 to divide the applied material into a number of horizontal segments. texcoordIndex selects 112 which segment is applied to the billboard as a texture. 113 114 \note Any billboards created will not appear in the scene until you call build() 115 */ 116 void createBillboard(const Ogre::Vector3 &position, float xScale = 1.0f, float yScale = 1.0f, 117 const Ogre::ColourValue &color = Ogre::ColourValue::White, Ogre::uint16 texcoordIndexU = 0, Ogre::uint16 texcoordIndexV = 0) 118 { 119 if (mRenderMethod == BB_METHOD_ACCELERATED) 120 { 121 mBillboardBuffer.push_back(new StaticBillboard(position, xScale, yScale, color, texcoordIndexU, texcoordIndexV)); 122 123 //mBillboardBuffer.push_back(bb); 124 125 ////bb->position = position; 126 //bb->xPos = (float)position.x; 127 //bb->yPos = (float)position.y; 128 //bb->zPos = (float)position.z; 129 //bb->xScaleHalf = xScale * 0.5f; 130 //bb->yScaleHalf = yScale * 0.5f; 131 132 //bb->texcoordIndexU = texcoordIndexU; 133 //bb->texcoordIndexV = texcoordIndexV; 134 135 //Ogre::uint32 packedColor; 136 //Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &packedColor); 137 //bb->color = packedColor; 138 } 139 else 140 { 141 Ogre::Billboard *bb = mpFallbackBillboardSet->createBillboard(position, color); 142 bb->setDimensions(xScale, yScale); 143 bb->setTexcoordRect(texcoordIndexU * mfUFactor, texcoordIndexV * mfVFactor, 144 (texcoordIndexU + 1) * mfUFactor, (texcoordIndexV + 1) * mfVFactor); 145 } 146 } 147 148 /** 149 \brief Sets the billboard's origin (pivotal point) 150 151 This function can be used to set what part of the billboard image is considered the 152 origin, or "center". By default, the center of the image is used, so billboards will 153 pivot around the center and positioning a billboard will place it's center at the desired 154 location. Other origins, like BBO_BOTTOM_CENTER are good for trees, etc. BBO_CENTER is 155 used by default. 156 */ 157 void setBillboardOrigin(Ogre::BillboardOrigin origin); 158 159 /// Returns the current billboard origin. 160 /// This returns the current billboard origin as set by setBillboardOrigin(). getBillboardOrigin()161 Ogre::BillboardOrigin getBillboardOrigin() const { return mBBOrigin; } 162 163 /// Returns the method used to render billboards. 164 /// The billboard render method is set in the constructor. See the BillboardMethod enum 165 /// documentation for more information on billboard render methods. getRenderMethod()166 BillboardMethod getRenderMethod() const { return mRenderMethod; } 167 168 ///Sets whether or not this StaticBillboardSet will be rendered. 169 /// \param visible The desired visibility state of the StaticBillboardSet (true/false) setVisible(bool visible)170 void setVisible(bool visible) 171 { 172 if (mVisible != visible) 173 { 174 mVisible = visible; 175 mpSceneNode->setVisible(visible); 176 } 177 } 178 179 /** 180 \brief Enables/disables distance fade-out for this billboard set 181 \param enabled Whether or not to enable fading 182 \param visibleDist The distance where billboards will be fully opaque (alpha 1) 183 \param invisibleDist The distance where billboards will be invisible (alpha 0) 184 185 You can use this function to enable distance based alpha fading, so billboards will 186 smoothly fade out into the distance. Note that the fading is performed 2-dimensionally, 187 which means height is not taken into account when fading - only xz distances. This works 188 well with flat terrain maps, but may not be well suited for spherical worlds. 189 190 The distance ranges given specify how the final alpha values should be calculated - 191 billboards at visibleDist will have alpha values of 1, and geometry at invisibleDist 192 will have alpha values of 0. 193 194 \note invisibleDist may be greater than or less than visibleDist, depending on 195 whether the geometry is fading out or in to the distance. 196 197 \note setFade() only works in BB_MODE_ACCELERATED mode. 198 */ 199 void setFade(bool enabled, Ogre::Real visibleDist, Ogre::Real invisibleDist); 200 201 /// Performs final steps required for the created billboards to appear in the scene. 202 /// Until this is called, any billboards created with createBillboard() will not appear. 203 void build(); 204 205 /// Deletes all billboards from the scene. 206 /// The only way to delete a billboard in a StaticBillboardSet is to delete them all, 207 /// which this function does. 208 void clear(); 209 210 /** 211 \brief Applies a material to the billboards in this set. 212 \param materialName The name of the material to apply to this StaticBillboardSet. 213 214 This may actually modify the material to include a vertex shader (which 215 is used to keep the billboards facing the camera). 216 */ 217 void setMaterial(const Ogre::String &materialName, const Ogre::String &resourceGroup = 218 Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); 219 220 /** 221 \brief Sets how many horizontal slices and vertical stacks the currently applied material is using. 222 \param stacks The number of vertical stacks. 223 \param slices The number of horizontal slices. 224 225 If the applied material contains multiple images all merged together into a grid 226 you can use this function to gain access to the individual images. Simply set how 227 many tiles are contained within the material horizontally and vertically, and use 228 the texcoordIndexU and texcoordIndexV parameters of createBillboard() to specify 229 which image is to be used for the billboard. 230 */ 231 void setTextureStacksAndSlices(Ogre::uint16 stacks, Ogre::uint16 slices); 232 233 /** 234 \brief Manually updates all StaticBillboardSet objects for a frame. 235 236 \note If you are using root->startRendering() or root->renderOneFrame() to update 237 your scene, there is no need to use this function at all. Doing so would be redundant 238 and ineffient, as it will be called automatically in this case. 239 240 However, if you update all your render targets yourself, you will have to call this 241 manually per frame from your program loop. If updateAll() doesn't get called one way 242 or another, your billboards will not be updated to face the camera. 243 */ 244 static void updateAll(const Ogre::Vector3 &cameraDirection); 245 246 private: 247 /// 248 Ogre::MaterialPtr getFadeMaterial(const Ogre::MaterialPtr &protoMaterial, Ogre::Real visibleDist, Ogre::Real invisibleDist); 249 250 private: 251 252 typedef std::vector < StaticBillboard* > TBillBuf; 253 254 bool mVisible; ///< 255 bool mFadeEnabled; ///< 256 BillboardMethod mRenderMethod; ///< 257 258 Ogre::SceneManager* mpSceneMgr; ///< 259 Ogre::SceneNode* mpSceneNode; ///< 260 Ogre::Entity* mpEntity; ///< 261 Ogre::MeshPtr mPtrMesh; ///< 262 Ogre::String mEntityName; ///< 263 Ogre::MaterialPtr mPtrMaterial; ///< 264 Ogre::MaterialPtr mPtrFadeMaterial; ///< 265 float mfUFactor, mfVFactor; ///< 266 267 Ogre::BillboardSet* mpFallbackBillboardSet; ///< 268 Ogre::BillboardOrigin mBBOrigin; ///< 269 Ogre::Real mFadeVisibleDist; ///< 270 Ogre::Real mFadeInvisibleDist; ///< 271 TBillBuf mBillboardBuffer; ///< 272 273 274 // static data 275 private: 276 277 typedef std::map<Ogre::String, Ogre::MaterialPtr> FadedMaterialMap; 278 279 static bool s_isGLSL; ///< OpenGL 280 //static bool s_shadersGenerated; ///< First instance generate shaders for billboard rendering 281 static unsigned int s_nSelfInstances; ///< Instances counter 282 static FadedMaterialMap s_mapFadedMaterial; ///< 283 284 //static Ogre::uint32 selfInstances; 285 static unsigned long GUID; getUniqueID(const Ogre::String & prefix)286 static Ogre::String getUniqueID(const Ogre::String &prefix) { return prefix + Ogre::StringConverter::toString(++GUID); } 287 }; 288 289 290 291 //------------------------------------------------------------------------------------- 292 293 //SBMaterialRef::addMaterialRef() and ::removeMaterialRef() are used to keep track 294 //of all the materials in use by the billboard system. This is necessary when keeping 295 //the materials' vertex shaders up-to-date. To get the list of all materials in use, 296 //use getList(). 297 class SBMaterialRef 298 { 299 public: 300 static void addMaterialRef(const Ogre::MaterialPtr &matP, Ogre::BillboardOrigin o); 301 static void removeMaterialRef(const Ogre::MaterialPtr &matP); 302 getList()303 inline static SBMaterialRefList &getList() { return selfList; } 304 getMaterial()305 inline Ogre::Material *getMaterial() { return material; } getOrigin()306 inline Ogre::BillboardOrigin getOrigin() { return origin; } 307 308 private: 309 SBMaterialRef(Ogre::Material *mat, Ogre::BillboardOrigin o); 310 311 static SBMaterialRefList selfList; 312 313 Ogre::uint32 refCount; 314 Ogre::Material *material; 315 Ogre::BillboardOrigin origin; 316 }; 317 } 318 319 #endif 320