diff --git a/RecastDemo/Include/ConvexVolumeTool.h b/RecastDemo/Include/ConvexVolumeTool.h new file mode 100644 index 0000000..6feb5c6 --- /dev/null +++ b/RecastDemo/Include/ConvexVolumeTool.h @@ -0,0 +1,52 @@ +// +// 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. +// + +#ifndef CONVEXVOLUMETOOL_H +#define CONVEXVOLUMETOOL_H + +#include "Sample.h" + +// Tool to create convex volumess for InputGeom + +class ConvexVolumeTool : public SampleTool +{ + Sample* m_sample; + int m_areaType; + float m_boxHeight; + float m_boxDescent; + + static const int MAX_PTS = 12; + float m_pts[MAX_PTS*3]; + int m_npts; + int m_hull[MAX_PTS]; + int m_nhull; + +public: + ConvexVolumeTool(); + ~ConvexVolumeTool(); + + virtual int type() { return TOOL_CONVEX_VOLUME; } + virtual void init(Sample* sample); + virtual void reset(); + virtual void handleMenu(); + virtual void handleClick(const float* p, bool shift); + virtual void handleRender(); + virtual void handleRenderOverlay(double* proj, double* model, int* view); +}; + +#endif // CONVEXVOLUMETOOL_H diff --git a/RecastDemo/Source/ConvexVolumeTool.cpp b/RecastDemo/Source/ConvexVolumeTool.cpp new file mode 100644 index 0000000..98d62cd --- /dev/null +++ b/RecastDemo/Source/ConvexVolumeTool.cpp @@ -0,0 +1,263 @@ +// +// 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 +#include +#include +#include "SDL.h" +#include "SDL_opengl.h" +#include "imgui.h" +#include "ConvexVolumeTool.h" +#include "InputGeom.h" +#include "Sample.h" +#include "Recast.h" +#include "RecastDebugDraw.h" +#include "DetourDebugDraw.h" + +#ifdef WIN32 +# define snprintf _snprintf +#endif + +// Quick and dirty convex hull. +inline bool left(const float* a, const float* b, const float* c) +{ + return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]) < 0; +} + +inline bool cmppt(const float* a, const float* b) +{ + if (a[0] < b[0]) return true; + if (a[0] > b[0]) return false; + if (a[2] < b[2]) return true; + if (a[2] > b[2]) return false; + return false; +} + +static int convexhull(const float* pts, int npts, int* out) +{ + // Find leftmost point. + int hull = 0; + for (int i = 1; i < npts; ++i) + if (cmppt(&pts[i*3], &pts[hull*3])) + hull = i; + // Gif wrap hull. + int endpt = 0; + int i = 0; + do + { + out[i++] = hull; + endpt = 0; + for (int j = 1; j < npts; ++j) + if (hull == endpt || left(&pts[hull*3], &pts[endpt*3], &pts[j*3])) + endpt = j; + hull = endpt; + } + while (endpt != out[0]); + + return i; +} + +static int pointInPoly(int nvert, const float* verts, const float* p) +{ + int i, j, c = 0; + for (i = 0, j = nvert-1; i < nvert; j = i++) + { + const float* vi = &verts[i*3]; + const float* vj = &verts[j*3]; + if (((vi[2] > p[2]) != (vj[2] > p[2])) && + (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) ) + c = !c; + } + return c; +} + + +ConvexVolumeTool::ConvexVolumeTool() : + m_sample(0), + m_areaType(SAMPLE_POLYAREA_GRASS), + m_boxHeight(6.0f), + m_boxDescent(1.0f), + m_npts(0), + m_nhull(0) +{ +} + +ConvexVolumeTool::~ConvexVolumeTool() +{ +} + +void ConvexVolumeTool::init(Sample* sample) +{ + m_sample = sample; +} + +void ConvexVolumeTool::reset() +{ + m_npts = 0; + m_nhull = 0; +} + +void ConvexVolumeTool::handleMenu() +{ + imguiSlider("Shape Height", &m_boxHeight, 0.1f, 20.0f, 0.1f); + imguiSlider("Shape Descent", &m_boxDescent, 0.1f, 20.0f, 0.1f); + + imguiSeparator(); + + imguiLabel("Area Type"); + imguiIndent(); + if (imguiCheck("Grass", m_areaType == SAMPLE_POLYAREA_GRASS)) + m_areaType = SAMPLE_POLYAREA_GRASS; + if (imguiCheck("Road", m_areaType == SAMPLE_POLYAREA_ROAD)) + m_areaType = SAMPLE_POLYAREA_ROAD; + if (imguiCheck("Water", m_areaType == SAMPLE_POLYAREA_WATER)) + m_areaType = SAMPLE_POLYAREA_WATER; + if (imguiCheck("Door", m_areaType == SAMPLE_POLYAREA_DOOR)) + m_areaType = SAMPLE_POLYAREA_DOOR; + imguiUnindent(); + + imguiSeparator(); + + if (imguiButton("Clear Shape")) + { + m_npts = 0; + m_nhull = 0; + } + + imguiSeparator(); + + imguiValue("Click to create points."); + imguiValue("The shape is convex hull"); + imguiValue("of all the create points."); + imguiValue("Click on highlited point"); + imguiValue("to finish the shape."); + + imguiSeparator(); +} + +void ConvexVolumeTool::handleClick(const float* p, bool shift) +{ + if (!m_sample) return; + InputGeom* geom = m_sample->getInputGeom(); + if (!geom) return; + + if (shift) + { + // Delete + int nearestIndex = -1; + const ConvexVolume* vols = geom->getConvexVolumes(); + for (int i = 0; i < geom->getConvexVolumeCount(); ++i) + { + if (pointInPoly(vols[i].nverts, vols[i].verts, p) && + p[1] >= vols[i].hmin, p[1] <= vols[i].hmax) + { + nearestIndex = i; + } + } + // If end point close enough, delete it. + if (nearestIndex != -1) + { + geom->deleteConvexVolume(nearestIndex); + } + } + else + { + // Create + + // If clicked on that last pt, create the shape. + if (m_npts && vdistSqr(p, &m_pts[(m_npts-1)*3]) < rcSqr(0.2f)) + { + if (m_nhull > 2) + { + // Create shape. + float verts[MAX_PTS*3]; + for (int i = 0; i < m_nhull; ++i) + vcopy(&verts[i*3], &m_pts[m_hull[i]*3]); + + float minh = FLT_MAX, maxh = 0; + for (int i = 0; i < m_nhull; ++i) + minh = rcMin(minh, verts[i*3+1]); + minh -= m_boxDescent; + maxh = minh + m_boxHeight; + + geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned char)m_areaType); + } + + m_npts = 0; + m_nhull = 0; + } + else + { + // Add new point + if (m_npts < MAX_PTS) + { + vcopy(&m_pts[m_npts*3], p); + m_npts++; + // Update hull. + if (m_npts > 1) + m_nhull = convexhull(m_pts, m_npts, m_hull); + else + m_nhull = 0; + } + } + } + +} + +void ConvexVolumeTool::handleRender() +{ + DebugDrawGL dd; + const float s = m_sample->getAgentRadius(); + + // Find height extents of the shape. + float minh = FLT_MAX, maxh = 0; + for (int i = 0; i < m_npts; ++i) + minh = rcMin(minh, m_pts[i*3+1]); + minh -= m_boxDescent; + maxh = minh + m_boxHeight; + + dd.begin(DU_DRAW_POINTS, 4.0f); + for (int i = 0; i < m_npts; ++i) + { + unsigned int col = duRGBA(255,255,255,255); + if (i == m_npts-1) + col = duRGBA(240,32,16,255); + dd.vertex(m_pts[i*3+0],m_pts[i*3+1]+0.1f,m_pts[i*3+2], col); + } + dd.end(); + + dd.begin(DU_DRAW_LINES, 2.0f); + for (int i = 0, j = m_nhull-1; i < m_nhull; j = i++) + { + const float* vi = &m_pts[m_hull[j]*3]; + const float* vj = &m_pts[m_hull[i]*3]; + dd.vertex(vj[0],minh,vj[2], duRGBA(255,255,255,64)); + dd.vertex(vi[0],minh,vi[2], duRGBA(255,255,255,64)); + dd.vertex(vj[0],maxh,vj[2], duRGBA(255,255,255,64)); + dd.vertex(vi[0],maxh,vi[2], duRGBA(255,255,255,64)); + dd.vertex(vj[0],minh,vj[2], duRGBA(255,255,255,64)); + dd.vertex(vj[0],maxh,vj[2], duRGBA(255,255,255,64)); + } + dd.end(); +} + +void ConvexVolumeTool::handleRenderOverlay(double* proj, double* model, int* view) +{ +}