void ESceneLightTools::SelectLightsForObject(CCustomObject* obj) { for (u32 i=0; i<frame_light.size(); i++){ CLight* l = frame_light[i]; // if (obj->IsDynamic()&&!l->m_Flags.is(CLight::flAffectDynamic)) continue; // if (!obj->IsDynamic()&&!l->m_Flags.is(CLight::flAffectStatic)) continue; Fbox bb; obj->GetBox(bb); Fvector C; float R; bb.getsphere(C,R); float d = C.distance_to(l->PPosition) - l->m_Range - R; Device.LightEnable(i,(d<0)); } }
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); } } }
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 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 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); } }