1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ 2 3 #include <cstring> 4 #include <assert.h> 5 #include "Rendering/GL/myGL.h" 6 7 #include "TerrainBase.h" 8 #include "TerrainNode.h" 9 #include "TerrainTexture.h" 10 11 namespace terrain { 12 QuadRenderData()13 QuadRenderData::QuadRenderData() 14 : normalMap(0) 15 , normalMapW(0) 16 , normalMapTexWidth(0) 17 , vertexSize(0) 18 , index(0) 19 , used(false) 20 , quad(0) 21 { 22 } 23 ~QuadRenderData()24 QuadRenderData::~QuadRenderData() 25 { 26 // delete normal map 27 if (normalMap) { 28 glDeleteTextures(1, &normalMap); 29 normalMap = 0; 30 } 31 } 32 GetDataSize()33 uint QuadRenderData::GetDataSize() 34 { 35 return normalMapW * normalMapW * 3 + vertexBuffer.GetSize(); 36 } 37 RenderDataManager(Heightmap * rhm,QuadMap * rqm)38 RenderDataManager::RenderDataManager(Heightmap* rhm, QuadMap* rqm) 39 : normalDataAllocates(0) 40 , renderDataAllocates(0) 41 , roothm(rhm) 42 , rootQMap(rqm) 43 { 44 } 45 ~RenderDataManager()46 RenderDataManager::~RenderDataManager() 47 { 48 for (size_t a = 0; a < freeRD.size(); a++) 49 delete freeRD[a]; 50 for (size_t a = 0; a < qrd.size(); a++) 51 delete qrd[a]; 52 } 53 Allocate()54 QuadRenderData* RenderDataManager::Allocate() 55 { 56 QuadRenderData* rd; 57 if (!freeRD.empty()) { 58 rd = freeRD.back(); 59 freeRD.pop_back(); 60 } 61 else rd = new QuadRenderData; 62 63 rd->index = qrd.size(); 64 qrd.push_back(rd); 65 66 renderDataAllocates++; 67 68 return rd; 69 } 70 PruneFreeList(int maxFreeRD)71 void RenderDataManager::PruneFreeList(int maxFreeRD) 72 { 73 const size_t maxFreeRDUnsigned = (maxFreeRD < 0) ? 0 : maxFreeRD; 74 while (freeRD.size() > maxFreeRDUnsigned) { 75 delete freeRD.back(); 76 freeRD.pop_back(); 77 } 78 } 79 Free(QuadRenderData * rd)80 void RenderDataManager::Free(QuadRenderData* rd) 81 { 82 if (rd->index < qrd.size()-1) { 83 qrd.back()->index = rd->index; 84 std::swap(qrd.back(), qrd[rd->index]); 85 } 86 qrd.pop_back(); 87 88 freeRD.push_back(rd); 89 rd->GetQuad()->renderData = 0; 90 91 rd->GetQuad()->FreeCachedTexture(); 92 } 93 UpdateRect(int sx,int sy,int w,int h)94 void RenderDataManager::UpdateRect(int sx, int sy,int w,int h) 95 { 96 for (size_t a = 0; a < qrd.size(); a++) 97 { 98 QuadRenderData* rd = qrd[a]; 99 TQuad* q = rd->GetQuad(); 100 101 // rect vs rect collision: 102 if (q->sqPos.x + q->width >= sx && q->sqPos.y + q->width >= sy && 103 q->sqPos.x <= sx + w && q->sqPos.y <= sy + h) 104 { 105 assert(q->renderData==qrd[a]); 106 Free(q->renderData); 107 } 108 } 109 } 110 111 // delete all renderdata that is not used this frame and has maxlod < VBufMinDetail FreeUnused()112 void RenderDataManager::FreeUnused() 113 { 114 for (int a = 0; a < qrd.size(); a++) 115 { 116 QuadRenderData* rd = qrd[a]; 117 118 if (rd->used) { 119 rd->used = false; 120 continue; 121 } 122 123 if (rd->GetQuad()->maxLodValue < VBufMinDetail) { 124 Free(rd); 125 a--; 126 } 127 } 128 } 129 InitializeNode(TQuad * q)130 void RenderDataManager::InitializeNode(TQuad* q) 131 { 132 assert(!q->renderData); 133 134 QuadRenderData* rd = q->renderData = Allocate(); 135 136 // Allocate vertex data space 137 const size_t vertexSize = q->GetVertexSize(); 138 if (static_cast<int>(vertexSize) != rd->vertexSize) { 139 const size_t size = NUM_VERTICES * vertexSize; 140 141 if (rd->vertexBuffer.GetSize() != size) { 142 rd->vertexBuffer.Init(size); 143 } 144 rd->vertexSize = vertexSize; 145 } 146 147 // build the vertex buffer 148 Vector3* v = (Vector3*)rd->vertexBuffer.LockData(); 149 150 uint vda = q->textureSetup->vertexDataReq; // vertex data requirements 151 const Heightmap* hm = roothm->GetLevel(q->depth); // get the right heightmap level 152 153 for (int y = q->hmPos.y; y <= (q->hmPos.y + QUAD_W); y++) 154 for (int x = q->hmPos.x; x <= (q->hmPos.x + QUAD_W); x++) 155 { 156 *(v++) = Vector3(x * hm->squareSize, hm->atSynced(x, y), y * hm->squareSize); 157 158 Vector3 tangent, binormal; 159 CalculateTangents(hm, x,y, tangent, binormal); 160 Vector3 normal = binormal.cross(tangent); 161 normal.ANormalize(); 162 163 if (vda & VRT_Normal) 164 *(v++) = normal; 165 166 if (vda & VRT_TangentSpaceMatrix) 167 { 168 tangent.ANormalize(); 169 binormal.ANormalize(); 170 171 // orthonormal matrix, so inverse=transpose 172 // Take the inverse of the tangent space -> world space transformation 173 Vector3* tgs2ws = v; 174 tgs2ws[0] = Vector3(tangent.x, binormal.x, normal.x); 175 tgs2ws[1] = Vector3(tangent.y, binormal.y, normal.y); 176 tgs2ws[2] = Vector3(tangent.z, binormal.z, normal.z); 177 v += 3; 178 } 179 } 180 rd->vertexBuffer.UnlockData(); 181 rd->SetQuad(q); 182 } 183 184 InitializeNodeNormalMap(TQuad * q,int cfgNormalMapLevel)185 void RenderDataManager::InitializeNodeNormalMap(TQuad* q, int cfgNormalMapLevel) 186 { 187 QuadRenderData* rd = q->renderData; 188 189 if (q->isLeaf()) { 190 if (rd->normalMap) { 191 glDeleteTextures(1, &rd->normalMap); 192 rd->normalMap = 0; 193 rd->normalMapW = 0; 194 } 195 return; 196 } 197 198 // find the right level heightmap to generate the normal map from 199 Heightmap* hm = roothm; 200 int level = 0; 201 for (; hm->highDetail; hm = hm->highDetail, level++) 202 if (level == q->depth + cfgNormalMapLevel) break; 203 204 // calculate dimensions 205 const int scale = 1 << (level - q->depth); 206 size_t w = QUAD_W * scale + 1; 207 const size_t h = w; 208 const int startx = q->hmPos.x * scale; 209 210 // use power-of-two texture sizes if required 211 size_t texw = 1; 212 //if (GLEW_ARB_texture_non_power_of_two) texw = w; 213 //else 214 while (texw < w) texw *= 2; 215 216 // if not yet created, create a texture for it 217 GLuint texture; 218 219 if (rd->normalMap && (rd->normalMapW == w) && (rd->normalMapTexWidth == texw)) { 220 texture = rd->normalMap; 221 glBindTexture(GL_TEXTURE_2D, texture); 222 } else { 223 if (rd->normalMap) 224 glDeleteTextures(1,&rd->normalMap); 225 226 glGenTextures(1, &texture); 227 glBindTexture(GL_TEXTURE_2D, texture); 228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 230 231 rd->normalMap = texture; 232 rd->normalMapW = w; 233 rd->normalMapTexWidth = texw; 234 } 235 236 // allocate temporary storage for normals 237 uchar* normals = new uchar[texw*texw*3]; 238 239 // calculate normals 240 for (size_t y=0; y<h; y++) { 241 const uchar* src = hm->GetNormal(startx, y + q->hmPos.y * scale); 242 memcpy(&normals [3 * y * texw], src, 3 * w); 243 } 244 245 // fill texture 246 glTexImage2D(GL_TEXTURE_2D, 0, 3, texw,texw,0, GL_RGB, GL_UNSIGNED_BYTE, normals); 247 248 delete[] normals; 249 } 250 251 }; 252