void ESceneAIMapTool::BuildNodes(bool bFromSelectedOnly) { // begin m_Nodes.reserve (1024*1024); // Initialize hash // hash_Initialize (); R_ASSERT(!m_Nodes.empty()); // Estimate nodes Fvector Pos,LevelSize; m_AIBBox.getsize (LevelSize); float estimated_nodes = (LevelSize.x/m_Params.fPatchSize)*(LevelSize.z/m_Params.fPatchSize); SPBItem* pb = UI->ProgressStart(1, "Building nodes..."); // General cycle for (int k=0; k<(int)m_Nodes.size(); k++){ SAINode* N = m_Nodes[k]; if (bFromSelectedOnly && !N->flags.is(SAINode::flSelected)) continue; // left if (0==N->n1){ Pos.set (N->Pos); Pos.x -= m_Params.fPatchSize; N->n1 = BuildNode(N->Pos,Pos,false); } // fwd if (0==N->n2){ Pos.set (N->Pos); Pos.z += m_Params.fPatchSize; N->n2 = BuildNode(N->Pos,Pos,false); } // right if (0==N->n3){ Pos.set (N->Pos); Pos.x += m_Params.fPatchSize; N->n3 = BuildNode(N->Pos,Pos,false); } // back if (0==N->n4){ Pos.set (N->Pos); Pos.z -= m_Params.fPatchSize; N->n4 = BuildNode(N->Pos,Pos,false); } if (bFromSelectedOnly){ // select neighbour nodes if (N->n1) N->n1->flags.set(SAINode::flSelected,TRUE); if (N->n2) N->n2->flags.set(SAINode::flSelected,TRUE); if (N->n3) N->n3->flags.set(SAINode::flSelected,TRUE); if (N->n4) N->n4->flags.set(SAINode::flSelected,TRUE); } if (k%512==0) { float p1 = float(k)/float(m_Nodes.size()); float p2 = float(m_Nodes.size())/estimated_nodes; float p = 0.1f*p1+0.9f*p2; clamp (p,0.f,1.f); pb->Update(p); // check need abort && redraw if (k%32768==0) UI->RedrawScene(true); if (UI->NeedAbort()) break; } } UI->ProgressEnd(pb); }
void ESceneAIMapTool::SmoothNodes() { SPBItem* pb = UI->ProgressStart(m_Nodes.size(), "Smoothing nodes..."); AINodeVec smoothed; smoothed.reserve(m_Nodes.size()); U8Vec mark; mark.assign (m_Nodes.size(),0); int sm_nodes=0; EnumerateNodes (); for (AINodeIt it=m_Nodes.begin(); it!=m_Nodes.end(); it++){ SAINode& N = **it; Fvector P1,P2,P3,P4,P,REF; int c; if (N.flags.is(SAINode::flSelected)){ sm_nodes++; // smooth point LF { bool bCorner = false; c=1; N.PointLF(REF,m_Params.fPatchSize); P1.set(REF); if (N.nLeft()) { SAINode& L = *N.nLeft(); L.PointFR(P,m_Params.fPatchSize); merge(P1); if (L.nForward()) { bCorner = true; SAINode& C = *L.nForward(); C.PointRB(P,m_Params.fPatchSize); merge(P1); } } if (N.nForward()) { SAINode& F = *N.nForward(); F.PointBL(P,m_Params.fPatchSize); merge(P1); if ((!bCorner) && F.nLeft()) { bCorner = true; SAINode& C = *F.nLeft(); C.PointRB(P,m_Params.fPatchSize); merge(P1); } } R_ASSERT(c<=4); P1.div(float(c)); } // smooth point FR { bool bCorner = false; c=1; N.PointFR(REF,m_Params.fPatchSize); P2.set(REF); if (N.nForward()) { SAINode& F = *N.nForward(); F.PointRB(P,m_Params.fPatchSize); merge(P2); if (F.nRight()) { bCorner = true; SAINode& C = *F.nRight(); C.PointBL(P,m_Params.fPatchSize); merge(P2); } } if (N.nRight()) { SAINode& R = *N.nRight(); R.PointLF(P,m_Params.fPatchSize); merge(P2); if ((!bCorner) && R.nForward()) { bCorner = true; SAINode& C = *R.nForward(); C.PointBL(P,m_Params.fPatchSize); merge(P2); } } R_ASSERT(c<=4); P2.div(float(c)); } // smooth point RB { bool bCorner = false; c=1; N.PointRB(REF,m_Params.fPatchSize); P3.set(REF); if (N.nRight()) { SAINode& R = *N.nRight(); R.PointBL(P,m_Params.fPatchSize); merge(P3); if (R.nBack()) { bCorner = true; SAINode& C = *R.nBack(); C.PointLF(P,m_Params.fPatchSize); merge(P3); } } if (N.nBack()) { SAINode& B = *N.nBack(); B.PointFR(P,m_Params.fPatchSize); merge(P3); if ((!bCorner) && B.nRight()) { bCorner = true; SAINode& C = *B.nRight(); C.PointLF(P,m_Params.fPatchSize); merge(P3); } } R_ASSERT(c<=4); P3.div(float(c)); } // smooth point BL { bool bCorner = false; c=1; N.PointBL(REF,m_Params.fPatchSize); P4.set(REF); if (N.nBack()) { SAINode& B = *N.nBack(); B.PointLF(P,m_Params.fPatchSize); merge(P4); if (B.nLeft()) { bCorner = true; SAINode& C = *B.nLeft(); C.PointFR(P,m_Params.fPatchSize); merge(P4); } } if (N.nLeft()) { SAINode& L = *N.nLeft(); L.PointRB(P,m_Params.fPatchSize); merge(P4); if ((!bCorner) && L.nBack()) { bCorner = true; SAINode& C = *L.nBack(); C.PointFR(P,m_Params.fPatchSize); merge(P4); } } R_ASSERT(c<=4); P4.div(float(c)); } // align plane Fvector data[4]; data[0]=P1; data[1]=P2; data[2]=P3; data[3]=P4; Fvector vOffs,vNorm,D; vNorm.set(N.Plane.n); vOffs.set(N.Pos); Mgc::OrthogonalPlaneFit( 4,(Mgc::Vector3*)data, *((Mgc::Vector3*)&vOffs), *((Mgc::Vector3*)&vNorm) ); if (vNorm.y<0) vNorm.invert(); // create _new node SAINode* NEW = xr_new<SAINode>(N); NEW->n1 = (SAINode*)(N.n1?N.n1->idx:InvalidNode); NEW->n2 = (SAINode*)(N.n2?N.n2->idx:InvalidNode); NEW->n3 = (SAINode*)(N.n3?N.n3->idx:InvalidNode); NEW->n4 = (SAINode*)(N.n4?N.n4->idx:InvalidNode); NEW->Plane.build(vOffs,vNorm); D.set (0,1,0); N.Plane.intersectRayPoint(N.Pos,D,NEW->Pos); // "project" position smoothed.push_back (NEW); }else{ // create _new node SAINode* NEW = xr_new<SAINode>(N); NEW->n1 = (SAINode*)(N.n1?N.n1->idx:InvalidNode); NEW->n2 = (SAINode*)(N.n2?N.n2->idx:InvalidNode); NEW->n3 = (SAINode*)(N.n3?N.n3->idx:InvalidNode); NEW->n4 = (SAINode*)(N.n4?N.n4->idx:InvalidNode); smoothed.push_back (NEW); } int k = it-m_Nodes.begin(); if (k%128==0) { pb->Update(k); if (UI->NeedAbort()) break; } } UI->ProgressEnd(pb); Clear (true); m_Nodes = smoothed; DenumerateNodes (); hash_FillFromNodes (); UpdateHLSelected (); if (sm_nodes) Scene->UndoSave(); }
int ESceneAIMapTool::BuildNodes(const Fvector& pos, int sz, bool bIC) { // Align emitter Fvector Pos = pos; SnapXZ (Pos,m_Params.fPatchSize); Pos.y += 1; Fvector Dir; Dir.set(0,-1,0); int cnt = 0; if (m_CFModel) cnt=Scene->RayQuery(PQ,Pos,Dir,3,CDB::OPT_ONLYNEAREST|CDB::OPT_CULL,m_CFModel); else cnt=Scene->RayQuery(PQ,Pos,Dir,3,CDB::OPT_ONLYNEAREST|CDB::OPT_CULL,GetSnapList()); if (0==cnt) { ELog.Msg (mtInformation,"Can't align position."); return 0; } else { Pos.y = Pos.y - PQ.r_begin()->range; } // Build first node int oldcount = m_Nodes.size(); SAINode* start = BuildNode(Pos,Pos,bIC); if (!start) return 0; // Estimate nodes float estimated_nodes = (2*sz-1)*(2*sz-1); SPBItem* pb = 0; if (estimated_nodes>1024) pb = UI->ProgressStart(1, "Building nodes..."); float radius = sz*m_Params.fPatchSize-EPS_L; // General cycle for (int k=0; k<(int)m_Nodes.size(); k++){ SAINode* N = m_Nodes[k]; // left if (0==N->n1){ Pos.set (N->Pos); Pos.x -= m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n1 = BuildNode(N->Pos,Pos,bIC); } // fwd if (0==N->n2){ Pos.set (N->Pos); Pos.z += m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n2 = BuildNode(N->Pos,Pos,bIC); } // right if (0==N->n3){ Pos.set (N->Pos); Pos.x += m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n3 = BuildNode(N->Pos,Pos,bIC); } // back if (0==N->n4){ Pos.set (N->Pos); Pos.z -= m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n4 = BuildNode(N->Pos,Pos,bIC); } if (estimated_nodes>1024){ if (k%128==0) { float p1 = float(k)/float(m_Nodes.size()); float p2 = float(m_Nodes.size())/estimated_nodes; float p = 0.1f*p1+0.9f*p2; clamp (p,0.f,1.f); pb->Update(p); // check need abort && redraw if (UI->NeedAbort()) break; } } } if (estimated_nodes>1024) UI->ProgressEnd(pb); return oldcount-m_Nodes.size(); }