Image Atlas.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. ImageAtlasEditor ImageAtlasEdit;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. void ImageAtlasEditor::Change::create(ptr user)
  8. {
  9. if(ElmImageAtlas *data=ImageAtlasEdit.data())
  10. {
  11. T.data=*data;
  12. ImageAtlasEdit.undoVis();
  13. }
  14. }
  15. void ImageAtlasEditor::Change::apply(ptr user)
  16. {
  17. if(ElmImageAtlas *data=ImageAtlasEdit.data())
  18. {
  19. data->undo(T.data);
  20. ImageAtlasEdit.setChanged();
  21. ImageAtlasEdit.toGui();
  22. ImageAtlasEdit.undoVis();
  23. }
  24. }
  25. void ImageAtlasEditor::ListElm::setColor() {color=GuiListTextColor(); if(removed)color.a/=2;}
  26. void ImageAtlasEditor::ListElm::operator=(C ElmImageAtlas::Img &src) {img_id=src.id; removed=src.removed; setColor();}
  27. int ImageAtlasEditor::ListElm::ComparePath(C ListElm &a, C ListElm &b) {return ::ComparePathNumber(ElmName(a), ElmName(b));}
  28. void ImageAtlasEditor::undoVis() {SetUndo(undos, undo, redo);}
  29. void ImageAtlasEditor::ShowRemoved(ImageAtlasEditor &iae) {iae.toGui ();}
  30. void ImageAtlasEditor::Make(ImageAtlasEditor &iae) {iae.makeDo();}
  31. Str ImageAtlasEditor::ElmFullName(C ListElm &le) {return Proj.elmFullName(le.img_id);}
  32. Str ImageAtlasEditor::ElmName(C ListElm &le) {if(Elm *elm=Proj.findElm (le.img_id))return elm->name; return UnknownName;}
  33. int ImageAtlasEditor::CompareSource(C ImageAtlas::Source &a, C ImageAtlas::Source &b) {return ComparePathNumber(a.name, b.name);}
  34. void ImageAtlasEditor::MipMaps( ImageAtlasEditor &iae, C Str &t) {if(ElmImageAtlas *d=iae.data()){iae.undos.set("mms"); d->mip_maps=TextBool(t); d->mip_maps_time.getUTC(); iae.setChanged();}}
  35. Str ImageAtlasEditor::MipMaps(C ImageAtlasEditor &iae ) {if(ElmImageAtlas *d=iae.data())return d->mip_maps; return S;}
  36. void ImageAtlasEditor::Undo(ImageAtlasEditor &editor) {editor.undos.undo();}
  37. void ImageAtlasEditor::Redo(ImageAtlasEditor &editor) {editor.undos.redo();}
  38. void ImageAtlasEditor::Locate(ImageAtlasEditor &editor) {Proj.elmLocate(editor.elm_id);}
  39. ElmImageAtlas* ImageAtlasEditor::data()C {return elm ? elm->imageAtlasData() : null;}
  40. GuiObj& ImageAtlasEditor::desc(C Str &desc)
  41. {
  42. list.desc(desc);
  43. region.desc(desc);
  44. return ::EE::GuiObj::desc(desc);
  45. }
  46. void ImageAtlasEditor::makeDo()
  47. {
  48. if(ElmImageAtlas *data=T.data())
  49. {
  50. ImageAtlas atlas;
  51. Memb<Image> images; // use 'Memb' because we're storing pointers
  52. Memc<ImageAtlas::Source> source;
  53. FREPA(data->images)
  54. {
  55. ElmImageAtlas::Img &img=data->images[i]; if(!img.removed)if(Elm *elm=Proj.findElm(img.id))
  56. {
  57. images.New().ImportTry((elm->type==ELM_IMAGE) ? Proj.editPath(*elm) : Proj.gamePath(*elm), -1, IMAGE_SOFT, 1); // use edit path for ELM_IMAGE and game path for ELM_ICON
  58. source.New().set(&images.last(), elm->name);
  59. }
  60. }
  61. source.sort(CompareSource);
  62. if(!atlas.create(source, SupportBC7 ? IMAGE_BC7 : IMAGE_BC3, data->mip_maps ? 0 : 1))Gui.msgBox(S, "Error creating Image Atlas");else
  63. {
  64. Save(atlas, Proj.gamePath(*elm)); Proj.savedGame(*elm);
  65. setChanged(true);
  66. }
  67. }
  68. }
  69. void ImageAtlasEditor::create()
  70. {
  71. Property &mip_maps=add("Mip Maps", MemberDesc(DATA_BOOL).setFunc(MipMaps, MipMaps));
  72. autoData(this);
  73. ListColumn lc[]=
  74. {
  75. ListColumn(DATA_NONE, 0, 0, 0.050f, S ), // column for "remove" button
  76. ListColumn(ElmFullName , 0.8f , "Element" ),
  77. ListColumn(ElmName , 0.4f , "Name in Atlas"),
  78. };
  79. ::PropWin::create("Image Atlas Editor"); button[1].show(); button[2].func(HideProjAct, SCAST(GuiObj, T)).show(); flag|=WIN_RESIZABLE;
  80. T+=make.create(Rect_LU(0.01f, -0.01f, 0.25f, 0.055f), "Create").func(Make, T).focusable(false).desc("Create and save image atlas from currently listed images");
  81. mip_maps.pos(make.rect().right()+Vec2(make.size().y, 0));
  82. T+=undo .create().func(Undo, T).focusable(false).desc("Undo"); undo.image="Gui/Misc/undo.img";
  83. T+=redo .create().func(Redo, T).focusable(false).desc("Redo"); redo.image="Gui/Misc/redo.img";
  84. T+=locate.create("Locate").func(Locate, T).focusable(false).desc("Locate this element in the Project");
  85. T+=show_removed.create().func(ShowRemoved, T).focusable(false).desc("Show removed elements"); show_removed.image="Gui/Misc/trash.img"; show_removed.mode=BUTTON_TOGGLE;
  86. T+=region.create();
  87. region+=list.create(lc, Elms(lc)); list.setElmTextColor(MEMBER(ListElm, color)); list.flag|=LIST_RESIZABLE_COLUMNS; FlagDisable(list.flag, LIST_SORTABLE); // disable sorting because of remove buttons
  88. list.elmHeight(0.043f).textSize(0, 1);
  89. flt w=0.02f+region.slidebarSize(); REPA(lc)w+=lc[i].width; rect(Rect_C(0, 0, w, 1));
  90. desc("Drag and drop an image here");
  91. }
  92. Rect ImageAtlasEditor::sizeLimit()C {Rect r=::EE::Window::sizeLimit(); r.min.set(0.85f, 0.4f); return r;}
  93. ImageAtlasEditor& ImageAtlasEditor::rect(C Rect &rect)
  94. {
  95. ::EE::Window::rect(rect);
  96. show_removed.rect(Rect_RU(Vec2(clientWidth()-0.01f, -0.01f) , make.rect().h()));
  97. locate .rect(Rect_RU(show_removed.pos()-Vec2(0.01f, 0), 0.15f, make.rect().h()));
  98. redo .rect(Rect_RU(locate .pos()-Vec2(0.01f, 0), make.rect().h()));
  99. undo .rect(Rect_RU(redo .pos() , make.rect().h()));
  100. region .rect(Rect(0, -clientHeight(), clientWidth(), show_removed.rect().min.y).extend(-0.01f));
  101. return T;
  102. }
  103. void ImageAtlasEditor::skinChanged()
  104. {
  105. REPAO(list_data).setColor();
  106. }
  107. void ImageAtlasEditor::flush()
  108. {
  109. if(elm && changed)
  110. {
  111. if(ElmImageAtlas *data=T.data())data->newVer(); // modify just before saving/sending in case we've received data from server after edit
  112. if(changed_file)Server.setElmLong(elm->id);else Server.setElmShort(elm->id);
  113. }
  114. changed=changed_file=false;
  115. }
  116. void ImageAtlasEditor::setChanged(bool file)
  117. {
  118. if(elm)
  119. {
  120. changed=true;
  121. if(ElmImageAtlas *data=T.data())
  122. {
  123. data->newVer();
  124. if(file){data->file_time.getUTC(); changed_file=true;}
  125. }
  126. toGui();
  127. }
  128. }
  129. void ImageAtlasEditor::Remove(ListElm &le) {ImageAtlasEdit.remove(le);}
  130. void ImageAtlasEditor::remove(ListElm &le)
  131. {
  132. if(ElmImageAtlas *data=T.data())if(ElmImageAtlas::Img *img=data->find(le.img_id))
  133. {
  134. undos.set(null, true);
  135. img->removed^=1; img->removed_time.getUTC();
  136. setChanged();
  137. }
  138. }
  139. void ImageAtlasEditor::toGui()
  140. {
  141. ::PropWin::toGui();
  142. int v=0; flt h=list.elmHeight();
  143. list_data.clear(); if(ElmImageAtlas *data=T.data())FREPA(data->images)if(!data->images[i].removed || show_removed())
  144. {
  145. ListElm &le=list_data.New(); le=data->images[i];
  146. le.remove.create().func(Remove, le).desc(data->images[i].removed ? "Restore this element" : "Remove this element");
  147. if(data->images[i].removed)le.remove.text="R";else le.remove.image="Gui/close.img";
  148. }
  149. list_data.sort(ListElm::ComparePath);
  150. FREPA(list_data)region+=list_data[i].remove.rect(Rect_LU(0, -(v++)*h-list.columnHeight(), h, h));
  151. list.setData(list_data);
  152. }
  153. void ImageAtlasEditor::set(Elm *elm)
  154. {
  155. if(elm && elm->type!=ELM_IMAGE_ATLAS)elm=null;
  156. if(T.elm!=elm)
  157. {
  158. flush();
  159. undos.del(); undoVis();
  160. T.elm =elm;
  161. T.elm_id=(elm ? elm->id : UIDZero);
  162. toGui();
  163. Proj.refresh(false, false);
  164. visible(T.elm!=null).moveToTop();
  165. }
  166. }
  167. void ImageAtlasEditor::activate(Elm *elm) {set(elm); if(T.elm)::EE::GuiObj::activate();}
  168. void ImageAtlasEditor::toggle(Elm *elm) {if(elm==T.elm)elm=null; set(elm);}
  169. ImageAtlasEditor& ImageAtlasEditor::hide( ){if(visible()){::PropWin::hide(); set(null);} return T;}
  170. void ImageAtlasEditor::elmChanged(C UID &elm_id)
  171. {
  172. if(elm && elm->id==elm_id)
  173. {
  174. undos.set(null, true);
  175. toGui();
  176. }
  177. }
  178. void ImageAtlasEditor::drag(Memc<UID> &elms, GuiObj *obj, C Vec2 &screen_pos)
  179. {
  180. if(elm && contains(obj))REPA(elms)if(Elm *image=Proj.findElm(elms[i]))if(ElmImageLike(image->type)) // add image element to the atlas
  181. {
  182. if(ElmImageAtlas *data=elm->imageAtlasData())
  183. {
  184. undos.set(null, true);
  185. ElmImageAtlas::Img &img=data->get(image->id);
  186. img.id=image->id; img.removed=false; img.removed_time.getUTC();
  187. setChanged();
  188. }
  189. }
  190. }
  191. void ImageAtlasEditor::erasing(C UID &elm_id) {if(elm && elm->id==elm_id)set(null);}
  192. ImageAtlasEditor::ImageAtlasEditor() : elm_id(UIDZero), elm(null), changed(false), changed_file(false), undos(true) {}
  193. ImageAtlasEditor::ListElm::ListElm() : removed(false), color(BLACK), img_id(UIDZero) {}
  194. /******************************************************************************/