1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #ifndef _TERRAIN_NODE_H_
4 #define _TERRAIN_NODE_H_
5 
6 #include "TerrainVertexBuffer.h"
7 #include "Map/SM3/Vector3.h"
8 #include <vector>
9 
10 class Frustum;
11 struct Sm3VisibilityNode;
12 
13 namespace terrain
14 {
15 	struct int2 {
int2int216 		int2(int x, int y) : x(x), y(y) {}
int2int217 		int2() : x(0), y(0) {}
18 		int x;
19 		int y;
20 	};
21 
22 	class Camera;
23 	struct Heightmap;
24 	struct QuadMap;
25 	struct IndexTable;
26 	class QuadRenderData;
27 	class QuadNormals;
28 	struct RenderSetupCollection;
29 	struct IShaderSetup;
30 	class TerrainTexture;
31 
32 //-----------------------------------------------------------------------
33 // Terrain Quadtree Node
34 //-----------------------------------------------------------------------
35 
36 	static const int QUAD_W = 16;
37 	static const int VERTC = QUAD_W + 1;
38 	static const int MAX_INDICES  = (QUAD_W + 1) * (QUAD_W + 1) * 2 * 3;
39 	static const int NUM_VERTICES = (QUAD_W + 1) * (QUAD_W + 1);
40 
41 	const float SquareSize = 8.0f;
42 	const float VBufMinDetail = 0.25f; ///< at lod < 0.25f, the vertex buffer is deleted
43 
44 	const float AREA_TEST_RANGE = 0.05f;
45 
46 	class TQuad
47 	{
48 	public:
49 		TQuad();
50 		~TQuad();
isLeaf()51 		bool isLeaf() const { return children[0] == NULL; }
52 		// sqStart=start in square coordinates
53 		// hmStart=start pixel on hm
54 		void Build(Heightmap* hm, int2 sqStart, int2 hmStart, int2 quadPos, int w, int depth);
55 		void Draw(IndexTable* indexTable, bool onlyPositions, int lodState);
56 		bool InFrustum(Frustum* f);
57 		float CalcLod(const Vector3& campos);
58 		void CollectNodes(std::vector<TQuad*>& quads);
59 		void FreeCachedTexture();
60 
61 		TQuad* FindSmallestContainingQuad2D(const Vector3& pos, float range, int maxlevel);
62 
63 		int GetVertexSize();
64 
65 		// Possible objects linked to this quad, for visibility determination
66 		std::vector<Sm3VisibilityNode*> nodeLinks;
67 
68 		TQuad* parent;
69 		TQuad* children[4];
70 		Vector3 start, end;  ///< quad node bounding box
71 		int2 qmPos; ///< Quad map coordinates
72 		int2 hmPos;
73 		int2 sqPos; ///< square position (position on highest detail heightmap)
74 		int depth, width;
75 		RenderSetupCollection* textureSetup;
76 		GLuint cacheTexture;
77 		/**
78 		 * maximum of the LOD values calculated for each render contexts
79 		 * used for determining if the QuadRenderData can be marked as free
80 		 * @see RenderDataManager::FreeUnused
81 		 */
82 		float maxLodValue;
83 
84 		enum DrawState {
85 			NoDraw, Parent, Queued, Culled
86 		} drawState;
87 
88 		QuadNormals* normalData;
89 		QuadRenderData* renderData;
90 	};
91 
92 	/**
93 	 * Each render context has a QuadRenderInfo for every quad they have to
94 	 * render.
95 	 */
96 	struct QuadRenderInfo
97 	{
98 		int lodState;
99 		TQuad* quad;
100 	};
101 
102 	class RenderContext
103 	{
104 	public:
105 		Camera* cam;
106 		/// contexts like shadow buffers do not need texturing
107 		bool needsTexturing;
108 		bool needsNormalMap;
109 
110 		std::vector<QuadRenderInfo> quads;
111 	};
112 
113 	// renderdata for a visible quad
114 	class QuadRenderData
115 	{
116 	public:
117 		QuadRenderData();
118 		~QuadRenderData();
119 
120 		uint GetDataSize();
121 
122 		// seems silly yeah, but I use it to set breakpoints in
GetQuad()123 		TQuad* GetQuad() { return quad; }
SetQuad(TQuad * q)124 		void SetQuad(TQuad* q) { quad = q; }
125 
126 		// renderdata: normalmap + vertex buffer
127 		// normalmap for detail preservation
128 		GLuint normalMap;
129 		uint normalMapW;
130 		uint normalMapTexWidth;
131 
132 		VertexBuffer vertexBuffer;
133 		int vertexSize;
134 
135 		int index;
136 		bool used;
137 	protected:
138 		TQuad* quad;
139 	};
140 
141 	// Manager for QuadRenderData
142 	class RenderDataManager {
143 	public:
144 		RenderDataManager(Heightmap* roothm, QuadMap* rootqm);
145 		~RenderDataManager();
146 
147 		void Free(QuadRenderData* qrd);
148 		void FreeUnused();
149 		/// allow the list of free renderdata to be maxFreeRD or lower
150 		void PruneFreeList(int maxFreeRD = 0);
151 
152 		void InitializeNode(TQuad* q);
153 		void InitializeNodeNormalMap(TQuad* q, int cfgNormalMapLevel);
154 
155 		void UpdateRect(int sx, int sy, int w, int h);
156 
ClearStat()157 		void ClearStat() {
158 			normalDataAllocates = 0;
159 			renderDataAllocates = 0;
160 		}
161 
162 		int normalDataAllocates; // performance statistic
163 		int renderDataAllocates;
164 
QuadRenderDataCount()165 		int QuadRenderDataCount() { return qrd.size(); }
166 
167 	protected:
168 		QuadRenderData* Allocate();
169 
170 		std::vector<QuadRenderData*> qrd;
171 		std::vector<QuadRenderData*> freeRD;
172 		Heightmap* roothm;
173 		QuadMap* rootQMap;
174 	};
175 
176 
177 
178 
179 //-----------------------------------------------------------------------
180 // Heightmap
181 //-----------------------------------------------------------------------
182 	struct Heightmap {
183 		Heightmap();
184 		~Heightmap();
185 
186 		void Alloc(int W, int H);
187 		void LodScaleDown(Heightmap* dst);
188 		void FindMinMax(int2 st, int2 size, float& minHgt, float& maxHgt, bool synced = true);
189 		Heightmap* CreateLowDetailHM();
190 		void GenerateNormals();
191 		void UpdateLowerUnsynced(int sx, int sy, int w, int h);
192 		/**
193 		 * @param level > 0 returns a high detail HM
194 		 *   < 0 returns a lower detail HM
195 		 */
196 		const Heightmap* GetLevel(int level);
197 
atSyncedHeightmap198 		float atSynced(int x, int y) const { return dataSynced[y * w + x]; }
atUnsyncedHeightmap199 		float atUnsynced(int x, int y) const { return dataUnsynced[y * w + x]; }
GetNormalHeightmap200 		const uchar* GetNormal(int x, int y) const { return &normalData[3 * (y * w + x)]; }
201 
202 		int w, h;
203 		std::vector<float> dataSynced;
204 		std::vector<float> dataUnsynced;
205 		// float scale, offset;
206 		float squareSize;
207 
208 		/**
209 		 * optional heightmap normals, stored as compressed vectors
210 		 * (3 bytes per normal)
211 		 */
212         uchar* normalData;
213 
214 		// geo-mip-map chain links
215 		Heightmap* lowDetail;
216 		Heightmap* highDetail;
217 	};
218 
219 //-----------------------------------------------------------------------
220 // Quad map - stores a 2D map of the quad nodes,
221 //            for quick access of nabours
222 //-----------------------------------------------------------------------
223 	struct QuadMap
224 	{
QuadMapQuadMap225 		QuadMap()
226 			: w(0)
227 			, map(NULL)
228 			, highDetail(NULL)
229 			, lowDetail(NULL)
230 		{
231 		}
~QuadMapQuadMap232 		~QuadMap() {
233 			delete[] map;
234 		}
235 
236 		void Alloc(int W);
237 		void Fill(TQuad* root);
AtQuadMap238 		TQuad*& At(int x, int y) { return map[y*w + x]; }
239 
240 		int w;
241 		TQuad** map;
242 
243 		QuadMap* highDetail;
244 		QuadMap* lowDetail;
245 	};
246 
247 
248 	/**
249 	 * Applies a "sobel" filter to the heightmap to find the slope in X
250 	 * and Z(Y in heightmap) direction.
251 	 */
CalculateTangents(const Heightmap * hm,int x,int y,Vector3 & tangent,Vector3 & binormal)252 	inline void CalculateTangents(const Heightmap* hm, int x, int y, Vector3& tangent, Vector3& binormal)
253 	{
254 		int xp = (x < hm->w-1) ? x+1 : x;
255 		int xm = (x > 0) ? x-1 : x;
256 		int yp = (y < hm->h-1) ? y+1 : y;
257 		int ym = (y > 0) ? y-1 : y;
258 
259 		//X filter:
260 		//-1 0 1
261 		//-2 0 2
262 		//-1 0 1
263 		const int dhdx =
264 			int     (-hm->atSynced(xm, ym) + hm->atSynced(xp, ym)) +
265 			int(2 * (-hm->atSynced(xm, y)  + hm->atSynced(xp, y))) +
266 			int(     -hm->atSynced(xm, yp) + hm->atSynced(xp, yp));
267 
268 		//
269 		//Z filter:
270 		//-1 -2 -1
271 		//0  0  0
272 		//1  2  1
273 		//
274 		const int dhdz =
275 			int(hm->atSynced(xm, yp) + 2 * hm->atSynced(x, yp) + hm->atSynced(xp, yp)) -
276 			int(hm->atSynced(xm, ym) + 2 * hm->atSynced(x, ym) + hm->atSynced(xp, ym));
277 
278 		tangent = Vector3(hm->squareSize * 2.0f, /*hm->scale * */ dhdx * 0.25f, 0.0f);
279 		binormal = Vector3(0.0f, dhdz * /*hm->scale * */ 0.25f, hm->squareSize * 2.0f);
280 
281 //		tangent.set(vdif * 2.0f, dhdx, 0.0f);
282 //		binormal.set(0.0f, dhdz, vdif * 2.0f);
283 	}
284 
285 
286 //-----------------------------------------------------------------------
287 // IndexTable
288 //    generates index buffers for the 16 different LOD configurations a quad can be in.
289 //-----------------------------------------------------------------------
290 #define NUM_TABLES 16
291 
292 	// flags that determine if a specific quad side has lower res
293 #define up_bit 1    // x=0 y=-1
294 #define left_bit 2  // x=-1 y=0
295 #define right_bit 4 // x=1 y=0
296 #define down_bit 8  // x=0 y=1
297 
298 	// table of precomputed indices
299 	struct IndexTable
300 	{
301 		typedef unsigned short index_t;
302 
303 		IndexTable();
304 
IndexTypeIndexTable305 		GLenum IndexType() const { return GL_UNSIGNED_SHORT; }
306 
307 		void Calculate(int sides);
308 
309 		int size[NUM_TABLES];
310 		IndexBuffer buffers[NUM_TABLES];
311 	};
312 
313 };
314 
315 #endif // _TERRAIN_NODE_H_
316 
317