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