void NavMeshPruneTool::handleClick(const float* s, const float* p, bool shift) { rcIgnoreUnused(s); rcIgnoreUnused(shift); if (!m_sample) return; InputGeom* geom = m_sample->getInputGeom(); if (!geom) return; dtNavMesh* nav = m_sample->getNavMesh(); if (!nav) return; dtNavMeshQuery* query = m_sample->getNavMeshQuery(); if (!query) return; dtVcopy(m_hitPos, p); m_hitPosSet = true; if (!m_flags) { m_flags = new NavmeshFlags; m_flags->init(nav); } const float ext[3] = {2,4,2}; dtQueryFilter filter; dtPolyRef ref = 0; query->findNearestPoly(p, ext, &filter, &ref, 0); floodNavmesh(nav, m_flags, ref, 1); }
void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view) { rcIgnoreUnused(model); rcIgnoreUnused(proj); // Tool help const int h = view[3]; int ty = h-40; if (m_mode == TOOLMODE_CREATE) { imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "LMB: add agent. Shift+LMB: remove agent.", imguiRGBA(255,255,255,192)); } else if (m_mode == TOOLMODE_MOVE_TARGET) { imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "LMB: set move target. Shift+LMB: adjust set velocity.", imguiRGBA(255,255,255,192)); ty -= 20; imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "Setting velocity will move the agents without pathfinder.", imguiRGBA(255,255,255,192)); } else if (m_mode == TOOLMODE_SELECT) { imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "LMB: select agent.", imguiRGBA(255,255,255,192)); } ty -= 20; imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "SPACE: Run/Pause simulation. 1: Step simulation.", imguiRGBA(255,255,255,192)); ty -= 20; if (m_state && m_state->isRunning()) imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- RUNNING -", imguiRGBA(255,32,16,255)); else imguiDrawText(280, ty, IMGUI_ALIGN_LEFT, "- PAUSED -", imguiRGBA(255,255,255,128)); }
void NavMeshPruneTool::handleRenderOverlay(double* proj, double* model, int* view) { rcIgnoreUnused(model); rcIgnoreUnused(proj); // Tool help const int h = view[3]; imguiDrawText(280, h-40, IMGUI_ALIGN_LEFT, "LMB: Click fill area.", imguiRGBA(255,255,255,192)); }
void NavMeshPruneTool::handleRenderOverlay(double* proj, double* model, int* view) { rcIgnoreUnused(model); rcIgnoreUnused(proj); // Tool help const int h = view[3]; ImGui::RenderTextRight(-330, -(h - 40), ImVec4(255, 255, 255, 192), "LMB: Click fill area."); }
/// @par /// /// Only sets the area id's for the walkable triangles. Does not alter the /// area id's for unwalkable triangles. /// /// See the #rcConfig documentation for more information on the configuration parameters. /// /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, const int* tris, int nt, unsigned char* areas) { rcIgnoreUnused(ctx); rcIgnoreUnused(nv); const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); float norm[3]; for (int i = 0; i < nt; ++i) { const int* tri = &tris[i*3]; 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; } }
/// @par /// /// See the #rcConfig documentation for more information on the configuration parameters. /// /// @see rcAllocHeightfield, rcHeightfield bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, const dtCoordinates& bmin, const dtCoordinates& bmax, float cs, float ch) { rcIgnoreUnused(ctx); hf.width = width; hf.height = height; rcVcopy(hf.bmin, bmin); rcVcopy(hf.bmax, bmax); hf.cs = cs; hf.ch = ch; hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM); if (!hf.spans) return false; memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height); return true; }
int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf) { rcIgnoreUnused(ctx); const int w = hf.width; const int h = hf.height; int spanCount = 0; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next) { if( rcCanMovableArea( s->area ) ) spanCount++; } } } return spanCount; }
/// @par /// /// Only sets the aread id's for the unwalkable triangles. Does not alter the /// area id's for walkable triangles. /// /// See the #rcConfig documentation for more information on the configuration parameters. /// /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const dtCoordinates* verts, int /*nv*/, const int* tris, int nt, unsigned char* areas) { rcIgnoreUnused(ctx); const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); dtCoordinates norm; for (int i = 0; i < nt; ++i) { const int* tri = &tris[i*3]; calcTriNormal(verts[tri[0]], verts[tri[1]], verts[tri[2]], norm); // Check if the face is walkable. if (norm.Y() <= walkableThr) areas[i] = RC_NULL_AREA; } }
/// @par /// /// Only sets the aread id's for the walkable triangles. Does not alter the /// area id's for unwalkable triangles. /// /// See the #rcConfig documentation for more information on the configuration parameters. /// /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const dtCoordinates* verts, int /*nv*/, const int* tris, int nt, unsigned char* areas) { rcIgnoreUnused(ctx); const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); dtCoordinates norm; for (int i = 0; i < nt; ++i) { const int* tri = &tris[i*3]; calcTriNormal(verts[tri[0]], verts[tri[1]], verts[tri[2]], norm); //#ifdef MODIFY_VOXEL_FLAG const bool terrain = tri[0] < RC_MAX_GROUND_FLOOR_VERTICES && tri[1] < RC_MAX_GROUND_FLOOR_VERTICES && tri[2] < RC_MAX_GROUND_FLOOR_VERTICES; //#endif // MODIFY_VOXEL_FLAG // Check if the face is walkable. #ifdef MODIFY_VOXEL_FLAG if( walkableThr < norm.Y() ) { areas[i] = terrain ? RC_TERRAIN_AREA | RC_WALKABLE_AREA : RC_OBJECT_AREA | RC_WALKABLE_AREA; } else { areas[i] = terrain ? RC_TERRAIN_AREA | RC_WALKABLE_AREA : RC_OBJECT_AREA | RC_UNWALKABLE_AREA;; } #else // MODIFY_VOXEL_FLAG if (norm[1] > walkableThr) { //areas[i] = RC_WALKABLE_AREA; areas[i] = terrain ? RC_WALKABLE_AREA : 1; } else { areas[i] = terrain ? RC_NULL_AREA : 2; } #endif // MODIFY_VOXEL_FLAG } }
static void getHeightData(const rcCompactHeightfield& chf, const unsigned short* poly, const int npoly, const unsigned short* verts, const int bs, rcHeightPatch& hp, rcIntArray& stack, int region) { rcIgnoreUnused( verts ); rcIgnoreUnused( npoly ); rcIgnoreUnused( poly ); // Note: Reads to the compact heightfield are offset by border size (bs) // since border size offset is already removed from the polymesh vertices. stack.resize(0); memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height); bool empty = true; // Copy the height from the same region, and mark region borders // as seed points to fill the rest. for (int hy = 0; hy < hp.height; hy++) { int y = hp.ymin + hy + bs; for (int hx = 0; hx < hp.width; hx++) { int x = hp.xmin + hx + bs; const rcCompactCell& c = chf.cells[x+y*chf.width]; ////////////////////////////////////////////////////////////////////////// bool b = false; ////////////////////////////////////////////////////////////////////////// for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; if (s.reg == region) { ////////////////////////////////////////////////////////////////////////// b = true; ////////////////////////////////////////////////////////////////////////// // Store height hp.data[hx + hy*hp.width] = s.y; empty = false; // If any of the neighbours is not in same region, // add the current location as flood fill start bool border = false; for (int dir = 0; dir < 4; ++dir) { if( rcIsConnectedWalkableArea( s, dir ) ) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); const rcCompactSpan& as = chf.spans[ai]; if (as.reg != region) { border = true; break; } } } if (border) { stack.push(x); stack.push(y); stack.push(i); } break; } } ////////////////////////////////////////////////////////////////////////// // if( !b ) { // const rcCompactSpan& s = chf.spans[c.index]; // hp.data[hx + hy*hp.width] = s.y; // } ////////////////////////////////////////////////////////////////////////// } } // if the polygon does not contian any points from the current region (rare, but happens) // then use the cells closest to the polygon vertices as seeds to fill the height field if (empty) getHeightDataSeedsFromVertices(chf, poly, npoly, verts, bs, hp, stack); static const int RETRACT_SIZE = 256; int head = 0; while (head*3 < stack.size()) { int cx = stack[head*3+0]; int cy = stack[head*3+1]; int ci = stack[head*3+2]; head++; if (head >= RETRACT_SIZE) { head = 0; if (stack.size() > RETRACT_SIZE*3) memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3)); stack.resize(stack.size()-RETRACT_SIZE*3); } const rcCompactSpan& cs = chf.spans[ci]; for (int dir = 0; dir < 4; ++dir) { if( !rcIsConnectedWalkableArea( cs, dir ) ) { continue; } const int ax = cx + rcGetDirOffsetX(dir); const int ay = cy + rcGetDirOffsetY(dir); const int hx = ax - hp.xmin - bs; const int hy = ay - hp.ymin - bs; if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height) continue; if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT) continue; const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir); const rcCompactSpan& as = chf.spans[ai]; hp.data[hx + hy*hp.width] = as.y; stack.push(ax); stack.push(ay); stack.push(ai); } } }
void CrowdTool::handleUpdate(const float dt) { rcIgnoreUnused(dt); }