bool EDetailManager::Export(LPCSTR path) { AnsiString fn = AnsiString(path)+"build.details"; bool bRes=true; SPBItem* pb = UI->ProgressStart(5,"Making details..."); CMemoryWriter F; pb->Inc ("merge textures"); Fvector2Vec offsets; Fvector2Vec scales; boolVec rotated; RStringSet textures_set; RStringVec textures; U32Vec remap; U8Vec remap_object (objects.size(),u8(-1)); int slot_cnt = dtH.size_x*dtH.size_z; for (int slot_idx=0; slot_idx<slot_cnt; slot_idx++){ DetailSlot* it = &dtSlots[slot_idx]; for (int part=0; part<4; part++){ u8 id = it->r_id(part); if (id!=DetailSlot::ID_Empty) { textures_set.insert(((EDetail*)(objects[id]))->GetTextureName()); remap_object[id] = 1; } } } textures.assign (textures_set.begin(),textures_set.end()); U8It remap_object_it= remap_object.begin(); u32 new_idx = 0; for (DetailIt d_it=objects.begin(); d_it!=objects.end(); d_it++,remap_object_it++) if ((*remap_object_it==1)&&(textures_set.find(((EDetail*)(*d_it))->GetTextureName())!=textures_set.end())) *remap_object_it = (u8)new_idx++; AnsiString do_tex_name = ChangeFileExt(fn,"_details"); int res = ImageLib.CreateMergedTexture(textures,do_tex_name.c_str(),STextureParams::tfADXT1,256,1024,256,1024,offsets,scales,rotated,remap); if (1!=res) bRes=FALSE; pb->Inc ("export geometry"); // objects int object_idx = 0; if (bRes){ do_tex_name = ExtractFileName(do_tex_name); F.open_chunk (DETMGR_CHUNK_OBJECTS); for (DetailIt it=objects.begin(); it!=objects.end(); it++){ if (remap_object[it-objects.begin()]!=u8(-1)){ F.open_chunk (object_idx++); if (!((EDetail*)(*it))->m_pRefs){ ELog.DlgMsg(mtError, "Bad object or object not found '%s'.", ((EDetail*)(*it))->m_sRefs.c_str()); bRes=false; }else{ LPCSTR tex_name = ((EDetail*)(*it))->GetTextureName(); for (u32 t_idx=0; t_idx<textures.size(); t_idx++) if (textures[t_idx]==tex_name) break; VERIFY(t_idx<textures.size()); t_idx = remap[t_idx]; ((EDetail*)(*it))->Export (F,do_tex_name.c_str(),offsets[t_idx],scales[t_idx],rotated[t_idx]); } F.close_chunk (); if (!bRes) break; } } F.close_chunk (); } pb->Inc ("export slots"); // slots if (bRes){ xr_vector<DetailSlot> dt_slots(slot_cnt); dt_slots.assign(dtSlots,dtSlots+slot_cnt); for (slot_idx=0; slot_idx<slot_cnt; slot_idx++){ DetailSlot& it = dt_slots[slot_idx]; // zero colors need lighting it.c_dir = 0; it.c_hemi = 0; it.c_r = 0; it.c_g = 0; it.c_b = 0; for (int part=0; part<4; part++){ u8 id = it.r_id(part); if (id!=DetailSlot::ID_Empty) it.w_id(part,remap_object[id]); } } F.open_chunk (DETMGR_CHUNK_SLOTS); F.w (dt_slots.begin(),dtH.size_x*dtH.size_z*sizeof(DetailSlot)); F.close_chunk (); pb->Inc(); // write header dtH.version = DETAIL_VERSION; dtH.object_count= object_idx; F.w_chunk (DETMGR_CHUNK_HEADER,&dtH,sizeof(DetailHeader)); bRes = F.save_to(fn.c_str()); } pb->Inc(); UI->ProgressEnd(pb); return bRes; }
bool EDetailManager::UpdateSlotObjects(int x, int z){ srand(time(NULL)); DetailSlot* slot = dtSlots+z*dtH.size_x+x; Irect R; GetSlotTCRect(R,x,z); //ELog.Msg(mtInformation,"TC [%d,%d]-[%d,%d]",R.x1,R.y1,R.x2,R.y2); SIndexDistVec best; // find best color index { for (int v=R.y1; v<=R.y2; v++){ for (int u=R.x1; u<=R.x2; u++){ u32 clr; if (m_Base.GetColor(clr,u,v)){ Fcolor C; C.set(clr); FindClosestIndex(C,best); } } } } std::sort(best.begin(),best.end(),CompareWeightFunc); // пройдем по 4 частям слота и определим плотность заполнения (учесть переворот V) Irect P[4]; float dx=float(R.x2-R.x1)/2.f; float dy=float(R.y2-R.y1)/2.f; // 2 3 // 0 1 P[0].x1=R.x1; P[0].y1=iFloor(R.y1+dy+0.501f); P[0].x2=iFloor(R.x1+dx+.499f); P[0].y2=R.y2; P[1].x1=iFloor(R.x1+dx+0.501f); P[1].y1=iFloor(R.y1+dy+0.501f); P[1].x2=R.x2; P[1].y2=R.y2; P[2].x1=R.x1; P[2].y1=R.y1; P[2].x2=iFloor(R.x1+dx+.499f); P[2].y2=iFloor(R.y1+dy+.499f); P[3].x1=iFloor(R.x1+dx+0.501f); P[3].y1=R.y1; P[3].x2=R.x2; P[3].y2=iFloor(R.y1+dx+.499f); for (int part=0; part<4; part++){ float alpha=0; int cnt=0; for (int v=P[part].y1; v<=P[part].y2; v++){ for (int u=P[part].x1; u<=P[part].x2; u++){ u32 clr; if (m_Base.GetColor(clr,u,v)){ Fcolor C; C.set(clr); CalcClosestCount(part,C,best); alpha+=C.a; cnt++; } } } alpha/=(cnt?float(cnt):1); alpha*=0.5f; for (u32 i=0; i<best.size(); i++) best[i].dens[part] = cnt?(best[i].cnt[part]*alpha)/float(cnt):0; } // fill empty slots R_ASSERT(best.size()); int id=-1; u32 o_cnt=0; for (u32 i=0; i<best.size(); i++) o_cnt+=m_ColorIndices[best[i].index].size(); // равномерно заполняем пустые слоты if (o_cnt>best.size()){ while (best.size()<4){ do{ id++; if (id>3) id=0; }while(m_ColorIndices[best[id].index].size()<=1); best.push_back(SIndexDist()); best.back()=best[id]; if (best.size()==o_cnt) break; } } // заполним палитру и установим Random'ы // Msg("Slot: %d %d",x,z); for(u32 k=0; k<best.size(); k++){ // objects ColorIndexPairIt CI=m_ColorIndices.find(best[k].index); R_ASSERT(CI!=m_ColorIndices.end()); U8Vec elem; elem.resize(CI->second.size()); for (U8It b_it=elem.begin(); b_it!=elem.end(); b_it++) *b_it=u8(b_it-elem.begin()); // best_rand A(DetailRandom); std::random_shuffle(elem.begin(),elem.end());//,A); for (b_it=elem.begin(); b_it!=elem.end(); b_it++){ bool bNotFound=true; slot->w_id (k, GetObject(CI,*b_it)); for (u32 j=0; j<k; j++) if (slot->r_id(j)==slot->r_id(k)){ bNotFound = false; break; } if (bNotFound) break; } slot->color_editor(); // density float f = ((EDetail*)objects[slot->r_id(k)])->m_fDensityFactor; slot->palette[k].a0 = (u16)iFloor(best[k].dens[0]*f*15.f+.5f); slot->palette[k].a1 = (u16)iFloor(best[k].dens[1]*f*15.f+.5f); slot->palette[k].a2 = (u16)iFloor(best[k].dens[2]*f*15.f+.5f); slot->palette[k].a3 = (u16)iFloor(best[k].dens[3]*f*15.f+.5f); } // определим ID незаполненных слотов как пустышки for(k=best.size(); k<4; k++) slot->w_id(k,DetailSlot::ID_Empty); return true; }