ConvexVolumeTool.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #define _USE_MATH_DEFINES
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <float.h>
  23. #include "SDL.h"
  24. #include "SDL_opengl.h"
  25. #include "imgui.h"
  26. #include "ConvexVolumeTool.h"
  27. #include "InputGeom.h"
  28. #include "Sample.h"
  29. #include "Recast.h"
  30. #include "RecastDebugDraw.h"
  31. #include "DetourDebugDraw.h"
  32. #ifdef WIN32
  33. # define snprintf _snprintf
  34. #endif
  35. // Quick and dirty convex hull.
  36. // Returns true if 'c' is left of line 'a'-'b'.
  37. inline bool left(const float* a, const float* b, const float* c)
  38. {
  39. const float u1 = b[0] - a[0];
  40. const float v1 = b[2] - a[2];
  41. const float u2 = c[0] - a[0];
  42. const float v2 = c[2] - a[2];
  43. return u1 * v2 - v1 * u2 < 0;
  44. }
  45. // Returns true if 'a' is more lower-left than 'b'.
  46. inline bool cmppt(const float* a, const float* b)
  47. {
  48. if (a[0] < b[0]) return true;
  49. if (a[0] > b[0]) return false;
  50. if (a[2] < b[2]) return true;
  51. if (a[2] > b[2]) return false;
  52. return false;
  53. }
  54. // Calculates convex hull on xz-plane of points on 'pts',
  55. // stores the indices of the resulting hull in 'out' and
  56. // returns number of points on hull.
  57. static int convexhull(const float* pts, int npts, int* out)
  58. {
  59. // Find lower-leftmost point.
  60. int hull = 0;
  61. for (int i = 1; i < npts; ++i)
  62. if (cmppt(&pts[i*3], &pts[hull*3]))
  63. hull = i;
  64. // Gift wrap hull.
  65. int endpt = 0;
  66. int i = 0;
  67. do
  68. {
  69. out[i++] = hull;
  70. endpt = 0;
  71. for (int j = 1; j < npts; ++j)
  72. if (hull == endpt || left(&pts[hull*3], &pts[endpt*3], &pts[j*3]))
  73. endpt = j;
  74. hull = endpt;
  75. }
  76. while (endpt != out[0]);
  77. return i;
  78. }
  79. static int pointInPoly(int nvert, const float* verts, const float* p)
  80. {
  81. int i, j, c = 0;
  82. for (i = 0, j = nvert-1; i < nvert; j = i++)
  83. {
  84. const float* vi = &verts[i*3];
  85. const float* vj = &verts[j*3];
  86. if (((vi[2] > p[2]) != (vj[2] > p[2])) &&
  87. (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
  88. c = !c;
  89. }
  90. return c;
  91. }
  92. ConvexVolumeTool::ConvexVolumeTool() :
  93. m_sample(0),
  94. m_areaType(SAMPLE_POLYAREA_GRASS),
  95. m_polyOffset(0.0f),
  96. m_boxHeight(6.0f),
  97. m_boxDescent(1.0f),
  98. m_npts(0),
  99. m_nhull(0)
  100. {
  101. }
  102. void ConvexVolumeTool::init(Sample* sample)
  103. {
  104. m_sample = sample;
  105. }
  106. void ConvexVolumeTool::reset()
  107. {
  108. m_npts = 0;
  109. m_nhull = 0;
  110. }
  111. void ConvexVolumeTool::handleMenu()
  112. {
  113. imguiSlider("Shape Height", &m_boxHeight, 0.1f, 20.0f, 0.1f);
  114. imguiSlider("Shape Descent", &m_boxDescent, 0.1f, 20.0f, 0.1f);
  115. imguiSlider("Poly Offset", &m_polyOffset, 0.0f, 10.0f, 0.1f);
  116. imguiSeparator();
  117. imguiLabel("Area Type");
  118. imguiIndent();
  119. if (imguiCheck("Ground", m_areaType == SAMPLE_POLYAREA_GROUND))
  120. m_areaType = SAMPLE_POLYAREA_GROUND;
  121. if (imguiCheck("Water", m_areaType == SAMPLE_POLYAREA_WATER))
  122. m_areaType = SAMPLE_POLYAREA_WATER;
  123. if (imguiCheck("Road", m_areaType == SAMPLE_POLYAREA_ROAD))
  124. m_areaType = SAMPLE_POLYAREA_ROAD;
  125. if (imguiCheck("Door", m_areaType == SAMPLE_POLYAREA_DOOR))
  126. m_areaType = SAMPLE_POLYAREA_DOOR;
  127. if (imguiCheck("Grass", m_areaType == SAMPLE_POLYAREA_GRASS))
  128. m_areaType = SAMPLE_POLYAREA_GRASS;
  129. if (imguiCheck("Jump", m_areaType == SAMPLE_POLYAREA_JUMP))
  130. m_areaType = SAMPLE_POLYAREA_JUMP;
  131. imguiUnindent();
  132. imguiSeparator();
  133. if (imguiButton("Clear Shape"))
  134. {
  135. m_npts = 0;
  136. m_nhull = 0;
  137. }
  138. }
  139. void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift)
  140. {
  141. if (!m_sample) return;
  142. InputGeom* geom = m_sample->getInputGeom();
  143. if (!geom) return;
  144. if (shift)
  145. {
  146. // Delete
  147. int nearestIndex = -1;
  148. const ConvexVolume* vols = geom->getConvexVolumes();
  149. for (int i = 0; i < geom->getConvexVolumeCount(); ++i)
  150. {
  151. if (pointInPoly(vols[i].nverts, vols[i].verts, p) &&
  152. p[1] >= vols[i].hmin && p[1] <= vols[i].hmax)
  153. {
  154. nearestIndex = i;
  155. }
  156. }
  157. // If end point close enough, delete it.
  158. if (nearestIndex != -1)
  159. {
  160. geom->deleteConvexVolume(nearestIndex);
  161. }
  162. }
  163. else
  164. {
  165. // Create
  166. // If clicked on that last pt, create the shape.
  167. if (m_npts && rcVdistSqr(p, &m_pts[(m_npts-1)*3]) < rcSqr(0.2f))
  168. {
  169. if (m_nhull > 2)
  170. {
  171. // Create shape.
  172. float verts[MAX_PTS*3];
  173. for (int i = 0; i < m_nhull; ++i)
  174. rcVcopy(&verts[i*3], &m_pts[m_hull[i]*3]);
  175. float minh = FLT_MAX, maxh = 0;
  176. for (int i = 0; i < m_nhull; ++i)
  177. minh = rcMin(minh, verts[i*3+1]);
  178. minh -= m_boxDescent;
  179. maxh = minh + m_boxHeight;
  180. if (m_polyOffset > 0.01f)
  181. {
  182. float offset[MAX_PTS*2*3];
  183. int noffset = rcOffsetPoly(verts, m_nhull, m_polyOffset, offset, MAX_PTS*2);
  184. if (noffset > 0)
  185. geom->addConvexVolume(offset, noffset, minh, maxh, (unsigned char)m_areaType);
  186. }
  187. else
  188. {
  189. geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned char)m_areaType);
  190. }
  191. }
  192. m_npts = 0;
  193. m_nhull = 0;
  194. }
  195. else
  196. {
  197. // Add new point
  198. if (m_npts < MAX_PTS)
  199. {
  200. rcVcopy(&m_pts[m_npts*3], p);
  201. m_npts++;
  202. // Update hull.
  203. if (m_npts > 1)
  204. m_nhull = convexhull(m_pts, m_npts, m_hull);
  205. else
  206. m_nhull = 0;
  207. }
  208. }
  209. }
  210. }
  211. void ConvexVolumeTool::handleToggle()
  212. {
  213. }
  214. void ConvexVolumeTool::handleStep()
  215. {
  216. }
  217. void ConvexVolumeTool::handleUpdate(const float /*dt*/)
  218. {
  219. }
  220. void ConvexVolumeTool::handleRender()
  221. {
  222. duDebugDraw& dd = m_sample->getDebugDraw();
  223. // Find height extent of the shape.
  224. float minh = FLT_MAX, maxh = 0;
  225. for (int i = 0; i < m_npts; ++i)
  226. minh = rcMin(minh, m_pts[i*3+1]);
  227. minh -= m_boxDescent;
  228. maxh = minh + m_boxHeight;
  229. dd.begin(DU_DRAW_POINTS, 4.0f);
  230. for (int i = 0; i < m_npts; ++i)
  231. {
  232. unsigned int col = duRGBA(255,255,255,255);
  233. if (i == m_npts-1)
  234. col = duRGBA(240,32,16,255);
  235. dd.vertex(m_pts[i*3+0],m_pts[i*3+1]+0.1f,m_pts[i*3+2], col);
  236. }
  237. dd.end();
  238. dd.begin(DU_DRAW_LINES, 2.0f);
  239. for (int i = 0, j = m_nhull-1; i < m_nhull; j = i++)
  240. {
  241. const float* vi = &m_pts[m_hull[j]*3];
  242. const float* vj = &m_pts[m_hull[i]*3];
  243. dd.vertex(vj[0],minh,vj[2], duRGBA(255,255,255,64));
  244. dd.vertex(vi[0],minh,vi[2], duRGBA(255,255,255,64));
  245. dd.vertex(vj[0],maxh,vj[2], duRGBA(255,255,255,64));
  246. dd.vertex(vi[0],maxh,vi[2], duRGBA(255,255,255,64));
  247. dd.vertex(vj[0],minh,vj[2], duRGBA(255,255,255,64));
  248. dd.vertex(vj[0],maxh,vj[2], duRGBA(255,255,255,64));
  249. }
  250. dd.end();
  251. }
  252. void ConvexVolumeTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* view)
  253. {
  254. // Tool help
  255. const int h = view[3];
  256. if (!m_npts)
  257. {
  258. 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));
  259. }
  260. else
  261. {
  262. 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));
  263. imguiDrawText(280, h-60, IMGUI_ALIGN_LEFT, "The shape will be convex hull of all added points.", imguiRGBA(255,255,255,192));
  264. }
  265. }