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