# include "chunkmanager.hpp"
# include <sstream>
# include <osg/Texture2D>
# include <osgUtil/IncrementalCompileOperation>
# include <components/resource/objectcache.hpp>
# include <components/resource/scenemanager.hpp>
# include <components/sceneutil/positionattitudetransform.hpp>
# include "terraindrawable.hpp"
# include "material.hpp"
# include "storage.hpp"
# include "texturemanager.hpp"
# include "compositemaprenderer.hpp"
namespace Terrain
{
ChunkManager : : ChunkManager ( Storage * storage , Resource : : SceneManager * sceneMgr , TextureManager * textureManager , CompositeMapRenderer * renderer )
: ResourceManager ( NULL )
, mStorage ( storage )
, mSceneManager ( sceneMgr )
, mTextureManager ( textureManager )
, mCompositeMapRenderer ( renderer )
, mCompositeMapSize ( 512 )
{
}
osg : : ref_ptr < osg : : Node > ChunkManager : : getChunk ( float size , const osg : : Vec2f & center , int lod , unsigned int lodFlags )
{
std : : ostringstream stream ;
stream < < size < < " " < < center . x ( ) < < " " < < center . y ( ) < < " " < < lod < < " " < < lodFlags ;
std : : string id = stream . str ( ) ;
osg : : ref_ptr < osg : : Object > obj = mCache - > getRefFromObjectCache ( id ) ;
if ( obj )
return obj - > asNode ( ) ;
else
{
osg : : ref_ptr < osg : : Node > node = createChunk ( size , center , lod , lodFlags ) ;
mCache - > addEntryToObjectCache ( id , node . get ( ) ) ;
return node ;
}
}
void ChunkManager : : reportStats ( unsigned int frameNumber , osg : : Stats * stats ) const
{
stats - > setAttribute ( frameNumber , " Terrain Chunk " , mCache - > getCacheSize ( ) ) ;
}
osg : : ref_ptr < osg : : Group > ChunkManager : : createCompositeMapRTT ( osg : : ref_ptr < osg : : Texture2D > & texture )
{
texture = new osg : : Texture2D ;
texture - > setTextureWidth ( mCompositeMapSize ) ;
texture - > setTextureHeight ( mCompositeMapSize ) ;
texture - > setInternalFormat ( GL_RGB ) ;
texture - > setFilter ( osg : : Texture : : MIN_FILTER , osg : : Texture : : LINEAR ) ;
texture - > setFilter ( osg : : Texture : : MAG_FILTER , osg : : Texture : : LINEAR ) ;
texture - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
texture - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
osg : : ref_ptr < osg : : Camera > camera ( new osg : : Camera ) ;
camera - > setRenderTargetImplementation ( osg : : Camera : : FRAME_BUFFER_OBJECT , osg : : Camera : : PIXEL_BUFFER_RTT ) ;
camera - > attach ( osg : : Camera : : COLOR_BUFFER , texture ) ;
camera - > setReferenceFrame ( osg : : Camera : : ABSOLUTE_RF ) ;
camera - > setViewMatrix ( osg : : Matrix : : identity ( ) ) ;
camera - > setProjectionMatrix ( osg : : Matrix : : identity ( ) ) ;
camera - > setProjectionResizePolicy ( osg : : Camera : : FIXED ) ;
camera - > setClearColor ( osg : : Vec4 ( 0.f , 0.f , 0.f , 1.f ) ) ;
camera - > setClearMask ( GL_COLOR_BUFFER_BIT ) ;
camera - > setViewport ( 0 , 0 , mCompositeMapSize , mCompositeMapSize ) ;
camera - > setRenderOrder ( osg : : Camera : : PRE_RENDER , - 1 ) ;
camera - > setImplicitBufferAttachmentMask ( osg : : DisplaySettings : : IMPLICIT_COLOR_BUFFER_ATTACHMENT ) ; // no need for a depth buffer
return camera ;
}
void ChunkManager : : createCompositeMapGeometry ( float chunkSize , const osg : : Vec2f & chunkCenter , const osg : : Vec4f & texCoords , osg : : Group * compositeMapNode )
{
if ( chunkSize > 1.f )
{
createCompositeMapGeometry ( chunkSize / 2.f , chunkCenter + osg : : Vec2f ( chunkSize / 4.f , chunkSize / 4.f ) , osg : : Vec4f ( texCoords . x ( ) + texCoords . z ( ) / 2.f , texCoords . y ( ) , texCoords . z ( ) / 2.f , texCoords . w ( ) / 2.f ) , compositeMapNode ) ;
createCompositeMapGeometry ( chunkSize / 2.f , chunkCenter + osg : : Vec2f ( - chunkSize / 4.f , chunkSize / 4.f ) , osg : : Vec4f ( texCoords . x ( ) , texCoords . y ( ) , texCoords . z ( ) / 2.f , texCoords . w ( ) / 2.f ) , compositeMapNode ) ;
createCompositeMapGeometry ( chunkSize / 2.f , chunkCenter + osg : : Vec2f ( chunkSize / 4.f , - chunkSize / 4.f ) , osg : : Vec4f ( texCoords . x ( ) + texCoords . z ( ) / 2.f , texCoords . y ( ) + texCoords . w ( ) / 2.f , texCoords . z ( ) / 2.f , texCoords . w ( ) / 2.f ) , compositeMapNode ) ;
createCompositeMapGeometry ( chunkSize / 2.f , chunkCenter + osg : : Vec2f ( - chunkSize / 4.f , - chunkSize / 4.f ) , osg : : Vec4f ( texCoords . x ( ) , texCoords . y ( ) + texCoords . w ( ) / 2.f , texCoords . z ( ) / 2.f , texCoords . w ( ) / 2.f ) , compositeMapNode ) ;
}
else
{
float left = texCoords . x ( ) * 2.f - 1 ;
float top = texCoords . y ( ) * 2.f - 1 ;
float width = texCoords . z ( ) * 2.f ;
float height = texCoords . w ( ) * 2.f ;
osg : : ref_ptr < osg : : Geometry > geom = osg : : createTexturedQuadGeometry ( osg : : Vec3 ( left , top , 0 ) , osg : : Vec3 ( width , 0 , 0 ) , osg : : Vec3 ( 0 , height , 0 ) ) ;
geom - > setTexCoordArray ( 1 , geom - > getTexCoordArray ( 0 ) , osg : : Array : : BIND_PER_VERTEX ) ;
std : : vector < osg : : ref_ptr < osg : : StateSet > > passes = createPasses ( chunkSize , chunkCenter , true ) ;
for ( std : : vector < osg : : ref_ptr < osg : : StateSet > > : : iterator it = passes . begin ( ) ; it ! = passes . end ( ) ; + + it )
{
osg : : ref_ptr < osg : : Group > group = new osg : : Group ;
group - > setStateSet ( * it ) ;
group - > addChild ( geom ) ;
compositeMapNode - > addChild ( group ) ;
}
}
}
std : : vector < osg : : ref_ptr < osg : : StateSet > > ChunkManager : : createPasses ( float chunkSize , const osg : : Vec2f & chunkCenter , bool forCompositeMap )
{
std : : vector < LayerInfo > layerList ;
std : : vector < osg : : ref_ptr < osg : : Image > > blendmaps ;
mStorage - > getBlendmaps ( chunkSize , chunkCenter , false , blendmaps , layerList ) ;
bool useShaders = mSceneManager - > getForceShaders ( ) ;
if ( ! mSceneManager - > getClampLighting ( ) & & ! forCompositeMap )
useShaders = true ; // always use shaders when lighting is unclamped, this is to avoid lighting seams between a terrain chunk with normal maps and one without normal maps
std : : vector < TextureLayer > layers ;
{
for ( std : : vector < LayerInfo > : : const_iterator it = layerList . begin ( ) ; it ! = layerList . end ( ) ; + + it )
{
TextureLayer textureLayer ;
textureLayer . mParallax = it - > mParallax ;
textureLayer . mSpecular = it - > mSpecular ;
textureLayer . mDiffuseMap = mTextureManager - > getTexture ( it - > mDiffuseMap ) ;
if ( ! forCompositeMap & & ! it - > mNormalMap . empty ( ) )
textureLayer . mNormalMap = mTextureManager - > getTexture ( it - > mNormalMap ) ;
if ( it - > requiresShaders ( ) )
useShaders = true ;
layers . push_back ( textureLayer ) ;
}
}
std : : vector < osg : : ref_ptr < osg : : Texture2D > > blendmapTextures ;
for ( std : : vector < osg : : ref_ptr < osg : : Image > > : : const_iterator it = blendmaps . begin ( ) ; it ! = blendmaps . end ( ) ; + + it )
{
osg : : ref_ptr < osg : : Texture2D > texture ( new osg : : Texture2D ) ;
texture - > setImage ( * it ) ;
texture - > setWrap ( osg : : Texture : : WRAP_S , osg : : Texture : : CLAMP_TO_EDGE ) ;
texture - > setWrap ( osg : : Texture : : WRAP_T , osg : : Texture : : CLAMP_TO_EDGE ) ;
texture - > setResizeNonPowerOfTwoHint ( false ) ;
blendmapTextures . push_back ( texture ) ;
}
float blendmapScale = mStorage - > getBlendmapScale ( chunkSize ) ;
return : : Terrain : : createPasses ( useShaders , mSceneManager - > getForcePerPixelLighting ( ) ,
mSceneManager - > getClampLighting ( ) , & mSceneManager - > getShaderManager ( ) , layers , blendmapTextures , blendmapScale , blendmapScale ) ;
}
osg : : ref_ptr < osg : : Node > ChunkManager : : createChunk ( float chunkSize , const osg : : Vec2f & chunkCenter , int lod , unsigned int lodFlags )
{
osg : : Vec2f worldCenter = chunkCenter * mStorage - > getCellWorldSize ( ) ;
osg : : ref_ptr < SceneUtil : : PositionAttitudeTransform > transform ( new SceneUtil : : PositionAttitudeTransform ) ;
transform - > setPosition ( osg : : Vec3f ( worldCenter . x ( ) , worldCenter . y ( ) , 0.f ) ) ;
osg : : ref_ptr < osg : : Vec3Array > positions ( new osg : : Vec3Array ) ;
osg : : ref_ptr < osg : : Vec3Array > normals ( new osg : : Vec3Array ) ;
osg : : ref_ptr < osg : : Vec4Array > colors ( new osg : : Vec4Array ) ;
osg : : ref_ptr < osg : : VertexBufferObject > vbo ( new osg : : VertexBufferObject ) ;
positions - > setVertexBufferObject ( vbo ) ;
normals - > setVertexBufferObject ( vbo ) ;
colors - > setVertexBufferObject ( vbo ) ;
mStorage - > fillVertexBuffers ( lod , chunkSize , chunkCenter , positions , normals , colors ) ;
osg : : ref_ptr < TerrainDrawable > geometry ( new TerrainDrawable ) ;
geometry - > setVertexArray ( positions ) ;
geometry - > setNormalArray ( normals , osg : : Array : : BIND_PER_VERTEX ) ;
geometry - > setColorArray ( colors , osg : : Array : : BIND_PER_VERTEX ) ;
geometry - > setUseDisplayList ( false ) ;
geometry - > setUseVertexBufferObjects ( true ) ;
unsigned int numVerts = ( mStorage - > getCellVertices ( ) - 1 ) * chunkSize / ( 1 < < lod ) + 1 ;
geometry - > addPrimitiveSet ( mBufferCache . getIndexBuffer ( numVerts , lodFlags ) ) ;
geometry - > getBound ( ) ;
bool useCompositeMap = chunkSize > = 1.f ;
unsigned int numUvSets = useCompositeMap ? 1 : 2 ;
for ( unsigned int i = 0 ; i < numUvSets ; + + i )
geometry - > setTexCoordArray ( i , mBufferCache . getUVBuffer ( numVerts ) ) ;
if ( useCompositeMap )
{
osg : : ref_ptr < osg : : Texture2D > compositeMap ;
osg : : ref_ptr < osg : : Group > compositeMapNode = createCompositeMapRTT ( compositeMap ) ;
createCompositeMapGeometry ( chunkSize , chunkCenter , osg : : Vec4f ( 0 , 0 , 1 , 1 ) , compositeMapNode ) ;
compositeMapNode - > getOrCreateStateSet ( ) - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
mCompositeMapRenderer - > addCompositeMap ( compositeMapNode , false ) ;
std : : vector < osg : : ref_ptr < osg : : StateSet > > passes2 ;
passes2 . push_back ( new osg : : StateSet ) ;
passes2 [ 0 ] - > setTextureAttributeAndModes ( 0 , compositeMap , osg : : StateAttribute : : ON ) ;
geometry - > setPasses ( passes2 ) ;
transform - > getOrCreateUserDataContainer ( ) - > addUserObject ( compositeMapNode ) ;
}
else
{
geometry - > setPasses ( createPasses ( chunkSize , chunkCenter , false ) ) ;
}
transform - > addChild ( geometry ) ;
if ( mSceneManager - > getIncrementalCompileOperation ( ) )
{
mSceneManager - > getIncrementalCompileOperation ( ) - > add ( geometry ) ;
}
return transform ;
}
}