1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "BaseGroundDrawer.h"
4 
5 #include "Game/Camera.h"
6 #include "Game/GlobalUnsynced.h"
7 #include "Game/SelectedUnitsHandler.h"
8 #include "Game/UI/GuiHandler.h"
9 #include "Ground.h"
10 #include "HeightLinePalette.h"
11 #include "MetalMap.h"
12 #include "ReadMap.h"
13 #include "MapInfo.h"
14 #include "Rendering/IPathDrawer.h"
15 #include "Rendering/Env/ITreeDrawer.h"
16 #include "Sim/Misc/LosHandler.h"
17 #include "Sim/Misc/RadarHandler.h"
18 #include "System/Config/ConfigHandler.h"
19 #include "System/FastMath.h"
20 #include "System/myMath.h"
21 
22 CONFIG(float, GroundLODScaleReflection).defaultValue(1.0f);
23 CONFIG(float, GroundLODScaleRefraction).defaultValue(1.0f);
24 CONFIG(float, GroundLODScaleTerrainReflection).defaultValue(1.0f);
25 CONFIG(bool, HighResLos).defaultValue(false).description("Controls whether LOS (\"L view\") edges are rendered in high resolution. Resource heavy!");
26 CONFIG(int, ExtraTextureUpdateRate).defaultValue(45);
27 
CBaseGroundDrawer()28 CBaseGroundDrawer::CBaseGroundDrawer()
29 {
30 	LODScaleReflection = configHandler->GetFloat("GroundLODScaleReflection");
31 	LODScaleRefraction = configHandler->GetFloat("GroundLODScaleRefraction");
32 	LODScaleTerrainReflection = configHandler->GetFloat("GroundLODScaleTerrainReflection");
33 
34 	memset(&infoTextureIDs[0], 0, sizeof(infoTextureIDs));
35 
36 	drawMode = drawNormal;
37 	drawLineOfSight = false;
38 	drawRadarAndJammer = true;
39 	drawMapEdges = false;
40 	drawDeferred = false;
41 	wireframe = false;
42 	advShading = false;
43 	highResInfoTex = false;
44 	updateTextureState = 0;
45 
46 	infoTexPBO.Bind();
47 	infoTexPBO.New(gs->pwr2mapx * gs->pwr2mapy * 4);
48 	infoTexPBO.Unbind();
49 
50 	highResInfoTexWanted = false;
51 
52 	highResLosTex = configHandler->GetBool("HighResLos");
53 	extraTextureUpdateRate = std::max(4, configHandler->GetInt("ExtraTextureUpdateRate") - 1);
54 
55 	jamColor[0] = (int)(losColorScale * 0.25f);
56 	jamColor[1] = (int)(losColorScale * 0.0f);
57 	jamColor[2] = (int)(losColorScale * 0.0f);
58 
59 	losColor[0] = (int)(losColorScale * 0.15f);
60 	losColor[1] = (int)(losColorScale * 0.05f);
61 	losColor[2] = (int)(losColorScale * 0.40f);
62 
63 	radarColor[0] = (int)(losColorScale *  0.05f);
64 	radarColor[1] = (int)(losColorScale *  0.15f);
65 	radarColor[2] = (int)(losColorScale * -0.20f);
66 
67 	alwaysColor[0] = (int)(losColorScale * 0.25f);
68 	alwaysColor[1] = (int)(losColorScale * 0.25f);
69 	alwaysColor[2] = (int)(losColorScale * 0.25f);
70 
71 	heightLinePal = new CHeightLinePalette();
72 	groundTextures = NULL;
73 }
74 
75 
~CBaseGroundDrawer()76 CBaseGroundDrawer::~CBaseGroundDrawer()
77 {
78 	for (unsigned int n = 0; n < NUM_INFOTEXTURES; n++) {
79 		glDeleteTextures(1, &infoTextureIDs[n]);
80 	}
81 
82 	delete heightLinePal;
83 }
84 
85 
86 
DrawTrees(bool drawReflection) const87 void CBaseGroundDrawer::DrawTrees(bool drawReflection) const
88 {
89 	glEnable(GL_ALPHA_TEST);
90 	glAlphaFunc(GL_GREATER, 0.005f);
91 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
92 	glEnable(GL_BLEND);
93 
94 	if (treeDrawer->drawTrees) {
95 		if (DrawExtraTex()) {
96 			glActiveTextureARB(GL_TEXTURE1_ARB);
97 			glEnable(GL_TEXTURE_2D);
98 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_ARB);
99 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
100 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
101 			glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
102 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
103 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE);
104 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
105 			glBindTexture(GL_TEXTURE_2D, infoTextureIDs[drawMode]);
106 			SetTexGen(1.0f / (gs->pwr2mapx * SQUARE_SIZE), 1.0f / (gs->pwr2mapy * SQUARE_SIZE), 0, 0);
107 			glActiveTextureARB(GL_TEXTURE0_ARB);
108 		}
109 
110 		treeDrawer->Draw(drawReflection);
111 
112 		if (DrawExtraTex()) {
113 			glActiveTextureARB(GL_TEXTURE1_ARB);
114 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
115 			glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
116 			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
117 
118 			glDisable(GL_TEXTURE_GEN_S);
119 			glDisable(GL_TEXTURE_GEN_T);
120 			glDisable(GL_TEXTURE_2D);
121 			glActiveTextureARB(GL_TEXTURE0_ARB);
122 		}
123 	}
124 
125 	glDisable(GL_ALPHA_TEST);
126 	glDisable(GL_BLEND);
127 }
128 
129 
130 
131 // XXX this part of extra textures is a mess really ...
DisableExtraTexture()132 void CBaseGroundDrawer::DisableExtraTexture()
133 {
134 	highResInfoTexWanted = (drawLineOfSight && highResLosTex);
135 	updateTextureState = 0;
136 
137 	if (drawLineOfSight) {
138 		// return to LOS-mode if it was active before
139 		SetDrawMode(drawLos);
140 
141 		while (!UpdateExtraTexture(drawMode));
142 	} else {
143 		SetDrawMode(drawNormal);
144 	}
145 }
146 
147 
SetHeightTexture()148 void CBaseGroundDrawer::SetHeightTexture()
149 {
150 	if (drawMode == drawHeight) {
151 		DisableExtraTexture();
152 	} else {
153 		SetDrawMode(drawHeight);
154 
155 		highResInfoTexWanted = true;
156 		updateTextureState = 0;
157 
158 		while (!UpdateExtraTexture(drawMode));
159 	}
160 }
161 
162 
163 
SetMetalTexture()164 void CBaseGroundDrawer::SetMetalTexture()
165 {
166 	if (drawMode == drawMetal) {
167 		DisableExtraTexture();
168 	} else {
169 		SetDrawMode(drawMetal);
170 
171 		highResInfoTexWanted = false;
172 		updateTextureState = 0;
173 
174 		while (!UpdateExtraTexture(drawMode));
175 	}
176 }
177 
178 
TogglePathTexture(BaseGroundDrawMode mode)179 void CBaseGroundDrawer::TogglePathTexture(BaseGroundDrawMode mode)
180 {
181 	switch (mode) {
182 		case drawPathTrav:
183 		case drawPathHeat:
184 		case drawPathFlow:
185 		case drawPathCost: {
186 			if (drawMode == mode) {
187 				DisableExtraTexture();
188 			} else {
189 				SetDrawMode(mode);
190 
191 				highResInfoTexWanted = false;
192 				updateTextureState = 0;
193 
194 				while (!UpdateExtraTexture(drawMode));
195 			}
196 		} break;
197 
198 		default: {
199 		} break;
200 	}
201 }
202 
203 
ToggleLosTexture()204 void CBaseGroundDrawer::ToggleLosTexture()
205 {
206 	if (drawMode == drawLos) {
207 		drawLineOfSight = false;
208 		DisableExtraTexture();
209 	} else {
210 		drawLineOfSight = true;
211 
212 		SetDrawMode(drawLos);
213 		highResInfoTexWanted = highResLosTex;
214 		updateTextureState = 0;
215 
216 		while (!UpdateExtraTexture(drawMode));
217 	}
218 }
219 
220 
ToggleRadarAndJammer()221 void CBaseGroundDrawer::ToggleRadarAndJammer()
222 {
223 	drawRadarAndJammer = !drawRadarAndJammer;
224 
225 	if (drawMode != drawLos)
226 		return;
227 
228 	updateTextureState = 0;
229 	while (!UpdateExtraTexture(drawMode));
230 }
231 
232 
233 
InterpolateLos(const unsigned short * p,int xsize,int ysize,int mip,int factor,int x,int y)234 static inline int InterpolateLos(
235 	const unsigned short* p,
236 	int xsize,
237 	int ysize,
238 	int mip,
239 	int factor,
240 	int x,
241 	int y
242 ) {
243 	const int x1 = x >> mip;
244 	const int y1 = y >> mip;
245 	const int s1 = (p[(y1 * xsize) + x1] != 0); // top left
246 	if (mip > 0) {
247 		int x2 = x1 + 1;
248 		int y2 = y1 + 1;
249 		if (x2 >= xsize) { x2 = xsize - 1; }
250 		if (y2 >= ysize) { y2 = ysize - 1; }
251 		const int s2 = (p[(y1 * xsize) + x2] != 0); // top right
252 		const int s3 = (p[(y2 * xsize) + x1] != 0); // bottom left
253 		const int s4 = (p[(y2 * xsize) + x2] != 0); // bottom right
254 		const int size  = (1 << mip);
255 		const float fracx = float(x % size) / size;
256 		const float fracy = float(y % size) / size;
257 		const float c1 = (s2 - s1) * fracx + s1;
258 		const float c2 = (s4 - s3) * fracx + s3;
259 		return factor * ((c2 - c1) * fracy + c1);
260 	}
261 	return factor * s1;
262 }
263 
264 
265 // Gradually calculate the extra texture based on updateTextureState:
266 //   updateTextureState < extraTextureUpdateRate:   Calculate the texture color values and copy them into buffer
267 //   updateTextureState = extraTextureUpdateRate:   Copy the buffer into a texture
268 // NOTE:
269 //   when switching TO an info-texture drawing mode
270 //   the texture is calculated in its entirety, not
271 //   over multiple frames
UpdateExtraTexture(unsigned int texDrawMode)272 bool CBaseGroundDrawer::UpdateExtraTexture(unsigned int texDrawMode)
273 {
274 	assert(texDrawMode != drawNormal);
275 
276 	if (mapInfo->map.voidWater && readMap->IsUnderWater())
277 		return true;
278 
279 	if (updateTextureState < extraTextureUpdateRate) {
280 		const int pwr2mapx_half = gs->pwr2mapx >> 1;
281 
282 		int starty;
283 		int endy;
284 		int offset;
285 
286 		// pointer to GPU-memory mapped into our address space
287 		unsigned char* infoTexMem = NULL;
288 
289 		infoTexPBO.Bind();
290 
291 		if (highResInfoTexWanted) {
292 			starty = updateTextureState * gs->mapy / extraTextureUpdateRate;
293 			endy = (updateTextureState + 1) * gs->mapy / extraTextureUpdateRate;
294 
295 			offset = starty * gs->pwr2mapx * 4;
296 			infoTexMem = reinterpret_cast<unsigned char*>(infoTexPBO.MapBuffer(offset, (endy - starty) * gs->pwr2mapx * 4));
297 		} else {
298 			starty = updateTextureState * gs->hmapy / extraTextureUpdateRate;
299 			endy = (updateTextureState + 1) * gs->hmapy / extraTextureUpdateRate;
300 
301 			offset = starty * pwr2mapx_half * 4;
302 			infoTexMem = reinterpret_cast<unsigned char*>(infoTexPBO.MapBuffer(offset, (endy - starty) * pwr2mapx_half * 4));
303 		}
304 
305 		switch (texDrawMode) {
306 			case drawPathTrav:
307 			case drawPathHeat:
308 			case drawPathFlow:
309 			case drawPathCost: {
310 				pathDrawer->UpdateExtraTexture(texDrawMode, starty, endy, offset, infoTexMem);
311 			} break;
312 
313 			case drawMetal: {
314 				const CMetalMap* metalMap = readMap->metalMap;
315 
316 				const unsigned short* myAirLos        = &losHandler->airLosMaps[gu->myAllyTeam].front();
317 				const unsigned  char* extraTex        = metalMap->GetDistributionMap();
318 				const unsigned  char* extraTexPal     = metalMap->GetTexturePalette();
319 				const          float* extractDepthMap = metalMap->GetExtractionMap();
320 
321 				for (int y = starty; y < endy; ++y) {
322 					const int y_pwr2mapx_half = y*pwr2mapx_half;
323 					const int y_hmapx = y * gs->hmapx;
324 
325 					for (int x = 0; x < gs->hmapx; ++x) {
326 						const int a   = (y_pwr2mapx_half + x) * 4 - offset;
327 						const int alx = ((x*2) >> losHandler->airMipLevel);
328 						const int aly = ((y*2) >> losHandler->airMipLevel);
329 
330 						if (myAirLos[alx + (aly * losHandler->airSizeX)]) {
331 							infoTexMem[a + COLOR_R] = (unsigned char)std::min(255.0f, 900.0f * fastmath::apxsqrt(fastmath::apxsqrt(extractDepthMap[y_hmapx + x])));
332 						} else {
333 							infoTexMem[a + COLOR_R] = 0;
334 						}
335 
336 						infoTexMem[a + COLOR_G] = (extraTexPal[extraTex[y_hmapx + x]*3 + 1]);
337 						infoTexMem[a + COLOR_B] = (extraTexPal[extraTex[y_hmapx + x]*3 + 2]);
338 						infoTexMem[a + COLOR_A] = 255;
339 					}
340 				}
341 
342 				break;
343 			}
344 
345 			case drawHeight: {
346 				const unsigned char* extraTexPal = heightLinePal->GetData();
347 
348 				// NOTE:
349 				//   PBO/ExtraTexture resolution is always gs->pwr2mapx * gs->pwr2mapy
350 				//   (we don't use it fully) while the CORNER heightmap has dimensions
351 				//   (gs->mapx + 1) * (gs->mapy + 1). In case POT(gs->mapx) == gs->mapx
352 				//   we would therefore get a buffer overrun in our PBO when iterating
353 				//   over column (gs->mapx + 1) or row (gs->mapy + 1) so we select the
354 				//   easiest solution and just skip those squares.
355 				const float* heightMap = readMap->GetCornerHeightMapUnsynced();
356 
357 				for (int y = starty; y < endy; ++y) {
358 					const int y_pwr2mapx = y * gs->pwr2mapx;
359 					const int y_mapx     = y * gs->mapxp1;
360 
361 					for (int x = 0; x < gs->mapx; ++x) {
362 						const float height = heightMap[y_mapx + x];
363 						const unsigned int value = (((unsigned int)(height * 8.0f)) % 255) * 3;
364 						const int i = (y_pwr2mapx + x) * 4 - offset;
365 
366 						infoTexMem[i + COLOR_R] = 64 + (extraTexPal[value    ] >> 1);
367 						infoTexMem[i + COLOR_G] = 64 + (extraTexPal[value + 1] >> 1);
368 						infoTexMem[i + COLOR_B] = 64 + (extraTexPal[value + 2] >> 1);
369 						infoTexMem[i + COLOR_A] = 255;
370 					}
371 				}
372 
373 				break;
374 			}
375 
376 			case drawLos: {
377 				const unsigned short* myLos         = &losHandler->losMaps[gu->myAllyTeam].front();
378 				const unsigned short* myAirLos      = &losHandler->airLosMaps[gu->myAllyTeam].front();
379 				const unsigned short* myRadar       = &radarHandler->radarMaps[gu->myAllyTeam].front();
380 				const unsigned short* myJammer      = &radarHandler->jammerMaps[gu->myAllyTeam].front();
381 			#ifdef RADARHANDLER_SONAR_JAMMER_MAPS
382 				const unsigned short* mySonar       = &radarHandler->sonarMaps[gu->myAllyTeam].front();
383 				const unsigned short* mySonarJammer = &radarHandler->sonarJammerMaps[gu->myAllyTeam].front();
384 			#endif
385 
386 				const int lowRes = highResInfoTexWanted ? 0 : -1;
387 				const int endx = highResInfoTexWanted ? gs->mapx : gs->hmapx;
388 				const int pwr2mapx = gs->pwr2mapx >> (-lowRes);
389 				const int losSizeX = losHandler->losSizeX;
390 				const int losSizeY = losHandler->losSizeY;
391 				const int airSizeX = losHandler->airSizeX;
392 				const int airSizeY = losHandler->airSizeY;
393 				const int losMipLevel = losHandler->losMipLevel + lowRes;
394 				const int airMipLevel = losHandler->airMipLevel + lowRes;
395 
396 				if (drawRadarAndJammer) {
397 					const int rxsize = radarHandler->xsize;
398 					const int rzsize = radarHandler->zsize;
399 
400 					for (int y = starty; y < endy; ++y) {
401 						for (int x = 0; x < endx; ++x) {
402 							int totalLos = 255;
403 
404 							if (!gs->globalLOS[gu->myAllyTeam]) {
405 								const int inLos = InterpolateLos(myLos,    losSizeX, losSizeY, losMipLevel, 128, x, y);
406 								const int inAir = InterpolateLos(myAirLos, airSizeX, airSizeY, airMipLevel, 128, x, y);
407 								totalLos = inLos + inAir;
408 							}
409 #ifdef RADARHANDLER_SONAR_JAMMER_MAPS
410 							const bool useRadar = (CGround::GetHeightReal(xPos, zPos, false) >= 0.0f);
411 							const unsigned short* radarMap  = useRadar ? myRadar  : mySonar;
412 							const unsigned short* jammerMap = useRadar ? myJammer : mySonarJammer;
413 #else
414 							const unsigned short* radarMap  = myRadar;
415 							const unsigned short* jammerMap = myJammer;
416 #endif
417 							const int inRadar = InterpolateLos(radarMap,  rxsize, rzsize, 3 + lowRes, 255, x, y);
418 							const int inJam   = InterpolateLos(jammerMap, rxsize, rzsize, 3 + lowRes, 255, x, y);
419 
420 							const int a = ((y * pwr2mapx) + x) * 4 - offset;
421 
422 							for (int c = 0; c < 3; c++) {
423 								int val = alwaysColor[c] * 255;
424 								val += (jamColor[c]   * inJam);
425 								val += (losColor[c]   * totalLos);
426 								val += (radarColor[c] * inRadar);
427 								infoTexMem[a + (2 - c)] = (val / losColorScale);
428 							}
429 
430 							infoTexMem[a + COLOR_A] = 255;
431 						}
432 					}
433 				} else {
434 					for (int y = starty; y < endy; ++y) {
435 						const int y_pwr2mapx = y * pwr2mapx;
436 						for (int x = 0; x < endx; ++x) {
437 							const int inLos = InterpolateLos(myLos,    losSizeX, losSizeY, losMipLevel, 32, x, y);
438 							const int inAir = InterpolateLos(myAirLos, airSizeX, airSizeY, airMipLevel, 32, x, y);
439 							const int value = 64 + inLos + inAir;
440 							const int a = (y_pwr2mapx + x) * 4 - offset;
441 
442 							infoTexMem[a + COLOR_R] = value;
443 							infoTexMem[a + COLOR_G] = value;
444 							infoTexMem[a + COLOR_B] = value;
445 							infoTexMem[a + COLOR_A] = 255;
446 						}
447 					}
448 				}
449 				break;
450 			}
451 
452 			case drawNormal: {
453 				assert(false);
454 			} break;
455 		}
456 
457 		infoTexPBO.UnmapBuffer();
458 		/*
459 		glBindTexture(GL_TEXTURE_2D, infoTextureIDs[texDrawMode]);
460 
461 		if (highResInfoTex) {
462 			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, starty, gs->pwr2mapx, (endy-starty), GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr(offset));
463 		} else {
464 			glTexSubImage2D(GL_TEXTURE_2D, 0, 0, starty, gs->pwr2mapx>>1, (endy-starty), GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr(offset));
465 		}
466 		*/
467 
468 		infoTexPBO.Unbind();
469 	}
470 
471 
472 	if (updateTextureState == extraTextureUpdateRate) {
473 		// entire texture has been updated, now check if it
474 		// needs to be regenerated as well (eg. if switching
475 		// between textures of different resolutions)
476 		//
477 		if (infoTextureIDs[texDrawMode] != 0 && highResInfoTexWanted != highResInfoTex) {
478 			glDeleteTextures(1, &infoTextureIDs[texDrawMode]);
479 			infoTextureIDs[texDrawMode] = 0;
480 		}
481 
482 		if (infoTextureIDs[texDrawMode] == 0) {
483 			// generate new texture
484 			infoTexPBO.Bind();
485 			glGenTextures(1, &infoTextureIDs[texDrawMode]);
486 			glBindTexture(GL_TEXTURE_2D, infoTextureIDs[texDrawMode]);
487 
488 			// XXX maybe use GL_RGB5 as internalformat?
489 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
490 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
491 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
492 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
493 
494 			if (highResInfoTexWanted) {
495 				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gs->pwr2mapx, gs->pwr2mapy, 0, GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr());
496 			} else {
497 				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, gs->pwr2mapx>>1, gs->pwr2mapy>>1, 0, GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr());
498 			}
499 
500 			infoTexPBO.Invalidate();
501 			infoTexPBO.Unbind();
502 
503 			highResInfoTex = highResInfoTexWanted;
504 			updateTextureState = 0;
505 			return true;
506 		}
507 
508 		infoTexPBO.Bind();
509 			glBindTexture(GL_TEXTURE_2D, infoTextureIDs[texDrawMode]);
510 
511 			if (highResInfoTex) {
512 				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gs->pwr2mapx, gs->pwr2mapy, GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr());
513 			} else {
514 				glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gs->pwr2mapx>>1, gs->pwr2mapy>>1, GL_BGRA, GL_UNSIGNED_BYTE, infoTexPBO.GetPtr());
515 			}
516 		infoTexPBO.Invalidate();
517 		infoTexPBO.Unbind();
518 
519 		updateTextureState = 0;
520 		return true;
521 	}
522 
523 	updateTextureState++;
524 	return false;
525 }
526 
527 
528 
GetInfoTexSize() const529 int2 CBaseGroundDrawer::GetInfoTexSize() const
530 {
531 	if (highResInfoTex)
532 		return (int2(gs->pwr2mapx, gs->pwr2mapy));
533 
534 	return (int2(gs->pwr2mapx >> 1, gs->pwr2mapy >> 1));
535 }
536 
537 
UpdateCamRestraints(CCamera * cam)538 void CBaseGroundDrawer::UpdateCamRestraints(CCamera* cam)
539 {
540 	// add restraints for camera sides
541 	cam->GetFrustumSides(readMap->GetCurrMinHeight() - 100.0f, readMap->GetCurrMaxHeight() + 30.0f,  SQUARE_SIZE);
542 
543 	// CAMERA DISTANCE IS ALREADY CHECKED IN CGroundDrawer::GridVisibility()!
544 /*
545 	// add restraint for maximum view distance (use flat z-dir as side)
546 	// this is supposed to prevent (far) terrain from first being drawn
547 	// and then immediately z-clipped away
548 	const float3& camDir3D = cam->forward;
549 
550 	// prevent colinearity in top-down view
551 	if (math::fabs(camDir3D.dot(UpVector)) < 0.95f) {
552 		float3 camDir2D  = float3(camDir3D.x, 0.0f, camDir3D.z).SafeANormalize();
553 		float3 camOffset = camDir2D * globalRendering->viewRange * 1.05f;
554 
555 		// FIXME magic constants
556 		static const float miny = 0.0f;
557 		static const float maxy = 255.0f / 3.5f;
558 		cam->GetFrustumSide(camDir2D, camOffset, miny, maxy, SQUARE_SIZE, (camDir3D.y > 0.0f), false);
559 	}
560 */
561 }
562