123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- //
- // 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 <string.h>
- #include <float.h>
- #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.
- // 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 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;
- }
- // 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.
- static int convexhull(const float* pts, int npts, int* out)
- {
- // Find lower-leftmost point.
- int hull = 0;
- for (int i = 1; i < npts; ++i)
- if (cmppt(&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;
- }
- 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_polyOffset(0.0f),
- m_boxHeight(6.0f),
- m_boxDescent(1.0f),
- m_npts(0),
- m_nhull(0)
- {
- }
- 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);
- imguiSlider("Poly Offset", &m_polyOffset, 0.0f, 10.0f, 0.1f);
- imguiSeparator();
- imguiLabel("Area Type");
- imguiIndent();
- if (imguiCheck("Ground", m_areaType == SAMPLE_POLYAREA_GROUND))
- m_areaType = SAMPLE_POLYAREA_GROUND;
- if (imguiCheck("Water", m_areaType == SAMPLE_POLYAREA_WATER))
- m_areaType = SAMPLE_POLYAREA_WATER;
- if (imguiCheck("Road", m_areaType == SAMPLE_POLYAREA_ROAD))
- m_areaType = SAMPLE_POLYAREA_ROAD;
- if (imguiCheck("Door", m_areaType == SAMPLE_POLYAREA_DOOR))
- m_areaType = SAMPLE_POLYAREA_DOOR;
- if (imguiCheck("Grass", m_areaType == SAMPLE_POLYAREA_GRASS))
- m_areaType = SAMPLE_POLYAREA_GRASS;
- if (imguiCheck("Jump", m_areaType == SAMPLE_POLYAREA_JUMP))
- m_areaType = SAMPLE_POLYAREA_JUMP;
- imguiUnindent();
- imguiSeparator();
- if (imguiButton("Clear Shape"))
- {
- m_npts = 0;
- m_nhull = 0;
- }
- }
- void ConvexVolumeTool::handleClick(const float* /*s*/, 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 && rcVdistSqr(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)
- rcVcopy(&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;
- if (m_polyOffset > 0.01f)
- {
- float offset[MAX_PTS*2*3];
- int noffset = rcOffsetPoly(verts, m_nhull, m_polyOffset, offset, MAX_PTS*2);
- if (noffset > 0)
- geom->addConvexVolume(offset, noffset, minh, maxh, (unsigned char)m_areaType);
- }
- else
- {
- 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)
- {
- rcVcopy(&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::handleToggle()
- {
- }
- void ConvexVolumeTool::handleStep()
- {
- }
- void ConvexVolumeTool::handleUpdate(const float /*dt*/)
- {
- }
- void ConvexVolumeTool::handleRender()
- {
- duDebugDraw& dd = m_sample->getDebugDraw();
-
- // Find height extent 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)
- {
- // Tool help
- const int h = view[3];
- if (!m_npts)
- {
- 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));
- }
-
- }
|