void _prim (DWORD prim) { if (bClass3) { sPoly src,dst; src.resize (3); src[0] = verts[ tris[prim].verts[0] ]; src[1] = verts[ tris[prim].verts[1] ]; src[2] = verts[ tris[prim].verts[2] ]; if (F->ClipPoly(src,dst)) { RESULT& R = dest->r_add(); R.id = prim; R.verts[0] = verts[ tris[prim].verts[0] ]; R.verts[1] = verts[ tris[prim].verts[1] ]; R.verts[2] = verts[ tris[prim].verts[2] ]; R.dummy = tris[prim].dummy; } } else { RESULT& R = dest->r_add(); R.id = prim; R.verts[0] = verts[ tris[prim].verts[0] ]; R.verts[1] = verts[ tris[prim].verts[1] ]; R.verts[2] = verts[ tris[prim].verts[2] ]; R.dummy = tris[prim].dummy; } }
void EDetailManager::UpdateSlotBBox(int sx, int sz, DetailSlot& slot) { Fbox bbox; Frect rect; GetSlotRect (rect,sx,sz); bbox.min.set (rect.x1, m_BBox.min.y, rect.y1); bbox.max.set (rect.x2, m_BBox.max.y, rect.y2); SBoxPickInfoVec pinf; ETOOLS::box_options(0); if (Scene->BoxPickObjects(bbox,pinf,&m_SnapObjects)){ bbox.grow (EPS_L_VAR); Fplane frustum_planes[4]; frustum_planes[0].build(bbox.min,left_vec); frustum_planes[1].build(bbox.min,back_vec); frustum_planes[2].build(bbox.max,right_vec); frustum_planes[3].build(bbox.max,fwd_vec); CFrustum frustum; frustum.CreateFromPlanes(frustum_planes,4); float y_min = flt_max; float y_max = flt_min; for (SBoxPickInfoIt it=pinf.begin(); it!=pinf.end(); it++){ for (int k=0; k<(int)it->inf.size(); k++){ float range; Fvector verts[3]; it->e_obj->GetFaceWorld(it->s_obj->_Transform(),it->e_mesh,it->inf[k].id,verts); sPoly sSrc (verts,3); sPoly sDest; sPoly* sRes = frustum.ClipPoly(sSrc, sDest); if (sRes){ for (u32 k=0; k<sRes->size(); k++){ float H = (*sRes)[k].y; if (H>y_max) y_max = H+0.03f; if (H<y_min) y_min = H-0.03f; } slot.w_y (y_min,y_max-y_min); slot.w_id(0,DetailSlot::ID_Empty); slot.w_id(1,DetailSlot::ID_Empty); slot.w_id(2,DetailSlot::ID_Empty); slot.w_id(3,DetailSlot::ID_Empty); } } } }else{ ZeroMemory(&slot,sizeof(DetailSlot)); slot.w_id(0,DetailSlot::ID_Empty); slot.w_id(1,DetailSlot::ID_Empty); slot.w_id(2,DetailSlot::ID_Empty); slot.w_id(3,DetailSlot::ID_Empty); } }
BOOL CFrustum::CreateFromClipPoly(Fvector* p, int count, Fvector& vBase, CFrustum& clip) { VERIFY(count<FRUSTUM_MAXPLANES); VERIFY(count>=3); sPoly poly1 (p,count); sPoly poly2; sPoly* dest = clip.ClipPoly(poly1,poly2); // here we end up with complete frustum-polygon in 'dest' if (0==dest) return false; CreateFromPoints(dest->begin(),dest->size(),vBase); return true; }
void CLightShadows::render () { // Gain access to collision-DB CDB::MODEL* DB = g_pGameLevel->ObjectSpace.GetStaticModel(); CDB::TRI* TRIS = DB->get_tris(); Fvector* VERTS = DB->get_verts(); int slot_line = S_rt_size/S_size; // Projection and xform float _43 = Device.mProject._43; Device.mProject._43 -= 0.002f; RCache.set_xform_world (Fidentity); RCache.set_xform_project (Device.mProject); Fvector View = Device.vCameraPosition; // Render shadows RCache.set_Shader (sh_World); RCache.set_Geometry (geom_World); int batch = 0; u32 Offset = 0; FVF::LIT* pv = (FVF::LIT*) RCache.Vertex.Lock (batch_size*3,geom_World->vb_stride,Offset); for (u32 s_it=0; s_it<shadows.size(); s_it++) { Device.Statistic->RenderDUMP_Srender.Begin (); shadow& S = shadows[s_it]; float Le = S.L->color.intensity()*S.E; int s_x = S.slot%slot_line; int s_y = S.slot/slot_line; Fvector2 t_scale, t_offset; t_scale.set (float(S_size)/float(S_rt_size),float(S_size)/float(S_rt_size)); t_scale.mul (.5f); t_offset.set(float(s_x)/float(slot_line),float(s_y)/float(slot_line)); t_offset.x += .5f/S_rt_size; t_offset.y += .5f/S_rt_size; // Search the cache cache_item* CI = 0; BOOL bValid = FALSE; cache_item CI_what; CI_what.O = S.O; CI_what.L = S.L; CI_what.tris=0; xr_vector<cache_item>::iterator CI_ptr = std::lower_bound(cache.begin(),cache.end(),CI_what,cache_search); if (CI_ptr==cache.end()) { // empty ? CI_ptr = cache.insert (CI_ptr,CI_what); CI = &*CI_ptr; bValid = FALSE; } else { if (CI_ptr->O != CI_what.O || CI_ptr->L != CI_what.L) { // we found something different CI_ptr = cache.insert (CI_ptr,CI_what); CI = &*CI_ptr; bValid = FALSE; } else { // Everything, OK. Check if info is still relevant... CI = &*CI_ptr; bValid = TRUE; if (!CI->Op.similar(CI->O->renderable.xform.c)) bValid = FALSE; else if (!CI->Lp.similar(CI->L->position)) bValid = FALSE; } } CI->time = Device.dwTimeGlobal; // acess time if (!bValid) { // Frustum CFrustum F; F.CreateFromMatrix (S.M,FRUSTUM_P_ALL); // Query xrc.frustum_options (0); xrc.frustum_query (DB,F); if (0==xrc.r_count()) continue; // Clip polys by frustum tess.clear (); for (CDB::RESULT* p = xrc.r_begin(); p!=xrc.r_end(); p++) { VERIFY((p->id>=0)&&(p->id<DB->get_tris_count())); // CDB::TRI& t = TRIS[p->id]; if (t.suppress_shadows) continue; sPoly A,B; A.push_back (VERTS[t.verts[0]]); A.push_back (VERTS[t.verts[1]]); A.push_back (VERTS[t.verts[2]]); // Calc plane, throw away degenerate tris and invisible to light polygons Fplane P; float mag = 0; Fvector t1,t2,n; t1.sub (A[0],A[1]); t2.sub (A[0],A[2]); n.crossproduct (t1,t2); mag = n.square_magnitude(); if (mag<EPS_S) continue; n.mul (1.f/_sqrt(mag)); P.build_unit_normal (A[0],n); float DOT_Fade = P.classify(S.L->position); if (DOT_Fade<0) continue; // Clip polygon sPoly* clip = F.ClipPoly (A,B); if (0==clip) continue; // Triangulate poly for (u32 v=2; v<clip->size(); v++) { tess.push_back (tess_tri()); tess_tri& T = tess.back(); T.v[0] = (*clip)[0]; T.v[1] = (*clip)[v-1]; T.v[2] = (*clip)[v]; T.N = P.n; } } // Remember params which builded cache item CI->O = S.O; CI->Op = CI->O->renderable.xform.c; CI->L = S.L; CI->Lp = CI->L->position; CI->tcnt = tess.size(); //Msg ("---free--- %x",u32(CI->tris)); xr_free (CI->tris); VERIFY(0==CI->tris); if (tess.size()) { CI->tris = xr_alloc<tess_tri>(CI->tcnt); //Msg ("---alloc--- %x",u32(CI->tris)); CopyMemory (CI->tris,&*tess.begin(),CI->tcnt * sizeof(tess_tri)); } } // Fill VB for (u32 tid=0; tid<CI->tcnt; tid++) { tess_tri& TT = CI->tris[tid]; Fvector* v = TT.v; Fvector T; Fplane ttp; ttp.build_unit_normal(v[0],TT.N); if (ttp.classify(View)<0) continue; int c0 = PLC_calc(v[0],TT.N,S.L,Le,S.C); int c1 = PLC_calc(v[1],TT.N,S.L,Le,S.C); int c2 = PLC_calc(v[2],TT.N,S.L,Le,S.C); if (c0>S_clip && c1>S_clip && c2>S_clip) continue; clamp (c0,S_ambient,255); clamp (c1,S_ambient,255); clamp (c2,S_ambient,255); S.M.transform(T,v[0]); pv->set(v[0],CLS(c0),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++; S.M.transform(T,v[1]); pv->set(v[1],CLS(c1),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++; S.M.transform(T,v[2]); pv->set(v[2],CLS(c2),(T.x+1)*t_scale.x+t_offset.x,(1-T.y)*t_scale.y+t_offset.y); pv++; batch++; if (batch==batch_size) { // Flush RCache.Vertex.Unlock (batch*3,geom_World->vb_stride); RCache.Render (D3DPT_TRIANGLELIST,Offset,batch); pv = (FVF::LIT*) RCache.Vertex.Lock(batch_size*3,geom_World->vb_stride,Offset); batch = 0; } } Device.Statistic->RenderDUMP_Srender.End (); } // Flush if nessesary RCache.Vertex.Unlock (batch*3,geom_World->vb_stride); if (batch) { RCache.Render (D3DPT_TRIANGLELIST,Offset,batch); } // Clear all shadows and free old entries in the cache shadows.clear (); for (int cit=0; cit<int(cache.size()); cit++) { cache_item& ci = cache[cit]; u32 time = Device.dwTimeGlobal - ci.time; if (time > cache_old) { //Msg ("---free--- %x",u32(ci.tris)); xr_free (ci.tris); VERIFY(0==ci.tris); cache.erase (cache.begin()+cit); cit --; } } // Projection Device.mProject._43 = _43; RCache.set_xform_project (Device.mProject); }
void CSector::traverse (CFrustum &F, _scissor& R_scissor) { // Register traversal process if (r_marker != PortalTraverser.i_marker) { r_marker = PortalTraverser.i_marker; PortalTraverser.r_sectors.push_back (this); r_frustums.clear (); r_scissors.clear (); } r_frustums.push_back (F); r_scissors.push_back (R_scissor); // Search visible portals and go through them sPoly S,D; for (u32 I=0; I<m_portals.size(); I++) { if (m_portals[I]->marker == PortalTraverser.i_marker) continue; CPortal* PORTAL = m_portals[I]; CSector* pSector; // Select sector (allow intersecting portals to be finely classified) if (PORTAL->bDualRender) { pSector = PORTAL->getSector (this); } else { pSector = PORTAL->getSectorBack (PortalTraverser.i_vBase); if (pSector==this) continue; if (pSector==PortalTraverser.i_start) continue; } // Early-out sphere if (!F.testSphere_dirty(PORTAL->S.P,PORTAL->S.R)) continue; // SSA (if required) if (PortalTraverser.i_options&CPortalTraverser::VQ_SSA) { Fvector dir2portal; dir2portal.sub (PORTAL->S.P, PortalTraverser.i_vBase); float R = PORTAL->S.R ; float distSQ = dir2portal.square_magnitude(); float ssa = R*R/distSQ; dir2portal.div (_sqrt(distSQ)); ssa *= _abs(PORTAL->P.n.dotproduct(dir2portal)); if (ssa<r_ssaDISCARD) continue; if (PortalTraverser.i_options&CPortalTraverser::VQ_FADE) { if (ssa<r_ssaLOD_A) PortalTraverser.fade_portal (PORTAL,ssa); if (ssa<r_ssaLOD_B) continue ; } } // Clip by frustum svector<Fvector,8>& POLY = PORTAL->getPoly(); S.assign (&*POLY.begin(),POLY.size()); D.clear(); sPoly* P = F.ClipPoly(S,D); if (0==P) continue; // Scissor and optimized HOM-testing _scissor scissor ; if (PortalTraverser.i_options&CPortalTraverser::VQ_SCISSOR && (!PORTAL->bDualRender)) { // Build scissor rectangle in projection-space Fbox2 bb; bb.invalidate(); float depth = flt_max; sPoly& p = *P; for (u32 vit=0; vit<p.size(); vit++) { Fvector4 t; Fmatrix& M = PortalTraverser.i_mXFORM_01; Fvector& v = p[vit]; t.x = v.x*M._11 + v.y*M._21 + v.z*M._31 + M._41; t.y = v.x*M._12 + v.y*M._22 + v.z*M._32 + M._42; t.z = v.x*M._13 + v.y*M._23 + v.z*M._33 + M._43; t.w = v.x*M._14 + v.y*M._24 + v.z*M._34 + M._44; t.mul (1.f/t.w); if (t.x < bb.min.x) bb.min.x = t.x; if (t.x > bb.max.x) bb.max.x = t.x; if (t.y < bb.min.y) bb.min.y = t.y; if (t.y > bb.max.y) bb.max.y = t.y; if (t.z < depth) depth = t.z; } // Msg ("bb(%s): (%f,%f)-(%f,%f), d=%f", PORTAL->bDualRender?"true":"false",bb.min.x, bb.min.y, bb.max.x, bb.max.y,depth); if (depth<EPS) { scissor = R_scissor; // Cull by HOM (slower algo) if ( (PortalTraverser.i_options&CPortalTraverser::VQ_HOM) && (!RImplementation.HOM.visible(*P)) ) continue; } else { // perform intersection (this is just to be sure, it is probably clipped in 3D already) if (bb.min.x > R_scissor.min.x) scissor.min.x = bb.min.x; else scissor.min.x = R_scissor.min.x; if (bb.min.y > R_scissor.min.y) scissor.min.y = bb.min.y; else scissor.min.y = R_scissor.min.y; if (bb.max.x < R_scissor.max.x) scissor.max.x = bb.max.x; else scissor.max.x = R_scissor.max.x; if (bb.max.y < R_scissor.max.y) scissor.max.y = bb.max.y; else scissor.max.y = R_scissor.max.y; scissor.depth = depth; // Msg ("scissor: (%f,%f)-(%f,%f)", scissor.min.x, scissor.min.y, scissor.max.x, scissor.max.y); // Check if box is non-empty if (scissor.min.x >= scissor.max.x) continue; if (scissor.min.y >= scissor.max.y) continue; // Cull by HOM (faster algo) if ( (PortalTraverser.i_options&CPortalTraverser::VQ_HOM) && (!RImplementation.HOM.visible(scissor,depth)) ) continue; } } else { scissor = R_scissor; // Cull by HOM (slower algo) if ( (PortalTraverser.i_options&CPortalTraverser::VQ_HOM) && (!RImplementation.HOM.visible(*P)) ) continue; } // Create _new_ frustum and recurse CFrustum Clip; Clip.CreateFromPortal (P, PORTAL->P.n, PortalTraverser.i_vBase,PortalTraverser.i_mXFORM); PORTAL->marker = PortalTraverser.i_marker; PORTAL->bDualRender = FALSE; pSector->traverse (Clip,scissor); } }
void CHOM::Render_DB (CFrustum& base) { //Update projection matrices on every frame to ensure valid HOM culling float view_dim = occ_dim_0; Fmatrix m_viewport = { view_dim/2.f, 0.0f, 0.0f, 0.0f, 0.0f, -view_dim/2.f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, view_dim/2.f + 0 + 0, view_dim/2.f + 0 + 0, 0.0f, 1.0f }; Fmatrix m_viewport_01 = { 1.f/2.f, 0.0f, 0.0f, 0.0f, 0.0f, -1.f/2.f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.f/2.f + 0 + 0, 1.f/2.f + 0 + 0, 0.0f, 1.0f }; m_xform.mul (m_viewport, Device.mFullTransform); m_xform_01.mul (m_viewport_01, Device.mFullTransform); // Query DB xrc.frustum_options (0); xrc.frustum_query (m_pModel,base); if (0==xrc.r_count()) return; // Prepare CDB::RESULT* it = xrc.r_begin (); CDB::RESULT* end = xrc.r_end (); Fvector COP = Device.vCameraPosition; end = std::remove_if (it,end,pred_fb(m_pTris)); std::sort (it,end,pred_fb(m_pTris,COP)); // Build frustum with near plane only CFrustum clip; clip.CreateFromMatrix (Device.mFullTransform,FRUSTUM_P_NEAR); sPoly src,dst; u32 _frame = Device.dwFrame ; #ifdef DEBUG tris_in_frame = xrc.r_count(); tris_in_frame_visible = 0; #endif // Perfrom selection, sorting, culling for (; it!=end; it++) { // Control skipping occTri& T = m_pTris [it->id]; u32 next = _frame + ::Random.randI(3,10); // Test for good occluder - should be improved :) if (!(T.flags || (T.plane.classify(COP)>0))) { T.skip=next; continue; } // Access to triangle vertices CDB::TRI& t = m_pModel->get_tris() [it->id]; Fvector* v = m_pModel->get_verts(); src.clear (); dst.clear (); src.push_back (v[t.verts[0]]); src.push_back (v[t.verts[1]]); src.push_back (v[t.verts[2]]); sPoly* P = clip.ClipPoly (src,dst); if (0==P) { T.skip=next; continue; } // XForm and Rasterize #ifdef DEBUG tris_in_frame_visible ++; #endif u32 pixels = 0; int limit = int(P->size())-1; for (int v=1; v<limit; v++) { m_xform.transform (T.raster[0],(*P)[0]); m_xform.transform (T.raster[1],(*P)[v+0]); m_xform.transform (T.raster[2],(*P)[v+1]); pixels += Raster.rasterize(&T); } if (0==pixels) { T.skip=next; continue; } } }