File: terraingrid.cpp

package info (click to toggle)
openmw 0.47.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 23,276 kB
  • sloc: cpp: 249,935; xml: 1,978; sh: 1,327; python: 63; makefile: 26
file content (129 lines) | stat: -rw-r--r-- 3,764 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "terraingrid.hpp"

#include <memory>

#include <osg/Group>
#include <osg/ComputeBoundsVisitor>

#include <components/sceneutil/positionattitudetransform.hpp>
#include "chunkmanager.hpp"
#include "compositemaprenderer.hpp"
#include "storage.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())
    {
        TerrainGrid::unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second);
    }
}

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);
}

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);

        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;

        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

    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

    TerrainGrid::World::loadCell(x,y);

    mTerrainRoot->addChild(terrainNode);

    mGrid[std::make_pair(x,y)] = terrainNode;
    updateWaterCulling();
}

void TerrainGrid::unloadCell(int x, int y)
{
    CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y));
    if (it == mGrid.end())
        return;

    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;
}

}