2017-03-06 19:41:02 +00:00
# include "chunkmanager.hpp"
# include <sstream>
# include <osg/Texture2D>
2019-08-10 13:37:00 +00:00
# include <osg/ClusterCullingCallback>
2020-05-07 13:37:00 +00:00
# include <osg/Material>
2017-03-06 19:41:02 +00:00
# include <osgUtil/IncrementalCompileOperation>
# include <components/resource/objectcache.hpp>
# include <components/resource/scenemanager.hpp>
2017-03-12 22:17:50 +00:00
# include <components/sceneutil/lightmanager.hpp>
2017-03-06 19:41:02 +00:00
# include "terraindrawable.hpp"
# include "material.hpp"
# include "storage.hpp"
# include "texturemanager.hpp"
2017-03-07 15:33:31 +00:00
# include "compositemaprenderer.hpp"
2017-03-06 19:41:02 +00:00
namespace Terrain
{
2017-03-07 15:33:31 +00:00
ChunkManager : : ChunkManager ( Storage * storage , Resource : : SceneManager * sceneMgr , TextureManager * textureManager , CompositeMapRenderer * renderer )
2019-03-13 07:15:58 +00:00
: GenericResourceManager < ChunkId > ( nullptr )
2017-03-06 19:41:02 +00:00
, mStorage ( storage )
, mSceneManager ( sceneMgr )
, mTextureManager ( textureManager )
2017-03-07 15:33:31 +00:00
, mCompositeMapRenderer ( renderer )
2020-06-18 10:50:06 +00:00
, mNodeMask ( 0 )
2017-03-07 15:33:31 +00:00
, mCompositeMapSize ( 512 )
2019-02-27 15:41:07 +00:00
, mCompositeMapLevel ( 1.f )
2019-02-28 08:48:04 +00:00
, mMaxCompGeometrySize ( 1.f )
2017-03-06 19:41:02 +00:00
{
2020-05-07 13:37:00 +00:00
mMultiPassRoot = new osg : : StateSet ;
mMultiPassRoot - > setRenderingHint ( osg : : StateSet : : OPAQUE_BIN ) ;
osg : : ref_ptr < osg : : Material > material ( new osg : : Material ) ;
material - > setColorMode ( osg : : Material : : AMBIENT_AND_DIFFUSE ) ;
mMultiPassRoot - > setAttributeAndModes ( material , osg : : StateAttribute : : ON ) ;
2017-03-06 19:41:02 +00:00
}
2020-01-12 07:42:47 +00:00
osg : : ref_ptr < osg : : Node > ChunkManager : : getChunk ( float size , const osg : : Vec2f & center , unsigned char lod , unsigned int lodFlags , bool activeGrid , const osg : : Vec3f & viewPoint , bool compile )
2017-03-06 19:41:02 +00:00
{
2019-03-13 07:15:58 +00:00
ChunkId id = std : : make_tuple ( center , lod , lodFlags ) ;
2017-03-06 19:41:02 +00:00
osg : : ref_ptr < osg : : Object > obj = mCache - > getRefFromObjectCache ( id ) ;
if ( obj )
return obj - > asNode ( ) ;
else
{
2020-04-30 13:37:00 +00:00
osg : : ref_ptr < osg : : Node > node = createChunk ( size , center , lod , lodFlags , compile ) ;
2017-03-06 19:41:02 +00:00
mCache - > addEntryToObjectCache ( id , node . get ( ) ) ;
return node ;
}
}
2017-03-07 03:02:06 +00:00
void ChunkManager : : reportStats ( unsigned int frameNumber , osg : : Stats * stats ) const
2017-03-06 19:41:02 +00:00
{
stats - > setAttribute ( frameNumber , " Terrain Chunk " , mCache - > getCacheSize ( ) ) ;
}
2017-08-21 02:34:41 +00:00
void ChunkManager : : clearCache ( )
{
2019-03-13 07:15:58 +00:00
GenericResourceManager < ChunkId > : : clearCache ( ) ;
2017-08-21 02:34:41 +00:00
mBufferCache . clearCache ( ) ;
}
2017-08-26 19:28:23 +00:00
void ChunkManager : : releaseGLObjects ( osg : : State * state )
{
2019-03-13 07:15:58 +00:00
GenericResourceManager < ChunkId > : : releaseGLObjects ( state ) ;
2017-08-26 19:28:23 +00:00
mBufferCache . releaseGLObjects ( state ) ;
}
2017-03-09 18:17:58 +00:00
osg : : ref_ptr < osg : : Texture2D > ChunkManager : : createCompositeMapRTT ( )
2017-03-07 15:33:31 +00:00
{
2017-03-09 18:17:58 +00:00
osg : : ref_ptr < osg : : Texture2D > texture = new osg : : Texture2D ;
2017-03-07 15:33:31 +00:00
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 ) ;
2017-03-09 18:17:58 +00:00
return texture ;
2017-03-07 15:33:31 +00:00
}
2017-03-09 18:17:58 +00:00
void ChunkManager : : createCompositeMapGeometry ( float chunkSize , const osg : : Vec2f & chunkCenter , const osg : : Vec4f & texCoords , CompositeMap & compositeMap )
2017-03-06 19:41:02 +00:00
{
2019-02-28 08:48:04 +00:00
if ( chunkSize > mMaxCompGeometrySize )
2017-03-08 21:13:05 +00:00
{
2017-03-09 18:17:58 +00:00
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 ) , compositeMap ) ;
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 ) , compositeMap ) ;
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 ) , compositeMap ) ;
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 ) , compositeMap ) ;
2017-03-08 21:13:05 +00:00
}
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 ;
2017-03-06 19:41:02 +00:00
2017-03-08 21:13:05 +00:00
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 )
{
2017-03-09 18:17:58 +00:00
osg : : ref_ptr < osg : : Geometry > geom = osg : : createTexturedQuadGeometry ( osg : : Vec3 ( left , top , 0 ) , osg : : Vec3 ( width , 0 , 0 ) , osg : : Vec3 ( 0 , height , 0 ) ) ;
geom - > setUseDisplayList ( false ) ; // don't bother making a display list for an object that is just rendered once.
geom - > setUseVertexBufferObjects ( false ) ;
geom - > setTexCoordArray ( 1 , geom - > getTexCoordArray ( 0 ) , osg : : Array : : BIND_PER_VERTEX ) ;
geom - > setStateSet ( * it ) ;
2020-10-17 08:26:35 +00:00
compositeMap . mDrawables . emplace_back ( geom ) ;
2017-03-08 21:13:05 +00:00
}
}
}
2017-03-06 19:41:02 +00:00
2017-03-08 21:13:05 +00:00
std : : vector < osg : : ref_ptr < osg : : StateSet > > ChunkManager : : createPasses ( float chunkSize , const osg : : Vec2f & chunkCenter , bool forCompositeMap )
{
2017-03-06 19:41:02 +00:00
std : : vector < LayerInfo > layerList ;
std : : vector < osg : : ref_ptr < osg : : Image > > blendmaps ;
2019-03-22 18:59:27 +00:00
mStorage - > getBlendmaps ( chunkSize , chunkCenter , blendmaps , layerList ) ;
2017-03-06 19:41:02 +00:00
bool useShaders = mSceneManager - > getForceShaders ( ) ;
2017-03-09 20:23:06 +00:00
if ( ! mSceneManager - > getClampLighting ( ) )
2017-03-06 19:41:02 +00:00
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
2017-03-09 20:23:06 +00:00
2017-03-06 19:41:02 +00:00
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 ) ;
2017-03-08 21:13:05 +00:00
if ( ! forCompositeMap & & ! it - > mNormalMap . empty ( ) )
2017-03-06 19:41:02 +00:00
textureLayer . mNormalMap = mTextureManager - > getTexture ( it - > mNormalMap ) ;
if ( it - > requiresShaders ( ) )
useShaders = true ;
layers . push_back ( textureLayer ) ;
}
}
2017-03-09 20:23:06 +00:00
if ( forCompositeMap )
useShaders = false ;
2017-03-06 19:41:02 +00:00
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 ) ;
2019-02-20 13:37:00 +00:00
return : : Terrain : : createPasses ( useShaders , & mSceneManager - > getShaderManager ( ) , layers , blendmapTextures , blendmapScale , blendmapScale ) ;
2017-03-08 21:13:05 +00:00
}
2020-04-30 13:37:00 +00:00
osg : : ref_ptr < osg : : Node > ChunkManager : : createChunk ( float chunkSize , const osg : : Vec2f & chunkCenter , unsigned char lod , unsigned int lodFlags , bool compile )
2017-03-08 21:13:05 +00:00
{
osg : : ref_ptr < osg : : Vec3Array > positions ( new osg : : Vec3Array ) ;
osg : : ref_ptr < osg : : Vec3Array > normals ( new osg : : Vec3Array ) ;
2019-02-20 13:37:00 +00:00
osg : : ref_ptr < osg : : Vec4ubArray > colors ( new osg : : Vec4ubArray ) ;
colors - > setNormalize ( true ) ;
2017-03-08 21:13:05 +00:00
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 ) ;
2017-03-07 14:04:41 +00:00
2019-02-20 13:37:00 +00:00
if ( chunkSize < = 1.f )
2017-03-12 22:17:50 +00:00
geometry - > setLightListCallback ( new SceneUtil : : LightListCallback ) ;
2017-03-08 21:13:05 +00:00
unsigned int numVerts = ( mStorage - > getCellVertices ( ) - 1 ) * chunkSize / ( 1 < < lod ) + 1 ;
2017-03-08 23:45:31 +00:00
geometry - > addPrimitiveSet ( mBufferCache . getIndexBuffer ( numVerts , lodFlags ) ) ;
2017-03-08 21:13:05 +00:00
2019-02-27 15:41:07 +00:00
bool useCompositeMap = chunkSize > = mCompositeMapLevel ;
2017-03-08 21:13:05 +00:00
unsigned int numUvSets = useCompositeMap ? 1 : 2 ;
2021-01-22 19:44:22 +00:00
geometry - > setTexCoordArrayList ( osg : : Geometry : : ArrayList ( numUvSets , mBufferCache . getUVBuffer ( numVerts ) ) ) ;
2017-03-08 21:13:05 +00:00
2019-08-10 13:37:00 +00:00
geometry - > createClusterCullingCallback ( ) ;
2020-05-07 13:37:00 +00:00
geometry - > setStateSet ( mMultiPassRoot ) ;
2017-03-08 21:13:05 +00:00
if ( useCompositeMap )
2017-03-07 15:33:31 +00:00
{
2017-03-09 18:17:58 +00:00
osg : : ref_ptr < CompositeMap > compositeMap = new CompositeMap ;
compositeMap - > mTexture = createCompositeMapRTT ( ) ;
2017-03-07 15:33:31 +00:00
2017-03-09 18:17:58 +00:00
createCompositeMapGeometry ( chunkSize , chunkCenter , osg : : Vec4f ( 0 , 0 , 1 , 1 ) , * compositeMap ) ;
2017-03-07 15:33:31 +00:00
2017-03-09 18:17:58 +00:00
mCompositeMapRenderer - > addCompositeMap ( compositeMap . get ( ) , false ) ;
2017-03-07 15:33:31 +00:00
2019-02-20 13:37:00 +00:00
geometry - > setCompositeMap ( compositeMap ) ;
geometry - > setCompositeMapRenderer ( mCompositeMapRenderer ) ;
2017-03-14 03:07:23 +00:00
TextureLayer layer ;
layer . mDiffuseMap = compositeMap - > mTexture ;
layer . mParallax = false ;
layer . mSpecular = false ;
2019-02-20 13:37:00 +00:00
geometry - > setPasses ( : : Terrain : : createPasses ( mSceneManager - > getForceShaders ( ) | | ! mSceneManager - > getClampLighting ( ) , & mSceneManager - > getShaderManager ( ) , std : : vector < TextureLayer > ( 1 , layer ) , std : : vector < osg : : ref_ptr < osg : : Texture2D > > ( ) , 1.f , 1.f ) ) ;
2017-03-07 15:33:31 +00:00
}
else
{
2017-03-08 21:13:05 +00:00
geometry - > setPasses ( createPasses ( chunkSize , chunkCenter , false ) ) ;
2017-03-07 15:33:31 +00:00
}
2017-03-06 19:41:02 +00:00
2020-04-23 09:12:10 +00:00
geometry - > setupWaterBoundingBox ( - 1 , chunkSize * mStorage - > getCellWorldSize ( ) / numVerts ) ;
2020-04-30 13:37:00 +00:00
if ( compile & & mSceneManager - > getIncrementalCompileOperation ( ) )
2017-03-06 19:41:02 +00:00
{
mSceneManager - > getIncrementalCompileOperation ( ) - > add ( geometry ) ;
}
2019-06-13 13:37:00 +00:00
geometry - > setNodeMask ( mNodeMask ) ;
return geometry ;
2017-03-06 19:41:02 +00:00
}
}