mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Recast: fully implement cylindric and AABB shape volumes
Cylindric and AABB volumes can now also be used to mark out area's on the NavMesh. The raycast tests now also take the new shapes into account. User can now also add shapes through the ShapeVolumeTool (previously ConvexVolumeTool). The geomset format has changed slightly: - identifier 'o' now maps to off-mesh links (previously 'c'). - identifier 'p' now maps to convex polygon volumes (previously 'v'). - identifier 'c' maps to cylinder volumes. - identifier 'b' maps to box volumes.
This commit is contained in:
parent
0722def4d8
commit
290f78f8c8
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
///@}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user