Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
BatchPage.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:
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//BatchPage.cpp
12//BatchPage is an extension to PagedGeometry which displays entities as static geometry.
13//-------------------------------------------------------------------------------------
14
15#include <OgreRoot.h>
16#include <OgreCamera.h>
17#include <OgreVector3.h>
18#include <OgreQuaternion.h>
19#include <OgreEntity.h>
20#include <OgreRenderSystem.h>
21#include <OgreRenderSystemCapabilities.h>
22#include <OgreHighLevelGpuProgram.h>
23#include <OgreHighLevelGpuProgramManager.h>
24#include <OgreLogManager.h>
25#include <OgreTechnique.h>
26
27#include "BatchPage.h"
28#include "BatchedGeometry.h"
29
30
31using namespace Ogre;
32using namespace Forests;
33
34
35
36unsigned long BatchPage::s_nRefCount = 0;
37unsigned long BatchPage::s_nGUID = 0;
38
39
40//-----------------------------------------------------------------------------
43m_pPagedGeom (NULL),
44m_pSceneMgr (NULL),
45m_pBatchGeom (NULL),
46m_nLODLevel (0),
47m_bFadeEnabled (false),
48m_bShadersSupported (false),
49m_fVisibleDist (Ogre::Real(0.)),
50m_fInvisibleDist (Ogre::Real(0.))
51{
52 // empty
53}
54
55
56//-----------------------------------------------------------------------------
58void BatchPage::init(PagedGeometry *geom_, const Any &data)
59{
60 assert(geom_ && "Can any code set null pointer?");
61
62 int datacast = data.has_value() ? Ogre::any_cast<int>(data) : 0;
63#ifdef _DEBUG
64 if (datacast < 0)
65 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,"Data of BatchPage must be a positive integer. It representing the LOD level this detail level stores.","BatchPage::BatchPage");
66#endif
67
68 m_pPagedGeom = geom_;
71 m_nLODLevel = datacast;
72 m_bFadeEnabled = false;
73
75 m_bShadersSupported = false; // shaders disabled by config
76 else
77 {
78 // determine if shaders available
79 const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
80 // For example, GeForce4MX has vertex shadres 1.1 and no pixel shaders
81 m_bShadersSupported = caps->hasCapability(RSC_VERTEX_PROGRAM) ? true : false;
82 }
83
85}
86
88{
89 delete m_pBatchGeom;
90 //unfadedMaterials.clear(); // Delete unfaded material references
91}
92
93
94//-----------------------------------------------------------------------------
96void BatchPage::addEntity(Entity *ent, const Vector3 &position, const Quaternion &rotation,
97 const Vector3 &scale, const Ogre::ColourValue &color)
98{
99 const size_t numManLod = ent->getNumManualLodLevels();
100
101#ifdef _DEBUG
102 //Warns if using LOD batch and entities does not have enough LOD support.
103 if (m_nLODLevel > 0 && numManLod < m_nLODLevel)
104 {
105 Ogre::LogManager::getSingleton().logMessage("BatchPage::addEntity: " + ent->getName() +
106 " entity has less than " + Ogre::StringConverter::toString(m_nLODLevel) +
107 " manual lod level(s). Performance warning.");
108 }
109#endif
110
111 if (m_nLODLevel == 0 || numManLod == 0)
112 m_pBatchGeom->addEntity(ent, position, rotation, scale, color);
113 else
114 {
115 const size_t bestLod = numManLod < m_nLODLevel - 1 ? numManLod : m_nLODLevel - 1;
116 Ogre::Entity * lod = ent->getManualLodLevel(bestLod);
117 m_pBatchGeom->addEntity(lod, position, rotation, scale, color);
118 }
119}
120
121
122//-----------------------------------------------------------------------------
125{
128
129 while (it.hasMoreElements())
130 {
131 BatchedGeometry::SubBatch *subBatch = it.getNext();
132 const MaterialPtr &ptrMat = subBatch->getMaterial();
133
134 //Disable specular unless a custom shader is being used.
135 //This is done because the default shader applied by BatchPage
136 //doesn't support specular, and fixed-function needs to look
137 //the same as the shader (for computers with no shader support)
138 for (unsigned short t = 0, tCnt = ptrMat->getNumTechniques(); t < tCnt; ++t)
139 {
140 Technique *tech = ptrMat->getTechnique(t);
141 for (unsigned short p = 0, pCnt = tech->getNumPasses(); p < pCnt; ++p)
142 {
143 Pass *pass = tech->getPass(p);
144 //if (pass->getVertexProgramName() == "")
145 // pass->setSpecular(0, 0, 0, 1);
146 if (!pass->hasVertexProgram())
147 pass->setSpecular(0.f, 0.f, 0.f, 1.f);
148 }
149 }
150
151 //Store the original materials
152 m_vecUnfadedMaterials.push_back(subBatch->getMaterial());
153 }
154
156}
157
158
159//-----------------------------------------------------------------------------
162{
164 m_vecUnfadedMaterials.clear();
165 m_bFadeEnabled = false;
166}
167
168//-----------------------------------------------------------------------------
170void BatchPage::setVisible(bool visible)
171{
172 m_pBatchGeom->setVisible(visible);
173}
174
175
176//-----------------------------------------------------------------------------
178void BatchPage::setFade(bool enabled, Real visibleDist, Real invisibleDist)
179{
181 return;
182
183 //If fade status has changed...
184 if (m_bFadeEnabled != enabled)
185 {
186 m_bFadeEnabled = enabled;
187
188 if (enabled)
189 //Transparent batches should render after impostors
190 m_pBatchGeom->setRenderQueueGroup(m_pPagedGeom ? m_pPagedGeom->getRenderQueue() : RENDER_QUEUE_6);
191 else
192 //Opaque batches should render in the normal render queue
193 m_pBatchGeom->setRenderQueueGroup(RENDER_QUEUE_MAIN);
194
195 m_fVisibleDist = visibleDist;
196 m_fInvisibleDist = invisibleDist;
198 }
199}
200
201
202//-----------------------------------------------------------------------------
205{
207 return;
208
209 unsigned int i = 0;
211 while (it.hasMoreElements())
212 {
213 BatchedGeometry::SubBatch *subBatch = it.getNext();
214 const MaterialPtr &ptrMat = m_vecUnfadedMaterials[i++];
215
216 //Check if lighting should be enabled
217 bool lightingEnabled = false;
218 for (unsigned short t = 0, tCnt = ptrMat->getNumTechniques(); t < tCnt; ++t)
219 {
220 Technique *tech = ptrMat->getTechnique(t);
221 for (unsigned short p = 0, pCnt = tech->getNumPasses(); p < pCnt; ++p)
222 {
223 if (tech->getPass(p)->getLightingEnabled())
224 {
225 lightingEnabled = true;
226 break;
227 }
228 }
229 if (lightingEnabled)
230 break;
231 }
232
233 //Compile the CG shader script based on various material / fade options
234 Ogre::StringStream tmpName;
235 tmpName << "BatchPage_";
236 if (m_bFadeEnabled)
237 tmpName << "fade_";
238 if (lightingEnabled)
239 tmpName << "lit_";
240 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
241 tmpName << "clr_";
242
243 for (size_t i = 0, iCnt = subBatch->m_pVertexData->vertexDeclaration->getElementCount(); i < iCnt; ++i)
244 {
245 const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i);
246 if (el->getSemantic() == VES_TEXTURE_COORDINATES)
247 {
248 String uvType;
249 switch (el->getType())
250 {
251 case VET_FLOAT1: uvType = "1"; break;
252 case VET_FLOAT2: uvType = "2"; break;
253 case VET_FLOAT3: uvType = "3"; break;
254 case VET_FLOAT4: uvType = "4"; break;
255 }
256 tmpName << uvType << '_';
257 }
258 }
259
260 tmpName << "vp";
261
262 const String vertexProgName = tmpName.str();
263
264 HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
265
266 String shaderLanguage;
267 if (mgr.isLanguageSupported("hlsl"))
268 shaderLanguage = "hlsl";
269 else if(mgr.isLanguageSupported("glsl"))
270 shaderLanguage = "glsl";
271 else
272 shaderLanguage = "cg";
273
274 //If the shader hasn't been created yet, create it
275 if (!HighLevelGpuProgramManager::getSingleton().getByName(vertexProgName))
276 {
277 Pass *pass = ptrMat->getTechnique(0)->getPass(0);
278 String vertexProgSource;
279
280 if(!shaderLanguage.compare("hlsl") || !shaderLanguage.compare("cg"))
281 {
282
283 vertexProgSource =
284 "void main( \n"
285 " float4 iPosition : POSITION, \n"
286 " float3 normal : NORMAL, \n"
287 " out float4 oPosition : POSITION, \n";
288
289 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource +=
290 " float4 iColor : COLOR, \n";
291
292 unsigned texNum = 0;
293 for (unsigned short i = 0; i < subBatch->m_pVertexData->vertexDeclaration->getElementCount(); ++i)
294 {
295 const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i);
296 if (el->getSemantic() == VES_TEXTURE_COORDINATES)
297 {
298 String uvType;
299 switch (el->getType())
300 {
301 case VET_FLOAT1: uvType = "float"; break;
302 case VET_FLOAT2: uvType = "float2"; break;
303 case VET_FLOAT3: uvType = "float3"; break;
304 case VET_FLOAT4: uvType = "float4"; break;
305 }
306
307 vertexProgSource +=
308 " " + uvType + " iUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n"
309 " out " + uvType + " oUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n";
310
311 ++texNum;
312 }
313 }
314
315 vertexProgSource +=
316 " out float oFog : FOG, \n"
317 " out float4 oColor : COLOR, \n";
318
319 if (lightingEnabled) vertexProgSource +=
320 " uniform float4 objSpaceLight, \n"
321 " uniform float4 lightDiffuse, \n"
322 " uniform float4 lightAmbient, \n";
323
324 if (m_bFadeEnabled) vertexProgSource +=
325 " uniform float3 camPos, \n";
326
327 vertexProgSource +=
328 " uniform float4x4 worldViewProj, \n"
329 " uniform float fadeGap, \n"
330 " uniform float invisibleDist )\n"
331 "{ \n";
332
333 if (lightingEnabled)
334 {
335 //Perform lighting calculations (no specular)
336 vertexProgSource +=
337 " float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n"
338 " float diffuseFactor = max(dot(normal, light), 0); \n";
339 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
340 vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n";
341 else
342 vertexProgSource += "oColor = (lightAmbient + diffuseFactor * lightDiffuse); \n";
343 }
344 else
345 {
346 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
347 vertexProgSource += "oColor = iColor; \n";
348 else
349 vertexProgSource += "oColor = float4(1, 1, 1, 1); \n";
350 }
351
352 if (m_bFadeEnabled) vertexProgSource +=
353 //Fade out in the distance
354 " float dist = distance(camPos.xz, iPosition.xz); \n"
355 " oColor.a *= (invisibleDist - dist) / fadeGap; \n";
356
357 texNum = 0;
358 for (size_t i = 0, iCnt = subBatch->m_pVertexData->vertexDeclaration->getElementCount(); i < iCnt; ++i)
359 {
360 const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i);
361 if (el->getSemantic() == VES_TEXTURE_COORDINATES)
362 {
363 vertexProgSource +=
364 " oUV" + StringConverter::toString(texNum) + " = iUV" + StringConverter::toString(texNum) + "; \n";
365 ++texNum;
366 }
367 }
368
369 vertexProgSource +=
370 " oPosition = mul(worldViewProj, iPosition); \n"
371 " oFog = oPosition.z; \n"
372 "}";
373 }
374
375 if(!shaderLanguage.compare("glsl"))
376 {
377 vertexProgSource =
378 "uniform mat4 worldViewProj;\n"
379 "uniform float fadeGap; \n"
380 "uniform float invisibleDist; \n";
381
382 if (lightingEnabled) vertexProgSource +=
383 "uniform vec4 objSpaceLight; \n"
384 "uniform vec4 lightDiffuse; \n"
385 "uniform vec4 lightAmbient; \n";
386
387 if (m_bFadeEnabled) vertexProgSource +=
388 "uniform vec3 camPos; \n";
389
390 vertexProgSource +=
391 "void main() \n"
392 "{ \n";
393
394 if (lightingEnabled)
395 {
396 //Perform lighting calculations (no specular)
397 vertexProgSource +=
398 " vec3 light = normalize(objSpaceLight.xyz - (gl_Vertex.xyz * objSpaceLight.w)); \n"
399 " float diffuseFactor = max(dot(gl_Normal, light), 0.0); \n";
400 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
401 {
402 vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse) * gl_Color; \n";
403 }
404 else
405 {
406 vertexProgSource += " gl_FrontColor = (lightAmbient + diffuseFactor * lightDiffuse); \n";
407 }
408 }
409 else
410 {
411 if (subBatch->m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
412 {
413 vertexProgSource += " gl_FrontColor = gl_Color; \n";
414 }
415 else
416 {
417 vertexProgSource += " gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); \n";
418 }
419 }
420
421 if (m_bFadeEnabled)
422 {
423 vertexProgSource +=
424 //Fade out in the distance
425 " float dist = distance(camPos.xz, gl_Vertex.xz); \n"
426 " gl_FrontColor.a *= (invisibleDist - dist) / fadeGap; \n";
427 }
428
429 unsigned texNum = 0;
430 for (size_t i = 0, iCnt = subBatch->m_pVertexData->vertexDeclaration->getElementCount(); i < iCnt; ++i)
431 {
432 const VertexElement *el = subBatch->m_pVertexData->vertexDeclaration->getElement(i);
433 if (el->getSemantic() == VES_TEXTURE_COORDINATES)
434 {
435 vertexProgSource +=
436 " gl_TexCoord[" + StringConverter::toString(texNum) + "] = gl_MultiTexCoord" + StringConverter::toString(texNum) + "; \n";
437 ++texNum;
438 }
439 }
440
441 vertexProgSource +=
442 " gl_Position = worldViewProj * gl_Vertex; \n"
443 " gl_FogFragCoord = gl_Position.z; \n"
444 "}";
445 }
446
447
448 HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram(
449 vertexProgName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, shaderLanguage, GPT_VERTEX_PROGRAM);
450
451 vertexShader->setSource(vertexProgSource);
452
453 if (shaderLanguage == "hlsl")
454 {
455 vertexShader->setParameter("target", "vs_1_1");
456 vertexShader->setParameter("entry_point", "main");
457 }
458 else if(shaderLanguage == "cg")
459 {
460 vertexShader->setParameter("profiles", "vs_1_1 arbvp1");
461 vertexShader->setParameter("entry_point", "main");
462 }
463 // GLSL can only have one entry point "main".
464
465 vertexShader->load();
466 }
467
468 //Now that the shader is ready to be applied, apply it
469 Ogre::StringStream materialSignature;
470 materialSignature << "BatchMat|";
471 materialSignature << ptrMat->getName() << "|";
472 if (m_bFadeEnabled)
473 {
474 materialSignature << m_fVisibleDist << "|";
475 materialSignature << m_fInvisibleDist << "|";
476 }
477
478 //Search for the desired material
479 MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str());
480 if (!generatedMaterial)
481 {
482 //Clone the material
483 generatedMaterial = ptrMat->clone(materialSignature.str());
484
485 //And apply the fade shader
486 for (unsigned short t = 0, tCnt = generatedMaterial->getNumTechniques(); t < tCnt; ++t)
487 {
488 Technique *tech = generatedMaterial->getTechnique(t);
489 for (unsigned short p = 0, pCnt = tech->getNumPasses(); p < pCnt; ++p)
490 {
491 Pass *pass = tech->getPass(p);
492
493 //Setup vertex program
494 //if (pass->getVertexProgramName() == "")
495 // pass->setVertexProgram(vertexProgName);
496 if (!pass->hasVertexProgram())
497 pass->setVertexProgram(vertexProgName);
498
499 try
500 {
501 GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters();
502
503 if (lightingEnabled)
504 {
505 params->setNamedAutoConstant("objSpaceLight", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
506 params->setNamedAutoConstant("lightDiffuse", GpuProgramParameters::ACT_DERIVED_LIGHT_DIFFUSE_COLOUR);
507 params->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_DERIVED_AMBIENT_LIGHT_COLOUR);
508 //params->setNamedAutoConstant("matAmbient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
509 }
510
511 params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
512
513 if (m_bFadeEnabled)
514 {
515 params->setNamedAutoConstant("camPos", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
516
517 //Set fade ranges
518 params->setNamedAutoConstant("invisibleDist", GpuProgramParameters::ACT_CUSTOM);
519 params->setNamedConstant("invisibleDist", m_fInvisibleDist);
520
521 params->setNamedAutoConstant("fadeGap", GpuProgramParameters::ACT_CUSTOM);
522 params->setNamedConstant("fadeGap", m_fInvisibleDist - m_fVisibleDist);
523
524 if (pass->getAlphaRejectFunction() == CMPF_ALWAYS_PASS)
525 pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
526 }
527 }
528 catch (...)
529 {
530 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
531 "Error configuring batched geometry transitions. If you're using materials with custom vertex shaders, \
532 they will need to implement fade transitions to be compatible with BatchPage.", "BatchPage::_updateShaders()");
533 }
534 }
535 }
536
537 }
538
539 //Apply the material
540 subBatch->setMaterial(generatedMaterial);
541 }
542
543}
BatchPage is an extension to PagedGeometry which displays entities as static geometry.
virtual void _updateShaders()
void init(PagedGeometry *geom, const Ogre::Any &data)
Replace pure virtual GeometryPage::init.
Definition BatchPage.cpp:58
static unsigned long s_nGUID
Definition BatchPage.h:104
PagedGeometry * m_pPagedGeom
Definition BatchPage.h:92
void addEntity(Ogre::Entity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, const Ogre::Vector3 &scale, const Ogre::ColourValue &color)
Add an entity to the page, at the specified position, rotation, and scale.
Definition BatchPage.cpp:96
Ogre::Real m_fVisibleDist
Definition BatchPage.h:98
void removeEntities()
Remove all geometry/entities from the page completely.
BatchPage()
Default constructor.
Definition BatchPage.cpp:42
BatchedGeometry * m_pBatchGeom
Definition BatchPage.h:94
TMaterials m_vecUnfadedMaterials
Definition BatchPage.h:100
Ogre::SceneManager * m_pSceneMgr
Definition BatchPage.h:93
void build()
Perform any final steps to make added entities appear in the scene.
static unsigned long s_nRefCount
Definition BatchPage.h:103
Ogre::Real m_fInvisibleDist
Definition BatchPage.h:99
void setFade(bool enabled, Ogre::Real visibleDist, Ogre::Real invisibleDist)
Sets fade behavior for this page.
void setVisible(bool visible)
Toggle the entire page's visibility.
Visible chunk of geometry.
void setMaterial(Ogre::MaterialPtr &mat)
const Ogre::MaterialPtr & getMaterial(void) const
Ogre::Technique * getTechnique() const
A "lightweight" version of Ogre::StaticGeometry, which gives you a little more control over the batch...
Ogre::MapIterator< TSubBatchMap > TSubBatchIterator
TConstSubBatchIterator getSubBatchIterator() const
virtual void addEntity(Ogre::Entity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &orientation=Ogre::Quaternion::IDENTITY, const Ogre::Vector3 &scale=Ogre::Vector3::UNIT_SCALE, const Ogre::ColourValue &color=Ogre::ColourValue::White)
A class providing highly optimized methods for rendering massive amounts of geometry.
Ogre::uint8 getRenderQueue() const
Returns the rendering queue that paged geometry was constructed with.
Ogre::SceneNode * getSceneNode() const
Gets the scene node to which all PagedGeometry geometry is attached.
Ogre::SceneManager * getSceneManager() const
Gets the scene manager which is being used to display the geometry.