Coverage Report

Created: 2025-07-11 06:36

/src/ogre/Components/Terrain/include/OgreTerrainQuadTreeNode.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
(Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
29
#ifndef __Ogre_TerrainQuadTreeNode_H__
30
#define __Ogre_TerrainQuadTreeNode_H__
31
32
#include "OgreTerrainPrerequisites.h"
33
#include "OgreCommon.h"
34
#include "OgreMovableObject.h"
35
#include "OgreRenderable.h"
36
37
namespace Ogre
38
{
39
    /** \addtogroup Optional
40
    *  @{
41
    */
42
    /** \addtogroup Terrain
43
    *  Some details on the terrain component
44
    *  @{
45
    */
46
47
48
    /** A node in a quad tree used to store a patch of terrain.
49
50
        <b>Algorithm overview:</b>
51
    @par
52
        Our goal is to perform traditional chunked LOD with geomorphing. But, 
53
        instead of just dividing the terrain into tiles, we will divide them into
54
        a hierarchy of tiles, a quadtree, where any level of the quadtree can 
55
        be a rendered tile (to the exclusion of its children). The idea is to 
56
        collect together children into a larger batch with their siblings as LOD 
57
        decreases, to improve performance.
58
    @par
59
        The minBatchSize and maxBatchSize parameters on Terrain a key to 
60
        defining this behaviour. Both values are expressed in vertices down one axis.
61
        maxBatchSize determines the number of tiles on one side of the terrain,
62
        which is numTiles = (terrainSize-1) / (maxBatchSize-1). This in turn determines the depth
63
        of the quad tree, which is sqrt(numTiles). The minBatchSize determines
64
        the 'floor' of how low the number of vertices can go in a tile before it
65
        has to be grouped together with its siblings to drop any lower. We also do not group 
66
        a tile with its siblings unless all of them are at this minimum batch size, 
67
        rather than trying to group them when they all end up on the same 'middle' LOD;
68
        this is for several reasons; firstly, tiles hitting the same 'middle' LOD is
69
        less likely and more transient if they have different levels of 'roughness',
70
        and secondly since we're sharing a vertex / index pool between all tiles, 
71
        only grouping at the min level means that the number of combinations of 
72
        buffer sizes for any one tile is greatly simplified, making it easier to 
73
        pool data. To be more specific, any tile / quadtree node can only have
74
        log2(maxBatchSize-1) - log2(minBatchSize-1) + 1 LOD levels (and if you set them 
75
        to the same value, LOD can only change by going up/down the quadtree).
76
        The numbers of vertices / indices in each of these levels is constant for
77
        the same (relative) LOD index no matter where you are in the tree, therefore
78
        buffers can potentially be reused more easily.
79
    */
80
    class _OgreTerrainExport TerrainQuadTreeNode : private Renderable, private MovableObject
81
    {
82
    public:
83
        /** Constructor.
84
        @param terrain The ultimate parent terrain
85
        @param parent Optional parent node (in which case xoff, yoff are 0 and size must be entire terrain)
86
        @param xoff, yoff Offsets from the start of the terrain data in 2D
87
        @param size The size of the node in vertices at the highest LOD
88
        @param lod The base LOD level
89
        @param depth The depth that this node is at in the tree (or convenience)
90
        */
91
        TerrainQuadTreeNode(Terrain* terrain, TerrainQuadTreeNode* parent, 
92
            uint16 xoff, uint16 yoff, uint16 size, uint16 lod, uint16 depth);
93
        virtual ~TerrainQuadTreeNode();
94
95
        /// Get the horizontal offset into the main terrain data of this node
96
0
        uint16 getXOffset() const { return mOffsetX; }
97
        /// Get the vertical offset into the main terrain data of this node
98
0
        uint16 getYOffset() const { return mOffsetY; }
99
        /// Is this a leaf node (no children)
100
        bool isLeaf() const;
101
        /// Get the base LOD level this node starts at (the highest LOD it handles)
102
0
        uint16 getBaseLod() const { return mBaseLod; }
103
        /// Get the number of LOD levels this node can represent itself (only > 1 for leaf nodes)
104
        uint16 getLodCount() const;
105
        /// Get child node
106
        TerrainQuadTreeNode* getChild(unsigned short child) const;
107
        /// Get parent node
108
        TerrainQuadTreeNode* getParent() const;
109
        /// Get ultimate parent terrain
110
        Terrain* getTerrain() const;
111
112
        /// Prepare node and children (perform CPU tasks, may be background thread)
113
        void prepare();
114
        /// Prepare node from a stream
115
        void prepare(StreamSerialiser& stream);
116
        /// Load node and children (perform GPU tasks, will be render thread)
117
        void load();
118
        /// Load node and children in a depth range (perform GPU tasks, will be render thread)
119
        void load(uint16 depthStart, uint16 depthEnd);
120
        void loadSelf();
121
        /// Unload node and children (perform GPU tasks, will be render thread)
122
        void unload();
123
        /// Unload node and children in a depth range (perform GPU tasks, will be render thread)
124
        void unload(uint16 depthStart, uint16 depthEnd);
125
        /// Unprepare node and children (perform CPU tasks, may be background thread)
126
        void unprepare();
127
        /// Save node to a stream
128
        void save(StreamSerialiser& stream);
129
130
        struct _OgreTerrainExport LodLevel : public TerrainAlloc
131
        {
132
            /// Number of vertices rendered down one side (not including skirts)
133
            uint16 batchSize;
134
            /// Index data on the gpu
135
            IndexData* gpuIndexData;
136
            /// Maximum delta height between this and the next lower lod
137
            Real maxHeightDelta;
138
            /// Temp calc area for max height delta
139
            Real calcMaxHeightDelta;
140
            /// The most recently calculated transition distance
141
            Real lastTransitionDist;
142
            /// The cFactor value used to calculate transitionDist
143
            Real lastCFactor;
144
145
0
            LodLevel() : batchSize(0), gpuIndexData(0), maxHeightDelta(0), calcMaxHeightDelta(0),
146
0
                lastTransitionDist(0), lastCFactor(0) {}
147
        };
148
        typedef std::vector<LodLevel*> LodLevelList;
149
150
        /** Get the LodLevel information for a given lod.
151
        @param lod The lod level index relative to this classes own list; if you
152
            want to use a global lod level, subtract getBaseLod() first. Higher
153
            LOD levels are lower detail.
154
        */
155
        const LodLevel* getLodLevel(uint16 lod);
156
157
        /** Notify the node (and children) that deltas are going to be calculated for a given range.
158
159
            Based on this call, we can know whether or not to reset the max height.
160
        */
161
        void preDeltaCalculation(const Rect& rect);
162
163
        /** Notify the node (and children) of a height delta value. */
164
        void notifyDelta(uint16 x, uint16 y, uint16 lod, Real delta);
165
166
        /** Notify the node (and children) that deltas have finished being calculated.
167
        */
168
        void postDeltaCalculation(const Rect& rect);
169
170
        /** Promote the delta values calculated to the runtime ones (this must
171
            be called in the main thread). 
172
        */
173
        void finaliseDeltaValues(const Rect& rect);
174
175
        /** Assign vertex data to the tree, from a depth and at a given resolution.
176
        @param treeDepthStart The first depth of tree that should use this data, owns the data
177
        @param treeDepthEnd The end of the depth that should use this data (exclusive)
178
        @param resolution The resolution of the data to use (compared to full terrain)
179
        @param sz The size of the data along one edge
180
        */
181
        void assignVertexData(uint16 treeDepthStart, uint16 treeDepthEnd, uint16 resolution, uint sz);
182
183
        /** Tell a node that it should use an anscestor's vertex data.
184
        @param owner
185
        @param treeDepthEnd The end of the depth that should use this data (exclusive)
186
        @param resolution The resolution of the data to use
187
        */
188
        void useAncestorVertexData(TerrainQuadTreeNode* owner, uint16 treeDepthEnd, uint16 resolution);
189
190
        /** Tell the node to update its vertex data for a given region. 
191
        */
192
        void updateVertexData(bool positions, bool deltas, const Rect& rect, bool cpuData);
193
194
195
196
        /** Merge a point (relative to terrain node) into the local bounds, 
197
            and that of children if applicable.
198
        @param x,y The point on the terrain to which this position corresponds 
199
            (affects which nodes update their bounds)
200
        @param pos The position relative to the terrain centre
201
        */
202
        void mergeIntoBounds(long x, long y, const Vector3& pos);
203
        /** Reset the bounds of this node and all its children for the region given.
204
        @param rect The region for which bounds should be reset, in top-level terrain coords
205
        */
206
        void resetBounds(const Rect& rect);
207
        
208
        /** Returns true if the given rectangle overlaps the terrain area that
209
            this node references.
210
         @param rect The region in top-level terrain coords
211
        */
212
        bool rectIntersectsNode(const Rect& rect);
213
        /** Returns true if the given rectangle completely contains the terrain area that
214
        this node references.
215
        @param rect The region in top-level terrain coords
216
        */
217
        bool rectContainsNode(const Rect& rect);
218
        /** Returns true if the given point is in the terrain area that
219
         this node references.
220
         @param x,y The point in top-level terrain coords
221
         */
222
        bool pointIntersectsNode(long x, long y);
223
224
        /// Get the AABB (local coords) of this node
225
0
        const AxisAlignedBox& getBoundingBox(void) const override { return mAABB; }
226
227
        /// Get the bounding radius of this node
228
        Real getBoundingRadius() const override;
229
        /// Get the local centre of this node, relative to parent terrain centre
230
0
        const Vector3& getLocalCentre() const { return mLocalCentre; }
231
        /// Get the minimum height of the node
232
        Real getMinHeight() const;
233
        /// Get the maximum height of the node
234
        Real getMaxHeight() const;
235
236
        /** Calculate appropriate LOD for this node and children
237
        @param cam The camera to be used (this should already be the LOD camera)
238
        @param cFactor The cFactor which incorporates the viewport size, max pixel error and lod bias
239
        @return true if this node or any of its children were selected for rendering
240
        */
241
        bool calculateCurrentLod(const Camera* cam, Real cFactor);
242
243
        /// Get the current LOD index (only valid after calculateCurrentLod)
244
0
        int getCurrentLod() const { return mCurrentLod; }
245
        /// Returns whether this node is rendering itself at the current LOD level
246
        bool isRenderedAtCurrentLod() const;
247
        /// Returns whether this node or its children are being rendered at the current LOD level
248
        bool isSelfOrChildRenderedAtCurrentLod() const;
249
        /// Manually set the current LOD, intended for internal use only
250
        void setCurrentLod(int lod);
251
        /// Get the transition state between the current LOD and the next lower one (only valid after calculateCurrentLod)
252
0
        float getLodTransition() const { return mLodTransition; }
253
        /// Manually set the current LOD transition state, intended for internal use only
254
        void setLodTransition(float t);
255
256
        /// Buffer binding used for holding positions
257
        static unsigned short POSITION_BUFFER;
258
        /// Buffer binding used for holding delta values
259
        static unsigned short DELTA_BUFFER;
260
261
    private:
262
        Terrain* mTerrain;
263
        TerrainQuadTreeNode* mParent;
264
        TerrainQuadTreeNode* mChildren[4];
265
        LodLevelList mLodLevels;
266
267
        uint16 mOffsetX, mOffsetY;
268
        uint16 mBoundaryX, mBoundaryY;
269
        /// The number of vertices at the original terrain resolution this node encompasses
270
        uint16 mSize;
271
        uint16 mBaseLod;
272
        uint16 mDepth;
273
        Vector3 mLocalCentre; /// Relative to terrain centre
274
        AxisAlignedBox mAABB; /// Relative to mLocalCentre
275
        Real mBoundingRadius; /// Relative to mLocalCentre
276
        int mCurrentLod; /// -1 = none (do not render)
277
        float mLodTransition; /// 0-1 transition to lower LOD
278
        /// The child with the largest height delta 
279
        TerrainQuadTreeNode* mChildWithMaxHeightDelta;
280
        bool mSelfOrChildRendered;
281
282
        struct VertexDataRecord : public TerrainAlloc
283
        {
284
            VertexData* cpuVertexData;
285
            VertexData* gpuVertexData;
286
            /// Resolution of the data compared to the base terrain data (NOT number of vertices!)
287
            uint16 resolution;
288
            /// Size of the data along one edge
289
            uint16 size;
290
            /// Number of quadtree levels (including this one) this data applies to
291
            uint16 treeLevels;
292
            /// Number of rows and columns of skirts
293
            uint16 numSkirtRowsCols;
294
            /// The number of rows / cols to skip in between skirts
295
            uint16 skirtRowColSkip;
296
            /// Is the GPU vertex data out of date?
297
            bool gpuVertexDataDirty;
298
299
            VertexDataRecord(uint16 res, uint16 sz, uint16 lvls) 
300
0
                : cpuVertexData(0), gpuVertexData(0), resolution(res), size(sz),
301
0
                treeLevels(lvls), numSkirtRowsCols(0),
302
0
                skirtRowColSkip(0), gpuVertexDataDirty(false) {}
303
        };
304
        
305
        TerrainQuadTreeNode* mNodeWithVertexData;
306
        VertexDataRecord* mVertexDataRecord;
307
308
        /** MovableObject implementation to provide the hook to the scene.
309
310
            In one sense, it would be most convenient to have a single MovableObject
311
            to represent the whole Terrain object, and then internally perform
312
            some quadtree frustum culling to narrow down which specific tiles are rendered.
313
            However, the one major flaw with that is that exposing the bounds to 
314
            the SceneManager at that level prevents it from doing anything smarter
315
            in terms of culling - for example a portal or occlusion culling SceneManager
316
            would have no opportunity to process the leaf nodes in those terms, and
317
            a simple frustum cull may give significantly poorer results. 
318
        @par
319
            Therefore, we in fact register a MovableObject at every node, and 
320
            use the LOD factor to determine which one is currently active. LODs
321
            must be mutually exclusive and to deal with precision errors, we really
322
            need to evaluate them all at once, rather than as part of the 
323
            _notifyCurrentCamera function. Therefore the root Terrain registers
324
            a SceneManager::Listener to precalculate which nodes will be displayed 
325
            when it comes to purely a LOD basis.
326
        */
327
        SceneNode* mLocalNode;
328
329
        // actual implementation of MovableObject methods
330
        bool isVisible(void) const override;
331
        const String& getMovableType(void) const override;
332
        void _updateRenderQueue(RenderQueue* queue) override;
333
        void visitRenderables(Renderable::Visitor* visitor,  bool debugRenderables = false) override;
334
        // actual implementations of Renderable methods
335
        const MaterialPtr& getMaterial(void) const override;
336
        Technique* getTechnique(void) const override;
337
        void getRenderOperation(RenderOperation& op) override;
338
        void getWorldTransforms(Matrix4* xform) const override;
339
        Real getSquaredViewDepth(const Camera* cam) const override;
340
        const LightList& getLights(void) const override;
341
        bool getCastShadows(void) const override;
342
        /// @deprecated will be private in 14
343
0
        bool getCastsShadows(void) const override { return getCastShadows(); }
344
345
346
        const VertexDataRecord* getVertexDataRecord() const;
347
        void createCpuVertexData();
348
        /* Update the vertex buffers - the rect in question is relative to the whole terrain, 
349
            not the local vertex data (which may use a subset)
350
        */
351
        void updateVertexBuffer(const HardwareVertexBufferPtr& posbuf, const HardwareVertexBufferPtr& deltabuf, const Rect& rect);
352
        void destroyCpuVertexData();
353
354
        void createGpuVertexData();
355
        void destroyGpuVertexData();
356
        void updateGpuVertexData();
357
        void createGpuIndexData();
358
        void destroyGpuIndexData();
359
360
        void populateIndexData(uint16 batchSize, IndexData* destData);
361
        void writePosVertex(bool compress, uint16 x, uint16 y, float height, const Vector3& pos, float uvScale, float** ppPos);
362
        void writeDeltaVertex(bool compress, uint16 x, uint16 y, float delta, float deltaThresh, float** ppDelta);
363
        
364
        uint16 calcSkirtVertexIndex(uint16 mainIndex, bool isCol);
365
366
    };
367
368
    /** @} */
369
    /** @} */
370
}
371
372
#endif