forked from mirror/openmw-tes3mp
Factor out terrain chunk loading/caching into a new resource manager
parent
274690f790
commit
35d53acc65
@ -0,0 +1,180 @@
|
||||
#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"
|
||||
|
||||
namespace
|
||||
{
|
||||
class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback
|
||||
{
|
||||
public:
|
||||
StaticBoundingBoxCallback(const osg::BoundingBox& bounds)
|
||||
: mBoundingBox(bounds)
|
||||
{
|
||||
}
|
||||
|
||||
virtual osg::BoundingBox computeBound(const osg::Drawable&) const
|
||||
{
|
||||
return mBoundingBox;
|
||||
}
|
||||
|
||||
private:
|
||||
osg::BoundingBox mBoundingBox;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, TextureManager* textureManager)
|
||||
: ResourceManager(NULL)
|
||||
, mStorage(storage)
|
||||
, mSceneManager(sceneMgr)
|
||||
, mTextureManager(textureManager)
|
||||
, mShaderManager(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> ChunkManager::getChunk(float size, const osg::Vec2f ¢er)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << size << " " << center.x() << " " << center.y();
|
||||
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);
|
||||
mCache->addEntryToObjectCache(id, node.get());
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::setShaderManager(Shader::ShaderManager *shaderManager)
|
||||
{
|
||||
mShaderManager = shaderManager;
|
||||
}
|
||||
|
||||
void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats)
|
||||
{
|
||||
stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter)
|
||||
{
|
||||
float minH, maxH;
|
||||
if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH))
|
||||
return NULL; // no terrain defined
|
||||
|
||||
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);
|
||||
|
||||
unsigned int lod = 0;
|
||||
|
||||
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, 0));
|
||||
|
||||
|
||||
// we already know the bounding box, so no need to let OSG compute it.
|
||||
osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize,
|
||||
-0.5f*mStorage->getCellWorldSize()*chunkSize,
|
||||
minH);
|
||||
osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize,
|
||||
0.5f*mStorage->getCellWorldSize()*chunkSize,
|
||||
maxH);
|
||||
osg::BoundingBox bounds(min, max);
|
||||
geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds));
|
||||
|
||||
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())
|
||||
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 (!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);
|
||||
}
|
||||
|
||||
// use texture coordinates for both texture units, the layer texture and blend texture
|
||||
for (unsigned int i=0; i<2; ++i)
|
||||
geometry->setTexCoordArray(i, mBufferCache.getUVBuffer(numVerts));
|
||||
|
||||
float blendmapScale = mStorage->getBlendmapScale(chunkSize);
|
||||
|
||||
geometry->setPasses(createPasses(mShaderManager ? useShaders : false, mSceneManager->getForcePerPixelLighting(),
|
||||
mSceneManager->getClampLighting(), mShaderManager, layers, blendmapTextures, blendmapScale, blendmapScale));
|
||||
|
||||
transform->addChild(geometry);
|
||||
|
||||
if (mSceneManager->getIncrementalCompileOperation())
|
||||
{
|
||||
mSceneManager->getIncrementalCompileOperation()->add(geometry);
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
#ifndef OPENMW_COMPONENTS_TERRAIN_CHUNKMANAGER_H
|
||||
#define OPENMW_COMPONENTS_TERRAIN_CHUNKMANAGER_H
|
||||
|
||||
#include <components/resource/resourcemanager.hpp>
|
||||
|
||||
#include "buffercache.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Geometry;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class PositionAttitudeTransform;
|
||||
}
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace Shader
|
||||
{
|
||||
class ShaderManager;
|
||||
}
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
class TextureManager;
|
||||
class Storage;
|
||||
|
||||
/// @brief Handles loading and caching of terrain chunks
|
||||
class ChunkManager : public Resource::ResourceManager
|
||||
{
|
||||
public:
|
||||
ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager);
|
||||
|
||||
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center);
|
||||
|
||||
// Optional
|
||||
void setShaderManager(Shader::ShaderManager* shaderManager);
|
||||
|
||||
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats);
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center);
|
||||
|
||||
Terrain::Storage* mStorage;
|
||||
Resource::SceneManager* mSceneManager;
|
||||
TextureManager* mTextureManager;
|
||||
Shader::ShaderManager* mShaderManager;
|
||||
BufferCache mBufferCache;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue