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