diff --git a/src/naveditor/ConvexVolumeTool.cpp b/src/naveditor/ConvexVolumeTool.cpp index 3edf84d5..efdcdabb 100644 --- a/src/naveditor/ConvexVolumeTool.cpp +++ b/src/naveditor/ConvexVolumeTool.cpp @@ -75,36 +75,76 @@ static int convexhull(const float* pts, int npts, int* out) } -ConvexVolumeTool::ConvexVolumeTool() : +ShapeVolumeTool::ShapeVolumeTool() : m_editor(0), + m_selectedPrimitive(VOLUME_CONVEX), m_areaType(RC_NULL_AREA), m_polyFlags(0), - m_polyOffset(0.0f), - m_boxHeight(650.0f), - m_boxDescent(150.0f), + m_boxDescent(32), + m_boxAscent(32), + m_cylinderRadius(64), + m_cylinderHeight(128), + m_convexOffset(0.0f), + m_convexHeight(650.0f), + m_convexDescent(150.0f), m_npts(0), m_nhull(0) { } -void ConvexVolumeTool::init(Editor* editor) +void ShapeVolumeTool::init(Editor* editor) { m_editor = editor; } -void ConvexVolumeTool::reset() +void ShapeVolumeTool::reset() { m_npts = 0; m_nhull = 0; } -void ConvexVolumeTool::handleMenu() +static const char* s_primitiveNames[] = { + "Box", + "Cylinder", + "Convex" +}; + +void ShapeVolumeTool::handleMenu() { + if (ImGui::BeginCombo("Primitive", s_primitiveNames[m_selectedPrimitive])) + { + for (int i = 0; i < V_ARRAYSIZE(s_primitiveNames); i++) + { + if (ImGui::Selectable(s_primitiveNames[i], i == m_selectedPrimitive)) + { + m_selectedPrimitive = i; + + m_npts = 0; + m_nhull = 0; + } + } + + ImGui::EndCombo(); + } + ImGui::PushItemWidth(120.f); - ImGui::SliderFloat("Shape Height", &m_boxHeight, 0.1f, MAX_COORD_FLOAT); - ImGui::SliderFloat("Shape Descent", &m_boxDescent, 0.1f, MAX_COORD_FLOAT); - ImGui::SliderFloat("Poly Offset", &m_polyOffset, 0.0f, MAX_COORD_FLOAT/2); + switch (m_selectedPrimitive) + { + case VOLUME_BOX: + ImGui::SliderFloat("Box Descent", &m_boxDescent, 0.1f, 4000); + ImGui::SliderFloat("Box Ascent", &m_boxAscent, 0.1f, 4000); + break; + case VOLUME_CYLINDER: + ImGui::SliderFloat("Cylinder Radius", &m_cylinderRadius, 0.1f, 4000); + ImGui::SliderFloat("Cylinder Height", &m_cylinderHeight, 0.1f, 4000); + break; + case VOLUME_CONVEX: + ImGui::SliderFloat("Convex Height", &m_convexHeight, 0.1f, 4000); + ImGui::SliderFloat("Convex Descent", &m_convexDescent, 0.1f, 4000); + ImGui::SliderFloat("Convex Offset", &m_convexOffset, 0.0f, 2000); + break; + } ImGui::PopItemWidth(); @@ -148,7 +188,7 @@ void ConvexVolumeTool::handleMenu() } } -void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift) +void ShapeVolumeTool::handleClick(const float* /*s*/, const float* p, bool shift) { if (!m_editor) return; InputGeom* geom = m_editor->getInputGeom(); @@ -158,7 +198,7 @@ void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shif { // Delete int nearestIndex = -1; - const ConvexVolume* vols = geom->getConvexVolumes(); + const ShapeVolume* vols = geom->getConvexVolumes(); for (int i = 0; i < geom->getConvexVolumeCount(); ++i) { if (rdPointInPolygon(p, vols[i].verts, vols[i].nverts) && @@ -173,77 +213,106 @@ void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shif geom->deleteConvexVolume(nearestIndex); } } - else + else // Create { - // Create - - // If clicked on that last pt, create the shape. - if (m_npts && rdVdistSqr(p, &m_pts[(m_npts-1)*3]) < rdSqr(0.2f)) + switch (m_selectedPrimitive) { - if (m_nhull > 2) - { - // Create shape. - float verts[MAX_PTS*3]; - for (int i = 0; i < m_nhull; ++i) - rdVcopy(&verts[i*3], &m_pts[m_hull[i]*3]); - - float minh = FLT_MAX, maxh = 0; - for (int i = 0; i < m_nhull; ++i) - minh = rdMin(minh, verts[i*3+2]); - minh -= m_boxDescent; - maxh = minh + m_boxHeight; + case VOLUME_BOX: + rdVcopy(&m_pts[m_npts*3], p); + m_npts++; - 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 short)m_polyFlags, (unsigned char)m_areaType); - } - else - { - geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned short)m_polyFlags, (unsigned char)m_areaType); - } + if (m_npts > 1) + { + float* bmin = &m_pts[0*3]; + float* bmax = &m_pts[1*3]; + + if (bmin[0] > bmax[0]) + rdSwap(bmin[0], bmax[0]); + if (bmin[1] > bmax[1]) + rdSwap(bmin[1], bmax[1]); + if (bmin[2] > bmax[2]) + rdSwap(bmin[2], bmax[2]); + + bmin[2] -= m_boxDescent; + bmax[2] += m_boxAscent; + + geom->addBoxVolume(&m_pts[0*3], &m_pts[1*3], (unsigned short)m_polyFlags, (unsigned char)m_areaType); + + m_npts = 0; + m_nhull = 0; } - - m_npts = 0; - m_nhull = 0; + break; + case VOLUME_CYLINDER: + geom->addCylinderVolume(p, m_cylinderRadius, m_cylinderHeight, (unsigned short)m_polyFlags, (unsigned char)m_areaType); + break; + case VOLUME_CONVEX: + // If clicked on that last pt, create the shape. + if (m_npts && rdVdistSqr(p, &m_pts[(m_npts-1)*3]) < rdSqr(0.2f)) + { + if (m_nhull > 2) + { + // Create shape. + float verts[MAX_PTS*3]; + for (int i = 0; i < m_nhull; ++i) + rdVcopy(&verts[i*3], &m_pts[m_hull[i]*3]); + + float minh = FLT_MAX, maxh = 0; + for (int i = 0; i < m_nhull; ++i) + minh = rdMin(minh, verts[i*3+2]); + minh -= m_convexDescent; + maxh = minh + m_convexHeight; + + if (m_convexOffset > 0.01f) + { + float offset[MAX_PTS*2*3]; + const int noffset = rcOffsetPoly(verts, m_nhull, m_convexOffset, offset, MAX_PTS*2); + if (noffset > 0) + geom->addConvexVolume(offset, noffset, minh, maxh, (unsigned short)m_polyFlags, (unsigned char)m_areaType); + } + else + { + geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned short)m_polyFlags, (unsigned char)m_areaType); + } + } + + m_npts = 0; + m_nhull = 0; + } + else + { + // Add new point + if (m_npts < MAX_PTS) + { + rdVcopy(&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; + } + } + break; } - else - { - // Add new point - if (m_npts < MAX_PTS) - { - rdVcopy(&m_pts[m_npts*3], p); - const float* f = &m_pts[m_npts * 3]; - - printf("<%f, %f, %f>\n", f[0], f[1], f[2]); - - m_npts++; - // Update hull. - if (m_npts > 1) - m_nhull = convexhull(m_pts, m_npts, m_hull); - else - m_nhull = 0; - } - } } - + + printf("<%f, %f, %f>\n", p[0], p[1], p[2]); } -void ConvexVolumeTool::handleToggle() +void ShapeVolumeTool::handleToggle() { } -void ConvexVolumeTool::handleStep() +void ShapeVolumeTool::handleStep() { } -void ConvexVolumeTool::handleUpdate(const float /*dt*/) +void ShapeVolumeTool::handleUpdate(const float /*dt*/) { } -void ConvexVolumeTool::handleRender() +void ShapeVolumeTool::handleRender() { duDebugDraw& dd = m_editor->getDebugDraw(); const float* drawOffset = m_editor->getDetourDrawOffset(); @@ -252,8 +321,8 @@ void ConvexVolumeTool::handleRender() float minh = FLT_MAX, maxh = 0; for (int i = 0; i < m_npts; ++i) minh = rdMin(minh, m_pts[i*3+2]); - minh -= m_boxDescent; - maxh = minh + m_boxHeight; + minh -= m_convexDescent; + maxh = minh + m_convexHeight; dd.begin(DU_DRAW_POINTS, 4.0f, drawOffset); for (int i = 0; i < m_npts; ++i) @@ -261,26 +330,30 @@ void ConvexVolumeTool::handleRender() 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],m_pts[i*3+2]+0.1f, col);//Needs to be flipped (y = z). + + dd.vertex(m_pts[i*3+0],m_pts[i*3+1],m_pts[i*3+2]+0.1f, col); } dd.end(); - dd.begin(DU_DRAW_LINES, 2.0f, drawOffset); - for (int i = 0, j = m_nhull-1; i < m_nhull; j = i++) + if (m_selectedPrimitive == VOLUME_CONVEX) { - const float* vi = &m_pts[m_hull[j]*3]; - const float* vj = &m_pts[m_hull[i]*3]; - dd.vertex(vj[0],vj[1],minh, duRGBA(255, 255, 255, 64)); - dd.vertex(vi[0],vi[1],minh, duRGBA(255, 255, 255, 64)); - dd.vertex(vj[0],vj[1],maxh, duRGBA(255, 255, 255, 64)); - dd.vertex(vi[0],vi[1],maxh, duRGBA(255, 255, 255, 64)); - dd.vertex(vj[0],vj[1],minh, duRGBA(255, 255, 255, 64)); - dd.vertex(vj[0],vj[1],maxh, duRGBA(255,255,255,64)); + dd.begin(DU_DRAW_LINES, 2.0f, drawOffset); + 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],vj[1],minh, duRGBA(255,255,255,64)); + dd.vertex(vi[0],vi[1],minh, duRGBA(255,255,255,64)); + dd.vertex(vj[0],vj[1],maxh, duRGBA(255,255,255,64)); + dd.vertex(vi[0],vi[1],maxh, duRGBA(255,255,255,64)); + dd.vertex(vj[0],vj[1],minh, duRGBA(255,255,255,64)); + dd.vertex(vj[0],vj[1],maxh, duRGBA(255,255,255,64)); + } + dd.end(); } - dd.end(); } -void ConvexVolumeTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* /*view*/) +void ShapeVolumeTool::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* /*view*/) { // Tool help if (!m_npts) diff --git a/src/naveditor/Editor_Common.cpp b/src/naveditor/Editor_Common.cpp index b8edd49f..6d3e2698 100644 --- a/src/naveditor/Editor_Common.cpp +++ b/src/naveditor/Editor_Common.cpp @@ -382,6 +382,7 @@ void Editor_StaticTileMeshCommon::renderTileMeshData() // TODO: also add flags for this m_geom->drawBoxVolumes(&m_dd, recastDrawOffset); + m_geom->drawCylinderVolumes(&m_dd, recastDrawOffset); m_geom->drawConvexVolumes(&m_dd, recastDrawOffset); // NOTE: commented out because this already gets rendered when the off-mesh @@ -579,6 +580,7 @@ void Editor_DynamicTileMeshCommon::renderTileMeshData() // TODO: also add flags for this m_geom->drawBoxVolumes(&m_dd, recastDrawOffset); + m_geom->drawCylinderVolumes(&m_dd, recastDrawOffset); m_geom->drawConvexVolumes(&m_dd, recastDrawOffset); // NOTE: commented out because this already gets rendered when the off-mesh diff --git a/src/naveditor/Editor_SoloMesh.cpp b/src/naveditor/Editor_SoloMesh.cpp index 510d5749..a3dc339b 100644 --- a/src/naveditor/Editor_SoloMesh.cpp +++ b/src/naveditor/Editor_SoloMesh.cpp @@ -92,10 +92,10 @@ void Editor_SoloMesh::handleTools() setTool(new OffMeshConnectionTool); } - enabled = type == TOOL_CONVEX_VOLUME; - if (ImGui::Checkbox("Create Convex Volumes", &enabled)) + enabled = type == TOOL_SHAPE_VOLUME; + if (ImGui::Checkbox("Create Shape Volumes", &enabled)) { - setTool(new ConvexVolumeTool); + setTool(new ShapeVolumeTool); } enabled = type == TOOL_CROWD; @@ -299,7 +299,7 @@ bool Editor_SoloMesh::handleBuild() } // (Optional) Mark areas. - const ConvexVolume* vols = m_geom->getConvexVolumes(); + const ShapeVolume* vols = m_geom->getConvexVolumes(); for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned short)vols[i].flags, (unsigned char)vols[i].area, *m_chf); diff --git a/src/naveditor/Editor_TempObstacles.cpp b/src/naveditor/Editor_TempObstacles.cpp index 7a52de2b..ad7ad9e7 100644 --- a/src/naveditor/Editor_TempObstacles.cpp +++ b/src/naveditor/Editor_TempObstacles.cpp @@ -38,43 +38,6 @@ static const int EXPECTED_LAYERS_PER_TILE = 4; -static bool isectSegAABB(const float* sp, const float* sq, - const float* amin, const float* amax, - float& tmin, float& tmax) -{ - float d[3]; - rdVsub(d, sq, sp); - tmin = 0; // set to -FLT_MAX to get first hit on line - tmax = FLT_MAX; // set to max distance ray can travel (for segment) - - // For all three slabs - for (int i = 0; i < 3; i++) - { - if (fabsf(d[i]) < RD_EPS) - { - // Ray is parallel to slab. No hit if origin not within slab - if (sp[i] < amin[i] || sp[i] > amax[i]) - return false; - } - else - { - // Compute intersection t value of ray with near and far plane of slab - const float ood = 1.0f / d[i]; - float t1 = (amin[i] - sp[i]) * ood; - float t2 = (amax[i] - sp[i]) * ood; - // Make t1 be intersection with near plane, t2 with far plane - if (t1 > t2) rdSwap(t1, t2); - // Compute the intersection of slab intersections intervals - if (t1 > tmin) tmin = t1; - if (t2 < tmax) tmax = t2; - // Exit with no collision as soon as slab intersection becomes empty - if (tmin > tmax) return false; - } - } - - return true; -} - static int calcLayerBufferSize(const int gridWidth, const int gridHeight) { const int headerSize = rdAlign4(sizeof(dtTileCacheLayerHeader)); @@ -397,7 +360,7 @@ int Editor_TempObstacles::rasterizeTileLayers( } // (Optional) Mark areas. - const ConvexVolume* vols = m_geom->getConvexVolumes(); + const ShapeVolume* vols = m_geom->getConvexVolumes(); for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) { rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, @@ -610,7 +573,7 @@ dtObstacleRef hitTestObstacle(const dtTileCache* tc, const float* sp, const floa float bmin[3], bmax[3], t0,t1; tc->getObstacleBounds(ob, bmin,bmax); - if (isectSegAABB(sp,sq, bmin,bmax, t0,t1)) + if (rdIntersectSegmentAABB(sp,sq, bmin,bmax, t0,t1)) { if (t0 < tmin) { @@ -892,10 +855,10 @@ void Editor_TempObstacles::handleTools() setTool(new OffMeshConnectionTool); } - enabled = type == TOOL_CONVEX_VOLUME; - if (ImGui::Checkbox("Create Convex Volumes", &enabled)) + enabled = type == TOOL_SHAPE_VOLUME; + if (ImGui::Checkbox("Create Shape Volumes", &enabled)) { - setTool(new ConvexVolumeTool); + setTool(new ShapeVolumeTool); } enabled = type == TOOL_CROWD; diff --git a/src/naveditor/Editor_TileMesh.cpp b/src/naveditor/Editor_TileMesh.cpp index 563758a6..07efe4a5 100644 --- a/src/naveditor/Editor_TileMesh.cpp +++ b/src/naveditor/Editor_TileMesh.cpp @@ -513,10 +513,10 @@ void Editor_TileMesh::handleTools() setTool(new OffMeshConnectionTool); } - isEnabled = type == TOOL_CONVEX_VOLUME; - if (ImGui::Checkbox("Create Convex Volumes", &isEnabled)) + isEnabled = type == TOOL_SHAPE_VOLUME; + if (ImGui::Checkbox("Create Shape Volumes", &isEnabled)) { - setTool(new ConvexVolumeTool); + setTool(new ShapeVolumeTool); } isEnabled = type == TOOL_CROWD; @@ -1103,15 +1103,23 @@ unsigned char* Editor_TileMesh::buildTileMesh(const int tx, const int ty, const } // (Optional) Mark areas. - const ConvexVolume* vols = m_geom->getConvexVolumes(); + const ShapeVolume* vols = m_geom->getConvexVolumes(); for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i) { - const ConvexVolume& vol = vols[i]; + const ShapeVolume& vol = vols[i]; - if (vol.bbox) + switch (vol.type) + { + case VOLUME_BOX: rcMarkBoxArea(m_ctx, &vol.verts[0], &vol.verts[3], vol.flags, vol.area, *m_chf); - else + break; + case VOLUME_CYLINDER: + rcMarkCylinderArea(m_ctx, &vol.verts[0], vol.verts[3], vol.verts[4], vol.flags, vol.area, *m_chf); + break; + case VOLUME_CONVEX: rcMarkConvexPolyArea(m_ctx, vol.verts, vol.nverts, vol.hmin, vol.hmax, vol.flags, vol.area, *m_chf); + break; + } } diff --git a/src/naveditor/InputGeom.cpp b/src/naveditor/InputGeom.cpp index 82d33fa1..99365420 100644 --- a/src/naveditor/InputGeom.cpp +++ b/src/naveditor/InputGeom.cpp @@ -278,7 +278,7 @@ bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath) } } } - else if (row[0] == 'c') + else if (row[0] == 'o') { // Off-mesh connection if (m_offMeshConCount < MAX_OFFMESH_CONNECTIONS) @@ -311,21 +311,35 @@ bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath) // Box volumes if (m_volumeCount < MAX_VOLUMES) { - ConvexVolume* vol = &m_volumes[m_volumeCount++]; + ShapeVolume* vol = &m_volumes[m_volumeCount++]; sscanf(row+1, "%hu %hhu %f %f %f %f %f %f", &vol->flags, &vol->area, &vol->verts[0], &vol->verts[1], &vol->verts[2], &vol->verts[3], &vol->verts[4], &vol->verts[5]); - vol->bbox = true; + vol->type = VOLUME_BOX; } } - else if (row[0] == 'v') + else if (row[0] == 'c') { - // Convex volumes + // Cylinder volumes if (m_volumeCount < MAX_VOLUMES) { - ConvexVolume* vol = &m_volumes[m_volumeCount++]; + ShapeVolume* vol = &m_volumes[m_volumeCount++]; + + sscanf(row + 1, "%hu %hhu %f %f %f %f %f", &vol->flags, &vol->area, + &vol->verts[0], &vol->verts[1], &vol->verts[2], + &vol->verts[3], &vol->verts[4]); + + vol->type = VOLUME_CYLINDER; + } + } + else if (row[0] == 'p') + { + // Convex polygon volumes + if (m_volumeCount < MAX_VOLUMES) + { + ShapeVolume* vol = &m_volumes[m_volumeCount++]; sscanf(row+1, "%d %hu %hhu %f %f", &vol->nverts, &vol->flags, &vol->area, &vol->hmin, &vol->hmax); for (int i = 0; i < vol->nverts; ++i) { @@ -334,7 +348,7 @@ bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath) sscanf(row, "%f %f %f", &vol->verts[i*3+0], &vol->verts[i*3+1], &vol->verts[i*3+2]); } - vol->bbox = false; + vol->type = VOLUME_CONVEX; } } else if (row[0] == 's') @@ -456,7 +470,7 @@ bool InputGeom::saveGeomSet(const BuildSettings* settings) const int order = m_offMeshConOrders[i]; const int area = m_offMeshConAreas[i]; const int flags = m_offMeshConFlags[i]; - fprintf(fp, "c %f %f %f %f %f %f %f %f %f %f %f %d %d %d %d %d\n", + fprintf(fp, "o %f %f %f %f %f %f %f %f %f %f %f %d %d %d %d %d\n", verts[0], verts[1], verts[2], verts[3], verts[4], verts[5], refs[0], refs[1], refs[2], @@ -468,18 +482,24 @@ bool InputGeom::saveGeomSet(const BuildSettings* settings) // Convex volumes for (int i = 0; i < m_volumeCount; ++i) { - ConvexVolume* vol = &m_volumes[i]; - if (vol->bbox) + ShapeVolume* vol = &m_volumes[i]; + + switch (vol->type) { + case VOLUME_BOX: fprintf(fp, "b %hu %hhu %f %f %f %f %f %f\n", vol->flags, vol->area, vol->verts[0], vol->verts[1], vol->verts[2], vol->verts[3], vol->verts[4], vol->verts[5]); - } - else - { - fprintf(fp, "v %d %hu %hhu %f %f\n", vol->nverts, vol->flags, vol->area, vol->hmin, vol->hmax); - for (int j = 0; j < vol->nverts; ++j) - fprintf(fp, "%f %f %f\n", vol->verts[j*3+0], vol->verts[j*3+1], vol->verts[j*3+2]); + break; + case VOLUME_CYLINDER: + fprintf(fp, "c %hu %hhu %f %f %f %f %f\n", vol->flags, vol->area, + vol->verts[0], vol->verts[1], vol->verts[2], + vol->verts[3], vol->verts[4]); + break; + case VOLUME_CONVEX: + fprintf(fp, "p %d %hu %hhu %f %f\n", vol->nverts, vol->flags, vol->area, vol->hmin, vol->hmax); + for (int j = 0; j < vol->nverts; ++j) + fprintf(fp, "%f %f %f\n", vol->verts[j*3+0], vol->verts[j*3+1], vol->verts[j*3+2]); } } @@ -488,45 +508,11 @@ bool InputGeom::saveGeomSet(const BuildSettings* settings) return true; } -static bool isectSegAABB(const float* sp, const float* sq, - const float* amin, const float* amax, - float& tmin, float& tmax) -{ - float d[3]; - d[0] = sq[0] - sp[0]; - d[1] = sq[1] - sp[1]; - d[2] = sq[2] - sp[2]; - tmin = 0.0; - tmax = 1.0f; - - for (int i = 0; i < 3; i++) - { - if (rdMathFabsf(d[i]) < RD_EPS) - { - if (sp[i] < amin[i] || sp[i] > amax[i]) - return false; - } - else - { - const float ood = 1.0f / d[i]; - float t1 = (amin[i] - sp[i]) * ood; - float t2 = (amax[i] - sp[i]) * ood; - if (t1 > t2) { float tmp = t1; t1 = t2; t2 = tmp; } - if (t1 > tmin) tmin = t1; - if (t2 < tmax) tmax = t2; - if (tmin > tmax) return false; - } - } - - return true; -} - - bool InputGeom::raycastMesh(const float* src, const float* dst, float* tmin) const { // Prune hit ray. float btmin, btmax; - if (!isectSegAABB(src, dst, m_meshBMin, m_meshBMax, btmin, btmax)) + if (!rdIntersectSegmentAABB(src, dst, m_meshBMin, m_meshBMax, btmin, btmax)) return false; float p[2], q[2]; p[0] = src[0] + (dst[0]-src[0])*btmin; @@ -549,21 +535,40 @@ bool InputGeom::raycastMesh(const float* src, const float* dst, float* tmin) con for (int i = 0; i < nvol; i++) { - const ConvexVolume& vol = m_volumes[i]; + const ShapeVolume& vol = m_volumes[i]; if (vol.area != RC_NULL_AREA) continue; // Clip brushes only. - if ((src[2] >= vol.hmin && src[2] <= vol.hmax) || - (dst[2] >= vol.hmin && dst[2] <= vol.hmax)) + if (vol.type == VOLUME_BOX) { - if (rdIntersectSegmentPoly2D(src, dst, vol.verts, vol.nverts, - tsmin, tsmax, segMin, segMax)) + if (rdIntersectSegmentAABB(src, dst, &vol.verts[0], &vol.verts[3], tsmin, tsmax)) { hit = true; break; } } + else if (vol.type == VOLUME_CYLINDER) + { + if (rdIntersectSegmentCylinder(src, dst, &vol.verts[0], vol.verts[3], vol.verts[4], tsmin, tsmax)) + { + hit = true; + break; + } + } + else if (vol.type == VOLUME_CONVEX) + { + if ((src[2] >= vol.hmin && src[2] <= vol.hmax) || + (dst[2] >= vol.hmin && dst[2] <= vol.hmax)) + { + if (rdIntersectSegmentPoly2D(src, dst, vol.verts, vol.nverts, + tsmin, tsmax, segMin, segMax)) + { + hit = true; + break; + } + } + } } if (hit) @@ -693,18 +698,46 @@ void InputGeom::drawOffMeshConnections(duDebugDraw* dd, const float* offset, boo dd->depthMask(true); } +void InputGeom::addBoxVolume(const float* bmin, const float* bmax, + unsigned short flags, unsigned char area) +{ + if (m_volumeCount >= MAX_VOLUMES) return; + ShapeVolume* vol = &m_volumes[m_volumeCount++]; + memset(vol, 0, sizeof(ShapeVolume)); + rdVcopy(&vol->verts[0], bmin); + rdVcopy(&vol->verts[3], bmax); + vol->flags = flags; + vol->area = area; + vol->type = VOLUME_BOX; +} + +void InputGeom::addCylinderVolume(const float* pos, const float radius, + const float height, unsigned short flags, unsigned char area) +{ + if (m_volumeCount >= MAX_VOLUMES) return; + ShapeVolume* vol = &m_volumes[m_volumeCount++]; + memset(vol, 0, sizeof(ShapeVolume)); + rdVcopy(vol->verts, pos); + vol->verts[3] = radius; + vol->verts[4] = height; + vol->flags = flags; + vol->area = area; + vol->type = VOLUME_CYLINDER; +} + void InputGeom::addConvexVolume(const float* verts, const int nverts, const float minh, const float maxh, unsigned short flags, unsigned char area) { if (m_volumeCount >= MAX_VOLUMES) return; - ConvexVolume* vol = &m_volumes[m_volumeCount++]; - memset(vol, 0, sizeof(ConvexVolume)); + ShapeVolume* vol = &m_volumes[m_volumeCount++]; + memset(vol, 0, sizeof(ShapeVolume)); memcpy(vol->verts, verts, sizeof(float)*3*nverts); vol->hmin = minh; vol->hmax = maxh; vol->nverts = nverts; vol->flags = flags; vol->area = area; + vol->type = VOLUME_CONVEX; } void InputGeom::deleteConvexVolume(int i) @@ -717,16 +750,16 @@ void InputGeom::drawBoxVolumes(struct duDebugDraw* dd, const float* offset, bool { for (int i = 0; i < m_volumeCount; ++i) { - const ConvexVolume* vol = &m_volumes[i]; + const ShapeVolume* vol = &m_volumes[i]; - if (!vol->bbox) + if (vol->type != VOLUME_BOX) continue; const unsigned int faceCol = vol->area == RC_NULL_AREA - ? duRGBA(255, 0, 0, 128) // Use red for visibility (null acts as deletion). - : duTransCol(dd->areaToCol(vol->area), 64); + ? duRGBA(255, 0, 0, 168) // Use red for visibility (null acts as deletion). + : duTransCol(dd->areaToCol(vol->area), 168); - unsigned int fcol[6] = { faceCol, 0, faceCol, faceCol, faceCol, faceCol }; + unsigned int fcol[6] = { faceCol, faceCol, faceCol, faceCol, faceCol, faceCol }; duDebugDrawBox(dd, vol->verts[0],vol->verts[1],vol->verts[2], @@ -744,23 +777,53 @@ void InputGeom::drawBoxVolumes(struct duDebugDraw* dd, const float* offset, bool } } +void InputGeom::drawCylinderVolumes(struct duDebugDraw* dd, const float* offset, bool /*hilight*/) +{ + for (int i = 0; i < m_volumeCount; ++i) + { + const ShapeVolume* vol = &m_volumes[i]; + + if (vol->type != VOLUME_CYLINDER) + continue; + + const unsigned int faceCol = vol->area == RC_NULL_AREA + ? duRGBA(255, 0, 0, 168) // Use red for visibility (null acts as deletion). + : duTransCol(dd->areaToCol(vol->area), 168); + + const float radius = vol->verts[3]; + const float height = vol->verts[4]; + + duDebugDrawCylinder(dd, + vol->verts[0]-radius,vol->verts[1]-radius,vol->verts[2]+0.1f, + vol->verts[0]+radius,vol->verts[1]+radius,vol->verts[2]+height, faceCol, offset); + + const unsigned int wireCol = vol->area == RC_NULL_AREA + ? duRGBA(255, 0, 0, 220) + : duTransCol(dd->areaToCol(vol->area), 220); + + duDebugDrawCylinderWire(dd, + vol->verts[0]-radius,vol->verts[1]-radius,vol->verts[2]+0.1f, + vol->verts[0]+radius,vol->verts[1]+radius,vol->verts[2]+height, wireCol, 2.0f, offset); + } +} + void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, const float* offset, bool /*hilight*/) { dd->begin(DU_DRAW_TRIS, 1.0f, offset); for (int i = 0; i < m_volumeCount; ++i) { - const ConvexVolume* vol = &m_volumes[i]; + const ShapeVolume* vol = &m_volumes[i]; - if (vol->bbox) + if (vol->type != VOLUME_CONVEX) continue; unsigned int col; if (vol->area == RC_NULL_AREA) - col = duRGBA(255, 0, 0, 128); // Use red for visibility (null acts as deletion). + col = duRGBA(255, 0, 0, 168); // Use red for visibility (null acts as deletion). else - col = duTransCol(dd->areaToCol(vol->area), 64); + col = duTransCol(dd->areaToCol(vol->area), 168); for (int j = 0, k = vol->nverts-1; j < vol->nverts; k = j++) { @@ -786,9 +849,9 @@ void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, const float* offset, b dd->begin(DU_DRAW_LINES, 2.0f, offset); for (int i = 0; i < m_volumeCount; ++i) { - const ConvexVolume* vol = &m_volumes[i]; + const ShapeVolume* vol = &m_volumes[i]; - if (vol->bbox) + if (vol->type != VOLUME_CONVEX) continue; unsigned int col; @@ -815,15 +878,15 @@ void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, const float* offset, b dd->begin(DU_DRAW_POINTS, 3.0f, offset); for (int i = 0; i < m_volumeCount; ++i) { - const ConvexVolume* vol = &m_volumes[i]; + const ShapeVolume* vol = &m_volumes[i]; - if (vol->bbox) + if (vol->type != VOLUME_CONVEX) continue; unsigned int col; if (vol->area == RC_NULL_AREA) - col = duRGBA(255, 0, 0, 220); + col = duDarkenCol(duRGBA(255, 0, 0, 220)); else col = duDarkenCol(duTransCol(dd->areaToCol(vol->area), 220)); diff --git a/src/naveditor/include/ConvexVolumeTool.h b/src/naveditor/include/ConvexVolumeTool.h index bb021db3..108fd370 100644 --- a/src/naveditor/include/ConvexVolumeTool.h +++ b/src/naveditor/include/ConvexVolumeTool.h @@ -21,16 +21,24 @@ #include "NavEditor/Include/Editor.h" -// Tool to create convex volumess for InputGeom +// Tool to create shape volumes for InputGeom -class ConvexVolumeTool : public EditorTool +class ShapeVolumeTool : public EditorTool { Editor* m_editor; + int m_selectedPrimitive; int m_areaType; int m_polyFlags; - float m_polyOffset; - float m_boxHeight; + float m_boxDescent; + float m_boxAscent; + + float m_cylinderRadius; + float m_cylinderHeight; + + float m_convexOffset; + float m_convexHeight; + float m_convexDescent; static const int MAX_PTS = 12; float m_pts[MAX_PTS*3]; @@ -39,9 +47,9 @@ class ConvexVolumeTool : public EditorTool int m_nhull; public: - ConvexVolumeTool(); + ShapeVolumeTool(); - virtual int type() { return TOOL_CONVEX_VOLUME; } + virtual int type() { return TOOL_SHAPE_VOLUME; } virtual void init(Editor* editor); virtual void reset(); virtual void handleMenu(); diff --git a/src/naveditor/include/Editor.h b/src/naveditor/include/Editor.h index 33e3dd40..0096ed70 100644 --- a/src/naveditor/include/Editor.h +++ b/src/naveditor/include/Editor.h @@ -116,7 +116,7 @@ enum EditorToolType TOOL_NAVMESH_PRUNE, TOOL_OFFMESH_CONNECTION, TOOL_TRAVERSE_LINK, - TOOL_CONVEX_VOLUME, + TOOL_SHAPE_VOLUME, TOOL_CROWD, MAX_TOOLS }; diff --git a/src/naveditor/include/InputGeom.h b/src/naveditor/include/InputGeom.h index f3f45bf6..411d7161 100644 --- a/src/naveditor/include/InputGeom.h +++ b/src/naveditor/include/InputGeom.h @@ -22,15 +22,22 @@ #include "NavEditor/Include/ChunkyTriMesh.h" #include "NavEditor/Include/MeshLoaderObj.h" -static const int MAX_CONVEXVOL_PTS = 12; -struct ConvexVolume +enum VolumeType : unsigned char { - float verts[MAX_CONVEXVOL_PTS*3]; + VOLUME_BOX, + VOLUME_CYLINDER, + VOLUME_CONVEX +}; + +static const int MAX_SHAPEVOL_PTS = 12; +struct ShapeVolume +{ + float verts[MAX_SHAPEVOL_PTS*3]; float hmin, hmax; int nverts; unsigned short flags; unsigned char area; - bool bbox; + unsigned char type; }; struct BuildSettings @@ -104,7 +111,7 @@ class InputGeom /// @name Convex Volumes. ///@{ static const int MAX_VOLUMES = 256; - ConvexVolume m_volumes[MAX_VOLUMES]; + ShapeVolume m_volumes[MAX_VOLUMES]; int m_volumeCount; ///@} @@ -160,11 +167,16 @@ public: /// @name Box Volumes. ///@{ int getConvexVolumeCount() const { return m_volumeCount; } - const ConvexVolume* getConvexVolumes() const { return m_volumes; } + const ShapeVolume* getConvexVolumes() const { return m_volumes; } + void addBoxVolume(const float* bmin, const float* bmax, + unsigned short flags, unsigned char area); + void addCylinderVolume(const float* pos, const float radius, + const float height, unsigned short flags, unsigned char area); void addConvexVolume(const float* verts, const int nverts, const float minh, const float maxh, unsigned short flags, unsigned char area); void deleteConvexVolume(int i); void drawBoxVolumes(struct duDebugDraw* dd, const float* offset, bool hilight = false); + void drawCylinderVolumes(struct duDebugDraw* dd, const float* offset, bool hilight = false); void drawConvexVolumes(struct duDebugDraw* dd, const float* offset, bool hilight = false); ///@}