#include "chunkmanager.hpp" #include #include #include #include #include #include #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 ChunkManager::getChunk(float size, const osg::Vec2f ¢er, int lod, unsigned int lodFlags) { std::ostringstream stream; stream << size << " " << center.x() << " " << center.y() << " " << lod << " " << lodFlags; std::string id = stream.str(); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) return obj->asNode(); else { osg::ref_ptr 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 ChunkManager::createCompositeMapRTT(osg::ref_ptr& 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 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 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 > passes = createPasses(chunkSize, chunkCenter, true); for (std::vector >::iterator it = passes.begin(); it != passes.end(); ++it) { osg::ref_ptr group = new osg::Group; group->setStateSet(*it); group->addChild(geom); compositeMapNode->addChild(group); } } } std::vector > ChunkManager::createPasses(float chunkSize, const osg::Vec2f &chunkCenter, bool forCompositeMap) { std::vector layerList; std::vector > 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 layers; { for (std::vector::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 > blendmapTextures; for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) { osg::ref_ptr 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 ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod, unsigned int lodFlags) { osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); osg::ref_ptr transform (new SceneUtil::PositionAttitudeTransform); transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); osg::ref_ptr positions (new osg::Vec3Array); osg::ref_ptr normals (new osg::Vec3Array); osg::ref_ptr colors (new osg::Vec4Array); osg::ref_ptr vbo (new osg::VertexBufferObject); positions->setVertexBufferObject(vbo); normals->setVertexBufferObject(vbo); colors->setVertexBufferObject(vbo); mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, positions, normals, colors); osg::ref_ptr 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; isetTexCoordArray(i, mBufferCache.getUVBuffer(numVerts)); if (useCompositeMap) { osg::ref_ptr compositeMap; osg::ref_ptr 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 > 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; } }