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