mirror of
https://github.com/recastnavigation/recastnavigation.git
synced 2026-08-15 15:50:03 +00:00
328 lines
7.2 KiB
C++
328 lines
7.2 KiB
C++
//
|
|
// 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 "ConvexVolumeTool.h"
|
|
|
|
#include "InputGeom.h"
|
|
#include "Recast.h"
|
|
#include "Sample.h"
|
|
#include "imgui.h"
|
|
|
|
#include <cfloat>
|
|
|
|
#ifdef WIN32
|
|
# define snprintf _snprintf
|
|
#endif
|
|
|
|
// Quick and dirty convex hull.
|
|
|
|
namespace {
|
|
/// Returns true if 'c' is left of line 'a'-'b'.
|
|
inline bool left(const float* a, const float* b, const float* c)
|
|
{
|
|
const float u1 = b[0] - a[0];
|
|
const float v1 = b[2] - a[2];
|
|
const float u2 = c[0] - a[0];
|
|
const float v2 = c[2] - a[2];
|
|
return u1 * v2 - v1 * u2 < 0;
|
|
}
|
|
|
|
/// Returns true if 'a' is more lower-left than 'b'.
|
|
inline bool comparePoints(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;
|
|
}
|
|
|
|
/// Calculates convex hull on xz-plane of points on 'pts',
|
|
/// stores the indices of the resulting hull in 'out' and
|
|
/// returns number of points on hull.
|
|
int convexhull(const float* pts, int npts, int* out)
|
|
{
|
|
// Find lower-leftmost point.
|
|
int hull = 0;
|
|
for (int i = 1; i < npts; ++i)
|
|
{
|
|
if (comparePoints(&pts[i * 3], &pts[hull * 3]))
|
|
{
|
|
hull = i;
|
|
}
|
|
}
|
|
// Gift 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;
|
|
}
|
|
|
|
bool pointInPoly(int nvert, const float* verts, const float* p)
|
|
{
|
|
bool result = false;
|
|
for (int 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]))
|
|
{
|
|
result = !result;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
void ConvexVolumeTool::handleMenu()
|
|
{
|
|
#if 0
|
|
imguiSlider("Shape Height", &boxHeight, 0.1f, 20.0f, 0.1f);
|
|
imguiSlider("Shape Descent", &boxDescent, 0.1f, 20.0f, 0.1f);
|
|
imguiSlider("Poly Offset", &polyOffset, 0.0f, 10.0f, 0.1f);
|
|
|
|
imguiSeparator();
|
|
|
|
imguiLabel("Area Type");
|
|
imguiIndent();
|
|
if (imguiCheck("Ground", areaType == SAMPLE_POLYAREA_GROUND))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_GROUND;
|
|
}
|
|
if (imguiCheck("Water", areaType == SAMPLE_POLYAREA_WATER))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_WATER;
|
|
}
|
|
if (imguiCheck("Road", areaType == SAMPLE_POLYAREA_ROAD))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_ROAD;
|
|
}
|
|
if (imguiCheck("Door", areaType == SAMPLE_POLYAREA_DOOR))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_DOOR;
|
|
}
|
|
if (imguiCheck("Grass", areaType == SAMPLE_POLYAREA_GRASS))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_GRASS;
|
|
}
|
|
if (imguiCheck("Jump", areaType == SAMPLE_POLYAREA_JUMP))
|
|
{
|
|
areaType = SAMPLE_POLYAREA_JUMP;
|
|
}
|
|
imguiUnindent();
|
|
|
|
imguiSeparator();
|
|
|
|
if (imguiButton("Clear Shape"))
|
|
{
|
|
numPoints = 0;
|
|
numHull = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift)
|
|
{
|
|
if (!sample)
|
|
{
|
|
return;
|
|
}
|
|
InputGeom* geom = 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 (numPoints && rcVdistSqr(p, &points[(numPoints - 1) * 3]) < rcSqr(0.2f))
|
|
{
|
|
if (numHull > 2)
|
|
{
|
|
// Create shape.
|
|
float verts[MAX_PTS * 3];
|
|
for (int i = 0; i < numHull; ++i)
|
|
{
|
|
rcVcopy(&verts[i * 3], &points[hull[i] * 3]);
|
|
}
|
|
|
|
float minh = FLT_MAX, maxh = 0;
|
|
for (int i = 0; i < numHull; ++i)
|
|
{
|
|
minh = rcMin(minh, verts[i * 3 + 1]);
|
|
}
|
|
minh -= boxDescent;
|
|
maxh = minh + boxHeight;
|
|
|
|
if (polyOffset > 0.01f)
|
|
{
|
|
float offset[MAX_PTS * 2 * 3];
|
|
int noffset = rcOffsetPoly(verts, numHull, polyOffset, offset, MAX_PTS * 2);
|
|
if (noffset > 0)
|
|
{
|
|
geom->addConvexVolume(offset, noffset, minh, maxh, (unsigned char)areaType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
geom->addConvexVolume(verts, numHull, minh, maxh, (unsigned char)areaType);
|
|
}
|
|
}
|
|
|
|
numPoints = 0;
|
|
numHull = 0;
|
|
}
|
|
else
|
|
{
|
|
// Add new point
|
|
if (numPoints < MAX_PTS)
|
|
{
|
|
rcVcopy(&points[numPoints * 3], p);
|
|
numPoints++;
|
|
// Update hull.
|
|
if (numPoints > 1)
|
|
{
|
|
numHull = convexhull(points, numPoints, hull);
|
|
}
|
|
else
|
|
{
|
|
numHull = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConvexVolumeTool::handleRender()
|
|
{
|
|
duDebugDraw& dd = sample->getDebugDraw();
|
|
|
|
// Find height extent of the shape.
|
|
float minh = FLT_MAX, maxh = 0;
|
|
for (int i = 0; i < numPoints; ++i)
|
|
{
|
|
minh = rcMin(minh, points[i * 3 + 1]);
|
|
}
|
|
minh -= boxDescent;
|
|
maxh = minh + boxHeight;
|
|
|
|
dd.begin(DU_DRAW_POINTS, 4.0f);
|
|
for (int i = 0; i < numPoints; ++i)
|
|
{
|
|
unsigned int col = duRGBA(255, 255, 255, 255);
|
|
if (i == numPoints - 1)
|
|
{
|
|
col = duRGBA(240, 32, 16, 255);
|
|
}
|
|
dd.vertex(points[i * 3 + 0], points[i * 3 + 1] + 0.1f, points[i * 3 + 2], col);
|
|
}
|
|
dd.end();
|
|
|
|
dd.begin(DU_DRAW_LINES, 2.0f);
|
|
for (int i = 0, j = numHull - 1; i < numHull; j = i++)
|
|
{
|
|
const float* vi = &points[hull[j] * 3];
|
|
const float* vj = &points[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)
|
|
{
|
|
#if 0
|
|
// Tool help
|
|
const int h = view[3];
|
|
if (!numPoints)
|
|
{
|
|
imguiDrawText(
|
|
280,
|
|
h - 40,
|
|
IMGUI_ALIGN_LEFT,
|
|
"LMB: Create new shape. SHIFT+LMB: Delete existing shape (click inside a shape).",
|
|
imguiRGBA(255, 255, 255, 192));
|
|
}
|
|
else
|
|
{
|
|
imguiDrawText(
|
|
280,
|
|
h - 40,
|
|
IMGUI_ALIGN_LEFT,
|
|
"Click LMB to add new points. Click on the red point to finish the shape.",
|
|
imguiRGBA(255, 255, 255, 192));
|
|
imguiDrawText(
|
|
280,
|
|
h - 60,
|
|
IMGUI_ALIGN_LEFT,
|
|
"The shape will be convex hull of all added points.",
|
|
imguiRGBA(255, 255, 255, 192));
|
|
}
|
|
#endif
|
|
}
|