1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "LegacyMeshDrawer.h"
4 #include "Game/Camera.h"
5 #include "Map/SMF/SMFReadMap.h"
6 #include "Map/SMF/SMFGroundDrawer.h"
7 #include "Rendering/GlobalRendering.h"
8 #include "Rendering/ProjectileDrawer.h"
9 #include "Rendering/GL/myGL.h"
10 #include "Rendering/GL/VertexArray.h"
11 #include "System/Config/ConfigHandler.h"
12 #include "System/FastMath.h"
13 #include "System/myMath.h"
14 #include "System/Util.h"
15
16 #define CLAMP(i) Clamp((i), 0, smfReadMap->maxHeightMapIdx)
17
CLegacyMeshDrawer(CSMFReadMap * rm,CSMFGroundDrawer * gd)18 CLegacyMeshDrawer::CLegacyMeshDrawer(CSMFReadMap* rm, CSMFGroundDrawer* gd)
19 : smfReadMap(rm)
20 , smfGroundDrawer(gd)
21 , viewRadius(4)
22 , neededLod(4)
23 //, waterDrawn(false)
24 {
25 }
26
~CLegacyMeshDrawer()27 CLegacyMeshDrawer::~CLegacyMeshDrawer()
28 {
29 }
30
31
32
33
DrawVertexAQ(CVertexArray * ma,int x,int y)34 void CLegacyMeshDrawer::DrawVertexAQ(CVertexArray* ma, int x, int y)
35 {
36 // don't send the normals as vertex attributes
37 // (DLOD'ed triangles mess with interpolation)
38 // const float3& n = readMap->vertexNormals[(y * smfReadMap->heightMapSizeX) + x];
39
40 DrawVertexAQ(ma, x, y, GetVisibleVertexHeight(y * smfReadMap->heightMapSizeX + x));
41 }
42
DrawVertexAQ(CVertexArray * ma,int x,int y,float height)43 void CLegacyMeshDrawer::DrawVertexAQ(CVertexArray* ma, int x, int y, float height)
44 {
45 //if (waterDrawn && height < 0.0f) {
46 // height *= 2.0f;
47 //}
48
49 ma->AddVertexQ0(x * SQUARE_SIZE, height, y * SQUARE_SIZE);
50 }
51
52
DrawGroundVertexArrayQ(CVertexArray * & ma)53 void CLegacyMeshDrawer::DrawGroundVertexArrayQ(CVertexArray*& ma)
54 {
55 ma->DrawArray0(GL_TRIANGLE_STRIP);
56 ma = GetVertexArray();
57 }
58
59
60
BigTexSquareRowVisible(const CCamera * cam,int bty) const61 bool CLegacyMeshDrawer::BigTexSquareRowVisible(const CCamera* cam, int bty) const
62 {
63 const int minz = bty * smfReadMap->bigTexSize;
64 const int maxz = minz + smfReadMap->bigTexSize;
65 const float miny = readMap->GetCurrMinHeight();
66 const float maxy = math::fabs(cam->GetPos().y);
67
68 const float3 mins( 0, miny, minz);
69 const float3 maxs(smfReadMap->mapSizeX, maxy, maxz);
70
71 return (cam->InView(mins, maxs));
72 }
73
74
75
FindRange(const CCamera * cam,int & xs,int & xe,int y,int lod)76 void CLegacyMeshDrawer::FindRange(const CCamera* cam, int& xs, int& xe, int y, int lod)
77 {
78 int xt0, xt1;
79
80 const std::vector<CCamera::FrustumLine> negSides = cam->GetNegFrustumSides();
81 const std::vector<CCamera::FrustumLine> posSides = cam->GetPosFrustumSides();
82
83 std::vector<CCamera::FrustumLine>::const_iterator fli;
84
85 for (fli = negSides.begin(); fli != negSides.end(); ++fli) {
86 const float xtf = fli->base + fli->dir * y;
87 xt0 = (int)xtf;
88 xt1 = (int)(xtf + fli->dir * lod);
89
90 if (xt0 > xt1)
91 xt0 = xt1;
92
93 xt0 = xt0 / lod * lod - lod;
94
95 if (xt0 > xs)
96 xs = xt0;
97 }
98 for (fli = posSides.begin(); fli != posSides.end(); ++fli) {
99 const float xtf = fli->base + fli->dir * y;
100 xt0 = (int)xtf;
101 xt1 = (int)(xtf + fli->dir * lod);
102
103 if (xt0 < xt1)
104 xt0 = xt1;
105
106 xt0 = xt0 / lod * lod + lod;
107
108 if (xt0 < xe)
109 xe = xt0;
110 }
111 }
112
113
114
DoDrawGroundRow(const CCamera * cam,int bty)115 void CLegacyMeshDrawer::DoDrawGroundRow(const CCamera* cam, int bty)
116 {
117 if (!BigTexSquareRowVisible(cam, bty)) {
118 //! skip this entire row of squares if we can't see it
119 return;
120 }
121
122 CVertexArray* ma = GetVertexArray();
123
124 bool inStrip = false;
125 float x0, x1;
126 int x,y;
127 int sx = 0;
128 int ex = smfReadMap->numBigTexX;
129
130 //! only process the necessary big squares in the x direction
131 const int bigSquareSizeY = bty * smfReadMap->bigSquareSize;
132
133 const std::vector<CCamera::FrustumLine> negSides = cam->GetNegFrustumSides();
134 const std::vector<CCamera::FrustumLine> posSides = cam->GetPosFrustumSides();
135
136 std::vector<CCamera::FrustumLine>::const_iterator fli;
137
138 for (fli = negSides.begin(); fli != negSides.end(); ++fli) {
139 x0 = fli->base + fli->dir * bigSquareSizeY;
140 x1 = x0 + fli->dir * smfReadMap->bigSquareSize;
141
142 if (x0 > x1)
143 x0 = x1;
144
145 x0 /= smfReadMap->bigSquareSize;
146
147 if (x0 > sx)
148 sx = (int) x0;
149 }
150 for (fli = posSides.begin(); fli != posSides.end(); ++fli) {
151 x0 = fli->base + fli->dir * bigSquareSizeY + smfReadMap->bigSquareSize;
152 x1 = x0 + fli->dir * smfReadMap->bigSquareSize;
153
154 if (x0 < x1)
155 x0 = x1;
156
157 x0 /= smfReadMap->bigSquareSize;
158
159 if (x0 < ex)
160 ex = (int) x0;
161 }
162
163 if (sx > ex)
164 return;
165
166 const float cx2 = cam2->GetPos().x / SQUARE_SIZE;
167 const float cy2 = cam2->GetPos().z / SQUARE_SIZE;
168
169 for (int btx = sx; btx < ex; ++btx) {
170 ma->Initialize();
171
172 for (int lod = 1; lod < neededLod; lod <<= 1) {
173 float oldcamxpart = 0.0f;
174 float oldcamypart = 0.0f;
175
176 const int hlod = lod >> 1;
177 const int dlod = lod << 1;
178
179 int cx = cx2;
180 int cy = cy2;
181
182 if (lod > 1) {
183 int cxo = (cx / hlod) * hlod;
184 int cyo = (cy / hlod) * hlod;
185 float cx2o = (cxo / lod) * lod;
186 float cy2o = (cyo / lod) * lod;
187 oldcamxpart = (cx2 - cx2o) / lod;
188 oldcamypart = (cy2 - cy2o) / lod;
189 }
190
191 cx = (cx / lod) * lod;
192 cy = (cy / lod) * lod;
193
194 const int ysquaremod = (cy % dlod) / lod;
195 const int xsquaremod = (cx % dlod) / lod;
196
197 const float camxpart = (cx2 - ((cx / dlod) * dlod)) / dlod;
198 const float camypart = (cy2 - ((cy / dlod) * dlod)) / dlod;
199
200 const float mcxp = 1.0f - camxpart, mcyp = 1.0f - camypart;
201 const float hcxp = 0.5f * camxpart, hcyp = 0.5f * camypart;
202 const float hmcxp = 0.5f * mcxp, hmcyp = 0.5f * mcyp;
203
204 const float mocxp = 1.0f - oldcamxpart, mocyp = 1.0f - oldcamypart;
205 const float hocxp = 0.5f * oldcamxpart, hocyp = 0.5f * oldcamypart;
206 const float hmocxp = 0.5f * mocxp, hmocyp = 0.5f * mocyp;
207
208 const int minty = bty * smfReadMap->bigSquareSize, maxty = minty + smfReadMap->bigSquareSize;
209 const int mintx = btx * smfReadMap->bigSquareSize, maxtx = mintx + smfReadMap->bigSquareSize;
210
211 const int minly = cy + (-viewRadius + 3 - ysquaremod) * lod;
212 const int maxly = cy + ( viewRadius - 1 - ysquaremod) * lod;
213 const int minlx = cx + (-viewRadius + 3 - xsquaremod) * lod;
214 const int maxlx = cx + ( viewRadius - 1 - xsquaremod) * lod;
215
216 const int xstart = std::max(minlx, mintx), xend = std::min(maxlx, maxtx);
217 const int ystart = std::max(minly, minty), yend = std::min(maxly, maxty);
218
219 const int vrhlod = viewRadius * hlod;
220
221 for (y = ystart; y < yend; y += lod) {
222 int xs = xstart;
223 int xe = xend;
224
225 FindRange(cam2, /*inout*/ xs, /*inout*/ xe, y, lod);
226
227 // If FindRange modifies (xs, xe) to a (less then) empty range,
228 // continue to the next row.
229 // If we'd continue, nloop (below) would become negative and we'd
230 // allocate a vertex array with negative size. (mantis #1415)
231 if (xe < xs) continue;
232
233 int ylod = y + lod;
234 int yhlod = y + hlod;
235 int nloop = (xe - xs) / lod + 1;
236
237 ma->EnlargeArrays(52 * nloop);
238
239 int yhdx = y * smfReadMap->heightMapSizeX;
240 int ylhdx = yhdx + lod * smfReadMap->heightMapSizeX;
241 int yhhdx = yhdx + hlod * smfReadMap->heightMapSizeX;
242
243 for (x = xs; x < xe; x += lod) {
244 int xlod = x + lod;
245 int xhlod = x + hlod;
246 //! info: all triangle quads start in the top left corner
247 if ((lod == 1) ||
248 (x > cx + vrhlod) || (x < cx - vrhlod) ||
249 (y > cy + vrhlod) || (y < cy - vrhlod)) {
250 //! normal terrain (all vertices in one LOD)
251 if (!inStrip) {
252 DrawVertexAQ(ma, x, y);
253 DrawVertexAQ(ma, x, ylod);
254 inStrip = true;
255 }
256
257 DrawVertexAQ(ma, xlod, y);
258 DrawVertexAQ(ma, xlod, ylod);
259 } else {
260 //! border between 2 different LODs
261 if ((x >= cx + vrhlod)) {
262 //! lower LOD to the right
263 int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod);
264 int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod);
265 int idx3 = CLAMP(yhhdx + x), idx3HLOD = CLAMP(idx3 + hlod);
266 float h1 = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx2)) * hmocxp + GetVisibleVertexHeight(idx3) * oldcamxpart;
267 float h2 = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx1LOD)) * hmocxp + GetVisibleVertexHeight(idx1HLOD) * oldcamxpart;
268 float h3 = (GetVisibleVertexHeight(idx2) + GetVisibleVertexHeight(idx1LOD)) * hmocxp + GetVisibleVertexHeight(idx3HLOD) * oldcamxpart;
269 float h4 = (GetVisibleVertexHeight(idx2) + GetVisibleVertexHeight(idx2LOD)) * hmocxp + GetVisibleVertexHeight(idx2HLOD) * oldcamxpart;
270
271 if (inStrip) {
272 ma->EndStrip();
273 inStrip = false;
274 }
275
276 DrawVertexAQ(ma, x, y);
277 DrawVertexAQ(ma, x, yhlod, h1);
278 DrawVertexAQ(ma, xhlod, y, h2);
279 DrawVertexAQ(ma, xhlod, yhlod, h3);
280 ma->EndStrip();
281 DrawVertexAQ(ma, x, yhlod, h1);
282 DrawVertexAQ(ma, x, ylod);
283 DrawVertexAQ(ma, xhlod, yhlod, h3);
284 DrawVertexAQ(ma, xhlod, ylod, h4);
285 ma->EndStrip();
286 DrawVertexAQ(ma, xhlod, ylod, h4);
287 DrawVertexAQ(ma, xlod, ylod);
288 DrawVertexAQ(ma, xhlod, yhlod, h3);
289 DrawVertexAQ(ma, xlod, y);
290 DrawVertexAQ(ma, xhlod, y, h2);
291 ma->EndStrip();
292 }
293 else if ((x <= cx - vrhlod)) {
294 //! lower LOD to the left
295 int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod);
296 int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod);
297 int idx3 = CLAMP(yhhdx + x), idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod);
298 float h1 = (GetVisibleVertexHeight(idx1LOD) + GetVisibleVertexHeight(idx2LOD)) * hocxp + GetVisibleVertexHeight(idx3LOD ) * mocxp;
299 float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx1LOD)) * hocxp + GetVisibleVertexHeight(idx1HLOD) * mocxp;
300 float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hocxp + GetVisibleVertexHeight(idx3HLOD) * mocxp;
301 float h4 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx2LOD)) * hocxp + GetVisibleVertexHeight(idx2HLOD) * mocxp;
302
303 if (inStrip) {
304 ma->EndStrip();
305 inStrip = false;
306 }
307
308 DrawVertexAQ(ma, xlod, yhlod, h1);
309 DrawVertexAQ(ma, xlod, y);
310 DrawVertexAQ(ma, xhlod, yhlod, h3);
311 DrawVertexAQ(ma, xhlod, y, h2);
312 ma->EndStrip();
313 DrawVertexAQ(ma, xlod, ylod);
314 DrawVertexAQ(ma, xlod, yhlod, h1);
315 DrawVertexAQ(ma, xhlod, ylod, h4);
316 DrawVertexAQ(ma, xhlod, yhlod, h3);
317 ma->EndStrip();
318 DrawVertexAQ(ma, xhlod, y, h2);
319 DrawVertexAQ(ma, x, y);
320 DrawVertexAQ(ma, xhlod, yhlod, h3);
321 DrawVertexAQ(ma, x, ylod);
322 DrawVertexAQ(ma, xhlod, ylod, h4);
323 ma->EndStrip();
324 }
325
326 if ((y >= cy + vrhlod)) {
327 //! lower LOD above
328 int idx1 = yhdx + x, idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod);
329 int idx2 = ylhdx + x, idx2LOD = CLAMP(idx2 + lod);
330 int idx3 = yhhdx + x, idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod);
331 float h1 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx1HLOD) * oldcamypart;
332 float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx2 )) * hmocyp + GetVisibleVertexHeight(idx3 ) * oldcamypart;
333 float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx3HLOD) * oldcamypart;
334 float h4 = (GetVisibleVertexHeight(idx2LOD) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx3LOD ) * oldcamypart;
335
336 if (inStrip) {
337 ma->EndStrip();
338 inStrip = false;
339 }
340
341 DrawVertexAQ(ma, x, y);
342 DrawVertexAQ(ma, x, yhlod, h2);
343 DrawVertexAQ(ma, xhlod, y, h1);
344 DrawVertexAQ(ma, xhlod, yhlod, h3);
345 DrawVertexAQ(ma, xlod, y);
346 DrawVertexAQ(ma, xlod, yhlod, h4);
347 ma->EndStrip();
348 DrawVertexAQ(ma, x, yhlod, h2);
349 DrawVertexAQ(ma, x, ylod);
350 DrawVertexAQ(ma, xhlod, yhlod, h3);
351 DrawVertexAQ(ma, xlod, ylod);
352 DrawVertexAQ(ma, xlod, yhlod, h4);
353 ma->EndStrip();
354 }
355 else if ((y <= cy - vrhlod)) {
356 //! lower LOD beneath
357 int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod);
358 int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod);
359 int idx3 = CLAMP(yhhdx + x), idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod);
360 float h1 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx2LOD)) * hocyp + GetVisibleVertexHeight(idx2HLOD) * mocyp;
361 float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx2 )) * hocyp + GetVisibleVertexHeight(idx3 ) * mocyp;
362 float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hocyp + GetVisibleVertexHeight(idx3HLOD) * mocyp;
363 float h4 = (GetVisibleVertexHeight(idx2LOD) + GetVisibleVertexHeight(idx1LOD)) * hocyp + GetVisibleVertexHeight(idx3LOD ) * mocyp;
364
365 if (inStrip) {
366 ma->EndStrip();
367 inStrip = false;
368 }
369
370 DrawVertexAQ(ma, x, yhlod, h2);
371 DrawVertexAQ(ma, x, ylod);
372 DrawVertexAQ(ma, xhlod, yhlod, h3);
373 DrawVertexAQ(ma, xhlod, ylod, h1);
374 DrawVertexAQ(ma, xlod, yhlod, h4);
375 DrawVertexAQ(ma, xlod, ylod);
376 ma->EndStrip();
377 DrawVertexAQ(ma, xlod, yhlod, h4);
378 DrawVertexAQ(ma, xlod, y);
379 DrawVertexAQ(ma, xhlod, yhlod, h3);
380 DrawVertexAQ(ma, x, y);
381 DrawVertexAQ(ma, x, yhlod, h2);
382 ma->EndStrip();
383 }
384 }
385 }
386
387 if (inStrip) {
388 ma->EndStrip();
389 inStrip = false;
390 }
391 } //for (y = ystart; y < yend; y += lod)
392
393 const int yst = std::max(ystart - lod, minty);
394 const int yed = std::min(yend + lod, maxty);
395 int nloop = (yed - yst) / lod + 1;
396
397 if (nloop > 0)
398 ma->EnlargeArrays(8 * nloop);
399
400 //! rita yttre begr?snings yta mot n?ta lod
401 if (maxlx < maxtx && maxlx >= mintx) {
402 x = maxlx;
403 int xlod = x + lod;
404 for (y = yst; y < yed; y += lod) {
405 DrawVertexAQ(ma, x, y);
406 DrawVertexAQ(ma, x, y + lod);
407
408 if (y % dlod) {
409 const int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x), idx1LOD = CLAMP(idx1 + lod);
410 const int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x), idx2LOD = CLAMP(idx2 + lod);
411 const int idx3 = CLAMP((y - lod) * smfReadMap->heightMapSizeX + x), idx3LOD = CLAMP(idx3 + lod);
412 const float h = (GetVisibleVertexHeight(idx3LOD) + GetVisibleVertexHeight(idx2LOD)) * hmcxp + GetVisibleVertexHeight(idx1LOD) * camxpart;
413 DrawVertexAQ(ma, xlod, y, h);
414 DrawVertexAQ(ma, xlod, y + lod);
415 } else {
416 const int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x), idx1LOD = CLAMP(idx1 + lod);
417 const int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x), idx2LOD = CLAMP(idx2 + lod);
418 const int idx3 = CLAMP((y + dlod) * smfReadMap->heightMapSizeX + x), idx3LOD = CLAMP(idx3 + lod);
419 const float h = (GetVisibleVertexHeight(idx1LOD) + GetVisibleVertexHeight(idx3LOD)) * hmcxp + GetVisibleVertexHeight(idx2LOD) * camxpart;
420 DrawVertexAQ(ma, xlod, y);
421 DrawVertexAQ(ma, xlod, y + lod, h);
422 }
423 ma->EndStrip();
424 }
425 }
426
427 if (minlx > mintx && minlx < maxtx) {
428 x = minlx - lod;
429 int xlod = x + lod;
430 for (y = yst; y < yed; y += lod) {
431 if (y % dlod) {
432 int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x);
433 int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x);
434 int idx3 = CLAMP((y - lod) * smfReadMap->heightMapSizeX + x);
435 float h = (GetVisibleVertexHeight(idx3) + GetVisibleVertexHeight(idx2)) * hcxp + GetVisibleVertexHeight(idx1) * mcxp;
436 DrawVertexAQ(ma, x, y, h);
437 DrawVertexAQ(ma, x, y + lod);
438 } else {
439 int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x);
440 int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x);
441 int idx3 = CLAMP((y + dlod) * smfReadMap->heightMapSizeX + x);
442 float h = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx3)) * hcxp + GetVisibleVertexHeight(idx2) * mcxp;
443 DrawVertexAQ(ma, x, y);
444 DrawVertexAQ(ma, x, y + lod, h);
445 }
446 DrawVertexAQ(ma, xlod, y);
447 DrawVertexAQ(ma, xlod, y + lod);
448 ma->EndStrip();
449 }
450 }
451
452 if (maxly < maxty && maxly > minty) {
453 y = maxly;
454 int xs = std::max(xstart - lod, mintx);
455 int xe = std::min(xend + lod, maxtx);
456 FindRange(cam2, xs, xe, y, lod);
457
458 if (xs < xe) {
459 x = xs;
460 int ylod = y + lod;
461 int nloop = (xe - xs) / lod + 2; //! one extra for if statment
462 int ylhdx = (y + lod) * smfReadMap->heightMapSizeX;
463
464 ma->EnlargeArrays(2 * nloop);
465
466 if (x % dlod) {
467 int idx2 = CLAMP(ylhdx + x), idx2PLOD = CLAMP(idx2 + lod), idx2MLOD = CLAMP(idx2 - lod);
468 float h = (GetVisibleVertexHeight(idx2MLOD) + GetVisibleVertexHeight(idx2PLOD)) * hmcyp + GetVisibleVertexHeight(idx2) * camypart;
469 DrawVertexAQ(ma, x, y);
470 DrawVertexAQ(ma, x, ylod, h);
471 } else {
472 DrawVertexAQ(ma, x, y);
473 DrawVertexAQ(ma, x, ylod);
474 }
475 for (x = xs; x < xe; x += lod) {
476 if (x % dlod) {
477 DrawVertexAQ(ma, x + lod, y);
478 DrawVertexAQ(ma, x + lod, ylod);
479 } else {
480 int idx2 = CLAMP(ylhdx + x), idx2PLOD = CLAMP(idx2 + lod), idx2PLOD2 = CLAMP(idx2 + dlod);
481 float h = (GetVisibleVertexHeight(idx2PLOD2) + GetVisibleVertexHeight(idx2)) * hmcyp + GetVisibleVertexHeight(idx2PLOD) * camypart;
482 DrawVertexAQ(ma, x + lod, y);
483 DrawVertexAQ(ma, x + lod, ylod, h);
484 }
485 }
486 ma->EndStrip();
487 }
488 }
489
490 if (minly > minty && minly < maxty) {
491 y = minly - lod;
492 int xs = std::max(xstart - lod, mintx);
493 int xe = std::min(xend + lod, maxtx);
494 FindRange(cam2, xs, xe, y, lod);
495
496 if (xs < xe) {
497 x = xs;
498 int ylod = y + lod;
499 int yhdx = y * smfReadMap->heightMapSizeX;
500 int nloop = (xe - xs) / lod + 2; //! one extra for if statment
501
502 ma->EnlargeArrays(2 * nloop);
503
504 if (x % dlod) {
505 int idx1 = CLAMP(yhdx + x), idx1PLOD = CLAMP(idx1 + lod), idx1MLOD = CLAMP(idx1 - lod);
506 float h = (GetVisibleVertexHeight(idx1MLOD) + GetVisibleVertexHeight(idx1PLOD)) * hcyp + GetVisibleVertexHeight(idx1) * mcyp;
507 DrawVertexAQ(ma, x, y, h);
508 DrawVertexAQ(ma, x, ylod);
509 } else {
510 DrawVertexAQ(ma, x, y);
511 DrawVertexAQ(ma, x, ylod);
512 }
513
514 for (x = xs; x < xe; x+= lod) {
515 if (x % dlod) {
516 DrawVertexAQ(ma, x + lod, y);
517 DrawVertexAQ(ma, x + lod, ylod);
518 } else {
519 int idx1 = CLAMP(yhdx + x), idx1PLOD = CLAMP(idx1 + lod), idx1PLOD2 = CLAMP(idx1 + dlod);
520 float h = (GetVisibleVertexHeight(idx1PLOD2) + GetVisibleVertexHeight(idx1)) * hcyp + GetVisibleVertexHeight(idx1PLOD) * mcyp;
521 DrawVertexAQ(ma, x + lod, y, h);
522 DrawVertexAQ(ma, x + lod, ylod);
523 }
524 }
525 ma->EndStrip();
526 }
527 }
528
529 } //for (int lod = 1; lod < neededLod; lod <<= 1)
530
531 smfGroundDrawer->SetupBigSquare(btx, bty);
532 DrawGroundVertexArrayQ(ma);
533 }
534 }
535
536
UpdateLODParams(const DrawPass::e & drawPass)537 void CLegacyMeshDrawer::UpdateLODParams(const DrawPass::e& drawPass)
538 {
539 // Get current ground detail (draw pass dependent)
540 viewRadius = smfGroundDrawer->GetGroundDetail(drawPass);
541
542 // Take FOV into account
543 viewRadius = int(viewRadius * fastmath::apxsqrt(45.0f / camera->GetFov()));
544
545 // Clamp it to mapsize dependent minimum, else we get holes in the terrain
546 viewRadius = std::max(std::max(smfReadMap->numBigTexY, smfReadMap->numBigTexX) + 1, viewRadius);
547
548 // we need a multiple of 2
549 viewRadius += (viewRadius & 1);
550
551 // Compute count of LODs needed/visible
552 neededLod = std::max(1, int((globalRendering->viewRange * 0.125f) / viewRadius) << 1);
553 neededLod = std::min(neededLod, std::min(gs->mapx, gs->mapy));
554 }
555
556
DrawMesh(const DrawPass::e & drawPass)557 void CLegacyMeshDrawer::DrawMesh(const DrawPass::e& drawPass)
558 {
559 if (drawPass == DrawPass::Shadow) {
560 DrawShadowMesh();
561 return;
562 }
563
564 UpdateLODParams(drawPass);
565
566 //waterDrawn = (drawPass == DrawPass::WaterReflection);
567
568 { // profiler scope
569 {
570 int camBty = math::floor(cam2->GetPos().z / (smfReadMap->bigSquareSize * SQUARE_SIZE));
571 camBty = std::max(0, std::min(smfReadMap->numBigTexY - 1, camBty));
572
573 //! try to render in "front to back" (so start with the camera nearest BigGroundLines)
574 for (int bty = camBty; bty >= 0; --bty) {
575 DoDrawGroundRow(cam2, bty);
576 }
577 for (int bty = camBty + 1; bty < smfReadMap->numBigTexY; ++bty) {
578 DoDrawGroundRow(cam2, bty);
579 }
580 }
581 }
582 }
583
584
DoDrawGroundShadowLOD(int nlod)585 void CLegacyMeshDrawer::DoDrawGroundShadowLOD(int nlod) {
586 CVertexArray* ma = GetVertexArray();
587 ma->Initialize();
588
589 bool inStrip = false;
590 int x,y;
591 int lod = 1 << nlod;
592
593 float cx2 = camera->GetPos().x / SQUARE_SIZE;
594 float cy2 = camera->GetPos().z / SQUARE_SIZE;
595
596 float oldcamxpart = 0.0f;
597 float oldcamypart = 0.0f;
598
599 int hlod = lod >> 1;
600 int dlod = lod << 1;
601
602 int cx = (int)cx2;
603 int cy = (int)cy2;
604 if (lod > 1) {
605 int cxo = (cx / hlod) * hlod;
606 int cyo = (cy / hlod) * hlod;
607 float cx2o = (cxo / lod) * lod;
608 float cy2o = (cyo / lod) * lod;
609 oldcamxpart = (cx2 - cx2o) / lod;
610 oldcamypart = (cy2 - cy2o) / lod;
611 }
612
613 cx = (cx / lod) * lod;
614 cy = (cy / lod) * lod;
615 const int ysquaremod = (cy % dlod) / lod;
616 const int xsquaremod = (cx % dlod) / lod;
617
618 const float camxpart = (cx2 - (cx / dlod) * dlod) / dlod;
619 const float camypart = (cy2 - (cy / dlod) * dlod) / dlod;
620
621 const int minty = 0, maxty = gs->mapy;
622 const int mintx = 0, maxtx = gs->mapx;
623
624 const int minly = cy + (-viewRadius + 3 - ysquaremod) * lod, maxly = cy + ( viewRadius - 1 - ysquaremod) * lod;
625 const int minlx = cx + (-viewRadius + 3 - xsquaremod) * lod, maxlx = cx + ( viewRadius - 1 - xsquaremod) * lod;
626
627 const int xstart = std::max(minlx, mintx), xend = std::min(maxlx, maxtx);
628 const int ystart = std::max(minly, minty), yend = std::min(maxly, maxty);
629
630 const int lhdx = lod * smfReadMap->heightMapSizeX;
631 const int hhdx = hlod * smfReadMap->heightMapSizeX;
632 const int dhdx = dlod * smfReadMap->heightMapSizeX;
633
634 const float mcxp = 1.0f - camxpart, mcyp = 1.0f - camypart;
635 const float hcxp = 0.5f * camxpart, hcyp = 0.5f * camypart;
636 const float hmcxp = 0.5f * mcxp, hmcyp = 0.5f * mcyp;
637
638 const float mocxp = 1.0f - oldcamxpart, mocyp = 1.0f - oldcamypart;
639 const float hocxp = 0.5f * oldcamxpart, hocyp = 0.5f * oldcamypart;
640 const float hmocxp = 0.5f * mocxp, hmocyp = 0.5f * mocyp;
641
642 const int vrhlod = viewRadius * hlod;
643
644 for (y = ystart; y < yend; y += lod) {
645 int xs = xstart;
646 int xe = xend;
647
648 if (xe < xs) continue;
649
650 int ylod = y + lod;
651 int yhlod = y + hlod;
652 int ydx = y * smfReadMap->heightMapSizeX;
653 int nloop = (xe - xs) / lod + 1;
654
655 ma->EnlargeArrays(52 * nloop);
656
657 for (x = xs; x < xe; x += lod) {
658 int xlod = x + lod;
659 int xhlod = x + hlod;
660 if ((lod == 1) ||
661 (x > cx + vrhlod) || (x < cx - vrhlod) ||
662 (y > cy + vrhlod) || (y < cy - vrhlod)) {
663 if (!inStrip) {
664 DrawVertexAQ(ma, x, y );
665 DrawVertexAQ(ma, x, ylod);
666 inStrip = true;
667 }
668 DrawVertexAQ(ma, xlod, y );
669 DrawVertexAQ(ma, xlod, ylod);
670 }
671 else { //! inre begr?sning mot f?eg?nde lod
672 int yhdx=ydx+x;
673 int ylhdx=yhdx+lhdx;
674 int yhhdx=yhdx+hhdx;
675
676 if ( x>= cx + vrhlod) {
677 const float h1 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hmocxp + GetVisibleVertexHeight(yhhdx ) * oldcamxpart;
678 const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hmocxp + GetVisibleVertexHeight(yhdx+hlod ) * oldcamxpart;
679 const float h3 = (GetVisibleVertexHeight(ylhdx) + GetVisibleVertexHeight(yhdx+lod )) * hmocxp + GetVisibleVertexHeight(yhhdx+hlod) * oldcamxpart;
680 const float h4 = (GetVisibleVertexHeight(ylhdx) + GetVisibleVertexHeight(ylhdx+lod)) * hmocxp + GetVisibleVertexHeight(ylhdx+hlod) * oldcamxpart;
681
682 if(inStrip){
683 ma->EndStrip();
684 inStrip=false;
685 }
686 DrawVertexAQ(ma, x,y);
687 DrawVertexAQ(ma, x,yhlod,h1);
688 DrawVertexAQ(ma, xhlod,y,h2);
689 DrawVertexAQ(ma, xhlod,yhlod,h3);
690 ma->EndStrip();
691 DrawVertexAQ(ma, x,yhlod,h1);
692 DrawVertexAQ(ma, x,ylod);
693 DrawVertexAQ(ma, xhlod,yhlod,h3);
694 DrawVertexAQ(ma, xhlod,ylod,h4);
695 ma->EndStrip();
696 DrawVertexAQ(ma, xhlod,ylod,h4);
697 DrawVertexAQ(ma, xlod,ylod);
698 DrawVertexAQ(ma, xhlod,yhlod,h3);
699 DrawVertexAQ(ma, xlod,y);
700 DrawVertexAQ(ma, xhlod,y,h2);
701 ma->EndStrip();
702 }
703 if (x <= cx - vrhlod) {
704 const float h1 = (GetVisibleVertexHeight(yhdx+lod) + GetVisibleVertexHeight(ylhdx+lod)) * hocxp + GetVisibleVertexHeight(yhhdx+lod ) * mocxp;
705 const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocxp + GetVisibleVertexHeight(yhdx+hlod ) * mocxp;
706 const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocxp + GetVisibleVertexHeight(yhhdx+hlod) * mocxp;
707 const float h4 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(ylhdx+lod)) * hocxp + GetVisibleVertexHeight(ylhdx+hlod) * mocxp;
708
709 if(inStrip){
710 ma->EndStrip();
711 inStrip=false;
712 }
713 DrawVertexAQ(ma, xlod,yhlod,h1);
714 DrawVertexAQ(ma, xlod,y);
715 DrawVertexAQ(ma, xhlod,yhlod,h3);
716 DrawVertexAQ(ma, xhlod,y,h2);
717 ma->EndStrip();
718 DrawVertexAQ(ma, xlod,ylod);
719 DrawVertexAQ(ma, xlod,yhlod,h1);
720 DrawVertexAQ(ma, xhlod,ylod,h4);
721 DrawVertexAQ(ma, xhlod,yhlod,h3);
722 ma->EndStrip();
723 DrawVertexAQ(ma, xhlod,y,h2);
724 DrawVertexAQ(ma, x,y);
725 DrawVertexAQ(ma, xhlod,yhlod,h3);
726 DrawVertexAQ(ma, x,ylod);
727 DrawVertexAQ(ma, xhlod,ylod,h4);
728 ma->EndStrip();
729 }
730 if (y >= cy + vrhlod) {
731 const float h1 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhdx+hlod ) * oldcamypart;
732 const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hmocyp + GetVisibleVertexHeight(yhhdx ) * oldcamypart;
733 const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhhdx+hlod) * oldcamypart;
734 const float h4 = (GetVisibleVertexHeight(ylhdx+lod) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhhdx+lod ) * oldcamypart;
735
736 if(inStrip){
737 ma->EndStrip();
738 inStrip=false;
739 }
740 DrawVertexAQ(ma, x,y);
741 DrawVertexAQ(ma, x,yhlod,h2);
742 DrawVertexAQ(ma, xhlod,y,h1);
743 DrawVertexAQ(ma, xhlod,yhlod,h3);
744 DrawVertexAQ(ma, xlod,y);
745 DrawVertexAQ(ma, xlod,yhlod,h4);
746 ma->EndStrip();
747 DrawVertexAQ(ma, x,yhlod,h2);
748 DrawVertexAQ(ma, x,ylod);
749 DrawVertexAQ(ma, xhlod,yhlod,h3);
750 DrawVertexAQ(ma, xlod,ylod);
751 DrawVertexAQ(ma, xlod,yhlod,h4);
752 ma->EndStrip();
753 }
754 if (y <= cy - vrhlod) {
755 const float h1 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(ylhdx+lod)) * hocyp + GetVisibleVertexHeight(ylhdx+hlod) * mocyp;
756 const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hocyp + GetVisibleVertexHeight(yhhdx ) * mocyp;
757 const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocyp + GetVisibleVertexHeight(yhhdx+hlod) * mocyp;
758 const float h4 = (GetVisibleVertexHeight(ylhdx+lod) + GetVisibleVertexHeight(yhdx+lod )) * hocyp + GetVisibleVertexHeight(yhhdx+lod ) * mocyp;
759
760 if (inStrip) {
761 ma->EndStrip();
762 inStrip = false;
763 }
764 DrawVertexAQ(ma, x,yhlod,h2);
765 DrawVertexAQ(ma, x,ylod);
766 DrawVertexAQ(ma, xhlod,yhlod,h3);
767 DrawVertexAQ(ma, xhlod,ylod,h1);
768 DrawVertexAQ(ma, xlod,yhlod,h4);
769 DrawVertexAQ(ma, xlod,ylod);
770 ma->EndStrip();
771 DrawVertexAQ(ma, xlod,yhlod,h4);
772 DrawVertexAQ(ma, xlod,y);
773 DrawVertexAQ(ma, xhlod,yhlod,h3);
774 DrawVertexAQ(ma, x,y);
775 DrawVertexAQ(ma, x,yhlod,h2);
776 ma->EndStrip();
777 }
778 }
779 }
780 if (inStrip) {
781 ma->EndStrip();
782 inStrip=false;
783 }
784 }
785
786 int yst = std::max(ystart - lod, minty);
787 int yed = std::min(yend + lod, maxty);
788 int nloop = (yed - yst) / lod + 1;
789 ma->EnlargeArrays(8 * nloop);
790
791 //!rita yttre begr?snings yta mot n?ta lod
792 if (maxlx < maxtx && maxlx >= mintx) {
793 x = maxlx;
794 const int xlod = x + lod;
795
796 for (y = yst; y < yed; y += lod) {
797 DrawVertexAQ(ma, x, y );
798 DrawVertexAQ(ma, x, y + lod);
799 const int yhdx = y * smfReadMap->heightMapSizeX + x;
800
801 if (y % dlod) {
802 const float h = (GetVisibleVertexHeight(yhdx - lhdx + lod) + GetVisibleVertexHeight(yhdx + lhdx + lod)) * hmcxp + GetVisibleVertexHeight(yhdx+lod) * camxpart;
803 DrawVertexAQ(ma, xlod, y, h);
804 DrawVertexAQ(ma, xlod, y + lod);
805 } else {
806 const float h = (GetVisibleVertexHeight(yhdx+lod) + GetVisibleVertexHeight(yhdx+dhdx+lod)) * hmcxp + GetVisibleVertexHeight(yhdx+lhdx+lod) * camxpart;
807 DrawVertexAQ(ma, xlod,y);
808 DrawVertexAQ(ma, xlod,y+lod,h);
809 }
810 ma->EndStrip();
811 }
812 }
813
814 if (minlx > mintx && minlx < maxtx) {
815 x = minlx - lod;
816 const int xlod = x + lod;
817
818 for(y = yst; y < yed; y += lod) {
819 int yhdx = y * smfReadMap->heightMapSizeX + x;
820 if(y%dlod){
821 const float h = (GetVisibleVertexHeight(yhdx-lhdx) + GetVisibleVertexHeight(yhdx+lhdx)) * hcxp + GetVisibleVertexHeight(yhdx) * mcxp;
822 DrawVertexAQ(ma, x,y,h);
823 DrawVertexAQ(ma, x,y+lod);
824 } else {
825 const float h = (GetVisibleVertexHeight(yhdx) + GetVisibleVertexHeight(yhdx+dhdx)) * hcxp + GetVisibleVertexHeight(yhdx+lhdx) * mcxp;
826 DrawVertexAQ(ma, x,y);
827 DrawVertexAQ(ma, x,y+lod,h);
828 }
829 DrawVertexAQ(ma, xlod,y);
830 DrawVertexAQ(ma, xlod,y+lod);
831 ma->EndStrip();
832 }
833 }
834 if (maxly < maxty && maxly > minty) {
835 y = maxly;
836 const int xs = std::max(xstart -lod, mintx);
837 const int xe = std::min(xend + lod, maxtx);
838
839 if (xs < xe) {
840 x = xs;
841 const int ylod = y + lod;
842 const int ydx = y * smfReadMap->heightMapSizeX;
843 const int nloop = (xe - xs) / lod + 2; //! two extra for if statment
844
845 ma->EnlargeArrays(2 * nloop);
846
847 if (x % dlod) {
848 const int ylhdx = ydx + x + lhdx;
849 const float h = (GetVisibleVertexHeight(ylhdx-lod) + GetVisibleVertexHeight(ylhdx+lod)) * hmcyp + GetVisibleVertexHeight(ylhdx) * camypart;
850 DrawVertexAQ(ma, x, y);
851 DrawVertexAQ(ma, x, ylod, h);
852 } else {
853 DrawVertexAQ(ma, x, y);
854 DrawVertexAQ(ma, x, ylod);
855 }
856
857 for (x = xs; x < xe; x += lod) {
858 if (x % dlod) {
859 DrawVertexAQ(ma, x + lod, y);
860 DrawVertexAQ(ma, x + lod, ylod);
861 } else {
862 DrawVertexAQ(ma, x+lod,y);
863 const int ylhdx = ydx + x + lhdx;
864 const float h = (GetVisibleVertexHeight(ylhdx+dlod) + GetVisibleVertexHeight(ylhdx)) * hmcyp + GetVisibleVertexHeight(ylhdx+lod) * camypart;
865 DrawVertexAQ(ma, x+lod,ylod,h);
866 }
867 }
868 ma->EndStrip();
869 }
870 }
871 if (minly > minty && minly < maxty) {
872 y = minly - lod;
873 const int xs = std::max(xstart - lod, mintx);
874 const int xe = std::min(xend + lod, maxtx);
875
876 if (xs < xe) {
877 x = xs;
878 const int ylod = y + lod;
879 const int ydx = y * smfReadMap->heightMapSizeX;
880 const int nloop = (xe - xs) / lod + 2; //! two extra for if statment
881
882 ma->EnlargeArrays(2 * nloop);
883
884 if (x % dlod) {
885 const int yhdx = ydx + x;
886 const float h = (GetVisibleVertexHeight(yhdx-lod) + GetVisibleVertexHeight(yhdx + lod)) * hcyp + GetVisibleVertexHeight(yhdx) * mcyp;
887 DrawVertexAQ(ma, x, y, h);
888 DrawVertexAQ(ma, x, ylod);
889 } else {
890 DrawVertexAQ(ma, x, y);
891 DrawVertexAQ(ma, x, ylod);
892 }
893
894 for (x = xs; x < xe; x += lod) {
895 if (x % dlod) {
896 DrawVertexAQ(ma, x + lod, y);
897 DrawVertexAQ(ma, x + lod, ylod);
898 } else {
899 const int yhdx = ydx + x;
900 const float h = (GetVisibleVertexHeight(yhdx+dlod) + GetVisibleVertexHeight(yhdx)) * hcyp + GetVisibleVertexHeight(yhdx+lod) * mcyp;
901 DrawVertexAQ(ma, x + lod, y, h);
902 DrawVertexAQ(ma, x + lod, ylod);
903 }
904 }
905 ma->EndStrip();
906 }
907 }
908 DrawGroundVertexArrayQ(ma);
909 }
910
911
DrawShadowMesh()912 void CLegacyMeshDrawer::DrawShadowMesh()
913 {
914 { // profiler scope
915 const int NUM_LODS = 4;
916 {
917 for (int nlod = 0; nlod < NUM_LODS + 1; ++nlod) {
918 DoDrawGroundShadowLOD(nlod);
919 }
920 }
921 }
922 }
923