Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
StaticBillboardSet.cpp
Go to the documentation of this file.
1/*-------------------------------------------------------------------------------------
2Copyright (c) 2006 John Judnich
3
4This 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.
5Permission 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:
61. 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.
72. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
83. 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 billboards (note: StaticBillboardSet
14//does not allow billboards to be moved or deleted individually in real-time)
15//-------------------------------------------------------------------------------------
16
17#include <OgreRoot.h>
18#include <OgreCamera.h>
19#include <OgreVector3.h>
20#include <OgreMeshManager.h>
21#include <OgreMesh.h>
22#include <OgreSubMesh.h>
23#include <OgreMaterialManager.h>
24#include <OgreMaterial.h>
25#include <OgreBillboardSet.h>
26#include <OgreBillboard.h>
27#include <OgreSceneNode.h>
28#include <OgreString.h>
29#include <OgreStringConverter.h>
30#include <OgreRenderSystem.h>
31#include <OgreRenderSystemCapabilities.h>
32#include <OgreHighLevelGpuProgramManager.h>
33#include <OgreHighLevelGpuProgram.h>
34#include <OgreHardwareBufferManager.h>
35#include <OgreHardwareBuffer.h>
36#include <OgreLogManager.h>
37#include <OgreEntity.h>
38#include <OgreTechnique.h>
39
40#include "StaticBillboardSet.h"
41
42using namespace Ogre;
43using namespace Forests;
44
45
46// Static data initialization
50unsigned long StaticBillboardSet::GUID = 0;
51
52
53//-----------------------------------------------------------------------------
55StaticBillboardSet::StaticBillboardSet(SceneManager *mgr, SceneNode *rootSceneNode) :
56mVisible (true),
57mFadeEnabled (false),
58mpSceneMgr (mgr),
59mpSceneNode (NULL),
60mpEntity (NULL),
61mfUFactor (1.f),
62mfVFactor (1.f),
63mBBOrigin (BBO_CENTER),
64mFadeVisibleDist (0.f),
65mFadeInvisibleDist (0.f)
66{
67 assert(rootSceneNode);
68
69 mpSceneNode = rootSceneNode->createChildSceneNode();
70 mEntityName = getUniqueID("SBSentity");
71
72 //Load vertex shader to align billboards to face the camera (if not loaded already)
73 if (s_nSelfInstances == 0)
74 {
75 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
76 s_isGLSL = mgr.isLanguageSupported("glsl");
77 Ogre::String shaderLanguage = s_isGLSL ? "glsl" : mgr.isLanguageSupported("hlsl") ? "hlsl" : "cg";
78
79 //First shader, simple camera-alignment
80 String vertexProg;
81 if (!s_isGLSL) // DirectX HLSL or nVidia CG
82 {
83 vertexProg =
84 "void Sprite_vp( \n"
85 " float4 position : POSITION, \n"
86 " float3 normal : NORMAL, \n"
87 " float4 color : COLOR, \n"
88 " float2 uv : TEXCOORD0, \n"
89 " out float4 oPosition : POSITION, \n"
90 " out float2 oUv : TEXCOORD0, \n"
91 " out float4 oColor : COLOR, \n"
92 " out float oFog : FOG, \n"
93 " uniform float4x4 worldViewProj, \n"
94 " uniform float uScroll, \n"
95 " uniform float vScroll, \n"
96 " uniform float4 preRotatedQuad[4] ) \n"
97 "{ \n"
98 //Face the camera
99 " float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n"
100 " float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n"
101 " oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n"
102
103 //Color
104 " oColor = color; \n"
105
106 //UV Scroll
107 " oUv = uv; \n"
108 " oUv.x += uScroll; \n"
109 " oUv.y += vScroll; \n"
110
111 //Fog
112 " oFog = oPosition.z; \n"
113 "}";
114 }
115 else // OpenGL GLSL
116 {
117 vertexProg =
118 "uniform mat4 worldViewProj;\n"
119 "uniform float uScroll; \n"
120 "uniform float vScroll; \n"
121 "uniform vec4 preRotatedQuad[4]; \n"
122
123 "void main() { \n"
124 //Face the camera
125 " vec4 vCenter = vec4( gl_Vertex.x, gl_Vertex.y, gl_Vertex.z, 1.0 ); \n"
126 " vec4 vScale = vec4( gl_Normal.x, gl_Normal.y, gl_Normal.x , 1.0 ); \n"
127 " gl_Position = worldViewProj * (vCenter + (preRotatedQuad[int(gl_Normal.z)] * vScale) ); \n"
128
129 //Color
130 " gl_FrontColor = gl_Color; \n"
131
132 //UV Scroll
133 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
134 " gl_TexCoord[0].x += uScroll; \n"
135 " gl_TexCoord[0].y += vScroll; \n"
136
137 //Fog
138 " gl_FogFragCoord = gl_Position.z; \n"
139 "}";
140 }
141
142 HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().getByName("Sprite_vp");
143 OgreAssert(!vertexShader, "Sprite_vp already exist");
144
145 vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram(
146 "Sprite_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, shaderLanguage, GPT_VERTEX_PROGRAM);
147 vertexShader->setSource(vertexProg);
148
149 // Set entry point for vertex program. GLSL can only have one entry point "main".
150 if (!s_isGLSL)
151 {
152 if (shaderLanguage == "hlsl")
153 {
154 vertexShader->setParameter("target", "vs_1_1");
155 vertexShader->setParameter("entry_point", "Sprite_vp");
156 }
157 else if(shaderLanguage == "cg")
158 {
159 vertexShader->setParameter("profiles", "vs_1_1 arbvp1");
160 vertexShader->setParameter("entry_point", "Sprite_vp");
161 }
162 else
163 {
164 assert(false && "Unknown shader language");
165 }
166 }
167
168 // compile vertex shader
169 vertexShader->load();
170
171
172 //====================================================================
173 //Second shader, camera alignment and distance based fading
174 String vertexProg2;
175 if (!s_isGLSL) // DirectX HLSL or nVidia CG
176 {
177 vertexProg2 =
178 "void SpriteFade_vp( \n"
179 " float4 position : POSITION, \n"
180 " float3 normal : NORMAL, \n"
181 " float4 color : COLOR, \n"
182 " float2 uv : TEXCOORD0, \n"
183 " out float4 oPosition : POSITION, \n"
184 " out float2 oUv : TEXCOORD0, \n"
185 " out float4 oColor : COLOR, \n"
186 " out float oFog : FOG, \n"
187 " uniform float4x4 worldViewProj, \n"
188
189 " uniform float3 camPos, \n"
190 " uniform float fadeGap, \n"
191 " uniform float invisibleDist, \n"
192
193 " uniform float uScroll, \n"
194 " uniform float vScroll, \n"
195 " uniform float4 preRotatedQuad[4] ) \n"
196 "{ \n"
197 //Face the camera
198 " float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n"
199 " float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n"
200 " oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n"
201
202 " oColor.rgb = color.rgb; \n"
203
204 //Fade out in the distance
205 " float dist = distance(camPos.xz, position.xz); \n"
206 " oColor.a = (invisibleDist - dist) / fadeGap; \n"
207
208 //UV scroll
209 " oUv = uv; \n"
210 " oUv.x += uScroll; \n"
211 " oUv.y += vScroll; \n"
212
213 //Fog
214 " oFog = oPosition.z; \n"
215 "}";
216 }
217 else // OpenGL GLSL
218 {
219 vertexProg2 =
220 "uniform mat4 worldViewProj;\n"
221 "uniform vec3 camPos; \n"
222 "uniform float fadeGap; \n"
223 "uniform float invisibleDist; \n"
224 "uniform float uScroll; \n"
225 "uniform float vScroll; \n"
226 "uniform vec4 preRotatedQuad[4]; \n"
227
228 "void main() { \n"
229 //Face the camera
230 " vec4 vCenter = vec4( gl_Vertex.x, gl_Vertex.y, gl_Vertex.z, 1.0 ); \n"
231 " vec4 vScale = vec4( gl_Normal.x, gl_Normal.y, gl_Normal.x , 1.0 ); \n"
232 " gl_Position = worldViewProj * (vCenter + (preRotatedQuad[int(gl_Normal.z)] * vScale) ); \n"
233
234 " gl_FrontColor.xyz = gl_Color.xyz; \n"
235
236 //Fade out in the distance
237 " vec4 position = gl_Vertex; \n"
238 " float dist = distance(camPos.xz, position.xz); \n"
239 " gl_FrontColor.w = (invisibleDist - dist) / fadeGap; \n"
240
241 //UV scroll
242 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
243 " gl_TexCoord[0].x += uScroll; \n"
244 " gl_TexCoord[0].y += vScroll; \n"
245
246 //Fog
247 " gl_FogFragCoord = gl_Position.z; \n"
248 "}";
249 }
250
251 HighLevelGpuProgramPtr vertexShader2 = HighLevelGpuProgramManager::getSingleton().getByName("SpriteFade_vp");
252 OgreAssert(!vertexShader2, "SpriteFade_vp already exist");
253 vertexShader2 = HighLevelGpuProgramManager::getSingleton().createProgram("SpriteFade_vp",
254 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, shaderLanguage, GPT_VERTEX_PROGRAM);
255 vertexShader2->setSource(vertexProg2);
256
257 // Set entry point. GLSL can only have one entry point "main".
258 if (!s_isGLSL)
259 {
260
261 if (shaderLanguage == "hlsl")
262 {
263 vertexShader2->setParameter("target", "vs_1_1");
264 vertexShader2->setParameter("entry_point", "SpriteFade_vp");
265 }
266 else if(shaderLanguage == "cg")
267 {
268 vertexShader2->setParameter("profiles", "vs_1_1 arbvp1");
269 vertexShader2->setParameter("entry_point", "SpriteFade_vp");
270 }
271 }
272 // compile it
273 vertexShader2->load();
274 }
275
276
278}
279
280
281//-----------------------------------------------------------------------------
284{
285
286 clear(); // Delete mesh data
287
288 //Update material reference list
289 if (mPtrMaterial)
293
294 //Delete vertex shaders and materials if no longer in use
295 if (--s_nSelfInstances == 0)
296 {
297 s_mapFadedMaterial.clear(); //Delete fade materials
298 HighLevelGpuProgramManager::getSingleton().remove("Sprite_vp");
299 HighLevelGpuProgramManager::getSingleton().remove("SpriteFade_vp");
300 }
301
302
303 //Delete scene node
304 if (mpSceneNode->getParent())
305 mpSceneNode->getParentSceneNode()->removeAndDestroyChild(mpSceneNode);
306 else
307 mpSceneNode->getCreator()->destroySceneNode(mpSceneNode);
308}
309
310
311//-----------------------------------------------------------------------------
314{
315
316 //Delete the entity and mesh data
317 if (mpEntity)
318 {
319 //Delete entity
320 mpSceneNode->detachAllObjects();
321 mpEntity->_getManager()->destroyEntity(mpEntity);
322 mpEntity = NULL;
323
324 //Delete mesh
325 MeshManager::getSingleton().remove(mPtrMesh);
326 mPtrMesh.reset();
327 }
328
329 if (!mBillboardBuffer.empty())
330 {
331 //Remove any billboard data which might be left over if the user forgot to call build()
332 for (int i = mBillboardBuffer.size() - 1; i > 0; /* empty */ )
333 delete mBillboardBuffer[--i];
334 mBillboardBuffer.clear();
335 }
336
337}
338
339
340//-----------------------------------------------------------------------------
343{
344
345 //Delete old entity and mesh data
346 if (mpEntity)
347 {
348 //Delete entity
349 mpSceneNode->detachAllObjects();
350 mpEntity->_getManager()->destroyEntity(mpEntity);
351 mpEntity = NULL;
352
353 //Delete mesh
354 MeshManager::getSingleton().remove(mPtrMesh);
355 mPtrMesh.reset();
356 }
357
358 //If there are no billboards to create, exit
359 if (mBillboardBuffer.empty())
360 return;
361
362 //Create manual mesh to store billboard quads
363 mPtrMesh = MeshManager::getSingleton().createManual(getUniqueID("SBSmesh"), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
364 Ogre::SubMesh *pSubMesh = mPtrMesh->createSubMesh();
365 pSubMesh->useSharedVertices = false;
366
367 //Setup vertex format information
368 pSubMesh->vertexData = new VertexData;
369 pSubMesh->vertexData->vertexStart = 0;
370 pSubMesh->vertexData->vertexCount = 4 * mBillboardBuffer.size();
371
372 VertexDeclaration* dcl = pSubMesh->vertexData->vertexDeclaration;
373 size_t offset = 0;
374 dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
375 offset += VertexElement::getTypeSize(VET_FLOAT3);
376 dcl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
377 offset += VertexElement::getTypeSize(VET_FLOAT3);
378 dcl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
379 offset += VertexElement::getTypeSize(VET_COLOUR);
380 dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
381 offset += VertexElement::getTypeSize(VET_FLOAT2);
382
383 //Populate a new vertex buffer
384 HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
385 offset, pSubMesh->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
386 float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
387
388 float minX = (float)Math::POS_INFINITY, minY = (float)Math::POS_INFINITY, minZ = (float)Math::POS_INFINITY;
389 float maxX = (float)Math::NEG_INFINITY, maxY = (float)Math::NEG_INFINITY, maxZ = (float)Math::NEG_INFINITY;
390
391 // For each billboard
392 size_t billboardCount = mBillboardBuffer.size();
393 for (size_t ibb = 0; ibb < billboardCount; ++ibb)
394 {
395 const StaticBillboard *bb = mBillboardBuffer[ibb];
396
397 // position
401
405 memcpy(pReal, &(bb->xPos), 5 * sizeof(float));
406 pReal += 5; // move to next float value
407 *pReal++ = 0.0f;
408
409 // color
410 *(reinterpret_cast< uint32* >(pReal++)) = bb->color;
411 // uv
412 *pReal++ = (bb->texcoordIndexU * mfUFactor);
413 *pReal++ = (bb->texcoordIndexV * mfVFactor);
414
415
416 // position
423 memcpy(pReal, &(bb->xPos), 5 * sizeof(float));
424 pReal += 5; // move to next float value
425 *pReal++ = 1.0f;
426 // color
427 *(reinterpret_cast< uint32* >(pReal++)) = bb->color;
428 // uv
429 *pReal++ = ((bb->texcoordIndexU + 1) * mfUFactor);
430 *pReal++ = (bb->texcoordIndexV * mfVFactor);
431
432
433 // position
440 memcpy(pReal, &(bb->xPos), 5 * sizeof(float));
441 pReal += 5; // move to next float value
442 *pReal++ = 2.0f;
443 // color
444 *(reinterpret_cast< uint32* > (pReal++)) = bb->color;
445 // uv
446 *pReal++ = (bb->texcoordIndexU * mfUFactor);
447 *pReal++ = ((bb->texcoordIndexV + 1) * mfVFactor);
448
449
450 // position
457 memcpy(pReal, &(bb->xPos), 5 * sizeof(float));
458 pReal += 5; // move to next float value
459 *pReal++ = 3.0f;
460 // color
461 *(reinterpret_cast< uint32* >(pReal++)) = bb->color;
462 // uv
463 *pReal++ = ((bb->texcoordIndexU + 1) * mfUFactor);
464 *pReal++ = ((bb->texcoordIndexV + 1) * mfVFactor);
465
466 //Update bounding box
467 if (bb->xPos - bb->xScaleHalf < minX) minX = bb->xPos - bb->xScaleHalf;
468 if (bb->xPos + bb->xScaleHalf > maxX) maxX = bb->xPos + bb->xScaleHalf;
469 if (bb->yPos - bb->yScaleHalf < minY) minY = bb->yPos - bb->yScaleHalf;
470 if (bb->yPos + bb->yScaleHalf > maxY) maxY = bb->yPos + bb->yScaleHalf;
471 //if (bb->zPos - halfXScale < minZ) minZ = bb->zPos - halfXScale;
472 //if (bb->zPos + halfXScale > maxZ) maxZ = bb->zPos + halfXScale;
473 if (bb->zPos < minZ) minZ = bb->zPos - 0.5f;
474 if (bb->zPos > maxZ) maxZ = bb->zPos + 0.5f;
475
476 delete bb;
477 }
478 mBillboardBuffer.clear(); //Empty the mBillboardBuffer now, because all billboards have been built
479
480 vbuf->unlock();
481 pSubMesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
482
483 // Populate index buffer
484 {
485 pSubMesh->indexData->indexStart = 0;
486 pSubMesh->indexData->indexCount = 6 * billboardCount;
487 assert(pSubMesh->indexData->indexCount <= std::numeric_limits<Ogre::uint16>::max() && "To many indices. Use 32 bit indices");
488 Ogre::HardwareIndexBufferSharedPtr &ptrIndBuf = pSubMesh->indexData->indexBuffer;
489 ptrIndBuf = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
490 pSubMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
491
492 Ogre::uint16 *pIBuf = static_cast < Ogre::uint16* > (ptrIndBuf->lock(HardwareBuffer::HBL_DISCARD));
493 for (Ogre::uint16 i = 0; i < billboardCount; ++i)
494 {
495 Ogre::uint16 offset = i * 4;
496
497 *pIBuf++ = 0 + offset;
498 *pIBuf++ = 2 + offset;
499 *pIBuf++ = 1 + offset;
500
501 *pIBuf++ = 1 + offset;
502 *pIBuf++ = 2 + offset;
503 *pIBuf++ = 3 + offset;
504 }
505 ptrIndBuf->unlock(); // Unlock buffer and update GPU
506 }
507
508 // Finish up mesh
509 {
510 AxisAlignedBox bounds(minX, minY, minZ, maxX, maxY, maxZ);
511 mPtrMesh->_setBounds(bounds);
512 Vector3 temp = bounds.getMaximum() - bounds.getMinimum();
513 mPtrMesh->_setBoundingSphereRadius(temp.length() * 0.5f);
514
515 // Loading mesh
516 Ogre::LoggingLevel logLev = LogManager::getSingleton().getDefaultLog()->getLogDetail();
517 LogManager::getSingleton().setLogDetail(LL_LOW);
518 mPtrMesh->load();
519 LogManager::getSingleton().setLogDetail(logLev);
520 }
521
522 // Create an entity for the mesh
523 mpEntity = mpSceneMgr->createEntity(mEntityName, mPtrMesh->getName(), mPtrMesh->getGroup());
524 mpEntity->setCastShadows(false);
526
527 // Add to scene
528 mpSceneNode->attachObject(mpEntity);
529 mpEntity->setVisible(mVisible);
530}
531
532
533//-----------------------------------------------------------------------------
535void StaticBillboardSet::setMaterial(const String &materialName, const Ogre::String &resourceGroup)
536{
537 bool needUpdateMat = !mPtrMaterial || mPtrMaterial->getName() != materialName || mPtrMaterial->getGroup() != resourceGroup;
538 if (!needUpdateMat)
539 return;
540
541 //Update material reference list
542 if (mFadeEnabled)
543 {
544 assert(mPtrFadeMaterial);
546 }
547 else if (mPtrMaterial)
549
550 mPtrMaterial = MaterialManager::getSingleton().getByName(materialName, resourceGroup);
551
552 if (mFadeEnabled)
553 {
556 }
557 else
559
560 //Apply material to entity
561 if (mpEntity)
563
564}
565
566
567//-----------------------------------------------------------------------------
569void StaticBillboardSet::setFade(bool enabled, Real visibleDist, Real invisibleDist)
570{
571 if (enabled)
572 {
573 if (!mPtrMaterial)
574 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Billboard fading cannot be enabled without a material applied first", "StaticBillboardSet::setFade()");
575
576 //Update material reference list
577 if (mFadeEnabled)
578 {
579 assert(mPtrFadeMaterial);
581 }
582 else
583 {
584 assert(mPtrMaterial);
586 }
587
588 mPtrFadeMaterial = getFadeMaterial(mPtrMaterial, visibleDist, invisibleDist);
590
591 //Apply material to entity
592 if (mpEntity)
593 mpEntity->setMaterial(mPtrFadeMaterial);
594
595 mFadeEnabled = true;
596 mFadeVisibleDist = visibleDist;
597 mFadeInvisibleDist = invisibleDist;
598 }
599 else // disable
600 {
601 if (mFadeEnabled)
602 {
603 //Update material reference list
604 assert(mPtrFadeMaterial);
605 assert(mPtrMaterial);
608
609 //Apply material to entity
610 if (mpEntity)
611 mpEntity->setMaterial(mPtrMaterial);
612
613 mFadeEnabled = false;
614 mFadeVisibleDist = visibleDist;
615 mFadeInvisibleDist = invisibleDist;
616 }
617 }
618}
619
620
621//-----------------------------------------------------------------------------
623void StaticBillboardSet::setTextureStacksAndSlices(Ogre::uint16 stacks, Ogre::uint16 slices)
624{
625 assert(stacks != 0 && slices != 0 && "division by zero");
626 mfUFactor = 1.0f / slices;
627 mfVFactor = 1.0f / stacks;
628}
629
630
631//-----------------------------------------------------------------------------
633MaterialPtr StaticBillboardSet::getFadeMaterial(const Ogre::MaterialPtr &protoMaterial,
634 Real visibleDist_, Real invisibleDist_)
635{
636 assert(protoMaterial);
637
638 Ogre::StringStream materialSignature;
639 materialSignature << mEntityName << "|";
640 materialSignature << visibleDist_ << "|";
641 materialSignature << invisibleDist_ << "|";
642 materialSignature << protoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureUScroll() << "|";
643 materialSignature << protoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->getTextureVScroll() << "|";
644
645 FadedMaterialMap::iterator it = s_mapFadedMaterial.find(materialSignature.str());
646 if (it != s_mapFadedMaterial.end())
647 return it->second; //Use the existing fade material
648 else
649 {
650 MaterialPtr fadeMaterial = protoMaterial->clone(getUniqueID("ImpostorFade"));
651
652 //And apply the fade shader
653 for (unsigned short t = 0; t < fadeMaterial->getNumTechniques(); ++t)
654 {
655 Technique *tech = fadeMaterial->getTechnique(t);
656 for (unsigned short p = 0; p < tech->getNumPasses(); ++p)
657 {
658 Pass *pass = tech->getPass(p);
659
660 //Setup vertex program
661 pass->setVertexProgram("SpriteFade_vp");
662 GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters();
663
664 params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
665
666 static const Ogre::String uScroll = "uScroll", vScroll = "vScroll",
667 preRotatedQuad0 = "preRotatedQuad[0]", preRotatedQuad1 = "preRotatedQuad[1]",
668 preRotatedQuad2 = "preRotatedQuad[2]", preRotatedQuad3 = "preRotatedQuad[3]",
669 camPos = "camPos", fadeGap = "fadeGap", invisibleDist = "invisibleDist";
670
671 params->setNamedAutoConstant(uScroll, GpuProgramParameters::ACT_CUSTOM);
672 params->setNamedAutoConstant(vScroll, GpuProgramParameters::ACT_CUSTOM);
673 params->setNamedAutoConstant(preRotatedQuad0, GpuProgramParameters::ACT_CUSTOM);
674 params->setNamedAutoConstant(preRotatedQuad1, GpuProgramParameters::ACT_CUSTOM);
675 params->setNamedAutoConstant(preRotatedQuad2, GpuProgramParameters::ACT_CUSTOM);
676 params->setNamedAutoConstant(preRotatedQuad3, GpuProgramParameters::ACT_CUSTOM);
677
678 params->setNamedAutoConstant(camPos, GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
679 params->setNamedAutoConstant(fadeGap, GpuProgramParameters::ACT_CUSTOM);
680 params->setNamedAutoConstant(invisibleDist, GpuProgramParameters::ACT_CUSTOM);
681
682 //Set fade ranges
683 params->setNamedConstant(invisibleDist, invisibleDist_);
684 params->setNamedConstant(fadeGap, invisibleDist_ - visibleDist_);
685
686 pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
687 //pass->setAlphaRejectFunction(CMPF_ALWAYS_PASS);
688 //pass->setDepthWriteEnabled(false);
689
690 } // for Pass
691
692 } // for Technique
693
694 //Add it to the list so it can be reused later
695 s_mapFadedMaterial.insert(std::pair<String, MaterialPtr>(materialSignature.str(), fadeMaterial));
696
697 return fadeMaterial;
698 }
699}
700
701
702//-----------------------------------------------------------------------------
704void StaticBillboardSet::updateAll(const Vector3 &cameraDirection)
705{
706 if (s_nSelfInstances == 0)
707 return;
708
709 //Set shader parameter so material will face camera
710 Vector3 forward = cameraDirection;
711 Vector3 vRight = forward.crossProduct(Vector3::UNIT_Y);
712 Vector3 vUp = forward.crossProduct(vRight);
713 vRight.normalise();
714 vUp.normalise();
715
716 //Even if camera is upside down, the billboards should remain upright
717 if (vUp.y < 0)
718 vUp *= -1;
719
720 // Precompute preRotatedQuad for both cases (BBO_CENTER, BBO_BOTTOM_CENTER)
721
722 Vector3 vPoint0 = (-vRight + vUp);
723 Vector3 vPoint1 = ( vRight + vUp);
724 Vector3 vPoint2 = (-vRight - vUp);
725 Vector3 vPoint3 = ( vRight - vUp);
726
727 float preRotatedQuad_BBO_CENTER[16] = // single prerotated quad oriented towards the camera
728 {
729 (float)vPoint0.x, (float)vPoint0.y, (float)vPoint0.z, 0.0f,
730 (float)vPoint1.x, (float)vPoint1.y, (float)vPoint1.z, 0.0f,
731 (float)vPoint2.x, (float)vPoint2.y, (float)vPoint2.z, 0.0f,
732 (float)vPoint3.x, (float)vPoint3.y, (float)vPoint3.z, 0.0f
733 };
734
735 vPoint0 = (-vRight + vUp + vUp);
736 vPoint1 = ( vRight + vUp + vUp);
737 vPoint2 = (-vRight);
738 vPoint3 = ( vRight);
739 float preRotatedQuad_BBO_BOTTOM_CENTER[16] =
740 {
741 (float)vPoint0.x, (float)vPoint0.y, (float)vPoint0.z, 0.0f,
742 (float)vPoint1.x, (float)vPoint1.y, (float)vPoint1.z, 0.0f,
743 (float)vPoint2.x, (float)vPoint2.y, (float)vPoint2.z, 0.0f,
744 (float)vPoint3.x, (float)vPoint3.y, (float)vPoint3.z, 0.0f
745 };
746
747 // Shaders uniform variables
748 static const Ogre::String uScroll = "uScroll", vScroll = "vScroll", preRotatedQuad0 = "preRotatedQuad[0]",
749 preRotatedQuad1 = "preRotatedQuad[1]", preRotatedQuad2 = "preRotatedQuad[2]", preRotatedQuad3 = "preRotatedQuad[3]";
750
751 // SVA for Ogre::Material hack
752 const GpuConstantDefinition *pGPU_ConstDef_preRotatedQuad0 = 0,
753 *pGPU_ConstDef_uScroll = 0, *pGPU_ConstDef_vScroll = 0;
754
755 // For each material in use by the billboard system..
756 SBMaterialRefList::iterator i1 = SBMaterialRef::getList().begin(), iend = SBMaterialRef::getList().end();
757 while (i1 != iend)
758 {
759 Ogre::Material *mat = i1->second->getMaterial();
760
761 // Ensure material is set up with the vertex shader
762 Pass *p = mat->getTechnique(0)->getPass(0);
763 if (!p->hasVertexProgram())
764 {
765 static const Ogre::String Sprite_vp = "Sprite_vp";
766 p->setVertexProgram(Sprite_vp);
767
768 p->getVertexProgramParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
769
770 GpuProgramParametersSharedPtr params = p->getVertexProgramParameters();
771 params->setNamedAutoConstant(uScroll, GpuProgramParameters::ACT_CUSTOM);
772 params->setNamedAutoConstant(vScroll, GpuProgramParameters::ACT_CUSTOM);
773 params->setNamedAutoConstant(preRotatedQuad0, GpuProgramParameters::ACT_CUSTOM);
774 params->setNamedAutoConstant(preRotatedQuad1, GpuProgramParameters::ACT_CUSTOM);
775 params->setNamedAutoConstant(preRotatedQuad2, GpuProgramParameters::ACT_CUSTOM);
776 params->setNamedAutoConstant(preRotatedQuad3, GpuProgramParameters::ACT_CUSTOM);
777 }
778
779 // Which prerotated quad use
780 const float *pQuad = i1->second->getOrigin() == BBO_CENTER ? preRotatedQuad_BBO_CENTER : preRotatedQuad_BBO_BOTTOM_CENTER;
781
782 // Update the vertex shader parameters
783 GpuProgramParametersSharedPtr params = p->getVertexProgramParameters();
784 //params->setNamedConstant(preRotatedQuad0, pQuad, 4);
785 //params->setNamedConstant(uScroll, p->getTextureUnitState(0)->getTextureUScroll());
786 //params->setNamedConstant(vScroll, p->getTextureUnitState(0)->getTextureVScroll());
787
788 // SVA some hack of Ogre::Material.
789 // Since material are cloned and use same vertex shader "Sprite_vp" hardware GPU indices
790 // must be same. I don`t know planes of Ogre Team to change this behaviour.
791 // Therefore this may be unsafe code. Instead of 3 std::map lookups(map::find(const Ogre::String&)) do only 1
792 {
793 const GpuConstantDefinition *def = params->_findNamedConstantDefinition(preRotatedQuad0, true);
794 if (def != pGPU_ConstDef_preRotatedQuad0) // new material, reread
795 {
796 pGPU_ConstDef_preRotatedQuad0 = def;
797 pGPU_ConstDef_uScroll = params->_findNamedConstantDefinition(uScroll, true);
798 pGPU_ConstDef_vScroll = params->_findNamedConstantDefinition(vScroll, true);
799 }
800 }
801
802 float fUScroll = (float)p->getTextureUnitState(0)->getTextureUScroll(),
803 fVScroll = (float)p->getTextureUnitState(0)->getTextureVScroll();
804 params->_writeRawConstants(pGPU_ConstDef_preRotatedQuad0->physicalIndex, pQuad, 16);
805 params->_writeRawConstants(pGPU_ConstDef_uScroll->physicalIndex, &fUScroll, 1);
806 params->_writeRawConstants(pGPU_ConstDef_vScroll->physicalIndex, &fVScroll, 1);
807
808 ++i1; // next material in billboard system
809 }
810}
811
812
813//-----------------------------------------------------------------------------
815void StaticBillboardSet::setBillboardOrigin(BillboardOrigin origin)
816{
817 assert((origin == BBO_CENTER || origin == BBO_BOTTOM_CENTER) && "Invalid origin - only BBO_CENTER and BBO_BOTTOM_CENTER is supported");
818 mBBOrigin = origin;
819}
820
821
822//-------------------------------------------------------------------------------------
823
825
826void SBMaterialRef::addMaterialRef(const MaterialPtr &matP, Ogre::BillboardOrigin o)
827{
828 Material *mat = matP.get();
829
830 SBMaterialRef *matRef;
831 SBMaterialRefList::iterator it;
832 it = selfList.find(mat);
833
834 if (it != selfList.end()){
835 //Material already exists in selfList - increment refCount
836 matRef = it->second;
837 ++matRef->refCount;
838 } else {
839 //Material does not exist in selfList - add it
840 matRef = new SBMaterialRef(mat, o);
841 selfList[mat] = matRef;
842 //No need to set refCount to 1 here because the SBMaterialRef
843 //constructor sets refCount to 1.
844 }
845}
846
847void SBMaterialRef::removeMaterialRef(const MaterialPtr &matP)
848{
849 Material *mat = matP.get();
850
851 SBMaterialRef *matRef;
852 SBMaterialRefList::iterator it;
853
854 //Find material in selfList
855 it = selfList.find(mat);
856 if (it != selfList.end()){
857 //Decrease the reference count, and remove the item if refCount == 0
858 matRef = it->second;
859 if (--matRef->refCount == 0){
860 delete matRef;
861 selfList.erase(it);
862 }
863 }
864}
865
866SBMaterialRef::SBMaterialRef(Material *mat, Ogre::BillboardOrigin o)
867{
868 material = mat;
869 origin = o;
870 refCount = 1;
871}
static void removeMaterialRef(const Ogre::MaterialPtr &matP)
static SBMaterialRefList selfList
static SBMaterialRefList & getList()
SBMaterialRef(Ogre::Material *mat, Ogre::BillboardOrigin o)
Ogre::BillboardOrigin origin
static void addMaterialRef(const Ogre::MaterialPtr &matP, Ogre::BillboardOrigin o)
StaticBillboardSet(Ogre::SceneManager *mgr, Ogre::SceneNode *rootSceneNode)
Initializes a StaticBillboardSet object.
void setBillboardOrigin(Ogre::BillboardOrigin origin)
Sets the billboard's origin (pivotal point)
Ogre::MaterialPtr getFadeMaterial(const Ogre::MaterialPtr &protoMaterial, Ogre::Real visibleDist, Ogre::Real invisibleDist)
static unsigned int s_nSelfInstances
Instances counter.
void setFade(bool enabled, Ogre::Real visibleDist, Ogre::Real invisibleDist)
Enables/disables distance fade-out for this billboard set.
Ogre::SceneManager * mpSceneMgr
void build()
Performs final steps required for the created billboards to appear in the scene.
static FadedMaterialMap s_mapFadedMaterial
std::map< Ogre::String, Ogre::MaterialPtr > FadedMaterialMap
static Ogre::String getUniqueID(const Ogre::String &prefix)
void setTextureStacksAndSlices(Ogre::uint16 stacks, Ogre::uint16 slices)
Sets how many horizontal slices and vertical stacks the currently applied material is using.
void setMaterial(const Ogre::String &materialName, const Ogre::String &resourceGroup=Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
Applies a material to the billboards in this set.
Ogre::BillboardOrigin mBBOrigin
void clear()
Deletes all billboards from the scene.
static void updateAll(const Ogre::Vector3 &cameraDirection)
Manually updates all StaticBillboardSet objects for a frame.
std::map< Ogre::Material *, SBMaterialRef * > SBMaterialRefList