void ESceneAIMapTool::CalculateNodesBBox(Fbox& bb) { bb.invalidate(); for (AINodeIt b_it=m_Nodes.begin(); b_it!=m_Nodes.end(); ++b_it) { VERIFY(_valid((*b_it)->Pos)); bb.modify((*b_it)->Pos); } }
void EScene::ZoomExtents( ObjClassID cls, BOOL bSel ) { Fbox BB; BB.invalidate(); if (cls==OBJCLASS_DUMMY){ SceneToolsMapPairIt _I = m_SceneTools.begin(); SceneToolsMapPairIt _E = m_SceneTools.end(); for (; _I!=_E; _I++) if (_I->second){ Fbox bb; bb.invalidate(); _I->second->GetBBox (bb,bSel); if (bb.is_valid()) BB.merge(bb); } }else{ ESceneToolBase* mt = GetTool(cls); if (mt) mt->GetBBox(BB,bSel); } if (BB.is_valid()) Device.m_Camera.ZoomExtents(BB); else ELog.Msg(mtError,"Can't calculate bounding box. Nothing selected or some object unsupported this function."); }
bool ESceneObjectTools::GetBox (Fbox& bb) { bb.invalidate (); Fbox bbo; for (ObjectIt a_it=m_Objects.begin(); a_it!=m_Objects.end(); a_it++){ (*a_it)->GetBox (bbo); bb.merge (bbo); } return bb.is_valid(); }
IC void get_q_box( Fbox &xf, float c, float alpha, float radius ) { Fvector src_pt, tgt_pt; calc_point (tgt_pt,radius,0,alpha); src_pt.set (0,tgt_pt.y,0); xf.invalidate (); xf.modify (src_pt); xf.modify (tgt_pt); xf.grow (c); }
float CalculateHeight(Fbox& BB) { // All nodes BB.invalidate(); for (u32 i=0; i<g_nodes.size(); i++) { vertex& N = g_nodes[i]; BB.modify (N.Pos); } return BB.max.y-BB.min.y+EPS_L; }
void ComputeSphere(Fsphere &B, FvectorVec& V) { if (V.size()<3) { B.P.set(0,0,0); B.R=0.f; return; } // 1: calc first variation Fsphere S1; Fsphere_compute (S1,V.begin(),V.size()); BOOL B1 = SphereValid(V,S1); // 2: calc ordinary algorithm (2nd) Fsphere S2; Fbox bbox; bbox.invalidate (); for (FvectorIt I=V.begin(); I!=V.end(); I++) bbox.modify(*I); bbox.grow (EPS_L); bbox.getsphere (S2.P,S2.R); S2.R = -1; for (I=V.begin(); I!=V.end(); I++) { float d = S2.P.distance_to_sqr(*I); if (d>S2.R) S2.R=d; } S2.R = _sqrt (_abs(S2.R)); BOOL B2 = SphereValid(V,S2); // 3: calc magic-fm Mgc::Sphere _S3 = Mgc::MinSphere(V.size(), (const Mgc::Vector3*) V.begin()); Fsphere S3; S3.P.set (_S3.Center().x,_S3.Center().y,_S3.Center().z); S3.R = _S3.Radius(); BOOL B3 = SphereValid(V,S3); // select best one if (B1 && (S1.R<S2.R)){ // miniball or FM if (B3 && (S3.R<S1.R)){ // FM wins B.set (S3); }else{ // MiniBall wins B.set (S1); } }else{ // base or FM if (B3 && (S3.R<S2.R)){ // FM wins B.set (S3); }else{ // Base wins :) R_ASSERT(B2); B.set (S2); } } }
bool CLevelTool::GetSelectionPosition(Fmatrix& result) { if(pCurTool) { Fvector center; Fbox BB; BB.invalidate (); // pCurTool->GetBBox (BB, true); const CCustomObject* object = pCurTool->LastSelected(); if(!object) return false; object->GetBox (BB); BB.getcenter (center); center.y = BB.max.y; Fvector2 pt_ss; pt_ss.set (10000,-10000); Fvector pt_ss_3d; BB.setb (center, Fvector().set(1.0f,1.0f,1.0f)); for(int k=0;k<8;++k) { Fvector pt; BB.getpoint(k,pt); EDevice.mFullTransform.transform(pt_ss_3d, pt); pt_ss.x = _min(pt_ss.x, pt_ss_3d.y); pt_ss.y = _max(pt_ss.y, pt_ss_3d.y); } float r_bb_ss = pt_ss.y - pt_ss.x; clamp(r_bb_ss, 0.0f,0.10f); float des_radius = 0.2f; float csale = des_radius/r_bb_ss; result.scale (csale,csale,csale); result.c = center; return true; }else return false; }
void CParticleGroup::OnFrame(u32 u_dt) { if (m_Def&&m_RT_Flags.is(flRT_Playing)){ float ct = m_CurrentTime; float f_dt = float(u_dt)/1000.f; for (CPGDef::EffectVec::const_iterator e_it=m_Def->m_Effects.begin(); e_it!=m_Def->m_Effects.end(); e_it++){ if ((*e_it)->m_Flags.is(CPGDef::SEffect::flEnabled)){ VERIFY (items.size()==m_Def->m_Effects.size()); SItem& I = items[e_it-m_Def->m_Effects.begin()]; if (I.IsPlaying()){ if ((ct<=(*e_it)->m_Time1)&&(ct+f_dt>=(*e_it)->m_Time1)) I.Stop((*e_it)->m_Flags.is(CPGDef::SEffect::flDefferedStop)); }else{ if (!m_RT_Flags.is(flRT_DefferedStop)) if ((ct<=(*e_it)->m_Time0)&&(ct+f_dt>=(*e_it)->m_Time0)) I.Play(); } } } m_CurrentTime += f_dt; if ((m_CurrentTime>m_Def->m_fTimeLimit)&&(m_Def->m_fTimeLimit>0.f)) if (!m_RT_Flags.is(flRT_DefferedStop)) Stop(true); bool bPlaying = false; Fbox box; box.invalidate(); for (SItemVecIt i_it=items.begin(); i_it!=items.end(); i_it++) i_it->OnFrame(u_dt,*m_Def->m_Effects[i_it-items.begin()],box,bPlaying); if (m_RT_Flags.is(flRT_DefferedStop)&&!bPlaying){ m_RT_Flags.set (flRT_Playing|flRT_DefferedStop,FALSE); } if (box.is_valid()){ vis.box.set (box); vis.box.getsphere (vis.sphere.P,vis.sphere.R); } } else { vis.box.set (m_InitialPosition,m_InitialPosition); vis.box.grow (EPS_L); vis.box.getsphere (vis.sphere.P,vis.sphere.R); } }
void xrMU_Model::calc_lighting () { // BB Fbox BB; BB.invalidate (); for (v_vertices_it vit=m_vertices.begin(); vit!=m_vertices.end(); vit++) BB.modify ((*vit)->P); // Export CForm CDB::CollectorPacked CL (BB,(u32)m_vertices.size(),(u32)m_faces.size()); export_cform_rcast (CL,Fidentity); CDB::MODEL* M = xr_new<CDB::MODEL> (); M->build (CL.getV(),(u32)CL.getVS(),CL.getT(),(u32)CL.getTS()); calc_lighting (color,Fidentity,M,inlc_global_data()->L_static(),LP_dont_rgb+LP_dont_sun); xr_delete (M); clMsg ("model '%s' - REF_lighted.",*m_name); }
bool CGroupObject::GetBox(Fbox& bb) { bb.invalidate (); // update box for (ObjectIt it=m_Objects.begin(); it!=m_Objects.end(); it++){ switch((*it)->ClassID){ case OBJCLASS_SPAWNPOINT: case OBJCLASS_SCENEOBJECT:{ Fbox box; if ((*it)->GetBox(box)) bb.merge(box); }break; default: bb.modify((*it)->PPosition); } } if (!bb.is_valid()){ bb.set (PPosition,PPosition); bb.grow (EMPTY_GROUP_SIZE); } return bb.is_valid(); }
void CPortal::Setup (Fvector* V, int vcnt, CSector* face, CSector* back) { // calc sphere Fbox BB; BB.invalidate (); for (int v=0; v<vcnt; v++) BB.modify (V[v]); BB.getsphere (S.P,S.R); // poly.assign (V,vcnt); pFace = face; pBack = back; marker = 0xffffffff; Fvector N,T; N.set (0,0,0); FPU::m64r(); u32 _cnt = 0; for (int i=2; i<vcnt; i++) { T.mknormal_non_normalized (poly[0],poly[i-1],poly[i]); float m = T.magnitude (); if (m>EPS_S) { N.add (T.div(m)) ; _cnt ++ ; } } R_ASSERT2 (_cnt, "Invalid portal detected"); N.div (float(_cnt)); P.build (poly[0],N); FPU::m24r (); /* if (_abs(1-P.n.magnitude())<EPS) xrDebug::Fatal (DEBUG_INFO,"Degenerated portal found at {%3.2f,%3.2f,%3.2f}.",VPUSH(poly[0])); */ }
void CBuild::BuildCForm () { // Collecting data Phase ("CFORM: creating..."); vecFace* cfFaces = new vecFace(); vecVertex* cfVertices = new vecVertex(); { xr_vector<bool> cfVertexMarks; cfVertexMarks.assign (lc_global_data()->g_vertices().size(),false); Status("Sorting..."); std::sort(lc_global_data()->g_vertices().begin(),lc_global_data()->g_vertices().end()); Status("Collecting faces..."); cfFaces->reserve (lc_global_data()->g_faces().size()); for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); ++I) { Face* F = *I; if (F->Shader().flags.bCollision) { cfFaces->push_back(F); int index = GetVertexIndex(F->v[0]); cfVertexMarks[index] = true; index = GetVertexIndex(F->v[1]); cfVertexMarks[index] = true; index = GetVertexIndex(F->v[2]); cfVertexMarks[index] = true; } } Status("Collecting vertices..."); cfVertices->reserve (lc_global_data()->g_vertices().size()); std::sort(cfFaces->begin(),cfFaces->end()); for (u32 V=0; V<lc_global_data()->g_vertices().size(); V++) if (cfVertexMarks[V]) cfVertices->push_back(lc_global_data()->g_vertices()[V]); } float p_total = 0; float p_cost = 1.f/(cfVertices->size()); Fbox BB; BB.invalidate(); for (vecVertexIt it = cfVertices->begin(); it!=cfVertices->end(); it++) BB.modify((*it)->P ); // CForm Phase ("CFORM: collision model..."); Status ("Items to process: %d", cfFaces->size()); p_total = 0; p_cost = 1.f/(cfFaces->size()); // Collect faces CDB::CollectorPacked CL (BB,cfVertices->size(),cfFaces->size()); for (vecFaceIt F = cfFaces->begin(); F!=cfFaces->end(); F++) { Face* T = *F; TestEdge (T->v[0],T->v[1],T); TestEdge (T->v[1],T->v[2],T); TestEdge (T->v[2],T->v[0],T); CL.add_face ( T->v[0]->P, T->v[1]->P, T->v[2]->P, T->dwMaterialGame, materials()[T->dwMaterial].sector, T->sm_group ); Progress(p_total+=p_cost); // progress } if (bCriticalErrCnt) { err_save (); clMsg ("MultipleEdges: %d faces",bCriticalErrCnt); } xr_delete (cfFaces); xr_delete (cfVertices); // Models Status ("Models..."); for (u32 ref=0; ref<mu_refs().size(); ref++) mu_refs()[ref]->export_cform_game(CL); // Simplification if (g_params().m_quality!=ebqDraft) SimplifyCFORM (CL); // bb? BB.invalidate (); for (size_t it = 0; it<CL.getVS(); it++) BB.modify( CL.getV()[it] ); // Saving string_path fn; IWriter* MFS = FS.w_open (strconcat(sizeof(fn),fn,pBuild->path,"level.cform")); Status ("Saving..."); // Header hdrCFORM hdr; hdr.version = CFORM_CURRENT_VERSION; hdr.vertcount = (u32)CL.getVS(); hdr.facecount = (u32)CL.getTS(); hdr.aabb = BB; MFS->w (&hdr,sizeof(hdr)); // Data MFS->w (CL.getV(),(u32)CL.getVS()*sizeof(Fvector)); MFS->w (CL.getT(),(u32)CL.getTS()*sizeof(CDB::TRI)); // Clear pDeflector (it is stored in the same memory space with dwMaterialGame) for (vecFaceIt I=lc_global_data()->g_faces().begin(); I!=lc_global_data()->g_faces().end(); I++) { Face* F = *I; F->pDeflector = NULL; } FS.w_close (MFS); }
void CDeflector::OA_Export() { if (UVpolys.empty()) return; // Correct normal // (semi-proportional to pixel density) FPU::m64r (); Fvector tN; tN.set (0,0,0); float density = 0; float fcount = 0; for (UVIt it = UVpolys.begin(); it!=UVpolys.end(); it++) { Face *F = it->owner; Fvector SN; SN.set (F->N); SN.mul (1+EPS*F->CalcArea()); tN.add (SN); density += F->Shader().lm_density; fcount += 1.f; } if (tN.magnitude()>EPS_S && _valid(tN)) normal.set(tN).normalize(); else clMsg("* ERROR: Internal precision error in CDeflector::OA_Export"); density /= fcount; // Orbitrary Oriented Ortho - Projection Fmatrix mView; Fvector at,from,up,right,y; at.set (0,0,0); from.add (at,normal); y.set (0,1,0); if (_abs(normal.y)>.99f) y.set(1,0,0); right.crossproduct(y,normal); right.normalize_safe(); up.crossproduct(normal,right); up.normalize_safe(); mView.build_camera(from,at,up); Fbox bb; bb.invalidate(); for (UVIt it = UVpolys.begin(); it!=UVpolys.end(); it++) { UVtri *T = &*it; Face *F = T->owner; Fvector P; // projected for (int i=0; i<3; i++) { mView.transform_tiny (P,F->v[i]->P); T->uv[i].set (P.x,P.y); bb.modify (F->v[i]->P); } } bb.getsphere(Sphere.P,Sphere.R); // UV rect Fvector2 min,max,size; GetRect (min,max); size.sub (max,min); // Surface u32 dwWidth = iCeil(size.x*g_params.m_lm_pixels_per_meter*density+.5f); clamp(dwWidth, 1u,512u-2*BORDER); u32 dwHeight = iCeil(size.y*g_params.m_lm_pixels_per_meter*density+.5f); clamp(dwHeight,1u,512u-2*BORDER); layer.create (dwWidth,dwHeight); }
void CActor::cam_Update(float dt, float fFOV) { if(m_holder) return; if(mstate_real & mcClimb&&cam_active!=eacFreeLook) camUpdateLadder(dt); Fvector point={0,CameraHeight(),0}, dangle={0,0,0}; Fmatrix xform,xformR; xform.setXYZ (0,r_torso.yaw,0); xform.translate_over(XFORM().c); // lookout if (this == Level().CurrentControlEntity()) { if (!fis_zero(r_torso_tgt_roll)){ Fvector src_pt,tgt_pt; float radius = point.y*0.5f; float alpha = r_torso_tgt_roll/2.f; float dZ = ((PI_DIV_2-((PI+alpha)/2))); calc_point (tgt_pt,radius,0,alpha); src_pt.set (0,tgt_pt.y,0); // init valid angle float valid_angle = alpha; // xform with roll xformR.setXYZ (-r_torso.pitch,r_torso.yaw,-dZ); Fmatrix33 mat; mat.i = xformR.i; mat.j = xformR.j; mat.k = xformR.k; // get viewport params float w,h; float c = viewport_near(w,h); w/=2.f;h/=2.f; // find tris Fbox box; box.invalidate (); box.modify (src_pt); box.modify (tgt_pt); box.grow (c); // query Fvector bc,bd ; Fbox xf ; xf.xform (box,xform) ; xf.get_CD (bc,bd) ; xrXRC xrc ; xrc.box_options (0) ; xrc.box_query (Level().ObjectSpace.GetStaticModel(), bc, bd) ; u32 tri_count = xrc.r_count(); if (tri_count) { float da = 0.f; BOOL bIntersect = FALSE; Fvector ext = {w,h,VIEWPORT_NEAR/2}; if (test_point(xrc,xform,mat,ext,radius,alpha)){ da = PI/1000.f; if (!fis_zero(r_torso.roll)) da *= r_torso.roll/_abs(r_torso.roll); float angle = 0.f; for (; _abs(angle)<_abs(alpha); angle+=da) if (test_point(xrc,xform,mat,ext,radius,angle)) { bIntersect=TRUE; break; } valid_angle = bIntersect?angle:alpha; } } r_torso.roll = valid_angle*2.f; r_torso_tgt_roll = r_torso.roll; } else { r_torso_tgt_roll = 0.f; r_torso.roll = 0.f; } } if (!fis_zero(r_torso.roll)) { float radius = point.y*0.5f; float valid_angle = r_torso.roll/2.f; calc_point (point,radius,0,valid_angle); dangle.z = (PI_DIV_2-((PI+valid_angle)/2)); } float flCurrentPlayerY = xform.c.y; // Smooth out stair step ups if ((character_physics_support()->movement()->Environment()==peOnGround) && (flCurrentPlayerY-fPrevCamPos>0)){ fPrevCamPos += dt*1.5f; if (fPrevCamPos > flCurrentPlayerY) fPrevCamPos = flCurrentPlayerY; if (flCurrentPlayerY-fPrevCamPos>0.2f) fPrevCamPos = flCurrentPlayerY-0.2f; point.y += fPrevCamPos-flCurrentPlayerY; }else{ fPrevCamPos = flCurrentPlayerY; } float _viewport_near = VIEWPORT_NEAR; // calc point xform.transform_tiny (point); CCameraBase* C = cam_Active(); if(eacFirstEye == cam_active) { // CCameraBase* C = cameras[eacFirstEye]; xrXRC xrc ; xrc.box_options (0) ; xrc.box_query (Level().ObjectSpace.GetStaticModel(), point, Fvector().set(VIEWPORT_NEAR,VIEWPORT_NEAR,VIEWPORT_NEAR) ); u32 tri_count = xrc.r_count(); if (tri_count) { _viewport_near = 0.01f; } else { xr_vector<ISpatial*> ISpatialResult; g_SpatialSpacePhysic->q_box(ISpatialResult, 0, STYPE_PHYSIC, point, Fvector().set(VIEWPORT_NEAR,VIEWPORT_NEAR,VIEWPORT_NEAR)); for (u32 o_it=0; o_it<ISpatialResult.size(); o_it++) { CPHShell* pCPHS= smart_cast<CPHShell*>(ISpatialResult[o_it]); if (pCPHS) { _viewport_near = 0.01f; break; } } } } /* { CCameraBase* C = cameras[eacFirstEye]; float oobox_size = 2*VIEWPORT_NEAR; Fmatrix _rot; _rot.k = C->vDirection; _rot.c = C->vPosition; _rot.i.crossproduct (C->vNormal, _rot.k); _rot.j.crossproduct (_rot.k, _rot.i); Fvector vbox; vbox.set (oobox_size, oobox_size, oobox_size); Level().debug_renderer().draw_aabb (C->vPosition, 0.05f, 0.051f, 0.05f, D3DCOLOR_XRGB(0,255,0)); Level().debug_renderer().draw_obb (_rot, Fvector().div(vbox,2.0f), D3DCOLOR_XRGB(255,0,0)); dMatrix3 d_rot; PHDynamicData::FMXtoDMX (_rot, d_rot); CPHActivationShape activation_shape; activation_shape.Create (point, vbox, this); dBodySetRotation (activation_shape.ODEBody(), d_rot); CPHCollideValidator::SetDynamicNotCollide(activation_shape); activation_shape.Activate (vbox,1,1.f,0.0F); point.set (activation_shape.Position()); activation_shape.Destroy (); } */ C->Update (point,dangle); C->f_fov = fFOV; if(eacFirstEye != cam_active) { cameras[eacFirstEye]->Update (point,dangle); cameras[eacFirstEye]->f_fov = fFOV; } if( psActorFlags.test(AF_PSP) ) { Cameras().Update (C); }else { Cameras().Update (cameras[eacFirstEye]); } fCurAVelocity = vPrevCamDir.sub(cameras[eacFirstEye]->vDirection).magnitude()/Device.fTimeDelta; vPrevCamDir = cameras[eacFirstEye]->vDirection; if (Level().CurrentEntity() == this) { Level().Cameras().Update (C); if(eacFirstEye == cam_active && !Level().Cameras().GetCamEffector(cefDemo)){ Cameras().ApplyDevice (_viewport_near); } } }
void CWallmarksEngine::AddWallmark_internal (CDB::TRI* pTri, const Fvector* pVerts, const Fvector &contact_point, ref_shader hShader, float sz) { // query for polygons in bounding box // calculate adjacency { Fbox bb_query; Fvector bbc,bbd; bb_query.set (contact_point,contact_point); bb_query.grow (sz*2.5f); bb_query.get_CD (bbc,bbd); xrc.box_options (CDB::OPT_FULL_TEST); xrc.box_query (g_pGameLevel->ObjectSpace.GetStaticModel(),bbc,bbd); u32 triCount = xrc.r_count (); if (0==triCount) return; CDB::TRI* tris = g_pGameLevel->ObjectSpace.GetStaticTris(); sml_collector.clear (); sml_collector.add_face_packed_D (pVerts[pTri->verts[0]],pVerts[pTri->verts[1]],pVerts[pTri->verts[2]],0); for (u32 t=0; t<triCount; t++) { CDB::TRI* T = tris+xrc.r_begin()[t].id; if (T==pTri) continue; sml_collector.add_face_packed_D (pVerts[T->verts[0]],pVerts[T->verts[1]],pVerts[T->verts[2]],0); } sml_collector.calc_adjacency (sml_adjacency); } // calc face normal Fvector N; N.mknormal (pVerts[pTri->verts[0]],pVerts[pTri->verts[1]],pVerts[pTri->verts[2]]); sml_normal.set (N); // build 3D ortho-frustum Fmatrix mView,mRot; BuildMatrix (mView,1/sz,contact_point); mRot.rotateZ (::Random.randF(deg2rad(-20.f),deg2rad(20.f))); mView.mulA_43 (mRot); sml_clipper.CreateFromMatrix (mView,FRUSTUM_P_LRTB); // create wallmark static_wallmark* W = static_wm_allocate(); RecurseTri (0,mView,*W); // calc sphere if (W->verts.size()<3) { static_wm_destroy(W); return; } else { Fbox bb; bb.invalidate(); FVF::LIT* I=&*W->verts.begin (); FVF::LIT* E=&*W->verts.end (); for (; I!=E; I++) bb.modify (I->p); bb.getsphere (W->bounds.P,W->bounds.R); } if (W->bounds.R < 1.f) { // search if similar wallmark exists wm_slot* slot = FindSlot (hShader); if (slot){ StaticWMVecIt it = slot->static_items.begin (); StaticWMVecIt end = slot->static_items.end (); for (; it!=end; it++) { static_wallmark* wm = *it; if (wm->bounds.P.similar(W->bounds.P,0.02f)){ // replace static_wm_destroy (wm); *it = W; return; } } } else { slot = AppendSlot(hShader); } // no similar - register _new_ slot->static_items.push_back(W); } }
void CBuild::xrPhase_Subdivide() { Status ("Subdividing in space..."); vecFace s1, s2; Fbox b1, b2; for (int X=0; X<int(g_XSplit.size()); X++) { if (g_XSplit[X]->empty()) { xr_delete (g_XSplit[X]); g_XSplit.erase (g_XSplit.begin()+X); X--; continue; } Progress (float(X)/float(g_XSplit.size())); // skip if subdivision is too small already if (int(g_XSplit[X]->size())<(c_SS_LowVertLimit*2)) continue; // calc bounding box Fbox bb; Fvector size; bb.invalidate(); for (vecFaceIt F=g_XSplit[X]->begin(); F!=g_XSplit[X]->end(); F++) { Face *XF = *F; bb.modify(XF->v[0]->P); bb.modify(XF->v[1]->P); bb.modify(XF->v[2]->P); } // analyze if we need to split size.sub(bb.max,bb.min); BOOL bSplit = FALSE; if (size.x>c_SS_maxsize) bSplit = TRUE; if (size.y>c_SS_maxsize) bSplit = TRUE; if (size.z>c_SS_maxsize) bSplit = TRUE; if (int(g_XSplit[X]->size()) > c_SS_HighVertLimit) bSplit = TRUE; CDeflector* defl_base = (CDeflector*)g_XSplit[X]->front()->pDeflector; if (!bSplit && defl_base) { if (defl_base->layer.width >= (c_LMAP_size-2*BORDER)) bSplit = TRUE; if (defl_base->layer.height >= (c_LMAP_size-2*BORDER)) bSplit = TRUE; } // perform subdivide if needed if (!bSplit) continue; // select longest BBox edge int box_edge = -1; if (size.x>=size.y && size.x>=size.z) { box_edge = 0; } else { if (size.y>=size.x && size.y>=size.z) { box_edge = 1; } else { box_edge = 2; } } setup_bbs (b1,b2,bb,box_edge); // align plane onto vertices // Process all faces and rearrange them u32 iteration_on_edge = 0 ; // up to 3 u32 iteration_per_edge = 0 ; // up to 10 resplit: s2.clear (); s1.clear (); iteration_per_edge ++ ; for (vecFaceIt F=g_XSplit[X]->begin(); F!=g_XSplit[X]->end(); F++) { Face *XF = *F; Fvector C; XF->CalcCenter(C); if (b1.contains(C)) { s1.push_back(XF); } else { s2.push_back(XF); } } if ((int(s1.size())<c_SS_LowVertLimit) || (int(s2.size())<c_SS_LowVertLimit)) { // splitting failed clMsg ("! ERROR: model #%d - split fail, faces: %d, s1/s2:%d/%d",X,g_XSplit[X]->size(),s1.size(),s2.size()); if (iteration_per_edge<10) { if (g_XSplit[X]->size() > c_SS_LowVertLimit*4) { if (s2.size()>s1.size()) { //b2 -less, b1-grow size.sub (b2.max,b2.min); b1.max[box_edge] += size[box_edge]/2; b2.min[box_edge] = b1.max[box_edge]; } else { //b2 -grow, b1-less size.sub (b1.max,b1.min); b2.min[box_edge] -= size[box_edge]/2; b1.max[box_edge] = b2.min[box_edge]; } goto resplit; } } else { // switch edge iteration_per_edge = 0 ; iteration_on_edge ++ ; if (iteration_on_edge<3) { box_edge = (box_edge+1)%3; setup_bbs (b1,b2,bb,box_edge); goto resplit; } } } else { // split deflector into TWO if (defl_base) { // _delete old deflector for (u32 it=0; it<lc_global_data()->g_deflectors().size(); it++) { if (lc_global_data()->g_deflectors()[it]==defl_base) { lc_global_data()->g_deflectors().erase (lc_global_data()->g_deflectors().begin()+it); xr_delete (defl_base); break; } } // Create _new deflectors CDeflector* D1 = new CDeflector(); D1->OA_Place(s1); D1->OA_Export(); lc_global_data()->g_deflectors().push_back(D1); CDeflector* D2 = new CDeflector(); D2->OA_Place(s2); D2->OA_Export(); lc_global_data()->g_deflectors().push_back(D2); } // Delete old SPLIT and push two new xr_delete (g_XSplit[X]); g_XSplit.erase (g_XSplit.begin()+X); X--; g_XSplit.push_back (new vecFace(s1)); Detach(&s1); g_XSplit.push_back (new vecFace(s2)); Detach(&s2); } s1.clear (); s2.clear (); } clMsg("%d subdivisions.",g_XSplit.size()); validate_splits (); }
void CBuild::BuildCForm () { Phase ("CFORM: construction..."); //Status ("Building base mesh : vertices..."); _mesh mesh; // a mesh object _decimater decimater(mesh); // a decimater object, connected to a mesh _HModQuadric hModQuadric; // use a quadric module decimater.add (hModQuadric); // register module at the decimater decimater.module(hModQuadric).set_max_err (0.0001,false); // error-limit 0.0001 // Initializing mesh Status ("Building base mesh : vertices[%d]...",g_vertices.size()); for (vecVertexIt _v=g_vertices.begin(); _v!=g_vertices.end(); _v++) (*_v)->handle = _mesh::InvalidVertexHandle.idx(); Status ("Building base mesh : base faces[%d]...",g_faces.size()); std::vector <_mesh::VertexHandle> fhandles; xr_vector <cform_FailFace> failedfaces; cform_mergeprops fmergeprops; for (vecFaceIt I=g_faces.begin(); I!=g_faces.end(); I++) { Progress (float(I-g_faces.begin())/float(g_faces.size())); Face* F = *I; if (F->Shader().flags.bCollision) { // test correctness TestEdge (F->v[0],F->v[1],F); TestEdge (F->v[1],F->v[2],F); TestEdge (F->v[2],F->v[0],F); // add vertices fhandles.clear (); for (u32 v=0; v<3; v++) { _mesh::VertexHandle h = _mesh::VertexHandle(F->v[v]->handle); if (_mesh::InvalidVertexHandle == h) { Fvector& p = F->v[v]->P; h = mesh.add_vertex (_mesh::Point(p.x,p.y,p.z)); F->v[v]->handle = h.idx(); } fhandles.push_back (h); } // add face fmergeprops.material = F->dwMaterialGame; fmergeprops.sector = materials[F->dwMaterial].sector; _mesh::FaceHandle hface = mesh.add_face (fhandles); if (hface == _mesh::InvalidFaceHandle) { failedfaces.push_back (cform_FailFace()); failedfaces.back().P[0] = F->v[0]->P; failedfaces.back().P[1] = F->v[1]->P; failedfaces.back().P[2] = F->v[2]->P; failedfaces.back().props = fmergeprops.props; } else mesh.face(hface).set_props (fmergeprops.props); } } if (bCriticalErrCnt) { err_save (); clMsg ("MultipleEdges: %d faces",bCriticalErrCnt); } Status ("Building base mesh : models[%d]...",mu_refs.size()); mesh.garbage_collection (); for (u32 ref=0; ref<mu_refs.size(); ref++) mu_refs[ref]->export_cform_game(mesh,failedfaces); Status ("Building base mesh : normals..."); mesh.garbage_collection (); mesh.request_vertex_normals (); mesh.update_vertex_normals (); // Decimate Status ("Reconstructing mesh-topology..."); clMsg ("%d faces failed topology check", failedfaces.size()); clMsg ("%f%% geometry/artist quality", 100.f * (1-float(failedfaces.size())/float(mesh.n_faces()))); decimater.initialize (); // let the decimater initialize the mesh and the modules int nf_before = int (mesh.n_faces()); int nv_before = int (mesh.n_vertices()); int nc = decimater.decimate (nv_before); // do decimation, as large, as possible mesh.garbage_collection (); int nf_after = int (mesh.n_faces()); int nv_after = int (mesh.n_vertices()); clMsg ("vertices: was[%d], now[%d] => %f %% left",nv_before,nv_after, 100.f*float(nv_after)/float(nv_before) ); clMsg (" faces: was[%d], now[%d] => %f %% left",nf_before,nf_after, 100.f*float(nf_after)/float(nf_before) ); // Decimate Status ("Refactoring CFORM..."); Fbox BB; BB.invalidate(); _mesh::VertexIter vit =mesh.vertices_begin(),vend=mesh.vertices_end(); for (; vit!=vend; ++vit) BB.modify( reinterpret_cast<Fvector&>(mesh.point(vit)) ); CDB::CollectorPacked CL(BB,mesh.n_vertices(),mesh.n_faces()); _mesh::FaceIter fit=mesh.faces_begin(),fend=mesh.faces_end(); for (; fit!=fend; ++fit){ // get vertex-handles fhandles.clear (); for (_mesh::CFVIter fv_it=mesh.cfv_iter(fit); fv_it; ++fv_it) fhandles.push_back (fv_it.handle()); CL.add_face_D ( reinterpret_cast<Fvector&>(mesh.point (fhandles[0])), reinterpret_cast<Fvector&>(mesh.point (fhandles[1])), reinterpret_cast<Fvector&>(mesh.point (fhandles[2])), fit->props () ); } Status ("Restoring fail-faces..."); for (u32 it=0; it<failedfaces.size(); it++) { cform_FailFace& F = failedfaces[it]; CL.add_face_D ( F.P[0], F.P[1], F.P[2], F.props ); } // Saving Status ("Saving..."); nf_after = int (CL.getTS()); nv_after = int (CL.getVS()); clMsg ("vertices: was[%d], now[%d] => %f %% left",nv_before,nv_after, 100.f*float(nv_after)/float(nv_before) ); clMsg (" faces: was[%d], now[%d] => %f %% left",nf_before,nf_after, 100.f*float(nf_after)/float(nf_before) ); string512 fn; IWriter* MFS = FS.w_open (strconcat(fn,pBuild->path,"level.cform")); // Header hdrCFORM hdr; hdr.version = CFORM_CURRENT_VERSION; hdr.vertcount = (u32)CL.getVS(); hdr.facecount = (u32)CL.getTS(); hdr.aabb = BB; MFS->w (&hdr,sizeof(hdr)); // Data MFS->w (CL.getV(),(u32)CL.getVS()*sizeof(Fvector)); MFS->w (CL.getT(),(u32)CL.getTS()*sizeof(CDB::TRI)); // Clear pDeflector (it is stored in the same memory space with dwMaterialGame) for (vecFaceIt I=g_faces.begin(); I!=g_faces.end(); I++) { Face* F = *I; F->pDeflector = NULL; } FS.w_close (MFS); }
void GetBox( Fbox& box, const Fvector *verts, u32 cnt ) { box.invalidate(); for( u32 i = 0; i < cnt; ++i ) box.modify( verts[i] ); }
void xrMU_Model::export_geometry () { // Declarator VDeclarator D; D.set (decl); // RT-check, BOX, low-point, frac-size Fbox BB; BB.invalidate (); for (v_vertices_it vit=m_vertices.begin(); vit!=m_vertices.end(); vit++) BB.modify ((*vit)->P); Fvector frac_low; float frac_Ysize; BB.getcenter (frac_low); frac_low.y = BB.min.y; frac_Ysize = BB.max.y - BB.min.y; // Begin building for (v_subdivs_it it=m_subdivs.begin(); it!=m_subdivs.end(); it++) { // Vertices { g_VB.Begin (D); vecOGF_V& verts = it->ogf->vertices; for (u32 v_it=0; v_it<verts.size(); v_it++) { OGF_Vertex& oV = verts[v_it]; // Position g_VB.Add (&oV.P,3*sizeof(float)); // Normal { base_color_c oV_c; oV.Color._get(oV_c); Fvector N = oV.N; N.add (1.f); N.mul (.5f*255.f); s32 nx = iFloor(N.x); clamp(nx,0,255); s32 ny = iFloor(N.y); clamp(ny,0,255); s32 nz = iFloor(N.z); clamp(nz,0,255); s32 cc = iFloor(oV_c.hemi*255.f); clamp(cc,0,255); u32 uN = color_rgba(nx,ny,nz,cc); g_VB.Add (&uN,4); } // Tangent { u32 uT = color_rgba(oV.T.x,oV.T.y,oV.T.z,0); g_VB.Add (&uT,4); } // Binormal { u32 uB = color_rgba(oV.B.x,oV.B.y,oV.B.z,0); g_VB.Add (&uB,4); } // TC s16 tu,tv,frac,dummy; tu = QC(oV.UV.begin()->x); tv = QC(oV.UV.begin()->y); g_VB.Add (&tu,2); g_VB.Add (&tv,2); // frac float f1 = (oV.P.y - frac_low.y) /frac_Ysize; float f2 = oV.P.distance_to(frac_low)/frac_Ysize; frac = QC((f1+f2)/2.f); dummy = 0; g_VB.Add (&frac, 2); g_VB.Add (&dummy,2); } g_VB.End (&it->vb_id,&it->vb_start); } // Indices g_IB.Register (LPWORD(&*it->ogf->faces.begin()),LPWORD(&*it->ogf->faces.end()),&it->ib_id,&it->ib_start); // SW if (it->ogf->progressive_test()) g_SWI.Register (&it->sw_id,&it->ogf->m_SWI); } }