| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- /******************************************************************************/
- #include "stdafx.h"
- /******************************************************************************/
- MergeSimilarMaterials MSM;
- Memc<IDReplace> ReplaceIDs;
- State IDReplaceState(UpdateIDReplace, DrawIDReplace, InitIDReplace, ShutIDReplace);
- C IDReplace* ReplaceID(C UID &src, Memc<IDReplace> &replace) {return src.valid() ? replace.binaryFind(src, IDReplace::Compare) : null;}
- /******************************************************************************/
- bool ThreadIDReplace(Thread &thread)
- {
- ThreadMayUseGPUData();
- FREPA(Proj.elms)
- {
- if(thread.wantStop())return false;
- Elm &elm=Proj.elms[i]; if(elm.data)
- {
- if( ReplaceID(elm. id))elm.setRemoved(true ); // if this element is replaced with another one, then remove it
- if(C IDReplace *parent=ReplaceID(elm.parent_id))elm.setParent (parent->to); // if parent of this element is being removed, then assign this element to the replacement
- FREPA(ReplaceIDs)if(elm.data->mayContain(ReplaceIDs[i].from))
- {
- bool changed=false;
- switch(elm.type)
- {
- case ELM_MESH:
- {
- Mesh mesh; if(Load(mesh, Proj.editPath(elm), Proj.game_path))
- {
- REPD (l, mesh.lods( ))
- REPAD(p, mesh.lod (l))
- {
- MeshPart &part=mesh.lod(l).parts[p];
- bool changed_multi_mtrl=false;
- MaterialPtr mtrls[4]; REPA(mtrls)
- {
- MaterialPtr &mtrl=mtrls[i];
- mtrl=part.multiMaterial(i);
- if(C IDReplace *id=ReplaceID(mtrl.id())){changed_multi_mtrl=true; mtrl=Proj.gamePath(id->to);}
- }
- if(changed_multi_mtrl)
- {
- changed=true;
- part.multiMaterial(mtrls[0], mtrls[1], mtrls[2], mtrls[3]);
- }
- REP(part.variations())if(i)
- if(C IDReplace *id=ReplaceID(part.variation(i).id())){changed=true; part.variation(i, Proj.gamePath(id->to));}
- }
- if(changed)
- {
- ElmMesh *mesh_data=elm.meshData();
- mesh_data->newVer();
- mesh_data->fromMtrl(mesh);
- mesh_data->file_time.getUTC();
- Skeleton *body_skel; Proj.getMeshSkels(mesh_data, null, &body_skel);
- Mesh game; EditToGameMesh(mesh, game, body_skel, Proj.getEnum(mesh_data->draw_group_id), &mesh_data->transform());
- Save(mesh, Proj.editPath(elm), Proj.game_path);
- Save(game, Proj.gamePath(elm)); Proj.savedGame(elm);
- }
- }
- }break;
- case ELM_OBJ:
- case ELM_OBJ_CLASS:
- {
- EditObject obj; if(obj.load(Proj.editPath(elm)))
- {
- REPA(obj)
- {
- EditParam ¶m=obj[i];
- if(ParamTypeID(param.type))REP(param.IDs())if(ReplaceID(param.asID(i))) // if any ID needs to be replaced
- {
- Memt<UID> ids;
- FREP(param.IDs()) // list in original order
- {
- UID id=param.asID(i); if(C IDReplace *replace=ReplaceID(id))id=replace->to;
- ids.add(id);
- }
- changed=true;
- param.setAsIDArray(ids);
- break;
- }
- }
- if(changed)
- {
- elm.data->newVer();
- Save(obj, Proj.editPath(elm));
- Proj.makeGameVer(elm);
- }
- }
- }break;
- case ELM_WORLD:
- {
- // TODO: replace terrain materials (watch out for heightmap material palette having both replacement and original)
- // TODO: replace world object params
- }break;
- }
- if(changed)Proj.elmChanged(elm); // this may cause conflicts with 'Gui.update' (if needed then move to 'ShutIDReplace')
- break;
- }
- }
- UpdateProgress.set(i, Proj.elms.elms());
- }
- return false;
- }
- bool InitIDReplace()
- {
- SetKbExclusive();
- Proj.pause();
- UpdateProgress.create(Rect_C(0, -0.05f, 1, 0.045f));
- UpdateThread .create(ThreadIDReplace);
- return true;
- }
- void ShutIDReplace()
- {
- UpdateThread .del();
- UpdateProgress.del();
- Proj.refresh().resume();
- WindowSetNormal();
- WindowFlash();
- }
- /******************************************************************************/
- bool UpdateIDReplace()
- {
- if(Kb.bp(KB_ESC)){SetProjectState(); Gui.msgBox(S, "Merging breaked on user request");}
- if(!UpdateThread.active())SetProjectState();
- WindowSetProgress(UpdateProgress());
- Time.wait(1000/30);
- //Gui.update(); this may cause conflicts with 'Proj.elmChanged'
- Server.update(null, true);
- if(Ms.bp(3))WindowToggle();
- return true;
- }
- /******************************************************************************/
- void DrawIDReplace()
- {
- D.clear(BackgroundColor());
- D.text(0, 0.05f, "Merging Elements");
- GuiPC gpc;
- gpc.visible=gpc.enabled=true;
- gpc.client_rect=gpc.clip.set(-D.w(), -D.h(), D.w(), D.h());
- gpc.offset.zero();
- UpdateProgress.draw(gpc);
- D.clip();
- }
- /******************************************************************************/
- /******************************************************************************/
- void IDReplace::set(C UID &from, C UID &to) {T.from=from; T.to=to;}
- int IDReplace::Compare(C IDReplace &a, C IDReplace &b) {return ::Compare(a.from, b.from);}
- int IDReplace::Compare(C IDReplace &a, C UID &b) {return ::Compare(a.from, b );}
- bool MergeSimilarMaterials::Mtrl::similar(C Mtrl &m)C
- {
- if(MSM. name && name!=m. name)return false;
- if(MSM. color_name && color_name!=m. color_name)return false;
- if(MSM. color_tex && base_0_tex!=m. base_0_tex)return false;
- if(MSM. normal_tex && base_1_tex!=m. base_1_tex)return false;
- if(MSM. detail_tex && detail_tex!=m. detail_tex)return false;
- if(MSM. macro_tex && macro_tex!=m. macro_tex)return false;
- if(MSM. reflect_tex && reflect_tex!=m.reflect_tex)return false;
- if(MSM. light_tex && light_tex!=m. light_tex)return false;
- if(MSM. cull && cull!=m. cull)return false;
- if(MSM. tech && tech!=m. tech)return false;
- if(MSM. color_value_on() && Abs(col -m.col ).max()>MSM. color_value)return false;
- if(MSM. bump_value_on() && Abs(bump -m.bump ) >MSM. bump_value)return false;
- if(MSM. spec_value_on() && Abs(spec -m.spec ) >MSM. spec_value)return false;
- if(MSM. glow_value_on() && Abs(glow -m.glow ) >MSM. glow_value)return false;
- if(MSM.reflect_value_on() && Abs(reflect -m.reflect ) >MSM.reflect_value)return false;
- if(MSM. uv_scale_on() && Abs(uv_scale-m.uv_scale) >MSM. uv_scale)return false;
- return true;
- }
- ::MergeSimilarMaterials::Mtrl& MergeSimilarMaterials::Mtrl::set(C UID &elm_id, C EditMaterial &m)
- {
- if(Elm *elm=Proj.findElm(elm_id))name=elm->name;
- T.elm_id=elm_id;
- color_name=GetBase(Edit::FileParams(m.color_map).name);
- base_0_tex=m.base_0_tex;
- base_1_tex=m.base_1_tex;
- detail_tex=m.detail_tex;
- macro_tex=m.macro_tex;
- reflect_tex=m.reflection_tex;
- light_tex=m.light_tex;
- cull=m.cull;
- tech=m.tech;
- col=m.color;
- bump=m.bump;
- spec=m.specular;
- glow=m.glow;
- reflect=m.reflection;
- uv_scale=m.tex_scale;
- return T;
- }
- int MergeSimilarMaterials::CompareMtrl(C Mtrl &a, C Mtrl &b) {return ComparePathNumber(Proj.elmFullName(b.elm_id), Proj.elmFullName(a.elm_id));}
- void MergeSimilarMaterials::Detect(MergeSimilarMaterials &msm)
- {
- MtrlEdit.flush(); // flush Material Editor changes first
- Memc<Mtrl> mtrls;
- Memc<Memc<Mtrl> > similar;
- // first load all existing materials
- FREPA(Proj.elms)
- {
- Elm &elm=Proj.elms[i]; if(elm.type==ELM_MTRL && elm.finalExists())
- {
- EditMaterial edit_mtrl;
- if(edit_mtrl.load(Proj.editPath(elm)))
- if(!msm.color_is || edit_mtrl.base_0_tex.valid())
- mtrls.New().set(elm.id, edit_mtrl);
- }
- }
- mtrls.sort(CompareMtrl);
- // detect similar ones
- for(; mtrls.elms(); )
- {
- Mtrl &mtrl=mtrls.last();
- // first check in already merged groups
- REPA(similar)
- {
- Memc<Mtrl> &group=similar[i];
- if(mtrl.similar(group[0])) // compare with the first one in the group only
- {
- Swap(group.New(), mtrl);
- mtrls.removeLast();
- goto merged;
- }
- }
- // now check all single materials
- REPD(i, mtrls.elms()-1)
- {
- Mtrl &test=mtrls[i];
- if(mtrl.similar(test)) // 2 materials are similar
- {
- Memc<Mtrl> &group=similar.New(); // create a new group
- Swap(group.New(), mtrl);
- Swap(group.New(), test);
- mtrls.removeLast( ); // first remove the one with higher index
- mtrls.remove (i, true); // now remove the one with lower index
- goto merged;
- }
- }
- mtrls.removeLast(); // no similar were detected so just remove it
- merged:;
- }
- // setup data
- MSM.replace.clear();
- MSM.data .clear();
- FREPA(similar)
- {
- C Memc<Mtrl> &src=similar[i];
- for(int i=1; i<src.elms(); i++)MSM.replace.New().set(src[i].elm_id, src[0].elm_id);
- if(MSM.data.elms())MSM.data.New(); FREPA(src)MSM.data.New().id=src[i].elm_id;
- }
- MSM.replace.sort(IDReplace::Compare);
- MSM.list.setData(MSM.data);
- }
- void MergeSimilarMaterials::display(C MemPtr<UID> &elm_ids)
- {
- Memc<UID> mtrl_ids; REPA(elm_ids)if(Elm *mtrl=Proj.findElm(elm_ids[i], ELM_MTRL))mtrl_ids.add(mtrl->id);
- if(mtrl_ids.elms()>1)
- {
- replace .clear();
- data .clear();
- mtrl_ids.sort(CompareProjPath);
- FREPA(mtrl_ids)
- {
- if(i)replace.New().set(mtrl_ids[i], mtrl_ids[0]);
- data.New().id=mtrl_ids[i];
- }
- replace.sort(IDReplace::Compare);
- list.setData(data);
- activate();
- }
- }
- void MergeSimilarMaterials::drag(Memc<UID> &elms, GuiObj *focus_obj, C Vec2 &screen_pos)
- {
- if(contains(focus_obj))
- {
- display(elms);
- elms.clear();
- }
- }
- void MergeSimilarMaterials::Merge(MergeSimilarMaterials &msm)
- {
- if(msm.replace.elms())
- {
- ReplaceIDs=msm.replace;
- msm.clearProj();
- IDReplaceState.set(StateFadeTime);
- }
- }
- Str MergeSimilarMaterials::Data::AsText(C Data &data) {return Proj.elmFullName(data.id);}
- void MergeSimilarMaterials::clearProj()
- {
- replace.clear();
- data .clear();
- list .clear();
- }
- void MergeSimilarMaterials::create()
- {
- add("Require Same:");
- add("Material Name" , MEMBER(MergeSimilarMaterials, name)).desc("Materials will be tested against their name in the project");
- add("Color Source Name", MEMBER(MergeSimilarMaterials, color_name)).desc("Materials will be tested against the source file name of the color texture.\nOnly the base part of the file name (without the path) is checked.");
- add("Color Texture" , MEMBER(MergeSimilarMaterials, color_tex )).desc("Materials will be tested against the actual color texture image");
- add("Normal Texture" , MEMBER(MergeSimilarMaterials, normal_tex));
- add("Detail Texture" , MEMBER(MergeSimilarMaterials, detail_tex));
- add("Macro Texture" , MEMBER(MergeSimilarMaterials, macro_tex));
- add("Reflect Texture" , MEMBER(MergeSimilarMaterials, reflect_tex));
- add("Light Texture" , MEMBER(MergeSimilarMaterials, light_tex));
- add("Technique" , MEMBER(MergeSimilarMaterials, tech));
- add("Cull" , MEMBER(MergeSimilarMaterials, cull));
- add("Color Value" , MEMBER(MergeSimilarMaterials, color_value )).desc("Tolerance").range(0, 2);
- add("Bump Value" , MEMBER(MergeSimilarMaterials, bump_value )).desc("Tolerance").range(0, 1);
- add("Specular Value" , MEMBER(MergeSimilarMaterials, spec_value )).desc("Tolerance").range(0, 1);
- add("Glow Value" , MEMBER(MergeSimilarMaterials, glow_value )).desc("Tolerance").range(0, 1);
- add("Reflection Value" , MEMBER(MergeSimilarMaterials, reflect_value)).desc("Tolerance").range(0, 1);
- add("UV Scale" , MEMBER(MergeSimilarMaterials, uv_scale )).desc("Tolerance").min (0);
- add();
- add("Merge Only If:");
- add("Color Texture Exists", MEMBER(MergeSimilarMaterials, color_is)).desc("When this option is selected, then Materials will not be merged if they don't have a color texture image set");
- flt h=0.043f;
- ::PropWin::create("Merge Similar Materials", Vec2(0.02f, -0.02f), 0.036f, h, 0.15f); button[2].func(HideProjAct, SCAST(GuiObj, T)).show();
- int c=0;
- FREPA(props)if(props[i].textline.is())
- {
- CheckBox *check=null;
- switch(c++)
- {
- case 0: check=& color_value_on; break;
- case 1: check=& bump_value_on; break;
- case 2: check=& spec_value_on; break;
- case 3: check=& glow_value_on; break;
- case 4: check=&reflect_value_on; break;
- case 5: check=& uv_scale_on; break;
- }
- if(check)T+=check->create(Rect_LU(props[i].textline.pos(), props[i].textline.size().y), true);
- props[i].textline.move(Vec2(h, 0));
- props[i].button .move(Vec2(h, 0));
- }
- autoData(this);
- Vec2 params=rect().size(); params.x+=h; Vec2 size=params; size.x+=1.3f; size.y+=0.6f;
- rect(Rect_C(0, size));
- T+=detected.create(Vec2(Avg(params.x, size.x)-0.05f, -0.04f), "Detected:", &ts);
- T+=detect.create(Rect_D(size.x*1/3, -clientHeight()+0.04f, 0.3f, 0.06f), "Detect").func(Detect, T).desc("Detect similar materials");
- T+= merge.create(Rect_D(size.x*2/3, -clientHeight()+0.04f, 0.3f, 0.06f), "Merge" ).func(Merge , T).desc("Merge detected materials");
- T+=region.create(Rect(params.x, detect.rect().max.y+0.04f, size.x-0.02f, detected.pos().y-0.03f));
- ListColumn lc[]=
- {
- ListColumn(Data::AsText, LCW_DATA, "File"),
- };
- region+=list.create(lc, Elms(lc), true).elmHeight(0.038f).textSize(0, 1); FlagDisable(list.flag, LIST_SORTABLE); list.cur_mode=LCM_MOUSE;
- }
- void MergeSimilarMaterials::update(C GuiPC &gpc)
- {
- ::EE::ClosableWindow::update(gpc);
- if(visible() && gpc.visible)
- {
- if(Ms.tappedFirst(0) && Gui.ms()==&list)if(Data *data=list())if(Elm *elm=Proj.findElm(data->id))MtrlEdit.toggle(elm);
- }
- }
- MergeSimilarMaterials::MergeSimilarMaterials() : name(false), color_name(false), color_is(false), color_tex(true), normal_tex(true), detail_tex(true), macro_tex(true), reflect_tex(true), light_tex(true), tech(true), cull(true), color_value(0.1f), bump_value(0.1f), spec_value(0.1f), glow_value(0.1f), reflect_value(0.1f), uv_scale(0.1f) {}
- MergeSimilarMaterials::Data::Data() : id(UIDZero) {}
- /******************************************************************************/
|