// // Copyright (c) 2009 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 #include "RecastDebugDraw.h" #include "SDL.h" #include "SDL_Opengl.h" #include "MeshLoaderObj.h" #include "Recast.h" void rcDebugDrawMesh(const rcMeshLoaderObj& mesh, const unsigned char* flags) { int nt = mesh.getTriCount(); const float* verts = mesh.getVerts(); const float* normals = mesh.getNormals(); const int* tris = mesh.getTris(); glBegin(GL_TRIANGLES); for (int i = 0; i < nt*3; i += 3) { float a = (2+normals[i+0]+normals[i+1])/4; if (flags && !flags[i/3]) glColor3f(a,a*0.3f,a*0.1f); else glColor3f(a,a,a); glVertex3fv(&verts[tris[i]*3]); glVertex3fv(&verts[tris[i+1]*3]); glVertex3fv(&verts[tris[i+2]*3]); } glEnd(); } void drawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col) { glColor4fv(col); // Top glVertex3f(minx, miny, minz); glVertex3f(maxx, miny, minz); glVertex3f(maxx, miny, minz); glVertex3f(maxx, miny, maxz); glVertex3f(maxx, miny, maxz); glVertex3f(minx, miny, maxz); glVertex3f(minx, miny, maxz); glVertex3f(minx, miny, minz); // bottom glVertex3f(minx, maxy, minz); glVertex3f(maxx, maxy, minz); glVertex3f(maxx, maxy, minz); glVertex3f(maxx, maxy, maxz); glVertex3f(maxx, maxy, maxz); glVertex3f(minx, maxy, maxz); glVertex3f(minx, maxy, maxz); glVertex3f(minx, maxy, minz); // Sides glVertex3f(minx, miny, minz); glVertex3f(minx, maxy, minz); glVertex3f(maxx, miny, minz); glVertex3f(maxx, maxy, minz); glVertex3f(maxx, miny, maxz); glVertex3f(maxx, maxy, maxz); glVertex3f(minx, miny, maxz); glVertex3f(minx, maxy, maxz); } void drawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col1, const float* col2) { 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 float dim[6] = { 0.95f, 0.55f, 0.65f, 0.85f, 0.65f, 0.85f, }; static const unsigned char inds[6*5] = { 0, 7, 6, 5, 4, 1, 0, 1, 2, 3, 2, 1, 5, 6, 2, 3, 3, 7, 4, 0, 4, 2, 6, 7, 3, 5, 0, 4, 5, 1, }; const unsigned char* in = inds; for (int i = 0; i < 6; ++i) { float d = dim[*in]; in++; if (i == 0) glColor4f(d*col2[0],d*col2[1],d*col2[2], col2[3]); else glColor4f(d*col1[0],d*col1[1],d*col1[2], col1[3]); glVertex3fv(&verts[*in*3]); in++; glVertex3fv(&verts[*in*3]); in++; glVertex3fv(&verts[*in*3]); in++; glVertex3fv(&verts[*in*3]); in++; } } void rcDebugDrawCylinderWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col) { static const int NUM_SEG = 16; float dir[NUM_SEG*2]; for (int i = 0; i < NUM_SEG; ++i) { const float a = (float)i/(float)NUM_SEG*(float)M_PI*2; dir[i*2] = cosf(a); dir[i*2+1] = sinf(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; glColor4fv(col); glBegin(GL_LINES); for (int i = 0, j=NUM_SEG-1; i < NUM_SEG; j=i++) { glVertex3f(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz); glVertex3f(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz); glVertex3f(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz); glVertex3f(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz); } for (int i = 0; i < NUM_SEG; i += NUM_SEG/4) { glVertex3f(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz); glVertex3f(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz); } glEnd(); } void rcDebugDrawBoxWire(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col) { glBegin(GL_LINES); drawBoxWire(minx, miny, minz, maxx, maxy, maxz, col); glEnd(); } void rcDebugDrawBox(float minx, float miny, float minz, float maxx, float maxy, float maxz, const float* col1, const float* col2) { glBegin(GL_QUADS); drawBox(minx, miny, minz, maxx, maxy, maxz, col1, col2); glEnd(); } void rcDebugDrawHeightfieldSolid(const rcHeightfield& hf, const float* orig, float cs, float ch) { static const float col0[4] = { 1,1,1,1 }; const int w = hf.width; const int h = hf.height; glBegin(GL_QUADS); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { float fx = orig[0] + x*cs; float fz = orig[2] + y*cs; const rcSpan* s = hf.spans[x + y*w]; while (s) { drawBox(fx, orig[1]+s->smin*ch, fz, fx+cs, orig[1] + s->smax*ch, fz+cs, col0, col0); s = s->next; } } } glEnd(); } void rcDebugDrawHeightfieldWalkable(const rcHeightfield& hf, const float* orig, float cs, float ch) { static const float col0[4] = { 1,1,1,1 }; static const float col1[4] = { 0.25f,0.44f,0.5f,1 }; const int w = hf.width; const int h = hf.height; glBegin(GL_QUADS); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { float fx = orig[0] + x*cs; float fz = orig[2] + y*cs; const rcSpan* s = hf.spans[x + y*w]; while (s) { bool csel = (s->flags & 0x2) == 0; drawBox(fx, orig[1]+s->smin*ch, fz, fx+cs, orig[1] + s->smax*ch, fz+cs, col0, csel ? col0 : col1); s = s->next; } } } glEnd(); } void rcDebugDrawCompactHeightfieldSolid(const rcCompactHeightfield& chf) { const float cs = chf.cs; const float ch = chf.ch; glColor3ub(64,112,128); glBegin(GL_QUADS); for (int y = 0; y < chf.height; ++y) { for (int x = 0; x < chf.width; ++x) { const float fx = chf.minx + x*cs; const float fz = chf.minz + y*cs; const rcCompactCell& c = chf.cells[x+y*chf.width]; for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; const float fy = chf.miny + (s.y+1)*ch; glVertex3f(fx, fy, fz); glVertex3f(fx, fy, fz+cs); glVertex3f(fx+cs, fy, fz+cs); glVertex3f(fx+cs, fy, fz); } } } glEnd(); } void rcDebugDrawCompactHeightfieldRegions(const rcCompactHeightfield& chf) { const float cs = chf.cs; const float ch = chf.ch; float col[4] = { 1,1,1,1 }; glBegin(GL_QUADS); for (int y = 0; y < chf.height; ++y) { for (int x = 0; x < chf.width; ++x) { const float fx = chf.minx + x*cs; const float fz = chf.minz + y*cs; const rcCompactCell& c = chf.cells[x+y*chf.width]; for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; if (s.reg) { intToCol(s.reg, col); glColor4fv(col); } else glColor4ub(0,0,0,128); const float fy = chf.miny + (s.y+1)*ch; glVertex3f(fx, fy, fz); glVertex3f(fx, fy, fz+cs); glVertex3f(fx+cs, fy, fz+cs); glVertex3f(fx+cs, fy, fz); } } } glEnd(); } void rcDebugDrawCompactHeightfieldDistance(const rcCompactHeightfield& chf) { const float cs = chf.cs; const float ch = chf.ch; float maxd = chf.maxDistance; if (maxd < 1.0f) maxd = 1; float dscale = 1.0f / maxd; glBegin(GL_QUADS); for (int y = 0; y < chf.height; ++y) { for (int x = 0; x < chf.width; ++x) { const float fx = chf.minx + x*cs; const float fz = chf.minz + y*cs; const rcCompactCell& c = chf.cells[x+y*chf.width]; for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; const float fy = chf.miny + (s.y+1)*ch; float cd = (float)s.dist * dscale; glColor3f(cd, cd, cd); glVertex3f(fx, fy, fz); glVertex3f(fx, fy, fz+cs); glVertex3f(fx+cs, fy, fz+cs); glVertex3f(fx+cs, fy, fz); } } } glEnd(); } void rcDebugDrawRawContours(const rcContourSet& cset, const float* orig, float cs, float ch) { float col[4] = { 1,1,1,1 }; glLineWidth(3.0f); for (int i = 0; i < cset.nconts; ++i) { const rcContour& c = cset.conts[i]; intToCol(c.reg, col); glColor4fv(col); glBegin(GL_LINE_LOOP); for (int j = 0; j < c.nrverts; ++j) { const int* v = &c.rverts[j*4]; float fx = orig[0] + v[0]*cs; float fy = orig[1] + (v[1]+1+(i&1))*ch; float fz = orig[2] + v[2]*cs; glVertex3f(fx,fy,fz); } glEnd(); } glLineWidth(1.0f); } void rcDebugDrawContours(const rcContourSet& cset, const float* orig, float cs, float ch) { float col[4] = { 1,1,1,1 }; glLineWidth(3.0f); glPointSize(4.0f); for (int i = 0; i < cset.nconts; ++i) { const rcContour& c = cset.conts[i]; intToCol(c.reg, col); glColor4fv(col); glBegin(GL_LINE_LOOP); for (int j = 0; j < c.nverts; ++j) { const int* v = &c.verts[j*4]; float fx = orig[0] + v[0]*cs; float fy = orig[1] + (v[1]+1+(i&1))*ch; float fz = orig[2] + v[2]*cs; glVertex3f(fx,fy,fz); } glEnd(); glColor4ub(0,0,0,128); glBegin(GL_POINTS); for (int j = 0; j < c.nverts; ++j) { const int* v = &c.verts[j*4]; float fx = orig[0] + v[0]*cs; float fy = orig[1] + (v[1]+1+(i&1))*ch; float fz = orig[2] + v[2]*cs; glVertex3f(fx,fy,fz); } glEnd(); } glLineWidth(1.0f); glPointSize(1.0f); } void rcDebugDrawPolyMesh(const struct rcPolyMesh& mesh, const float* orig, float cs, float ch) { const int nvp = mesh.nvp; glColor4ub(0,196,255,64); glBegin(GL_TRIANGLES); for (int i = 0; i < mesh.npolys; ++i) { const unsigned short* p = &mesh.polys[i*nvp*2]; unsigned short vi[3]; for (int j = 2; j < nvp; ++j) { if (p[j] == 0xffff) 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 = &mesh.verts[vi[k]*3]; const float x = orig[0] + v[0]*cs; const float y = orig[1] + (v[1]+2)*ch; const float z = orig[2] + v[2]*cs; glVertex3f(x, y, z); } } } glEnd(); // Draw tri boundaries glColor4ub(0,0,0,64); glLineWidth(1.0f); glBegin(GL_LINES); for (int i = 0; i < mesh.npolys; ++i) { const unsigned short* poly = &mesh.polys[i*nvp*2]; for (int j = 0; j < nvp; ++j) { if (poly[j] == 0xffff) break; if (poly[nvp+j] == 0xffff) continue; int vi[2]; vi[0] = poly[j]; if (j+1 >= nvp || poly[j+1] == 0xffff) vi[1] = poly[0]; else vi[1] = poly[j+1]; for (int k = 0; k < 2; ++k) { const unsigned short* v = &mesh.verts[vi[k]*3]; const float x = orig[0] + v[0]*cs; const float y = orig[1] + (v[1]+2)*ch + 0.1f; const float z = orig[2] + v[2]*cs; glVertex3f(x, y, z); } } } glEnd(); // Draw boundaries glLineWidth(3.0f); glColor4ub(0,0,0,128); glBegin(GL_LINES); for (int i = 0; i < mesh.npolys; ++i) { const unsigned short* poly = &mesh.polys[i*nvp*2]; for (int j = 0; j < nvp; ++j) { if (poly[j] == 0xffff) break; if (poly[nvp+j] != 0xffff) continue; int vi[2]; vi[0] = poly[j]; if (j+1 >= nvp || poly[j+1] == 0xffff) vi[1] = poly[0]; else vi[1] = poly[j+1]; for (int k = 0; k < 2; ++k) { const unsigned short* v = &mesh.verts[vi[k]*3]; const float x = orig[0] + v[0]*cs; const float y = orig[1] + (v[1]+2)*ch + 0.1f; const float z = orig[2] + v[2]*cs; glVertex3f(x, y, z); } } } glEnd(); glLineWidth(1.0f); glPointSize(4.0f); glColor4ub(0,0,0,128); glBegin(GL_POINTS); for (int i = 0; i < mesh.nverts; ++i) { const unsigned short* v = &mesh.verts[i*3]; const float x = orig[0] + v[0]*cs; const float y = orig[1] + (v[1]+2)*ch + 0.1f; const float z = orig[2] + v[2]*cs; glVertex3f(x, y, z); } glEnd(); glPointSize(1.0f); }