|
|
|
@ -1,6 +1,8 @@
|
|
|
|
|
#include "terraingrid.hpp"
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <osg/io_utils>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
#include <components/resource/resourcesystem.hpp>
|
|
|
|
|
#include <components/resource/texturemanager.hpp>
|
|
|
|
@ -47,8 +49,10 @@ namespace Terrain
|
|
|
|
|
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
|
|
|
|
|
Storage* storage, int nodeMask)
|
|
|
|
|
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
|
|
|
|
|
, mNumSplits(4)
|
|
|
|
|
, mKdTreeBuilder(new osg::KdTreeBuilder)
|
|
|
|
|
{
|
|
|
|
|
mCache = BufferCache((storage->getCellVertices()-1)/static_cast<float>(mNumSplits) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TerrainGrid::~TerrainGrid()
|
|
|
|
@ -62,25 +66,39 @@ TerrainGrid::~TerrainGrid()
|
|
|
|
|
class GridElement
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
osg::ref_ptr<osg::PositionAttitudeTransform> mNode;
|
|
|
|
|
osg::ref_ptr<osg::Node> mNode;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
|
|
|
|
|
{
|
|
|
|
|
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
|
|
|
|
|
return; // already loaded
|
|
|
|
|
|
|
|
|
|
osg::Vec2f center(x+0.5f, y+0.5f);
|
|
|
|
|
if (chunkSize * mNumSplits > 1.f)
|
|
|
|
|
{
|
|
|
|
|
// keep splitting
|
|
|
|
|
osg::ref_ptr<osg::Group> group (new osg::Group);
|
|
|
|
|
if (parent)
|
|
|
|
|
parent->addChild(group);
|
|
|
|
|
std::cout << "splitting " << chunkSize << " " << std::endl;
|
|
|
|
|
float newChunkSize = chunkSize/2.f;
|
|
|
|
|
buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f));
|
|
|
|
|
buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f));
|
|
|
|
|
buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f));
|
|
|
|
|
buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f));
|
|
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
float minH, maxH;
|
|
|
|
|
if (!mStorage->getMinMaxHeights(1, center, minH, maxH))
|
|
|
|
|
return; // no terrain defined
|
|
|
|
|
if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH))
|
|
|
|
|
return NULL; // no terrain defined
|
|
|
|
|
|
|
|
|
|
std::auto_ptr<GridElement> element (new GridElement);
|
|
|
|
|
std::cout << "creating " << chunkSize << " " << chunkCenter << std::endl;
|
|
|
|
|
|
|
|
|
|
osg::Vec2f worldCenter = center*mStorage->getCellWorldSize();
|
|
|
|
|
element->mNode = new osg::PositionAttitudeTransform;
|
|
|
|
|
element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f));
|
|
|
|
|
mTerrainRoot->addChild(element->mNode);
|
|
|
|
|
osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize();
|
|
|
|
|
osg::ref_ptr<osg::PositionAttitudeTransform> transform (new osg::PositionAttitudeTransform);
|
|
|
|
|
transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f));
|
|
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
|
parent->addChild(transform);
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
|
|
|
|
|
osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
|
|
|
|
@ -91,7 +109,7 @@ void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
normals->setVertexBufferObject(vbo);
|
|
|
|
|
colors->setVertexBufferObject(vbo);
|
|
|
|
|
|
|
|
|
|
mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors);
|
|
|
|
|
mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors);
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
|
|
|
|
geometry->setVertexArray(positions);
|
|
|
|
@ -103,11 +121,11 @@ void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
geometry->addPrimitiveSet(mCache.getIndexBuffer(0));
|
|
|
|
|
|
|
|
|
|
// we already know the bounding box, so no need to let OSG compute it.
|
|
|
|
|
osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(),
|
|
|
|
|
-0.5f*mStorage->getCellWorldSize(),
|
|
|
|
|
osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize,
|
|
|
|
|
-0.5f*mStorage->getCellWorldSize()*chunkSize,
|
|
|
|
|
minH);
|
|
|
|
|
osg::Vec3f max (0.5f*mStorage->getCellWorldSize(),
|
|
|
|
|
0.5f*mStorage->getCellWorldSize(),
|
|
|
|
|
osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize,
|
|
|
|
|
0.5f*mStorage->getCellWorldSize()*chunkSize,
|
|
|
|
|
maxH);
|
|
|
|
|
osg::BoundingBox bounds(min, max);
|
|
|
|
|
geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds));
|
|
|
|
@ -115,13 +133,10 @@ void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
|
|
|
|
geode->addDrawable(geometry);
|
|
|
|
|
|
|
|
|
|
// build a kdtree to speed up intersection tests with the terrain
|
|
|
|
|
// Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree
|
|
|
|
|
geode->accept(*mKdTreeBuilder);
|
|
|
|
|
|
|
|
|
|
std::vector<LayerInfo> layerList;
|
|
|
|
|
std::vector<osg::ref_ptr<osg::Image> > blendmaps;
|
|
|
|
|
mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList);
|
|
|
|
|
mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList);
|
|
|
|
|
|
|
|
|
|
// For compiling textures, I don't think the osgFX::Effect does it correctly
|
|
|
|
|
osg::ref_ptr<osg::Node> textureCompileDummy (new osg::Node);
|
|
|
|
@ -152,18 +167,48 @@ void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
for (unsigned int i=0; i<2; ++i)
|
|
|
|
|
geometry->setTexCoordArray(i, mCache.getUVBuffer());
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osgFX::Effect> effect (new Terrain::Effect(layerTextures, blendmapTextures, ESM::Land::LAND_TEXTURE_SIZE, ESM::Land::LAND_TEXTURE_SIZE));
|
|
|
|
|
float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize;
|
|
|
|
|
osg::ref_ptr<osgFX::Effect> effect (new Terrain::Effect(layerTextures, blendmapTextures, blendmapScale, blendmapScale));
|
|
|
|
|
|
|
|
|
|
effect->addCullCallback(new SceneUtil::LightListCallback);
|
|
|
|
|
|
|
|
|
|
transform->addChild(effect);
|
|
|
|
|
effect->addChild(geode);
|
|
|
|
|
element->mNode->addChild(effect);
|
|
|
|
|
|
|
|
|
|
return transform;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TerrainGrid::loadCell(int x, int y)
|
|
|
|
|
{
|
|
|
|
|
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
|
|
|
|
|
return; // already loaded
|
|
|
|
|
|
|
|
|
|
osg::Vec2f center(x+0.5f, y+0.5f);
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Node> terrainNode = buildTerrain(NULL, 1.f, center);
|
|
|
|
|
if (!terrainNode)
|
|
|
|
|
return; // no terrain defined
|
|
|
|
|
|
|
|
|
|
std::auto_ptr<GridElement> element (new GridElement);
|
|
|
|
|
element->mNode = terrainNode;
|
|
|
|
|
mTerrainRoot->addChild(element->mNode);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// build a kdtree to speed up intersection tests with the terrain
|
|
|
|
|
// Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree
|
|
|
|
|
geode->accept(*mKdTreeBuilder);
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if (mIncrementalCompileOperation)
|
|
|
|
|
{
|
|
|
|
|
mIncrementalCompileOperation->add(geode);
|
|
|
|
|
mIncrementalCompileOperation->add(textureCompileDummy);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mGrid[std::make_pair(x,y)] = element.release();
|
|
|
|
|
}
|
|
|
|
|