void CBuild::Light() { //****************************************** Implicit { FPU::m64r (); Phase ("LIGHT: Implicit..."); mem_Compact (); ImplicitLighting(); } //****************************************** Lmaps { FPU::m64r (); Phase ("LIGHT: LMaps..."); mem_Compact (); // Randomize deflectors std::random_shuffle (g_deflectors.begin(),g_deflectors.end()); for (u32 dit = 0; dit<g_deflectors.size(); dit++) task_pool.push_back(dit); // Main process (4 threads) Status ("Lighting..."); CThreadManager threads; const u32 thNUM = 6; CTimer start_time; start_time.Start(); for (int L=0; L<thNUM; L++) threads.start(xr_new<CLMThread> (L)); threads.wait (500); clMsg ("%f seconds",start_time.GetElapsed_sec()); } //****************************************** Vertex FPU::m64r (); Phase ("LIGHT: Vertex..."); mem_Compact (); LightVertex (); //****************************************** Merge LMAPS { FPU::m64r (); Phase ("LIGHT: Merging lightmaps..."); mem_Compact (); xrPhase_MergeLM (); } }
void CBuild::SaveTREE (IWriter &fs) { CMemoryWriter MFS; Status ("Geometry buffers..."); xr_vector<u32> remap; remap.reserve (g_tree.size()); for (u32 rid=0; rid<g_tree.size(); rid++) { OGF* o = dynamic_cast<OGF*> (g_tree[rid]); if (o) remap.push_back(rid); } std::stable_sort (remap.begin(),remap.end(),remap_order); clMsg ("remap-size: %d / %d",remap.size(),g_tree.size()); for (u32 sid=0; sid<remap.size(); sid++) { u32 id = remap[sid]; //clMsg ("%3d: subdiv: %d",sid,id); g_tree[id]->PreSave (id); } Status ("Visuals..."); fs.open_chunk (fsL_VISUALS); for (xr_vector<OGF_Base*>::iterator it = g_tree.begin(); it!=g_tree.end(); it++) { u32 idx = u32(it-g_tree.begin()); MFS.open_chunk (idx); (*it)->Save (MFS); MFS.close_chunk (); Progress (float(idx)/float(g_tree.size())); } fs.w (MFS.pointer(),MFS.size()); fs.close_chunk (); clMsg ("Average: %d verts/%d faces, 50(%2.1f), 100(%2.1f), 500(%2.1f), 1000(%2.1f), 5000(%2.1f)", g_batch_verts/g_batch_count, g_batch_faces/g_batch_count, 100.f * float(g_batch_50)/float(g_batch_count), 100.f * float(g_batch_100)/float(g_batch_count), 100.f * float(g_batch_500)/float(g_batch_count), 100.f * float(g_batch_1000)/float(g_batch_count), 100.f * float(g_batch_5000)/float(g_batch_count) ); mem_Compact (); SaveGEOMs ("level.geom", g_VB,g_IB,g_SWI); // Normal SaveGEOMs ("level.geomx", x_VB,x_IB,x_SWI); // Fast-Path Status ("Shader table..."); fs.open_chunk (fsL_SHADERS); fs.w_u32 (g_Shaders.size()); for (xr_vector<LPCSTR>::iterator T=g_Shaders.begin(); T!=g_Shaders.end(); T++) fs.w_stringZ (*T); fs.close_chunk (); //mem_Compact (); }
void CBuild::mem_CompactSubdivs() { // Memory compact CTimer dwT; dwT.Start(); vecFace temp; for (int SP = 0; SP<int(g_XSplit.size()); SP++) { temp.clear (); temp.assign (g_XSplit[SP]->begin(),g_XSplit[SP]->end()); xr_delete (g_XSplit[SP]); mem_Compact (); g_XSplit[SP] = xr_new<vecFace> (); g_XSplit[SP]->assign(temp.begin(),temp.end()); } clMsg ("%d ms for memory compacting...",dwT.GetElapsed_ms()); }
void CBuild::PreOptimize() { // We use overlapping hash table to avoid boundary conflicts vecVertex* HASH [HDIM_X+1][HDIM_Y+1][HDIM_Z+1]; Fvector VMmin, VMscale, VMeps, scale; // Calculate offset,scale,epsilon Fbox bb = scene_bb; VMscale.set (bb.max.x-bb.min.x, bb.max.y-bb.min.y, bb.max.z-bb.min.z); VMmin.set (bb.min); VMeps.set (VMscale.x/HDIM_X/2,VMscale.y/HDIM_Y/2,VMscale.z/HDIM_Z/2); VMeps.x = (VMeps.x<EPS_L)?VMeps.x:EPS_L; VMeps.y = (VMeps.y<EPS_L)?VMeps.y:EPS_L; VMeps.z = (VMeps.z<EPS_L)?VMeps.z:EPS_L; scale.set (float(HDIM_X),float(HDIM_Y),float(HDIM_Z)); scale.div (VMscale); u32 Vcount = lc_global_data()->g_vertices().size(), Vremoved=0; u32 Fcount = lc_global_data()->g_faces().size(), Fremoved=0; // Pre-alloc memory int _size = (HDIM_X+1)*(HDIM_Y+1)*(HDIM_Z+1); int _average= (Vcount/_size)/2; if (_average<2) _average = 2; { for (int ix=0; ix<HDIM_X+1; ix++) for (int iy=0; iy<HDIM_Y+1; iy++) for (int iz=0; iz<HDIM_Z+1; iz++) { HASH[ix][iy][iz] = new vecVertex(); HASH[ix][iy][iz]->reserve (_average); } } // Status("Processing..."); g_bUnregister = false; for (int it = 0; it<(int)lc_global_data()->g_vertices().size(); it++) { if (0==(it%100000)) { Progress(_sqrt(float(it)/float(lc_global_data()->g_vertices().size()))); Status ("Processing... (%d verts removed)",Vremoved); } if (it>=(int)lc_global_data()->g_vertices().size()) break; Vertex *pTest = lc_global_data()->g_vertices()[it]; Fvector &V = pTest->P; // Hash u32 ix,iy,iz; ix = iFloor ((V.x-VMmin.x)*scale.x); iy = iFloor ((V.y-VMmin.y)*scale.y); iz = iFloor ((V.z-VMmin.z)*scale.z); R_ASSERT (ix<=HDIM_X && iy<=HDIM_Y && iz<=HDIM_Z); vecVertex &H = *(HASH[ix][iy][iz]); // Search similar vertices in hash table for (vecVertexIt T=H.begin(); T!=H.end(); T++) { Vertex *pBase = *T; if (pBase->similar(*pTest,g_params().m_weld_distance)) { while(pTest->m_adjacents.size()) pTest->m_adjacents.front()->VReplace(pTest, pBase); lc_global_data()->destroy_vertex(lc_global_data()->g_vertices()[it]); Vremoved += 1; pTest = NULL; break; } } // If we get here - there is no similar vertices - register in hash tables if (pTest) { H.push_back (pTest); u32 ixE,iyE,izE; ixE = iFloor((V.x+VMeps.x-VMmin.x)*scale.x); iyE = iFloor((V.y+VMeps.y-VMmin.y)*scale.y); izE = iFloor((V.z+VMeps.z-VMmin.z)*scale.z); R_ASSERT(ixE<=HDIM_X && iyE<=HDIM_Y && izE<=HDIM_Z); if (ixE!=ix) HASH[ixE][iy][iz]->push_back (pTest); if (iyE!=iy) HASH[ix][iyE][iz]->push_back (pTest); if (izE!=iz) HASH[ix][iy][izE]->push_back (pTest); if ((ixE!=ix)&&(iyE!=iy)) HASH[ixE][iyE][iz]->push_back (pTest); if ((ixE!=ix)&&(izE!=iz)) HASH[ixE][iy][izE]->push_back (pTest); if ((iyE!=iy)&&(izE!=iz)) HASH[ix][iyE][izE]->push_back (pTest); if ((ixE!=ix)&&(iyE!=iy)&&(izE!=iz)) HASH[ixE][iyE][izE]->push_back (pTest); } } Status("Removing degenerated/duplicated faces..."); g_bUnregister = false; for (u32 it=0; it<lc_global_data()->g_faces().size(); it++) { R_ASSERT (it>=0 && it<(int)lc_global_data()->g_faces().size()); Face* F = lc_global_data()->g_faces()[it]; if ( F->isDegenerated()) { lc_global_data()->destroy_face (lc_global_data()->g_faces()[it]); Fremoved ++; } else { // Check validity F->Verify ( ); } Progress (float(it)/float(lc_global_data()->g_faces().size())); } if (InvalideFaces()) { err_save (); xrDebug::Fatal (DEBUG_INFO,"* FATAL: %d invalid faces. Compilation aborted",InvalideFaces()); } Status ("Adjacency check..."); g_bUnregister = false; for (u32 it = 0; it<lc_global_data()->g_vertices().size(); ++it) { if (lc_global_data()->g_vertices()[it] && (lc_global_data()->g_vertices()[it]->m_adjacents.empty())) { lc_global_data()->destroy_vertex (lc_global_data()->g_vertices()[it]); ++Vremoved; } } Status ("Cleanup..."); lc_global_data()->g_vertices().erase (std::remove(lc_global_data()->g_vertices().begin(),lc_global_data()->g_vertices().end(),(Vertex*)0),lc_global_data()->g_vertices().end()); lc_global_data()->g_faces().erase (std::remove(lc_global_data()->g_faces().begin(),lc_global_data()->g_faces().end(),(Face*)0),lc_global_data()->g_faces().end()); { for (int ix=0; ix<HDIM_X+1; ix++) for (int iy=0; iy<HDIM_Y+1; iy++) for (int iz=0; iz<HDIM_Z+1; iz++) { xr_delete(HASH[ix][iy][iz]); } } mem_Compact (); clMsg("%d vertices removed. (%d left)",Vcount-lc_global_data()->g_vertices().size(),lc_global_data()->g_vertices().size()); clMsg("%d faces removed. (%d left)", Fcount-lc_global_data()->g_faces().size(), lc_global_data()->g_faces().size()); // ------------------------------------------------------------- /* int err_count =0 ; for (int _1=0; _1<g_faces.size(); _1++) { Progress(float(_1)/float(g_faces.size())); for (int _2=0; _2<g_faces.size(); _2++) { if (_1==_2) continue; if (FaceEqual(*g_faces[_1],*g_faces[_2])) { err_count ++; } } } clMsg ("! duplicate/same faces found:%d",err_count); */ // ------------------------------------------------------------- }
/* // Iterate on edges - select with maximum error int callback_edge_error (Face* F) { float max_err = -1; int max_id = -1; for (u32 e=0; e<3; e++) { Vertex *V1,*V2; F->EdgeVerts (e,&V1,&V2); float len = V1->P.distance_to (V2->P); // len if (len<aht_min_edge) continue; if (len>max_err) { max_err = len; max_id = e; } } if (max_id<0) return max_id; // There should be an edge larger than "min_edge" base_color_c c1; F->v[0]->C._get(c1); base_color_c c2; F->v[1]->C._get(c2); base_color_c c3; F->v[2]->C._get(c3); bool b1 = fsimilar (c1.hemi,c2.hemi,aht_min_err); bool b2 = fsimilar (c2.hemi,c3.hemi,aht_min_err); bool b3 = fsimilar (c3.hemi,c1.hemi,aht_min_err); if (b1 && b2 && b3) return -1; // don't touch flat-shaded triangle else return max_id; // tesselate longest edge } void callback_vertex_hemi (Vertex* V) { // calc vertex attributes CDB::COLLIDER DB; DB.ray_options (0); base_color_c vC; LightPoint (&DB, RCAST_Model, vC, V->P, V->N, pBuild->L_static, LP_dont_rgb+LP_dont_sun,0); V->C._set (vC); } int smfVertex (Vertex* V) { return 1 + (std::lower_bound(g_vertices.begin(),g_vertices.end(),V)-g_vertices.begin()); } void GSaveAsSMF (LPCSTR fname) { IWriter* W = FS.w_open (fname); string256 tmp; // vertices std::sort (g_vertices.begin(),g_vertices.end()); for (u32 v_idx=0; v_idx<g_vertices.size(); v_idx++){ Fvector v = g_vertices[v_idx]->P; sprintf (tmp,"v %f %f %f",v.x,v.y,-v.z); W->w_string (tmp); } // transfer faces for (u32 f_idx=0; f_idx<g_faces.size(); f_idx++){ Face* t = g_faces [f_idx]; sprintf (tmp,"f %d %d %d", smfVertex(t->v[0]), smfVertex(t->v[2]), smfVertex(t->v[1]) ); W->w_string (tmp); } // colors W->w_string ("bind c vertex"); for (u32 v_idx=0; v_idx<g_vertices.size(); v_idx++){ base_color_c c; g_vertices[v_idx]->C._get(c); float h = c.hemi/2.f; sprintf (tmp,"c %f %f %f",h,h,h); W->w_string (tmp); } FS.w_close (W); } */ void CBuild::xrPhase_AdaptiveHT () { CDB::COLLIDER DB; DB.ray_options (0); Status ("Tesselating..."); if (1) { for (u32 fit=0; fit<lc_global_data()->g_faces().size(); fit++) { // clear split flag from all faces + calculate normals lc_global_data()->g_faces()[fit]->flags.bSplitted = false; lc_global_data()->g_faces()[fit]->flags.bLocked = true; lc_global_data()->g_faces()[fit]->CalcNormal (); } u_Tesselate (callback_edge_longest,0,0); // tesselate } // Tesselate + calculate Status ("Precalculating..."); { mem_Compact (); // Build model FPU::m64r (); BuildRapid (FALSE); // Prepare FPU::m64r (); Status ("Precalculating : base hemisphere ..."); mem_Compact (); Light_prepare (); // calc approximate normals for vertices + base lighting for (u32 vit=0; vit<lc_global_data()->g_vertices().size(); vit++) { base_color_c vC; Vertex* V = lc_global_data()->g_vertices()[vit]; V->normalFromAdj (); LightPoint (&DB, lc_global_data()->RCAST_Model(), vC, V->P, V->N, pBuild->L_static(), LP_dont_rgb+LP_dont_sun,0); vC.mul (0.5f); V->C._set (vC); } } ////////////////////////////////////////////////////////////////////////// /* Status ("Adaptive tesselation..."); { for (u32 fit=0; fit<g_faces.size(); fit++) { // clear split flag from all faces + calculate normals g_faces[fit]->flags.bSplitted = false; g_faces[fit]->flags.bLocked = true; } u_Tesselate (callback_edge_error,0,callback_vertex_hemi); // tesselate } */ ////////////////////////////////////////////////////////////////////////// Status ("Gathering lighting information..."); u_SmoothVertColors (5); ////////////////////////////////////////////////////////////////////////// /* Status ("Exporting to SMF..."); { string_path fn; GSaveAsSMF (strconcat(fn,pBuild->path,"hemi_source.smf")); } */ }