diff --git a/Recast/Include/Recast.h b/Recast/Include/Recast.h index e85c0d2e..a83641d8 100644 --- a/Recast/Include/Recast.h +++ b/Recast/Include/Recast.h @@ -441,6 +441,29 @@ struct rcPolyMeshDetail int ntris; ///< The number of triangles in #tris. }; +static const unsigned char RC_AREA_FLAGS_MASK = 0x3F; + +/// @ingroup recast +class rcAreaModification +{ +public: + /// Mask is set to all available bits, which means value is fully applied + /// @param[in] value The area id to apply. [Limit: <= #RC_AREA_FLAGS_MASK] + rcAreaModification(unsigned char value); + /// @param[in] value The area id to apply. [Limit: <= #RC_AREA_FLAGS_MASK] + /// @param[in] mask Bitwise mask used when applying value. [Limit: <= #RC_AREA_FLAGS_MASK] + rcAreaModification(unsigned char value, unsigned char mask); + rcAreaModification(const rcAreaModification& other); + void operator = (const rcAreaModification& other); + bool operator == (const rcAreaModification& other) const; + bool operator != (const rcAreaModification& other) const; + void apply(unsigned char& area) const; + unsigned char getMaskedValue() const; + + unsigned char m_value; ///< Value to apply to target area id + unsigned char m_mask; ///< Bitwise mask used when applying value to target area id +}; + /// @name Allocation Functions /// Functions used to allocate and de-allocate Recast objects. /// @see rcAllocSetCustom @@ -790,8 +813,7 @@ bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int heigh const float* bmin, const float* bmax, float cs, float ch); -/// Sets the area id of all triangles with a slope below the specified value -/// to #RC_WALKABLE_AREA. +/// Modifies the area id of all triangles with a slope below the specified value. /// @ingroup recast /// @param[in,out] ctx The build context to use during the operation. /// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. @@ -801,10 +823,11 @@ bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int heigh /// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] /// @param[in] nt The number of triangles. /// @param[out] areas The triangle area ids. [Length: >= @p nt] +/// @param[in] areaMod The area modification to apply. void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, - const int* tris, int nt, unsigned char* areas); + const int* tris, int nt, unsigned char* areas, rcAreaModification areaMod); -/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA. +/// Modifies the area id of all triangles with a slope greater than or equal to the specified value. /// @ingroup recast /// @param[in,out] ctx The build context to use during the operation. /// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. @@ -966,9 +989,9 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf); /// @param[in,out] ctx The build context to use during the operation. /// @param[in] bmin The minimum of the bounding box. [(x, y, z)] /// @param[in] bmax The maximum of the bounding box. [(x, y, z)] -/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in] areaMod The area modification to apply. /// @param[in,out] chf A populated compact heightfield. -void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, rcAreaModification areaMod, rcCompactHeightfield& chf); /// Applies the area id to the all spans within the specified convex polygon. @@ -978,10 +1001,10 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne /// @param[in] nverts The number of vertices in the polygon. /// @param[in] hmin The height of the base of the polygon. /// @param[in] hmax The height of the top of the polygon. -/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in] areaMod The area modification to apply. /// @param[in,out] chf A populated compact heightfield. void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, - const float hmin, const float hmax, unsigned char areaId, + const float hmin, const float hmax, rcAreaModification areaMod, rcCompactHeightfield& chf); /// Helper function to offset voncex polygons for rcMarkConvexPolyArea. @@ -1000,10 +1023,10 @@ int rcOffsetPoly(const float* verts, const int nverts, const float offset, /// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)] /// @param[in] r The radius of the cylinder. /// @param[in] h The height of the cylinder. -/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in] areaMod The area modification to apply. /// @param[in,out] chf A populated compact heightfield. void rcMarkCylinderArea(rcContext* ctx, const float* pos, - const float r, const float h, unsigned char areaId, + const float r, const float h, rcAreaModification areaMod, rcCompactHeightfield& chf); /// Builds the distance field for the specified compact heightfield. diff --git a/Recast/Source/Recast.cpp b/Recast/Source/Recast.cpp index 8308d197..4aefa682 100644 --- a/Recast/Source/Recast.cpp +++ b/Recast/Source/Recast.cpp @@ -71,6 +71,50 @@ void rcContext::log(const rcLogCategory category, const char* format, ...) doLog(category, msg, len); } +rcAreaModification::rcAreaModification(unsigned char value) : + m_value(value), + m_mask(RC_AREA_FLAGS_MASK) +{ +} + +rcAreaModification::rcAreaModification(unsigned char value, unsigned char mask) : + m_value(value), + m_mask(mask) +{ +} + +rcAreaModification::rcAreaModification(const rcAreaModification& other) : + m_value(other.m_value), + m_mask(other.m_mask) +{ +} + +void rcAreaModification::operator = (const rcAreaModification& other) +{ + m_value = other.m_value; + m_mask = other.m_mask; +} + +bool rcAreaModification::operator == (const rcAreaModification& other) const +{ + return ((m_value == other.m_value) && (m_mask == other.m_mask)); +} + +bool rcAreaModification::operator != (const rcAreaModification& other) const +{ + return ((m_value == other.m_value) && (m_mask == other.m_mask)); +} + +void rcAreaModification::apply(unsigned char& area) const +{ + area = ((m_value & m_mask) | (area & ~m_mask)); +} + +unsigned char rcAreaModification::getMaskedValue() const +{ + return (m_value & m_mask); +} + rcHeightfield* rcAllocHeightfield() { return new (rcAlloc(sizeof(rcHeightfield), RC_ALLOC_PERM)) rcHeightfield; @@ -263,7 +307,8 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, const int* tris, int nt, - unsigned char* areas) + unsigned char* areas, + rcAreaModification areaMod) { rcIgnoreUnused(ctx); rcIgnoreUnused(nv); @@ -278,7 +323,7 @@ void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm); // Check if the face is walkable. if (norm[1] > walkableThr) - areas[i] = RC_WALKABLE_AREA; + areaMod.apply(areas[i]); } } diff --git a/Recast/Source/RecastArea.cpp b/Recast/Source/RecastArea.cpp index 97139cf9..92d8b205 100644 --- a/Recast/Source/RecastArea.cpp +++ b/Recast/Source/RecastArea.cpp @@ -313,7 +313,7 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf) /// The value of spacial parameters are in world units. /// /// @see rcCompactHeightfield, rcMedianFilterWalkableArea -void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, rcAreaModification areaMod, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -348,7 +348,7 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne if ((int)s.y >= miny && (int)s.y <= maxy) { if (chf.areas[i] != RC_NULL_AREA) - chf.areas[i] = areaId; + areaMod.apply(chf.areas[i]); } } } @@ -379,7 +379,7 @@ static int pointInPoly(int nvert, const float* verts, const float* p) /// /// @see rcCompactHeightfield, rcMedianFilterWalkableArea void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, - const float hmin, const float hmax, unsigned char areaId, + const float hmin, const float hmax, rcAreaModification areaMod, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -435,7 +435,7 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, if (pointInPoly(nverts, verts, p)) { - chf.areas[i] = areaId; + areaMod.apply(chf.areas[i]); } } } @@ -527,7 +527,7 @@ int rcOffsetPoly(const float* verts, const int nverts, const float offset, /// /// @see rcCompactHeightfield, rcMedianFilterWalkableArea void rcMarkCylinderArea(rcContext* ctx, const float* pos, - const float r, const float h, unsigned char areaId, + const float r, const float h, rcAreaModification areaMod, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -582,7 +582,7 @@ void rcMarkCylinderArea(rcContext* ctx, const float* pos, if (dx*dx + dz*dz < r2) { - chf.areas[i] = areaId; + areaMod.apply(chf.areas[i]); } } } diff --git a/RecastDemo/Include/ConvexVolumeTool.h b/RecastDemo/Include/ConvexVolumeTool.h index 1f56cb07..1aa36316 100644 --- a/RecastDemo/Include/ConvexVolumeTool.h +++ b/RecastDemo/Include/ConvexVolumeTool.h @@ -26,7 +26,7 @@ class ConvexVolumeTool : public SampleTool { Sample* m_sample; - int m_areaType; + rcAreaModification m_areaMod; float m_polyOffset; float m_boxHeight; float m_boxDescent; diff --git a/RecastDemo/Include/InputGeom.h b/RecastDemo/Include/InputGeom.h index edc12957..bc1c95c9 100644 --- a/RecastDemo/Include/InputGeom.h +++ b/RecastDemo/Include/InputGeom.h @@ -21,14 +21,16 @@ #include "ChunkyTriMesh.h" #include "MeshLoaderObj.h" +#include "Recast.h" static const int MAX_CONVEXVOL_PTS = 12; struct ConvexVolume { + ConvexVolume(): areaMod(RC_AREA_FLAGS_MASK) {} float verts[MAX_CONVEXVOL_PTS*3]; float hmin, hmax; int nverts; - int area; + rcAreaModification areaMod; }; struct BuildSettings @@ -136,7 +138,7 @@ public: int getConvexVolumeCount() const { return m_volumeCount; } const ConvexVolume* getConvexVolumes() const { return m_volumes; } void addConvexVolume(const float* verts, const int nverts, - const float minh, const float maxh, unsigned char area); + const float minh, const float maxh, rcAreaModification areaMod); void deleteConvexVolume(int i); void drawConvexVolumes(struct duDebugDraw* dd, bool hilight = false); ///@} diff --git a/RecastDemo/Include/Sample.h b/RecastDemo/Include/Sample.h index f59975c8..bc1a257b 100644 --- a/RecastDemo/Include/Sample.h +++ b/RecastDemo/Include/Sample.h @@ -38,17 +38,24 @@ enum SampleToolType MAX_TOOLS }; -/// These are just sample areas to use consistent values across the samples. -/// The use should specify these base on his needs. -enum SamplePolyAreas -{ - SAMPLE_POLYAREA_GROUND, - SAMPLE_POLYAREA_WATER, - SAMPLE_POLYAREA_ROAD, - SAMPLE_POLYAREA_DOOR, - SAMPLE_POLYAREA_GRASS, - SAMPLE_POLYAREA_JUMP, -}; +/// Mask of the ceil part of the area id (3 lower bits) +/// the 0 value (RC_NULL_AREA) is left unused +static const unsigned char SAMPLE_POLYAREA_TYPE_MASK = 0x07; +/// Value for the kind of ceil "ground" +static const unsigned char SAMPLE_POLYAREA_TYPE_GROUND = 0x1; +/// Value for the kind of ceil "water" +static const unsigned char SAMPLE_POLYAREA_TYPE_WATER = 0x2; +/// Value for the kind of ceil "road" +static const unsigned char SAMPLE_POLYAREA_TYPE_ROAD = 0x3; +/// Value for the kind of ceil "grass" +static const unsigned char SAMPLE_POLYAREA_TYPE_GRASS = 0x4; +/// Flag for door area. Can be combined with area types and jump flag. +static const unsigned char SAMPLE_POLYAREA_FLAG_DOOR = 0x08; +/// Flag for jump area. Can be combined with area types and door flag. +static const unsigned char SAMPLE_POLYAREA_FLAG_JUMP = 0x10; + +extern rcAreaModification const SAMPLE_AREAMOD_GROUND; + enum SamplePolyFlags { SAMPLE_POLYFLAGS_WALK = 0x01, // Ability to walk (ground, grass, road) @@ -59,6 +66,8 @@ enum SamplePolyFlags SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities. }; +unsigned short sampleAreaToFlags(unsigned char area); + class SampleDebugDraw : public DebugDrawGL { public: diff --git a/RecastDemo/Source/ConvexVolumeTool.cpp b/RecastDemo/Source/ConvexVolumeTool.cpp index 33e7c45f..117171d0 100644 --- a/RecastDemo/Source/ConvexVolumeTool.cpp +++ b/RecastDemo/Source/ConvexVolumeTool.cpp @@ -97,10 +97,16 @@ static int pointInPoly(int nvert, const float* verts, const float* p) return c; } +rcAreaModification const SAMPLE_AREAMOD_GROUND(SAMPLE_POLYAREA_TYPE_GROUND, SAMPLE_POLYAREA_TYPE_MASK); +static rcAreaModification const SAMPLE_AREAMOD_WATER(SAMPLE_POLYAREA_TYPE_WATER, SAMPLE_POLYAREA_TYPE_MASK); +static rcAreaModification const SAMPLE_AREAMOD_ROAD(SAMPLE_POLYAREA_TYPE_ROAD, SAMPLE_POLYAREA_TYPE_MASK); +static rcAreaModification const SAMPLE_AREAMOD_GRASS(SAMPLE_POLYAREA_TYPE_GRASS, SAMPLE_POLYAREA_TYPE_MASK); +static rcAreaModification const SAMPLE_AREAMOD_DOOR(SAMPLE_POLYAREA_FLAG_DOOR, SAMPLE_POLYAREA_FLAG_DOOR); +static rcAreaModification const SAMPLE_AREAMOD_JUMP(SAMPLE_POLYAREA_FLAG_JUMP, SAMPLE_POLYAREA_FLAG_JUMP); ConvexVolumeTool::ConvexVolumeTool() : m_sample(0), - m_areaType(SAMPLE_POLYAREA_GRASS), + m_areaMod(SAMPLE_AREAMOD_GRASS), m_polyOffset(0.0f), m_boxHeight(6.0f), m_boxDescent(1.0f), @@ -130,18 +136,18 @@ void ConvexVolumeTool::handleMenu() 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; + if (imguiCheck("Ground", m_areaMod == SAMPLE_AREAMOD_GROUND)) + m_areaMod = SAMPLE_AREAMOD_GROUND; + if (imguiCheck("Water", m_areaMod == SAMPLE_AREAMOD_WATER)) + m_areaMod = SAMPLE_AREAMOD_WATER; + if (imguiCheck("Road", m_areaMod == SAMPLE_AREAMOD_ROAD)) + m_areaMod = SAMPLE_AREAMOD_ROAD; + if (imguiCheck("Grass", m_areaMod == SAMPLE_AREAMOD_GRASS)) + m_areaMod = SAMPLE_AREAMOD_GRASS; + if (imguiCheck("Door", m_areaMod == SAMPLE_AREAMOD_DOOR)) + m_areaMod = SAMPLE_AREAMOD_DOOR; + if (imguiCheck("Jump", m_areaMod == SAMPLE_AREAMOD_JUMP)) + m_areaMod = SAMPLE_AREAMOD_JUMP; imguiUnindent(); imguiSeparator(); @@ -203,11 +209,11 @@ void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shif 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); + geom->addConvexVolume(offset, noffset, minh, maxh, m_areaMod); } else { - geom->addConvexVolume(verts, m_nhull, minh, maxh, (unsigned char)m_areaType); + geom->addConvexVolume(verts, m_nhull, minh, maxh, m_areaMod); } } diff --git a/RecastDemo/Source/InputGeom.cpp b/RecastDemo/Source/InputGeom.cpp index 29af6c36..33672b67 100644 --- a/RecastDemo/Source/InputGeom.cpp +++ b/RecastDemo/Source/InputGeom.cpp @@ -253,7 +253,7 @@ bool InputGeom::loadGeomSet(rcContext* ctx, const std::string& filepath) if (m_volumeCount < MAX_VOLUMES) { ConvexVolume* vol = &m_volumes[m_volumeCount++]; - sscanf(row+1, "%d %d %f %f", &vol->nverts, &vol->area, &vol->hmin, &vol->hmax); + sscanf(row+1, "%d %c %c %f %f", &vol->nverts, &vol->areaMod.m_value, &vol->areaMod.m_mask, &vol->hmin, &vol->hmax); for (int i = 0; i < vol->nverts; ++i) { row[0] = '\0'; @@ -375,7 +375,7 @@ bool InputGeom::saveGeomSet(const BuildSettings* settings) for (int i = 0; i < m_volumeCount; ++i) { ConvexVolume* vol = &m_volumes[i]; - fprintf(fp, "v %d %d %f %f\n", vol->nverts, vol->area, vol->hmin, vol->hmax); + fprintf(fp, "v %d %c %c %f %f\n", vol->nverts, vol->areaMod.m_value, vol->areaMod.m_mask, 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]); } @@ -529,7 +529,7 @@ void InputGeom::drawOffMeshConnections(duDebugDraw* dd, bool hilight) } void InputGeom::addConvexVolume(const float* verts, const int nverts, - const float minh, const float maxh, unsigned char area) + const float minh, const float maxh, rcAreaModification areaMod) { if (m_volumeCount >= MAX_VOLUMES) return; ConvexVolume* vol = &m_volumes[m_volumeCount++]; @@ -538,7 +538,7 @@ void InputGeom::addConvexVolume(const float* verts, const int nverts, vol->hmin = minh; vol->hmax = maxh; vol->nverts = nverts; - vol->area = area; + vol->areaMod = areaMod; } void InputGeom::deleteConvexVolume(int i) @@ -556,7 +556,7 @@ void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, bool /*hilight*/) for (int i = 0; i < m_volumeCount; ++i) { const ConvexVolume* vol = &m_volumes[i]; - unsigned int col = duTransCol(dd->areaToCol(vol->area), 32); + unsigned int col = duTransCol(dd->areaToCol(vol->areaMod.getMaskedValue()), 32); for (int j = 0, k = vol->nverts-1; j < vol->nverts; k = j++) { const float* va = &vol->verts[k*3]; @@ -582,7 +582,7 @@ void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, bool /*hilight*/) for (int i = 0; i < m_volumeCount; ++i) { const ConvexVolume* vol = &m_volumes[i]; - unsigned int col = duTransCol(dd->areaToCol(vol->area), 220); + unsigned int col = duTransCol(dd->areaToCol(vol->areaMod.getMaskedValue()), 220); for (int j = 0, k = vol->nverts-1; j < vol->nverts; k = j++) { const float* va = &vol->verts[k*3]; @@ -601,7 +601,7 @@ void InputGeom::drawConvexVolumes(struct duDebugDraw* dd, bool /*hilight*/) for (int i = 0; i < m_volumeCount; ++i) { const ConvexVolume* vol = &m_volumes[i]; - unsigned int col = duDarkenCol(duTransCol(dd->areaToCol(vol->area), 220)); + unsigned int col = duDarkenCol(duTransCol(dd->areaToCol(vol->areaMod.getMaskedValue()), 220)); for (int j = 0; j < vol->nverts; ++j) { dd->vertex(vol->verts[j*3+0],vol->verts[j*3+1]+0.1f,vol->verts[j*3+2], col); diff --git a/RecastDemo/Source/NavMeshTesterTool.cpp b/RecastDemo/Source/NavMeshTesterTool.cpp index 99d6c521..031f9ae3 100644 --- a/RecastDemo/Source/NavMeshTesterTool.cpp +++ b/RecastDemo/Source/NavMeshTesterTool.cpp @@ -257,12 +257,12 @@ void NavMeshTesterTool::init(Sample* sample) if (m_navQuery) { // Change costs. - m_filter.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - m_filter.setAreaCost(SAMPLE_POLYAREA_WATER, 10.0f); - m_filter.setAreaCost(SAMPLE_POLYAREA_ROAD, 1.0f); - m_filter.setAreaCost(SAMPLE_POLYAREA_DOOR, 1.0f); - m_filter.setAreaCost(SAMPLE_POLYAREA_GRASS, 2.0f); - m_filter.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); + m_filter.setAreaCost(SAMPLE_POLYAREA_TYPE_GROUND, 1.0f); + m_filter.setAreaCost(SAMPLE_POLYAREA_TYPE_WATER, 10.0f); + m_filter.setAreaCost(SAMPLE_POLYAREA_TYPE_ROAD, 1.0f); + m_filter.setAreaCost(SAMPLE_POLYAREA_FLAG_DOOR, 1.0f); + m_filter.setAreaCost(SAMPLE_POLYAREA_TYPE_GRASS, 2.0f); + m_filter.setAreaCost(SAMPLE_POLYAREA_FLAG_JUMP, 1.5f); } m_neighbourhoodRadius = sample->getAgentRadius() * 20.0f; diff --git a/RecastDemo/Source/OffMeshConnectionTool.cpp b/RecastDemo/Source/OffMeshConnectionTool.cpp index 5abdfc7f..5efda624 100644 --- a/RecastDemo/Source/OffMeshConnectionTool.cpp +++ b/RecastDemo/Source/OffMeshConnectionTool.cpp @@ -119,7 +119,7 @@ void OffMeshConnectionTool::handleClick(const float* /*s*/, const float* p, bool } else { - const unsigned char area = SAMPLE_POLYAREA_JUMP; + const unsigned char area = SAMPLE_POLYAREA_FLAG_JUMP; const unsigned short flags = SAMPLE_POLYFLAGS_JUMP; geom->addOffMeshConnection(m_hitPos, p, m_sample->getAgentRadius(), m_bidir ? 1 : 0, area, flags); m_hitPosSet = false; diff --git a/RecastDemo/Source/Sample.cpp b/RecastDemo/Source/Sample.cpp index 26f2f76c..45b4275a 100644 --- a/RecastDemo/Source/Sample.cpp +++ b/RecastDemo/Source/Sample.cpp @@ -35,25 +35,53 @@ # define snprintf _snprintf #endif +unsigned short sampleAreaToFlags(unsigned char area) +{ + unsigned char areaType = (area & SAMPLE_POLYAREA_TYPE_MASK); + unsigned short flags = (unsigned short)((areaType == SAMPLE_POLYAREA_TYPE_WATER) ? SAMPLE_POLYFLAGS_SWIM : SAMPLE_POLYFLAGS_WALK); + if((areaType & SAMPLE_POLYAREA_FLAG_DOOR) != 0) + { + flags |= SAMPLE_POLYFLAGS_DOOR; + } + if((areaType & SAMPLE_POLYAREA_FLAG_JUMP) != 0) + { + flags |= SAMPLE_POLYFLAGS_JUMP; + } + return flags; +} + + unsigned int SampleDebugDraw::areaToCol(unsigned int area) { - switch(area) + unsigned int col; + + unsigned char ceil = (area & SAMPLE_POLYAREA_TYPE_MASK); + switch(ceil) { - // Ground (0) : light blue - case SAMPLE_POLYAREA_GROUND: return duRGBA(0, 192, 255, 255); + // Ground : light blue + case SAMPLE_POLYAREA_TYPE_GROUND: col = duRGBA(0, 192, 255, 255); break; // Water : blue - case SAMPLE_POLYAREA_WATER: return duRGBA(0, 0, 255, 255); + case SAMPLE_POLYAREA_TYPE_WATER: col = duRGBA(0, 0, 255, 255); break; // Road : brown - case SAMPLE_POLYAREA_ROAD: return duRGBA(50, 20, 12, 255); - // Door : cyan - case SAMPLE_POLYAREA_DOOR: return duRGBA(0, 255, 255, 255); + case SAMPLE_POLYAREA_TYPE_ROAD: col = duRGBA(50, 20, 12, 255); break; // Grass : green - case SAMPLE_POLYAREA_GRASS: return duRGBA(0, 255, 0, 255); - // Jump : yellow - case SAMPLE_POLYAREA_JUMP: return duRGBA(255, 255, 0, 255); - // Unexpected : red - default: return duRGBA(255, 0, 0, 255); + case SAMPLE_POLYAREA_TYPE_GRASS: col = duRGBA(0, 255, 0, 255); break; + // Unexpected ceil : red + default: col = duRGBA(255, 0, 0, 255); break; } + + if(area & SAMPLE_POLYAREA_FLAG_DOOR) + { + // Door : cyan + col = duLerpCol(col, duRGBA(0, 255, 255, 255), 127); + } + if(area & SAMPLE_POLYAREA_FLAG_JUMP) + { + // Jump : yellow + col = duLerpCol(col, duRGBA(255, 255, 0, 255), 127); + } + + return col; } Sample::Sample() : diff --git a/RecastDemo/Source/Sample_SoloMesh.cpp b/RecastDemo/Source/Sample_SoloMesh.cpp index 68cf7c88..90b65807 100644 --- a/RecastDemo/Source/Sample_SoloMesh.cpp +++ b/RecastDemo/Source/Sample_SoloMesh.cpp @@ -435,7 +435,7 @@ bool Sample_SoloMesh::handleBuild() // If your input data is multiple meshes, you can transform them here, calculate // the are type for each of the meshes and rasterize them. memset(m_triareas, 0, ntris*sizeof(unsigned char)); - rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas); + rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas, SAMPLE_AREAMOD_GROUND); if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb)) { m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not rasterize triangles."); @@ -498,7 +498,7 @@ bool Sample_SoloMesh::handleBuild() // (Optional) Mark areas. const ConvexVolume* 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 char)vols[i].area, *m_chf); + rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, vols[i].areaMod, *m_chf); // Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas. @@ -639,23 +639,7 @@ bool Sample_SoloMesh::handleBuild() // Update poly flags from areas. for (int i = 0; i < m_pmesh->npolys; ++i) { - if (m_pmesh->areas[i] == RC_WALKABLE_AREA) - m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; - - if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND || - m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || - m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; - } - else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM; - } - else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; - } + m_pmesh->flags[i] = sampleAreaToFlags(m_pmesh->areas[i]); } diff --git a/RecastDemo/Source/Sample_TempObstacles.cpp b/RecastDemo/Source/Sample_TempObstacles.cpp index 76a14312..d306c731 100644 --- a/RecastDemo/Source/Sample_TempObstacles.cpp +++ b/RecastDemo/Source/Sample_TempObstacles.cpp @@ -195,23 +195,7 @@ struct MeshProcess : public dtTileCacheMeshProcess // Update poly flags from areas. for (int i = 0; i < params->polyCount; ++i) { - if (polyAreas[i] == DT_TILECACHE_WALKABLE_AREA) - polyAreas[i] = SAMPLE_POLYAREA_GROUND; - - if (polyAreas[i] == SAMPLE_POLYAREA_GROUND || - polyAreas[i] == SAMPLE_POLYAREA_GRASS || - polyAreas[i] == SAMPLE_POLYAREA_ROAD) - { - polyFlags[i] = SAMPLE_POLYFLAGS_WALK; - } - else if (polyAreas[i] == SAMPLE_POLYAREA_WATER) - { - polyFlags[i] = SAMPLE_POLYFLAGS_SWIM; - } - else if (polyAreas[i] == SAMPLE_POLYAREA_DOOR) - { - polyFlags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; - } + polyFlags[i] = sampleAreaToFlags(polyAreas[i]); } // Pass in off-mesh connections. @@ -351,7 +335,8 @@ int Sample_TempObstacles::rasterizeTileLayers( memset(rc.triareas, 0, ntris*sizeof(unsigned char)); rcMarkWalkableTriangles(m_ctx, tcfg.walkableSlopeAngle, - verts, nverts, tris, ntris, rc.triareas); + verts, nverts, tris, ntris, rc.triareas, + SAMPLE_AREAMOD_GROUND); if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb)) return 0; @@ -393,7 +378,7 @@ int Sample_TempObstacles::rasterizeTileLayers( { rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, - (unsigned char)vols[i].area, *rc.chf); + vols[i].areaMod, *rc.chf); } rc.lset = rcAllocHeightfieldLayerSet(); diff --git a/RecastDemo/Source/Sample_TileMesh.cpp b/RecastDemo/Source/Sample_TileMesh.cpp index 7641987b..c45fc70b 100644 --- a/RecastDemo/Source/Sample_TileMesh.cpp +++ b/RecastDemo/Source/Sample_TileMesh.cpp @@ -1039,7 +1039,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const memset(m_triareas, 0, nctris*sizeof(unsigned char)); rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, - verts, nverts, ctris, nctris, m_triareas); + verts, nverts, ctris, nctris, m_triareas, SAMPLE_AREAMOD_GROUND); if (!rcRasterizeTriangles(m_ctx, verts, nverts, ctris, m_triareas, nctris, *m_solid, m_cfg.walkableClimb)) return 0; @@ -1092,7 +1092,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const // (Optional) Mark areas. const ConvexVolume* 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 char)vols[i].area, *m_chf); + rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, vols[i].areaMod, *m_chf); // Partition the heightfield so that we can use simple algorithm later to triangulate the walkable areas. @@ -1226,23 +1226,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const // Update poly flags from areas. for (int i = 0; i < m_pmesh->npolys; ++i) { - if (m_pmesh->areas[i] == RC_WALKABLE_AREA) - m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND; - - if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND || - m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS || - m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK; - } - else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM; - } - else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR) - { - m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR; - } + m_pmesh->flags[i] = sampleAreaToFlags(m_pmesh->areas[i]); } dtNavMeshCreateParams params; diff --git a/Tests/Recast/Tests_Recast.cpp b/Tests/Recast/Tests_Recast.cpp index b9176220..f64ae8d2 100644 --- a/Tests/Recast/Tests_Recast.cpp +++ b/Tests/Recast/Tests_Recast.cpp @@ -448,27 +448,27 @@ TEST_CASE("rcMarkWalkableTriangles") SECTION("One walkable triangle") { - rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); + rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas, rcAreaModification(RC_WALKABLE_AREA)); REQUIRE(areas[0] == RC_WALKABLE_AREA); } SECTION("One non-walkable triangle") { - rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas); + rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas, rcAreaModification(RC_WALKABLE_AREA)); REQUIRE(areas[0] == RC_NULL_AREA); } SECTION("Non-walkable triangle area id's are not modified") { areas[0] = 42; - rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas); + rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas, rcAreaModification(RC_WALKABLE_AREA)); REQUIRE(areas[0] == 42); } SECTION("Slopes equal to the max slope are considered unwalkable.") { walkableSlopeAngle = 0; - rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); + rcMarkWalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas, rcAreaModification(RC_WALKABLE_AREA)); REQUIRE(areas[0] == RC_NULL_AREA); } }