void OffMeshConnectionTool::handleRender() { DebugDrawGL dd; const float s = m_sample->getAgentRadius(); if (m_hitPosSet) duDebugDrawCross(&dd, m_hitPos[0],m_hitPos[1]+0.1f,m_hitPos[2], s, duRGBA(0,0,0,128), 2.0f); InputGeom* geom = m_sample->getInputGeom(); if (geom) geom->drawOffMeshConnections(&dd, true); }
void CrowdTool::handleRender() { DebugDrawGL dd; const float s = m_sample->getAgentRadius(); dtNavMesh* nmesh = m_sample->getNavMesh(); if (!nmesh) return; dtNavMeshQuery* navquery = m_sample->getNavMeshQuery(); if (m_showNodes) { if (navquery) duDebugDrawNavMeshNodes(&dd, *navquery); } dd.depthMask(false); // Draw paths if (m_showPath) { for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const dtPolyRef* path = ag->corridor.getPath(); const int npath = ag->corridor.getPathCount(); for (int i = 0; i < npath; ++i) duDebugDrawNavMeshPoly(&dd, *nmesh, path[i], duRGBA(0,0,0,32)); } } if (m_targetRef) duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], s, duRGBA(255,255,255,192), 2.0f); // Occupancy grid. if (m_showGrid) { float gridy = -FLT_MAX; for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float* pos = ag->corridor.getPos(); gridy = dtMax(gridy, pos[1]); } gridy += 1.0f; dd.begin(DU_DRAW_QUADS); const ProximityGrid* grid = m_crowd.getGrid(); const int* bounds = grid->getBounds(); const float cs = grid->getCellSize(); for (int y = bounds[1]; y <= bounds[3]; ++y) { for (int x = bounds[0]; x <= bounds[2]; ++x) { const int count = grid->getItemCountAt(x,y); if (!count) continue; unsigned int col = duRGBA(128,0,0,dtMin(count*40,255)); dd.vertex(x*cs, gridy, y*cs, col); dd.vertex(x*cs, gridy, y*cs+cs, col); dd.vertex(x*cs+cs, gridy, y*cs+cs, col); dd.vertex(x*cs+cs, gridy, y*cs, col); } } dd.end(); } // Trail for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float* pos = ag->npos; dd.begin(DU_DRAW_LINES,3.0f); float prev[3], preva = 1; dtVcopy(prev, pos); for (int j = 0; j < AGENT_MAX_TRAIL-1; ++j) { const int idx = (ag->htrail + AGENT_MAX_TRAIL-j) % AGENT_MAX_TRAIL; const float* v = &ag->trail[idx*3]; float a = 1 - j/(float)AGENT_MAX_TRAIL; dd.vertex(prev[0],prev[1]+0.1f,prev[2], duRGBA(0,0,0,(int)(128*preva))); dd.vertex(v[0],v[1]+0.1f,v[2], duRGBA(0,0,0,(int)(128*a))); preva = a; dtVcopy(prev, v); } dd.end(); } // Corners & co for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float radius = ag->radius; const float* pos = ag->npos; if (m_showCorners) { if (ag->ncorners) { dd.begin(DU_DRAW_LINES, 2.0f); for (int j = 0; j < ag->ncorners; ++j) { const float* va = j == 0 ? pos : &ag->cornerVerts[(j-1)*3]; const float* vb = &ag->cornerVerts[j*3]; dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,192)); dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,192)); } dd.end(); if (m_anticipateTurns) { /* float dvel[3], pos[3]; calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel); pos[0] = ag->pos[0] + dvel[0]; pos[1] = ag->pos[1] + dvel[1]; pos[2] = ag->pos[2] + dvel[2]; const float off = ag->radius+0.1f; const float* tgt = &ag->cornerVerts[0]; const float y = ag->pos[1]+off; dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(ag->pos[0],y,ag->pos[2], duRGBA(255,0,0,192)); dd.vertex(pos[0],y,pos[2], duRGBA(255,0,0,192)); dd.vertex(pos[0],y,pos[2], duRGBA(255,0,0,192)); dd.vertex(tgt[0],y,tgt[2], duRGBA(255,0,0,192)); dd.end();*/ } } } if (m_showCollisionSegments) { const float* center = ag->boundary.getCenter(); duDebugDrawCross(&dd, center[0],center[1]+radius,center[2], 0.2f, duRGBA(192,0,128,255), 2.0f); duDebugDrawCircle(&dd, center[0],center[1]+radius,center[2], ag->collisionQueryRange, duRGBA(192,0,128,128), 2.0f); dd.begin(DU_DRAW_LINES, 3.0f); for (int j = 0; j < ag->boundary.getSegmentCount(); ++j) { const float* s = ag->boundary.getSegment(j); unsigned int col = duRGBA(192,0,128,192); if (dtTriArea2D(pos, s, s+3) < 0.0f) col = duDarkenCol(col); duAppendArrow(&dd, s[0],s[1]+0.2f,s[2], s[3],s[4]+0.2f,s[5], 0.0f, 0.3f, col); } dd.end(); } if (m_showOpt) { dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(ag->opts[0],ag->opts[1]+0.3f,ag->opts[2], duRGBA(0,128,0,192)); dd.vertex(ag->opte[0],ag->opte[1]+0.3f,ag->opte[2], duRGBA(0,128,0,192)); dd.end(); } } // Agent cylinders. for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float radius = ag->radius; const float* pos = ag->npos; duDebugDrawCircle(&dd, pos[0], pos[1], pos[2], radius, duRGBA(0,0,0,32), 2.0f); } for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float height = ag->height; const float radius = ag->radius; const float* pos = ag->npos; duDebugDrawCylinder(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius, pos[0]+radius, pos[1]+height, pos[2]+radius, duRGBA(220,220,220,128)); } // Velocity stuff. for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float radius = ag->radius; const float height = ag->height; const float* pos = ag->npos; const float* vel = ag->vel; const float* dvel = ag->dvel; duDebugDrawCircle(&dd, pos[0], pos[1]+height, pos[2], radius, duRGBA(220,220,220,192), 2.0f); if (m_showVO) { // Draw detail about agent sela const dtObstacleAvoidanceDebugData* debug = m_crowd.getVODebugData(i); const float dx = pos[0]; const float dy = pos[1]+height; const float dz = pos[2]; dd.begin(DU_DRAW_QUADS); for (int i = 0; i < debug->getSampleCount(); ++i) { const float* p = debug->getSampleVelocity(i); const float sr = debug->getSampleSize(i); const float pen = debug->getSamplePenalty(i); const float pen2 = debug->getSamplePreferredSidePenalty(i); unsigned int col = duLerpCol(duRGBA(255,255,255,220), duRGBA(128,96,0,220), (int)(pen*255)); col = duLerpCol(col, duRGBA(128,0,0,220), (int)(pen2*128)); dd.vertex(dx+p[0]-sr, dy, dz+p[2]-sr, col); dd.vertex(dx+p[0]-sr, dy, dz+p[2]+sr, col); dd.vertex(dx+p[0]+sr, dy, dz+p[2]+sr, col); dd.vertex(dx+p[0]+sr, dy, dz+p[2]-sr, col); } dd.end(); } duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], pos[0]+dvel[0],pos[1]+height+dvel[1],pos[2]+dvel[2], 0.0f, 0.4f, duRGBA(0,192,255,192), 1.0f); duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2], 0.0f, 0.4f, duRGBA(0,0,0,192), 2.0f); } // Targets for (int i = 0; i < m_crowd.getAgentCount(); ++i) { const Agent* ag = m_crowd.getAgent(i); if (!ag->active) continue; const float* pos = ag->npos; const float* target = ag->corridor.getTarget(); if (m_showTargets) { duDebugDrawArc(&dd, pos[0], pos[1], pos[2], target[0], target[1], target[2], 0.25f, 0, 0.4f, duRGBA(0,0,0,128), 1.0f); } } dd.depthMask(true); }
void NavigationPath::UpdatePath(bool force) { if (m_navMesh == nullptr) return; if (m_query == nullptr) { m_query.reset(new dtNavMeshQuery); m_query->init(m_navMesh, 10000 /* MAX_NODES */); } PSPAWNINFO me = GetCharInfo()->pSpawn; if (me == nullptr) return; float startOffset[3] = { me->X, me->Feet, me->Y }; float endOffset[3] = { m_destination.x, m_destination.z, m_destination.y }; float spos[3]; float epos[3]; glm::vec3 thisPos(startOffset[0], startOffset[1], startOffset[2]); if (thisPos == m_lastPos && !force) return; m_lastPos = thisPos; m_currentPathCursor = 0; m_currentPathSize = 0; dtPolyRef startRef, endRef; m_query->findNearestPoly(startOffset, m_extents, &m_filter, &startRef, spos); if (!startRef) { WriteChatf(PLUGIN_MSG "No start reference"); return; } dtPolyRef polys[MAX_POLYS]; int numPolys = 0; if (!m_corridor) { if (m_useCorridor) { // initialize planning m_corridor.reset(new dtPathCorridor); m_corridor->init(MAX_PATH_SIZE); m_corridor->reset(startRef, startOffset); } m_query->findNearestPoly(endOffset, m_extents, &m_filter, &endRef, epos); if (!endRef) { WriteChatf(PLUGIN_MSG "No end reference"); return; } dtStatus status = m_query->findPath(startRef, endRef, spos, epos, &m_filter, polys, &numPolys, MAX_POLYS); if (status & DT_OUT_OF_NODES) DebugSpewAlways("findPath from %.2f,%.2f,%.2f to %.2f,%.2f,%.2f failed: out of nodes", startOffset[0], startOffset[1], startOffset[2], endOffset[0], endOffset[1], endOffset[2]); if (status & DT_PARTIAL_RESULT) DebugSpewAlways("findPath from %.2f,%.2f,%.2f to %.2f,%.2f,%.2f returned a partial result.", startOffset[0], startOffset[1], startOffset[2], endOffset[0], endOffset[1], endOffset[2]); if (m_corridor) { m_corridor->setCorridor(endOffset, polys, numPolys); } } else { // this is an update m_corridor->movePosition(startOffset, m_query.get(), &m_filter); } if (m_corridor) { m_corridor->optimizePathTopology(m_query.get(), &m_filter); m_currentPathSize = m_corridor->findCorners(m_currentPath, m_cornerFlags, polys, 10, m_query.get(), &m_filter); } if (m_debugDrawGrp) m_debugDrawGrp->Reset(); if (numPolys > 0) { m_query->findStraightPath(spos, epos, polys, numPolys, m_currentPath, 0, 0, &m_currentPathSize, MAX_POLYS, 0); // The 0th index is the starting point. Begin by trying to reach the // 2nd point... if (m_currentPathSize > 1) m_currentPathCursor = 1; if (m_debugDrawGrp && mq2nav::GetSettings().debug_render_pathing) { DebugDrawDX dd(m_debugDrawGrp.get()); // draw current position duDebugDrawCross(&dd, me->X, me->Feet, me->Y, 0.5, DXColor(51, 255, 255), 1); // Draw the waypoints. Green is next point for (int i = 0; i < m_currentPathSize; ++i) { int color = DXColor(255, 255, 255); if (i < m_currentPathCursor) color = DXColor(0, 102, 204); if (i == m_currentPathCursor) color = DXColor(0, 255, 0); if (i == m_currentPathSize - 1) color = DXColor(255, 0, 0); duDebugDrawCross(&dd, m_currentPath[i * 3], m_currentPath[i * 3 + 1], m_currentPath[i * 3 + 2], 0.5, color, 1); } } } if (m_line && mq2nav::GetSettings().show_nav_path) { m_line->Update(); } }
void CrowdToolState::handleRender() { DebugDrawGL dd; const float rad = m_sample->getAgentRadius(); dtNavMesh* nav = m_sample->getNavMesh(); dtCrowd* crowd = m_sample->getCrowd(); if (!nav || !crowd) return; if (m_toolParams.m_showNodes && crowd->getPathQueue()) { const dtNavMeshQuery* navquery = crowd->getPathQueue()->getNavQuery(); if (navquery) duDebugDrawNavMeshNodes(&dd, *navquery); } dd.depthMask(false); // Draw paths if (m_toolParams.m_showPath) { for (int i = 0; i < crowd->getAgentCount(); i++) { if (m_toolParams.m_showDetailAll == false && i != m_agentDebug.idx) continue; const dtCrowdAgent* ag =crowd->getAgent(i); if (!ag->active) continue; const dtPolyRef* path = ag->corridor.getPath(); const int npath = ag->corridor.getPathCount(); for (int j = 0; j < npath; ++j) duDebugDrawNavMeshPoly(&dd, *nav, path[j], duRGBA(255,255,255,24)); } } if (m_targetRef) duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], rad, duRGBA(255,255,255,192), 2.0f); // Occupancy grid. if (m_toolParams.m_showGrid) { float gridy = -FLT_MAX; for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); if (!ag->active) continue; const float* pos = ag->corridor.getPos(); gridy = dtMax(gridy, pos[1]); } gridy += 1.0f; dd.begin(DU_DRAW_QUADS); const dtProximityGrid* grid = crowd->getGrid(); const int* bounds = grid->getBounds(); const float cs = grid->getCellSize(); for (int y = bounds[1]; y <= bounds[3]; ++y) { for (int x = bounds[0]; x <= bounds[2]; ++x) { const int count = grid->getItemCountAt(x,y); if (!count) continue; unsigned int col = duRGBA(128,0,0,dtMin(count*40,255)); dd.vertex(x*cs, gridy, y*cs, col); dd.vertex(x*cs, gridy, y*cs+cs, col); dd.vertex(x*cs+cs, gridy, y*cs+cs, col); dd.vertex(x*cs+cs, gridy, y*cs, col); } } dd.end(); } // Trail for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); if (!ag->active) continue; const AgentTrail* trail = &m_trails[i]; const float* pos = ag->npos; dd.begin(DU_DRAW_LINES,3.0f); float prev[3], preva = 1; dtVcopy(prev, pos); for (int j = 0; j < AGENT_MAX_TRAIL-1; ++j) { const int idx = (trail->htrail + AGENT_MAX_TRAIL-j) % AGENT_MAX_TRAIL; const float* v = &trail->trail[idx*3]; float a = 1 - j/(float)AGENT_MAX_TRAIL; dd.vertex(prev[0],prev[1]+0.1f,prev[2], duRGBA(0,0,0,(int)(128*preva))); dd.vertex(v[0],v[1]+0.1f,v[2], duRGBA(0,0,0,(int)(128*a))); preva = a; dtVcopy(prev, v); } dd.end(); } // Corners & co for (int i = 0; i < crowd->getAgentCount(); i++) { if (m_toolParams.m_showDetailAll == false && i != m_agentDebug.idx) continue; const dtCrowdAgent* ag =crowd->getAgent(i); if (!ag->active) continue; const float radius = ag->params.radius; const float* pos = ag->npos; if (m_toolParams.m_showCorners) { if (ag->ncorners) { dd.begin(DU_DRAW_LINES, 2.0f); for (int j = 0; j < ag->ncorners; ++j) { const float* va = j == 0 ? pos : &ag->cornerVerts[(j-1)*3]; const float* vb = &ag->cornerVerts[j*3]; dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,192)); dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,192)); } if (ag->ncorners && ag->cornerFlags[ag->ncorners-1] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) { const float* v = &ag->cornerVerts[(ag->ncorners-1)*3]; dd.vertex(v[0],v[1],v[2], duRGBA(192,0,0,192)); dd.vertex(v[0],v[1]+radius*2,v[2], duRGBA(192,0,0,192)); } dd.end(); if (m_toolParams.m_anticipateTurns) { /* float dvel[3], pos[3]; calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel); pos[0] = ag->pos[0] + dvel[0]; pos[1] = ag->pos[1] + dvel[1]; pos[2] = ag->pos[2] + dvel[2]; const float off = ag->radius+0.1f; const float* tgt = &ag->cornerVerts[0]; const float y = ag->pos[1]+off; dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(ag->pos[0],y,ag->pos[2], duRGBA(255,0,0,192)); dd.vertex(pos[0],y,pos[2], duRGBA(255,0,0,192)); dd.vertex(pos[0],y,pos[2], duRGBA(255,0,0,192)); dd.vertex(tgt[0],y,tgt[2], duRGBA(255,0,0,192)); dd.end();*/ } } } if (m_toolParams.m_showCollisionSegments) { const float* center = ag->boundary.getCenter(); duDebugDrawCross(&dd, center[0],center[1]+radius,center[2], 0.2f, duRGBA(192,0,128,255), 2.0f); duDebugDrawCircle(&dd, center[0],center[1]+radius,center[2], ag->params.collisionQueryRange, duRGBA(192,0,128,128), 2.0f); dd.begin(DU_DRAW_LINES, 3.0f); for (int j = 0; j < ag->boundary.getSegmentCount(); ++j) { const float* s = ag->boundary.getSegment(j); unsigned int col = duRGBA(192,0,128,192); if (dtTriArea2D(pos, s, s+3) < 0.0f) col = duDarkenCol(col); duAppendArrow(&dd, s[0],s[1]+0.2f,s[2], s[3],s[4]+0.2f,s[5], 0.0f, 0.3f, col); } dd.end(); } if (m_toolParams.m_showNeis) { duDebugDrawCircle(&dd, pos[0],pos[1]+radius,pos[2], ag->params.collisionQueryRange, duRGBA(0,192,128,128), 2.0f); dd.begin(DU_DRAW_LINES, 2.0f); for (int j = 0; j < ag->nneis; ++j) { // Get 'n'th active agent. // TODO: fix this properly. const dtCrowdAgent* nei = crowd->getAgent(ag->neis[j].idx); if (nei) { dd.vertex(pos[0],pos[1]+radius,pos[2], duRGBA(0,192,128,128)); dd.vertex(nei->npos[0],nei->npos[1]+radius,nei->npos[2], duRGBA(0,192,128,128)); } } dd.end(); } if (m_toolParams.m_showOpt) { dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(m_agentDebug.optStart[0],m_agentDebug.optStart[1]+0.3f,m_agentDebug.optStart[2], duRGBA(0,128,0,192)); dd.vertex(m_agentDebug.optEnd[0],m_agentDebug.optEnd[1]+0.3f,m_agentDebug.optEnd[2], duRGBA(0,128,0,192)); dd.end(); } } // Agent cylinders. for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); if (!ag->active) continue; const float radius = ag->params.radius; const float* pos = ag->npos; unsigned int col = duRGBA(0,0,0,32); if (m_agentDebug.idx == i) col = duRGBA(255,0,0,128); duDebugDrawCircle(&dd, pos[0], pos[1], pos[2], radius, col, 2.0f); } for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); if (!ag->active) continue; const float height = ag->params.height; const float radius = ag->params.radius; const float* pos = ag->npos; unsigned int col = duRGBA(220,220,220,128); if (ag->targetState == DT_CROWDAGENT_TARGET_REQUESTING || ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) col = duLerpCol(col, duRGBA(128,0,255,128), 32); else if (ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) col = duLerpCol(col, duRGBA(128,0,255,128), 128); else if (ag->targetState == DT_CROWDAGENT_TARGET_FAILED) col = duRGBA(255,32,16,128); else if (ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY) col = duLerpCol(col, duRGBA(64,255,0,128), 128); duDebugDrawCylinder(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius, pos[0]+radius, pos[1]+height, pos[2]+radius, col); } if (m_toolParams.m_showVO) { for (int i = 0; i < crowd->getAgentCount(); i++) { if (m_toolParams.m_showDetailAll == false && i != m_agentDebug.idx) continue; const dtCrowdAgent* ag =crowd->getAgent(i); if (!ag->active) continue; // Draw detail about agent sela const dtObstacleAvoidanceDebugData* vod = m_agentDebug.vod; const float dx = ag->npos[0]; const float dy = ag->npos[1]+ag->params.height; const float dz = ag->npos[2]; duDebugDrawCircle(&dd, dx,dy,dz, ag->params.maxSpeed, duRGBA(255,255,255,64), 2.0f); dd.begin(DU_DRAW_QUADS); for (int j = 0; j < vod->getSampleCount(); ++j) { const float* p = vod->getSampleVelocity(j); const float sr = vod->getSampleSize(j); const float pen = vod->getSamplePenalty(j); const float pen2 = vod->getSamplePreferredSidePenalty(j); unsigned int col = duLerpCol(duRGBA(255,255,255,220), duRGBA(128,96,0,220), (int)(pen*255)); col = duLerpCol(col, duRGBA(128,0,0,220), (int)(pen2*128)); dd.vertex(dx+p[0]-sr, dy, dz+p[2]-sr, col); dd.vertex(dx+p[0]-sr, dy, dz+p[2]+sr, col); dd.vertex(dx+p[0]+sr, dy, dz+p[2]+sr, col); dd.vertex(dx+p[0]+sr, dy, dz+p[2]-sr, col); } dd.end(); } } // Velocity stuff. for (int i = 0; i < crowd->getAgentCount(); ++i) { const dtCrowdAgent* ag = crowd->getAgent(i); if (!ag->active) continue; const float radius = ag->params.radius; const float height = ag->params.height; const float* pos = ag->npos; const float* vel = ag->vel; const float* dvel = ag->dvel; unsigned int col = duRGBA(220,220,220,192); if (ag->targetState == DT_CROWDAGENT_TARGET_REQUESTING || ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE) col = duLerpCol(col, duRGBA(128,0,255,192), 32); else if (ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_PATH) col = duLerpCol(col, duRGBA(128,0,255,192), 128); else if (ag->targetState == DT_CROWDAGENT_TARGET_FAILED) col = duRGBA(255,32,16,192); else if (ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY) col = duLerpCol(col, duRGBA(64,255,0,192), 128); duDebugDrawCircle(&dd, pos[0], pos[1]+height, pos[2], radius, col, 2.0f); duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], pos[0]+dvel[0],pos[1]+height+dvel[1],pos[2]+dvel[2], 0.0f, 0.4f, duRGBA(0,192,255,192), (m_agentDebug.idx == i) ? 2.0f : 1.0f); duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2], pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2], 0.0f, 0.4f, duRGBA(0,0,0,160), 2.0f); } dd.depthMask(true); }