void TestCase::handleRender() { glLineWidth(2.0f); glBegin(GL_LINES); for (Test* iter = m_tests; iter; iter = iter->next) { float dir[3]; dtVsub(dir, iter->epos, iter->spos); dtVnormalize(dir); glColor4ub(128,25,0,192); glVertex3f(iter->spos[0],iter->spos[1]-0.3f,iter->spos[2]); glVertex3f(iter->spos[0],iter->spos[1]+0.3f,iter->spos[2]); glVertex3f(iter->spos[0],iter->spos[1]+0.3f,iter->spos[2]); glVertex3f(iter->spos[0]+dir[0]*0.3f,iter->spos[1]+0.3f+dir[1]*0.3f,iter->spos[2]+dir[2]*0.3f); glColor4ub(51,102,0,129); glVertex3f(iter->epos[0],iter->epos[1]-0.3f,iter->epos[2]); glVertex3f(iter->epos[0],iter->epos[1]+0.3f,iter->epos[2]); if (iter->expand) glColor4ub(255,192,0,255); else glColor4ub(0,0,0,64); for (int i = 0; i < iter->nstraight-1; ++i) { glVertex3f(iter->straight[i*3+0],iter->straight[i*3+1]+0.3f,iter->straight[i*3+2]); glVertex3f(iter->straight[(i+1)*3+0],iter->straight[(i+1)*3+1]+0.3f,iter->straight[(i+1)*3+2]); } } glEnd(); glLineWidth(1.0f); }
static void calcSmoothSteerDirection(const dtCrowdAgent* ag, float* dir) { if (!ag->ncorners) { dtVset(dir, 0,0,0); return; } const int ip0 = 0; const int ip1 = dtMin(1, ag->ncorners-1); const float* p0 = &ag->cornerVerts[ip0*3]; const float* p1 = &ag->cornerVerts[ip1*3]; float dir0[3], dir1[3]; dtVsub(dir0, p0, ag->npos); dtVsub(dir1, p1, ag->npos); dir0[1] = 0; dir1[1] = 0; float len0 = dtVlen(dir0); float len1 = dtVlen(dir1); if (len1 > 0.001f) dtVscale(dir1,dir1,1.0f/len1); dir[0] = dir0[0] - dir1[0]*len0*0.5f; dir[1] = 0; dir[2] = dir0[2] - dir1[2]*len0*0.5f; dtVnormalize(dir); }
static void calcVel(float* vel, const float* pos, const float* tgt, const float speed) { dtVsub(vel, tgt, pos); vel[1] = 0.0; dtVnormalize(vel); dtVscale(vel, vel, speed); }
void OgreDetourCrowd::calcVel(float* velocity, const float* position, const float* target, const float speed) { dtVsub(velocity, target, position); velocity[1] = 0.0; dtVnormalize(velocity); dtVscale(velocity, velocity, speed); }
static void calcStraightSteerDirection(const dtCrowdAgent* ag, float* dir) { if (!ag->ncorners) { dtVset(dir, 0,0,0); return; } dtVsub(dir, &ag->cornerVerts[0], ag->npos); dir[1] = 0; dtVnormalize(dir); }
void Agent::Force(const float* p) { float vel[3]; if (m_CrowdAgent && m_CrowdAgent->active) { // calculate velocity dtVsub(vel, p, m_CrowdAgent->npos); vel[1] = 0.0; dtVnormalize(vel); dtVscale(vel, vel, m_CrowdAgent->params.maxSpeed); m_NavMesh->Crowd()->requestMoveVelocity(m_AgentID, vel); } }
void dtCrowd::updateStepOffMeshVelocity(const float dt, dtCrowdAgentDebugInfo*) { // UE4 version of offmesh anims, updates velocity and checks distance instead of fixed time for (int i = 0; i < m_numActiveAgents; ++i) { dtCrowdAgent* ag = m_activeAgents[i]; const int agentIndex = getAgentIndex(ag); dtCrowdAgentAnimation* anim = &m_agentAnims[agentIndex]; if (!anim->active) continue; anim->t += dt; const float dist = dtVdistSqr(ag->npos, anim->endPos); const float distThres = dtSqr(5.0f); if (dist < distThres) { // Reset animation anim->active = 0; // Prepare agent for walking. ag->state = DT_CROWDAGENT_STATE_WALKING; // UE4: m_keepOffmeshConnections support if (m_keepOffmeshConnections) { ag->corridor.pruneOffmeshConenction(anim->polyRef); } } if (ag->state == DT_CROWDAGENT_STATE_OFFMESH) { float dir[3] = { 0 }; dtVsub(dir, anim->endPos, anim->initPos); dir[1] = 0.0f; dtVnormalize(dir); dtVscale(ag->nvel, dir, ag->params.maxSpeed); dtVcopy(ag->vel, ag->nvel); dtVset(ag->dvel, 0, 0, 0); } } }
void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel) { // Prepare obstacles for (int i = 0; i < m_ncircles; ++i) { dtObstacleCircle* cir = &m_circles[i]; // Side const float* pa = pos; const float* pb = cir->p; const float orig[3] = {0,0,0}; float dv[3]; dtVsub(cir->dp,pb,pa); dtVnormalize(cir->dp); dtVsub(dv, cir->dvel, dvel); const float a = dtTriArea2D(orig, cir->dp,dv); if (a < 0.01f) { cir->np[0] = -cir->dp[2]; cir->np[2] = cir->dp[0]; } else { cir->np[0] = cir->dp[2]; cir->np[2] = -cir->dp[0]; } } for (int i = 0; i < m_nsegments; ++i) { dtObstacleSegment* seg = &m_segments[i]; // Precalc if the agent is really close to the segment. const float r = 0.01f; float t; seg->touch = dtDistancePtSegSqr2D(pos, seg->p, seg->q, t) < dtSqr(r); } }
bool TestCase::handleRenderOverlay(double* proj, double* model, int* view) { GLdouble x, y, z; char text[64], subtext[64]; int n = 0; static const float LABEL_DIST = 1.0f; for (Test* iter = m_tests; iter; iter = iter->next) { float pt[3], dir[3]; if (iter->nstraight) { dtVcopy(pt, &iter->straight[3]); if (dtVdist(pt, iter->spos) > LABEL_DIST) { dtVsub(dir, pt, iter->spos); dtVnormalize(dir); dtVmad(pt, iter->spos, dir, LABEL_DIST); } pt[1]+=0.5f; } else { dtVsub(dir, iter->epos, iter->spos); dtVnormalize(dir); dtVmad(pt, iter->spos, dir, LABEL_DIST); pt[1]+=0.5f; } if (gluProject((GLdouble)pt[0], (GLdouble)pt[1], (GLdouble)pt[2], model, proj, view, &x, &y, &z)) { snprintf(text, 64, "Path %d\n", n); unsigned int col = imguiRGBA(0,0,0,128); if (iter->expand) col = imguiRGBA(255,192,0,220); imguiDrawText((int)x, (int)(y-25), IMGUI_ALIGN_CENTER, text, col); } n++; } static int resScroll = 0; bool mouseOverMenu = imguiBeginScrollArea("Test Results", 10, view[3] - 10 - 350, 200, 350, &resScroll); // mouseOverMenu = true; n = 0; for (Test* iter = m_tests; iter; iter = iter->next) { const int total = iter->findNearestPolyTime + iter->findPathTime + iter->findStraightPathTime; snprintf(subtext, 64, "%.4f ms", (float)total/1000.0f); snprintf(text, 64, "Path %d", n); if (imguiCollapse(text, subtext, iter->expand)) iter->expand = !iter->expand; if (iter->expand) { snprintf(text, 64, "Poly: %.4f ms", (float)iter->findNearestPolyTime/1000.0f); imguiValue(text); snprintf(text, 64, "Path: %.4f ms", (float)iter->findPathTime/1000.0f); imguiValue(text); snprintf(text, 64, "Straight: %.4f ms", (float)iter->findStraightPathTime/1000.0f); imguiValue(text); imguiSeparator(); } n++; } imguiEndScrollArea(); return mouseOverMenu; }
void NavMeshTesterTool::handleRender() { DebugDrawGL dd; static const unsigned int startCol = duRGBA(128,25,0,192); static const unsigned int endCol = duRGBA(51,102,0,129); static const unsigned int pathCol = duRGBA(0,0,0,64); const float agentRadius = m_sample->getAgentRadius(); const float agentHeight = m_sample->getAgentHeight(); const float agentClimb = m_sample->getAgentClimb(); dd.depthMask(false); if (m_sposSet) drawAgent(m_spos, agentRadius, agentHeight, agentClimb, startCol); if (m_eposSet) drawAgent(m_epos, agentRadius, agentHeight, agentClimb, endCol); dd.depthMask(true); if (!m_navMesh) { return; } if (m_toolMode == TOOLMODE_PATHFIND_FOLLOW) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_startRef, startCol); duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_endRef, endCol); if (m_npolys) { for (int i = 1; i < m_npolys-1; ++i) duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); } if (m_nsmoothPath) { dd.depthMask(false); const unsigned int pathCol = duRGBA(0,0,0,220); dd.begin(DU_DRAW_LINES, 3.0f); for (int i = 0; i < m_nsmoothPath; ++i) dd.vertex(m_smoothPath[i*3], m_smoothPath[i*3+1]+0.1f, m_smoothPath[i*3+2], pathCol); dd.end(); dd.depthMask(true); } if (m_pathIterNum) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_pathIterPolys[0], duRGBA(255,255,255,128)); dd.depthMask(false); dd.begin(DU_DRAW_LINES, 1.0f); const unsigned int prevCol = duRGBA(255,192,0,220); const unsigned int curCol = duRGBA(255,255,255,220); const unsigned int steerCol = duRGBA(0,192,255,220); dd.vertex(m_prevIterPos[0],m_prevIterPos[1]-0.3f,m_prevIterPos[2], prevCol); dd.vertex(m_prevIterPos[0],m_prevIterPos[1]+0.3f,m_prevIterPos[2], prevCol); dd.vertex(m_iterPos[0],m_iterPos[1]-0.3f,m_iterPos[2], curCol); dd.vertex(m_iterPos[0],m_iterPos[1]+0.3f,m_iterPos[2], curCol); dd.vertex(m_prevIterPos[0],m_prevIterPos[1]+0.3f,m_prevIterPos[2], prevCol); dd.vertex(m_iterPos[0],m_iterPos[1]+0.3f,m_iterPos[2], prevCol); dd.vertex(m_prevIterPos[0],m_prevIterPos[1]+0.3f,m_prevIterPos[2], steerCol); dd.vertex(m_steerPos[0],m_steerPos[1]+0.3f,m_steerPos[2], steerCol); for (int i = 0; i < m_steerPointCount-1; ++i) { dd.vertex(m_steerPoints[i*3+0],m_steerPoints[i*3+1]+0.2f,m_steerPoints[i*3+2], duDarkenCol(steerCol)); dd.vertex(m_steerPoints[(i+1)*3+0],m_steerPoints[(i+1)*3+1]+0.2f,m_steerPoints[(i+1)*3+2], duDarkenCol(steerCol)); } dd.end(); dd.depthMask(true); } } else if (m_toolMode == TOOLMODE_PATHFIND_STRAIGHT || m_toolMode == TOOLMODE_PATHFIND_SLICED) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_startRef, startCol); duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_endRef, endCol); if (m_npolys) { for (int i = 1; i < m_npolys-1; ++i) duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); } if (m_nstraightPath) { dd.depthMask(false); const unsigned int pathCol = duRGBA(64,16,0,220); const unsigned int offMeshCol = duRGBA(128,96,0,220); dd.begin(DU_DRAW_LINES, 2.0f); for (int i = 0; i < m_nstraightPath-1; ++i) { unsigned int col = 0; if (m_straightPathFlags[i] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) col = offMeshCol; else col = pathCol; dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], col); dd.vertex(m_straightPath[(i+1)*3], m_straightPath[(i+1)*3+1]+0.4f, m_straightPath[(i+1)*3+2], col); } dd.end(); dd.begin(DU_DRAW_POINTS, 6.0f); for (int i = 0; i < m_nstraightPath; ++i) { unsigned int col = 0; if (m_straightPathFlags[i] & DT_STRAIGHTPATH_START) col = startCol; else if (m_straightPathFlags[i] & DT_STRAIGHTPATH_START) col = endCol; else if (m_straightPathFlags[i] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) col = offMeshCol; else col = pathCol; dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], pathCol); } dd.end(); dd.depthMask(true); } } else if (m_toolMode == TOOLMODE_RAYCAST) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_startRef, startCol); if (m_nstraightPath) { for (int i = 1; i < m_npolys; ++i) duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); dd.depthMask(false); const unsigned int pathCol = m_hitResult ? duRGBA(64,16,0,220) : duRGBA(240,240,240,220); dd.begin(DU_DRAW_LINES, 2.0f); for (int i = 0; i < m_nstraightPath-1; ++i) { dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], pathCol); dd.vertex(m_straightPath[(i+1)*3], m_straightPath[(i+1)*3+1]+0.4f, m_straightPath[(i+1)*3+2], pathCol); } dd.end(); dd.begin(DU_DRAW_POINTS, 4.0f); for (int i = 0; i < m_nstraightPath; ++i) dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], pathCol); dd.end(); if (m_hitResult) { const unsigned int hitCol = duRGBA(0,0,0,128); dd.begin(DU_DRAW_LINES, 2.0f); dd.vertex(m_hitPos[0], m_hitPos[1] + 0.4f, m_hitPos[2], hitCol); dd.vertex(m_hitPos[0] + m_hitNormal[0]*agentRadius, m_hitPos[1] + 0.4f + m_hitNormal[1]*agentRadius, m_hitPos[2] + m_hitNormal[2]*agentRadius, hitCol); dd.end(); } dd.depthMask(true); } } else if (m_toolMode == TOOLMODE_DISTANCE_TO_WALL) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_startRef, startCol); dd.depthMask(false); duDebugDrawCircle(&dd, m_spos[0], m_spos[1]+agentHeight/2, m_spos[2], m_distanceToWall, duRGBA(64,16,0,220), 2.0f); dd.begin(DU_DRAW_LINES, 3.0f); dd.vertex(m_hitPos[0], m_hitPos[1] + 0.02f, m_hitPos[2], duRGBA(0,0,0,192)); dd.vertex(m_hitPos[0], m_hitPos[1] + agentHeight, m_hitPos[2], duRGBA(0,0,0,192)); dd.end(); dd.depthMask(true); } else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_CIRCLE) { for (int i = 0; i < m_npolys; ++i) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); dd.depthMask(false); if (m_parent[i]) { float p0[3], p1[3]; dd.depthMask(false); getPolyCenter(m_navMesh, m_parent[i], p0); getPolyCenter(m_navMesh, m_polys[i], p1); duDebugDrawArc(&dd, p0[0],p0[1],p0[2], p1[0],p1[1],p1[2], 0.25f, 0.0f, 0.4f, duRGBA(0,0,0,128), 2.0f); dd.depthMask(true); } dd.depthMask(true); } if (m_sposSet && m_eposSet) { dd.depthMask(false); const float dx = m_epos[0] - m_spos[0]; const float dz = m_epos[2] - m_spos[2]; const float dist = sqrtf(dx*dx + dz*dz); duDebugDrawCircle(&dd, m_spos[0], m_spos[1]+agentHeight/2, m_spos[2], dist, duRGBA(64,16,0,220), 2.0f); dd.depthMask(true); } } else if (m_toolMode == TOOLMODE_FIND_POLYS_IN_SHAPE) { for (int i = 0; i < m_npolys; ++i) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); dd.depthMask(false); if (m_parent[i]) { float p0[3], p1[3]; dd.depthMask(false); getPolyCenter(m_navMesh, m_parent[i], p0); getPolyCenter(m_navMesh, m_polys[i], p1); duDebugDrawArc(&dd, p0[0],p0[1],p0[2], p1[0],p1[1],p1[2], 0.25f, 0.0f, 0.4f, duRGBA(0,0,0,128), 2.0f); dd.depthMask(true); } dd.depthMask(true); } if (m_sposSet && m_eposSet) { dd.depthMask(false); const unsigned int col = duRGBA(64,16,0,220); dd.begin(DU_DRAW_LINES, 2.0f); for (int i = 0, j = 3; i < 4; j=i++) { const float* p0 = &m_queryPoly[j*3]; const float* p1 = &m_queryPoly[i*3]; dd.vertex(p0, col); dd.vertex(p1, col); } dd.end(); dd.depthMask(true); } } else if (m_toolMode == TOOLMODE_FIND_LOCAL_NEIGHBOURHOOD) { for (int i = 0; i < m_npolys; ++i) { duDebugDrawNavMeshPoly(&dd, *m_navMesh, m_polys[i], pathCol); dd.depthMask(false); if (m_parent[i]) { float p0[3], p1[3]; dd.depthMask(false); getPolyCenter(m_navMesh, m_parent[i], p0); getPolyCenter(m_navMesh, m_polys[i], p1); duDebugDrawArc(&dd, p0[0],p0[1],p0[2], p1[0],p1[1],p1[2], 0.25f, 0.0f, 0.4f, duRGBA(0,0,0,128), 2.0f); dd.depthMask(true); } static const int MAX_SEGS = DT_VERTS_PER_POLYGON*2; float segs[MAX_SEGS*6]; int nsegs = 0; m_navQuery->getPolyWallSegments(m_polys[i], &m_filter, segs, &nsegs, MAX_SEGS); dd.begin(DU_DRAW_LINES, 2.0f); for (int j = 0; j < nsegs; ++j) { const float* s = &segs[j*6]; // Skip too distant segments. float tseg; float distSqr = dtDistancePtSegSqr2D(m_spos, s, s+3, tseg); if (distSqr > dtSqr(m_neighbourhoodRadius)) continue; float delta[3], norm[3], p0[3], p1[3]; dtVsub(delta, s+3,s); dtVmad(p0, s, delta, 0.5f); norm[0] = delta[2]; norm[1] = 0; norm[2] = -delta[0]; dtVnormalize(norm); dtVmad(p1, p0, norm, agentRadius*0.5f); // Skip backfacing segments. unsigned int col = duRGBA(255,255,255,192); if (dtTriArea2D(m_spos, s, s+3) < 0.0f) col = duRGBA(255,255,255,64); dd.vertex(p0[0],p0[1]+agentClimb,p0[2],duRGBA(0,0,0,128)); dd.vertex(p1[0],p1[1]+agentClimb,p1[2],duRGBA(0,0,0,128)); dd.vertex(s[0],s[1]+agentClimb,s[2],col); dd.vertex(s[3],s[4]+agentClimb,s[5],col); } dd.end(); dd.depthMask(true); } if (m_sposSet) { dd.depthMask(false); duDebugDrawCircle(&dd, m_spos[0], m_spos[1]+agentHeight/2, m_spos[2], m_neighbourhoodRadius, duRGBA(64,16,0,220), 2.0f); dd.depthMask(true); } } }
void dtCrowd::updateStepProximityData(const float dt, dtCrowdAgentDebugInfo*) { // Register agents to proximity grid. m_grid->clear(); for (int i = 0; i < m_numActiveAgents; ++i) { dtCrowdAgent* ag = m_activeAgents[i]; const float* p = ag->npos; const float r = ag->params.radius; m_grid->addItem((unsigned short)i, p[0] - r, p[2] - r, p[0] + r, p[2] + r); } // Get nearby navmesh segments and agents to collide with. for (int i = 0; i < m_numActiveAgents; ++i) { dtCrowdAgent* ag = m_activeAgents[i]; if (ag->state != DT_CROWDAGENT_STATE_WALKING) continue; m_navquery->updateLinkFilter(ag->params.linkFilter); // Update the collision boundary after certain distance has been passed or // if it has become invalid. const float updateThr = ag->params.collisionQueryRange*0.25f; if (dtVdist2DSqr(ag->npos, ag->boundary.getCenter()) > dtSqr(updateThr) || !ag->boundary.isValid(m_navquery, &m_filters[ag->params.filter])) { // UE4: force removing segments too close to offmesh links const bool useForcedRemove = m_linkRemovalRadius > 0.0f && ag->ncorners && (ag->cornerFlags[ag->ncorners - 1] & DT_STRAIGHTPATH_OFFMESH_CONNECTION); const float* removePos = useForcedRemove ? &ag->cornerVerts[(ag->ncorners - 1) * 3] : 0; const float removeRadius = m_linkRemovalRadius; // UE4: prepare filter containing only current area // boundary update will take all corner polys and include them in local neighborhood unsigned char allowedArea = DT_WALKABLE_AREA; if (m_raycastSingleArea) { m_navquery->getAttachedNavMesh()->getPolyArea(ag->corridor.getFirstPoly(), &allowedArea); m_raycastFilter.setAreaCost(allowedArea, 1.0f); } // UE4: move dir for segment scoring float moveDir[3] = { 0.0f }; if (ag->ncorners) { dtVsub(moveDir, &ag->cornerVerts[2], &ag->cornerVerts[0]); } else { dtVcopy(moveDir, ag->vel); } dtVnormalize(moveDir); ag->boundary.update(ag->corridor.getFirstPoly(), ag->npos, ag->params.collisionQueryRange, removePos, removeRadius, useForcedRemove, ag->corridor.getPath(), ag->corridor.getPathCount(), moveDir, m_navquery, m_raycastSingleArea ? &m_raycastFilter : &m_filters[ag->params.filter]); m_raycastFilter.setAreaCost(allowedArea, DT_UNWALKABLE_POLY_COST); } // Query neighbour agents ag->nneis = getNeighbours(ag->npos, ag->params.height, ag->params.collisionQueryRange, ag, ag->neis, DT_CROWDAGENT_MAX_NEIGHBOURS, m_activeAgents, m_numActiveAgents, m_grid); for (int j = 0; j < ag->nneis; j++) ag->neis[j].idx = getAgentIndex(m_activeAgents[ag->neis[j].idx]); } }
bool Visualization::update() { if (!m_initialized) { printf("Visualization has not been yet initialized."); return false; } // Compute the time since last update (in seconds). Uint32 time = SDL_GetTicks(); float dt = (time - m_lastTickCount) / 1000.0f; m_lastTickCount = time; bool singleSimulationStep = false; bool scrollForward = false; bool scrollBackward = false; int mscroll = 0; SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: // Handle any key presses here. if (event.key.keysym.sym == SDLK_ESCAPE) //Escape. { m_stopRequested = true; } else if (event.key.keysym.sym == SDLK_SPACE) { m_paused = !m_paused; } else if (event.key.keysym.sym == SDLK_TAB) { singleSimulationStep = true; } else if (event.key.keysym.sym == SDLK_r) { float pos[3] = {-15, 0, 15}; m_crowd->pushAgentPosition(0, pos); } else if (event.key.keysym.sym == SDLK_KP7) { float pos[3] = {-19, 0, -19}; dtVnormalize(pos); dtVscale(pos, pos, 2.f); dtCrowdAgent ag; m_crowd->fetchAgent(ag, 0); dtVcopy(ag.velocity, pos); m_crowd->pushAgent(ag); } else if (event.key.keysym.sym == SDLK_KP9) { float pos[] = {19, 0, -19}; dtVnormalize(pos); dtVscale(pos, pos, 2.f); dtCrowdAgent ag; m_crowd->fetchAgent(ag, 0); dtVcopy(ag.velocity, pos); m_crowd->pushAgent(ag); } else if (event.key.keysym.sym == SDLK_KP3) { float pos[3] = {19, 0, 19}; dtVnormalize(pos); dtVscale(pos, pos, 2.f); dtCrowdAgent ag; m_crowd->fetchAgent(ag, 0); dtVcopy(ag.velocity, pos); m_crowd->pushAgent(ag); } else if (event.key.keysym.sym == SDLK_KP1) { float pos[3] = {-19, 0, 19}; dtVnormalize(pos); dtVscale(pos, pos, 2.f); dtCrowdAgent ag; m_crowd->fetchAgent(ag, 0); dtVcopy(ag.velocity, pos); m_crowd->pushAgent(ag); } else if (event.key.keysym.sym == SDLK_KP5) { float pos[3] = {0, 0, 0}; dtVnormalize(pos); dtVscale(pos, pos, 2.f); dtCrowdAgent ag; m_crowd->fetchAgent(ag, 0); dtVcopy(ag.velocity, pos); m_crowd->pushAgent(ag); } break; case SDL_MOUSEBUTTONDOWN: if (event.button.button == SDL_BUTTON_RIGHT) { // Rotate view m_rotating = true; m_initialMousePosition[0] = m_mousePosition[0]; m_initialMousePosition[1] = m_mousePosition[1]; m_intialCameraOrientation[0] = m_cameraOrientation[0]; m_intialCameraOrientation[1] = m_cameraOrientation[1]; m_intialCameraOrientation[2] = m_cameraOrientation[2]; } else if (event.button.button == SDL_BUTTON_WHEELUP) { scrollForward = true; } else if (event.button.button == SDL_BUTTON_WHEELDOWN) { scrollBackward = true; } break; case SDL_MOUSEBUTTONUP: if (event.button.button == SDL_BUTTON_RIGHT) { m_rotating = false; } else if (event.button.button == SDL_BUTTON_LEFT) { float pickedPosition[3]; int index = 0; pick(pickedPosition, &index); } break; case SDL_MOUSEMOTION: m_mousePosition[0] = event.motion.x; m_mousePosition[1] = m_winHeight-1 - event.motion.y; if (m_rotating) { int dx = m_mousePosition[0] - m_initialMousePosition[0]; int dy = m_mousePosition[1] - m_initialMousePosition[1]; m_cameraOrientation[0] = m_intialCameraOrientation[0] - dy*0.25f; m_cameraOrientation[1] = m_intialCameraOrientation[1] + dx*0.25f; } break; case SDL_QUIT: m_stopRequested = true; break; default: break; } } unsigned char mbut = 0; if (SDL_GetMouseState(0,0) & SDL_BUTTON_LMASK) mbut |= IMGUI_MBUT_LEFT; if (SDL_GetMouseState(0,0) & SDL_BUTTON_RMASK) mbut |= IMGUI_MBUT_RIGHT; // Update the camera velocity from keyboard state. Uint8* keystate = SDL_GetKeyState(NULL); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4800) #endif updateCameraVelocity( dt, keystate[SDLK_w] || keystate[SDLK_UP] || scrollForward, keystate[SDLK_s] || keystate[SDLK_DOWN] || scrollBackward, keystate[SDLK_a] || keystate[SDLK_LEFT], keystate[SDLK_d] || keystate[SDLK_RIGHT], SDL_GetModState() & KMOD_SHIFT); #ifdef _MSC_VER #pragma warning(pop) #endif //Update the camera position updateCameraPosition(dt); //Update the crowd if (m_crowd) { if (singleSimulationStep) { m_paused = true; m_debugInfo->startUpdate(); m_crowd->update(m_crowdDt); m_debugInfo->endUpdate(m_crowdDt); m_crowdAvailableDt = 0.f; } else if (!m_paused) { m_crowdAvailableDt += dt; while(m_crowdAvailableDt > m_crowdDt) { m_debugInfo->startUpdate(); m_crowd->update(m_crowdDt); m_debugInfo->endUpdate(m_crowdDt); m_crowdAvailableDt -= m_crowdDt; } } else { m_crowdAvailableDt = 0.f; } } // Set rendering context glViewport(0, 0, m_winWidth, m_winHeight); glClearColor(0.3f, 0.3f, 0.32f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); // Render 3D glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0f, (float)m_winWidth/(float)m_winHeight, m_zNear, m_zFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(m_cameraOrientation[0],1,0,0); glRotatef(m_cameraOrientation[1],0,1,0); glRotatef(m_cameraOrientation[2],0,0,1); glTranslatef(-m_cameraPosition[0], -m_cameraPosition[1], -m_cameraPosition[2]); // Extract OpenGL view properties glGetDoublev(GL_PROJECTION_MATRIX, m_projection); glGetDoublev(GL_MODELVIEW_MATRIX, m_modelView); glGetIntegerv(GL_VIEWPORT, m_viewport); renderScene(); renderCrowd(); // Render 2D Overlay glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, m_winWidth, 0, m_winHeight); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); imguiBeginFrame(m_mousePosition[0], m_mousePosition[1], mbut,mscroll); renderDebugInfoOverlay(); imguiEndFrame(); imguiRenderGLDraw(); glEnable(GL_DEPTH_TEST); SDL_GL_SwapBuffers(); return true; }