2019-12-26 21:32:58 +01:00
/*-------------------------------------------------------------------------------------
Copyright ( c ) 2006 John Judnich
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 .
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 :
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 .
2. Altered source versions must be plainly marked as such , and must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//StaticBillboardSet.h
//Provides a method of displaying billboards faster than Ogre's built-in BillboardSet
//functions by taking advantage of the static nature of billboards (note: StaticBillboardSet
//does not allow billboards to be moved or deleted individually in real-time)
//-------------------------------------------------------------------------------------
# include "StaticBillboardSet.h"
# include "ShaderHelper.h"
# include <OgreRoot.h>
# include <OgreCamera.h>
# include <OgreVector.h>
# include <OgreMeshManager.h>
# include <OgreMesh.h>
# include <OgreSubMesh.h>
# include <OgreMaterialManager.h>
# include <OgreMaterial.h>
# include <OgreBillboardSet.h>
# include <OgreBillboard.h>
# include <OgreSceneNode.h>
# include <OgreString.h>
# include <OgreStringConverter.h>
# include <OgreRenderSystem.h>
# include <OgreRenderSystemCapabilities.h>
# include <OgreHighLevelGpuProgramManager.h>
# include <OgreHighLevelGpuProgram.h>
# include <OgreHardwareBufferManager.h>
# include <OgreHardwareBuffer.h>
# include <OgreLogManager.h>
# include <OgreEntity.h>
# include <OgreTechnique.h>
using namespace Ogre ;
namespace Forests {
//-------------------------------------------------------------------------------------
unsigned long StaticBillboardSet : : GUID = 0 ;
uint32 StaticBillboardSet : : selfInstances = 0 ;
StaticBillboardSet : : FadedMaterialMap StaticBillboardSet : : fadedMaterialMap ;
StaticBillboardSet : : StaticBillboardSet ( SceneManager * mgr , SceneNode * rootSceneNode , BillboardMethod method )
{
sceneMgr = mgr ;
renderMethod = method ;
visible = true ;
fadeEnabled = false ;
bbOrigin = BBO_CENTER ;
subMesh = NULL ;
//Fall back to BB_METHOD_COMPATIBLE if vertex shaders are not available
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
const RenderSystemCapabilities * caps = Root : : getSingleton ( ) . getRenderSystem ( ) - > getCapabilities ( ) ;
if ( ! caps - > hasCapability ( RSC_VERTEX_PROGRAM ) )
renderMethod = BB_METHOD_COMPATIBLE ;
}
node = rootSceneNode - > createChildSceneNode ( ) ;
entityName = getUniqueID ( " SBSentity " ) ;
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
//Accelerated billboard method
entity = NULL ;
uFactor = 1.0f ;
vFactor = 1.0f ;
//Load vertex shader to align billboards to face the camera (if not loaded already)
if ( + + selfInstances = = 1 ) {
String shaderLanguage = ShaderHelper : : getShaderLanguage ( ) ;
const std : : string fragmentProgramName ( " ImposterFragStandard " ) ;
//We also need a fragment program to go with our vertex program. Especially on ATI cards on Linux where we can't mix shaders and the fixed function pipeline.
if ( ! HighLevelGpuProgramManager : : getSingleton ( ) . getByName ( fragmentProgramName , Ogre : : ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ) {
String fragmentProgSource ;
if ( shaderLanguage = = " hlsl " | | shaderLanguage = = " cg " )
{
fragmentProgSource = " void main \n "
" ( \n "
" float2 iTexcoord : TEXCOORD0, \n "
" float iFog : FOG, \n "
" out float4 oColour : COLOR, \n "
" uniform sampler2D diffuseTexture : TEXUNIT0, \n "
" uniform float3 iFogColour, \n "
" uniform float4 iLightAmbient \n "
" ) \n "
" { \n "
" oColour = tex2D(diffuseTexture, iTexcoord.xy); \n "
" oColour.xyz = lerp((iLightAmbient * oColour).xyz, iFogColour, iFog); \n "
" } " ;
} else {
fragmentProgSource =
" #version 330 \n "
" uniform sampler2D diffuseMap; \n "
" uniform vec3 iFogColour; \n "
" uniform vec4 iLightAmbient; \n "
" in vec4 oUv0; \n "
" in float fog; \n "
" in float fade; \n "
" out vec4 fragColour; \n "
" void main() { \n "
" fragColour = texture(diffuseMap, oUv0.st); \n "
" if (fragColour.a < 0.5) { discard; } \n "
" fragColour.rgb = mix(iFogColour, iLightAmbient.rgb * fragColour.rgb, fog).rgb; \n "
" fragColour.a = fade; \n "
" } " ;
}
HighLevelGpuProgramPtr fragShader = HighLevelGpuProgramManager : : getSingleton ( ) . createProgram (
fragmentProgramName ,
ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ,
shaderLanguage , GPT_FRAGMENT_PROGRAM ) ;
fragShader - > setSource ( fragmentProgSource ) ;
if ( shaderLanguage = = " hlsl " ) {
fragShader - > setParameter ( " target " , " ps_2_0 " ) ;
fragShader - > setParameter ( " entry_point " , " main " ) ;
} else if ( shaderLanguage = = " cg " ) {
fragShader - > setParameter ( " profiles " , " ps_2_0 arbfp1 " ) ;
fragShader - > setParameter ( " entry_point " , " main " ) ;
}
//No need with glsl
fragShader - > load ( ) ;
if ( fragShader - > hasCompileError ( ) | | ! fragShader - > isSupported ( ) ) {
Ogre : : LogManager : : getSingleton ( ) . getDefaultLog ( ) - > logMessage ( " Error loading the billboard fragment shader. " , Ogre : : LML_CRITICAL ) ;
}
}
//First shader, simple camera-alignment
HighLevelGpuProgramPtr vertexShader ;
vertexShader = HighLevelGpuProgramManager : : getSingleton ( ) . getByName ( " Sprite_vp " , Ogre : : ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ;
if ( ! vertexShader ) {
String vertexProg ;
if ( shaderLanguage = = " hlsl " | | shaderLanguage = = " cg " )
{
vertexProg =
" void Sprite_vp( \n "
" float4 position : POSITION, \n "
" float3 normal : NORMAL, \n "
" float4 color : COLOR, \n "
" float2 uv : TEXCOORD0, \n "
" out float4 oPosition : POSITION, \n "
" out float2 oUv : TEXCOORD0, \n "
" out float4 oColor : COLOR, \n "
" out float oFog : FOG, \n "
" uniform float4 iFogParams, \n "
" uniform float4x4 worldViewProj, \n "
" uniform float uScroll, \n "
" uniform float vScroll, \n "
" uniform float4 preRotatedQuad[4] ) \n "
" { \n "
//Face the camera
" float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n "
" float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n "
" oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n "
//Color
" oColor = color; \n "
//UV Scroll
" oUv = uv; \n "
" oUv.x += uScroll; \n "
" oUv.y += vScroll; \n " ;
//Fog
if ( mgr - > getFogMode ( ) = = Ogre : : FOG_EXP2 ) {
vertexProg + =
" oFog = 1 - clamp (pow (2.71828, -oPosition.z * iFogParams.x), 0, 1); \n " ;
} else {
vertexProg + =
" oFog = oPosition.z; \n " ;
}
vertexProg + = " } " ;
}
else
{
// Must be GLSL
vertexProg =
" #version 330 \n "
" uniform mat4 worldViewProj; \n "
" uniform float uScroll; \n "
" uniform float vScroll; \n "
" uniform vec4 preRotatedQuad[4]; \n "
" uniform vec4 iFogParams; \n " // density, linear start, linear end, 1/(end-start)
" in vec3 normal; \n "
" in vec4 vertex; \n "
" in vec4 uv0; \n "
" out vec4 oUv0; \n "
" out float fog; \n "
" out float fade; \n "
" void main() { \n "
" fade = 1; \n "
//Face the camera
" vec4 vCenter = vec4( vertex.x, vertex.y, vertex.z, 1.0 ); \n "
" vec4 vScale = vec4( normal.x, normal.y, normal.x , 1.0 ); \n "
" gl_Position = worldViewProj * (vCenter + (preRotatedQuad[int(normal.z)] * vScale) ); \n "
//Color
// " gl_FrontColor = gl_Color; \n"
//UV Scroll
" oUv0 = uv0; \n "
" oUv0.x += uScroll; \n "
" oUv0.y += vScroll; \n " ;
//Fog
if ( mgr - > getFogMode ( ) = = Ogre : : FOG_EXP2 ) {
vertexProg + =
" fog = clamp(exp(- iFogParams.x * iFogParams.x * gl_Position.z * gl_Position.z), 0.0, 1.0); \n " ;
} else {
vertexProg + =
" fog = gl_Position.z; \n " ;
}
vertexProg + = " } " ;
}
vertexShader = HighLevelGpuProgramManager : : getSingleton ( )
. createProgram ( " Sprite_vp " ,
ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ,
shaderLanguage , GPT_VERTEX_PROGRAM ) ;
vertexShader - > setSource ( vertexProg ) ;
if ( shaderLanguage = = " hlsl " )
{
vertexShader - > setParameter ( " target " , " vs_1_1 " ) ;
vertexShader - > setParameter ( " entry_point " , " Sprite_vp " ) ;
}
else if ( shaderLanguage = = " cg " )
{
vertexShader - > setParameter ( " profiles " , " vs_1_1 arbvp1 " ) ;
vertexShader - > setParameter ( " entry_point " , " Sprite_vp " ) ;
}
// GLSL can only have one entry point "main".
vertexShader - > load ( ) ;
if ( vertexShader - > hasCompileError ( ) | | ! vertexShader - > isSupported ( ) ) {
Ogre : : LogManager : : getSingleton ( ) . getDefaultLog ( ) - > logMessage ( " Error loading the billboard vertex shader. " , Ogre : : LML_CRITICAL ) ;
}
}
//Second shader, camera alignment and distance based fading
HighLevelGpuProgramPtr vertexShader2 ;
vertexShader2 = HighLevelGpuProgramManager : : getSingleton ( ) . getByName ( " SpriteFade_vp " , Ogre : : ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ;
if ( ! vertexShader2 ) {
String vertexProg2 ;
if ( shaderLanguage = = " hlsl " | | shaderLanguage = = " cg " )
{
vertexProg2 =
" void SpriteFade_vp( \n "
" float4 position : POSITION, \n "
" float3 normal : NORMAL, \n "
" float4 color : COLOR, \n "
" float2 uv : TEXCOORD0, \n "
" out float4 oPosition : POSITION, \n "
" out float2 oUv : TEXCOORD0, \n "
" out float4 oColor : COLOR, \n "
" out float oFog : FOG, \n "
" uniform float4x4 worldViewProj, \n "
" uniform float4 iFogParams, \n "
" uniform float3 camPos, \n "
" uniform float fadeGap, \n "
" uniform float invisibleDist, \n "
" uniform float uScroll, \n "
" uniform float vScroll, \n "
" uniform float4 preRotatedQuad[4] ) \n "
" { \n "
//Face the camera
" float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n "
" float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n "
" oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n "
" oColor.rgb = color.rgb; \n "
//Fade out in the distance
" float dist = distance(camPos.xz, position.xz); \n "
" oColor.a = (invisibleDist - dist) / fadeGap; \n "
//UV scroll
" oUv = uv; \n "
" oUv.x += uScroll; \n "
" oUv.y += vScroll; \n " ;
//Fog
if ( mgr - > getFogMode ( ) = = Ogre : : FOG_EXP2 ) {
vertexProg2 + =
" oFog = 1 - clamp (pow (2.71828, -oPosition.z * iFogParams.x), 0, 1); \n " ;
} else {
vertexProg2 + =
" oFog = oPosition.z; \n " ;
}
vertexProg2 + = " } " ;
}
else
{
// Must be GLSL
vertexProg2 =
" #version 330 \n "
" uniform mat4 worldViewProj; \n "
" uniform vec3 camPos; \n "
" uniform float fadeGap; \n "
" uniform float invisibleDist; \n "
" uniform float uScroll; \n "
" uniform float vScroll; \n "
" uniform vec4 preRotatedQuad[4]; \n "
" uniform vec4 iFogParams; \n " // density, linear start, linear end, 1/(end-start)
" in vec3 normal; \n "
" in vec4 vertex; \n "
" in vec4 uv0; \n "
" out vec4 oUv0; \n "
" out float fog; \n "
" out float fade; \n "
" void main() { \n "
//Face the camera
" vec4 vCenter = vec4( vertex.x, vertex.y, vertex.z, 1.0 ); \n "
" vec4 vScale = vec4( normal.x, normal.y, normal.x , 1.0 ); \n "
" gl_Position = worldViewProj * (vCenter + (preRotatedQuad[int(normal.z)] * vScale) ); \n "
// " gl_FrontColor.xyz = gl_Color.xyz; \n"
//Fade out in the distance
" vec4 position = vertex; \n "
" float dist = distance(camPos.xz, position.xz); \n "
" fade = (invisibleDist - dist) / fadeGap; \n "
//UV scroll
" oUv0 = uv0; \n "
" oUv0.x += uScroll; \n "
" oUv0.y += vScroll; \n " ;
//Fog
if ( mgr - > getFogMode ( ) = = Ogre : : FOG_EXP2 ) {
vertexProg2 + =
" fog = clamp(exp(- iFogParams.x * iFogParams.x * gl_Position.z * gl_Position.z), 0.0, 1.0); " ;
} else {
vertexProg2 + =
" fog = gl_Position.z; \n " ;
}
vertexProg2 + = " } " ;
}
vertexShader2 = HighLevelGpuProgramManager : : getSingleton ( )
. createProgram ( " SpriteFade_vp " ,
ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ,
shaderLanguage , GPT_VERTEX_PROGRAM ) ;
vertexShader2 - > setSource ( vertexProg2 ) ;
if ( shaderLanguage = = " hlsl " )
{
vertexShader2 - > setParameter ( " target " , " vs_1_1 " ) ;
vertexShader2 - > setParameter ( " entry_point " , " SpriteFade_vp " ) ;
}
else if ( shaderLanguage = = " cg " )
{
vertexShader2 - > setParameter ( " profiles " , " vs_1_1 arbvp1 " ) ;
vertexShader2 - > setParameter ( " entry_point " , " SpriteFade_vp " ) ;
}
// GLSL can only have one entry point "main".
vertexShader2 - > load ( ) ;
if ( vertexShader2 - > hasCompileError ( ) | | ! vertexShader2 - > isSupported ( ) ) {
Ogre : : LogManager : : getSingleton ( ) . getDefaultLog ( ) - > logMessage ( " Error loading the billboard vertex shader. " , Ogre : : LML_CRITICAL ) ;
}
}
}
} else {
//Compatible billboard method
fallbackSet = sceneMgr - > createBillboardSet ( getUniqueID ( " SBS " ) , 100 ) ;
node - > attachObject ( fallbackSet ) ;
uFactor = 0 ;
vFactor = 0 ;
}
}
StaticBillboardSet : : ~ StaticBillboardSet ( )
{
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
//Delete mesh data
clear ( ) ;
//Delete scene node
sceneMgr - > destroySceneNode ( node ) ;
//Update material reference list
if ( materialPtr ) SBMaterialRef : : removeMaterialRef ( materialPtr ) ;
if ( fadeMaterialPtr ) SBMaterialRef : : removeMaterialRef ( fadeMaterialPtr ) ;
//Delete vertex shaders and materials if no longer in use
if ( - - selfInstances = = 0 ) {
//Delete fade materials
fadedMaterialMap . clear ( ) ;
}
} else {
//Delete scene node
sceneMgr - > destroySceneNode ( node ) ;
//Remove billboard set
sceneMgr - > destroyBillboardSet ( fallbackSet ) ;
}
}
void StaticBillboardSet : : clear ( )
{
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
//Delete the entity and mesh data
if ( entity ) {
//Delete entity
node - > detachAllObjects ( ) ;
sceneMgr - > destroyEntity ( entity ) ;
entity = 0 ;
//Delete mesh
assert ( mesh ) ;
String meshName ( mesh - > getName ( ) ) ;
mesh . reset ( ) ;
if ( MeshManager : : getSingletonPtr ( ) )
MeshManager : : getSingleton ( ) . remove ( meshName , Ogre : : ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ;
}
//Remove any billboard data which might be left over if the user forgot to call build()
billboardBuffer . clear ( ) ;
} else {
fallbackSet - > clear ( ) ;
}
}
void StaticBillboardSet : : build ( )
{
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
//Delete old entity and mesh data
if ( entity ) {
//Delete entity
node - > detachAllObjects ( ) ;
sceneMgr - > destroyEntity ( entity ) ;
entity = 0 ;
//Delete mesh
assert ( mesh ) ;
String meshName ( mesh - > getName ( ) ) ;
mesh . reset ( ) ;
if ( MeshManager : : getSingletonPtr ( ) )
MeshManager : : getSingleton ( ) . remove ( meshName , Ogre : : ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ;
}
//If there are no billboards to create, exit
if ( billboardBuffer . empty ( ) )
return ;
//Create manual mesh to store billboard quads
mesh = MeshManager : : getSingleton ( ) . createManual ( getUniqueID ( " SBSmesh " ) , ResourceGroupManager : : DEFAULT_RESOURCE_GROUP_NAME ) ;
subMesh = mesh - > createSubMesh ( ) ;
subMesh - > useSharedVertices = false ;
//Setup vertex format information
subMesh - > vertexData = new VertexData ;
subMesh - > vertexData - > vertexStart = 0 ;
subMesh - > vertexData - > vertexCount = 4 * billboardBuffer . size ( ) ;
VertexDeclaration * dcl = subMesh - > vertexData - > vertexDeclaration ;
size_t offset = 0 ;
dcl - > addElement ( 0 , offset , VET_FLOAT3 , VES_POSITION ) ;
offset + = VertexElement : : getTypeSize ( VET_FLOAT3 ) ;
dcl - > addElement ( 0 , offset , VET_FLOAT3 , VES_NORMAL ) ;
offset + = VertexElement : : getTypeSize ( VET_FLOAT3 ) ;
dcl - > addElement ( 0 , offset , VET_COLOUR , VES_DIFFUSE ) ;
offset + = VertexElement : : getTypeSize ( VET_COLOUR ) ;
dcl - > addElement ( 0 , offset , VET_FLOAT2 , VES_TEXTURE_COORDINATES ) ;
offset + = VertexElement : : getTypeSize ( VET_FLOAT2 ) ;
//Populate a new vertex buffer
HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager : : getSingleton ( )
. createVertexBuffer ( offset , subMesh - > vertexData - > vertexCount , HardwareBuffer : : HBU_STATIC_WRITE_ONLY , false ) ;
float * pReal = static_cast < float * > ( vbuf - > lock ( HardwareBuffer : : HBL_DISCARD ) ) ;
float minX = Math : : POS_INFINITY , minY = Math : : POS_INFINITY , minZ = Math : : POS_INFINITY ;
float maxX = Math : : NEG_INFINITY , maxY = Math : : NEG_INFINITY , maxZ = Math : : NEG_INFINITY ;
2021-04-06 21:59:39 +02:00
std : : vector < StaticBillboard > : : iterator i1 , i2 ;
2019-12-26 21:32:58 +01:00
i1 = billboardBuffer . begin ( ) ;
i2 = billboardBuffer . end ( ) ;
while ( i1 ! = i2 )
{
2021-04-06 21:59:39 +02:00
StaticBillboard & bb = ( * i1 ) ;
float halfXScale = bb . xScale * 0.5f ;
float halfYScale = bb . yScale * 0.5f ;
2019-12-26 21:32:58 +01:00
// position
2021-04-06 21:59:39 +02:00
* pReal + + = bb . position . x ;
* pReal + + = bb . position . y ;
* pReal + + = bb . position . z ;
2019-12-26 21:32:58 +01:00
// normals (actually used as scale / translate info for vertex shader)
* pReal + + = halfXScale ;
* pReal + + = halfYScale ;
* pReal + + = 0.0f ;
// color
2021-04-06 21:59:39 +02:00
* ( ( uint32 * ) pReal + + ) = bb . color ;
2019-12-26 21:32:58 +01:00
// uv
2021-04-06 21:59:39 +02:00
* pReal + + = ( bb . texcoordIndexU * uFactor ) ;
* pReal + + = ( bb . texcoordIndexV * vFactor ) ;
2019-12-26 21:32:58 +01:00
// position
2021-04-06 21:59:39 +02:00
* pReal + + = bb . position . x ;
* pReal + + = bb . position . y ;
* pReal + + = bb . position . z ;
2019-12-26 21:32:58 +01:00
// normals (actually used as scale / translate info for vertex shader)
* pReal + + = halfXScale ;
* pReal + + = halfYScale ;
* pReal + + = 1.0f ;
// color
2021-04-06 21:59:39 +02:00
* ( ( uint32 * ) pReal + + ) = bb . color ;
2019-12-26 21:32:58 +01:00
// uv
2021-04-06 21:59:39 +02:00
* pReal + + = ( ( bb . texcoordIndexU + 1 ) * uFactor ) ;
* pReal + + = ( bb . texcoordIndexV * vFactor ) ;
2019-12-26 21:32:58 +01:00
// position
2021-04-06 21:59:39 +02:00
* pReal + + = bb . position . x ;
* pReal + + = bb . position . y ;
* pReal + + = bb . position . z ;
2019-12-26 21:32:58 +01:00
// normals (actually used as scale / translate info for vertex shader)
* pReal + + = halfXScale ;
* pReal + + = halfYScale ;
* pReal + + = 2.0f ;
// color
2021-04-06 21:59:39 +02:00
* ( ( uint32 * ) pReal + + ) = bb . color ;
2019-12-26 21:32:58 +01:00
// uv
2021-04-06 21:59:39 +02:00
* pReal + + = ( bb . texcoordIndexU * uFactor ) ;
* pReal + + = ( ( bb . texcoordIndexV + 1 ) * vFactor ) ;
2019-12-26 21:32:58 +01:00
// position
2021-04-06 21:59:39 +02:00
* pReal + + = bb . position . x ;
* pReal + + = bb . position . y ;
* pReal + + = bb . position . z ;
2019-12-26 21:32:58 +01:00
// normals (actually used as scale / translate info for vertex shader)
* pReal + + = halfXScale ;
* pReal + + = halfYScale ;
* pReal + + = 3.0f ;
// color
2021-04-06 21:59:39 +02:00
* ( ( uint32 * ) pReal + + ) = bb . color ;
2019-12-26 21:32:58 +01:00
// uv
2021-04-06 21:59:39 +02:00
* pReal + + = ( ( bb . texcoordIndexU + 1 ) * uFactor ) ;
* pReal + + = ( ( bb . texcoordIndexV + 1 ) * vFactor ) ;
2019-12-26 21:32:58 +01:00
//Update bounding box
2021-04-06 21:59:39 +02:00
if ( bb . position . x - halfXScale < minX ) minX = bb . position . x - halfXScale ;
if ( bb . position . x + halfXScale > maxX ) maxX = bb . position . x + halfXScale ;
if ( bb . position . y - halfYScale < minY ) minY = bb . position . y - halfYScale ;
if ( bb . position . y + halfYScale > maxY ) maxY = bb . position . y + halfYScale ;
if ( bb . position . z - halfXScale < minZ ) minZ = bb . position . z - halfXScale ;
if ( bb . position . z + halfXScale > maxZ ) maxZ = bb . position . z + halfXScale ;
2019-12-26 21:32:58 +01:00
+ + i1 ;
}
AxisAlignedBox bounds ( minX , minY , minZ , maxX , maxY , maxZ ) ;
vbuf - > unlock ( ) ;
subMesh - > vertexData - > vertexBufferBinding - > setBinding ( 0 , vbuf ) ;
//Populate index buffer
subMesh - > indexData - > indexStart = 0 ;
subMesh - > indexData - > indexCount = 6 * billboardBuffer . size ( ) ;
subMesh - > indexData - > indexBuffer = HardwareBufferManager : : getSingleton ( )
. createIndexBuffer ( HardwareIndexBuffer : : IT_16BIT , subMesh - > indexData - > indexCount , HardwareBuffer : : HBU_STATIC_WRITE_ONLY ) ;
Ogre : : uint16 * pI = static_cast < Ogre : : uint16 * > ( subMesh - > indexData - > indexBuffer - > lock ( HardwareBuffer : : HBL_DISCARD ) ) ;
for ( Ogre : : uint16 i = 0 ; i < billboardBuffer . size ( ) ; + + i )
{
Ogre : : uint16 offset = i * 4 ;
* pI + + = 0 + offset ;
* pI + + = 2 + offset ;
* pI + + = 1 + offset ;
* pI + + = 1 + offset ;
* pI + + = 2 + offset ;
* pI + + = 3 + offset ;
}
subMesh - > indexData - > indexBuffer - > unlock ( ) ;
//Finish up mesh
mesh - > _setBounds ( bounds ) ;
Vector3 temp = bounds . getMaximum ( ) - bounds . getMinimum ( ) ;
mesh - > _setBoundingSphereRadius ( temp . length ( ) * 0.5f ) ;
mesh - > load ( ) ;
//Empty the billboardBuffer now, because all billboards have been built
billboardBuffer . clear ( ) ;
//Create an entity for the mesh
entity = sceneMgr - > createEntity ( entityName , mesh - > getName ( ) ) ;
entity - > setCastShadows ( false ) ;
//Apply texture
if ( fadeEnabled ) {
assert ( fadeMaterialPtr ) ;
entity - > setMaterialName ( fadeMaterialPtr - > getName ( ) ) ;
} else {
assert ( materialPtr ) ;
entity - > setMaterialName ( materialPtr - > getName ( ) ) ;
}
//Add to scene
node - > attachObject ( entity ) ;
entity - > setVisible ( visible ) ;
}
}
void StaticBillboardSet : : setMaterial ( const String & materialName )
{
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
if ( ! materialPtr | | materialPtr - > getName ( ) ! = materialName ) {
//Update material reference list
if ( fadeEnabled ) {
assert ( fadeMaterialPtr ) ;
SBMaterialRef : : removeMaterialRef ( fadeMaterialPtr ) ;
} else {
if ( materialPtr )
SBMaterialRef : : removeMaterialRef ( materialPtr ) ;
}
materialPtr = MaterialManager : : getSingleton ( ) . getByName ( materialName ) ;
if ( fadeEnabled ) {
fadeMaterialPtr = getFadeMaterial ( fadeVisibleDist , fadeInvisibleDist ) ;
SBMaterialRef : : addMaterialRef ( fadeMaterialPtr , bbOrigin ) ;
} else {
SBMaterialRef : : addMaterialRef ( materialPtr , bbOrigin ) ;
}
//Apply material to entity
if ( entity ) {
if ( fadeEnabled ) {
entity - > setMaterialName ( fadeMaterialPtr - > getName ( ) ) ;
} else {
entity - > setMaterialName ( materialPtr - > getName ( ) ) ;
}
}
}
} else {
if ( ! materialPtr | | materialPtr - > getName ( ) ! = materialName ) {
materialPtr = MaterialManager : : getSingleton ( ) . getByName ( materialName ) ;
fallbackSet - > setMaterialName ( materialPtr - > getName ( ) ) ;
}
}
}
void StaticBillboardSet : : setFade ( bool enabled , Real visibleDist , Real invisibleDist )
{
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
if ( enabled ) {
if ( ! materialPtr )
OGRE_EXCEPT ( Exception : : ERR_ITEM_NOT_FOUND , " Billboard fading cannot be enabled without a material applied first " , " StaticBillboardSet::setFade() " ) ;
//Update material reference list
if ( fadeEnabled ) {
assert ( fadeMaterialPtr ) ;
SBMaterialRef : : removeMaterialRef ( fadeMaterialPtr ) ;
} else {
assert ( materialPtr ) ;
SBMaterialRef : : removeMaterialRef ( materialPtr ) ;
}
fadeMaterialPtr = getFadeMaterial ( visibleDist , invisibleDist ) ;
SBMaterialRef : : addMaterialRef ( fadeMaterialPtr , bbOrigin ) ;
//Apply material to entity
if ( entity )
entity - > setMaterialName ( fadeMaterialPtr - > getName ( ) ) ;
fadeEnabled = enabled ;
fadeVisibleDist = visibleDist ;
fadeInvisibleDist = invisibleDist ;
} else {
if ( fadeEnabled ) {
//Update material reference list
assert ( fadeMaterialPtr ) ;
assert ( materialPtr ) ;
SBMaterialRef : : removeMaterialRef ( fadeMaterialPtr ) ;
SBMaterialRef : : addMaterialRef ( materialPtr , bbOrigin ) ;
//Apply material to entity
if ( entity )
entity - > setMaterialName ( materialPtr - > getName ( ) ) ;
fadeEnabled = enabled ;
fadeVisibleDist = visibleDist ;
fadeInvisibleDist = invisibleDist ;
}
}
}
}
void StaticBillboardSet : : setTextureStacksAndSlices ( Ogre : : uint16 stacks , Ogre : : uint16 slices )
{
uFactor = 1.0f / slices ;
vFactor = 1.0f / stacks ;
}
MaterialPtr StaticBillboardSet : : getFadeMaterial ( Real visibleDist , Real invisibleDist )
{
Ogre : : StringStream materialSignature ;
materialSignature < < entityName < < " | " ;
materialSignature < < visibleDist < < " | " ;
materialSignature < < invisibleDist < < " | " ;
materialSignature < < materialPtr - > getTechnique ( 0 ) - > getPass ( 0 ) - > getTextureUnitState ( 0 ) - > getTextureUScroll ( ) < < " | " ;
materialSignature < < materialPtr - > getTechnique ( 0 ) - > getPass ( 0 ) - > getTextureUnitState ( 0 ) - > getTextureVScroll ( ) < < " | " ;
FadedMaterialMap : : iterator it = fadedMaterialMap . find ( materialSignature . str ( ) ) ;
MaterialPtr fadeMaterial ;
//If a correctly faded version of the material exists...
if ( it ! = fadedMaterialMap . end ( ) ) {
//Use the existing fade material
fadeMaterial = it - > second ;
} else {
//Otherwise clone the material
fadeMaterial = materialPtr - > clone ( getUniqueID ( " ImpostorFade " ) ) ;
fadeMaterial - > getTechnique ( 0 ) - > setSceneBlending ( Ogre : : SBT_TRANSPARENT_ALPHA ) ;
fadeMaterial - > getTechnique ( 0 ) - > setDepthWriteEnabled ( false ) ;
//And apply the fade shader
for ( unsigned short t = 0 ; t < fadeMaterial - > getNumTechniques ( ) ; + + t ) {
Technique * tech = fadeMaterial - > getTechnique ( t ) ;
for ( unsigned short p = 0 ; p < tech - > getNumPasses ( ) ; + + p ) {
Pass * pass = tech - > getPass ( p ) ;
//Setup vertex program
pass - > setVertexProgram ( " SpriteFade_vp " ) ;
pass - > setFragmentProgram ( " ImposterFragStandard " ) ;
GpuProgramParametersSharedPtr params = pass - > getVertexProgramParameters ( ) ;
params - > setIgnoreMissingParams ( true ) ;
params - > setNamedAutoConstant ( " worldViewProj " , GpuProgramParameters : : ACT_WORLDVIEWPROJ_MATRIX ) ;
params - > setNamedAutoConstant ( " iFogParams " , GpuProgramParameters : : ACT_FOG_PARAMS ) ;
params - > setNamedAutoConstant ( " uScroll " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " vScroll " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " preRotatedQuad[0] " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " preRotatedQuad[1] " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " preRotatedQuad[2] " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " preRotatedQuad[3] " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " camPos " , GpuProgramParameters : : ACT_CAMERA_POSITION_OBJECT_SPACE ) ;
params - > setNamedAutoConstant ( " fadeGap " , GpuProgramParameters : : ACT_CUSTOM ) ;
params - > setNamedAutoConstant ( " invisibleDist " , GpuProgramParameters : : ACT_CUSTOM ) ;
//Set fade ranges
params - > setNamedConstant ( " invisibleDist " , invisibleDist ) ;
params - > setNamedConstant ( " fadeGap " , invisibleDist - visibleDist ) ;
pass - > setSceneBlending ( SBT_TRANSPARENT_ALPHA ) ;
//pass->setAlphaRejectFunction(CMPF_ALWAYS_PASS);
//pass->setDepthWriteEnabled(false);
if ( pass - > hasFragmentProgram ( ) ) {
params = pass - > getFragmentProgramParameters ( ) ;
params - > setIgnoreMissingParams ( true ) ;
params - > setNamedAutoConstant ( " iFogColour " , GpuProgramParameters : : ACT_FOG_COLOUR ) ;
params - > setNamedAutoConstant ( " iLightAmbient " , GpuProgramParameters : : ACT_AMBIENT_LIGHT_COLOUR ) ;
}
}
}
//Add it to the list so it can be reused later
fadedMaterialMap . insert ( std : : pair < String , MaterialPtr > ( materialSignature . str ( ) , fadeMaterial ) ) ;
}
return fadeMaterial ;
}
void StaticBillboardSet : : updateAll ( const Vector3 & cameraDirection )
{
if ( selfInstances > 0 ) { //selfInstances will only be greater than 0 if one or more StaticBillboardSet's are using BB_METHOD_ACCELERATED
//Set shader parameter so material will face camera
Vector3 forward = cameraDirection ;
Vector3 vRight = forward . crossProduct ( Vector3 : : UNIT_Y ) ;
Vector3 vUp = forward . crossProduct ( vRight ) ;
vRight . normalise ( ) ;
vUp . normalise ( ) ;
//Even if camera is upside down, the billboards should remain upright
if ( vUp . y < 0 ) vUp * = - 1 ;
//For each material in use by the billboard system..
SBMaterialRefList : : iterator i1 , i2 ;
i1 = SBMaterialRef : : getList ( ) . begin ( ) ;
i2 = SBMaterialRef : : getList ( ) . end ( ) ;
while ( i1 ! = i2 ) {
Material * mat = i1 - > second - > getMaterial ( ) ;
BillboardOrigin bbOrigin = i1 - > second - > getOrigin ( ) ;
Vector3 vPoint0 , vPoint1 , vPoint2 , vPoint3 ;
if ( bbOrigin = = BBO_CENTER ) {
vPoint0 = ( - vRight + vUp ) ;
vPoint1 = ( vRight + vUp ) ;
vPoint2 = ( - vRight - vUp ) ;
vPoint3 = ( vRight - vUp ) ;
}
else if ( bbOrigin = = BBO_BOTTOM_CENTER ) {
vPoint0 = ( - vRight + vUp + vUp ) ;
vPoint1 = ( vRight + vUp + vUp ) ;
vPoint2 = ( - vRight ) ;
vPoint3 = ( vRight ) ;
}
//single prerotated quad oriented towards the camera
float preRotatedQuad [ 16 ] = {
vPoint0 . x , vPoint0 . y , vPoint0 . z , 0.0f ,
vPoint1 . x , vPoint1 . y , vPoint1 . z , 0.0f ,
vPoint2 . x , vPoint2 . y , vPoint2 . z , 0.0f ,
vPoint3 . x , vPoint3 . y , vPoint3 . z , 0.0f
} ;
//Ensure material is set up with the vertex shader
Pass * p = mat - > getTechnique ( 0 ) - > getPass ( 0 ) ;
if ( ! p - > hasVertexProgram ( ) ) {
p - > setVertexProgram ( " Sprite_vp " ) ;
p - > getVertexProgramParameters ( ) - > setIgnoreMissingParams ( true ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " iFogParams " , GpuProgramParameters : : ACT_FOG_PARAMS ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " worldViewProj " , GpuProgramParameters : : ACT_WORLDVIEWPROJ_MATRIX ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " uScroll " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " vScroll " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " preRotatedQuad[0] " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " preRotatedQuad[1] " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " preRotatedQuad[2] " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > getVertexProgramParameters ( ) - > setNamedAutoConstant ( " preRotatedQuad[3] " , GpuProgramParameters : : ACT_CUSTOM ) ;
p - > setFragmentProgram ( " ImposterFragStandard " ) ;
if ( p - > hasFragmentProgram ( ) ) {
p - > getFragmentProgramParameters ( ) - > setIgnoreMissingParams ( true ) ;
p - > getFragmentProgramParameters ( ) - > setNamedAutoConstant ( " iFogColour " , GpuProgramParameters : : ACT_FOG_COLOUR ) ;
p - > getFragmentProgramParameters ( ) - > setNamedAutoConstant ( " iLightAmbient " , GpuProgramParameters : : ACT_AMBIENT_LIGHT_COLOUR ) ;
}
}
//Update the vertex shader parameters
GpuProgramParametersSharedPtr params = p - > getVertexProgramParameters ( ) ;
params - > setNamedConstant ( " preRotatedQuad[0] " , preRotatedQuad , 4 ) ;
params - > setNamedConstant ( " uScroll " , p - > getTextureUnitState ( 0 ) - > getTextureUScroll ( ) ) ;
params - > setNamedConstant ( " vScroll " , p - > getTextureUnitState ( 0 ) - > getTextureVScroll ( ) ) ;
+ + i1 ;
}
}
}
void StaticBillboardSet : : setBillboardOrigin ( BillboardOrigin origin )
{
if ( origin ! = BBO_CENTER & & origin ! = BBO_BOTTOM_CENTER )
OGRE_EXCEPT ( Exception : : ERR_INVALIDPARAMS , " Invalid origin - only BBO_CENTER and BBO_BOTTOM_CENTER is supported " , " StaticBillboardSet::setBillboardOrigin() " ) ;
if ( renderMethod = = BB_METHOD_ACCELERATED ) {
bbOrigin = origin ;
} else {
bbOrigin = origin ;
fallbackSet - > setBillboardOrigin ( origin ) ;
}
}
//-------------------------------------------------------------------------------------
SBMaterialRefList SBMaterialRef : : selfList ;
void SBMaterialRef : : addMaterialRef ( const MaterialPtr & matP , Ogre : : BillboardOrigin o )
{
Material * mat = matP . get ( ) ;
SBMaterialRef * matRef ;
SBMaterialRefList : : iterator it ;
it = selfList . find ( mat ) ;
if ( it ! = selfList . end ( ) ) {
//Material already exists in selfList - increment refCount
matRef = it - > second ;
+ + matRef - > refCount ;
} else {
//Material does not exist in selfList - add it
matRef = new SBMaterialRef ( mat , o ) ;
selfList [ mat ] = matRef ;
//No need to set refCount to 1 here because the SBMaterialRef
//constructor sets refCount to 1.
}
}
void SBMaterialRef : : removeMaterialRef ( const MaterialPtr & matP )
{
Material * mat = matP . get ( ) ;
SBMaterialRef * matRef ;
SBMaterialRefList : : iterator it ;
//Find material in selfList
it = selfList . find ( mat ) ;
if ( it ! = selfList . end ( ) ) {
//Decrease the reference count, and remove the item if refCount == 0
matRef = it - > second ;
if ( - - matRef - > refCount = = 0 ) {
delete matRef ;
selfList . erase ( it ) ;
}
}
}
SBMaterialRef : : SBMaterialRef ( Material * mat , Ogre : : BillboardOrigin o )
{
material = mat ;
origin = o ;
refCount = 1 ;
}
}