forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
612
lib/haxerecast/recastnavigation/DebugUtils/Source/DebugDraw.cpp
Normal file
612
lib/haxerecast/recastnavigation/DebugUtils/Source/DebugDraw.cpp
Normal file
@ -0,0 +1,612 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <string.h>
|
||||
#include "DebugDraw.h"
|
||||
#include "DetourMath.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
|
||||
duDebugDraw::~duDebugDraw()
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
unsigned int duDebugDraw::areaToCol(unsigned int area)
|
||||
{
|
||||
if (area == 0)
|
||||
{
|
||||
// Treat zero area type as default.
|
||||
return duRGBA(0, 192, 255, 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
return duIntToCol(area, 255);
|
||||
}
|
||||
}
|
||||
|
||||
inline int bit(int a, int b)
|
||||
{
|
||||
return (a & (1 << b)) >> b;
|
||||
}
|
||||
|
||||
unsigned int duIntToCol(int i, int a)
|
||||
{
|
||||
int r = bit(i, 1) + bit(i, 3) * 2 + 1;
|
||||
int g = bit(i, 2) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 0) + bit(i, 5) * 2 + 1;
|
||||
return duRGBA(r*63,g*63,b*63,a);
|
||||
}
|
||||
|
||||
void duIntToCol(int i, float* col)
|
||||
{
|
||||
int r = bit(i, 0) + bit(i, 3) * 2 + 1;
|
||||
int g = bit(i, 1) + bit(i, 4) * 2 + 1;
|
||||
int b = bit(i, 2) + bit(i, 5) * 2 + 1;
|
||||
col[0] = 1 - r*63.0f/255.0f;
|
||||
col[1] = 1 - g*63.0f/255.0f;
|
||||
col[2] = 1 - b*63.0f/255.0f;
|
||||
}
|
||||
|
||||
void duCalcBoxColors(unsigned int* colors, unsigned int colTop, unsigned int colSide)
|
||||
{
|
||||
if (!colors) return;
|
||||
|
||||
colors[0] = duMultCol(colTop, 250);
|
||||
colors[1] = duMultCol(colSide, 140);
|
||||
colors[2] = duMultCol(colSide, 165);
|
||||
colors[3] = duMultCol(colSide, 217);
|
||||
colors[4] = duMultCol(colSide, 165);
|
||||
colors[5] = duMultCol(colSide, 217);
|
||||
}
|
||||
|
||||
void duDebugDrawCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCylinderWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendBoxWire(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendArc(dd, x0,y0,z0, x1,y1,z1, h, as0, as1, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendArrow(dd, x0,y0,z0, x1,y1,z1, as0, as1, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCircle(dd, x,y,z, r, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float size, unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
duAppendCross(dd, x,y,z, size, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
duAppendCylinder(dd, minx,miny,minz, maxx,maxy,maxz, col);
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
|
||||
const int w, const int h, const float size,
|
||||
const unsigned int col, const float lineWidth)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, lineWidth);
|
||||
for (int i = 0; i <= h; ++i)
|
||||
{
|
||||
dd->vertex(ox,oy,oz+i*size, col);
|
||||
dd->vertex(ox+w*size,oy,oz+i*size, col);
|
||||
}
|
||||
for (int i = 0; i <= w; ++i)
|
||||
{
|
||||
dd->vertex(ox+i*size,oy,oz, col);
|
||||
dd->vertex(ox+i*size,oy,oz+h*size, col);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
|
||||
void duAppendCylinderWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
static const int NUM_SEG = 16;
|
||||
static float dir[NUM_SEG*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = dtMathCosf(a);
|
||||
dir[i*2+1] = dtMathSinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
const float cx = (maxx + minx)/2;
|
||||
const float cz = (maxz + minz)/2;
|
||||
const float rx = (maxx - minx)/2;
|
||||
const float rz = (maxz - minz)/2;
|
||||
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
for (int i = 0; i < NUM_SEG; i += NUM_SEG/4)
|
||||
{
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendBoxWire(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
// Top
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
|
||||
// bottom
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
|
||||
// Sides
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
}
|
||||
|
||||
void duAppendBoxPoints(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
// Top
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, minz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(maxx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, maxz, col);
|
||||
dd->vertex(minx, miny, minz, col);
|
||||
|
||||
// bottom
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, minz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(maxx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, maxz, col);
|
||||
dd->vertex(minx, maxy, minz, col);
|
||||
}
|
||||
|
||||
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, const unsigned int* fcol)
|
||||
{
|
||||
if (!dd) return;
|
||||
const float verts[8*3] =
|
||||
{
|
||||
minx, miny, minz,
|
||||
maxx, miny, minz,
|
||||
maxx, miny, maxz,
|
||||
minx, miny, maxz,
|
||||
minx, maxy, minz,
|
||||
maxx, maxy, minz,
|
||||
maxx, maxy, maxz,
|
||||
minx, maxy, maxz,
|
||||
};
|
||||
static const unsigned char inds[6*4] =
|
||||
{
|
||||
7, 6, 5, 4,
|
||||
0, 1, 2, 3,
|
||||
1, 5, 6, 2,
|
||||
3, 7, 4, 0,
|
||||
2, 6, 7, 3,
|
||||
0, 4, 5, 1,
|
||||
};
|
||||
|
||||
const unsigned char* in = inds;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
dd->vertex(&verts[*in*3], fcol[i]); in++;
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
|
||||
float maxx, float maxy, float maxz, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
static const int NUM_SEG = 16;
|
||||
static float dir[NUM_SEG*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = cosf(a);
|
||||
dir[i*2+1] = sinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int col2 = duMultCol(col, 160);
|
||||
|
||||
const float cx = (maxx + minx)/2;
|
||||
const float cz = (maxz + minz)/2;
|
||||
const float rx = (maxx - minx)/2;
|
||||
const float rz = (maxz - minz)/2;
|
||||
|
||||
for (int i = 2; i < NUM_SEG; ++i)
|
||||
{
|
||||
const int a = 0, b = i-1, c = i;
|
||||
dd->vertex(cx+dir[a*2+0]*rx, miny, cz+dir[a*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[b*2+0]*rx, miny, cz+dir[b*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[c*2+0]*rx, miny, cz+dir[c*2+1]*rz, col2);
|
||||
}
|
||||
for (int i = 2; i < NUM_SEG; ++i)
|
||||
{
|
||||
const int a = 0, b = i, c = i-1;
|
||||
dd->vertex(cx+dir[a*2+0]*rx, maxy, cz+dir[a*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[b*2+0]*rx, maxy, cz+dir[b*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[c*2+0]*rx, maxy, cz+dir[c*2+1]*rz, col);
|
||||
}
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
|
||||
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
|
||||
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
|
||||
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void evalArc(const float x0, const float y0, const float z0,
|
||||
const float dx, const float dy, const float dz,
|
||||
const float h, const float u, float* res)
|
||||
{
|
||||
res[0] = x0 + dx * u;
|
||||
res[1] = y0 + dy * u + h * (1-(u*2-1)*(u*2-1));
|
||||
res[2] = z0 + dz * u;
|
||||
}
|
||||
|
||||
|
||||
inline void vcross(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
inline void vnormalize(float* v)
|
||||
{
|
||||
float d = 1.0f / sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
||||
v[0] *= d;
|
||||
v[1] *= d;
|
||||
v[2] *= d;
|
||||
}
|
||||
|
||||
inline void vsub(float* dest, const float* v1, const float* v2)
|
||||
{
|
||||
dest[0] = v1[0]-v2[0];
|
||||
dest[1] = v1[1]-v2[1];
|
||||
dest[2] = v1[2]-v2[2];
|
||||
}
|
||||
|
||||
inline float vdistSqr(const float* v1, const float* v2)
|
||||
{
|
||||
const float x = v1[0]-v2[0];
|
||||
const float y = v1[1]-v2[1];
|
||||
const float z = v1[2]-v2[2];
|
||||
return x*x + y*y + z*z;
|
||||
}
|
||||
|
||||
|
||||
void appendArrowHead(struct duDebugDraw* dd, const float* p, const float* q,
|
||||
const float s, unsigned int col)
|
||||
{
|
||||
const float eps = 0.001f;
|
||||
if (!dd) return;
|
||||
if (vdistSqr(p,q) < eps*eps) return;
|
||||
float ax[3], ay[3] = {0,1,0}, az[3];
|
||||
vsub(az, q, p);
|
||||
vnormalize(az);
|
||||
vcross(ax, ay, az);
|
||||
vcross(ay, az, ax);
|
||||
vnormalize(ay);
|
||||
|
||||
dd->vertex(p, col);
|
||||
// dd->vertex(p[0]+az[0]*s+ay[0]*s/2, p[1]+az[1]*s+ay[1]*s/2, p[2]+az[2]*s+ay[2]*s/2, col);
|
||||
dd->vertex(p[0]+az[0]*s+ax[0]*s/3, p[1]+az[1]*s+ax[1]*s/3, p[2]+az[2]*s+ax[2]*s/3, col);
|
||||
|
||||
dd->vertex(p, col);
|
||||
// dd->vertex(p[0]+az[0]*s-ay[0]*s/2, p[1]+az[1]*s-ay[1]*s/2, p[2]+az[2]*s-ay[2]*s/2, col);
|
||||
dd->vertex(p[0]+az[0]*s-ax[0]*s/3, p[1]+az[1]*s-ax[1]*s/3, p[2]+az[2]*s-ax[2]*s/3, col);
|
||||
|
||||
}
|
||||
|
||||
void duAppendArc(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1, const float h,
|
||||
const float as0, const float as1, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
static const int NUM_ARC_PTS = 8;
|
||||
static const float PAD = 0.05f;
|
||||
static const float ARC_PTS_SCALE = (1.0f-PAD*2) / (float)NUM_ARC_PTS;
|
||||
const float dx = x1 - x0;
|
||||
const float dy = y1 - y0;
|
||||
const float dz = z1 - z0;
|
||||
const float len = sqrtf(dx*dx + dy*dy + dz*dz);
|
||||
float prev[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, prev);
|
||||
for (int i = 1; i <= NUM_ARC_PTS; ++i)
|
||||
{
|
||||
const float u = PAD + i * ARC_PTS_SCALE;
|
||||
float pt[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, u, pt);
|
||||
dd->vertex(prev[0],prev[1],prev[2], col);
|
||||
dd->vertex(pt[0],pt[1],pt[2], col);
|
||||
prev[0] = pt[0]; prev[1] = pt[1]; prev[2] = pt[2];
|
||||
}
|
||||
|
||||
// End arrows
|
||||
if (as0 > 0.001f)
|
||||
{
|
||||
float p[3], q[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD, p);
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, PAD+0.05f, q);
|
||||
appendArrowHead(dd, p, q, as0, col);
|
||||
}
|
||||
|
||||
if (as1 > 0.001f)
|
||||
{
|
||||
float p[3], q[3];
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-PAD, p);
|
||||
evalArc(x0,y0,z0, dx,dy,dz, len*h, 1-(PAD+0.05f), q);
|
||||
appendArrowHead(dd, p, q, as1, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendArrow(struct duDebugDraw* dd, const float x0, const float y0, const float z0,
|
||||
const float x1, const float y1, const float z1,
|
||||
const float as0, const float as1, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
dd->vertex(x0,y0,z0, col);
|
||||
dd->vertex(x1,y1,z1, col);
|
||||
|
||||
// End arrows
|
||||
const float p[3] = {x0,y0,z0}, q[3] = {x1,y1,z1};
|
||||
if (as0 > 0.001f)
|
||||
appendArrowHead(dd, p, q, as0, col);
|
||||
if (as1 > 0.001f)
|
||||
appendArrowHead(dd, q, p, as1, col);
|
||||
}
|
||||
|
||||
void duAppendCircle(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float r, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
static const int NUM_SEG = 40;
|
||||
static float dir[40*2];
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
for (int i = 0; i < NUM_SEG; ++i)
|
||||
{
|
||||
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
|
||||
dir[i*2] = cosf(a);
|
||||
dir[i*2+1] = sinf(a);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
|
||||
{
|
||||
dd->vertex(x+dir[j*2+0]*r, y, z+dir[j*2+1]*r, col);
|
||||
dd->vertex(x+dir[i*2+0]*r, y, z+dir[i*2+1]*r, col);
|
||||
}
|
||||
}
|
||||
|
||||
void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const float z,
|
||||
const float s, unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
dd->vertex(x-s,y,z, col);
|
||||
dd->vertex(x+s,y,z, col);
|
||||
dd->vertex(x,y-s,z, col);
|
||||
dd->vertex(x,y+s,z, col);
|
||||
dd->vertex(x,y,z-s, col);
|
||||
dd->vertex(x,y,z+s, col);
|
||||
}
|
||||
|
||||
duDisplayList::duDisplayList(int cap) :
|
||||
m_pos(0),
|
||||
m_color(0),
|
||||
m_size(0),
|
||||
m_cap(0),
|
||||
m_depthMask(true),
|
||||
m_prim(DU_DRAW_LINES),
|
||||
m_primSize(1.0f)
|
||||
{
|
||||
if (cap < 8)
|
||||
cap = 8;
|
||||
resize(cap);
|
||||
}
|
||||
|
||||
duDisplayList::~duDisplayList()
|
||||
{
|
||||
delete [] m_pos;
|
||||
delete [] m_color;
|
||||
}
|
||||
|
||||
void duDisplayList::resize(int cap)
|
||||
{
|
||||
float* newPos = new float[cap*3];
|
||||
if (m_size)
|
||||
memcpy(newPos, m_pos, sizeof(float)*3*m_size);
|
||||
delete [] m_pos;
|
||||
m_pos = newPos;
|
||||
|
||||
unsigned int* newColor = new unsigned int[cap];
|
||||
if (m_size)
|
||||
memcpy(newColor, m_color, sizeof(unsigned int)*m_size);
|
||||
delete [] m_color;
|
||||
m_color = newColor;
|
||||
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
void duDisplayList::clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void duDisplayList::depthMask(bool state)
|
||||
{
|
||||
m_depthMask = state;
|
||||
}
|
||||
|
||||
void duDisplayList::begin(duDebugDrawPrimitives prim, float size)
|
||||
{
|
||||
clear();
|
||||
m_prim = prim;
|
||||
m_primSize = size;
|
||||
}
|
||||
|
||||
void duDisplayList::vertex(const float x, const float y, const float z, unsigned int color)
|
||||
{
|
||||
if (m_size+1 >= m_cap)
|
||||
resize(m_cap*2);
|
||||
float* p = &m_pos[m_size*3];
|
||||
p[0] = x;
|
||||
p[1] = y;
|
||||
p[2] = z;
|
||||
m_color[m_size] = color;
|
||||
m_size++;
|
||||
}
|
||||
|
||||
void duDisplayList::vertex(const float* pos, unsigned int color)
|
||||
{
|
||||
vertex(pos[0],pos[1],pos[2],color);
|
||||
}
|
||||
|
||||
void duDisplayList::end()
|
||||
{
|
||||
}
|
||||
|
||||
void duDisplayList::draw(struct duDebugDraw* dd)
|
||||
{
|
||||
if (!dd) return;
|
||||
if (!m_size) return;
|
||||
dd->depthMask(m_depthMask);
|
||||
dd->begin(m_prim, m_primSize);
|
||||
for (int i = 0; i < m_size; ++i)
|
||||
dd->vertex(&m_pos[i*3], m_color[i]);
|
||||
dd->end();
|
||||
}
|
@ -0,0 +1,864 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#include "DebugDraw.h"
|
||||
#include "DetourDebugDraw.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourCommon.h"
|
||||
#include "DetourNode.h"
|
||||
|
||||
|
||||
static float distancePtLine2d(const float* pt, const float* p, const float* q)
|
||||
{
|
||||
float pqx = q[0] - p[0];
|
||||
float pqz = q[2] - p[2];
|
||||
float dx = pt[0] - p[0];
|
||||
float dz = pt[2] - p[2];
|
||||
float d = pqx*pqx + pqz*pqz;
|
||||
float t = pqx*dx + pqz*dz;
|
||||
if (d != 0) t /= d;
|
||||
dx = p[0] + t*pqx - pt[0];
|
||||
dz = p[2] + t*pqz - pt[2];
|
||||
return dx*dx + dz*dz;
|
||||
}
|
||||
|
||||
static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
|
||||
const unsigned int col, const float linew,
|
||||
bool inner)
|
||||
{
|
||||
static const float thr = 0.01f*0.01f;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, linew);
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
for (int j = 0, nj = (int)p->vertCount; j < nj; ++j)
|
||||
{
|
||||
unsigned int c = col;
|
||||
if (inner)
|
||||
{
|
||||
if (p->neis[j] == 0) continue;
|
||||
if (p->neis[j] & DT_EXT_LINK)
|
||||
{
|
||||
bool con = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == j)
|
||||
{
|
||||
con = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (con)
|
||||
c = duRGBA(255,255,255,48);
|
||||
else
|
||||
c = duRGBA(0,0,0,48);
|
||||
}
|
||||
else
|
||||
c = duRGBA(0,48,64,32);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p->neis[j] != 0) continue;
|
||||
}
|
||||
|
||||
const float* v0 = &tile->verts[p->verts[j]*3];
|
||||
const float* v1 = &tile->verts[p->verts[(j+1) % nj]*3];
|
||||
|
||||
// Draw detail mesh edges which align with the actual poly edge.
|
||||
// This is really slow.
|
||||
for (int k = 0; k < pd->triCount; ++k)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+k)*4];
|
||||
const float* tv[3];
|
||||
for (int m = 0; m < 3; ++m)
|
||||
{
|
||||
if (t[m] < p->vertCount)
|
||||
tv[m] = &tile->verts[p->verts[t[m]]*3];
|
||||
else
|
||||
tv[m] = &tile->detailVerts[(pd->vertBase+(t[m]-p->vertCount))*3];
|
||||
}
|
||||
for (int m = 0, n = 2; m < 3; n=m++)
|
||||
{
|
||||
if ((dtGetDetailTriEdgeFlags(t[3], n) & DT_DETAIL_EDGE_BOUNDARY) == 0)
|
||||
continue;
|
||||
|
||||
if (distancePtLine2d(tv[n],v0,v1) < thr &&
|
||||
distancePtLine2d(tv[m],v0,v1) < thr)
|
||||
{
|
||||
dd->vertex(tv[n], c);
|
||||
dd->vertex(tv[m], c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery* query,
|
||||
const dtMeshTile* tile, unsigned char flags)
|
||||
{
|
||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||
|
||||
int tileNum = mesh.decodePolyIdTile(base);
|
||||
const unsigned int tileColor = duIntToCol(tileNum, 128);
|
||||
|
||||
dd->depthMask(false);
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links.
|
||||
continue;
|
||||
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[i];
|
||||
|
||||
unsigned int col;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,64);
|
||||
else
|
||||
{
|
||||
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
|
||||
col = tileColor;
|
||||
else
|
||||
col = duTransCol(dd->areaToCol(p->getArea()), 64);
|
||||
}
|
||||
|
||||
for (int j = 0; j < pd->triCount; ++j)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
if (t[k] < p->vertCount)
|
||||
dd->vertex(&tile->verts[p->verts[t[k]]*3], col);
|
||||
else
|
||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[k]-p->vertCount)*3], col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw inter poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,32), 1.5f, true);
|
||||
|
||||
// Draw outer poly boundaries
|
||||
drawPolyBoundaries(dd, tile, duRGBA(0,48,64,220), 2.5f, false);
|
||||
|
||||
if (flags & DU_DRAWNAVMESH_OFFMESHCONS)
|
||||
{
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
if (p->getType() != DT_POLYTYPE_OFFMESH_CONNECTION) // Skip regular polys.
|
||||
continue;
|
||||
|
||||
unsigned int col, col2;
|
||||
if (query && query->isInClosedList(base | (dtPolyRef)i))
|
||||
col = duRGBA(255,196,0,220);
|
||||
else
|
||||
col = duDarkenCol(duTransCol(dd->areaToCol(p->getArea()), 220));
|
||||
|
||||
const dtOffMeshConnection* con = &tile->offMeshCons[i - tile->header->offMeshBase];
|
||||
const float* va = &tile->verts[p->verts[0]*3];
|
||||
const float* vb = &tile->verts[p->verts[1]*3];
|
||||
|
||||
// Check to see if start and end end-points have links.
|
||||
bool startSet = false;
|
||||
bool endSet = false;
|
||||
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
|
||||
{
|
||||
if (tile->links[k].edge == 0)
|
||||
startSet = true;
|
||||
if (tile->links[k].edge == 1)
|
||||
endSet = true;
|
||||
}
|
||||
|
||||
// End points and their on-mesh locations.
|
||||
dd->vertex(va[0],va[1],va[2], col);
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
|
||||
col2 = startSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, col2);
|
||||
|
||||
dd->vertex(vb[0],vb[1],vb[2], col);
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);
|
||||
col2 = endSet ? col : duRGBA(220,32,16,196);
|
||||
duAppendCircle(dd, con->pos[3],con->pos[4]+0.1f,con->pos[5], con->rad, col2);
|
||||
|
||||
// End point vertices.
|
||||
dd->vertex(con->pos[0],con->pos[1],con->pos[2], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[0],con->pos[1]+0.2f,con->pos[2], duRGBA(0,48,64,196));
|
||||
|
||||
dd->vertex(con->pos[3],con->pos[4],con->pos[5], duRGBA(0,48,64,196));
|
||||
dd->vertex(con->pos[3],con->pos[4]+0.2f,con->pos[5], duRGBA(0,48,64,196));
|
||||
|
||||
// Connection arc.
|
||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
||||
(con->flags & 1) ? 0.6f : 0, 0.6f, col);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
const unsigned int vcol = duRGBA(0,0,0,196);
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
for (int i = 0; i < tile->header->vertCount; ++i)
|
||||
{
|
||||
const float* v = &tile->verts[i*3];
|
||||
dd->vertex(v[0], v[1], v[2], vcol);
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->depthMask(true);
|
||||
}
|
||||
|
||||
void duDebugDrawNavMesh(duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTile(dd, mesh, 0, tile, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshWithClosedList(struct duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMeshQuery& query, unsigned char flags)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtNavMeshQuery* q = (flags & DU_DRAWNAVMESH_CLOSEDLIST) ? &query : 0;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTile(dd, mesh, q, tile, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshNodes(struct duDebugDraw* dd, const dtNavMeshQuery& query)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtNodePool* pool = query.getNodePool();
|
||||
if (pool)
|
||||
{
|
||||
const float off = 0.5f;
|
||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||
{
|
||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||
{
|
||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||
if (!node) continue;
|
||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,255));
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int i = 0; i < pool->getHashSize(); ++i)
|
||||
{
|
||||
for (dtNodeIndex j = pool->getFirst(i); j != DT_NULL_IDX; j = pool->getNext(j))
|
||||
{
|
||||
const dtNode* node = pool->getNodeAtIdx(j+1);
|
||||
if (!node) continue;
|
||||
if (!node->pidx) continue;
|
||||
const dtNode* parent = pool->getNodeAtIdx(node->pidx);
|
||||
if (!parent) continue;
|
||||
dd->vertex(node->pos[0],node->pos[1]+off,node->pos[2], duRGBA(255,192,0,128));
|
||||
dd->vertex(parent->pos[0],parent->pos[1]+off,parent->pos[2], duRGBA(255,192,0,128));
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void drawMeshTileBVTree(duDebugDraw* dd, const dtMeshTile* tile)
|
||||
{
|
||||
// Draw BV nodes.
|
||||
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||
dd->begin(DU_DRAW_LINES, 1.0f);
|
||||
for (int i = 0; i < tile->header->bvNodeCount; ++i)
|
||||
{
|
||||
const dtBVNode* n = &tile->bvTree[i];
|
||||
if (n->i < 0) // Leaf indices are positive.
|
||||
continue;
|
||||
duAppendBoxWire(dd, tile->header->bmin[0] + n->bmin[0]*cs,
|
||||
tile->header->bmin[1] + n->bmin[1]*cs,
|
||||
tile->header->bmin[2] + n->bmin[2]*cs,
|
||||
tile->header->bmin[0] + n->bmax[0]*cs,
|
||||
tile->header->bmin[1] + n->bmax[1]*cs,
|
||||
tile->header->bmin[2] + n->bmax[2]*cs,
|
||||
duRGBA(255,255,255,128));
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTileBVTree(dd, tile);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
|
||||
{
|
||||
// Draw portals
|
||||
const float padx = 0.04f;
|
||||
const float pady = tile->header->walkableClimb;
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
for (int side = 0; side < 8; ++side)
|
||||
{
|
||||
unsigned short m = DT_EXT_LINK | (unsigned short)side;
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
dtPoly* poly = &tile->polys[i];
|
||||
|
||||
// Create new links.
|
||||
const int nv = poly->vertCount;
|
||||
for (int j = 0; j < nv; ++j)
|
||||
{
|
||||
// Skip edges which do not point to the right side.
|
||||
if (poly->neis[j] != m)
|
||||
continue;
|
||||
|
||||
// Create new links
|
||||
const float* va = &tile->verts[poly->verts[j]*3];
|
||||
const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
|
||||
|
||||
if (side == 0 || side == 4)
|
||||
{
|
||||
unsigned int col = side == 0 ? duRGBA(128,0,0,128) : duRGBA(128,0,128,128);
|
||||
|
||||
const float x = va[0] + ((side == 0) ? -padx : padx);
|
||||
|
||||
dd->vertex(x,va[1]-pady,va[2], col);
|
||||
dd->vertex(x,va[1]+pady,va[2], col);
|
||||
|
||||
dd->vertex(x,va[1]+pady,va[2], col);
|
||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
||||
|
||||
dd->vertex(x,vb[1]+pady,vb[2], col);
|
||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
||||
|
||||
dd->vertex(x,vb[1]-pady,vb[2], col);
|
||||
dd->vertex(x,va[1]-pady,va[2], col);
|
||||
}
|
||||
else if (side == 2 || side == 6)
|
||||
{
|
||||
unsigned int col = side == 2 ? duRGBA(0,128,0,128) : duRGBA(0,128,128,128);
|
||||
|
||||
const float z = va[2] + ((side == 2) ? -padx : padx);
|
||||
|
||||
dd->vertex(va[0],va[1]-pady,z, col);
|
||||
dd->vertex(va[0],va[1]+pady,z, col);
|
||||
|
||||
dd->vertex(va[0],va[1]+pady,z, col);
|
||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
||||
|
||||
dd->vertex(vb[0],vb[1]+pady,z, col);
|
||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
||||
|
||||
dd->vertex(vb[0],vb[1]-pady,z, col);
|
||||
dd->vertex(va[0],va[1]-pady,z, col);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPortals(duDebugDraw* dd, const dtNavMesh& mesh)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
drawMeshTilePortal(dd, tile);
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPolysWithFlags(struct duDebugDraw* dd, const dtNavMesh& mesh,
|
||||
const unsigned short polyFlags, const unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
for (int i = 0; i < mesh.getMaxTiles(); ++i)
|
||||
{
|
||||
const dtMeshTile* tile = mesh.getTile(i);
|
||||
if (!tile->header) continue;
|
||||
dtPolyRef base = mesh.getPolyRefBase(tile);
|
||||
|
||||
for (int j = 0; j < tile->header->polyCount; ++j)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[j];
|
||||
if ((p->flags & polyFlags) == 0) continue;
|
||||
duDebugDrawNavMeshPoly(dd, mesh, base|(dtPolyRef)j, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
if (dtStatusFailed(mesh.getTileAndPolyByRef(ref, &tile, &poly)))
|
||||
return;
|
||||
|
||||
dd->depthMask(false);
|
||||
|
||||
const unsigned int c = duTransCol(col, 64);
|
||||
const unsigned int ip = (unsigned int)(poly - tile->polys);
|
||||
|
||||
if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
{
|
||||
dtOffMeshConnection* con = &tile->offMeshCons[ip - tile->header->offMeshBase];
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
// Connection arc.
|
||||
duAppendArc(dd, con->pos[0],con->pos[1],con->pos[2], con->pos[3],con->pos[4],con->pos[5], 0.25f,
|
||||
(con->flags & 1) ? 0.6f : 0.0f, 0.6f, c);
|
||||
|
||||
dd->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
const dtPolyDetail* pd = &tile->detailMeshes[ip];
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
for (int i = 0; i < pd->triCount; ++i)
|
||||
{
|
||||
const unsigned char* t = &tile->detailTris[(pd->triBase+i)*4];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
if (t[j] < poly->vertCount)
|
||||
dd->vertex(&tile->verts[poly->verts[t[j]]*3], c);
|
||||
else
|
||||
dd->vertex(&tile->detailVerts[(pd->vertBase+t[j]-poly->vertCount)*3], c);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
dd->depthMask(true);
|
||||
|
||||
}
|
||||
|
||||
static void debugDrawTileCachePortals(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
|
||||
// Portals
|
||||
unsigned int pcol = duRGBA(255,255,255,255);
|
||||
|
||||
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
|
||||
|
||||
// Layer portals
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int idx = x+y*w;
|
||||
const int lh = (int)layer.heights[idx];
|
||||
if (lh == 0xff) continue;
|
||||
|
||||
for (int dir = 0; dir < 4; ++dir)
|
||||
{
|
||||
if (layer.cons[idx] & (1<<(dir+4)))
|
||||
{
|
||||
const int* seg = &segs[dir*4];
|
||||
const float ax = bmin[0] + (x+seg[0])*cs;
|
||||
const float ay = bmin[1] + (lh+2)*ch;
|
||||
const float az = bmin[2] + (y+seg[1])*cs;
|
||||
const float bx = bmin[0] + (x+seg[2])*cs;
|
||||
const float by = bmin[1] + (lh+2)*ch;
|
||||
const float bz = bmin[2] + (y+seg[3])*cs;
|
||||
dd->vertex(ax, ay, az, pcol);
|
||||
dd->vertex(bx, by, bz, pcol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawTileCacheLayerAreas(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
const float* bmax = layer.header->bmax;
|
||||
const int idx = layer.header->tlayer;
|
||||
|
||||
unsigned int color = duIntToCol(idx+1, 255);
|
||||
|
||||
// Layer bounds
|
||||
float lbmin[3], lbmax[3];
|
||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||
lbmin[1] = bmin[1];
|
||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||
lbmax[1] = bmax[1];
|
||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||
|
||||
// Layer height
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int lidx = x+y*w;
|
||||
const int lh = (int)layer.heights[lidx];
|
||||
if (lh == 0xff) continue;
|
||||
|
||||
const unsigned char area = layer.areas[lidx];
|
||||
unsigned int col;
|
||||
if (area == 63)
|
||||
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
|
||||
else if (area == 0)
|
||||
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
|
||||
else
|
||||
col = duLerpCol(color, dd->areaToCol(area), 32);
|
||||
|
||||
const float fx = bmin[0] + x*cs;
|
||||
const float fy = bmin[1] + (lh+1)*ch;
|
||||
const float fz = bmin[2] + y*cs;
|
||||
|
||||
dd->vertex(fx, fy, fz, col);
|
||||
dd->vertex(fx, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||
}
|
||||
|
||||
void duDebugDrawTileCacheLayerRegions(struct duDebugDraw* dd, const dtTileCacheLayer& layer, const float cs, const float ch)
|
||||
{
|
||||
const int w = (int)layer.header->width;
|
||||
const int h = (int)layer.header->height;
|
||||
const float* bmin = layer.header->bmin;
|
||||
const float* bmax = layer.header->bmax;
|
||||
const int idx = layer.header->tlayer;
|
||||
|
||||
unsigned int color = duIntToCol(idx+1, 255);
|
||||
|
||||
// Layer bounds
|
||||
float lbmin[3], lbmax[3];
|
||||
lbmin[0] = bmin[0] + layer.header->minx*cs;
|
||||
lbmin[1] = bmin[1];
|
||||
lbmin[2] = bmin[2] + layer.header->miny*cs;
|
||||
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
|
||||
lbmax[1] = bmax[1];
|
||||
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
|
||||
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
|
||||
|
||||
// Layer height
|
||||
dd->begin(DU_DRAW_QUADS);
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int lidx = x+y*w;
|
||||
const int lh = (int)layer.heights[lidx];
|
||||
if (lh == 0xff) continue;
|
||||
const unsigned char reg = layer.regs[lidx];
|
||||
|
||||
unsigned int col = duLerpCol(color, duIntToCol(reg, 255), 192);
|
||||
|
||||
const float fx = bmin[0] + x*cs;
|
||||
const float fy = bmin[1] + (lh+1)*ch;
|
||||
const float fz = bmin[2] + y*cs;
|
||||
|
||||
dd->vertex(fx, fy, fz, col);
|
||||
dd->vertex(fx, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz+cs, col);
|
||||
dd->vertex(fx+cs, fy, fz, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
debugDrawTileCachePortals(dd, layer, cs, ch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*struct dtTileCacheContour
|
||||
{
|
||||
int nverts;
|
||||
unsigned char* verts;
|
||||
unsigned char reg;
|
||||
unsigned char area;
|
||||
};
|
||||
|
||||
struct dtTileCacheContourSet
|
||||
{
|
||||
int nconts;
|
||||
dtTileCacheContour* conts;
|
||||
};*/
|
||||
|
||||
void duDebugDrawTileCacheContours(duDebugDraw* dd, const struct dtTileCacheContourSet& lcset,
|
||||
const float* orig, const float cs, const float ch)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
|
||||
|
||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||
|
||||
dd->begin(DU_DRAW_LINES, 2.0f);
|
||||
|
||||
for (int i = 0; i < lcset.nconts; ++i)
|
||||
{
|
||||
const dtTileCacheContour& c = lcset.conts[i];
|
||||
unsigned int color = 0;
|
||||
|
||||
color = duIntToCol(i, a);
|
||||
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const int k = (j+1) % c.nverts;
|
||||
const unsigned char* va = &c.verts[j*4];
|
||||
const unsigned char* vb = &c.verts[k*4];
|
||||
const float ax = orig[0] + va[0]*cs;
|
||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
const float az = orig[2] + va[2]*cs;
|
||||
const float bx = orig[0] + vb[0]*cs;
|
||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||
const float bz = orig[2] + vb[2]*cs;
|
||||
unsigned int col = color;
|
||||
if ((va[3] & 0xf) != 0xf)
|
||||
{
|
||||
// Portal segment
|
||||
col = duRGBA(255,255,255,128);
|
||||
int d = va[3] & 0xf;
|
||||
|
||||
const float cx = (ax+bx)*0.5f;
|
||||
const float cy = (ay+by)*0.5f;
|
||||
const float cz = (az+bz)*0.5f;
|
||||
|
||||
const float dx = cx + offs[d*2+0]*2*cs;
|
||||
const float dy = cy;
|
||||
const float dz = cz + offs[d*2+1]*2*cs;
|
||||
|
||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||
}
|
||||
|
||||
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_POINTS, 4.0f);
|
||||
|
||||
for (int i = 0; i < lcset.nconts; ++i)
|
||||
{
|
||||
const dtTileCacheContour& c = lcset.conts[i];
|
||||
unsigned int color = 0;
|
||||
|
||||
for (int j = 0; j < c.nverts; ++j)
|
||||
{
|
||||
const unsigned char* va = &c.verts[j*4];
|
||||
|
||||
color = duDarkenCol(duIntToCol(i, a));
|
||||
if (va[3] & 0x80)
|
||||
{
|
||||
// Border vertex
|
||||
color = duRGBA(255,0,0,255);
|
||||
}
|
||||
|
||||
float fx = orig[0] + va[0]*cs;
|
||||
float fy = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
float fz = orig[2] + va[2]*cs;
|
||||
dd->vertex(fx,fy,fz, color);
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
void duDebugDrawTileCachePolyMesh(duDebugDraw* dd, const struct dtTileCachePolyMesh& lmesh,
|
||||
const float* orig, const float cs, const float ch)
|
||||
{
|
||||
if (!dd) return;
|
||||
|
||||
const int nvp = lmesh.nvp;
|
||||
|
||||
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
|
||||
|
||||
dd->begin(DU_DRAW_TRIS);
|
||||
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
const unsigned char area = lmesh.areas[i];
|
||||
|
||||
unsigned int color;
|
||||
if (area == DT_TILECACHE_WALKABLE_AREA)
|
||||
color = duRGBA(0,192,255,64);
|
||||
else if (area == DT_TILECACHE_NULL_AREA)
|
||||
color = duRGBA(0,0,0,64);
|
||||
else
|
||||
color = dd->areaToCol(area);
|
||||
|
||||
unsigned short vi[3];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
vi[0] = p[0];
|
||||
vi[1] = p[j-1];
|
||||
vi[2] = p[j];
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x,y,z, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw neighbours edges
|
||||
const unsigned int coln = duRGBA(0,48,64,32);
|
||||
dd->begin(DU_DRAW_LINES, 1.5f);
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
if (p[nvp+j] & 0x8000) continue;
|
||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||
int vi[2] = {p[j], p[nj]};
|
||||
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x, y, z, coln);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
// Draw boundary edges
|
||||
const unsigned int colb = duRGBA(0,48,64,220);
|
||||
dd->begin(DU_DRAW_LINES, 2.5f);
|
||||
for (int i = 0; i < lmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &lmesh.polys[i*nvp*2];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == DT_TILECACHE_NULL_IDX) break;
|
||||
if ((p[nvp+j] & 0x8000) == 0) continue;
|
||||
const int nj = (j+1 >= nvp || p[j+1] == DT_TILECACHE_NULL_IDX) ? 0 : j+1;
|
||||
int vi[2] = {p[j], p[nj]};
|
||||
|
||||
unsigned int col = colb;
|
||||
if ((p[nvp+j] & 0xf) != 0xf)
|
||||
{
|
||||
const unsigned short* va = &lmesh.verts[vi[0]*3];
|
||||
const unsigned short* vb = &lmesh.verts[vi[1]*3];
|
||||
|
||||
const float ax = orig[0] + va[0]*cs;
|
||||
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
|
||||
const float az = orig[2] + va[2]*cs;
|
||||
const float bx = orig[0] + vb[0]*cs;
|
||||
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
|
||||
const float bz = orig[2] + vb[2]*cs;
|
||||
|
||||
const float cx = (ax+bx)*0.5f;
|
||||
const float cy = (ay+by)*0.5f;
|
||||
const float cz = (az+bz)*0.5f;
|
||||
|
||||
int d = p[nvp+j] & 0xf;
|
||||
|
||||
const float dx = cx + offs[d*2+0]*2*cs;
|
||||
const float dy = cy;
|
||||
const float dz = cz + offs[d*2+1]*2*cs;
|
||||
|
||||
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
|
||||
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
|
||||
|
||||
col = duRGBA(255,255,255,128);
|
||||
}
|
||||
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[vi[k]*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x, y, z, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
dd->end();
|
||||
|
||||
dd->begin(DU_DRAW_POINTS, 3.0f);
|
||||
const unsigned int colv = duRGBA(0,0,0,220);
|
||||
for (int i = 0; i < lmesh.nverts; ++i)
|
||||
{
|
||||
const unsigned short* v = &lmesh.verts[i*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
dd->vertex(x,y,z, colv);
|
||||
}
|
||||
dd->end();
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
451
lib/haxerecast/recastnavigation/DebugUtils/Source/RecastDump.cpp
Normal file
451
lib/haxerecast/recastnavigation/DebugUtils/Source/RecastDump.cpp
Normal file
@ -0,0 +1,451 @@
|
||||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "Recast.h"
|
||||
#include "RecastAlloc.h"
|
||||
#include "RecastDump.h"
|
||||
|
||||
|
||||
duFileIO::~duFileIO()
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
static void ioprintf(duFileIO* io, const char* format, ...)
|
||||
{
|
||||
char line[256];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int n = vsnprintf(line, sizeof(line), format, ap);
|
||||
va_end(ap);
|
||||
if (n > 0)
|
||||
io->write(line, sizeof(char)*n);
|
||||
}
|
||||
|
||||
bool duDumpPolyMeshToObj(rcPolyMesh& pmesh, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpPolyMeshToObj: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpPolyMeshToObj: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int nvp = pmesh.nvp;
|
||||
const float cs = pmesh.cs;
|
||||
const float ch = pmesh.ch;
|
||||
const float* orig = pmesh.bmin;
|
||||
|
||||
ioprintf(io, "# Recast Navmesh\n");
|
||||
ioprintf(io, "o NavMesh\n");
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < pmesh.nverts; ++i)
|
||||
{
|
||||
const unsigned short* v = &pmesh.verts[i*3];
|
||||
const float x = orig[0] + v[0]*cs;
|
||||
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
|
||||
const float z = orig[2] + v[2]*cs;
|
||||
ioprintf(io, "v %f %f %f\n", x,y,z);
|
||||
}
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < pmesh.npolys; ++i)
|
||||
{
|
||||
const unsigned short* p = &pmesh.polys[i*nvp*2];
|
||||
for (int j = 2; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == RC_MESH_NULL_IDX) break;
|
||||
ioprintf(io, "f %d %d %d\n", p[0]+1, p[j-1]+1, p[j]+1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpPolyMeshDetailToObj: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpPolyMeshDetailToObj: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ioprintf(io, "# Recast Navmesh\n");
|
||||
ioprintf(io, "o NavMesh\n");
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < dmesh.nverts; ++i)
|
||||
{
|
||||
const float* v = &dmesh.verts[i*3];
|
||||
ioprintf(io, "v %f %f %f\n", v[0],v[1],v[2]);
|
||||
}
|
||||
|
||||
ioprintf(io, "\n");
|
||||
|
||||
for (int i = 0; i < dmesh.nmeshes; ++i)
|
||||
{
|
||||
const unsigned int* m = &dmesh.meshes[i*4];
|
||||
const unsigned int bverts = m[0];
|
||||
const unsigned int btris = m[2];
|
||||
const unsigned int ntris = m[3];
|
||||
const unsigned char* tris = &dmesh.tris[btris*4];
|
||||
for (unsigned int j = 0; j < ntris; ++j)
|
||||
{
|
||||
ioprintf(io, "f %d %d %d\n",
|
||||
(int)(bverts+tris[j*4+0])+1,
|
||||
(int)(bverts+tris[j*4+1])+1,
|
||||
(int)(bverts+tris[j*4+2])+1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
|
||||
static const int CSET_VERSION = 2;
|
||||
|
||||
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpContourSet: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpContourSet: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->write(&CSET_MAGIC, sizeof(CSET_MAGIC));
|
||||
io->write(&CSET_VERSION, sizeof(CSET_VERSION));
|
||||
|
||||
io->write(&cset.nconts, sizeof(cset.nconts));
|
||||
|
||||
io->write(cset.bmin, sizeof(cset.bmin));
|
||||
io->write(cset.bmax, sizeof(cset.bmax));
|
||||
|
||||
io->write(&cset.cs, sizeof(cset.cs));
|
||||
io->write(&cset.ch, sizeof(cset.ch));
|
||||
|
||||
io->write(&cset.width, sizeof(cset.width));
|
||||
io->write(&cset.height, sizeof(cset.height));
|
||||
io->write(&cset.borderSize, sizeof(cset.borderSize));
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
const rcContour& cont = cset.conts[i];
|
||||
io->write(&cont.nverts, sizeof(cont.nverts));
|
||||
io->write(&cont.nrverts, sizeof(cont.nrverts));
|
||||
io->write(&cont.reg, sizeof(cont.reg));
|
||||
io->write(&cont.area, sizeof(cont.area));
|
||||
io->write(cont.verts, sizeof(int)*4*cont.nverts);
|
||||
io->write(cont.rverts, sizeof(int)*4*cont.nrverts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duReadContourSet: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isReading())
|
||||
{
|
||||
printf("duReadContourSet: input IO not reading.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int magic = 0;
|
||||
int version = 0;
|
||||
|
||||
io->read(&magic, sizeof(magic));
|
||||
io->read(&version, sizeof(version));
|
||||
|
||||
if (magic != CSET_MAGIC)
|
||||
{
|
||||
printf("duReadContourSet: Bad voodoo.\n");
|
||||
return false;
|
||||
}
|
||||
if (version != CSET_VERSION)
|
||||
{
|
||||
printf("duReadContourSet: Bad version.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(&cset.nconts, sizeof(cset.nconts));
|
||||
|
||||
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*cset.nconts, RC_ALLOC_PERM);
|
||||
if (!cset.conts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contours (%d)\n", cset.nconts);
|
||||
return false;
|
||||
}
|
||||
memset(cset.conts, 0, sizeof(rcContour)*cset.nconts);
|
||||
|
||||
io->read(cset.bmin, sizeof(cset.bmin));
|
||||
io->read(cset.bmax, sizeof(cset.bmax));
|
||||
|
||||
io->read(&cset.cs, sizeof(cset.cs));
|
||||
io->read(&cset.ch, sizeof(cset.ch));
|
||||
|
||||
io->read(&cset.width, sizeof(cset.width));
|
||||
io->read(&cset.height, sizeof(cset.height));
|
||||
io->read(&cset.borderSize, sizeof(cset.borderSize));
|
||||
|
||||
for (int i = 0; i < cset.nconts; ++i)
|
||||
{
|
||||
rcContour& cont = cset.conts[i];
|
||||
io->read(&cont.nverts, sizeof(cont.nverts));
|
||||
io->read(&cont.nrverts, sizeof(cont.nrverts));
|
||||
io->read(&cont.reg, sizeof(cont.reg));
|
||||
io->read(&cont.area, sizeof(cont.area));
|
||||
|
||||
cont.verts = (int*)rcAlloc(sizeof(int)*4*cont.nverts, RC_ALLOC_PERM);
|
||||
if (!cont.verts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contour verts (%d)\n", cont.nverts);
|
||||
return false;
|
||||
}
|
||||
cont.rverts = (int*)rcAlloc(sizeof(int)*4*cont.nrverts, RC_ALLOC_PERM);
|
||||
if (!cont.rverts)
|
||||
{
|
||||
printf("duReadContourSet: Could not alloc contour rverts (%d)\n", cont.nrverts);
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(cont.verts, sizeof(int)*4*cont.nverts);
|
||||
io->read(cont.rverts, sizeof(int)*4*cont.nrverts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
|
||||
static const int CHF_VERSION = 3;
|
||||
|
||||
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duDumpCompactHeightfield: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isWriting())
|
||||
{
|
||||
printf("duDumpCompactHeightfield: input IO not writing.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->write(&CHF_MAGIC, sizeof(CHF_MAGIC));
|
||||
io->write(&CHF_VERSION, sizeof(CHF_VERSION));
|
||||
|
||||
io->write(&chf.width, sizeof(chf.width));
|
||||
io->write(&chf.height, sizeof(chf.height));
|
||||
io->write(&chf.spanCount, sizeof(chf.spanCount));
|
||||
|
||||
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||
io->write(&chf.borderSize, sizeof(chf.borderSize));
|
||||
|
||||
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||
|
||||
io->write(chf.bmin, sizeof(chf.bmin));
|
||||
io->write(chf.bmax, sizeof(chf.bmax));
|
||||
|
||||
io->write(&chf.cs, sizeof(chf.cs));
|
||||
io->write(&chf.ch, sizeof(chf.ch));
|
||||
|
||||
int tmp = 0;
|
||||
if (chf.cells) tmp |= 1;
|
||||
if (chf.spans) tmp |= 2;
|
||||
if (chf.dist) tmp |= 4;
|
||||
if (chf.areas) tmp |= 8;
|
||||
|
||||
io->write(&tmp, sizeof(tmp));
|
||||
|
||||
if (chf.cells)
|
||||
io->write(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
||||
if (chf.spans)
|
||||
io->write(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
||||
if (chf.dist)
|
||||
io->write(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
||||
if (chf.areas)
|
||||
io->write(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
|
||||
{
|
||||
if (!io)
|
||||
{
|
||||
printf("duReadCompactHeightfield: input IO is null.\n");
|
||||
return false;
|
||||
}
|
||||
if (!io->isReading())
|
||||
{
|
||||
printf("duReadCompactHeightfield: input IO not reading.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int magic = 0;
|
||||
int version = 0;
|
||||
|
||||
io->read(&magic, sizeof(magic));
|
||||
io->read(&version, sizeof(version));
|
||||
|
||||
if (magic != CHF_MAGIC)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Bad voodoo.\n");
|
||||
return false;
|
||||
}
|
||||
if (version != CHF_VERSION)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Bad version.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
io->read(&chf.width, sizeof(chf.width));
|
||||
io->read(&chf.height, sizeof(chf.height));
|
||||
io->read(&chf.spanCount, sizeof(chf.spanCount));
|
||||
|
||||
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
|
||||
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
|
||||
io->read(&chf.borderSize, sizeof(chf.borderSize));
|
||||
|
||||
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
|
||||
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
|
||||
|
||||
io->read(chf.bmin, sizeof(chf.bmin));
|
||||
io->read(chf.bmax, sizeof(chf.bmax));
|
||||
|
||||
io->read(&chf.cs, sizeof(chf.cs));
|
||||
io->read(&chf.ch, sizeof(chf.ch));
|
||||
|
||||
int tmp = 0;
|
||||
io->read(&tmp, sizeof(tmp));
|
||||
|
||||
if (tmp & 1)
|
||||
{
|
||||
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*chf.width*chf.height, RC_ALLOC_PERM);
|
||||
if (!chf.cells)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc cells (%d)\n", chf.width*chf.height);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
|
||||
}
|
||||
if (tmp & 2)
|
||||
{
|
||||
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.spans)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc spans (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
|
||||
}
|
||||
if (tmp & 4)
|
||||
{
|
||||
chf.dist = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.dist)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc dist (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.dist, sizeof(unsigned short)*chf.spanCount);
|
||||
}
|
||||
if (tmp & 8)
|
||||
{
|
||||
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_PERM);
|
||||
if (!chf.areas)
|
||||
{
|
||||
printf("duReadCompactHeightfield: Could not alloc areas (%d)\n", chf.spanCount);
|
||||
return false;
|
||||
}
|
||||
io->read(chf.areas, sizeof(unsigned char)*chf.spanCount);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const float pc)
|
||||
{
|
||||
const int t = ctx.getAccumulatedTime(label);
|
||||
if (t < 0) return;
|
||||
ctx.log(RC_LOG_PROGRESS, "%s:\t%.2fms\t(%.1f%%)", name, t/1000.0f, t*pc);
|
||||
}
|
||||
|
||||
void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
|
||||
{
|
||||
const float pc = 100.0f / totalTimeUsec;
|
||||
|
||||
ctx.log(RC_LOG_PROGRESS, "Build Times");
|
||||
logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
|
||||
logLine(ctx, RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
|
||||
logLine(ctx, RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);
|
||||
logLine(ctx, RC_TIMER_ERODE_AREA, "- Erode Area", pc);
|
||||
logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
|
||||
logLine(ctx, RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_WATERSHED, " - Watershed", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_POLYMESH, "- Build Polymesh", pc);
|
||||
logLine(ctx, RC_TIMER_BUILD_POLYMESHDETAIL, "- Build Polymesh Detail", pc);
|
||||
logLine(ctx, RC_TIMER_MERGE_POLYMESH, "- Merge Polymeshes", pc);
|
||||
logLine(ctx, RC_TIMER_MERGE_POLYMESHDETAIL, "- Merge Polymesh Details", pc);
|
||||
ctx.log(RC_LOG_PROGRESS, "=== TOTAL:\t%.2fms", totalTimeUsec/1000.0f);
|
||||
}
|
||||
|
Reference in New Issue
Block a user