mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
Apply clang-format to code base
This commit is contained in:
parent
f37d0be806
commit
ddb0522bbf
2199 changed files with 118692 additions and 114392 deletions
|
@ -9,167 +9,168 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
template <typename IndexArrayType>
|
||||
osg::ref_ptr<IndexArrayType> createIndexBuffer(unsigned int flags, unsigned int verts)
|
||||
{
|
||||
// LOD level n means every 2^n-th vertex is kept, but we currently handle LOD elsewhere.
|
||||
size_t lodLevel = 0;//(flags >> (4*4));
|
||||
|
||||
size_t lodDeltas[4];
|
||||
for (int i=0; i<4; ++i)
|
||||
lodDeltas[i] = (flags >> (4*i)) & (0xf);
|
||||
|
||||
bool anyDeltas = (lodDeltas[Terrain::North] || lodDeltas[Terrain::South] || lodDeltas[Terrain::West] || lodDeltas[Terrain::East]);
|
||||
|
||||
size_t increment = static_cast<size_t>(1) << lodLevel;
|
||||
assert(increment < verts);
|
||||
|
||||
osg::ref_ptr<IndexArrayType> indices (new IndexArrayType(osg::PrimitiveSet::TRIANGLES));
|
||||
indices->reserve((verts-1)*(verts-1)*2*3 / increment);
|
||||
|
||||
size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1;
|
||||
// If any edge needs stitching we'll skip all edges at this point,
|
||||
// mainly because stitching one edge would have an effect on corners and on the adjacent edges
|
||||
if (anyDeltas)
|
||||
template <typename IndexArrayType>
|
||||
osg::ref_ptr<IndexArrayType> createIndexBuffer(unsigned int flags, unsigned int verts)
|
||||
{
|
||||
colStart += increment;
|
||||
colEnd -= increment;
|
||||
rowEnd -= increment;
|
||||
rowStart += increment;
|
||||
// LOD level n means every 2^n-th vertex is kept, but we currently handle LOD elsewhere.
|
||||
size_t lodLevel = 0; //(flags >> (4*4));
|
||||
|
||||
size_t lodDeltas[4];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
lodDeltas[i] = (flags >> (4 * i)) & (0xf);
|
||||
|
||||
bool anyDeltas = (lodDeltas[Terrain::North] || lodDeltas[Terrain::South] || lodDeltas[Terrain::West]
|
||||
|| lodDeltas[Terrain::East]);
|
||||
|
||||
size_t increment = static_cast<size_t>(1) << lodLevel;
|
||||
assert(increment < verts);
|
||||
|
||||
osg::ref_ptr<IndexArrayType> indices(new IndexArrayType(osg::PrimitiveSet::TRIANGLES));
|
||||
indices->reserve((verts - 1) * (verts - 1) * 2 * 3 / increment);
|
||||
|
||||
size_t rowStart = 0, colStart = 0, rowEnd = verts - 1, colEnd = verts - 1;
|
||||
// If any edge needs stitching we'll skip all edges at this point,
|
||||
// mainly because stitching one edge would have an effect on corners and on the adjacent edges
|
||||
if (anyDeltas)
|
||||
{
|
||||
colStart += increment;
|
||||
colEnd -= increment;
|
||||
rowEnd -= increment;
|
||||
rowStart += increment;
|
||||
}
|
||||
for (size_t row = rowStart; row < rowEnd; row += increment)
|
||||
{
|
||||
for (size_t col = colStart; col < colEnd; col += increment)
|
||||
{
|
||||
// diamond pattern
|
||||
if ((row + col % 2) % 2 == 1)
|
||||
{
|
||||
indices->push_back(verts * (col + increment) + row);
|
||||
indices->push_back(verts * (col + increment) + row + increment);
|
||||
indices->push_back(verts * col + row + increment);
|
||||
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * (col + increment) + row);
|
||||
indices->push_back(verts * (col) + row + increment);
|
||||
}
|
||||
else
|
||||
{
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * (col + increment) + row + increment);
|
||||
indices->push_back(verts * col + row + increment);
|
||||
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * (col + increment) + row);
|
||||
indices->push_back(verts * (col + increment) + row + increment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t innerStep = increment;
|
||||
if (anyDeltas)
|
||||
{
|
||||
// Now configure LOD transitions at the edges - this is pretty tedious,
|
||||
// and some very long and boring code, but it works great
|
||||
|
||||
// South
|
||||
size_t row = 0;
|
||||
size_t outerStep = static_cast<size_t>(1) << (lodDeltas[Terrain::South] + lodLevel);
|
||||
for (size_t col = 0; col < verts - 1; col += outerStep)
|
||||
{
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * (col + outerStep) + row);
|
||||
// Make sure not to touch the right edge
|
||||
if (col + outerStep == verts - 1)
|
||||
indices->push_back(verts * (col + outerStep - innerStep) + row + innerStep);
|
||||
else
|
||||
indices->push_back(verts * (col + outerStep) + row + innerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the left or right edges
|
||||
if (col + i == 0 || col + i == verts - 1 - innerStep)
|
||||
continue;
|
||||
indices->push_back(verts * (col) + row);
|
||||
indices->push_back(verts * (col + i + innerStep) + row + innerStep);
|
||||
indices->push_back(verts * (col + i) + row + innerStep);
|
||||
}
|
||||
}
|
||||
|
||||
// North
|
||||
row = verts - 1;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel);
|
||||
for (size_t col = 0; col < verts - 1; col += outerStep)
|
||||
{
|
||||
indices->push_back(verts * (col + outerStep) + row);
|
||||
indices->push_back(verts * col + row);
|
||||
// Make sure not to touch the left edge
|
||||
if (col == 0)
|
||||
indices->push_back(verts * (col + innerStep) + row - innerStep);
|
||||
else
|
||||
indices->push_back(verts * col + row - innerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the left or right edges
|
||||
if (col + i == 0 || col + i == verts - 1 - innerStep)
|
||||
continue;
|
||||
indices->push_back(verts * (col + i) + row - innerStep);
|
||||
indices->push_back(verts * (col + i + innerStep) + row - innerStep);
|
||||
indices->push_back(verts * (col + outerStep) + row);
|
||||
}
|
||||
}
|
||||
|
||||
// West
|
||||
size_t col = 0;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel);
|
||||
for (row = 0; row < verts - 1; row += outerStep)
|
||||
{
|
||||
indices->push_back(verts * col + row + outerStep);
|
||||
indices->push_back(verts * col + row);
|
||||
// Make sure not to touch the top edge
|
||||
if (row + outerStep == verts - 1)
|
||||
indices->push_back(verts * (col + innerStep) + row + outerStep - innerStep);
|
||||
else
|
||||
indices->push_back(verts * (col + innerStep) + row + outerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the top or bottom edges
|
||||
if (row + i == 0 || row + i == verts - 1 - innerStep)
|
||||
continue;
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * (col + innerStep) + row + i);
|
||||
indices->push_back(verts * (col + innerStep) + row + i + innerStep);
|
||||
}
|
||||
}
|
||||
|
||||
// East
|
||||
col = verts - 1;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel);
|
||||
for (row = 0; row < verts - 1; row += outerStep)
|
||||
{
|
||||
indices->push_back(verts * col + row);
|
||||
indices->push_back(verts * col + row + outerStep);
|
||||
// Make sure not to touch the bottom edge
|
||||
if (row == 0)
|
||||
indices->push_back(verts * (col - innerStep) + row + innerStep);
|
||||
else
|
||||
indices->push_back(verts * (col - innerStep) + row);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the top or bottom edges
|
||||
if (row + i == 0 || row + i == verts - 1 - innerStep)
|
||||
continue;
|
||||
indices->push_back(verts * col + row + outerStep);
|
||||
indices->push_back(verts * (col - innerStep) + row + i + innerStep);
|
||||
indices->push_back(verts * (col - innerStep) + row + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
for (size_t row = rowStart; row < rowEnd; row += increment)
|
||||
{
|
||||
for (size_t col = colStart; col < colEnd; col += increment)
|
||||
{
|
||||
// diamond pattern
|
||||
if ((row + col%2) % 2 == 1)
|
||||
{
|
||||
indices->push_back(verts*(col+increment)+row);
|
||||
indices->push_back(verts*(col+increment)+row+increment);
|
||||
indices->push_back(verts*col+row+increment);
|
||||
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*(col+increment)+row);
|
||||
indices->push_back(verts*(col)+row+increment);
|
||||
}
|
||||
else
|
||||
{
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*(col+increment)+row+increment);
|
||||
indices->push_back(verts*col+row+increment);
|
||||
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*(col+increment)+row);
|
||||
indices->push_back(verts*(col+increment)+row+increment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t innerStep = increment;
|
||||
if (anyDeltas)
|
||||
{
|
||||
// Now configure LOD transitions at the edges - this is pretty tedious,
|
||||
// and some very long and boring code, but it works great
|
||||
|
||||
// South
|
||||
size_t row = 0;
|
||||
size_t outerStep = static_cast<size_t>(1) << (lodDeltas[Terrain::South] + lodLevel);
|
||||
for (size_t col = 0; col < verts-1; col += outerStep)
|
||||
{
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*(col+outerStep)+row);
|
||||
// Make sure not to touch the right edge
|
||||
if (col+outerStep == verts-1)
|
||||
indices->push_back(verts*(col+outerStep-innerStep)+row+innerStep);
|
||||
else
|
||||
indices->push_back(verts*(col+outerStep)+row+innerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the left or right edges
|
||||
if (col+i == 0 || col+i == verts-1-innerStep)
|
||||
continue;
|
||||
indices->push_back(verts*(col)+row);
|
||||
indices->push_back(verts*(col+i+innerStep)+row+innerStep);
|
||||
indices->push_back(verts*(col+i)+row+innerStep);
|
||||
}
|
||||
}
|
||||
|
||||
// North
|
||||
row = verts-1;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::North] + lodLevel);
|
||||
for (size_t col = 0; col < verts-1; col += outerStep)
|
||||
{
|
||||
indices->push_back(verts*(col+outerStep)+row);
|
||||
indices->push_back(verts*col+row);
|
||||
// Make sure not to touch the left edge
|
||||
if (col == 0)
|
||||
indices->push_back(verts*(col+innerStep)+row-innerStep);
|
||||
else
|
||||
indices->push_back(verts*col+row-innerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the left or right edges
|
||||
if (col+i == 0 || col+i == verts-1-innerStep)
|
||||
continue;
|
||||
indices->push_back(verts*(col+i)+row-innerStep);
|
||||
indices->push_back(verts*(col+i+innerStep)+row-innerStep);
|
||||
indices->push_back(verts*(col+outerStep)+row);
|
||||
}
|
||||
}
|
||||
|
||||
// West
|
||||
size_t col = 0;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::West] + lodLevel);
|
||||
for (row = 0; row < verts-1; row += outerStep)
|
||||
{
|
||||
indices->push_back(verts*col+row+outerStep);
|
||||
indices->push_back(verts*col+row);
|
||||
// Make sure not to touch the top edge
|
||||
if (row+outerStep == verts-1)
|
||||
indices->push_back(verts*(col+innerStep)+row+outerStep-innerStep);
|
||||
else
|
||||
indices->push_back(verts*(col+innerStep)+row+outerStep);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the top or bottom edges
|
||||
if (row+i == 0 || row+i == verts-1-innerStep)
|
||||
continue;
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*(col+innerStep)+row+i);
|
||||
indices->push_back(verts*(col+innerStep)+row+i+innerStep);
|
||||
}
|
||||
}
|
||||
|
||||
// East
|
||||
col = verts-1;
|
||||
outerStep = size_t(1) << (lodDeltas[Terrain::East] + lodLevel);
|
||||
for (row = 0; row < verts-1; row += outerStep)
|
||||
{
|
||||
indices->push_back(verts*col+row);
|
||||
indices->push_back(verts*col+row+outerStep);
|
||||
// Make sure not to touch the bottom edge
|
||||
if (row == 0)
|
||||
indices->push_back(verts*(col-innerStep)+row+innerStep);
|
||||
else
|
||||
indices->push_back(verts*(col-innerStep)+row);
|
||||
|
||||
for (size_t i = 0; i < outerStep; i += innerStep)
|
||||
{
|
||||
// Make sure not to touch the top or bottom edges
|
||||
if (row+i == 0 || row+i == verts-1-innerStep)
|
||||
continue;
|
||||
indices->push_back(verts*col+row+outerStep);
|
||||
indices->push_back(verts*(col-innerStep)+row+i+innerStep);
|
||||
indices->push_back(verts*(col-innerStep)+row+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -186,15 +187,15 @@ namespace Terrain
|
|||
|
||||
int vertexCount = numVerts * numVerts;
|
||||
|
||||
osg::ref_ptr<osg::Vec2Array> uvs (new osg::Vec2Array(osg::Array::BIND_PER_VERTEX));
|
||||
osg::ref_ptr<osg::Vec2Array> uvs(new osg::Vec2Array(osg::Array::BIND_PER_VERTEX));
|
||||
uvs->reserve(vertexCount);
|
||||
|
||||
for (unsigned int col = 0; col < numVerts; ++col)
|
||||
{
|
||||
for (unsigned int row = 0; row < numVerts; ++row)
|
||||
{
|
||||
uvs->push_back(osg::Vec2f(col / static_cast<float>(numVerts-1),
|
||||
((numVerts-1) - row) / static_cast<float>(numVerts-1)));
|
||||
uvs->push_back(osg::Vec2f(
|
||||
col / static_cast<float>(numVerts - 1), ((numVerts - 1) - row) / static_cast<float>(numVerts - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,7 +218,7 @@ namespace Terrain
|
|||
|
||||
osg::ref_ptr<osg::DrawElements> buffer;
|
||||
|
||||
if (numVerts*numVerts <= (0xffffu))
|
||||
if (numVerts * numVerts <= (0xffffu))
|
||||
buffer = createIndexBuffer<osg::DrawElementsUShort>(flags, numVerts);
|
||||
else
|
||||
buffer = createIndexBuffer<osg::DrawElementsUInt>(flags, numVerts);
|
||||
|
@ -241,7 +242,7 @@ namespace Terrain
|
|||
}
|
||||
}
|
||||
|
||||
void BufferCache::releaseGLObjects(osg::State *state)
|
||||
void BufferCache::releaseGLObjects(osg::State* state)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mIndexBufferMutex);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H
|
||||
#define COMPONENTS_TERRAIN_BUFFERCACHE_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Array>
|
||||
#include <osg/PrimitiveSet>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
@ -18,7 +18,7 @@ namespace Terrain
|
|||
/// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each)
|
||||
/// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices)
|
||||
/// @note Thread safe.
|
||||
osg::ref_ptr<osg::DrawElements> getIndexBuffer (unsigned int numVerts, unsigned int flags);
|
||||
osg::ref_ptr<osg::DrawElements> getIndexBuffer(unsigned int numVerts, unsigned int flags);
|
||||
|
||||
/// @note Thread safe.
|
||||
osg::ref_ptr<osg::Vec2Array> getUVBuffer(unsigned int numVerts);
|
||||
|
@ -30,10 +30,10 @@ namespace Terrain
|
|||
private:
|
||||
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
|
||||
// combination of LOD deltas and index buffer LOD we may need.
|
||||
std::map<std::pair<int, int>, osg::ref_ptr<osg::DrawElements> > mIndexBufferMap;
|
||||
std::map<std::pair<int, int>, osg::ref_ptr<osg::DrawElements>> mIndexBufferMap;
|
||||
std::mutex mIndexBufferMutex;
|
||||
|
||||
std::map<int, osg::ref_ptr<osg::Vec2Array> > mUvBufferMap;
|
||||
std::map<int, osg::ref_ptr<osg::Vec2Array>> mUvBufferMap;
|
||||
std::mutex mUvBufferMutex;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "cellborder.hpp"
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/Geometry>
|
||||
|
||||
#include "world.hpp"
|
||||
|
||||
|
@ -13,102 +13,100 @@
|
|||
namespace Terrain
|
||||
{
|
||||
|
||||
CellBorder::CellBorder(Terrain::World *world, osg::Group *root, int borderMask, Resource::SceneManager* sceneManager)
|
||||
: mWorld(world)
|
||||
, mSceneManager(sceneManager)
|
||||
, mRoot(root)
|
||||
, mBorderMask(borderMask)
|
||||
{
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Group> CellBorder::createBorderGeometry(float x, float y, float size, Terrain::Storage* terrain, Resource::SceneManager* sceneManager, int mask,
|
||||
float offset, osg::Vec4f color)
|
||||
{
|
||||
const int cellSize = ESM::Land::REAL_SIZE;
|
||||
const int borderSegments = 40;
|
||||
|
||||
osg::Vec3 cellCorner = osg::Vec3(x * cellSize,y * cellSize,0);
|
||||
size *= cellSize;
|
||||
|
||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
||||
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
|
||||
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
|
||||
|
||||
normals->push_back(osg::Vec3(0.0f,-1.0f, 0.0f));
|
||||
|
||||
float borderStep = size / ((float)borderSegments);
|
||||
|
||||
for (int i = 0; i <= 2 * borderSegments; ++i)
|
||||
CellBorder::CellBorder(
|
||||
Terrain::World* world, osg::Group* root, int borderMask, Resource::SceneManager* sceneManager)
|
||||
: mWorld(world)
|
||||
, mSceneManager(sceneManager)
|
||||
, mRoot(root)
|
||||
, mBorderMask(borderMask)
|
||||
{
|
||||
osg::Vec3f pos = i < borderSegments ?
|
||||
osg::Vec3(i * borderStep,0.0f,0.0f) :
|
||||
osg::Vec3(size, (i - borderSegments) * borderStep,0.0f);
|
||||
|
||||
pos += cellCorner;
|
||||
pos += osg::Vec3f(0,0, terrain->getHeightAt(pos) + offset);
|
||||
|
||||
vertices->push_back(pos);
|
||||
|
||||
osg::Vec4f col = i % 2 == 0 ?
|
||||
osg::Vec4f(0,0,0,1) :
|
||||
color;
|
||||
|
||||
colors->push_back(col);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Geometry> border = new osg::Geometry;
|
||||
border->setVertexArray(vertices.get());
|
||||
border->setNormalArray(normals.get());
|
||||
border->setNormalBinding(osg::Geometry::BIND_OVERALL);
|
||||
border->setColorArray(colors.get());
|
||||
border->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
|
||||
osg::ref_ptr<osg::Group> CellBorder::createBorderGeometry(float x, float y, float size, Terrain::Storage* terrain,
|
||||
Resource::SceneManager* sceneManager, int mask, float offset, osg::Vec4f color)
|
||||
{
|
||||
const int cellSize = ESM::Land::REAL_SIZE;
|
||||
const int borderSegments = 40;
|
||||
|
||||
border->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP,0,vertices->size()));
|
||||
osg::Vec3 cellCorner = osg::Vec3(x * cellSize, y * cellSize, 0);
|
||||
size *= cellSize;
|
||||
|
||||
osg::ref_ptr<osg::Group> borderGroup = new osg::Group;
|
||||
borderGroup->addChild(border.get());
|
||||
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
|
||||
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
|
||||
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
|
||||
|
||||
osg::StateSet *stateSet = borderGroup->getOrCreateStateSet();
|
||||
osg::ref_ptr<osg::Material> material (new osg::Material);
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
stateSet->setAttribute(material);
|
||||
normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));
|
||||
|
||||
osg::PolygonMode* polygonmode = new osg::PolygonMode;
|
||||
polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
|
||||
stateSet->setAttributeAndModes(polygonmode,osg::StateAttribute::ON);
|
||||
float borderStep = size / ((float)borderSegments);
|
||||
|
||||
sceneManager->recreateShaders(borderGroup, "debug");
|
||||
borderGroup->setNodeMask(mask);
|
||||
for (int i = 0; i <= 2 * borderSegments; ++i)
|
||||
{
|
||||
osg::Vec3f pos = i < borderSegments ? osg::Vec3(i * borderStep, 0.0f, 0.0f)
|
||||
: osg::Vec3(size, (i - borderSegments) * borderStep, 0.0f);
|
||||
|
||||
return borderGroup;
|
||||
}
|
||||
pos += cellCorner;
|
||||
pos += osg::Vec3f(0, 0, terrain->getHeightAt(pos) + offset);
|
||||
|
||||
void CellBorder::createCellBorderGeometry(int x, int y)
|
||||
{
|
||||
auto borderGroup = createBorderGeometry(x, y, 1.f, mWorld->getStorage(), mSceneManager, mBorderMask);
|
||||
mRoot->addChild(borderGroup);
|
||||
vertices->push_back(pos);
|
||||
|
||||
mCellBorderNodes[std::make_pair(x,y)] = borderGroup;
|
||||
}
|
||||
osg::Vec4f col = i % 2 == 0 ? osg::Vec4f(0, 0, 0, 1) : color;
|
||||
|
||||
void CellBorder::destroyCellBorderGeometry(int x, int y)
|
||||
{
|
||||
CellGrid::iterator it = mCellBorderNodes.find(std::make_pair(x,y));
|
||||
colors->push_back(col);
|
||||
}
|
||||
|
||||
if (it == mCellBorderNodes.end())
|
||||
return;
|
||||
osg::ref_ptr<osg::Geometry> border = new osg::Geometry;
|
||||
border->setVertexArray(vertices.get());
|
||||
border->setNormalArray(normals.get());
|
||||
border->setNormalBinding(osg::Geometry::BIND_OVERALL);
|
||||
border->setColorArray(colors.get());
|
||||
border->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
|
||||
|
||||
osg::ref_ptr<osg::Node> borderNode = it->second;
|
||||
mRoot->removeChild(borderNode);
|
||||
border->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, vertices->size()));
|
||||
|
||||
mCellBorderNodes.erase(it);
|
||||
}
|
||||
osg::ref_ptr<osg::Group> borderGroup = new osg::Group;
|
||||
borderGroup->addChild(border.get());
|
||||
|
||||
void CellBorder::destroyCellBorderGeometry()
|
||||
{
|
||||
for (const auto& v : mCellBorderNodes)
|
||||
mRoot->removeChild(v.second);
|
||||
mCellBorderNodes.clear();
|
||||
}
|
||||
osg::StateSet* stateSet = borderGroup->getOrCreateStateSet();
|
||||
osg::ref_ptr<osg::Material> material(new osg::Material);
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
stateSet->setAttribute(material);
|
||||
|
||||
osg::PolygonMode* polygonmode = new osg::PolygonMode;
|
||||
polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
|
||||
stateSet->setAttributeAndModes(polygonmode, osg::StateAttribute::ON);
|
||||
|
||||
sceneManager->recreateShaders(borderGroup, "debug");
|
||||
borderGroup->setNodeMask(mask);
|
||||
|
||||
return borderGroup;
|
||||
}
|
||||
|
||||
void CellBorder::createCellBorderGeometry(int x, int y)
|
||||
{
|
||||
auto borderGroup = createBorderGeometry(x, y, 1.f, mWorld->getStorage(), mSceneManager, mBorderMask);
|
||||
mRoot->addChild(borderGroup);
|
||||
|
||||
mCellBorderNodes[std::make_pair(x, y)] = borderGroup;
|
||||
}
|
||||
|
||||
void CellBorder::destroyCellBorderGeometry(int x, int y)
|
||||
{
|
||||
CellGrid::iterator it = mCellBorderNodes.find(std::make_pair(x, y));
|
||||
|
||||
if (it == mCellBorderNodes.end())
|
||||
return;
|
||||
|
||||
osg::ref_ptr<osg::Node> borderNode = it->second;
|
||||
mRoot->removeChild(borderNode);
|
||||
|
||||
mCellBorderNodes.erase(it);
|
||||
}
|
||||
|
||||
void CellBorder::destroyCellBorderGeometry()
|
||||
{
|
||||
for (const auto& v : mCellBorderNodes)
|
||||
mRoot->removeChild(v.second);
|
||||
mCellBorderNodes.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ namespace Terrain
|
|||
class CellBorder
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::pair<int, int>, osg::ref_ptr<osg::Node> > CellGrid;
|
||||
typedef std::map<std::pair<int, int>, osg::ref_ptr<osg::Node>> CellGrid;
|
||||
|
||||
CellBorder(Terrain::World *world, osg::Group *root, int borderMask, Resource::SceneManager* sceneManager);
|
||||
CellBorder(Terrain::World* world, osg::Group* root, int borderMask, Resource::SceneManager* sceneManager);
|
||||
|
||||
void createCellBorderGeometry(int x, int y);
|
||||
void destroyCellBorderGeometry(int x, int y);
|
||||
|
@ -32,12 +32,13 @@ namespace Terrain
|
|||
*/
|
||||
void destroyCellBorderGeometry();
|
||||
|
||||
static osg::ref_ptr<osg::Group> createBorderGeometry(float x, float y, float size, Storage* terrain, Resource::SceneManager* sceneManager, int mask, float offset = 10.0, osg::Vec4f color = { 1,1,0,0 });
|
||||
static osg::ref_ptr<osg::Group> createBorderGeometry(float x, float y, float size, Storage* terrain,
|
||||
Resource::SceneManager* sceneManager, int mask, float offset = 10.0, osg::Vec4f color = { 1, 1, 0, 0 });
|
||||
|
||||
protected:
|
||||
Terrain::World *mWorld;
|
||||
Terrain::World* mWorld;
|
||||
Resource::SceneManager* mSceneManager;
|
||||
osg::Group *mRoot;
|
||||
osg::Group* mRoot;
|
||||
|
||||
CellGrid mCellBorderNodes;
|
||||
int mBorderMask;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "chunkmanager.hpp"
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Material>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <osgUtil/IncrementalCompileOperation>
|
||||
|
||||
|
@ -10,279 +10,304 @@
|
|||
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
|
||||
#include "terraindrawable.hpp"
|
||||
#include "compositemaprenderer.hpp"
|
||||
#include "material.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "terraindrawable.hpp"
|
||||
#include "texturemanager.hpp"
|
||||
#include "compositemaprenderer.hpp"
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer)
|
||||
: GenericResourceManager<ChunkId>(nullptr)
|
||||
, mStorage(storage)
|
||||
, mSceneManager(sceneMgr)
|
||||
, mTextureManager(textureManager)
|
||||
, mCompositeMapRenderer(renderer)
|
||||
, mNodeMask(0)
|
||||
, mCompositeMapSize(512)
|
||||
, mCompositeMapLevel(1.f)
|
||||
, mMaxCompGeometrySize(1.f)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
struct FindChunkTemplate
|
||||
{
|
||||
void operator() (ChunkId id, osg::Object* obj)
|
||||
ChunkManager::ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
||||
CompositeMapRenderer* renderer)
|
||||
: GenericResourceManager<ChunkId>(nullptr)
|
||||
, mStorage(storage)
|
||||
, mSceneManager(sceneMgr)
|
||||
, mTextureManager(textureManager)
|
||||
, mCompositeMapRenderer(renderer)
|
||||
, mNodeMask(0)
|
||||
, mCompositeMapSize(512)
|
||||
, mCompositeMapLevel(1.f)
|
||||
, mMaxCompGeometrySize(1.f)
|
||||
{
|
||||
if (std::get<0>(id) == std::get<0>(mId) && std::get<1>(id) == std::get<1>(mId))
|
||||
mFoundTemplate = obj;
|
||||
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);
|
||||
}
|
||||
ChunkId mId;
|
||||
osg::ref_ptr<osg::Object> mFoundTemplate;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
// Override lod with the vertexLodMod adjusted value.
|
||||
// TODO: maybe we can refactor this code by moving all vertexLodMod code into this class.
|
||||
lod = static_cast<unsigned char>(lodFlags >> (4*4));
|
||||
ChunkId id = std::make_tuple(center, lod, lodFlags);
|
||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(id);
|
||||
if (obj)
|
||||
return static_cast<osg::Node*>(obj.get());
|
||||
else
|
||||
struct FindChunkTemplate
|
||||
{
|
||||
FindChunkTemplate find;
|
||||
find.mId = id;
|
||||
mCache->call(find);
|
||||
TerrainDrawable* templateGeometry = find.mFoundTemplate ? static_cast<TerrainDrawable*>(find.mFoundTemplate.get()) : nullptr;
|
||||
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile, templateGeometry);
|
||||
mCache->addEntryToObjectCache(id, node.get());
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const
|
||||
{
|
||||
stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
void ChunkManager::clearCache()
|
||||
{
|
||||
GenericResourceManager<ChunkId>::clearCache();
|
||||
|
||||
mBufferCache.clearCache();
|
||||
}
|
||||
|
||||
void ChunkManager::releaseGLObjects(osg::State *state)
|
||||
{
|
||||
GenericResourceManager<ChunkId>::releaseGLObjects(state);
|
||||
mBufferCache.releaseGLObjects(state);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> 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);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap)
|
||||
{
|
||||
if (chunkSize > mMaxCompGeometrySize)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
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)
|
||||
void operator()(ChunkId id, osg::Object* obj)
|
||||
{
|
||||
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);
|
||||
|
||||
compositeMap.mDrawables.emplace_back(geom);
|
||||
if (std::get<0>(id) == std::get<0>(mId) && std::get<1>(id) == std::get<1>(mId))
|
||||
mFoundTemplate = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
ChunkId mId;
|
||||
osg::ref_ptr<osg::Object> mFoundTemplate;
|
||||
};
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > ChunkManager::createPasses(float chunkSize, const osg::Vec2f &chunkCenter, bool forCompositeMap)
|
||||
{
|
||||
std::vector<LayerInfo> layerList;
|
||||
std::vector<osg::ref_ptr<osg::Image> > blendmaps;
|
||||
mStorage->getBlendmaps(chunkSize, chunkCenter, 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;
|
||||
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)
|
||||
{
|
||||
for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
|
||||
// Override lod with the vertexLodMod adjusted value.
|
||||
// TODO: maybe we can refactor this code by moving all vertexLodMod code into this class.
|
||||
lod = static_cast<unsigned char>(lodFlags >> (4 * 4));
|
||||
ChunkId id = std::make_tuple(center, lod, lodFlags);
|
||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(id);
|
||||
if (obj)
|
||||
return static_cast<osg::Node*>(obj.get());
|
||||
else
|
||||
{
|
||||
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);
|
||||
FindChunkTemplate find;
|
||||
find.mId = id;
|
||||
mCache->call(find);
|
||||
TerrainDrawable* templateGeometry
|
||||
= find.mFoundTemplate ? static_cast<TerrainDrawable*>(find.mFoundTemplate.get()) : nullptr;
|
||||
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile, templateGeometry);
|
||||
mCache->addEntryToObjectCache(id, node.get());
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
if (forCompositeMap)
|
||||
useShaders = false;
|
||||
|
||||
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)
|
||||
void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
|
||||
texture->setImage(*it);
|
||||
stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
void ChunkManager::clearCache()
|
||||
{
|
||||
GenericResourceManager<ChunkId>::clearCache();
|
||||
|
||||
mBufferCache.clearCache();
|
||||
}
|
||||
|
||||
void ChunkManager::releaseGLObjects(osg::State* state)
|
||||
{
|
||||
GenericResourceManager<ChunkId>::releaseGLObjects(state);
|
||||
mBufferCache.releaseGLObjects(state);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> ChunkManager::createCompositeMapRTT()
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> 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);
|
||||
texture->setResizeNonPowerOfTwoHint(false);
|
||||
blendmapTextures.push_back(texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
float blendmapScale = mStorage->getBlendmapScale(chunkSize);
|
||||
|
||||
return ::Terrain::createPasses(useShaders, mSceneManager, layers, blendmapTextures, blendmapScale, blendmapScale);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry)
|
||||
{
|
||||
osg::ref_ptr<TerrainDrawable> geometry (new TerrainDrawable);
|
||||
|
||||
if (!templateGeometry)
|
||||
void ChunkManager::createCompositeMapGeometry(
|
||||
float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap)
|
||||
{
|
||||
osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
|
||||
osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
|
||||
osg::ref_ptr<osg::Vec4ubArray> colors (new osg::Vec4ubArray);
|
||||
colors->setNormalize(true);
|
||||
|
||||
mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, positions, normals, colors);
|
||||
|
||||
osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
|
||||
positions->setVertexBufferObject(vbo);
|
||||
normals->setVertexBufferObject(vbo);
|
||||
colors->setVertexBufferObject(vbo);
|
||||
|
||||
geometry->setVertexArray(positions);
|
||||
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unfortunately we need to copy vertex data because of poor coupling with VertexBufferObject.
|
||||
osg::ref_ptr<osg::Array> positions = static_cast<osg::Array*>(templateGeometry->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
osg::ref_ptr<osg::Array> normals = static_cast<osg::Array*>(templateGeometry->getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
osg::ref_ptr<osg::Array> colors = static_cast<osg::Array*>(templateGeometry->getColorArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
|
||||
osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
|
||||
positions->setVertexBufferObject(vbo);
|
||||
normals->setVertexBufferObject(vbo);
|
||||
colors->setVertexBufferObject(vbo);
|
||||
|
||||
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);
|
||||
|
||||
if (chunkSize <= 1.f)
|
||||
geometry->setLightListCallback(new SceneUtil::LightListCallback);
|
||||
|
||||
unsigned int numVerts = (mStorage->getCellVertices()-1) * chunkSize / (1 << lod) + 1;
|
||||
|
||||
geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags));
|
||||
|
||||
bool useCompositeMap = chunkSize >= mCompositeMapLevel;
|
||||
unsigned int numUvSets = useCompositeMap ? 1 : 2;
|
||||
|
||||
geometry->setTexCoordArrayList(osg::Geometry::ArrayList(numUvSets, mBufferCache.getUVBuffer(numVerts)));
|
||||
|
||||
geometry->createClusterCullingCallback();
|
||||
|
||||
geometry->setStateSet(mMultiPassRoot);
|
||||
|
||||
if (templateGeometry)
|
||||
{
|
||||
if (templateGeometry->getCompositeMap())
|
||||
if (chunkSize > mMaxCompGeometrySize)
|
||||
{
|
||||
geometry->setCompositeMap(templateGeometry->getCompositeMap());
|
||||
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
|
||||
}
|
||||
geometry->setPasses(templateGeometry->getPasses());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (useCompositeMap)
|
||||
{
|
||||
osg::ref_ptr<CompositeMap> compositeMap = new CompositeMap;
|
||||
compositeMap->mTexture = createCompositeMapRTT();
|
||||
|
||||
createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), *compositeMap);
|
||||
|
||||
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
|
||||
|
||||
geometry->setCompositeMap(compositeMap);
|
||||
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
|
||||
|
||||
TextureLayer layer;
|
||||
layer.mDiffuseMap = compositeMap->mTexture;
|
||||
layer.mParallax = false;
|
||||
layer.mSpecular = false;
|
||||
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager, std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 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),
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry->setPasses(createPasses(chunkSize, chunkCenter, false));
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
compositeMap.mDrawables.emplace_back(geom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geometry->setupWaterBoundingBox(-1, chunkSize * mStorage->getCellWorldSize() / numVerts);
|
||||
|
||||
if (!templateGeometry && compile && mSceneManager->getIncrementalCompileOperation())
|
||||
std::vector<osg::ref_ptr<osg::StateSet>> ChunkManager::createPasses(
|
||||
float chunkSize, const osg::Vec2f& chunkCenter, bool forCompositeMap)
|
||||
{
|
||||
mSceneManager->getIncrementalCompileOperation()->add(geometry);
|
||||
std::vector<LayerInfo> layerList;
|
||||
std::vector<osg::ref_ptr<osg::Image>> blendmaps;
|
||||
mStorage->getBlendmaps(chunkSize, chunkCenter, 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 (!forCompositeMap && !it->mNormalMap.empty())
|
||||
textureLayer.mNormalMap = mTextureManager->getTexture(it->mNormalMap);
|
||||
|
||||
if (it->requiresShaders())
|
||||
useShaders = true;
|
||||
|
||||
layers.push_back(textureLayer);
|
||||
}
|
||||
}
|
||||
|
||||
if (forCompositeMap)
|
||||
useShaders = false;
|
||||
|
||||
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);
|
||||
|
||||
return ::Terrain::createPasses(
|
||||
useShaders, mSceneManager, layers, blendmapTextures, blendmapScale, blendmapScale);
|
||||
}
|
||||
geometry->setNodeMask(mNodeMask);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f& chunkCenter, unsigned char lod,
|
||||
unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry)
|
||||
{
|
||||
osg::ref_ptr<TerrainDrawable> geometry(new TerrainDrawable);
|
||||
|
||||
if (!templateGeometry)
|
||||
{
|
||||
osg::ref_ptr<osg::Vec3Array> positions(new osg::Vec3Array);
|
||||
osg::ref_ptr<osg::Vec3Array> normals(new osg::Vec3Array);
|
||||
osg::ref_ptr<osg::Vec4ubArray> colors(new osg::Vec4ubArray);
|
||||
colors->setNormalize(true);
|
||||
|
||||
mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, positions, normals, colors);
|
||||
|
||||
osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject);
|
||||
positions->setVertexBufferObject(vbo);
|
||||
normals->setVertexBufferObject(vbo);
|
||||
colors->setVertexBufferObject(vbo);
|
||||
|
||||
geometry->setVertexArray(positions);
|
||||
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
|
||||
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unfortunately we need to copy vertex data because of poor coupling with VertexBufferObject.
|
||||
osg::ref_ptr<osg::Array> positions
|
||||
= static_cast<osg::Array*>(templateGeometry->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
osg::ref_ptr<osg::Array> normals
|
||||
= static_cast<osg::Array*>(templateGeometry->getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
osg::ref_ptr<osg::Array> colors
|
||||
= static_cast<osg::Array*>(templateGeometry->getColorArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||
|
||||
osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject);
|
||||
positions->setVertexBufferObject(vbo);
|
||||
normals->setVertexBufferObject(vbo);
|
||||
colors->setVertexBufferObject(vbo);
|
||||
|
||||
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);
|
||||
|
||||
if (chunkSize <= 1.f)
|
||||
geometry->setLightListCallback(new SceneUtil::LightListCallback);
|
||||
|
||||
unsigned int numVerts = (mStorage->getCellVertices() - 1) * chunkSize / (1 << lod) + 1;
|
||||
|
||||
geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags));
|
||||
|
||||
bool useCompositeMap = chunkSize >= mCompositeMapLevel;
|
||||
unsigned int numUvSets = useCompositeMap ? 1 : 2;
|
||||
|
||||
geometry->setTexCoordArrayList(osg::Geometry::ArrayList(numUvSets, mBufferCache.getUVBuffer(numVerts)));
|
||||
|
||||
geometry->createClusterCullingCallback();
|
||||
|
||||
geometry->setStateSet(mMultiPassRoot);
|
||||
|
||||
if (templateGeometry)
|
||||
{
|
||||
if (templateGeometry->getCompositeMap())
|
||||
{
|
||||
geometry->setCompositeMap(templateGeometry->getCompositeMap());
|
||||
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
|
||||
}
|
||||
geometry->setPasses(templateGeometry->getPasses());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (useCompositeMap)
|
||||
{
|
||||
osg::ref_ptr<CompositeMap> compositeMap = new CompositeMap;
|
||||
compositeMap->mTexture = createCompositeMapRTT();
|
||||
|
||||
createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0, 0, 1, 1), *compositeMap);
|
||||
|
||||
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
|
||||
|
||||
geometry->setCompositeMap(compositeMap);
|
||||
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
|
||||
|
||||
TextureLayer layer;
|
||||
layer.mDiffuseMap = compositeMap->mTexture;
|
||||
layer.mParallax = false;
|
||||
layer.mSpecular = false;
|
||||
geometry->setPasses(::Terrain::createPasses(
|
||||
mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager,
|
||||
std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D>>(), 1.f, 1.f));
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry->setPasses(createPasses(chunkSize, chunkCenter, false));
|
||||
}
|
||||
}
|
||||
|
||||
geometry->setupWaterBoundingBox(-1, chunkSize * mStorage->getCellWorldSize() / numVerts);
|
||||
|
||||
if (!templateGeometry && compile && mSceneManager->getIncrementalCompileOperation())
|
||||
{
|
||||
mSceneManager->getIncrementalCompileOperation()->add(geometry);
|
||||
}
|
||||
geometry->setNodeMask(mNodeMask);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ namespace Terrain
|
|||
class ChunkManager : public Resource::GenericResourceManager<ChunkId>, public QuadTreeWorld::ChunkManager
|
||||
{
|
||||
public:
|
||||
ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager, CompositeMapRenderer* renderer);
|
||||
ChunkManager(Storage* storage, Resource::SceneManager* sceneMgr, TextureManager* textureManager,
|
||||
CompositeMapRenderer* renderer);
|
||||
|
||||
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) override;
|
||||
osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags,
|
||||
bool activeGrid, const osg::Vec3f& viewPoint, bool compile) override;
|
||||
|
||||
void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; }
|
||||
void setCompositeMapLevel(float level) { mCompositeMapLevel = level; }
|
||||
|
@ -52,13 +54,16 @@ namespace Terrain
|
|||
void releaseGLObjects(osg::State* state) override;
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry);
|
||||
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
||||
unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry);
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> createCompositeMapRTT();
|
||||
|
||||
void createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& map);
|
||||
void createCompositeMapGeometry(
|
||||
float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& map);
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(float chunkSize, const osg::Vec2f& chunkCenter, bool forCompositeMap);
|
||||
std::vector<osg::ref_ptr<osg::StateSet>> createPasses(
|
||||
float chunkSize, const osg::Vec2f& chunkCenter, bool forCompositeMap);
|
||||
|
||||
Terrain::Storage* mStorage;
|
||||
Resource::SceneManager* mSceneManager;
|
||||
|
|
|
@ -1,199 +1,191 @@
|
|||
#include "compositemaprenderer.hpp"
|
||||
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/RenderInfo>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
CompositeMapRenderer::CompositeMapRenderer()
|
||||
: mTargetFrameRate(120)
|
||||
, mMinimumTimeAvailable(0.0025)
|
||||
{
|
||||
setSupportsDisplayList(false);
|
||||
setCullingActive(false);
|
||||
|
||||
mFBO = new osg::FrameBufferObject;
|
||||
|
||||
getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
CompositeMapRenderer::~CompositeMapRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const
|
||||
{
|
||||
double dt = mTimer.time_s();
|
||||
dt = std::min(dt, 0.2);
|
||||
mTimer.setStartTick();
|
||||
double targetFrameTime = 1.0/static_cast<double>(mTargetFrameRate);
|
||||
double conservativeTimeRatio(0.75);
|
||||
double availableTime = std::max((targetFrameTime - dt)*conservativeTimeRatio,
|
||||
mMinimumTimeAvailable);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
|
||||
if (mImmediateCompileSet.empty() && mCompileSet.empty())
|
||||
return;
|
||||
|
||||
while (!mImmediateCompileSet.empty())
|
||||
CompositeMapRenderer::CompositeMapRenderer()
|
||||
: mTargetFrameRate(120)
|
||||
, mMinimumTimeAvailable(0.0025)
|
||||
{
|
||||
osg::ref_ptr<CompositeMap> node = *mImmediateCompileSet.begin();
|
||||
mImmediateCompileSet.erase(node);
|
||||
setSupportsDisplayList(false);
|
||||
setCullingActive(false);
|
||||
|
||||
mMutex.unlock();
|
||||
compile(*node, renderInfo, nullptr);
|
||||
mMutex.lock();
|
||||
mFBO = new osg::FrameBufferObject;
|
||||
|
||||
getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
double timeLeft = availableTime;
|
||||
CompositeMapRenderer::~CompositeMapRenderer() {}
|
||||
|
||||
while (!mCompileSet.empty() && timeLeft > 0)
|
||||
void CompositeMapRenderer::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
osg::ref_ptr<CompositeMap> node = *mCompileSet.begin();
|
||||
mCompileSet.erase(node);
|
||||
double dt = mTimer.time_s();
|
||||
dt = std::min(dt, 0.2);
|
||||
mTimer.setStartTick();
|
||||
double targetFrameTime = 1.0 / static_cast<double>(mTargetFrameRate);
|
||||
double conservativeTimeRatio(0.75);
|
||||
double availableTime = std::max((targetFrameTime - dt) * conservativeTimeRatio, mMinimumTimeAvailable);
|
||||
|
||||
mMutex.unlock();
|
||||
compile(*node, renderInfo, &timeLeft);
|
||||
mMutex.lock();
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
|
||||
if (node->mCompiled < node->mDrawables.size())
|
||||
if (mImmediateCompileSet.empty() && mCompileSet.empty())
|
||||
return;
|
||||
|
||||
while (!mImmediateCompileSet.empty())
|
||||
{
|
||||
// We did not compile the map fully.
|
||||
// Place it back to queue to continue work in the next time.
|
||||
mCompileSet.insert(node);
|
||||
osg::ref_ptr<CompositeMap> node = *mImmediateCompileSet.begin();
|
||||
mImmediateCompileSet.erase(node);
|
||||
|
||||
mMutex.unlock();
|
||||
compile(*node, renderInfo, nullptr);
|
||||
mMutex.lock();
|
||||
}
|
||||
}
|
||||
mTimer.setStartTick();
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo &renderInfo, double* timeLeft) const
|
||||
{
|
||||
// if there are no more external references we can assume the texture is no longer required
|
||||
if (compositeMap.mTexture->referenceCount() <= 1)
|
||||
{
|
||||
compositeMap.mCompiled = compositeMap.mDrawables.size();
|
||||
return;
|
||||
double timeLeft = availableTime;
|
||||
|
||||
while (!mCompileSet.empty() && timeLeft > 0)
|
||||
{
|
||||
osg::ref_ptr<CompositeMap> node = *mCompileSet.begin();
|
||||
mCompileSet.erase(node);
|
||||
|
||||
mMutex.unlock();
|
||||
compile(*node, renderInfo, &timeLeft);
|
||||
mMutex.lock();
|
||||
|
||||
if (node->mCompiled < node->mDrawables.size())
|
||||
{
|
||||
// We did not compile the map fully.
|
||||
// Place it back to queue to continue work in the next time.
|
||||
mCompileSet.insert(node);
|
||||
}
|
||||
}
|
||||
mTimer.setStartTick();
|
||||
}
|
||||
|
||||
osg::Timer timer;
|
||||
osg::State& state = *renderInfo.getState();
|
||||
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
|
||||
|
||||
if (!mFBO)
|
||||
return;
|
||||
|
||||
if (!ext->isFrameBufferObjectSupported)
|
||||
return;
|
||||
|
||||
osg::FrameBufferAttachment attach (compositeMap.mTexture);
|
||||
mFBO->setAttachment(osg::Camera::COLOR_BUFFER, attach);
|
||||
mFBO->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
|
||||
GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
void CompositeMapRenderer::compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo, double* timeLeft) const
|
||||
{
|
||||
// if there are no more external references we can assume the texture is no longer required
|
||||
if (compositeMap.mTexture->referenceCount() <= 1)
|
||||
{
|
||||
compositeMap.mCompiled = compositeMap.mDrawables.size();
|
||||
return;
|
||||
}
|
||||
|
||||
osg::Timer timer;
|
||||
osg::State& state = *renderInfo.getState();
|
||||
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
|
||||
|
||||
if (!mFBO)
|
||||
return;
|
||||
|
||||
if (!ext->isFrameBufferObjectSupported)
|
||||
return;
|
||||
|
||||
osg::FrameBufferAttachment attach(compositeMap.mTexture);
|
||||
mFBO->setAttachment(osg::Camera::COLOR_BUFFER, attach);
|
||||
mFBO->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
|
||||
|
||||
GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
|
||||
OSG_ALWAYS << "Error attaching FBO" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// inform State that Texture attribute has changed due to compiling of FBO texture
|
||||
// should OSG be doing this on its own?
|
||||
state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), osg::StateAttribute::TEXTURE);
|
||||
|
||||
for (unsigned int i = compositeMap.mCompiled; i < compositeMap.mDrawables.size(); ++i)
|
||||
{
|
||||
osg::Drawable* drw = compositeMap.mDrawables[i];
|
||||
osg::StateSet* stateset = drw->getStateSet();
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->pushStateSet(stateset);
|
||||
|
||||
renderInfo.getState()->apply();
|
||||
|
||||
glViewport(0, 0, compositeMap.mTexture->getTextureWidth(), compositeMap.mTexture->getTextureHeight());
|
||||
drw->drawImplementation(renderInfo);
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->popStateSet();
|
||||
|
||||
++compositeMap.mCompiled;
|
||||
|
||||
compositeMap.mDrawables[i] = nullptr;
|
||||
|
||||
if (timeLeft)
|
||||
{
|
||||
*timeLeft -= timer.time_s();
|
||||
timer.setStartTick();
|
||||
|
||||
if (*timeLeft <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (compositeMap.mCompiled == compositeMap.mDrawables.size())
|
||||
compositeMap.mDrawables = std::vector<osg::ref_ptr<osg::Drawable>>();
|
||||
|
||||
state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT);
|
||||
|
||||
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
|
||||
OSG_ALWAYS << "Error attaching FBO" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// inform State that Texture attribute has changed due to compiling of FBO texture
|
||||
// should OSG be doing this on its own?
|
||||
state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), osg::StateAttribute::TEXTURE);
|
||||
|
||||
for (unsigned int i=compositeMap.mCompiled; i<compositeMap.mDrawables.size(); ++i)
|
||||
void CompositeMapRenderer::setMinimumTimeAvailableForCompile(double time)
|
||||
{
|
||||
osg::Drawable* drw = compositeMap.mDrawables[i];
|
||||
osg::StateSet* stateset = drw->getStateSet();
|
||||
mMinimumTimeAvailable = time;
|
||||
}
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->pushStateSet(stateset);
|
||||
void CompositeMapRenderer::setTargetFrameRate(float framerate)
|
||||
{
|
||||
mTargetFrameRate = framerate;
|
||||
}
|
||||
|
||||
renderInfo.getState()->apply();
|
||||
void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
if (immediate)
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
else
|
||||
mCompileSet.insert(compositeMap);
|
||||
}
|
||||
|
||||
glViewport(0,0,compositeMap.mTexture->getTextureWidth(), compositeMap.mTexture->getTextureHeight());
|
||||
drw->drawImplementation(renderInfo);
|
||||
|
||||
if (stateset)
|
||||
renderInfo.getState()->popStateSet();
|
||||
|
||||
++compositeMap.mCompiled;
|
||||
|
||||
compositeMap.mDrawables[i] = nullptr;
|
||||
|
||||
if (timeLeft)
|
||||
void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
CompileSet::iterator found = mCompileSet.find(compositeMap);
|
||||
if (found == mCompileSet.end())
|
||||
return;
|
||||
else
|
||||
{
|
||||
*timeLeft -= timer.time_s();
|
||||
timer.setStartTick();
|
||||
|
||||
if (*timeLeft <= 0)
|
||||
break;
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
mCompileSet.erase(found);
|
||||
}
|
||||
}
|
||||
if (compositeMap.mCompiled == compositeMap.mDrawables.size())
|
||||
compositeMap.mDrawables = std::vector<osg::ref_ptr<osg::Drawable>>();
|
||||
|
||||
state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT);
|
||||
|
||||
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::setMinimumTimeAvailableForCompile(double time)
|
||||
{
|
||||
mMinimumTimeAvailable = time;
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::setTargetFrameRate(float framerate)
|
||||
{
|
||||
mTargetFrameRate = framerate;
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
if (immediate)
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
else
|
||||
mCompileSet.insert(compositeMap);
|
||||
}
|
||||
|
||||
void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
CompileSet::iterator found = mCompileSet.find(compositeMap);
|
||||
if (found == mCompileSet.end())
|
||||
return;
|
||||
else
|
||||
unsigned int CompositeMapRenderer::getCompileSetSize() const
|
||||
{
|
||||
mImmediateCompileSet.insert(compositeMap);
|
||||
mCompileSet.erase(found);
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
return mCompileSet.size();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CompositeMapRenderer::getCompileSetSize() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
return mCompileSet.size();
|
||||
}
|
||||
|
||||
CompositeMap::CompositeMap()
|
||||
: mCompiled(0)
|
||||
{
|
||||
}
|
||||
|
||||
CompositeMap::~CompositeMap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CompositeMap::CompositeMap()
|
||||
: mCompiled(0)
|
||||
{
|
||||
}
|
||||
|
||||
CompositeMap::~CompositeMap() {}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#include <osg/Drawable>
|
||||
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
|
@ -21,13 +21,14 @@ namespace Terrain
|
|||
public:
|
||||
CompositeMap();
|
||||
~CompositeMap();
|
||||
std::vector<osg::ref_ptr<osg::Drawable> > mDrawables;
|
||||
std::vector<osg::ref_ptr<osg::Drawable>> mDrawables;
|
||||
osg::ref_ptr<osg::Texture2D> mTexture;
|
||||
unsigned int mCompiled;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The CompositeMapRenderer is responsible for updating composite map textures in a blocking or non-blocking way.
|
||||
* @brief The CompositeMapRenderer is responsible for updating composite map textures in a blocking or non-blocking
|
||||
* way.
|
||||
*/
|
||||
class CompositeMapRenderer : public osg::Drawable
|
||||
{
|
||||
|
@ -46,7 +47,7 @@ namespace Terrain
|
|||
void setTargetFrameRate(float framerate);
|
||||
|
||||
/// Add a composite map to be rendered
|
||||
void addCompositeMap(CompositeMap* map, bool immediate=false);
|
||||
void addCompositeMap(CompositeMap* map, bool immediate = false);
|
||||
|
||||
/// Mark this composite map to be required for the current frame
|
||||
void setImmediate(CompositeMap* map);
|
||||
|
@ -58,7 +59,7 @@ namespace Terrain
|
|||
double mMinimumTimeAvailable;
|
||||
mutable osg::Timer mTimer;
|
||||
|
||||
typedef std::set<osg::ref_ptr<CompositeMap> > CompileSet;
|
||||
typedef std::set<osg::ref_ptr<CompositeMap>> CompileSet;
|
||||
|
||||
mutable CompileSet mCompileSet;
|
||||
mutable CompileSet mImmediateCompileSet;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef COMPONENTS_TERRAIN_HEIGHTCULL_H
|
||||
#define COMPONENTS_TERRAIN_HEIGHTCULL_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
@ -19,38 +19,21 @@ namespace Terrain
|
|||
class HeightCullCallback : public SceneUtil::NodeCallback<HeightCullCallback>
|
||||
{
|
||||
public:
|
||||
void setLowZ(float z)
|
||||
{
|
||||
mLowZ = z;
|
||||
}
|
||||
float getLowZ() const
|
||||
{
|
||||
return mLowZ;
|
||||
}
|
||||
void setLowZ(float z) { mLowZ = z; }
|
||||
float getLowZ() const { return mLowZ; }
|
||||
|
||||
void setHighZ(float highZ)
|
||||
{
|
||||
mHighZ = highZ;
|
||||
}
|
||||
float getHighZ() const
|
||||
{
|
||||
return mHighZ;
|
||||
}
|
||||
void setHighZ(float highZ) { mHighZ = highZ; }
|
||||
float getHighZ() const { return mHighZ; }
|
||||
|
||||
void setCullMask(unsigned int mask)
|
||||
{
|
||||
mMask = mask;
|
||||
}
|
||||
unsigned int getCullMask() const
|
||||
{
|
||||
return mMask;
|
||||
}
|
||||
void setCullMask(unsigned int mask) { mMask = mask; }
|
||||
unsigned int getCullMask() const { return mMask; }
|
||||
|
||||
void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (mLowZ <= mHighZ)
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
private:
|
||||
float mLowZ{ -std::numeric_limits<float>::max() };
|
||||
float mHighZ{ std::numeric_limits<float>::max() };
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#include "material.hpp"
|
||||
|
||||
#include <osg/Fog>
|
||||
#include <osg/Depth>
|
||||
#include <osg/TexEnvCombine>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Capability>
|
||||
#include <osg/Depth>
|
||||
#include <osg/Fog>
|
||||
#include <osg/TexEnvCombine>
|
||||
#include <osg/TexMat>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <components/stereo/stereomanager.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/shader/shadermanager.hpp>
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
#include <components/shader/shadermanager.hpp>
|
||||
#include <components/stereo/stereomanager.hpp>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
|
@ -33,13 +33,14 @@ namespace
|
|||
if (texMat == mTexMatMap.end())
|
||||
{
|
||||
osg::Matrixf matrix;
|
||||
float scale = (blendmapScale/(static_cast<float>(blendmapScale)+1.f));
|
||||
float scale = (blendmapScale / (static_cast<float>(blendmapScale) + 1.f));
|
||||
matrix.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f));
|
||||
matrix.preMultScale(osg::Vec3f(scale, scale, 1.f));
|
||||
matrix.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f));
|
||||
// We need to nudge the blendmap to look like vanilla.
|
||||
// This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the blendmap, apparently.
|
||||
matrix.preMultTranslate(osg::Vec3f(1.0f/blendmapScale/4.0f, 1.0f/blendmapScale/4.0f, 0.f));
|
||||
// This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the
|
||||
// blendmap, apparently.
|
||||
matrix.preMultTranslate(osg::Vec3f(1.0f / blendmapScale / 4.0f, 1.0f / blendmapScale / 4.0f, 0.f));
|
||||
|
||||
texMat = mTexMatMap.insert(std::make_pair(blendmapScale, new osg::TexMat(matrix))).first;
|
||||
}
|
||||
|
@ -66,8 +67,10 @@ namespace
|
|||
auto texMat = mTexMatMap.find(layerTileSize);
|
||||
if (texMat == mTexMatMap.end())
|
||||
{
|
||||
texMat = mTexMatMap.insert(std::make_pair(layerTileSize,
|
||||
new osg::TexMat(osg::Matrix::scale(osg::Vec3f(layerTileSize, layerTileSize, 1.f))))).first;
|
||||
texMat = mTexMatMap
|
||||
.insert(std::make_pair(layerTileSize,
|
||||
new osg::TexMat(osg::Matrix::scale(osg::Vec3f(layerTileSize, layerTileSize, 1.f)))))
|
||||
.first;
|
||||
}
|
||||
return texMat->second;
|
||||
}
|
||||
|
@ -196,18 +199,19 @@ namespace
|
|||
|
||||
namespace Terrain
|
||||
{
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager, const std::vector<TextureLayer> &layers,
|
||||
const std::vector<osg::ref_ptr<osg::Texture2D> > &blendmaps, int blendmapScale, float layerTileSize)
|
||||
std::vector<osg::ref_ptr<osg::StateSet>> createPasses(bool useShaders, Resource::SceneManager* sceneManager,
|
||||
const std::vector<TextureLayer>& layers, const std::vector<osg::ref_ptr<osg::Texture2D>>& blendmaps,
|
||||
int blendmapScale, float layerTileSize)
|
||||
{
|
||||
auto& shaderManager = sceneManager->getShaderManager();
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > passes;
|
||||
std::vector<osg::ref_ptr<osg::StateSet>> passes;
|
||||
|
||||
unsigned int blendmapIndex = 0;
|
||||
for (std::vector<TextureLayer>::const_iterator it = layers.begin(); it != layers.end(); ++it)
|
||||
{
|
||||
bool firstLayer = (it == layers.begin());
|
||||
|
||||
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
|
||||
osg::ref_ptr<osg::StateSet> stateset(new osg::StateSet);
|
||||
|
||||
if (!blendmaps.empty())
|
||||
{
|
||||
|
@ -232,7 +236,8 @@ namespace Terrain
|
|||
stateset->setTextureAttributeAndModes(0, it->mDiffuseMap);
|
||||
|
||||
if (layerTileSize != 1.f)
|
||||
stateset->setTextureAttributeAndModes(0, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(
|
||||
0, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);
|
||||
|
||||
stateset->addUniform(UniformCollection::value().mDiffuseMap);
|
||||
|
||||
|
@ -259,8 +264,10 @@ namespace Terrain
|
|||
defineMap["writeNormals"] = (it == layers.end() - 1) ? "1" : "0";
|
||||
Stereo::Manager::instance().shaderStereoDefines(defineMap);
|
||||
|
||||
osg::ref_ptr<osg::Shader> vertexShader = shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX);
|
||||
osg::ref_ptr<osg::Shader> fragmentShader = shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT);
|
||||
osg::ref_ptr<osg::Shader> vertexShader
|
||||
= shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX);
|
||||
osg::ref_ptr<osg::Shader> fragmentShader
|
||||
= shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT);
|
||||
if (!vertexShader || !fragmentShader)
|
||||
{
|
||||
// Try again without shader. Error already logged by above
|
||||
|
@ -277,7 +284,8 @@ namespace Terrain
|
|||
stateset->setTextureAttributeAndModes(0, tex.get());
|
||||
|
||||
if (layerTileSize != 1.f)
|
||||
stateset->setTextureAttributeAndModes(0, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);
|
||||
stateset->setTextureAttributeAndModes(
|
||||
0, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);
|
||||
|
||||
// Multiply by the alpha map
|
||||
if (!blendmaps.empty())
|
||||
|
@ -290,7 +298,6 @@ namespace Terrain
|
|||
stateset->setTextureAttributeAndModes(1, BlendmapTexMat::value(blendmapScale));
|
||||
stateset->setTextureAttributeAndModes(1, TexEnvCombine::value(), osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
passes.push_back(stateset);
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace Terrain
|
|||
bool mSpecular;
|
||||
};
|
||||
|
||||
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager,
|
||||
const std::vector<TextureLayer>& layers,
|
||||
const std::vector<osg::ref_ptr<osg::Texture2D> >& blendmaps, int blendmapScale, float layerTileSize);
|
||||
std::vector<osg::ref_ptr<osg::StateSet>> createPasses(bool useShaders, Resource::SceneManager* sceneManager,
|
||||
const std::vector<TextureLayer>& layers, const std::vector<osg::ref_ptr<osg::Texture2D>>& blendmaps,
|
||||
int blendmapScale, float layerTileSize);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -10,144 +10,140 @@
|
|||
namespace Terrain
|
||||
{
|
||||
|
||||
float distance(const osg::BoundingBox& box, const osg::Vec3f& v)
|
||||
{
|
||||
if (box.contains(v))
|
||||
return 0;
|
||||
else
|
||||
float distance(const osg::BoundingBox& box, const osg::Vec3f& v)
|
||||
{
|
||||
osg::Vec3f maxDist(0,0,0);
|
||||
if (v.x() < box.xMin())
|
||||
maxDist.x() = box.xMin() - v.x();
|
||||
else if (v.x() > box.xMax())
|
||||
maxDist.x() = v.x() - box.xMax();
|
||||
if (v.y() < box.yMin())
|
||||
maxDist.y() = box.yMin() - v.y();
|
||||
else if (v.y() > box.yMax())
|
||||
maxDist.y() = v.y() - box.yMax();
|
||||
if (v.z() < box.zMin())
|
||||
maxDist.z() = box.zMin() - v.z();
|
||||
else if (v.z() > box.zMax())
|
||||
maxDist.z() = v.z() - box.zMax();
|
||||
return maxDist.length();
|
||||
if (box.contains(v))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
osg::Vec3f maxDist(0, 0, 0);
|
||||
if (v.x() < box.xMin())
|
||||
maxDist.x() = box.xMin() - v.x();
|
||||
else if (v.x() > box.xMax())
|
||||
maxDist.x() = v.x() - box.xMax();
|
||||
if (v.y() < box.yMin())
|
||||
maxDist.y() = box.yMin() - v.y();
|
||||
else if (v.y() > box.yMax())
|
||||
maxDist.y() = v.y() - box.yMax();
|
||||
if (v.z() < box.zMin())
|
||||
maxDist.z() = box.zMin() - v.z();
|
||||
else if (v.z() > box.zMax())
|
||||
maxDist.z() = v.z() - box.zMax();
|
||||
return maxDist.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChildDirection reflect(ChildDirection dir, Direction dir2)
|
||||
{
|
||||
assert(dir != Root);
|
||||
const int lookupTable[4][4] =
|
||||
ChildDirection reflect(ChildDirection dir, Direction dir2)
|
||||
{
|
||||
// NW NE SW SE
|
||||
{ SW, SE, NW, NE }, // N
|
||||
{ NE, NW, SE, SW }, // E
|
||||
{ SW, SE, NW, NE }, // S
|
||||
{ NE, NW, SE, SW } // W
|
||||
};
|
||||
return (ChildDirection)lookupTable[dir2][dir];
|
||||
}
|
||||
|
||||
bool adjacent(ChildDirection dir, Direction dir2)
|
||||
{
|
||||
assert(dir != Root);
|
||||
const bool lookupTable[4][4] =
|
||||
{
|
||||
// NW NE SW SE
|
||||
{ true, true, false, false }, // N
|
||||
{ false, true, false, true }, // E
|
||||
{ false, false, true, true }, // S
|
||||
{ true, false, true, false } // W
|
||||
};
|
||||
return lookupTable[dir2][dir];
|
||||
}
|
||||
|
||||
QuadTreeNode* searchNeighbour (QuadTreeNode* currentNode, Direction dir)
|
||||
{
|
||||
if (currentNode->getDirection() == Root)
|
||||
return nullptr; // Arrived at root node, the root node does not have neighbours
|
||||
|
||||
QuadTreeNode* nextNode;
|
||||
if (adjacent(currentNode->getDirection(), dir))
|
||||
nextNode = searchNeighbour(currentNode->getParent(), dir);
|
||||
else
|
||||
nextNode = currentNode->getParent();
|
||||
|
||||
if (nextNode && nextNode->getNumChildren())
|
||||
return nextNode->getChild(reflect(currentNode->getDirection(), dir));
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float size, const osg::Vec2f& center)
|
||||
: mParent(parent)
|
||||
, mDirection(direction)
|
||||
, mValidBounds(false)
|
||||
, mSize(size)
|
||||
, mCenter(center)
|
||||
{
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
mNeighbours[i] = nullptr;
|
||||
}
|
||||
|
||||
QuadTreeNode::~QuadTreeNode()
|
||||
{
|
||||
}
|
||||
|
||||
QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir)
|
||||
{
|
||||
return mNeighbours[dir];
|
||||
}
|
||||
|
||||
float QuadTreeNode::distance(const osg::Vec3f& v) const
|
||||
{
|
||||
const osg::BoundingBox& box = getBoundingBox();
|
||||
return Terrain::distance(box, v);
|
||||
}
|
||||
|
||||
void QuadTreeNode::initNeighbours()
|
||||
{
|
||||
for (int i=0; i<4; ++i)
|
||||
mNeighbours[i] = searchNeighbour(this, (Direction)i);
|
||||
|
||||
for (unsigned int i=0; i<getNumChildren(); ++i)
|
||||
getChild(i)->initNeighbours();
|
||||
}
|
||||
|
||||
void QuadTreeNode::traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback)
|
||||
{
|
||||
if (!hasValidBounds())
|
||||
return;
|
||||
LodCallback::ReturnValue lodResult = lodCallback->isSufficientDetail(this, distance(viewPoint));
|
||||
if (lodResult == LodCallback::StopTraversal)
|
||||
return;
|
||||
else if (lodResult == LodCallback::Deeper && getNumChildren())
|
||||
{
|
||||
for (unsigned int i=0; i<getNumChildren(); ++i)
|
||||
getChild(i)->traverseNodes(vd, viewPoint, lodCallback);
|
||||
assert(dir != Root);
|
||||
const int lookupTable[4][4] = {
|
||||
// NW NE SW SE
|
||||
{ SW, SE, NW, NE }, // N
|
||||
{ NE, NW, SE, SW }, // E
|
||||
{ SW, SE, NW, NE }, // S
|
||||
{ NE, NW, SE, SW } // W
|
||||
};
|
||||
return (ChildDirection)lookupTable[dir2][dir];
|
||||
}
|
||||
else
|
||||
vd->add(this);
|
||||
}
|
||||
|
||||
void QuadTreeNode::setBoundingBox(const osg::BoundingBox &boundingBox)
|
||||
{
|
||||
mBoundingBox = boundingBox;
|
||||
mValidBounds = boundingBox.valid();
|
||||
}
|
||||
bool adjacent(ChildDirection dir, Direction dir2)
|
||||
{
|
||||
assert(dir != Root);
|
||||
const bool lookupTable[4][4] = {
|
||||
// NW NE SW SE
|
||||
{ true, true, false, false }, // N
|
||||
{ false, true, false, true }, // E
|
||||
{ false, false, true, true }, // S
|
||||
{ true, false, true, false } // W
|
||||
};
|
||||
return lookupTable[dir2][dir];
|
||||
}
|
||||
|
||||
const osg::BoundingBox &QuadTreeNode::getBoundingBox() const
|
||||
{
|
||||
return mBoundingBox;
|
||||
}
|
||||
QuadTreeNode* searchNeighbour(QuadTreeNode* currentNode, Direction dir)
|
||||
{
|
||||
if (currentNode->getDirection() == Root)
|
||||
return nullptr; // Arrived at root node, the root node does not have neighbours
|
||||
|
||||
float QuadTreeNode::getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
QuadTreeNode* nextNode;
|
||||
if (adjacent(currentNode->getDirection(), dir))
|
||||
nextNode = searchNeighbour(currentNode->getParent(), dir);
|
||||
else
|
||||
nextNode = currentNode->getParent();
|
||||
|
||||
const osg::Vec2f &QuadTreeNode::getCenter() const
|
||||
{
|
||||
return mCenter;
|
||||
}
|
||||
if (nextNode && nextNode->getNumChildren())
|
||||
return nextNode->getChild(reflect(currentNode->getDirection(), dir));
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float size, const osg::Vec2f& center)
|
||||
: mParent(parent)
|
||||
, mDirection(direction)
|
||||
, mValidBounds(false)
|
||||
, mSize(size)
|
||||
, mCenter(center)
|
||||
{
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
mNeighbours[i] = nullptr;
|
||||
}
|
||||
|
||||
QuadTreeNode::~QuadTreeNode() {}
|
||||
|
||||
QuadTreeNode* QuadTreeNode::getNeighbour(Direction dir)
|
||||
{
|
||||
return mNeighbours[dir];
|
||||
}
|
||||
|
||||
float QuadTreeNode::distance(const osg::Vec3f& v) const
|
||||
{
|
||||
const osg::BoundingBox& box = getBoundingBox();
|
||||
return Terrain::distance(box, v);
|
||||
}
|
||||
|
||||
void QuadTreeNode::initNeighbours()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
mNeighbours[i] = searchNeighbour(this, (Direction)i);
|
||||
|
||||
for (unsigned int i = 0; i < getNumChildren(); ++i)
|
||||
getChild(i)->initNeighbours();
|
||||
}
|
||||
|
||||
void QuadTreeNode::traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback)
|
||||
{
|
||||
if (!hasValidBounds())
|
||||
return;
|
||||
LodCallback::ReturnValue lodResult = lodCallback->isSufficientDetail(this, distance(viewPoint));
|
||||
if (lodResult == LodCallback::StopTraversal)
|
||||
return;
|
||||
else if (lodResult == LodCallback::Deeper && getNumChildren())
|
||||
{
|
||||
for (unsigned int i = 0; i < getNumChildren(); ++i)
|
||||
getChild(i)->traverseNodes(vd, viewPoint, lodCallback);
|
||||
}
|
||||
else
|
||||
vd->add(this);
|
||||
}
|
||||
|
||||
void QuadTreeNode::setBoundingBox(const osg::BoundingBox& boundingBox)
|
||||
{
|
||||
mBoundingBox = boundingBox;
|
||||
mValidBounds = boundingBox.valid();
|
||||
}
|
||||
|
||||
const osg::BoundingBox& QuadTreeNode::getBoundingBox() const
|
||||
{
|
||||
return mBoundingBox;
|
||||
}
|
||||
|
||||
float QuadTreeNode::getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
const osg::Vec2f& QuadTreeNode::getCenter() const
|
||||
{
|
||||
return mCenter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace Terrain
|
|||
StopTraversal,
|
||||
StopTraversalAndUse
|
||||
};
|
||||
virtual ReturnValue isSufficientDetail(QuadTreeNode *node, float dist) = 0;
|
||||
virtual ReturnValue isSufficientDetail(QuadTreeNode* node, float dist) = 0;
|
||||
};
|
||||
|
||||
class ViewData;
|
||||
|
@ -62,7 +62,7 @@ namespace Terrain
|
|||
ChildDirection getDirection() { return mDirection; }
|
||||
|
||||
/// Get neighbour node in this direction
|
||||
QuadTreeNode* getNeighbour (Direction dir);
|
||||
QuadTreeNode* getNeighbour(Direction dir);
|
||||
|
||||
/// Initialize neighbours - do this after the quadtree is built
|
||||
void initNeighbours();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include "terraingrid.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
|
@ -20,14 +20,18 @@ namespace Terrain
|
|||
class ViewDataMap;
|
||||
class ViewData;
|
||||
struct ViewDataEntry;
|
||||
|
||||
|
||||
class DebugChunkManager;
|
||||
|
||||
/// @brief Terrain implementation that loads cells into a Quad Tree, with geometry LOD and texture LOD.
|
||||
class QuadTreeWorld : public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell)
|
||||
class QuadTreeWorld
|
||||
: public TerrainGrid // note: derived from TerrainGrid is only to render default cells (see loadCell)
|
||||
{
|
||||
public:
|
||||
QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize, bool debugChunks);
|
||||
QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem,
|
||||
Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask,
|
||||
int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize,
|
||||
bool debugChunks);
|
||||
|
||||
~QuadTreeWorld();
|
||||
|
||||
|
@ -37,14 +41,15 @@ namespace Terrain
|
|||
|
||||
void setViewDistance(float distance) override;
|
||||
|
||||
void cacheCell(View *view, int x, int y) override {}
|
||||
void cacheCell(View* view, int x, int y) override {}
|
||||
/// @note Not thread safe.
|
||||
void loadCell(int x, int y) override;
|
||||
/// @note Not thread safe.
|
||||
void unloadCell(int x, int y) override;
|
||||
|
||||
View* createView() override;
|
||||
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, Loading::Reporter& reporter) override;
|
||||
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i& cellgrid, std::atomic<bool>& abort,
|
||||
Loading::Reporter& reporter) override;
|
||||
void rebuildViews() override;
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats* stats) override;
|
||||
|
@ -52,8 +57,10 @@ namespace Terrain
|
|||
class ChunkManager
|
||||
{
|
||||
public:
|
||||
virtual ~ChunkManager(){}
|
||||
virtual osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) = 0;
|
||||
virtual ~ChunkManager() {}
|
||||
virtual osg::ref_ptr<osg::Node> getChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
||||
unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
|
||||
= 0;
|
||||
virtual unsigned int getNodeMask() { return 0; }
|
||||
|
||||
void setViewDistance(float viewDistance) { mViewDistance = viewDistance; }
|
||||
|
@ -62,6 +69,7 @@ namespace Terrain
|
|||
// Automatically set by addChunkManager based on getViewDistance()
|
||||
unsigned int getMaxLodLevel() const { return mMaxLodLevel; }
|
||||
void setMaxLodLevel(unsigned int level) { mMaxLodLevel = level; }
|
||||
|
||||
private:
|
||||
float mViewDistance = 0.f;
|
||||
unsigned int mMaxLodLevel = ~0u;
|
||||
|
@ -70,7 +78,8 @@ namespace Terrain
|
|||
|
||||
private:
|
||||
void ensureQuadTreeBuilt();
|
||||
void loadRenderingNode(ViewDataEntry& entry, ViewData* vd, float cellWorldSize, const osg::Vec4i &gridbounds, bool compile);
|
||||
void loadRenderingNode(
|
||||
ViewDataEntry& entry, ViewData* vd, float cellWorldSize, const osg::Vec4i& gridbounds, bool compile);
|
||||
|
||||
osg::ref_ptr<RootNode> mRootNode;
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Array>
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Array>
|
||||
|
||||
#include "defs.hpp"
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Terrain
|
|||
virtual bool hasData(int cellX, int cellY)
|
||||
{
|
||||
float dummy;
|
||||
return getMinMaxHeights(1, osg::Vec2f(cellX+0.5, cellY+0.5), dummy, dummy);
|
||||
return getMinMaxHeights(1, osg::Vec2f(cellX + 0.5, cellY + 0.5), dummy, dummy);
|
||||
}
|
||||
|
||||
/// Get the minimum and maximum heights of a terrain region.
|
||||
|
@ -44,7 +44,7 @@ namespace Terrain
|
|||
/// @param min min height will be stored here
|
||||
/// @param max max height will be stored here
|
||||
/// @return true if there was data available for this terrain chunk
|
||||
virtual bool getMinMaxHeights (float size, const osg::Vec2f& center, float& min, float& max) = 0;
|
||||
virtual bool getMinMaxHeights(float size, const osg::Vec2f& center, float& min, float& max) = 0;
|
||||
|
||||
/// Fill vertex buffers for a terrain chunk.
|
||||
/// @note May be called from background threads. Make sure to only call thread-safe functions from here!
|
||||
|
@ -57,12 +57,12 @@ namespace Terrain
|
|||
/// @param positions buffer to write vertices
|
||||
/// @param normals buffer to write vertex normals
|
||||
/// @param colours buffer to write vertex colours
|
||||
virtual void fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center,
|
||||
osg::ref_ptr<osg::Vec3Array> positions,
|
||||
osg::ref_ptr<osg::Vec3Array> normals,
|
||||
osg::ref_ptr<osg::Vec4ubArray> colours) = 0;
|
||||
virtual void fillVertexBuffers(int lodLevel, float size, const osg::Vec2f& center,
|
||||
osg::ref_ptr<osg::Vec3Array> positions, osg::ref_ptr<osg::Vec3Array> normals,
|
||||
osg::ref_ptr<osg::Vec4ubArray> colours)
|
||||
= 0;
|
||||
|
||||
typedef std::vector<osg::ref_ptr<osg::Image> > ImageVector;
|
||||
typedef std::vector<osg::ref_ptr<osg::Image>> ImageVector;
|
||||
/// Create textures holding layer blend values for a terrain chunk.
|
||||
/// @note The terrain chunk shouldn't be larger than one cell since otherwise we might
|
||||
/// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used.
|
||||
|
@ -71,10 +71,11 @@ namespace Terrain
|
|||
/// @param chunkCenter center of the chunk in cell units
|
||||
/// @param blendmaps created blendmaps will be written here
|
||||
/// @param layerList names of the layer textures used will be written here
|
||||
virtual void getBlendmaps (float chunkSize, const osg::Vec2f& chunkCenter, ImageVector& blendmaps,
|
||||
std::vector<LayerInfo>& layerList) = 0;
|
||||
virtual void getBlendmaps(
|
||||
float chunkSize, const osg::Vec2f& chunkCenter, ImageVector& blendmaps, std::vector<LayerInfo>& layerList)
|
||||
= 0;
|
||||
|
||||
virtual float getHeightAt (const osg::Vec3f& worldPos) = 0;
|
||||
virtual float getHeightAt(const osg::Vec3f& worldPos) = 0;
|
||||
|
||||
/// Get the transformation factor for mapping cell units to world units.
|
||||
virtual float getCellWorldSize() = 0;
|
||||
|
|
|
@ -10,159 +10,156 @@
|
|||
namespace Terrain
|
||||
{
|
||||
|
||||
TerrainDrawable::TerrainDrawable()
|
||||
{
|
||||
TerrainDrawable::TerrainDrawable() {}
|
||||
|
||||
}
|
||||
TerrainDrawable::~TerrainDrawable() {}
|
||||
|
||||
TerrainDrawable::~TerrainDrawable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TerrainDrawable::TerrainDrawable(const TerrainDrawable ©, const osg::CopyOp ©op)
|
||||
: osg::Geometry(copy, copyop)
|
||||
, mPasses(copy.mPasses)
|
||||
, mLightListCallback(copy.mLightListCallback)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TerrainDrawable::accept(osg::NodeVisitor &nv)
|
||||
{
|
||||
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
|
||||
TerrainDrawable::TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop)
|
||||
: osg::Geometry(copy, copyop)
|
||||
, mPasses(copy.mPasses)
|
||||
, mLightListCallback(copy.mLightListCallback)
|
||||
{
|
||||
osg::Geometry::accept(nv);
|
||||
}
|
||||
else if (nv.validNodeMask(*this))
|
||||
{
|
||||
nv.pushOntoNodePath(this);
|
||||
cull(static_cast<osgUtil::CullVisitor*>(&nv));
|
||||
nv.popFromNodePath();
|
||||
}
|
||||
}
|
||||
|
||||
inline float distance(const osg::Vec3& coord,const osg::Matrix& matrix)
|
||||
{
|
||||
return -((float)coord[0]*(float)matrix(0,2)+(float)coord[1]*(float)matrix(1,2)+(float)coord[2]*(float)matrix(2,2)+matrix(3,2));
|
||||
}
|
||||
|
||||
//canot use ClusterCullingCallback::cull: viewpoint != eyepoint
|
||||
// !osgfixpotential!
|
||||
bool clusterCull(osg::ClusterCullingCallback* cb, const osg::Vec3f& eyePoint, bool shadowcam)
|
||||
{
|
||||
float _deviation = cb->getDeviation();
|
||||
const osg::Vec3& _controlPoint = cb->getControlPoint();
|
||||
osg::Vec3 _normal = cb->getNormal();
|
||||
if (shadowcam) _normal = _normal * -1; //inverting for shadowcam frontfaceculing
|
||||
float _radius = cb->getRadius();
|
||||
if (_deviation<=-1.0f) return false;
|
||||
osg::Vec3 eye_cp = eyePoint - _controlPoint;
|
||||
float radius = eye_cp.length();
|
||||
if (radius<_radius) return false;
|
||||
float deviation = (eye_cp * _normal)/radius;
|
||||
return deviation < _deviation;
|
||||
}
|
||||
|
||||
void TerrainDrawable::cull(osgUtil::CullVisitor *cv)
|
||||
{
|
||||
const osg::BoundingBox& bb = getBoundingBox();
|
||||
|
||||
if (_cullingActive && cv->isCulled(getBoundingBox()))
|
||||
return;
|
||||
|
||||
bool shadowcam = cv->getCurrentCamera()->getName() == "ShadowCamera";
|
||||
|
||||
if (cv->getCullingMode() & osg::CullStack::CLUSTER_CULLING && clusterCull(mClusterCullingCallback, cv->getEyePoint(), shadowcam))
|
||||
return;
|
||||
|
||||
osg::RefMatrix& matrix = *cv->getModelViewMatrix();
|
||||
|
||||
if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR && bb.valid())
|
||||
{
|
||||
if (!cv->updateCalculatedNearFar(matrix, *this, false))
|
||||
return;
|
||||
}
|
||||
|
||||
float depth = bb.valid() ? distance(bb.center(),matrix) : 0.0f;
|
||||
if (osg::isNaN(depth))
|
||||
return;
|
||||
|
||||
if (shadowcam)
|
||||
void TerrainDrawable::accept(osg::NodeVisitor& nv)
|
||||
{
|
||||
cv->addDrawableAndDepth(this, &matrix, depth);
|
||||
return;
|
||||
if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
|
||||
{
|
||||
osg::Geometry::accept(nv);
|
||||
}
|
||||
else if (nv.validNodeMask(*this))
|
||||
{
|
||||
nv.pushOntoNodePath(this);
|
||||
cull(static_cast<osgUtil::CullVisitor*>(&nv));
|
||||
nv.popFromNodePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (mCompositeMap && mCompositeMapRenderer)
|
||||
inline float distance(const osg::Vec3& coord, const osg::Matrix& matrix)
|
||||
{
|
||||
mCompositeMapRenderer->setImmediate(mCompositeMap);
|
||||
mCompositeMapRenderer = nullptr;
|
||||
return -((float)coord[0] * (float)matrix(0, 2) + (float)coord[1] * (float)matrix(1, 2)
|
||||
+ (float)coord[2] * (float)matrix(2, 2) + matrix(3, 2));
|
||||
}
|
||||
|
||||
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
|
||||
|
||||
osg::StateSet* stateset = getStateSet();
|
||||
if (stateset)
|
||||
cv->pushStateSet(stateset);
|
||||
|
||||
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||
// canot use ClusterCullingCallback::cull: viewpoint != eyepoint
|
||||
// !osgfixpotential!
|
||||
bool clusterCull(osg::ClusterCullingCallback* cb, const osg::Vec3f& eyePoint, bool shadowcam)
|
||||
{
|
||||
cv->pushStateSet(*it);
|
||||
cv->addDrawableAndDepth(this, &matrix, depth);
|
||||
cv->popStateSet();
|
||||
float _deviation = cb->getDeviation();
|
||||
const osg::Vec3& _controlPoint = cb->getControlPoint();
|
||||
osg::Vec3 _normal = cb->getNormal();
|
||||
if (shadowcam)
|
||||
_normal = _normal * -1; // inverting for shadowcam frontfaceculing
|
||||
float _radius = cb->getRadius();
|
||||
if (_deviation <= -1.0f)
|
||||
return false;
|
||||
osg::Vec3 eye_cp = eyePoint - _controlPoint;
|
||||
float radius = eye_cp.length();
|
||||
if (radius < _radius)
|
||||
return false;
|
||||
float deviation = (eye_cp * _normal) / radius;
|
||||
return deviation < _deviation;
|
||||
}
|
||||
|
||||
if (stateset)
|
||||
cv->popStateSet();
|
||||
if (pushedLight)
|
||||
cv->popStateSet();
|
||||
}
|
||||
|
||||
void TerrainDrawable::createClusterCullingCallback()
|
||||
{
|
||||
mClusterCullingCallback = new osg::ClusterCullingCallback(this);
|
||||
}
|
||||
|
||||
void TerrainDrawable::setPasses(const TerrainDrawable::PassVector &passes)
|
||||
{
|
||||
mPasses = passes;
|
||||
}
|
||||
|
||||
void TerrainDrawable::setLightListCallback(SceneUtil::LightListCallback *lightListCallback)
|
||||
{
|
||||
mLightListCallback = lightListCallback;
|
||||
}
|
||||
|
||||
void TerrainDrawable::setupWaterBoundingBox(float waterheight, float margin)
|
||||
{
|
||||
osg::Vec3Array* vertices = static_cast<osg::Vec3Array*>(getVertexArray());
|
||||
for (unsigned int i=0; i<vertices->size(); ++i)
|
||||
{
|
||||
const osg::Vec3f& vertex = (*vertices)[i];
|
||||
if (vertex.z() <= waterheight)
|
||||
mWaterBoundingBox.expandBy(vertex);
|
||||
}
|
||||
if (mWaterBoundingBox.valid())
|
||||
void TerrainDrawable::cull(osgUtil::CullVisitor* cv)
|
||||
{
|
||||
const osg::BoundingBox& bb = getBoundingBox();
|
||||
mWaterBoundingBox.xMin() = std::max(bb.xMin(), mWaterBoundingBox.xMin() - margin);
|
||||
mWaterBoundingBox.yMin() = std::max(bb.yMin(), mWaterBoundingBox.yMin() - margin);
|
||||
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
|
||||
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainDrawable::compileGLObjects(osg::RenderInfo &renderInfo) const
|
||||
{
|
||||
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||
if (_cullingActive && cv->isCulled(getBoundingBox()))
|
||||
return;
|
||||
|
||||
bool shadowcam = cv->getCurrentCamera()->getName() == "ShadowCamera";
|
||||
|
||||
if (cv->getCullingMode() & osg::CullStack::CLUSTER_CULLING
|
||||
&& clusterCull(mClusterCullingCallback, cv->getEyePoint(), shadowcam))
|
||||
return;
|
||||
|
||||
osg::RefMatrix& matrix = *cv->getModelViewMatrix();
|
||||
|
||||
if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR && bb.valid())
|
||||
{
|
||||
if (!cv->updateCalculatedNearFar(matrix, *this, false))
|
||||
return;
|
||||
}
|
||||
|
||||
float depth = bb.valid() ? distance(bb.center(), matrix) : 0.0f;
|
||||
if (osg::isNaN(depth))
|
||||
return;
|
||||
|
||||
if (shadowcam)
|
||||
{
|
||||
cv->addDrawableAndDepth(this, &matrix, depth);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCompositeMap && mCompositeMapRenderer)
|
||||
{
|
||||
mCompositeMapRenderer->setImmediate(mCompositeMap);
|
||||
mCompositeMapRenderer = nullptr;
|
||||
}
|
||||
|
||||
bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
|
||||
|
||||
osg::StateSet* stateset = getStateSet();
|
||||
if (stateset)
|
||||
cv->pushStateSet(stateset);
|
||||
|
||||
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||
{
|
||||
cv->pushStateSet(*it);
|
||||
cv->addDrawableAndDepth(this, &matrix, depth);
|
||||
cv->popStateSet();
|
||||
}
|
||||
|
||||
if (stateset)
|
||||
cv->popStateSet();
|
||||
if (pushedLight)
|
||||
cv->popStateSet();
|
||||
}
|
||||
|
||||
void TerrainDrawable::createClusterCullingCallback()
|
||||
{
|
||||
osg::StateSet* stateset = *it;
|
||||
stateset->compileGLObjects(*renderInfo.getState());
|
||||
mClusterCullingCallback = new osg::ClusterCullingCallback(this);
|
||||
}
|
||||
|
||||
osg::Geometry::compileGLObjects(renderInfo);
|
||||
}
|
||||
void TerrainDrawable::setPasses(const TerrainDrawable::PassVector& passes)
|
||||
{
|
||||
mPasses = passes;
|
||||
}
|
||||
|
||||
void TerrainDrawable::setLightListCallback(SceneUtil::LightListCallback* lightListCallback)
|
||||
{
|
||||
mLightListCallback = lightListCallback;
|
||||
}
|
||||
|
||||
void TerrainDrawable::setupWaterBoundingBox(float waterheight, float margin)
|
||||
{
|
||||
osg::Vec3Array* vertices = static_cast<osg::Vec3Array*>(getVertexArray());
|
||||
for (unsigned int i = 0; i < vertices->size(); ++i)
|
||||
{
|
||||
const osg::Vec3f& vertex = (*vertices)[i];
|
||||
if (vertex.z() <= waterheight)
|
||||
mWaterBoundingBox.expandBy(vertex);
|
||||
}
|
||||
if (mWaterBoundingBox.valid())
|
||||
{
|
||||
const osg::BoundingBox& bb = getBoundingBox();
|
||||
mWaterBoundingBox.xMin() = std::max(bb.xMin(), mWaterBoundingBox.xMin() - margin);
|
||||
mWaterBoundingBox.yMin() = std::max(bb.yMin(), mWaterBoundingBox.yMin() - margin);
|
||||
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
|
||||
mWaterBoundingBox.xMax() = std::min(bb.xMax(), mWaterBoundingBox.xMax() + margin);
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
for (PassVector::const_iterator it = mPasses.begin(); it != mPasses.end(); ++it)
|
||||
{
|
||||
osg::StateSet* stateset = *it;
|
||||
stateset->compileGLObjects(*renderInfo.getState());
|
||||
}
|
||||
|
||||
osg::Geometry::compileGLObjects(renderInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,12 @@ namespace Terrain
|
|||
class TerrainDrawable : public osg::Geometry
|
||||
{
|
||||
public:
|
||||
osg::Object* cloneType() const override { return new TerrainDrawable (); }
|
||||
osg::Object* clone(const osg::CopyOp& copyop) const override { return new TerrainDrawable (*this,copyop); }
|
||||
bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const TerrainDrawable *>(obj)!=nullptr; }
|
||||
osg::Object* cloneType() const override { return new TerrainDrawable(); }
|
||||
osg::Object* clone(const osg::CopyOp& copyop) const override { return new TerrainDrawable(*this, copyop); }
|
||||
bool isSameKindAs(const osg::Object* obj) const override
|
||||
{
|
||||
return dynamic_cast<const TerrainDrawable*>(obj) != nullptr;
|
||||
}
|
||||
const char* className() const override { return "TerrainDrawable"; }
|
||||
const char* libraryName() const override { return "Terrain"; }
|
||||
|
||||
|
@ -40,12 +43,12 @@ namespace Terrain
|
|||
~TerrainDrawable(); // has to be defined in the cpp file because we only forward declared some members.
|
||||
TerrainDrawable(const TerrainDrawable& copy, const osg::CopyOp& copyop);
|
||||
|
||||
void accept(osg::NodeVisitor &nv) override;
|
||||
void accept(osg::NodeVisitor& nv) override;
|
||||
void cull(osgUtil::CullVisitor* cv);
|
||||
|
||||
typedef std::vector<osg::ref_ptr<osg::StateSet> > PassVector;
|
||||
void setPasses (const PassVector& passes);
|
||||
const PassVector& getPasses() const { return mPasses; }
|
||||
typedef std::vector<osg::ref_ptr<osg::StateSet>> PassVector;
|
||||
void setPasses(const PassVector& passes);
|
||||
const PassVector& getPasses() const { return mPasses; }
|
||||
|
||||
void setLightListCallback(SceneUtil::LightListCallback* lightListCallback);
|
||||
|
||||
|
@ -73,5 +76,4 @@ namespace Terrain
|
|||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,131 +2,135 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
#include <osg/Group>
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include "chunkmanager.hpp"
|
||||
#include "compositemaprenderer.hpp"
|
||||
#include "view.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "heightcull.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "view.hpp"
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
class MyView : public View
|
||||
{
|
||||
public:
|
||||
osg::ref_ptr<osg::Node> mLoaded;
|
||||
|
||||
void reset() override {}
|
||||
};
|
||||
|
||||
TerrainGrid::TerrainGrid(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask)
|
||||
: Terrain::World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask)
|
||||
, mNumSplits(4)
|
||||
{
|
||||
}
|
||||
|
||||
TerrainGrid::TerrainGrid(osg::Group* parent, Storage* storage, unsigned int nodeMask)
|
||||
: Terrain::World(parent, storage, nodeMask)
|
||||
, mNumSplits(4)
|
||||
{
|
||||
}
|
||||
|
||||
TerrainGrid::~TerrainGrid()
|
||||
{
|
||||
while (!mGrid.empty())
|
||||
class MyView : public View
|
||||
{
|
||||
TerrainGrid::unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second);
|
||||
}
|
||||
}
|
||||
public:
|
||||
osg::ref_ptr<osg::Node> mLoaded;
|
||||
|
||||
void TerrainGrid::cacheCell(View* view, int x, int y)
|
||||
{
|
||||
osg::Vec2f center(x+0.5f, y+0.5f);
|
||||
static_cast<MyView*>(view)->mLoaded = buildTerrain(nullptr, 1.f, center);
|
||||
}
|
||||
void reset() override {}
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
|
||||
{
|
||||
if (chunkSize * mNumSplits > 1.f)
|
||||
TerrainGrid::TerrainGrid(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem,
|
||||
Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask)
|
||||
: Terrain::World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask)
|
||||
, mNumSplits(4)
|
||||
{
|
||||
// keep splitting
|
||||
osg::ref_ptr<osg::Group> group (new osg::Group);
|
||||
if (parent)
|
||||
parent->addChild(group);
|
||||
|
||||
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
|
||||
|
||||
TerrainGrid::TerrainGrid(osg::Group* parent, Storage* storage, unsigned int nodeMask)
|
||||
: Terrain::World(parent, storage, nodeMask)
|
||||
, mNumSplits(4)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> node = mChunkManager->getChunk(chunkSize, chunkCenter, 0, 0, false, osg::Vec3f(), true);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
const float cellWorldSize = mStorage->getCellWorldSize();
|
||||
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> pat = new SceneUtil::PositionAttitudeTransform;
|
||||
pat->setPosition(osg::Vec3f(chunkCenter.x()*cellWorldSize, chunkCenter.y()*cellWorldSize, 0.f));
|
||||
pat->addChild(node);
|
||||
if (parent)
|
||||
parent->addChild(pat);
|
||||
return pat;
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainGrid::loadCell(int x, int y)
|
||||
{
|
||||
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
|
||||
return; // already loaded
|
||||
TerrainGrid::~TerrainGrid()
|
||||
{
|
||||
while (!mGrid.empty())
|
||||
{
|
||||
TerrainGrid::unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second);
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec2f center(x+0.5f, y+0.5f);
|
||||
osg::ref_ptr<osg::Node> terrainNode = buildTerrain(nullptr, 1.f, center);
|
||||
if (!terrainNode)
|
||||
return; // no terrain defined
|
||||
void TerrainGrid::cacheCell(View* view, int x, int y)
|
||||
{
|
||||
osg::Vec2f center(x + 0.5f, y + 0.5f);
|
||||
static_cast<MyView*>(view)->mLoaded = buildTerrain(nullptr, 1.f, center);
|
||||
}
|
||||
|
||||
TerrainGrid::World::loadCell(x,y);
|
||||
osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain(
|
||||
osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter)
|
||||
{
|
||||
if (chunkSize * mNumSplits > 1.f)
|
||||
{
|
||||
// keep splitting
|
||||
osg::ref_ptr<osg::Group> group(new osg::Group);
|
||||
if (parent)
|
||||
parent->addChild(group);
|
||||
|
||||
mTerrainRoot->addChild(terrainNode);
|
||||
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
|
||||
{
|
||||
osg::ref_ptr<osg::Node> node
|
||||
= mChunkManager->getChunk(chunkSize, chunkCenter, 0, 0, false, osg::Vec3f(), true);
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
mGrid[std::make_pair(x,y)] = terrainNode;
|
||||
updateWaterCulling();
|
||||
}
|
||||
const float cellWorldSize = mStorage->getCellWorldSize();
|
||||
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> pat = new SceneUtil::PositionAttitudeTransform;
|
||||
pat->setPosition(osg::Vec3f(chunkCenter.x() * cellWorldSize, chunkCenter.y() * cellWorldSize, 0.f));
|
||||
pat->addChild(node);
|
||||
if (parent)
|
||||
parent->addChild(pat);
|
||||
return pat;
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainGrid::unloadCell(int x, int y)
|
||||
{
|
||||
CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y));
|
||||
if (it == mGrid.end())
|
||||
return;
|
||||
void TerrainGrid::loadCell(int x, int y)
|
||||
{
|
||||
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
|
||||
return; // already loaded
|
||||
|
||||
Terrain::World::unloadCell(x,y);
|
||||
osg::Vec2f center(x + 0.5f, y + 0.5f);
|
||||
osg::ref_ptr<osg::Node> terrainNode = buildTerrain(nullptr, 1.f, center);
|
||||
if (!terrainNode)
|
||||
return; // no terrain defined
|
||||
|
||||
osg::ref_ptr<osg::Node> terrainNode = it->second;
|
||||
mTerrainRoot->removeChild(terrainNode);
|
||||
TerrainGrid::World::loadCell(x, y);
|
||||
|
||||
mGrid.erase(it);
|
||||
updateWaterCulling();
|
||||
}
|
||||
mTerrainRoot->addChild(terrainNode);
|
||||
|
||||
void TerrainGrid::updateWaterCulling()
|
||||
{
|
||||
if (!mHeightCullCallback) return;
|
||||
mGrid[std::make_pair(x, y)] = terrainNode;
|
||||
updateWaterCulling();
|
||||
}
|
||||
|
||||
osg::ComputeBoundsVisitor computeBoundsVisitor;
|
||||
mTerrainRoot->accept(computeBoundsVisitor);
|
||||
float lowZ = computeBoundsVisitor.getBoundingBox()._min.z();
|
||||
mHeightCullCallback->setLowZ(lowZ);
|
||||
}
|
||||
void TerrainGrid::unloadCell(int x, int y)
|
||||
{
|
||||
CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x, y));
|
||||
if (it == mGrid.end())
|
||||
return;
|
||||
|
||||
View *TerrainGrid::createView()
|
||||
{
|
||||
return new MyView;
|
||||
}
|
||||
Terrain::World::unloadCell(x, y);
|
||||
|
||||
osg::ref_ptr<osg::Node> terrainNode = it->second;
|
||||
mTerrainRoot->removeChild(terrainNode);
|
||||
|
||||
mGrid.erase(it);
|
||||
updateWaterCulling();
|
||||
}
|
||||
|
||||
void TerrainGrid::updateWaterCulling()
|
||||
{
|
||||
if (!mHeightCullCallback)
|
||||
return;
|
||||
|
||||
osg::ComputeBoundsVisitor computeBoundsVisitor;
|
||||
mTerrainRoot->accept(computeBoundsVisitor);
|
||||
float lowZ = computeBoundsVisitor.getBoundingBox()._min.z();
|
||||
mHeightCullCallback->setLowZ(lowZ);
|
||||
}
|
||||
|
||||
View* TerrainGrid::createView()
|
||||
{
|
||||
return new MyView;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,8 +26,9 @@ namespace Terrain
|
|||
class TerrainGrid : public Terrain::World
|
||||
{
|
||||
public:
|
||||
TerrainGrid(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask=~0u, unsigned int borderMask=0);
|
||||
TerrainGrid(osg::Group* parent, Storage* storage, unsigned int nodeMask=~0u);
|
||||
TerrainGrid(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem,
|
||||
Storage* storage, unsigned int nodeMask, unsigned int preCompileMask = ~0u, unsigned int borderMask = 0);
|
||||
TerrainGrid(osg::Group* parent, Storage* storage, unsigned int nodeMask = ~0u);
|
||||
~TerrainGrid();
|
||||
|
||||
void cacheCell(View* view, int x, int y) override;
|
||||
|
@ -44,7 +45,7 @@ namespace Terrain
|
|||
bool isGridEmpty() const { return mGrid.empty(); }
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Node> buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter);
|
||||
osg::ref_ptr<osg::Node> buildTerrain(osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter);
|
||||
void updateWaterCulling();
|
||||
|
||||
// split each ESM::Cell into mNumSplits*mNumSplits terrain chunks
|
||||
|
|
|
@ -3,62 +3,60 @@
|
|||
#include <osg/Stats>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/resource/objectcache.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
TextureManager::TextureManager(Resource::SceneManager *sceneMgr)
|
||||
: ResourceManager(sceneMgr->getVFS())
|
||||
, mSceneManager(sceneMgr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct UpdateTextureFilteringFunctor
|
||||
{
|
||||
UpdateTextureFilteringFunctor(Resource::SceneManager* sceneMgr)
|
||||
: mSceneManager(sceneMgr)
|
||||
TextureManager::TextureManager(Resource::SceneManager* sceneMgr)
|
||||
: ResourceManager(sceneMgr->getVFS())
|
||||
, mSceneManager(sceneMgr)
|
||||
{
|
||||
}
|
||||
Resource::SceneManager* mSceneManager;
|
||||
|
||||
void operator()(std::string, osg::Object* obj)
|
||||
struct UpdateTextureFilteringFunctor
|
||||
{
|
||||
mSceneManager->applyFilterSettings(static_cast<osg::Texture2D*>(obj));
|
||||
}
|
||||
};
|
||||
UpdateTextureFilteringFunctor(Resource::SceneManager* sceneMgr)
|
||||
: mSceneManager(sceneMgr)
|
||||
{
|
||||
}
|
||||
Resource::SceneManager* mSceneManager;
|
||||
|
||||
void TextureManager::updateTextureFiltering()
|
||||
{
|
||||
UpdateTextureFilteringFunctor f(mSceneManager);
|
||||
mCache->call(f);
|
||||
}
|
||||
void operator()(std::string, osg::Object* obj)
|
||||
{
|
||||
mSceneManager->applyFilterSettings(static_cast<osg::Texture2D*>(obj));
|
||||
}
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> TextureManager::getTexture(const std::string &name)
|
||||
{
|
||||
// don't bother with case folding, since there is only one way of referring to terrain textures we can assume the case is always the same
|
||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name);
|
||||
if (obj)
|
||||
return static_cast<osg::Texture2D*>(obj.get());
|
||||
else
|
||||
void TextureManager::updateTextureFiltering()
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(mSceneManager->getImageManager()->getImage(name)));
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
||||
mSceneManager->applyFilterSettings(texture);
|
||||
mCache->addEntryToObjectCache(name, texture.get());
|
||||
return texture;
|
||||
UpdateTextureFilteringFunctor f(mSceneManager);
|
||||
mCache->call(f);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const
|
||||
{
|
||||
stats->setAttribute(frameNumber, "Terrain Texture", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> TextureManager::getTexture(const std::string& name)
|
||||
{
|
||||
// don't bother with case folding, since there is only one way of referring to terrain textures we can assume
|
||||
// the case is always the same
|
||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name);
|
||||
if (obj)
|
||||
return static_cast<osg::Texture2D*>(obj.get());
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Texture2D> texture(new osg::Texture2D(mSceneManager->getImageManager()->getImage(name)));
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
||||
mSceneManager->applyFilterSettings(texture);
|
||||
mCache->addEntryToObjectCache(name, texture.get());
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const
|
||||
{
|
||||
stats->setAttribute(frameNumber, "Terrain Texture", mCache->getCacheSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Terrain
|
|||
|
||||
private:
|
||||
Resource::SceneManager* mSceneManager;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -5,202 +5,203 @@
|
|||
namespace Terrain
|
||||
{
|
||||
|
||||
ViewData::ViewData()
|
||||
: mNumEntries(0)
|
||||
, mLastUsageTimeStamp(0.0)
|
||||
, mChanged(false)
|
||||
, mHasViewPoint(false)
|
||||
, mWorldUpdateRevision(0)
|
||||
{
|
||||
}
|
||||
ViewData::ViewData()
|
||||
: mNumEntries(0)
|
||||
, mLastUsageTimeStamp(0.0)
|
||||
, mChanged(false)
|
||||
, mHasViewPoint(false)
|
||||
, mWorldUpdateRevision(0)
|
||||
{
|
||||
}
|
||||
|
||||
ViewData::~ViewData()
|
||||
{
|
||||
}
|
||||
ViewData::~ViewData() {}
|
||||
|
||||
void ViewData::copyFrom(const ViewData& other)
|
||||
{
|
||||
mNumEntries = other.mNumEntries;
|
||||
mEntries = other.mEntries;
|
||||
mChanged = other.mChanged;
|
||||
mHasViewPoint = other.mHasViewPoint;
|
||||
mViewPoint = other.mViewPoint;
|
||||
mActiveGrid = other.mActiveGrid;
|
||||
mWorldUpdateRevision = other.mWorldUpdateRevision;
|
||||
}
|
||||
void ViewData::copyFrom(const ViewData& other)
|
||||
{
|
||||
mNumEntries = other.mNumEntries;
|
||||
mEntries = other.mEntries;
|
||||
mChanged = other.mChanged;
|
||||
mHasViewPoint = other.mHasViewPoint;
|
||||
mViewPoint = other.mViewPoint;
|
||||
mActiveGrid = other.mActiveGrid;
|
||||
mWorldUpdateRevision = other.mWorldUpdateRevision;
|
||||
}
|
||||
|
||||
void ViewData::add(QuadTreeNode *node)
|
||||
{
|
||||
unsigned int index = mNumEntries++;
|
||||
void ViewData::add(QuadTreeNode* node)
|
||||
{
|
||||
unsigned int index = mNumEntries++;
|
||||
|
||||
if (index+1 > mEntries.size())
|
||||
mEntries.resize(index+1);
|
||||
if (index + 1 > mEntries.size())
|
||||
mEntries.resize(index + 1);
|
||||
|
||||
ViewDataEntry& entry = mEntries[index];
|
||||
if (entry.set(node))
|
||||
mChanged = true;
|
||||
}
|
||||
ViewDataEntry& entry = mEntries[index];
|
||||
if (entry.set(node))
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void ViewData::setViewPoint(const osg::Vec3f &viewPoint)
|
||||
{
|
||||
mViewPoint = viewPoint;
|
||||
mHasViewPoint = true;
|
||||
}
|
||||
void ViewData::setViewPoint(const osg::Vec3f& viewPoint)
|
||||
{
|
||||
mViewPoint = viewPoint;
|
||||
mHasViewPoint = true;
|
||||
}
|
||||
|
||||
// NOTE: As a performance optimisation, we cache mRenderingNodes from previous frames here.
|
||||
// If this cache becomes invalid (e.g. through mWorldUpdateRevision), we need to use clear() instead of reset().
|
||||
void ViewData::reset()
|
||||
{
|
||||
// clear any unused entries
|
||||
for (unsigned int i=mNumEntries; i<mEntries.size(); ++i)
|
||||
mEntries[i].set(nullptr);
|
||||
// NOTE: As a performance optimisation, we cache mRenderingNodes from previous frames here.
|
||||
// If this cache becomes invalid (e.g. through mWorldUpdateRevision), we need to use clear() instead of reset().
|
||||
void ViewData::reset()
|
||||
{
|
||||
// clear any unused entries
|
||||
for (unsigned int i = mNumEntries; i < mEntries.size(); ++i)
|
||||
mEntries[i].set(nullptr);
|
||||
|
||||
// reset index for next frame
|
||||
mNumEntries = 0;
|
||||
mChanged = false;
|
||||
}
|
||||
// reset index for next frame
|
||||
mNumEntries = 0;
|
||||
mChanged = false;
|
||||
}
|
||||
|
||||
void ViewData::clear()
|
||||
{
|
||||
for (unsigned int i=0; i<mEntries.size(); ++i)
|
||||
mEntries[i].set(nullptr);
|
||||
mNumEntries = 0;
|
||||
mLastUsageTimeStamp = 0;
|
||||
mChanged = false;
|
||||
mHasViewPoint = false;
|
||||
}
|
||||
void ViewData::clear()
|
||||
{
|
||||
for (unsigned int i = 0; i < mEntries.size(); ++i)
|
||||
mEntries[i].set(nullptr);
|
||||
mNumEntries = 0;
|
||||
mLastUsageTimeStamp = 0;
|
||||
mChanged = false;
|
||||
mHasViewPoint = false;
|
||||
}
|
||||
|
||||
bool ViewData::suitableToUse(const osg::Vec4i &activeGrid) const
|
||||
{
|
||||
return hasViewPoint() && activeGrid == mActiveGrid && getNumEntries();
|
||||
}
|
||||
bool ViewData::suitableToUse(const osg::Vec4i& activeGrid) const
|
||||
{
|
||||
return hasViewPoint() && activeGrid == mActiveGrid && getNumEntries();
|
||||
}
|
||||
|
||||
bool ViewData::contains(QuadTreeNode *node) const
|
||||
{
|
||||
for (unsigned int i=0; i<mNumEntries; ++i)
|
||||
if (mEntries[i].mNode == node)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewDataEntry::ViewDataEntry()
|
||||
: mNode(nullptr)
|
||||
, mLodFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool ViewDataEntry::set(QuadTreeNode *node)
|
||||
{
|
||||
if (node == mNode)
|
||||
bool ViewData::contains(QuadTreeNode* node) const
|
||||
{
|
||||
for (unsigned int i = 0; i < mNumEntries; ++i)
|
||||
if (mEntries[i].mNode == node)
|
||||
return true;
|
||||
return false;
|
||||
else
|
||||
{
|
||||
mNode = node;
|
||||
// clear cached data
|
||||
mRenderingNode = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate)
|
||||
{
|
||||
ViewerMap::const_iterator found = mViewers.find(viewer);
|
||||
ViewData* vd = nullptr;
|
||||
if (found == mViewers.end())
|
||||
ViewDataEntry::ViewDataEntry()
|
||||
: mNode(nullptr)
|
||||
, mLodFlags(0)
|
||||
{
|
||||
vd = createOrReuseView();
|
||||
mViewers[viewer] = vd;
|
||||
}
|
||||
else
|
||||
vd = found->second;
|
||||
needsUpdate = false;
|
||||
|
||||
if (!(vd->suitableToUse(activeGrid) && (vd->getViewPoint()-viewPoint).length2() < mReuseDistance*mReuseDistance && vd->getWorldUpdateRevision() >= mWorldUpdateRevision))
|
||||
bool ViewDataEntry::set(QuadTreeNode* node)
|
||||
{
|
||||
float shortestDist = viewer ? mReuseDistance*mReuseDistance : std::numeric_limits<float>::max();
|
||||
const ViewData* mostSuitableView = nullptr;
|
||||
for (const ViewData* other : mUsedViews)
|
||||
if (node == mNode)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
if (other->suitableToUse(activeGrid) && other->getWorldUpdateRevision() >= mWorldUpdateRevision)
|
||||
mNode = node;
|
||||
// clear cached data
|
||||
mRenderingNode = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ViewData* ViewDataMap::getViewData(
|
||||
osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i& activeGrid, bool& needsUpdate)
|
||||
{
|
||||
ViewerMap::const_iterator found = mViewers.find(viewer);
|
||||
ViewData* vd = nullptr;
|
||||
if (found == mViewers.end())
|
||||
{
|
||||
vd = createOrReuseView();
|
||||
mViewers[viewer] = vd;
|
||||
}
|
||||
else
|
||||
vd = found->second;
|
||||
needsUpdate = false;
|
||||
|
||||
if (!(vd->suitableToUse(activeGrid)
|
||||
&& (vd->getViewPoint() - viewPoint).length2() < mReuseDistance * mReuseDistance
|
||||
&& vd->getWorldUpdateRevision() >= mWorldUpdateRevision))
|
||||
{
|
||||
float shortestDist = viewer ? mReuseDistance * mReuseDistance : std::numeric_limits<float>::max();
|
||||
const ViewData* mostSuitableView = nullptr;
|
||||
for (const ViewData* other : mUsedViews)
|
||||
{
|
||||
float dist = (viewPoint-other->getViewPoint()).length2();
|
||||
if (dist < shortestDist)
|
||||
if (other->suitableToUse(activeGrid) && other->getWorldUpdateRevision() >= mWorldUpdateRevision)
|
||||
{
|
||||
shortestDist = dist;
|
||||
mostSuitableView = other;
|
||||
float dist = (viewPoint - other->getViewPoint()).length2();
|
||||
if (dist < shortestDist)
|
||||
{
|
||||
shortestDist = dist;
|
||||
mostSuitableView = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mostSuitableView && mostSuitableView != vd)
|
||||
{
|
||||
vd->copyFrom(*mostSuitableView);
|
||||
return vd;
|
||||
}
|
||||
else if (!mostSuitableView)
|
||||
{
|
||||
if (vd->getWorldUpdateRevision() != mWorldUpdateRevision)
|
||||
if (mostSuitableView && mostSuitableView != vd)
|
||||
{
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
vd->clear();
|
||||
vd->copyFrom(*mostSuitableView);
|
||||
return vd;
|
||||
}
|
||||
else if (!mostSuitableView)
|
||||
{
|
||||
if (vd->getWorldUpdateRevision() != mWorldUpdateRevision)
|
||||
{
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
vd->clear();
|
||||
}
|
||||
vd->setViewPoint(viewPoint);
|
||||
vd->setActiveGrid(activeGrid);
|
||||
needsUpdate = true;
|
||||
}
|
||||
vd->setViewPoint(viewPoint);
|
||||
vd->setActiveGrid(activeGrid);
|
||||
needsUpdate = true;
|
||||
}
|
||||
return vd;
|
||||
}
|
||||
return vd;
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::createOrReuseView()
|
||||
{
|
||||
ViewData* vd = nullptr;
|
||||
if (mUnusedViews.size())
|
||||
ViewData* ViewDataMap::createOrReuseView()
|
||||
{
|
||||
vd = mUnusedViews.front();
|
||||
mUnusedViews.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
mViewVector.emplace_back();
|
||||
vd = &mViewVector.back();
|
||||
}
|
||||
mUsedViews.push_back(vd);
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
|
||||
ViewData *ViewDataMap::createIndependentView() const
|
||||
{
|
||||
ViewData* vd = new ViewData;
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
|
||||
void ViewDataMap::clearUnusedViews(double referenceTime)
|
||||
{
|
||||
for (ViewerMap::iterator it = mViewers.begin(); it != mViewers.end(); )
|
||||
{
|
||||
if (it->second->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
mViewers.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
for (std::deque<ViewData*>::iterator it = mUsedViews.begin(); it != mUsedViews.end(); )
|
||||
{
|
||||
if ((*it)->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
ViewData* vd = nullptr;
|
||||
if (mUnusedViews.size())
|
||||
{
|
||||
(*it)->clear();
|
||||
mUnusedViews.push_back(*it);
|
||||
it = mUsedViews.erase(it);
|
||||
vd = mUnusedViews.front();
|
||||
mUnusedViews.pop_front();
|
||||
}
|
||||
else
|
||||
++it;
|
||||
{
|
||||
mViewVector.emplace_back();
|
||||
vd = &mViewVector.back();
|
||||
}
|
||||
mUsedViews.push_back(vd);
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewDataMap::rebuildViews()
|
||||
{
|
||||
++mWorldUpdateRevision;
|
||||
}
|
||||
ViewData* ViewDataMap::createIndependentView() const
|
||||
{
|
||||
ViewData* vd = new ViewData;
|
||||
vd->setWorldUpdateRevision(mWorldUpdateRevision);
|
||||
return vd;
|
||||
}
|
||||
|
||||
void ViewDataMap::clearUnusedViews(double referenceTime)
|
||||
{
|
||||
for (ViewerMap::iterator it = mViewers.begin(); it != mViewers.end();)
|
||||
{
|
||||
if (it->second->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
mViewers.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
for (std::deque<ViewData*>::iterator it = mUsedViews.begin(); it != mUsedViews.end();)
|
||||
{
|
||||
if ((*it)->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
|
||||
{
|
||||
(*it)->clear();
|
||||
mUnusedViews.push_back(*it);
|
||||
it = mUsedViews.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewDataMap::rebuildViews()
|
||||
{
|
||||
++mWorldUpdateRevision;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef OPENMW_COMPONENTS_TERRAIN_VIEWDATA_H
|
||||
#define OPENMW_COMPONENTS_TERRAIN_VIEWDATA_H
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Node>
|
||||
|
||||
|
@ -60,8 +60,16 @@ namespace Terrain
|
|||
void setViewPoint(const osg::Vec3f& viewPoint);
|
||||
const osg::Vec3f& getViewPoint() const { return mViewPoint; }
|
||||
|
||||
void setActiveGrid(const osg::Vec4i &grid) { if (grid != mActiveGrid) {mActiveGrid = grid;mEntries.clear();mNumEntries=0;} }
|
||||
const osg::Vec4i &getActiveGrid() const { return mActiveGrid;}
|
||||
void setActiveGrid(const osg::Vec4i& grid)
|
||||
{
|
||||
if (grid != mActiveGrid)
|
||||
{
|
||||
mActiveGrid = grid;
|
||||
mEntries.clear();
|
||||
mNumEntries = 0;
|
||||
}
|
||||
}
|
||||
const osg::Vec4i& getActiveGrid() const { return mActiveGrid; }
|
||||
|
||||
unsigned int getWorldUpdateRevision() const { return mWorldUpdateRevision; }
|
||||
void setWorldUpdateRevision(int updateRevision) { mWorldUpdateRevision = updateRevision; }
|
||||
|
@ -81,13 +89,18 @@ namespace Terrain
|
|||
{
|
||||
public:
|
||||
ViewDataMap()
|
||||
: mReuseDistance(150) // large value should be safe because the visibility of each node is still updated individually for each camera even if the base view was reused.
|
||||
// this value also serves as a threshold for when a newly loaded LOD gets unloaded again so that if you hover around an LOD transition point the LODs won't keep loading and unloading all the time.
|
||||
: mReuseDistance(
|
||||
150) // large value should be safe because the visibility of each node is still updated individually for
|
||||
// each camera even if the base view was reused. this value also serves as a threshold for when a
|
||||
// newly loaded LOD gets unloaded again so that if you hover around an LOD transition point the
|
||||
// LODs won't keep loading and unloading all the time.
|
||||
, mExpiryDelay(1.f)
|
||||
, mWorldUpdateRevision(0)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
ViewData* getViewData(osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate);
|
||||
ViewData* getViewData(
|
||||
osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i& activeGrid, bool& needsUpdate);
|
||||
|
||||
ViewData* createOrReuseView();
|
||||
ViewData* createIndependentView() const;
|
||||
|
|
|
@ -1,148 +1,152 @@
|
|||
#include "world.hpp"
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Camera>
|
||||
#include <osg/Group>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "storage.hpp"
|
||||
#include "texturemanager.hpp"
|
||||
#include "chunkmanager.hpp"
|
||||
#include "compositemaprenderer.hpp"
|
||||
#include "heightcull.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "texturemanager.hpp"
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask)
|
||||
: mStorage(storage)
|
||||
, mParent(parent)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mBorderVisible(false)
|
||||
, mHeightCullCallback(new HeightCullCallback)
|
||||
{
|
||||
mTerrainRoot = new osg::Group;
|
||||
mTerrainRoot->setNodeMask(nodeMask);
|
||||
mTerrainRoot->setName("Terrain Root");
|
||||
|
||||
osg::ref_ptr<osg::Camera> compositeCam = new osg::Camera;
|
||||
compositeCam->setRenderOrder(osg::Camera::PRE_RENDER, -1);
|
||||
compositeCam->setProjectionMatrix(osg::Matrix::identity());
|
||||
compositeCam->setViewMatrix(osg::Matrix::identity());
|
||||
compositeCam->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
compositeCam->setClearMask(0);
|
||||
compositeCam->setNodeMask(preCompileMask);
|
||||
mCompositeMapCamera = compositeCam;
|
||||
|
||||
compileRoot->addChild(compositeCam);
|
||||
|
||||
mCompositeMapRenderer = new CompositeMapRenderer;
|
||||
compositeCam->addChild(mCompositeMapRenderer);
|
||||
|
||||
mParent->addChild(mTerrainRoot);
|
||||
|
||||
mTextureManager = std::make_unique<TextureManager>(mResourceSystem->getSceneManager());
|
||||
mChunkManager = std::make_unique<ChunkManager>(mStorage, mResourceSystem->getSceneManager(), mTextureManager.get(), mCompositeMapRenderer);
|
||||
mChunkManager->setNodeMask(nodeMask);
|
||||
mCellBorder = std::make_unique<CellBorder>(this,mTerrainRoot.get(),borderMask,mResourceSystem->getSceneManager());
|
||||
|
||||
mResourceSystem->addResourceManager(mChunkManager.get());
|
||||
mResourceSystem->addResourceManager(mTextureManager.get());
|
||||
}
|
||||
|
||||
World::World(osg::Group* parent, Storage* storage, unsigned int nodeMask)
|
||||
: mStorage(storage)
|
||||
, mParent(parent)
|
||||
, mCompositeMapCamera(nullptr)
|
||||
, mCompositeMapRenderer(nullptr)
|
||||
, mResourceSystem(nullptr)
|
||||
, mTextureManager(nullptr)
|
||||
, mChunkManager(nullptr)
|
||||
, mCellBorder(nullptr)
|
||||
, mBorderVisible(false)
|
||||
, mHeightCullCallback(nullptr)
|
||||
{
|
||||
mTerrainRoot = new osg::Group;
|
||||
mTerrainRoot->setNodeMask(nodeMask);
|
||||
|
||||
mParent->addChild(mTerrainRoot);
|
||||
}
|
||||
|
||||
World::~World()
|
||||
{
|
||||
if (mResourceSystem && mChunkManager)
|
||||
mResourceSystem->removeResourceManager(mChunkManager.get());
|
||||
if (mResourceSystem && mTextureManager)
|
||||
mResourceSystem->removeResourceManager(mTextureManager.get());
|
||||
|
||||
mParent->removeChild(mTerrainRoot);
|
||||
|
||||
if (mCompositeMapCamera && mCompositeMapRenderer)
|
||||
World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem,
|
||||
Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask)
|
||||
: mStorage(storage)
|
||||
, mParent(parent)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mBorderVisible(false)
|
||||
, mHeightCullCallback(new HeightCullCallback)
|
||||
{
|
||||
mCompositeMapCamera->removeChild(mCompositeMapRenderer);
|
||||
mCompositeMapCamera->getParent(0)->removeChild(mCompositeMapCamera);
|
||||
mTerrainRoot = new osg::Group;
|
||||
mTerrainRoot->setNodeMask(nodeMask);
|
||||
mTerrainRoot->setName("Terrain Root");
|
||||
|
||||
osg::ref_ptr<osg::Camera> compositeCam = new osg::Camera;
|
||||
compositeCam->setRenderOrder(osg::Camera::PRE_RENDER, -1);
|
||||
compositeCam->setProjectionMatrix(osg::Matrix::identity());
|
||||
compositeCam->setViewMatrix(osg::Matrix::identity());
|
||||
compositeCam->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
compositeCam->setClearMask(0);
|
||||
compositeCam->setNodeMask(preCompileMask);
|
||||
mCompositeMapCamera = compositeCam;
|
||||
|
||||
compileRoot->addChild(compositeCam);
|
||||
|
||||
mCompositeMapRenderer = new CompositeMapRenderer;
|
||||
compositeCam->addChild(mCompositeMapRenderer);
|
||||
|
||||
mParent->addChild(mTerrainRoot);
|
||||
|
||||
mTextureManager = std::make_unique<TextureManager>(mResourceSystem->getSceneManager());
|
||||
mChunkManager = std::make_unique<ChunkManager>(
|
||||
mStorage, mResourceSystem->getSceneManager(), mTextureManager.get(), mCompositeMapRenderer);
|
||||
mChunkManager->setNodeMask(nodeMask);
|
||||
mCellBorder
|
||||
= std::make_unique<CellBorder>(this, mTerrainRoot.get(), borderMask, mResourceSystem->getSceneManager());
|
||||
|
||||
mResourceSystem->addResourceManager(mChunkManager.get());
|
||||
mResourceSystem->addResourceManager(mTextureManager.get());
|
||||
}
|
||||
}
|
||||
|
||||
void World::setBordersVisible(bool visible)
|
||||
{
|
||||
mBorderVisible = visible;
|
||||
|
||||
if (visible)
|
||||
World::World(osg::Group* parent, Storage* storage, unsigned int nodeMask)
|
||||
: mStorage(storage)
|
||||
, mParent(parent)
|
||||
, mCompositeMapCamera(nullptr)
|
||||
, mCompositeMapRenderer(nullptr)
|
||||
, mResourceSystem(nullptr)
|
||||
, mTextureManager(nullptr)
|
||||
, mChunkManager(nullptr)
|
||||
, mCellBorder(nullptr)
|
||||
, mBorderVisible(false)
|
||||
, mHeightCullCallback(nullptr)
|
||||
{
|
||||
for (std::set<std::pair<int,int>>::iterator it = mLoadedCells.begin(); it != mLoadedCells.end(); ++it)
|
||||
mCellBorder->createCellBorderGeometry(it->first,it->second);
|
||||
mTerrainRoot = new osg::Group;
|
||||
mTerrainRoot->setNodeMask(nodeMask);
|
||||
|
||||
mParent->addChild(mTerrainRoot);
|
||||
}
|
||||
else
|
||||
mCellBorder->destroyCellBorderGeometry();
|
||||
}
|
||||
|
||||
void World::loadCell(int x, int y)
|
||||
{
|
||||
if (mBorderVisible)
|
||||
mCellBorder->createCellBorderGeometry(x,y);
|
||||
World::~World()
|
||||
{
|
||||
if (mResourceSystem && mChunkManager)
|
||||
mResourceSystem->removeResourceManager(mChunkManager.get());
|
||||
if (mResourceSystem && mTextureManager)
|
||||
mResourceSystem->removeResourceManager(mTextureManager.get());
|
||||
|
||||
mLoadedCells.insert(std::pair<int,int>(x,y));
|
||||
}
|
||||
mParent->removeChild(mTerrainRoot);
|
||||
|
||||
void World::unloadCell(int x, int y)
|
||||
{
|
||||
if (mBorderVisible)
|
||||
mCellBorder->destroyCellBorderGeometry(x,y);
|
||||
if (mCompositeMapCamera && mCompositeMapRenderer)
|
||||
{
|
||||
mCompositeMapCamera->removeChild(mCompositeMapRenderer);
|
||||
mCompositeMapCamera->getParent(0)->removeChild(mCompositeMapCamera);
|
||||
}
|
||||
}
|
||||
|
||||
mLoadedCells.erase(std::pair<int,int>(x,y));
|
||||
}
|
||||
void World::setBordersVisible(bool visible)
|
||||
{
|
||||
mBorderVisible = visible;
|
||||
|
||||
void World::setTargetFrameRate(float rate)
|
||||
{
|
||||
mCompositeMapRenderer->setTargetFrameRate(rate);
|
||||
}
|
||||
if (visible)
|
||||
{
|
||||
for (std::set<std::pair<int, int>>::iterator it = mLoadedCells.begin(); it != mLoadedCells.end(); ++it)
|
||||
mCellBorder->createCellBorderGeometry(it->first, it->second);
|
||||
}
|
||||
else
|
||||
mCellBorder->destroyCellBorderGeometry();
|
||||
}
|
||||
|
||||
float World::getHeightAt(const osg::Vec3f &worldPos)
|
||||
{
|
||||
return mStorage->getHeightAt(worldPos);
|
||||
}
|
||||
void World::loadCell(int x, int y)
|
||||
{
|
||||
if (mBorderVisible)
|
||||
mCellBorder->createCellBorderGeometry(x, y);
|
||||
|
||||
void World::updateTextureFiltering()
|
||||
{
|
||||
if (mTextureManager)
|
||||
mTextureManager->updateTextureFiltering();
|
||||
}
|
||||
mLoadedCells.insert(std::pair<int, int>(x, y));
|
||||
}
|
||||
|
||||
void World::clearAssociatedCaches()
|
||||
{
|
||||
if (mChunkManager)
|
||||
mChunkManager->clearCache();
|
||||
}
|
||||
void World::unloadCell(int x, int y)
|
||||
{
|
||||
if (mBorderVisible)
|
||||
mCellBorder->destroyCellBorderGeometry(x, y);
|
||||
|
||||
osg::Callback* World::getHeightCullCallback(float highz, unsigned int mask)
|
||||
{
|
||||
if (!mHeightCullCallback) return nullptr;
|
||||
mLoadedCells.erase(std::pair<int, int>(x, y));
|
||||
}
|
||||
|
||||
mHeightCullCallback->setHighZ(highz);
|
||||
mHeightCullCallback->setCullMask(mask);
|
||||
return mHeightCullCallback;
|
||||
}
|
||||
void World::setTargetFrameRate(float rate)
|
||||
{
|
||||
mCompositeMapRenderer->setTargetFrameRate(rate);
|
||||
}
|
||||
|
||||
float World::getHeightAt(const osg::Vec3f& worldPos)
|
||||
{
|
||||
return mStorage->getHeightAt(worldPos);
|
||||
}
|
||||
|
||||
void World::updateTextureFiltering()
|
||||
{
|
||||
if (mTextureManager)
|
||||
mTextureManager->updateTextureFiltering();
|
||||
}
|
||||
|
||||
void World::clearAssociatedCaches()
|
||||
{
|
||||
if (mChunkManager)
|
||||
mChunkManager->clearCache();
|
||||
}
|
||||
|
||||
osg::Callback* World::getHeightCullCallback(float highz, unsigned int mask)
|
||||
{
|
||||
if (!mHeightCullCallback)
|
||||
return nullptr;
|
||||
|
||||
mHeightCullCallback->setHighZ(highz);
|
||||
mHeightCullCallback->setCullMask(mask);
|
||||
return mHeightCullCallback;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef COMPONENTS_TERRAIN_WORLD_H
|
||||
#define COMPONENTS_TERRAIN_WORLD_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
@ -37,7 +37,7 @@ namespace Terrain
|
|||
class CompositeMapRenderer;
|
||||
class View;
|
||||
class HeightCullCallback;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The basic interface for a terrain world. How the terrain chunks are paged and displayed
|
||||
* is up to the implementation.
|
||||
|
@ -49,7 +49,8 @@ namespace Terrain
|
|||
/// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..)
|
||||
/// @param nodeMask mask for the terrain root
|
||||
/// @param preCompileMask mask for pre compiling textures
|
||||
World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask);
|
||||
World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage,
|
||||
unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask);
|
||||
World(osg::Group* parent, Storage* storage, unsigned int nodeMask);
|
||||
virtual ~World();
|
||||
|
||||
|
@ -60,7 +61,7 @@ namespace Terrain
|
|||
/// @note Thread safe.
|
||||
void updateTextureFiltering();
|
||||
|
||||
float getHeightAt (const osg::Vec3f& worldPos);
|
||||
float getHeightAt(const osg::Vec3f& worldPos);
|
||||
|
||||
/// Clears the cached land and landtexture data.
|
||||
/// @note Thread safe.
|
||||
|
@ -89,7 +90,10 @@ namespace Terrain
|
|||
|
||||
/// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads.
|
||||
|
||||
virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, Loading::Reporter& reporter) {}
|
||||
virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i& cellgrid,
|
||||
std::atomic<bool>& abort, Loading::Reporter& reporter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void rebuildViews() {}
|
||||
|
||||
|
@ -101,7 +105,7 @@ namespace Terrain
|
|||
|
||||
osg::Callback* getHeightCullCallback(float highz, unsigned int mask);
|
||||
|
||||
void setActiveGrid(const osg::Vec4i &grid) { mActiveGrid = grid; }
|
||||
void setActiveGrid(const osg::Vec4i& grid) { mActiveGrid = grid; }
|
||||
|
||||
protected:
|
||||
Storage* mStorage;
|
||||
|
@ -121,7 +125,7 @@ namespace Terrain
|
|||
|
||||
bool mBorderVisible;
|
||||
|
||||
std::set<std::pair<int,int>> mLoadedCells;
|
||||
std::set<std::pair<int, int>> mLoadedCells;
|
||||
osg::ref_ptr<HeightCullCallback> mHeightCullCallback;
|
||||
|
||||
osg::Vec4i mActiveGrid;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue