1 //
2 // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
3 //
4 // This software is provided 'as-is', without any express or implied
5 // warranty.  In no event will the authors be held liable for any damages
6 // arising from the use of this software.
7 // Permission is granted to anyone to use this software for any purpose,
8 // including commercial applications, and to alter it and redistribute it
9 // freely, subject to the following restrictions:
10 // 1. The origin of this software must not be misrepresented; you must not
11 //    claim that you wrote the original software. If you use this software
12 //    in a product, an acknowledgment in the product documentation would be
13 //    appreciated but is not required.
14 // 2. Altered source versions must be plainly marked as such, and must not be
15 //    misrepresented as being the original software.
16 // 3. This notice may not be removed or altered from any source distribution.
17 //
18 
19 #include "DebugDraw.h"
20 #include "DetourDebugDraw.h"
21 #include "DetourNavMesh.h"
22 #include "DetourCommon.h"
23 #include "DetourNode.h"
24 
25 
distancePtLine2d(const float * pt,const float * p,const float * q)26 static float distancePtLine2d(const float* pt, const float* p, const float* q)
27 {
28 	float pqx = q[0] - p[0];
29 	float pqz = q[2] - p[2];
30 	float dx = pt[0] - p[0];
31 	float dz = pt[2] - p[2];
32 	float d = pqx*pqx + pqz*pqz;
33 	float t = pqx*dx + pqz*dz;
34 	if (d != 0) t /= d;
35 	dx = p[0] + t*pqx - pt[0];
36 	dz = p[2] + t*pqz - pt[2];
37 	return dx*dx + dz*dz;
38 }
39 
drawPolyBoundaries(duDebugDraw * dd,const dtMeshTile * tile,const unsigned int col,const float linew,bool inner)40 static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
41 							   const unsigned int col, const float linew,
42 							   bool inner)
43 {
44 	static const float thr = 0.01f*0.01f;
45 
46 	dd->begin(DU_DRAW_LINES, linew);
47 
48 	for (int i = 0; i < tile->header->polyCount; ++i)
49 	{
50 		const dtPoly* p = &tile->polys[i];
51 
52 		if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue;
53 
54 		const dtPolyDetail* pd = &tile->detailMeshes[i];
55 
56 		for (int j = 0, nj = (int)p->vertCount; j < nj; ++j)
57 		{
58 			unsigned int c = col;
59 			if (inner)
60 			{
61 				if (p->neis[j] == 0) continue;
62 				if (p->neis[j] & DT_EXT_LINK)
63 				{
64 					bool con = false;
65 					for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
66 					{
67 						if (tile->links[k].edge == j)
68 						{
69 							con = true;
70 							break;
71 						}
72 					}
73 					if (con)
74 						c = duRGBA(255,255,255,48);
75 					else
76 						c = duRGBA(0,0,0,48);
77 				}
78 				else
79 					c = duRGBA(0,48,64,32);
80 			}
81 			else
82 			{
83 				if (p->neis[j] != 0) continue;
84 			}
85 
86 			const float* v0 = &tile->verts[p->verts[j]*3];
87 			const float* v1 = &tile->verts[p->verts[(j+1) % nj]*3];
88 
89 			// Draw detail mesh edges which align with the actual poly edge.
90 			// This is really slow.
91 			for (int k = 0; k < pd->triCount; ++k)
92 			{
93 				const unsigned char* t = &tile->detailTris[(pd->triBase+k)*4];
94 				const float* tv[3];
95 				for (int m = 0; m < 3; ++m)
96 				{
97 					if (t[m] < p->vertCount)
98 						tv[m] = &tile->verts[p->verts[t[m]]*3];
99 					else
100 						tv[m] = &tile->detailVerts[(pd->vertBase+(t[m]-p->vertCount))*3];
101 				}
102 				for (int m = 0, n = 2; m < 3; n=m++)
103 				{
104 					if ((dtGetDetailTriEdgeFlags(t[3], n) & DT_DETAIL_EDGE_BOUNDARY) == 0)
105 						continue;
106 
107 					if (distancePtLine2d(tv[n],v0,v1) < thr &&
108 						distancePtLine2d(tv[m],v0,v1) < thr)
109 					{
110 						dd->vertex(tv[n], c);
111 						dd->vertex(tv[m], c);
112 					}
113 				}
114 			}
115 		}
116 	}
117 	dd->end();
118 }
119 
drawMeshTile(duDebugDraw * dd,const dtNavMesh & mesh,const dtNavMeshQuery * query,const dtMeshTile * tile,unsigned char flags)120 static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery* query,
121 						 const dtMeshTile* tile, unsigned char flags)
122 {
123 	dtPolyRef base = mesh.getPolyRefBase(tile);
124 
125 	int tileNum = mesh.decodePolyIdTile(base);
126 	const unsigned int tileColor = duIntToCol(tileNum, 128);
127 
128 	dd->depthMask(false);
129 
130 	dd->begin(DU_DRAW_TRIS);
131 	for (int i = 0; i < tile->header->polyCount; ++i)
132 	{
133 		const dtPoly* p = &tile->polys[i];
134 		if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)	// Skip off-mesh links.
135 			continue;
136 
137 		const dtPolyDetail* pd = &tile->detailMeshes[i];
138 
139 		unsigned int col;
140 		if (query && query->isInClosedList(base | (dtPolyRef)i))
141 			col = duRGBA(255,196,0,64);
142 		else
143 		{
144 			if (flags & DU_DRAWNAVMESH_COLOR_TILES)
145 				col = tileColor;
146 			else
147 				col = duTransCol(dd->areaToCol(p->getArea()), 64);
148 		}
149 
150 		for (int j = 0; j < pd->triCount; ++j)
151 		{
152 			const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
153 			for (int k = 0; k < 3; ++k)
154 			{
155 				if (t[k] < p->vertCount)
156 					dd->vertex(&tile->verts[p->verts[t[k]]*3], col);
157 				else
158 					dd->vertex(&tile->detailVerts[(pd->vertBase+t[k]-p->vertCount)*3], col);
159 			}
160 		}
161 	}
162 	dd->end();
163 
164 	// Draw inter poly boundaries
165 	drawPolyBoundaries(dd, tile, duRGBA(0,48,64,32), 1.5f, true);
166 
167 	// Draw outer poly boundaries
168 	drawPolyBoundaries(dd, tile, duRGBA(0,48,64,220), 2.5f, false);
169 
170 	if (flags & DU_DRAWNAVMESH_OFFMESHCONS)
171 	{
172 		dd->begin(DU_DRAW_LINES, 2.0f);
173 		for (int i = 0; i < tile->header->polyCount; ++i)
174 		{
175 			const dtPoly* p = &tile->polys[i];
176 			if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION)	// Skip regular polys.
177 				continue;
178 
179 			unsigned int col, col2;
180 			if (query && query->isInClosedList(base | (dtPolyRef)i))
181 				col = duRGBA(255,196,0,220);
182 			else
183 				col = duDarkenCol(duTransCol(dd->areaToCol(p->getArea()), 220));
184 
185 			const dtOffMeshConnection* con = &tile->offMeshCons[i - tile->header->offMeshBase];
186 			const float* va = &tile->verts[p->verts[0]*3];
187 			const float* vb = &tile->verts[p->verts[1]*3];
188 
189 			// Check to see if start and end end-points have links.
190 			bool startSet = false;
191 			bool endSet = false;
192 			for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
193 			{
194 				if (tile->links[k].edge == 0)
195 					startSet = true;
196 				if (tile->links[k].edge == 1)
197 					endSet = true;
198 			}
199 
200 			// End points and their on-mesh locations.
201 			dd->vertex(va[0],va[1],va[2], col);
202 			dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
203 			col2 = startSet ? col : duRGBA(220,32,16,196);
204 			duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
205 
206 			dd->vertex(vb[0],vb[1],vb[2], col);
207 			dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
208 			col2 = endSet ? col : duRGBA(220,32,16,196);
209 			duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
210 
211 			// End point vertices.
212 			dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
213 			dd->vertex(con->pos[0],con->pos[1]+0.2f,con->pos[2], duRGBA(0,48,64,196));
214 
215 			dd->vertex(con->pos[3],con->pos[4],con->pos[5], duRGBA(0,48,64,196));
216 			dd->vertex(con->pos[3],con->pos[4]+0.2f,con->pos[5], duRGBA(0,48,64,196));
217 
218 			// Connection arc.
219 			duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
220 						(con->flags & 1) ? 0.6f : 0, 0.6f, col);
221 		}
222 		dd->end();
223 	}
224 
225 	const unsigned int vcol = duRGBA(0,0,0,196);
226 	dd->begin(DU_DRAW_POINTS, 3.0f);
227 	for (int i = 0; i < tile->header->vertCount; ++i)
228 	{
229 		const float* v = &tile->verts[i*3];
230 		dd->vertex(v[0], v[1], v[2], vcol);
231 	}
232 	dd->end();
233 
234 	dd->depthMask(true);
235 }
236 
duDebugDrawNavMesh(duDebugDraw * dd,const dtNavMesh & mesh,unsigned char flags)237 void duDebugDrawNavMesh(duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags)
238 {
239 	if (!dd) return;
240 
241 	for (int i = 0; i < mesh.getMaxTiles(); ++i)
242 	{
243 		const dtMeshTile* tile = mesh.getTile(i);
244 		if (!tile->header) continue;
245 		drawMeshTile(dd, mesh, 0, tile, flags);
246 	}
247 }
248 
duDebugDrawNavMeshWithClosedList(struct duDebugDraw * dd,const dtNavMesh & mesh,const dtNavMeshQuery & query,unsigned char flags)249 void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags)
250 {
251 	if (!dd) return;
252 
253 	const dtNavMeshQuery* q = (flags & DU_DRAWNAVMESH_CLOSEDLIST) ? &query : 0;
254 
255 	for (int i = 0; i < mesh.getMaxTiles(); ++i)
256 	{
257 		const dtMeshTile* tile = mesh.getTile(i);
258 		if (!tile->header) continue;
259 		drawMeshTile(dd, mesh, q, tile, flags);
260 	}
261 }
262 
duDebugDrawNavMeshNodes(struct duDebugDraw * dd,const dtNavMeshQuery & query)263 void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query)
264 {
265 	if (!dd) return;
266 
267 	const dtNodePool* pool = query.getNodePool();
268 	if (pool)
269 	{
270 		const float off = 0.5f;
271 		dd->begin(DU_DRAW_POINTS, 4.0f);
272 		for (int i = 0; i < pool->getHashSize(); ++i)
273 		{
274 			for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
275 			{
276 				const dtNode* node = pool->getNodeAtIdx(j+1);
277 				if (!node) continue;
278 				dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,255));
279 			}
280 		}
281 		dd->end();
282 
283 		dd->begin(DU_DRAW_LINES, 2.0f);
284 		for (int i = 0; i < pool->getHashSize(); ++i)
285 		{
286 			for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
287 			{
288 				const dtNode* node = pool->getNodeAtIdx(j+1);
289 				if (!node) continue;
290 				if (!node->pidx) continue;
291 				const dtNode* parent = pool->getNodeAtIdx(node->pidx);
292 				if (!parent) continue;
293 				dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,128));
294 				dd->vertex(parent->pos[0],parent->pos[1]+off,parent->pos[2], duRGBA(255,192,0,128));
295 			}
296 		}
297 		dd->end();
298 	}
299 }
300 
301 
drawMeshTileBVTree(duDebugDraw * dd,const dtMeshTile * tile)302 static void drawMeshTileBVTree(duDebugDraw* dd, const dtMeshTile* tile)
303 {
304 	// Draw BV nodes.
305 	const float cs = 1.0f / tile->header->bvQuantFactor;
306 	dd->begin(DU_DRAW_LINES, 1.0f);
307 	for (int i = 0; i < tile->header->bvNodeCount; ++i)
308 	{
309 		const dtBVNode* n = &tile->bvTree[i];
310 		if (n->i < 0) // Leaf indices are positive.
311 			continue;
312 		duAppendBoxWire(dd, tile->header->bmin[0] + n->bmin[0]*cs,
313 						tile->header->bmin[1] + n->bmin[1]*cs,
314 						tile->header->bmin[2] + n->bmin[2]*cs,
315 						tile->header->bmin[0] + n->bmax[0]*cs,
316 						tile->header->bmin[1] + n->bmax[1]*cs,
317 						tile->header->bmin[2] + n->bmax[2]*cs,
318 						duRGBA(255,255,255,128));
319 	}
320 	dd->end();
321 }
322 
duDebugDrawNavMeshBVTree(duDebugDraw * dd,const dtNavMesh & mesh)323 void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
324 {
325 	if (!dd) return;
326 
327 	for (int i = 0; i < mesh.getMaxTiles(); ++i)
328 	{
329 		const dtMeshTile* tile = mesh.getTile(i);
330 		if (!tile->header) continue;
331 		drawMeshTileBVTree(dd, tile);
332 	}
333 }
334 
drawMeshTilePortal(duDebugDraw * dd,const dtMeshTile * tile)335 static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
336 {
337 	// Draw portals
338 	const float padx = 0.04f;
339 	const float pady = tile->header->walkableClimb;
340 
341 	dd->begin(DU_DRAW_LINES, 2.0f);
342 
343 	for (int side = 0; side < 8; ++side)
344 	{
345 		unsigned short m = DT_EXT_LINK | (unsigned short)side;
346 
347 		for (int i = 0; i < tile->header->polyCount; ++i)
348 		{
349 			dtPoly* poly = &tile->polys[i];
350 
351 			// Create new links.
352 			const int nv = poly->vertCount;
353 			for (int j = 0; j < nv; ++j)
354 			{
355 				// Skip edges which do not point to the right side.
356 				if (poly->neis[j] != m)
357 					continue;
358 
359 				// Create new links
360 				const float* va = &tile->verts[poly->verts[j]*3];
361 				const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
362 
363 				if (side == 0 || side == 4)
364 				{
365 					unsigned int col = side == 0 ? duRGBA(128,0,0,128) : duRGBA(128,0,128,128);
366 
367 					const float x = va[0] + ((side == 0) ? -padx : padx);
368 
369 					dd->vertex(x,va[1]-pady,va[2], col);
370 					dd->vertex(x,va[1]+pady,va[2], col);
371 
372 					dd->vertex(x,va[1]+pady,va[2], col);
373 					dd->vertex(x,vb[1]+pady,vb[2], col);
374 
375 					dd->vertex(x,vb[1]+pady,vb[2], col);
376 					dd->vertex(x,vb[1]-pady,vb[2], col);
377 
378 					dd->vertex(x,vb[1]-pady,vb[2], col);
379 					dd->vertex(x,va[1]-pady,va[2], col);
380 				}
381 				else if (side == 2 || side == 6)
382 				{
383 					unsigned int col = side == 2 ? duRGBA(0,128,0,128) : duRGBA(0,128,128,128);
384 
385 					const float z = va[2] + ((side == 2) ? -padx : padx);
386 
387 					dd->vertex(va[0],va[1]-pady,z, col);
388 					dd->vertex(va[0],va[1]+pady,z, col);
389 
390 					dd->vertex(va[0],va[1]+pady,z, col);
391 					dd->vertex(vb[0],vb[1]+pady,z, col);
392 
393 					dd->vertex(vb[0],vb[1]+pady,z, col);
394 					dd->vertex(vb[0],vb[1]-pady,z, col);
395 
396 					dd->vertex(vb[0],vb[1]-pady,z, col);
397 					dd->vertex(va[0],va[1]-pady,z, col);
398 				}
399 
400 			}
401 		}
402 	}
403 
404 	dd->end();
405 }
406 
duDebugDrawNavMeshPortals(duDebugDraw * dd,const dtNavMesh & mesh)407 void duDebugDrawNavMeshPortals(duDebugDraw* dd, const dtNavMesh& mesh)
408 {
409 	if (!dd) return;
410 
411 	for (int i = 0; i < mesh.getMaxTiles(); ++i)
412 	{
413 		const dtMeshTile* tile = mesh.getTile(i);
414 		if (!tile->header) continue;
415 		drawMeshTilePortal(dd, tile);
416 	}
417 }
418 
duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw * dd,const dtNavMesh & mesh,const unsigned short polyFlags,const unsigned int col)419 void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh,
420 									  const unsigned short polyFlags, const unsigned int col)
421 {
422 	if (!dd) return;
423 
424 	for (int i = 0; i < mesh.getMaxTiles(); ++i)
425 	{
426 		const dtMeshTile* tile = mesh.getTile(i);
427 		if (!tile->header) continue;
428 		dtPolyRef base = mesh.getPolyRefBase(tile);
429 
430 		for (int j = 0; j < tile->header->polyCount; ++j)
431 		{
432 			const dtPoly* p = &tile->polys[j];
433 			if ((p->flags & polyFlags) == 0) continue;
434 			duDebugDrawNavMeshPoly(dd, mesh, base|(dtPolyRef)j, col);
435 		}
436 	}
437 }
438 
duDebugDrawNavMeshPoly(duDebugDraw * dd,const dtNavMesh & mesh,dtPolyRef ref,const unsigned int col)439 void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
440 {
441 	if (!dd) return;
442 
443 	const dtMeshTile* tile = 0;
444 	const dtPoly* poly = 0;
445 	if (dtStatusFailed(mesh.getTileAndPolyByRef(ref, &tile, &poly)))
446 		return;
447 
448 	dd->depthMask(false);
449 
450 	const unsigned int c = duTransCol(col, 64);
451 	const unsigned int ip = (unsigned int)(poly - tile->polys);
452 
453 	if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
454 	{
455 		dtOffMeshConnection* con = &tile->offMeshCons[ip - tile->header->offMeshBase];
456 
457 		dd->begin(DU_DRAW_LINES, 2.0f);
458 
459 		// Connection arc.
460 		duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
461 					(con->flags & 1) ? 0.6f : 0.0f, 0.6f, c);
462 
463 		dd->end();
464 	}
465 	else
466 	{
467 		const dtPolyDetail* pd = &tile->detailMeshes[ip];
468 
469 		dd->begin(DU_DRAW_TRIS);
470 		for (int i = 0; i < pd->triCount; ++i)
471 		{
472 			const unsigned char* t = &tile->detailTris[(pd->triBase+i)*4];
473 			for (int j = 0; j < 3; ++j)
474 			{
475 				if (t[j] < poly->vertCount)
476 					dd->vertex(&tile->verts[poly->verts[t[j]]*3], c);
477 				else
478 					dd->vertex(&tile->detailVerts[(pd->vertBase+t[j]-poly->vertCount)*3], c);
479 			}
480 		}
481 		dd->end();
482 	}
483 
484 	dd->depthMask(true);
485 
486 }
487 
debugDrawTileCachePortals(struct duDebugDraw * dd,const dtTileCacheLayer & layer,const float cs,const float ch)488 static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
489 {
490 	const int w = (int)layer.header->width;
491 	const int h = (int)layer.header->height;
492 	const float* bmin = layer.header->bmin;
493 
494 	// Portals
495 	unsigned int pcol = duRGBA(255,255,255,255);
496 
497 	const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
498 
499 	// Layer portals
500 	dd->begin(DU_DRAW_LINES, 2.0f);
501 	for (int y = 0; y < h; ++y)
502 	{
503 		for (int x = 0; x < w; ++x)
504 		{
505 			const int idx = x+y*w;
506 			const int lh = (int)layer.heights[idx];
507 			if (lh == 0xff) continue;
508 
509 			for (int dir = 0; dir < 4; ++dir)
510 			{
511 				if (layer.cons[idx] & (1<<(dir+4)))
512 				{
513 					const int* seg = &segs[dir*4];
514 					const float ax = bmin[0] + (x+seg[0])*cs;
515 					const float ay = bmin[1] + (lh+2)*ch;
516 					const float az = bmin[2] + (y+seg[1])*cs;
517 					const float bx = bmin[0] + (x+seg[2])*cs;
518 					const float by = bmin[1] + (lh+2)*ch;
519 					const float bz = bmin[2] + (y+seg[3])*cs;
520 					dd->vertex(ax, ay, az, pcol);
521 					dd->vertex(bx, by, bz, pcol);
522 				}
523 			}
524 		}
525 	}
526 	dd->end();
527 }
528 
duDebugDrawTileCacheLayerAreas(struct duDebugDraw * dd,const dtTileCacheLayer & layer,const float cs,const float ch)529 void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
530 {
531 	const int w = (int)layer.header->width;
532 	const int h = (int)layer.header->height;
533 	const float* bmin = layer.header->bmin;
534 	const float* bmax = layer.header->bmax;
535 	const int idx = layer.header->tlayer;
536 
537 	unsigned int color = duIntToCol(idx+1, 255);
538 
539 	// Layer bounds
540 	float lbmin[3], lbmax[3];
541 	lbmin[0] = bmin[0] + layer.header->minx*cs;
542 	lbmin[1] = bmin[1];
543 	lbmin[2] = bmin[2] + layer.header->miny*cs;
544 	lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
545 	lbmax[1] = bmax[1];
546 	lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
547 	duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
548 
549 	// Layer height
550 	dd->begin(DU_DRAW_QUADS);
551 	for (int y = 0; y < h; ++y)
552 	{
553 		for (int x = 0; x < w; ++x)
554 		{
555 			const int lidx = x+y*w;
556 			const int lh = (int)layer.heights[lidx];
557 			if (lh == 0xff) continue;
558 
559 			const unsigned char area = layer.areas[lidx];
560 			unsigned int col;
561 			if (area == 63)
562 				col = duLerpCol(color, duRGBA(0,192,255,64), 32);
563 			else if (area == 0)
564 				col = duLerpCol(color, duRGBA(0,0,0,64), 32);
565 			else
566 				col = duLerpCol(color, dd->areaToCol(area), 32);
567 
568 			const float fx = bmin[0] + x*cs;
569 			const float fy = bmin[1] + (lh+1)*ch;
570 			const float fz = bmin[2] + y*cs;
571 
572 			dd->vertex(fx, fy, fz, col);
573 			dd->vertex(fx, fy, fz+cs, col);
574 			dd->vertex(fx+cs, fy, fz+cs, col);
575 			dd->vertex(fx+cs, fy, fz, col);
576 		}
577 	}
578 	dd->end();
579 
580 	debugDrawTileCachePortals(dd, layer, cs, ch);
581 }
582 
duDebugDrawTileCacheLayerRegions(struct duDebugDraw * dd,const dtTileCacheLayer & layer,const float cs,const float ch)583 void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
584 {
585 	const int w = (int)layer.header->width;
586 	const int h = (int)layer.header->height;
587 	const float* bmin = layer.header->bmin;
588 	const float* bmax = layer.header->bmax;
589 	const int idx = layer.header->tlayer;
590 
591 	unsigned int color = duIntToCol(idx+1, 255);
592 
593 	// Layer bounds
594 	float lbmin[3], lbmax[3];
595 	lbmin[0] = bmin[0] + layer.header->minx*cs;
596 	lbmin[1] = bmin[1];
597 	lbmin[2] = bmin[2] + layer.header->miny*cs;
598 	lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
599 	lbmax[1] = bmax[1];
600 	lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
601 	duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
602 
603 	// Layer height
604 	dd->begin(DU_DRAW_QUADS);
605 	for (int y = 0; y < h; ++y)
606 	{
607 		for (int x = 0; x < w; ++x)
608 		{
609 			const int lidx = x+y*w;
610 			const int lh = (int)layer.heights[lidx];
611 			if (lh == 0xff) continue;
612 			const unsigned char reg = layer.regs[lidx];
613 
614 			unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192);
615 
616 			const float fx = bmin[0] + x*cs;
617 			const float fy = bmin[1] + (lh+1)*ch;
618 			const float fz = bmin[2] + y*cs;
619 
620 			dd->vertex(fx, fy, fz, col);
621 			dd->vertex(fx, fy, fz+cs, col);
622 			dd->vertex(fx+cs, fy, fz+cs, col);
623 			dd->vertex(fx+cs, fy, fz, col);
624 		}
625 	}
626 	dd->end();
627 
628 	debugDrawTileCachePortals(dd, layer, cs, ch);
629 }
630 
631 
632 
633 
634 /*struct dtTileCacheContour
635 {
636 	int nverts;
637 	unsigned char* verts;
638 	unsigned char reg;
639 	unsigned char area;
640 };
641 
642 struct dtTileCacheContourSet
643 {
644 	int nconts;
645 	dtTileCacheContour* conts;
646 };*/
647 
duDebugDrawTileCacheContours(duDebugDraw * dd,const struct dtTileCacheContourSet & lcset,const float * orig,const float cs,const float ch)648 void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
649 								  const float* orig, const float cs, const float ch)
650 {
651 	if (!dd) return;
652 
653 	const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
654 
655 	const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
656 
657 	dd->begin(DU_DRAW_LINES, 2.0f);
658 
659 	for (int i = 0; i < lcset.nconts; ++i)
660 	{
661 		const dtTileCacheContour& c = lcset.conts[i];
662 		unsigned int color = 0;
663 
664 		color = duIntToCol(i, a);
665 
666 		for (int j = 0; j < c.nverts; ++j)
667 		{
668 			const int k = (j+1) % c.nverts;
669 			const unsigned char* va = &c.verts[j*4];
670 			const unsigned char* vb = &c.verts[k*4];
671 			const float ax = orig[0] + va[0]*cs;
672 			const float ay = orig[1] + (va[1]+1+(i&1))*ch;
673 			const float az = orig[2] + va[2]*cs;
674 			const float bx = orig[0] + vb[0]*cs;
675 			const float by = orig[1] + (vb[1]+1+(i&1))*ch;
676 			const float bz = orig[2] + vb[2]*cs;
677 			unsigned int col = color;
678 			if ((va[3] & 0xf) != 0xf)
679 			{
680 				// Portal segment
681 				col = duRGBA(255,255,255,128);
682 				int d = va[3] & 0xf;
683 
684 				const float cx = (ax+bx)*0.5f;
685 				const float cy = (ay+by)*0.5f;
686 				const float cz = (az+bz)*0.5f;
687 
688 				const float dx = cx + offs[d*2+0]*2*cs;
689 				const float dy = cy;
690 				const float dz = cz + offs[d*2+1]*2*cs;
691 
692 				dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
693 				dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
694 			}
695 
696 			duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
697 		}
698 	}
699 	dd->end();
700 
701 	dd->begin(DU_DRAW_POINTS, 4.0f);
702 
703 	for (int i = 0; i < lcset.nconts; ++i)
704 	{
705 		const dtTileCacheContour& c = lcset.conts[i];
706 		unsigned int color = 0;
707 
708 		for (int j = 0; j < c.nverts; ++j)
709 		{
710 			const unsigned char* va = &c.verts[j*4];
711 
712 			color = duDarkenCol(duIntToCol(i, a));
713 			if (va[3] & 0x80)
714 			{
715 				// Border vertex
716 				color = duRGBA(255,0,0,255);
717 			}
718 
719 			float fx = orig[0] + va[0]*cs;
720 			float fy = orig[1] + (va[1]+1+(i&1))*ch;
721 			float fz = orig[2] + va[2]*cs;
722 			dd->vertex(fx,fy,fz, color);
723 		}
724 	}
725 	dd->end();
726 }
727 
duDebugDrawTileCachePolyMesh(duDebugDraw * dd,const struct dtTileCachePolyMesh & lmesh,const float * orig,const float cs,const float ch)728 void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
729 								  const float* orig, const float cs, const float ch)
730 {
731 	if (!dd) return;
732 
733 	const int nvp = lmesh.nvp;
734 
735 	const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
736 
737 	dd->begin(DU_DRAW_TRIS);
738 
739 	for (int i = 0; i < lmesh.npolys; ++i)
740 	{
741 		const unsigned short* p = &lmesh.polys[i*nvp*2];
742 		const unsigned char area = lmesh.areas[i];
743 
744 		unsigned int color;
745 		if (area == DT_TILECACHE_WALKABLE_AREA)
746 			color = duRGBA(0,192,255,64);
747 		else if (area == DT_TILECACHE_NULL_AREA)
748 			color = duRGBA(0,0,0,64);
749 		else
750 			color = dd->areaToCol(area);
751 
752 		unsigned short vi[3];
753 		for (int j = 2; j < nvp; ++j)
754 		{
755 			if (p[j] == DT_TILECACHE_NULL_IDX) break;
756 			vi[0] = p[0];
757 			vi[1] = p[j-1];
758 			vi[2] = p[j];
759 			for (int k = 0; k < 3; ++k)
760 			{
761 				const unsigned short* v = &lmesh.verts[vi[k]*3];
762 				const float x = orig[0] + v[0]*cs;
763 				const float y = orig[1] + (v[1]+1)*ch;
764 				const float z = orig[2] + v[2]*cs;
765 				dd->vertex(x,y,z, color);
766 			}
767 		}
768 	}
769 	dd->end();
770 
771 	// Draw neighbours edges
772 	const unsigned int coln = duRGBA(0,48,64,32);
773 	dd->begin(DU_DRAW_LINES, 1.5f);
774 	for (int i = 0; i < lmesh.npolys; ++i)
775 	{
776 		const unsigned short* p = &lmesh.polys[i*nvp*2];
777 		for (int j = 0; j < nvp; ++j)
778 		{
779 			if (p[j] == DT_TILECACHE_NULL_IDX) break;
780 			if (p[nvp+j] & 0x8000) continue;
781 			const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
782 			int vi[2] = {p[j], p[nj]};
783 
784 			for (int k = 0; k < 2; ++k)
785 			{
786 				const unsigned short* v = &lmesh.verts[vi[k]*3];
787 				const float x = orig[0] + v[0]*cs;
788 				const float y = orig[1] + (v[1]+1)*ch + 0.1f;
789 				const float z = orig[2] + v[2]*cs;
790 				dd->vertex(x, y, z, coln);
791 			}
792 		}
793 	}
794 	dd->end();
795 
796 	// Draw boundary edges
797 	const unsigned int colb = duRGBA(0,48,64,220);
798 	dd->begin(DU_DRAW_LINES, 2.5f);
799 	for (int i = 0; i < lmesh.npolys; ++i)
800 	{
801 		const unsigned short* p = &lmesh.polys[i*nvp*2];
802 		for (int j = 0; j < nvp; ++j)
803 		{
804 			if (p[j] == DT_TILECACHE_NULL_IDX) break;
805 			if ((p[nvp+j] & 0x8000) == 0) continue;
806 			const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
807 			int vi[2] = {p[j], p[nj]};
808 
809 			unsigned int col = colb;
810 			if ((p[nvp+j] & 0xf) != 0xf)
811 			{
812 				const unsigned short* va = &lmesh.verts[vi[0]*3];
813 				const unsigned short* vb = &lmesh.verts[vi[1]*3];
814 
815 				const float ax = orig[0] + va[0]*cs;
816 				const float ay = orig[1] + (va[1]+1+(i&1))*ch;
817 				const float az = orig[2] + va[2]*cs;
818 				const float bx = orig[0] + vb[0]*cs;
819 				const float by = orig[1] + (vb[1]+1+(i&1))*ch;
820 				const float bz = orig[2] + vb[2]*cs;
821 
822 				const float cx = (ax+bx)*0.5f;
823 				const float cy = (ay+by)*0.5f;
824 				const float cz = (az+bz)*0.5f;
825 
826 				int d = p[nvp+j] & 0xf;
827 
828 				const float dx = cx + offs[d*2+0]*2*cs;
829 				const float dy = cy;
830 				const float dz = cz + offs[d*2+1]*2*cs;
831 
832 				dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
833 				dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
834 
835 				col = duRGBA(255,255,255,128);
836 			}
837 
838 			for (int k = 0; k < 2; ++k)
839 			{
840 				const unsigned short* v = &lmesh.verts[vi[k]*3];
841 				const float x = orig[0] + v[0]*cs;
842 				const float y = orig[1] + (v[1]+1)*ch + 0.1f;
843 				const float z = orig[2] + v[2]*cs;
844 				dd->vertex(x, y, z, col);
845 			}
846 		}
847 	}
848 	dd->end();
849 
850 	dd->begin(DU_DRAW_POINTS, 3.0f);
851 	const unsigned int colv = duRGBA(0,0,0,220);
852 	for (int i = 0; i < lmesh.nverts; ++i)
853 	{
854 		const unsigned short* v = &lmesh.verts[i*3];
855 		const float x = orig[0] + v[0]*cs;
856 		const float y = orig[1] + (v[1]+1)*ch + 0.1f;
857 		const float z = orig[2] + v[2]*cs;
858 		dd->vertex(x,y,z, colv);
859 	}
860 	dd->end();
861 }
862 
863 
864 
865