You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/components/terrain/terraingrid.cpp

199 lines
6.8 KiB
C++

/*
* Copyright (c) 2015 scrawl <scrawl@baseoftrash.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
10 years ago
#include "terraingrid.hpp"
10 years ago
#include <memory>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <osg/PositionAttitudeTransform>
#include <osg/Geometry>
#include <osg/Geode>
#include <osgFX/Effect>
#include <osgUtil/IncrementalCompileOperation>
10 years ago
#include "material.hpp"
#include "storage.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
{
10 years ago
TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico,
Storage* storage, int nodeMask)
: Terrain::World(parent, resourceSystem, ico, storage, nodeMask)
{
}
TerrainGrid::~TerrainGrid()
{
while (!mGrid.empty())
{
unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second);
}
}
10 years ago
class GridElement
{
10 years ago
public:
osg::ref_ptr<osg::PositionAttitudeTransform> mNode;
};
void TerrainGrid::loadCell(int x, int y)
{
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
return; // already loaded
10 years ago
osg::Vec2f center(x+0.5f, y+0.5f);
float minH, maxH;
if (!mStorage->getMinMaxHeights(1, center, minH, maxH))
return; // no terrain defined
10 years ago
std::auto_ptr<GridElement> element (new GridElement);
10 years ago
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);
10 years ago
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);
10 years ago
mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors);
10 years ago
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
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);
10 years ago
geometry->addPrimitiveSet(mCache.getIndexBuffer(0));
10 years ago
// 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(),
minH);
osg::Vec3f max (0.5f*mStorage->getCellWorldSize(),
0.5f*mStorage->getCellWorldSize(),
maxH);
osg::BoundingBox bounds(min, max);
geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds));
10 years ago
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(geometry);
10 years ago
std::vector<LayerInfo> layerList;
std::vector<osg::ref_ptr<osg::Image> > blendmaps;
mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList);
10 years ago
// For compiling textures, I don't think the osgFX::Effect does it correctly
osg::ref_ptr<osg::Node> textureCompileDummy (new osg::Node);
10 years ago
std::vector<osg::ref_ptr<osg::Texture2D> > layerTextures;
for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
{
layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT));
textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back());
}
10 years ago
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->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
texture->setResizeNonPowerOfTwoHint(false);
blendmapTextures.push_back(texture);
textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back());
}
// use texture coordinates for both texture units, the layer texture and blend texture
for (unsigned int i=0; i<2; ++i)
10 years ago
geometry->setTexCoordArray(i, mCache.getUVBuffer());
10 years ago
osg::ref_ptr<osgFX::Effect> effect (new Terrain::Effect(layerTextures, blendmapTextures));
10 years ago
effect->addCullCallback(new SceneUtil::LightListCallback);
10 years ago
effect->addChild(geode);
element->mNode->addChild(effect);
10 years ago
if (mIncrementalCompileOperation)
{
10 years ago
mIncrementalCompileOperation->add(geode);
mIncrementalCompileOperation->add(textureCompileDummy);
}
10 years ago
mGrid[std::make_pair(x,y)] = element.release();
}
10 years ago
void TerrainGrid::unloadCell(int x, int y)
{
10 years ago
Grid::iterator it = mGrid.find(std::make_pair(x,y));
if (it == mGrid.end())
10 years ago
return;
10 years ago
GridElement* element = it->second;
mTerrainRoot->removeChild(element->mNode);
delete element;
10 years ago
mGrid.erase(it);
}
}