Image.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. ImageEditor ImageEdit;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. ::ImageEditor::ImageMode ImageEditor::ImageModes[]=
  8. {
  9. {IMAGE_2D , "2D Texture", null},
  10. {IMAGE_CUBE, "Cube Texture", u"SkyBox"},
  11. {IMAGE_SOFT, "Software", u"This mode is used for custom processing only\nIt cannot be used for drawing"},
  12. };
  13. cchar8 *ImageEditor::Channels[]=
  14. {
  15. "RGBA", "RGB", "A",
  16. };
  17. int ImageEditor::ChannelsElms=Elms(Channels);
  18. /******************************************************************************/
  19. void ImageEditor::Render() {}
  20. GuiObj* ImageEditor::GuiImage2::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel){return (image && image->mode()==IMAGE_CUBE) ? ::EE::GuiObj::test(gpc, pos, mouse_wheel) : null;}
  21. void ImageEditor::GuiImage2::update(C GuiPC &gpc)
  22. {
  23. if(Gui.ms()==this && Ms.b(0))
  24. {
  25. cam.yaw -=Ms.d().x;
  26. cam.pitch+=Ms.d().y;
  27. cam.setSpherical().updateVelocities(CAM_ATTACH_FREE);
  28. Ms.freeze();
  29. }else
  30. if(visible())
  31. {
  32. cam.yaw+=Time.ad()/2;
  33. cam.setSpherical().updateVelocities(CAM_ATTACH_FREE);
  34. }
  35. }
  36. void ImageEditor::GuiImage2::draw(C GuiPC &gpc)
  37. {
  38. if(visible() && gpc.visible)
  39. {
  40. Rect rect=T.rect()+gpc.offset;
  41. if(image)
  42. {
  43. D.clip(rect&gpc.clip);
  44. if(image->mode()==IMAGE_CUBE)
  45. {
  46. int clouds =Clouds.layered.layers(); Clouds.layered.set(0);
  47. AMBIENT_MODE ambient =D. ambientMode(); D. ambientMode(AMBIENT_FLAT);
  48. DOF_MODE dof =D. dofMode(); D. dofMode( DOF_NONE);
  49. bool eye_adapt=D.eyeAdaptation(); D.eyeAdaptation( false);
  50. bool astros =AstrosDraw ; AstrosDraw =false;
  51. bool ocean =Water.draw ; Water.draw =false;
  52. bool fog =Fog .draw ; Fog .draw =false;
  53. flt fov=D.viewFov(); Camera c=ActiveCam;
  54. D.viewRect(rect).viewFov(DefaultFOV); cam.set();
  55. Sky.skybox(image);
  56. CurrentEnvironment().bloom.set();
  57. Renderer(ImageEditor::Render);
  58. Sky.atmospheric();
  59. D.viewRect(null).viewFov(fov); c.set();
  60. D. dofMode(dof );
  61. D. ambientMode(ambient );
  62. D.eyeAdaptation(eye_adapt);
  63. AstrosDraw =astros;
  64. Water.draw =ocean;
  65. Fog .draw =fog;
  66. Clouds.layered.set(clouds);
  67. }else
  68. {
  69. Rect r=rect;
  70. if(ImageEdit.no_scale)
  71. {
  72. r.setC(r.center(), D.pixelToScreenSize(image->size()));
  73. D.alignScreenToPixel(r);
  74. }
  75. ALPHA_MODE alpha=D.alpha(ImageEdit.channels ? ALPHA_NONE : ALPHA_BLEND);
  76. if(ImageEdit.channels==2)VI.shader(ShaderFiles("Main")->get("DrawTexW"));
  77. image->drawFit(color, color_add, r);
  78. D.alpha(alpha);
  79. }
  80. }
  81. D.clip(gpc.clip);
  82. rect.draw(rect_color, false);
  83. if(ImageEdit.elm && ImageEdit.elm->importing()){TextStyleParams ts; ts.size*=0.6f; ts.align.set(0, 1); D.text(ts, rect.down(), "Reloading");}
  84. }
  85. }
  86. ::ImageEditor::CubeFace& ImageEditor::CubeFace::create(DIR_ENUM dir, int x, int y)
  87. {
  88. ::EE::GuiImage::create().desc(DirToText(dir));
  89. T.face=dir;
  90. T.ofs.set(x, y);
  91. return T;
  92. }
  93. void ImageEditor::CubeFace::draw(C GuiPC &gpc)
  94. {
  95. if(visible() && gpc.visible)
  96. {
  97. Rect rect=T.rect()+gpc.offset;
  98. if(image && image->mode()==IMAGE_CUBE)
  99. {
  100. D.clip(rect&gpc.clip);
  101. image->drawCubeFace(WHITE, TRANSPARENT, rect, face);
  102. }
  103. D.clip(gpc.clip);
  104. rect.draw(ColorAlpha(rect_color, 0.25f), false);
  105. }
  106. }
  107. void ImageEditor::Change::create(ptr user)
  108. {
  109. if(ElmImage *d=ImageEdit.data())data=*d;
  110. ImageEdit.undoVis();
  111. }
  112. void ImageEditor::Change::apply(ptr user)
  113. {
  114. if(ElmImage *d=ImageEdit.data())d->undo(data);
  115. ImageEdit.setChanged();
  116. ImageEdit.toGui();
  117. ImageEdit.undoVis();
  118. }
  119. void ImageEditor::undoVis() {SetUndo(undos, undo, redo);}
  120. ElmImage* ImageEditor::data()C {return elm ? elm->imageData() : null;}
  121. void ImageEditor::PreChanged(C Property &prop) {ImageEdit.undos.set(&prop);}
  122. void ImageEditor::Changed(C Property &prop) {ImageEdit.setChanged();}
  123. void ImageEditor::Type( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){int i=TextInt(t); if(InRange(i, ElmImage::NUM))d->type=ElmImage::TYPE(i); d->type_time.getUTC();}}
  124. Str ImageEditor::Type(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->type; return -1;}
  125. void ImageEditor::Mode( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){int i=TextInt(t); if(InRange(i, ImageModes)){d->mode=ImageModes[i].mode; d->mode_time.getUTC();}}}
  126. Str ImageEditor::Mode(C ImageEditor &ie ) {if(ElmImage *d=ie.data())REPA(ImageModes)if(ImageModes[i].mode==d->mode)return i; return -1;}
  127. void ImageEditor::MipMaps( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){d->mipMaps(TextBool(t)); d->mip_maps_time.getUTC();}}
  128. Str ImageEditor::MipMaps(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->mipMaps(); return S;}
  129. void ImageEditor::Pow2( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){d->pow2(TextBool(t)); d->pow2_time.getUTC();}}
  130. Str ImageEditor::Pow2(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->pow2(); return S;}
  131. void ImageEditor::Width( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){d->size.x=TextInt(t); d->size_time.getUTC();}}
  132. Str ImageEditor::Width(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->size.x; return S;}
  133. void ImageEditor::Height( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){d->size.y=TextInt(t); d->size_time.getUTC();}}
  134. Str ImageEditor::Height(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->size.y; return S;}
  135. void ImageEditor::AlphaLum( ImageEditor &ie, C Str &t) {if(ElmImage *d=ie.data()){d->alphaLum(TextBool(t)); d->alpha_lum_time.getUTC();}}
  136. Str ImageEditor::AlphaLum(C ImageEditor &ie ) {if(ElmImage *d=ie.data())return d->alphaLum(); return S;}
  137. void ImageEditor::Undo(ImageEditor &editor) {editor.undos.undo();}
  138. void ImageEditor::Redo(ImageEditor &editor) {editor.undos.redo();}
  139. void ImageEditor::Locate(ImageEditor &editor) {Proj.elmLocate(editor.elm_id);}
  140. void ImageEditor::setMipMap(bool on) {undos.set("mipMap"); MipMaps(T, on); setChanged(); toGui();}
  141. void ImageEditor::create()
  142. {
  143. ListColumn lct[]=
  144. {
  145. ListColumn(MEMBER(NameDesc, name), LCW_MAX_DATA_PARENT, "Name"),
  146. };
  147. ListColumn lcm[]=
  148. {
  149. ListColumn(MEMBER(ImageMode, name), LCW_MAX_DATA_PARENT, "name"),
  150. };
  151. add("Type" , MemberDesc( ).setFunc(Type , Type )).setEnum().combobox.setColumns(lct, Elms(lct)).setData(ElmImage::ImageTypes, ElmImage::ImageTypesElms).menu.list.setElmDesc(MEMBER(NameDesc, desc));
  152. add("Mip Maps" , MemberDesc(DATA_BOOL).setFunc(MipMaps , MipMaps ));
  153. add("Power of 2" , MemberDesc(DATA_BOOL).setFunc(Pow2 , Pow2 )).desc("Resize image to nearest power of 2");
  154. add("Alpha from Luminance", MemberDesc(DATA_BOOL).setFunc(AlphaLum, AlphaLum)).desc("Set image opacity from its brightness");
  155. add("Mode" , MemberDesc( ).setFunc(Mode , Mode )).setEnum().combobox.setColumns(lcm, Elms(lcm)).setData(ImageModes, Elms(ImageModes)).menu.list.setElmDesc(MEMBER(ImageMode, desc));
  156. add("Width" , MemberDesc(DATA_INT ).setFunc(Width , Width )).range(-1, 65536).desc("Set custom image width (0=default, -1=keep original)");
  157. add("Height" , MemberDesc(DATA_INT ).setFunc(Height , Height )).range(-1, 65536).desc("Set custom image height (0=default, -1=keep original)");
  158. add();
  159. add("Info:");
  160. width =&add();
  161. height =&add();
  162. type =&add();
  163. mip_maps=&add();
  164. mem_size=&add();
  165. add();
  166. add("Display:");
  167. chn =&add("Channels", MemberDesc(MEMBER(ImageEditor, channels))).setEnum(Channels, Elms(Channels));
  168. nos =&add("No Scale", MemberDesc(MEMBER(ImageEditor, no_scale)));
  169. src =&add("Source" , MemberDesc(MEMBER(ImageEditor, source ))).desc("Display source cube face images separately");
  170. autoData(this);
  171. flt h=0.043f;
  172. ::PropWin::create("Image Editor", Vec2(0.02f, -0.07f), 0.036f, h, 0.28f); ::PropWin::changed(Changed, PreChanged); chn->changed(null, null); nos->changed(null, null); src->changed(null, null);
  173. button[1].show(); button[2].func(HideProjAct, SCAST(GuiObj, T)).show(); flag|=WIN_RESIZABLE;
  174. T+=undo .create(Rect_LU(0.02f, -0.01f , 0.05f, 0.05f)).func(Undo, T).focusable(false).desc("Undo"); undo.image="Gui/Misc/undo.img";
  175. T+=redo .create(Rect_LU(undo.rect().ru(), 0.05f, 0.05f)).func(Redo, T).focusable(false).desc("Redo"); redo.image="Gui/Misc/redo.img";
  176. T+=locate.create(Rect_LU(redo.rect().ru()+Vec2(0.01f, 0), 0.14f, 0.05f), "Locate").func(Locate, T).focusable(false).desc("Locate this element in the Project");
  177. src->move(Vec2(0, h*2));
  178. T+=gui_image.create(); gui_image.moveToBottom();
  179. T+=cube_faces[0].create(DIR_LEFT , 0, -1);
  180. T+=cube_faces[1].create(DIR_FORWARD, 1, -1);
  181. T+=cube_faces[2].create(DIR_RIGHT , 2, -1);
  182. T+=cube_faces[3].create(DIR_BACK , 3, -1);
  183. T+=cube_faces[4].create(DIR_DOWN , 1, -2);
  184. T+=cube_faces[5].create(DIR_UP , 1, 0);
  185. rect(Rect_C(0, 0, Min(1.7f, D.w()*2), Min(1.07f, D.h()*2)));
  186. }
  187. void ImageEditor::make2D()
  188. {
  189. gui_image.image=((data() && data()->mode==IMAGE_SOFT) ? &image_2d : game_image); REPAO(cube_faces).image=gui_image.image;
  190. image_2d.del();
  191. if(gui_image.image==&image_2d && game_image)game_image->copyTry(image_2d, -1, -1, 1, IMAGE_R8G8B8A8, IMAGE_2D);
  192. }
  193. void ImageEditor::setInfo()
  194. {
  195. if(width )width ->name.set(S+"Width: " + (game_image ? game_image->w () : 0));
  196. if(height )height ->name.set(S+"Height: " + (game_image ? game_image->h () : 0));
  197. if(type )type ->name.set(S+"Type: " + ImageTI[game_image ? game_image->type () : IMAGE_NONE].name);
  198. if(mip_maps)mip_maps->name.set(S+"Mip Maps: "+ (game_image ? game_image->mipMaps () : 0));
  199. if(mem_size)mem_size->name.set(S+"Size: " +FileSize(game_image ? game_image->typeMemUsage() : 0)); // use 'typeMemUsage' because we need this only for stats
  200. if(chn )chn->visible(data() && data()->mode!=IMAGE_CUBE);
  201. if(nos )nos->visible(data() && data()->mode!=IMAGE_CUBE);
  202. if(src )src->visible(data() && data()->mode==IMAGE_CUBE);
  203. REPAO(cube_faces).visible(src && src->visible() && source);
  204. }
  205. void ImageEditor::update(C GuiPC &gpc)
  206. {
  207. ::EE::ClosableWindow::update(gpc);
  208. if(gpc.visible && visible())setInfo();
  209. }
  210. ImageEditor& ImageEditor::hide( ) {set(null); ::PropWin::hide(); return T;}
  211. Rect ImageEditor::sizeLimit( )C {Rect r=::EE::Window::sizeLimit(); r.min.set(0.7f, 0.26f); return r;}
  212. ImageEditor& ImageEditor::rect(C Rect &rect)
  213. {
  214. ::EE::Window::rect(rect);
  215. flt x=0; if(props.elms())x=props[0].combobox.rect().max.x;
  216. gui_image.rect(Rect(x, -clientHeight(), clientWidth(), 0).extend(-0.02f));
  217. Rect r=gui_image.rect();
  218. flt face_size=(r.size()/Vec2(4, 3)).min();
  219. REPAO(cube_faces).rect(Rect_LU(r.lu()+cube_faces[i].ofs*face_size, face_size));
  220. return T;
  221. }
  222. void ImageEditor::flush()
  223. {
  224. if(elm && changed)
  225. {
  226. if(ElmImage *data=T.data())data->newVer(); // modify just before saving/sending in case we've received data from server after edit
  227. if(game_image){Save(*game_image, Proj.gamePath(*elm)); Proj.savedGame(*elm);}
  228. Server.setElmShort(elm->id);
  229. }
  230. changed=false;
  231. }
  232. void ImageEditor::setChanged()
  233. {
  234. if(elm)
  235. {
  236. changed=true;
  237. if(ElmImage *data=T.data())
  238. {
  239. data->newVer();
  240. if(!edit_image.is())edit_image.ImportTry(Proj.editPath(*elm));
  241. if( game_image)EditToGameImage(edit_image, *game_image, *data);
  242. make2D();
  243. }
  244. }
  245. }
  246. void ImageEditor::set(Elm *elm)
  247. {
  248. if(elm && elm->type!=ELM_IMAGE)elm=null;
  249. if(T.elm!=elm)
  250. {
  251. flush();
  252. undos.del(); undoVis();
  253. T.elm =elm;
  254. T.elm_id=(elm ? elm->id : UIDZero);
  255. edit_image.del();
  256. if(elm)game_image=Proj.gamePath(*elm);else game_image.clear();
  257. toGui();
  258. make2D();
  259. setInfo();
  260. Proj.refresh(false, false);
  261. visible(T.elm!=null).moveToTop();
  262. }
  263. }
  264. void ImageEditor::activate(Elm *elm) {set(elm); if(T.elm)::EE::GuiObj::activate();}
  265. void ImageEditor::toggle(Elm *elm) {if(elm==T.elm)elm=null; set(elm);}
  266. void ImageEditor::elmChanged(C UID &elm_id)
  267. {
  268. if(elm && elm->id==elm_id)
  269. {
  270. undos.set(null, true);
  271. edit_image.del(); toGui(); make2D(); setInfo(); // delete 'edit_image' so it will be reloaded when needed
  272. }
  273. }
  274. void ImageEditor::ImageName::set(C Str &name, C Str &file) {T.name=name; T.file=file;}
  275. int ImageEditor::FaceToIndex(DIR_ENUM dir)
  276. {
  277. REPA(cube_faces)if(cube_faces[i].face==dir)return i;
  278. return -1;
  279. }
  280. void ImageEditor::setImage(Memc<ImageName> &images, GuiObj *obj)
  281. {
  282. if(ElmImage *d=data())
  283. if(images.elms())
  284. {
  285. Str import=images[0].file;
  286. if(d->mode==IMAGE_CUBE)
  287. {
  288. if(images.elms()>1) // multi
  289. {
  290. import=elm->srcFile();
  291. REPA(images)
  292. {
  293. DIR_ENUM dir=DIR_NUM;
  294. C Str &name=images[i].name;
  295. if(Contains(name, "front" ) || Contains(name, "forward"))dir=DIR_FORWARD;else
  296. if(Contains(name, "back" ) )dir=DIR_BACK ;else
  297. if(Contains(name, "top" ) || Contains(name, "up" ))dir=DIR_UP ;else
  298. if(Contains(name, "bottom") || Contains(name, "down" ))dir=DIR_DOWN ;else
  299. if(Contains(name, "left" ) )dir=DIR_LEFT ;else
  300. if(Contains(name, "right" ) )dir=DIR_RIGHT ;
  301. import=SetCubeFile(import, FaceToIndex(dir), images[i].file);
  302. }
  303. }else
  304. REPA(cube_faces)if(cube_faces[i].contains(obj)) // check if cube face is selected
  305. {
  306. import=SetCubeFile(elm->srcFile(), i, images[0].file);
  307. break;
  308. }
  309. }
  310. elm->setSrcFile(import); Server.setElmShort(elm_id); Proj.elmReload(elm_id);
  311. }
  312. }
  313. void ImageEditor::drop(Memc<Str> &names, GuiObj *obj, C Vec2 &screen_pos)
  314. {
  315. if(contains(obj))
  316. {
  317. Memc<ImageName> images;
  318. REPA(names)if(ExtType(GetExt(names[i]))==EXT_IMAGE)images.New().set(GetBaseNoExt(names[i]), names[i]);
  319. setImage(images, obj);
  320. }
  321. }
  322. void ImageEditor::drag(Memc<UID> &elms, GuiObj *obj, C Vec2 &screen_pos)
  323. {
  324. if(contains(obj))
  325. {
  326. Memc<ImageName> images;
  327. REPA(elms)if(Elm *image=Proj.findElm(elms[i], ELM_IMAGE))if(elm!=image)images.New().set(image->name, EncodeFileName(image->id));
  328. setImage(images, obj);
  329. }
  330. }
  331. void ImageEditor::erasing(C UID &elm_id) {if(elm && elm->id==elm_id)set(null);}
  332. ImageEditor::ImageEditor() : elm_id(UIDZero), elm(null), changed(false), no_scale(false), source(true), channels(0), width(null), height(null), type(null), mip_maps(null), mem_size(null), chn(null), nos(null), src(null), undos(true) {}
  333. ImageEditor::CubeFace::CubeFace() : ofs(0), face(DIR_RIGHT) {}
  334. /******************************************************************************/