1
2 #ifdef HAVE_CONFIG_H
3 #include <etr_config.h>
4 #endif
5
6 #include "quadtree.h"
7 #include "textures.h"
8 #include "course.h"
9 #include "ogl.h"
10
11 #include <climits>
12 #include <cstring>
13
14 #define TERRAIN_ERROR_SCALE 0.1f
15 #define VERTEX_FORCE_THRESHOLD 100
16 #define ERROR_MAGNIFICATION_THRESHOLD 20
17 #define ERROR_MAGNIFICATION_AMOUNT 3
18 #define ENV_MAP_ALPHA 50
19 #define colorval(j,ch) \
20 VNCArray[j*STRIDE_GL_ARRAY+STRIDE_GL_ARRAY-4+(ch)]
21
22 #define setalphaval(i) colorval(VertexIndices[i], 3) = \
23 ( terrain <= VertexTerrains[i] ) ? 255 : 0
24
25 #define update_min_max( idx ) \
26 if ( idx > VertexArrayMaxIdx ) { \
27 VertexArrayMaxIdx = idx; \
28 } \
29 if ( idx < VertexArrayMinIdx ) { \
30 VertexArrayMinIdx = idx; \
31 }
32
make_tri_list(void (* tri_func)(int,int,int,int),unsigned char EnabledFlags,int flags,int terrain)33 static void make_tri_list(void(*tri_func)(int, int, int, int), unsigned char EnabledFlags, int flags, int terrain) {
34 if ((EnabledFlags & 1) == 0) {
35 tri_func(0, 2, 8, terrain);
36 } else {
37 if (flags & 8) tri_func(0, 1, 8, terrain);
38 if (flags & 1) tri_func(0, 2, 1, terrain);
39 }
40 if ((EnabledFlags & 2) == 0) {
41 tri_func(0, 4, 2, terrain);
42 } else {
43 if (flags & 1) tri_func(0, 3, 2, terrain);
44 if (flags & 2) tri_func(0, 4, 3, terrain);
45 }
46 if ((EnabledFlags & 4) == 0) {
47 tri_func(0, 6, 4, terrain);
48 } else {
49 if (flags & 2) tri_func(0, 5, 4, terrain);
50 if (flags & 4) tri_func(0, 6, 5, terrain);
51 }
52 if ((EnabledFlags & 8) == 0) {
53 tri_func(0, 8, 6, terrain);
54 } else {
55 if (flags & 4) tri_func(0, 7, 6, terrain);
56 if (flags & 8) tri_func(0, 8, 7, terrain);
57 }
58 }
59
60 GLuint *quadsquare::VertexArrayIndices = nullptr;
61 GLuint quadsquare::VertexArrayCounter;
62 GLuint quadsquare::VertexArrayMinIdx;
63 GLuint quadsquare::VertexArrayMaxIdx;
64
quadsquare(quadcornerdata * pcd)65 quadsquare::quadsquare(quadcornerdata* pcd) {
66 pcd->Square = this;
67 Static = false;
68 ForceEastVert = false;
69 ForceSouthVert = false;
70 Dirty = true;
71
72 for (int i = 0; i < 4; i++) {
73 Child[i] = (quadsquare*) nullptr;
74 }
75
76 EnabledFlags = 0;
77
78 for (int i = 0; i < 2; i++) SubEnabledCount[i] = 0;
79
80 Vertex[0].Y = 0.25f * (pcd->Verts[0].Y
81 + pcd->Verts[1].Y + pcd->Verts[2].Y + pcd->Verts[3].Y);
82 Vertex[1].Y = 0.5f * (pcd->Verts[3].Y + pcd->Verts[0].Y);
83 Vertex[2].Y = 0.5f * (pcd->Verts[0].Y + pcd->Verts[1].Y);
84 Vertex[3].Y = 0.5f * (pcd->Verts[1].Y + pcd->Verts[2].Y);
85 Vertex[4].Y = 0.5f * (pcd->Verts[2].Y + pcd->Verts[3].Y);
86
87 for (int i = 0; i < 2; i++) Error[i] = 0;
88 for (int i = 0; i < 4; i++) {
89 Error[i+2] = std::fabs((Vertex[0].Y + pcd->Verts[i].Y)
90 - (Vertex[i+1].Y + Vertex[((i+1)&3) + 1].Y)) * 0.25f;
91 }
92
93 MinY = MaxY = pcd->Verts[0].Y;
94 for (int i = 1; i < 4; i++) {
95 float y = pcd->Verts[i].Y;
96 if (y < MinY) MinY = y;
97 if (y > MaxY) MaxY = y;
98 }
99 }
100
~quadsquare()101 quadsquare::~quadsquare() {
102 for (int i = 0; i < 4; i++) {
103 if (Child[i]) delete Child[i];
104 }
105 }
106
SetStatic(const quadcornerdata & cd)107 void quadsquare::SetStatic(const quadcornerdata &cd) {
108 if (Static == false) {
109 Static = true;
110 if (cd.Parent && cd.Parent->Square) {
111 cd.Parent->Square->SetStatic(*cd.Parent);
112 }
113 }
114 }
115
CountNodes()116 int quadsquare::CountNodes() {
117 int count = 1;
118 for (int i = 0; i < 4; i++) {
119 if (Child[i]) count += Child[i]->CountNodes();
120 }
121 return count;
122 }
123
GetHeight(const quadcornerdata & cd,float x,float z)124 float quadsquare::GetHeight(const quadcornerdata &cd, float x, float z) {
125 int half = 1 << cd.Level;
126
127 float lx = (x - cd.xorg) / float(half);
128 float lz = (z - cd.zorg) / float(half);
129
130 int ix = (int)std::floor(lx);
131 int iz = (int)std::floor(lz);
132
133 if (ix < 0) ix = 0;
134 if (ix > 1) ix = 1;
135 if (iz < 0) iz = 0;
136 if (iz > 1) iz = 1;
137
138 int index = (ix ^ (iz ^ 1)) + (iz << 1);
139 if (Child[index] && Child[index]->Static) {
140 quadcornerdata q;
141 SetupCornerData(&q, cd, index);
142 return Child[index]->GetHeight(q, x, z);
143 }
144
145 lx -= ix;
146 if (lx < 0) lx = 0;
147 if (lx > 1) lx = 1;
148
149 lz -= iz;
150 if (lx < 0) lz = 0;
151 if (lz > 1) lz = 1;
152
153 float s00, s01, s10, s11;
154 switch (index) {
155 default:
156 case 0:
157 s00 = Vertex[2].Y;
158 s01 = cd.Verts[0].Y;
159 s10 = Vertex[0].Y;
160 s11 = Vertex[1].Y;
161 break;
162 case 1:
163 s00 = cd.Verts[1].Y;
164 s01 = Vertex[2].Y;
165 s10 = Vertex[3].Y;
166 s11 = Vertex[0].Y;
167 break;
168 case 2:
169 s00 = Vertex[3].Y;
170 s01 = Vertex[0].Y;
171 s10 = cd.Verts[2].Y;
172 s11 = Vertex[4].Y;
173 break;
174 case 3:
175 s00 = Vertex[0].Y;
176 s01 = Vertex[1].Y;
177 s10 = Vertex[4].Y;
178 s11 = cd.Verts[3].Y;
179 break;
180 }
181
182 return (s00 * (1-lx) + s01 * lx) * (1 - lz) + (s10 * (1-lx) + s11 * lx) * lz;
183 }
184
GetNeighbor(int dir,const quadcornerdata & cd)185 quadsquare* quadsquare::GetNeighbor(int dir, const quadcornerdata& cd) {
186 if (cd.Parent == 0) return 0;
187 quadsquare* p = 0;
188
189 int index = cd.ChildIndex ^ 1 ^ ((dir & 1) << 1);
190 bool SameParent = ((dir - cd.ChildIndex) & 2) ? true : false;
191
192 if (SameParent) {
193 p = cd.Parent->Square;
194 } else {
195 p = cd.Parent->Square->GetNeighbor(dir, *cd.Parent);
196 if (p == 0) return 0;
197 }
198 quadsquare* n = p->Child[index];
199 return n;
200 }
201
RecomputeError(const quadcornerdata & cd)202 float quadsquare::RecomputeError(const quadcornerdata& cd) {
203 int half = 1 << cd.Level;
204 int whole = half << 1;
205 float terrain_error;
206 float maxerror = 0;
207 float e;
208
209 std::size_t numTerr = Course.TerrList.size();
210 if (cd.ChildIndex & 1) {
211 e = std::fabs(Vertex[0].Y - (cd.Verts[1].Y + cd.Verts[3].Y) * 0.5f);
212 } else {
213 e = std::fabs(Vertex[0].Y - (cd.Verts[0].Y + cd.Verts[2].Y) * 0.5f);
214 }
215 if (e > maxerror) maxerror = e;
216
217 MaxY = Vertex[0].Y;
218 MinY = Vertex[0].Y;
219
220 for (int i = 0; i < 4; i++) {
221 float y = cd.Verts[i].Y;
222 if (y < MinY) MinY = y;
223 if (y > MaxY) MaxY = y;
224 }
225
226
227 e = std::fabs(Vertex[1].Y - (cd.Verts[0].Y + cd.Verts[3].Y) * 0.5f);
228 if (e > maxerror) maxerror = e;
229 Error[0] = e;
230
231 e = std::fabs(Vertex[4].Y - (cd.Verts[2].Y + cd.Verts[3].Y) * 0.5f);
232 if (e > maxerror) maxerror = e;
233 Error[1] = e;
234
235 if (cd.Level == 0 && cd.xorg <= RowSize-1 && cd.zorg <= NumRows-1) {
236
237 int x = cd.xorg + half;
238 int z = cd.zorg + whole;
239 int idx = x + z * RowSize;
240 bool different_terrains = false;
241
242 terrain_error = 0.f;
243
244 if (x < RowSize && z < NumRows) {
245
246 if (x < RowSize - 1) {
247 if (Fields[idx].terrain != Fields[idx + 1].terrain) {
248 different_terrains = true;
249 }
250 }
251 if (z >= 1) {
252 idx -= RowSize;
253 if (Fields[idx].terrain != Fields[idx + 1].terrain) {
254 different_terrains = true;
255 }
256 }
257
258 if (different_terrains) {
259 ForceSouthVert = true;
260 terrain_error = TERRAIN_ERROR_SCALE * whole * whole;
261 } else {
262 ForceSouthVert = false;
263 }
264
265 if (terrain_error > Error[0]) {
266 Error[0] = terrain_error;
267 }
268 if (Error[0] > maxerror) {
269 maxerror = Error[0];
270 }
271 }
272
273 x = cd.xorg + whole;
274 z = cd.zorg + half;
275 idx = x + z * RowSize;
276 terrain_error = 0;
277 different_terrains = false;
278
279 if (x < RowSize && z < NumRows) {
280
281 if (z >= 1) {
282 if (Fields[idx].terrain != Fields[idx - RowSize].terrain) {
283 different_terrains = true;
284 }
285 }
286 if (z >= 1 && x < RowSize - 1) {
287 idx += 1;
288 if (Fields[idx].terrain != Fields[idx - RowSize].terrain) {
289 different_terrains = true;
290 }
291 }
292
293 if (different_terrains) {
294 ForceEastVert = true;
295 terrain_error = TERRAIN_ERROR_SCALE * whole * whole;
296 } else {
297 ForceEastVert = false;
298 }
299
300 if (terrain_error > Error[1]) {
301 Error[1] = terrain_error;
302 }
303 if (Error[1] > maxerror) {
304 maxerror = Error[1];
305 }
306 }
307 }
308
309 for (int i = 0; i < 4; i++) {
310 float y = Vertex[1 + i].Y;
311 if (y < MinY) MinY = y;
312 if (y > MaxY) MaxY = y;
313 }
314
315 for (int i = 0; i < 4; i++) {
316 if (Child[i]) {
317 quadcornerdata q;
318 SetupCornerData(&q, cd, i);
319 Error[i+2] = Child[i]->RecomputeError(q);
320
321 if (Child[i]->MinY < MinY) MinY = Child[i]->MinY;
322 if (Child[i]->MaxY > MaxY) MaxY = Child[i]->MaxY;
323 } else {
324 Error[i+2] = std::fabs((Vertex[0].Y + cd.Verts[i].Y)
325 - (Vertex[i+1].Y + Vertex[((i+1)&3) + 1].Y)) * 0.25f;
326 }
327 if (Error[i+2] > maxerror) maxerror = Error[i+2];
328 }
329
330 std::size_t *terrain_count = new std::size_t[numTerr];
331 std::memset(terrain_count, 0, sizeof(*terrain_count)*numTerr);
332
333 for (int i=cd.xorg; i<=cd.xorg+whole; i++) {
334 for (int j=cd.zorg; j<=cd.zorg+whole; j++) {
335
336 if (i < 0 || i >= RowSize ||
337 j < 0 || j >= NumRows) {
338 continue;
339 }
340
341 int terrain = (int) Fields[i + RowSize*j].terrain;
342 terrain_count[ terrain ] += 1;
343 }
344 }
345
346 std::size_t max_count = 0;
347 std::size_t total = 0;
348 for (std::size_t t=0; t<numTerr; t++) {
349 if (terrain_count[t] > max_count) {
350 max_count = terrain_count[t];
351 }
352 total += terrain_count[t];
353 }
354
355 delete [] terrain_count;
356
357 if (total > 0) {
358 terrain_error = (1.f - ((float)max_count / (float)total));
359 if (numTerr > 1) {
360 terrain_error *= numTerr / (numTerr - 1.f);
361 }
362 terrain_error *= whole * whole;
363 terrain_error *= TERRAIN_ERROR_SCALE;
364 } else terrain_error = 0;
365
366 if (terrain_error > maxerror) maxerror = terrain_error;
367 if (terrain_error > Error[0]) Error[0] = terrain_error;
368 if (terrain_error > Error[1]) Error[1] = terrain_error;
369
370 Dirty = false;
371
372 return maxerror;
373 }
374
ResetTree()375 void quadsquare::ResetTree() {
376 for (int i = 0; i < 4; i++) {
377 if (Child[i]) {
378 Child[i]->ResetTree();
379 if (Child[i]->Static == false) {
380 delete Child[i];
381 Child[i] = 0;
382 }
383 }
384 }
385 EnabledFlags = 0;
386 SubEnabledCount[0] = 0;
387 SubEnabledCount[1] = 0;
388 Dirty = true;
389 }
390
391
StaticCullData(const quadcornerdata & cd,float ThresholdDetail)392 void quadsquare::StaticCullData(const quadcornerdata& cd, float ThresholdDetail) {
393 ResetTree();
394 if (Dirty) RecomputeError(cd);
395 for (int level = 0; level <= cd.Level; level++) {
396 StaticCullAux(cd, ThresholdDetail, level);
397 }
398 }
399
400
StaticCullAux(const quadcornerdata & cd,float ThresholdDetail,int TargetLevel)401 void quadsquare::StaticCullAux(const quadcornerdata& cd, float ThresholdDetail, int TargetLevel) {
402 quadcornerdata q;
403
404 if (cd.Level > TargetLevel) {
405 for (int j = 0; j < 4; j++) {
406 int i;
407 if (j < 2) i = 1 - j;
408 else i = j;
409
410 if (Child[i]) {
411 SetupCornerData(&q, cd, i);
412 Child[i]->StaticCullAux(q, ThresholdDetail, TargetLevel);
413 }
414 }
415 return;
416 }
417 float size = 2 << cd.Level; // Edge length.
418 if (Child[0] == nullptr && Child[3] == nullptr && Error[0] * ThresholdDetail < size) {
419 quadsquare* s = GetNeighbor(0, cd);
420 if (s == nullptr || (s->Child[1] == nullptr && s->Child[2] == nullptr)) {
421
422 float y = (cd.Verts[0].Y + cd.Verts[3].Y) * 0.5f;
423 Vertex[1].Y = y;
424 Error[0] = 0;
425 if (s) s->Vertex[3].Y = y;
426
427 Dirty = true;
428 }
429 }
430
431 if (Child[2] == nullptr && Child[3] == nullptr && Error[1] * ThresholdDetail < size) {
432 quadsquare* s = GetNeighbor(3, cd);
433 if (s == nullptr || (s->Child[0] == nullptr && s->Child[1] == nullptr)) {
434 float y = (cd.Verts[2].Y + cd.Verts[3].Y) * 0.5f;
435 Vertex[4].Y = y;
436 Error[1] = 0;
437
438 if (s) s->Vertex[2].Y = y;
439 Dirty = true;
440 }
441 }
442
443 bool StaticChildren = false;
444 for (int i = 0; i < 4; i++) {
445 if (Child[i]) {
446 StaticChildren = true;
447 if (Child[i]->Dirty) Dirty = true;
448 }
449 }
450
451 if (StaticChildren == false && cd.Parent != nullptr) {
452 bool NecessaryEdges = false;
453 for (int i = 0; i < 4; i++) {
454 float diff = std::fabs(Vertex[i+1].Y - (cd.Verts[i].Y
455 + cd.Verts[(i+3)&3].Y) * 0.5f);
456 if (diff > 0.00001f) {
457 NecessaryEdges = true;
458 }
459 }
460
461 if (!NecessaryEdges) {
462 size *= 1.414213562f;
463 if (cd.Parent->Square->Error[2 + cd.ChildIndex] * ThresholdDetail < size) {
464 delete cd.Parent->Square->Child[cd.ChildIndex];
465 cd.Parent->Square->Child[cd.ChildIndex] = 0;
466 }
467 }
468 }
469 }
470
EnableEdgeVertex(int index,bool IncrementCount,const quadcornerdata & cd)471 void quadsquare::EnableEdgeVertex(int index, bool IncrementCount, const quadcornerdata& cd) {
472 int ct = 0;
473 int stack[32];
474
475
476 if ((EnabledFlags & (1 << index)) && IncrementCount == false) return;
477
478 EnabledFlags |= 1 << index;
479 if (IncrementCount == true && (index == 0 || index == 3)) {
480 SubEnabledCount[index & 1]++;
481 }
482 quadsquare* p = this;
483 const quadcornerdata* pcd = &cd;
484 for (;;) {
485 int ci = pcd->ChildIndex;
486 if (pcd->Parent == nullptr || pcd->Parent->Square == nullptr) return;
487 p = pcd->Parent->Square;
488 pcd = pcd->Parent;
489
490 bool SameParent = ((index - ci) & 2) ? true : false;
491
492 ci = ci ^ 1 ^ ((index & 1) << 1);
493
494 stack[ct] = ci;
495 ct++;
496
497 if (SameParent) break;
498 }
499
500 p = p->EnableDescendant(ct, stack, *pcd);
501
502 index ^= 2;
503 p->EnabledFlags |= (1 << index);
504 if (IncrementCount == true && (index == 0 || index == 3)) {
505 p->SubEnabledCount[index & 1]++;
506 }
507 }
508
509
EnableDescendant(int count,int path[],const quadcornerdata & cd)510 quadsquare* quadsquare::EnableDescendant(int count, int path[], const quadcornerdata& cd) {
511 count--;
512 int ChildIndex = path[count];
513
514 if ((EnabledFlags & (16 << ChildIndex)) == 0) {
515 EnableChild(ChildIndex, cd);
516 }
517
518 if (count > 0) {
519 quadcornerdata q;
520 SetupCornerData(&q, cd, ChildIndex);
521 return Child[ChildIndex]->EnableDescendant(count, path, q);
522 } else {
523 return Child[ChildIndex];
524 }
525 }
526
527
CreateChild(int index,const quadcornerdata & cd)528 void quadsquare::CreateChild(int index, const quadcornerdata& cd) {
529 if (Child[index] == 0) {
530 quadcornerdata q;
531 SetupCornerData(&q, cd, index);
532
533 Child[index] = new quadsquare(&q);
534 }
535 }
536
EnableChild(int index,const quadcornerdata & cd)537 void quadsquare::EnableChild(int index, const quadcornerdata& cd) {
538 if ((EnabledFlags & (16 << index)) == 0) {
539 EnabledFlags |= (16 << index);
540 EnableEdgeVertex(index, true, cd);
541 EnableEdgeVertex((index + 1) & 3, true, cd);
542
543 if (Child[index] == 0) {
544 CreateChild(index, cd);
545 }
546 }
547 }
548
NotifyChildDisable(const quadcornerdata & cd,int index)549 void quadsquare::NotifyChildDisable(const quadcornerdata& cd, int index) {
550 EnabledFlags &= ~(16 << index);
551 quadsquare* s;
552
553 if (index & 2) s = this;
554 else s = GetNeighbor(1, cd);
555 if (s) {
556 s->SubEnabledCount[1]--;
557 }
558
559 if (index == 1 || index == 2) s = GetNeighbor(2, cd);
560 else s = this;
561 if (s) {
562 s->SubEnabledCount[0]--;
563 }
564 }
565
566 static float DetailThreshold = 100;
567
568
VertexTest(int x,float y,int z,float error,const float Viewer[3],int level,vertex_loc_t vertex_loc) const569 bool quadsquare::VertexTest(int x, float y, int z, float error,
570 const float Viewer[3], int level, vertex_loc_t vertex_loc) const {
571 float dx = std::fabs(x - Viewer[0]) * std::fabs(ScaleX);
572 float dy = std::fabs(y - Viewer[1]);
573 float dz = std::fabs(z - Viewer[2]) * std::fabs(ScaleZ);
574 float d = std::max(dx, std::max(dy, dz));
575
576 if (vertex_loc == South && ForceSouthVert && d < VERTEX_FORCE_THRESHOLD) {
577 return true;
578 }
579 if (vertex_loc == East && ForceEastVert && d < VERTEX_FORCE_THRESHOLD) {
580 return true;
581 }
582 if (d < ERROR_MAGNIFICATION_THRESHOLD) {
583 error *= ERROR_MAGNIFICATION_AMOUNT;
584 }
585
586 return error * DetailThreshold > d;
587 }
588
BoxTest(int x,int z,float size,float miny,float maxy,float error,const float Viewer[3])589 bool quadsquare::BoxTest(int x, int z, float size, float miny, float maxy, float error, const float Viewer[3]) {
590 float half = size * 0.5f;
591 float dx = (std::fabs(x + half - Viewer[0]) - half) * std::fabs(ScaleX);
592 float dy = std::fabs((miny + maxy) * 0.5f - Viewer[1]) - (maxy - miny) * 0.5f;
593 float dz = (std::fabs(z + half - Viewer[2]) - half) * std::fabs(ScaleZ);
594 float d = std::max(dx, std::max(dy, dz));
595
596 if (d < ERROR_MAGNIFICATION_THRESHOLD) {
597 error *= ERROR_MAGNIFICATION_AMOUNT;
598 }
599
600 if (error * DetailThreshold > d) {
601 return true;
602 }
603 if ((x < RowSize-1 && x+size >= RowSize) ||
604 (z < NumRows-1 && z+size >= NumRows)) {
605 return true;
606 }
607
608 return false;
609 }
610
Update(const quadcornerdata & cd,const TVector3d & ViewerLocation,float Detail)611 void quadsquare::Update(const quadcornerdata& cd, const TVector3d& ViewerLocation, float Detail) {
612 float Viewer[3];
613
614 DetailThreshold = Detail;
615 Viewer[0] = ViewerLocation.x / ScaleX;
616 Viewer[1] = ViewerLocation.y;
617 Viewer[2] = ViewerLocation.z / ScaleZ;
618 UpdateAux(cd, Viewer, 0, SomeClip);
619 }
620
621
UpdateAux(const quadcornerdata & cd,const float ViewerLocation[3],float CenterError,clip_result_t vis)622 void quadsquare::UpdateAux(const quadcornerdata& cd,
623 const float ViewerLocation[3], float CenterError, clip_result_t vis) {
624 if (vis != NoClip) {
625 vis = ClipSquare(cd);
626
627 if (vis == NotVisible) {
628 return;
629 }
630 }
631 if (Dirty) {
632 RecomputeError(cd);
633 }
634
635 int half = 1 << cd.Level;
636 int whole = half << 1;
637 if ((EnabledFlags & 1) == 0 &&
638 VertexTest(cd.xorg + whole, Vertex[1].Y, cd.zorg + half,
639 Error[0], ViewerLocation, cd.Level, East) == true) {
640 EnableEdgeVertex(0, false, cd);
641 }
642
643 if ((EnabledFlags & 8) == 0 &&
644 VertexTest(cd.xorg + half, Vertex[4].Y, cd.zorg + whole,
645 Error[1], ViewerLocation, cd.Level, South) == true) {
646 EnableEdgeVertex(3, false, cd);
647 }
648
649 if (cd.Level > 0) {
650 if ((EnabledFlags & 32) == 0) {
651 if (BoxTest(cd.xorg, cd.zorg, half, MinY, MaxY, Error[3],
652 ViewerLocation) == true) EnableChild(1, cd);
653 }
654 if ((EnabledFlags & 16) == 0) {
655 if (BoxTest(cd.xorg + half, cd.zorg, half, MinY, MaxY,
656 Error[2], ViewerLocation) == true) EnableChild(0, cd);
657 }
658 if ((EnabledFlags & 64) == 0) {
659 if (BoxTest(cd.xorg, cd.zorg + half, half, MinY, MaxY,
660 Error[4], ViewerLocation) == true) EnableChild(2, cd);
661 }
662 if ((EnabledFlags & 128) == 0) {
663 if (BoxTest(cd.xorg + half, cd.zorg + half, half, MinY, MaxY,
664 Error[5], ViewerLocation) == true) EnableChild(3, cd);
665 }
666
667 quadcornerdata q;
668
669 if (EnabledFlags & 32) {
670 SetupCornerData(&q, cd, 1);
671 Child[1]->UpdateAux(q, ViewerLocation, Error[3], vis);
672 }
673 if (EnabledFlags & 16) {
674 SetupCornerData(&q, cd, 0);
675 Child[0]->UpdateAux(q, ViewerLocation, Error[2], vis);
676 }
677 if (EnabledFlags & 64) {
678 SetupCornerData(&q, cd, 2);
679 Child[2]->UpdateAux(q, ViewerLocation, Error[4], vis);
680 }
681 if (EnabledFlags & 128) {
682 SetupCornerData(&q, cd, 3);
683 Child[3]->UpdateAux(q, ViewerLocation, Error[5], vis);
684 }
685 }
686 if ((EnabledFlags & 1) &&
687 SubEnabledCount[0] == 0 &&
688 VertexTest(cd.xorg + whole, Vertex[1].Y, cd.zorg + half,
689 Error[0], ViewerLocation, cd.Level, East) == false) {
690 EnabledFlags &= ~1;
691 quadsquare* s = GetNeighbor(0, cd);
692 if (s) s->EnabledFlags &= ~4;
693 }
694
695 if ((EnabledFlags & 8) &&
696 SubEnabledCount[1] == 0 &&
697 VertexTest(cd.xorg + half, Vertex[4].Y, cd.zorg + whole,
698 Error[1], ViewerLocation, cd.Level, South) == false) {
699 EnabledFlags &= ~8;
700 quadsquare* s = GetNeighbor(3, cd);
701 if (s) s->EnabledFlags &= ~2;
702 }
703
704 if (EnabledFlags == 0 &&
705 cd.Parent != nullptr &&
706 BoxTest(cd.xorg, cd.zorg, whole, MinY, MaxY, CenterError,
707 ViewerLocation) == false) {
708 cd.Parent->Square->NotifyChildDisable(*cd.Parent, cd.ChildIndex);
709 }
710 }
711
712 GLuint VertexIndices[9];
713 int VertexTerrains[9];
714
InitVert(int i,int x,int z)715 void quadsquare::InitVert(int i, int x, int z) {
716 if (x >= RowSize) x = RowSize-1;
717 if (z >= NumRows) z = NumRows - 1;
718
719 int idx = x + RowSize * z;
720
721 VertexIndices[i] = idx;
722 VertexTerrains[i] = Fields[idx].terrain;
723 }
724
725 GLubyte *VNCArray;
726
DrawTris()727 void quadsquare::DrawTris() {
728 int tmp_min_idx = VertexArrayMinIdx;
729
730 if (glLockArraysEXT_p) {
731 if (tmp_min_idx == 0) tmp_min_idx = 1;
732 glLockArraysEXT_p(tmp_min_idx, VertexArrayMaxIdx - tmp_min_idx + 1);
733 }
734
735 glDrawElements(GL_TRIANGLES, VertexArrayCounter,
736 GL_UNSIGNED_INT, VertexArrayIndices);
737 if (glUnlockArraysEXT_p) glUnlockArraysEXT_p();
738 }
739
InitArrayCounters()740 void quadsquare::InitArrayCounters() {
741 VertexArrayCounter = 0;
742 VertexArrayMinIdx = INT_MAX;
743 VertexArrayMaxIdx = 0;
744 }
745
Render(const quadcornerdata & cd,GLubyte * vnc_array)746 void quadsquare::Render(const quadcornerdata& cd, GLubyte *vnc_array) {
747 VNCArray = vnc_array;
748
749 std::size_t numTerrains = Course.TerrList.size();
750 for (std::size_t j=0; j<numTerrains; j++) {
751 if (Course.TerrList[j].texture != nullptr) {
752 InitArrayCounters();
753 RenderAux(cd, SomeClip, (int)j);
754 if (VertexArrayCounter == 0) continue;
755
756 Course.TerrList[j].texture->Bind();
757 DrawTris();
758 }
759 }
760
761 if (param.perf_level > 1) {
762 InitArrayCounters();
763 RenderAux(cd, SomeClip, -1);
764
765 if (VertexArrayCounter != 0) {
766 glDisable(GL_FOG);
767 for (GLuint i=0; i<VertexArrayCounter; i++) {
768 colorval(VertexArrayIndices[i], 0) = 0;
769 colorval(VertexArrayIndices[i], 1) = 0;
770 colorval(VertexArrayIndices[i], 2) = 0;
771 colorval(VertexArrayIndices[i], 3) = 255;
772 }
773 Course.TerrList[0].texture->Bind();
774 DrawTris();
775 //if (fog_on)
776 glEnable(GL_FOG);
777 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
778 for (GLuint i=0; i<VertexArrayCounter; i++) {
779 colorval(VertexArrayIndices[i], 0) = 255;
780 colorval(VertexArrayIndices[i], 1) = 255;
781 colorval(VertexArrayIndices[i], 2) = 255;
782 }
783
784 for (std::size_t j=0; j<numTerrains; j++) {
785 if (Course.TerrList[j].texture != nullptr) {
786 Course.TerrList[j].texture->Bind();
787
788 for (GLuint i=0; i<VertexArrayCounter; i++) {
789 colorval(VertexArrayIndices[i], 3) =
790 (Fields[VertexArrayIndices[i]].terrain == (char)j) ? 255 : 0;
791 }
792 DrawTris();
793 }
794 }
795 }
796 }
797 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
798 }
799
ClipSquare(const quadcornerdata & cd)800 clip_result_t quadsquare::ClipSquare(const quadcornerdata& cd) {
801 if (cd.xorg >= RowSize-1) {
802 return NotVisible;
803 }
804
805 if (cd.zorg >= NumRows-1) {
806 return NotVisible;
807 }
808
809 int whole = 2 << cd.Level;
810 TVector3d minimum(
811 cd.xorg * ScaleX,
812 MinY,
813 cd.zorg * ScaleZ);
814 TVector3d maximum(
815 (cd.xorg + whole) * ScaleX,
816 MaxY,
817 (cd.zorg + whole) * ScaleZ);
818
819 if (minimum.x > maximum.x)
820 std::swap(minimum.x, maximum.x);
821
822 if (minimum.z > maximum.z)
823 std::swap(minimum.z, maximum.z);
824
825 clip_result_t clip_result = clip_aabb_to_view_frustum(minimum, maximum);
826
827 if (clip_result == NotVisible || clip_result == SomeClip) {
828 return clip_result;
829 }
830
831 if (cd.xorg + whole >= RowSize) {
832 return SomeClip;
833 }
834 if (cd.zorg + whole >= NumRows) {
835 return SomeClip;
836 }
837
838 return clip_result;
839 }
840
841
MakeTri(int a,int b,int c,int terrain)842 inline void quadsquare::MakeTri(int a, int b, int c, int terrain) {
843 if ((VertexTerrains[a] == terrain ||
844 VertexTerrains[b] == terrain ||
845 VertexTerrains[c] == terrain)) {
846 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[a];
847 setalphaval(a);
848 update_min_max(VertexIndices[a]);
849 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[b];
850 setalphaval(b);
851 update_min_max(VertexIndices[b]);
852 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[c];
853 setalphaval(c);
854 update_min_max(VertexIndices[c]);
855 }
856 }
857
858
MakeSpecialTri(int a,int b,int c,int terrain)859 inline void quadsquare::MakeSpecialTri(int a, int b, int c, int terrain) {
860 if (VertexTerrains[a] != VertexTerrains[b] &&
861 VertexTerrains[a] != VertexTerrains[c] &&
862 VertexTerrains[b] != VertexTerrains[c]) {
863 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[a];
864 update_min_max(VertexIndices[a]);
865 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[b];
866 update_min_max(VertexIndices[b]);
867 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[c];
868 update_min_max(VertexIndices[c]);
869 }
870 }
871
MakeNoBlendTri(int a,int b,int c,int terrain)872 inline void quadsquare::MakeNoBlendTri(int a, int b, int c, int terrain) {
873 if ((VertexTerrains[a] == terrain ||
874 VertexTerrains[b] == terrain ||
875 VertexTerrains[c] == terrain) &&
876 (VertexTerrains[a] >= terrain &&
877 VertexTerrains[b] >= terrain &&
878 VertexTerrains[c] >= terrain)) {
879 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[a];
880 setalphaval(a);
881 update_min_max(VertexIndices[a]);
882 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[b];
883 setalphaval(b);
884 update_min_max(VertexIndices[b]);
885 VertexArrayIndices[VertexArrayCounter++] = VertexIndices[c];
886 setalphaval(c);
887 update_min_max(VertexIndices[c]);
888 }
889 }
890
RenderAux(const quadcornerdata & cd,clip_result_t vis,int terrain)891 void quadsquare::RenderAux(const quadcornerdata& cd, clip_result_t vis, int terrain) {
892 int half = 1 << cd.Level;
893 int whole = 2 << cd.Level;
894 if (vis != NoClip) {
895 vis = ClipSquare(cd);
896 if (vis == NotVisible) return;
897 }
898
899 int flags = 0;
900 int mask = 1;
901 quadcornerdata q;
902
903 for (int i = 0; i < 4; i++, mask <<= 1) {
904 if (EnabledFlags & (16 << i)) {
905 SetupCornerData(&q, cd, i);
906 Child[i]->RenderAux(q, vis, terrain);
907 } else {
908 flags |= mask;
909 }
910 }
911
912 if (flags == 0) return;
913
914 InitVert(0, cd.xorg + half, cd.zorg + half);
915 InitVert(1, cd.xorg + whole, cd.zorg + half);
916 InitVert(2, cd.xorg + whole, cd.zorg);
917 InitVert(3, cd.xorg + half, cd.zorg);
918 InitVert(4, cd.xorg, cd.zorg);
919 InitVert(5, cd.xorg, cd.zorg + half);
920 InitVert(6, cd.xorg, cd.zorg + whole);
921 InitVert(7, cd.xorg + half, cd.zorg + whole);
922 InitVert(8, cd.xorg + whole, cd.zorg + whole);
923 if (terrain == -1) {
924 make_tri_list(MakeSpecialTri, EnabledFlags, flags, terrain);
925 } else if (param.perf_level > 1) {
926 make_tri_list(MakeTri, EnabledFlags, flags, terrain);
927 } else {
928 make_tri_list(MakeNoBlendTri, EnabledFlags, flags, terrain);
929 }
930
931 }
932
933
SetupCornerData(quadcornerdata * q,const quadcornerdata & cd,int ChildIndex)934 void quadsquare::SetupCornerData(quadcornerdata* q, const quadcornerdata& cd, int ChildIndex) {
935 int half = 1 << cd.Level;
936
937 q->Parent = &cd;
938 q->Square = Child[ChildIndex];
939 q->Level = cd.Level - 1;
940 q->ChildIndex = ChildIndex;
941
942 switch (ChildIndex) {
943 default:
944 case 0:
945 q->xorg = cd.xorg + half;
946 q->zorg = cd.zorg;
947 q->Verts[0] = cd.Verts[0];
948 q->Verts[1] = Vertex[2];
949 q->Verts[2] = Vertex[0];
950 q->Verts[3] = Vertex[1];
951 break;
952
953 case 1:
954 q->xorg = cd.xorg;
955 q->zorg = cd.zorg;
956 q->Verts[0] = Vertex[2];
957 q->Verts[1] = cd.Verts[1];
958 q->Verts[2] = Vertex[3];
959 q->Verts[3] = Vertex[0];
960 break;
961
962 case 2:
963 q->xorg = cd.xorg;
964 q->zorg = cd.zorg + half;
965 q->Verts[0] = Vertex[0];
966 q->Verts[1] = Vertex[3];
967 q->Verts[2] = cd.Verts[2];
968 q->Verts[3] = Vertex[4];
969 break;
970
971 case 3:
972 q->xorg = cd.xorg + half;
973 q->zorg = cd.zorg + half;
974 q->Verts[0] = Vertex[1];
975 q->Verts[1] = Vertex[0];
976 q->Verts[2] = Vertex[4];
977 q->Verts[3] = cd.Verts[3];
978 break;
979 }
980 }
981
982 int quadsquare::RowSize;
983 int quadsquare::NumRows;
984
AddHeightMap(const quadcornerdata & cd,const HeightMapInfo & hm)985 void quadsquare::AddHeightMap(const quadcornerdata& cd, const HeightMapInfo& hm) {
986 RowSize = hm.RowWidth;
987 NumRows = hm.ZSize;
988
989 if (cd.Parent == nullptr) {
990 if (VertexArrayIndices != nullptr) {
991 delete[] VertexArrayIndices;
992 }
993 VertexArrayIndices = new GLuint[6 * RowSize * NumRows];
994 }
995 int BlockSize = 2 << cd.Level;
996 if (cd.xorg > hm.XOrigin + ((hm.XSize + 2) << hm.Scale) ||
997 cd.xorg + BlockSize < hm.XOrigin - (1 << hm.Scale) ||
998 cd.zorg > hm.ZOrigin + ((hm.ZSize + 2) << hm.Scale) ||
999 cd.zorg + BlockSize < hm.ZOrigin - (1 << hm.Scale)) {
1000 return;
1001 }
1002
1003 if (cd.Parent && cd.Parent->Square) {
1004 cd.Parent->Square->EnableChild(cd.ChildIndex, *cd.Parent);
1005 }
1006
1007 int half = 1 << cd.Level;
1008 for (int i = 0; i < 4; i++) {
1009 quadcornerdata q;
1010 SetupCornerData(&q, cd, i);
1011
1012 if (Child[i] == nullptr && cd.Level > hm.Scale) {
1013 Child[i] = new quadsquare(&q);
1014 }
1015 if (Child[i]) {
1016 Child[i]->AddHeightMap(q, hm);
1017 }
1018 }
1019 float s[5];
1020 s[0] = hm.Sample(cd.xorg + half, cd.zorg + half);
1021 s[1] = hm.Sample(cd.xorg + half*2, cd.zorg + half);
1022 s[2] = hm.Sample(cd.xorg + half, cd.zorg);
1023 s[3] = hm.Sample(cd.xorg, cd.zorg + half);
1024 s[4] = hm.Sample(cd.xorg + half, cd.zorg + half*2);
1025
1026 for (int i = 0; i < 5; i++) {
1027 if (s[i] != 0) {
1028 Dirty = true;
1029 Vertex[i].Y += s[i];
1030 }
1031 }
1032
1033 if (!Dirty) {
1034 for (int i = 0; i < 4; i++) {
1035 if (Child[i] && Child[i]->Dirty) {
1036 Dirty = true;
1037 break;
1038 }
1039 }
1040 }
1041
1042 if (Dirty) SetStatic(cd);
1043 }
1044
1045 double quadsquare::ScaleX;
1046 double quadsquare::ScaleZ;
SetScale(double x,double z)1047 void quadsquare::SetScale(double x, double z) {
1048 ScaleX = x;
1049 ScaleZ = z;
1050 }
1051
1052 CourseFields* quadsquare::Fields;
SetFields(CourseFields * fields)1053 void quadsquare::SetFields(CourseFields* fields) {
1054 Fields = fields;
1055 }
1056
Sample(int x,int z) const1057 float HeightMapInfo::Sample(int x, int z) const {
1058 if (x >= XSize) {
1059 x = XSize - 1;
1060 }
1061 if (z >= ZSize) {
1062 z = ZSize - 1;
1063 }
1064 return Data[ x + z * RowWidth ].elevation;
1065 }
1066
1067 // --------------------------------------------------------------------
1068 // global calls
1069 // --------------------------------------------------------------------
1070
1071 #define CULL_DETAIL_FACTOR 25
1072
1073 static quadsquare *root = (quadsquare*) nullptr;
1074 static quadcornerdata root_corner_data = {(quadcornerdata*)nullptr };
1075
ResetQuadtree()1076 void ResetQuadtree() {
1077 if (root != nullptr) {
1078 delete root;
1079 root = (quadsquare*) nullptr;
1080 }
1081 }
1082
get_root_level(int nx,int nz)1083 static int get_root_level(int nx, int nz) {
1084 return (int)std::log2(static_cast<double>(std::max(nx, nz)));
1085 }
1086
1087
InitQuadtree(CourseFields * fields,int nx,int nz,double scalex,double scalez,const TVector3d & view_pos,double detail)1088 void InitQuadtree(CourseFields* fields, int nx, int nz,
1089 double scalex, double scalez, const TVector3d& view_pos, double detail) {
1090 HeightMapInfo hm;
1091
1092 hm.Data = fields;
1093 hm.XOrigin = 0;
1094 hm.ZOrigin = 0;
1095 hm.XSize = nx;
1096 hm.ZSize = nz;
1097 hm.RowWidth = hm.XSize;
1098 hm.Scale = 0;
1099
1100 root_corner_data.Square = nullptr;
1101 root_corner_data.ChildIndex = 0;
1102 root_corner_data.Level = get_root_level(nx, nz);
1103 root_corner_data.xorg = 0;
1104 root_corner_data.zorg = 0;
1105
1106 for (int i=0; i<4; i++) {
1107 root_corner_data.Verts[i].Y = 0;
1108 root_corner_data.Verts[i].Y = 0;
1109 }
1110
1111 root = new quadsquare(&root_corner_data);
1112 root->AddHeightMap(root_corner_data, hm);
1113 root->SetScale(scalex, scalez);
1114 root->SetFields(&Course.Fields[0]);
1115
1116 root->StaticCullData(root_corner_data, CULL_DETAIL_FACTOR);
1117
1118 for (int i = 0; i < 10; i++) {
1119 root->Update(root_corner_data, view_pos, detail);
1120 }
1121 }
1122
UpdateQuadtree(const TVector3d & view_pos,float detail)1123 void UpdateQuadtree(const TVector3d& view_pos, float detail) {
1124 root->Update(root_corner_data, view_pos, detail);
1125 }
1126
RenderQuadtree()1127 void RenderQuadtree() {
1128 GLubyte *vnc_array = Course.GetGLArrays();
1129
1130 glEnableClientState(GL_VERTEX_ARRAY);
1131 glVertexPointer(3, GL_FLOAT, STRIDE_GL_ARRAY, vnc_array);
1132
1133 glEnableClientState(GL_NORMAL_ARRAY);
1134 glNormalPointer(GL_FLOAT, STRIDE_GL_ARRAY,
1135 vnc_array + 4 * sizeof(GLfloat));
1136
1137 glEnableClientState(GL_COLOR_ARRAY);
1138 glColorPointer(4, GL_UNSIGNED_BYTE, STRIDE_GL_ARRAY,
1139 vnc_array + 8 * sizeof(GLfloat));
1140
1141 root->Render(root_corner_data, vnc_array);
1142
1143 glDisableClientState(GL_VERTEX_ARRAY);
1144 glDisableClientState(GL_NORMAL_ARRAY);
1145 glDisableClientState(GL_COLOR_ARRAY);
1146 }
1147