From 9d32e29ffb3f32eef205e24091a7c356bf9e4a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 19 Jan 2020 17:17:09 -0300 Subject: [PATCH] Added TexturePacker console tool and updated to a new version of the Texture Atlas format. More premake5 project refactor. Fixed some Stysheet Properties types and fixed some StyleSheetProperty transitions. --- .gitignore | 17 +- bin/assets/atlases/bnb.eta | Bin 29772 -> 45644 bytes bin/assets/atlases/tiles.eta | Bin 852 -> 1300 bytes bin/assets/atlases/tiles.png | Bin 21384 -> 21422 bytes bin/assets/ui/uitheme.eta | Bin 11172 -> 17124 bytes bin/assets/ui/uitheme1.5x.eta | Bin 11172 -> 17124 bytes bin/assets/ui/uitheme2x.eta | Bin 11172 -> 17124 bytes include/eepp/graphics/packerhelper.hpp | 2 +- include/eepp/graphics/textureatlasloader.hpp | 16 +- include/eepp/graphics/texturepacker.hpp | 108 +++--- include/eepp/ui/css/mediaquery.hpp | 12 - premake4.lua | 76 +++-- premake5.lua | 320 ++++++++---------- projects/emscripten/make.sh | 6 +- projects/linux/ee.creator.user | 136 ++++++-- projects/linux/ee.files | 1 + src/eepp/graphics/fonttruetype.cpp | 19 +- src/eepp/graphics/textureatlasloader.cpp | 28 +- src/eepp/graphics/texturepacker.cpp | 124 +++---- src/eepp/system/time.cpp | 2 +- src/eepp/ui/css/mediaquery.cpp | 19 +- .../ui/css/stylesheetpropertytransition.cpp | 4 +- src/eepp/ui/css/stylesheetspecification.cpp | 58 ++-- src/eepp/ui/uiscenenode.cpp | 10 +- src/eepp/ui/uiwidget.cpp | 2 +- .../backend/SDL2/displaymanagersdl2.cpp | 10 +- src/eepp/window/backend/SDL2/windowsdl2.cpp | 5 +- src/tools/mapeditor/mapeditor.cpp | 18 +- .../textureatlaseditor/textureatlaseditor.cpp | 17 +- src/tools/texturepacker/texturepacker.cpp | 173 ++++++++++ 30 files changed, 746 insertions(+), 437 deletions(-) create mode 100644 src/tools/texturepacker/texturepacker.cpp diff --git a/.gitignore b/.gitignore index dd7f5d0ad..436c671c6 100644 --- a/.gitignore +++ b/.gitignore @@ -24,21 +24,8 @@ projects/android-project-ant/libs src/examples/strobe src/thirdparty/SDL2-2.0.10* *.dll -eees* -eeew* -eetest* -eesound* -eesprite* -eefonts* -eevbo-fbo-batch* -eephysics* -eestrobe* -eeiv* -eehttp-request* -eepp-TextureAtlasEditor* -eepp-UIEditor* -bin/eeui-hello-world* -bin/eepp-MapEditor* +bin/ee* +bin/eepp-* ee.tag log.log external_projects.lua diff --git a/bin/assets/atlases/bnb.eta b/bin/assets/atlases/bnb.eta index 5a3915aea7b6e0626abbc846339b82afc95a4aab..9ee60a3884cad333bc719f58d25cc3a4cbdb1dc9 100644 GIT binary patch literal 45644 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 diff --git a/bin/assets/atlases/tiles.eta b/bin/assets/atlases/tiles.eta index b644a0114adcb198cbf6b98dc7a3f698e370219c..3ddda2f949a58f22920ba1f4672b4752872ff5a3 100644 GIT binary patch literal 1300 zcmZ>D4RO4{&cKk%qY}pe1dKq;1jG$c45S#?Km-~n$;?SD)+@+MM-!(PcjvuleCvWC zZZo8pr8w+K7m@*o9ZXsQ$N*s$AilO06q*pA0Hi<|1VG_z1ZE8!0duzk)CnLOghB4U zj>p}`K>2|LFn2pZ9iafEK^Wxj8+hDp0+b&}0CRT&)Da3m8iYaazKO@(ra<|D1Tc4l g+@OGjLGHeV$K7T?`GEv5cPjuLfs8@!zKzG-0MB+GqW}N^ delta 140 zcmbQjb%jmV)iuQN1v3Lf5BJ6h1|VPrVkRg5qs$CMH!t&}otZ;~?Y zQ;8!&+2(!UmZ_A3q9O*_&CG9pf6UAuGoN$L^UQr;*L`32^<;zuEn*m1836#mSh9G* zD*Y$=|1SfI{=G6FvJL=N?_RP%v?h6Tv}^sWaoupQgkozOkk0BAcui>PaQx-VdiB^l zKgzVNCh0AbR36Xc9&bW7oZZ^l)Iu*$orobiV&g`}ep|y-s&(c05?A36i!vqBHhsAF ztEX6g4;a+NAzPwiM*7;R(sPfe!c=F!%1%}m+H}O4_ycryUZXd71YwBL93os0mp3e}?Tb0|Y8DB>aZ?>UJFfHk)PIrXyL)$`6 zDocqoHbY`ZbOqAZ*X_ajZv&St?em(L7&I*$V!?hs?l5gYkX{l|?#c6_fto&3c98!1 zu~8?_nnWvhjxu0pOH*ks+q$w`P>v?(c;a1ZsIt!)_ObL)PO#{bR4?dDHJLsxpa&PE zLeGxC@f4a;Q%vs_NJvGR8oXv2uI}pep{(2y5;hSzGSF)YmjL#a*J>o3Z(GQm%>g>n z!_yd+_fr7-%`lY$1$LF^n*?az&=KssHT!OPDo@Vy@B~aMJDVan3jR|p(y0MY+&blp zor7JKdi(=7y|+aI+oyAW$Xe)$iS@!@Z8Sj&{Cb2{fMSE$t(wmz^wQE&947}FSu0mx zZKD?pcNYYd!%mbCJ5A)tGsaQI=Z#~KxVR`|i;lPv=KuZ-#JS@gWhsNlMJq){iP|oo zBzEcqDc#A`3!X8PAJs7FuG{r@P6ZmGX!1FBUO^oZfY_wVE;e;UCC?K5#+uNJ+ zPO`DosOXa?jiX0~ew$W4;Yv_&(4_E$xl7|~H7l2s3Rbp#=q(oxW)Zc~v2955z%MHA zWf;5cU>riUevc&DBBMrX)U^2CB&13cWo&9m8tdXJ-4lhkQO@@d5}9?XSE&wIUR0;&poOIy(sp)YjR!+xbS5+@_D5KR=*M2c1|RvQ?ij86qRLx+DU&*Nt-#ToaQ#*uhnLNU&S|RG7=9 zDjx3B{4!OhZl(mvPK$2*S1yrMJk^7TJ8sj|C?5XmN3oc_ow9v%Y`VKX-0geaD{EN# zn~e+j@1&5`ncI1Jn4>jsuv{{pgIUJUwsbb-2~#2XJS+EP8L-RW@?-<-4HxSE^FgLY zZW-zS?p#@SUck;>pNnQ(H2gtvO1H$DZxp&z*x~Mt>W;w!$f1#=o&0xzll+=!E&hBj7kvk@6#P!=-

95^(Y#)7-Q$ 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 G(*FYs18`OV diff --git a/bin/assets/ui/uitheme.eta b/bin/assets/ui/uitheme.eta index 652bc1687b5fa9b3692c200750d919548f3bd7e7..f012f8540598586ef1649e0a23feb24bd24b8dfa 100644 GIT binary patch delta 2021 zcmZvcD{vZ76ow&TVHXxy-peBi2_)H&=?tO*NvEZy@1#u|`eN1J zG1EOHZ}{HW`Q{swe&GW(*F`LziBIi8m>!_u73r~)hlo$4nv=`KH9s~w^4FbuiS%j! z*V7L?cj`sbi}Fh+_Y&{Qubf;UzLvQj8SUUlQ_J)e>28BpCfhVFO;8W#>cGl=t>)`?$RvLv}) z#X&W#1W3G0fKhBD!Sh8Dn5n1uhRssEmx{_4IZ@#5dO+$2~!TDCtKvVl?IGkoNh*f5b>w@Bjb+ delta 1125 zcmYL|Jy6nd7{`72msn&Ng&>M3qJL2oO_R!cprYuV$`T4XMu!GQh6a}I7#e)|FSyxV z10z$%HL=MSqa)WjFgh}NexEy@?YYl=f8Xczclu-S_ntkG*o}9G2L`&1;~d++aU;w$ zV|e}^W~}7k7bcJK{oiS}GL&U<8^^U@8LKgrW10ZA3d3KST*6Hw#WXLxW4vPuh)wm9 z^3-MJwvmq)so>chdBPMCebM%eDJ*eh^aInZ;rw%$v$~^inS#QPuDoVilsJ9$4by_e z4!iod?8-~mo-(b9COY<*X{ka#I@_1H}6O?tq6CIt519UIn%Q6@{N~FOVV%5 z`HIOD-gBa_i?Lbto1d6`!uN0OGWkXCcR_hCtSp0)`MJj+X{2XQQN!FK@ z@2@ELhfy=$o`lm(Q_}Cjs-Agrt)I6N(Nv8{A6tcWj1V^F#tWv9jI*|mL z6bbg0fl_t>Wy|%8DJQ=jq0BJDU{m8c;)q=VvP`MTa@BjxYP^w!%+1moX~0~Z>IU|&(pT^)-!zbSq4O^x&xvz-2uBQ?}Cr&7{Ou|#A28QJ##sr>?5e` Xf%5hq*s7RE`OAYri#!N_NR zb$rQ|7o~;d*U#BqmvmbEb!bMqKDb+ejsL#?y^QC&6KbbJm@IdHbagmv&6&xbPs-IZ z7}KSFaxf|Z_gs2SfEO+0uQ5jSI%C*-58Gc+>5UMeqeja9lz;#NM&AJeZt2_qEX;b} zD+0!lQMj>7z&HZ2n|lQK5Re_rN7ca?>03`|WEw|;{o4f0BGBmHAz%i9;sA4+ke?A_ z3K{AkyQMbxoEUy&WQJZ6FoBtdoKXTaWHg;3F-W~M{FWFBGLA=L1gNN?DPjb^+?n!* z7#?JtxJ0H{CbeB7=VlURH}R)B{qHEs5llZl#eiTy)Dtus0kIX}qd3ic zBxaa~s0aV5EDoy*w~wO-O64pn;BvPiDY8uaHjZ(K_VuQ zNF)-8tVB#yB9Q}bbH3!sBNv)X{%Q85-1f%| zk#!!Jzobj}m-PII=9+B&g(GE$%!<3oSs2*V{gty2u+pBvSrFKG@5*AEGFgDy{#zT& z037ZUO2tDcd!B|B&Wyw^dLTTu5V#3I(vI-d$wlBR;hn{qp#p1p-&ky$1K`s8+77)g z*Y=gnhOchN0?>tz=(Z+O(wSJZCt!vI^~zG!$z|XZ>4}s3f$M(S;K={XsrP|i4N%?m z1J9jmFQ`TNrIUMrcjZ@hzF97KfVF&Mac00mne8B&mU$O^&vhxtX@qd>ZRpz4ZAOv? zVLgmzHxJ{46$K}pDn!Ck1ScFv2%#3m!eJCwR${nvFZS88!i>ny$smsJsuTafWpOaP ziW9xG61eU%LF`{6NklJ_*hwvg2Q^D!CuJ44I8lk)(bL35kJ3bsYUU$%9Rt_>3=u76 zvFmR38xOuemv#0#XZPQNb`Ip*a8fzKO;3-ouB4$A zF~`~qD<6E=1jwl!)0a6srte-kp)b65Lh1*3THeXyXISNN+pPlLk!1l}Zk*Eg7N_KA xw{}M2*%`4a<#Rgq+6OskyxizkHzxGzQ4`3 z4_uEhjT!D=dl@s?waqkaeENO7RqB4t5mg7cL~37DN;4PcTI!KIy;96q2}lQS)Z)_nCsiT?6WKFz|qB zPI&RsBc@sDH|}`MG$Xw2*f<^G>DbKLAbP|&cZOavd4>C&(10I0*O`36cZbohjNjGK zm)t6^yH%bWQF*|l{Kx~2b(KduHfCxJKHygG7L!ZTHoRCbO3sgGm^`wUs1Kefr{#kW z;>rZZ41Ic1HFiJpf;auT-oljDADf0hd`_mZQs}EQcqZW4S@m}XHkn4Go`V21sJ}Re zdJxBhZE?p@WaDLNCi%RbIWRarTz}L)V)2ez2x@i*bDvanieO(*Iezz4RCD Cmb6;{ diff --git a/include/eepp/graphics/packerhelper.hpp b/include/eepp/graphics/packerhelper.hpp index 49b5c3e9c..2fbcc6931 100644 --- a/include/eepp/graphics/packerhelper.hpp +++ b/include/eepp/graphics/packerhelper.hpp @@ -7,7 +7,7 @@ namespace EE { namespace Graphics { namespace Private { #pragma pack( push, 1 ) -#define HDR_NAME_SIZE 64 +#define HDR_NAME_SIZE 128 struct sTextureRegionHdr { char Name[HDR_NAME_SIZE]; diff --git a/include/eepp/graphics/textureatlasloader.hpp b/include/eepp/graphics/textureatlasloader.hpp index e2310b4cb..bc8a4ca62 100644 --- a/include/eepp/graphics/textureatlasloader.hpp +++ b/include/eepp/graphics/textureatlasloader.hpp @@ -125,11 +125,17 @@ class EE_API TextureAtlasLoader { /** @return True if the texture atlas is loading. */ const bool& isLoading() const; - /** @brief The function will check if the texture atlas is updated. - Checks if all the images inside the images path are inside the texture atlas, and if they - have the same date and size, otherwise it will recreate or update the texture atlas. - */ - bool updateTextureAtlas( std::string TextureAtlasPath, std::string ImagesPath ); + /** The function will check if the texture atlas is updated. Checks if all the images inside the + * images path are inside the texture atlas, and if they have the same date and size, otherwise + * it will recreate or update the texture atlas. + * + * @param TextureAtlasPath The path to the texture atlas ( the ".eta" file ) + * @param ImagesPath The directory where the source images are located. + * @param maxImageSize Maximum texture size allowed for the new texture atlas created. Default + * value will use the current image size. + */ + bool updateTextureAtlas( std::string TextureAtlasPath, std::string ImagesPath, + Sizei maxImageSize = Sizei::Zero ); /** Rewrites the texture atlas file. Usefull if the TextureRegions where modified and need to be * updated inside the texture atlas. */ diff --git a/include/eepp/graphics/texturepacker.hpp b/include/eepp/graphics/texturepacker.hpp index 8f1022b97..77e129ff1 100644 --- a/include/eepp/graphics/texturepacker.hpp +++ b/include/eepp/graphics/texturepacker.hpp @@ -50,41 +50,65 @@ class EE_API TexturePacker { public: static TexturePacker* New(); + /** Creates a new instance of the texture packer indicating the maximum size of the texture + *atlas. + * @param maxWidth The maximum width that the texture atlas will use. + * @param maxHeight The maximum height that the texture atlas will use. + * @param pixelDensity Indicates the device pixel density that represents the resources that + *will the packer pack. + * @param textureFilter Indicates with texture filter should be used when the texture of the + *atlas is loaded. + * @param forcePowOfTwo Indicates that if the max with and height must be adjusted to fit a + *power of two texture. + * @param scalableSVG True if SVG images are scaled to the packer PixelDensity + * @param pixelBorder Indicates how many pixels will be added to separate one image to another + *in the texture atlas. Usefull to avoid artifacts when rendered scaled TextureRegions. Use at + *least 1 pixel to separate images if you will scale any TextureRegion. + * @param allowChilds When enabled if the atlas does not have enough space left in the image to + *put more resources it will create a new image atlas and add the rest of the images in that + *images, repeating this process recursivelly until using all source images. + * @param allowFlipping Indicates if the images can be flipped inside the texture atlas. This + *is not compatible with eepp ( since it can't flip the textures back to the original + *orientation ). So avoid it for eepp. + */ static TexturePacker* - New( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity = PixelDensitySize::MDPI, - const bool& ForcePowOfTwo = true, const bool& scalableSVG = false, - const Uint32& PixelBorder = 0, + New( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity = PixelDensitySize::MDPI, + const bool& forcePowOfTwo = true, const bool& scalableSVG = false, + const Uint32& pixelBorder = 2, const Texture::TextureFilter& textureFilter = Texture::TextureFilter::Linear, - const bool& AllowFlipping = false ); + const bool& allowChilds = false, const bool& allowFlipping = false ); /** Creates a new texture packer ( you will need to call SetOptions before adding any texture or * image ). */ TexturePacker(); - /** Creates a new texture packer indicating the size of the texture atlas. - * @param MaxWidth The maximum width that the texture atlas will use. - * @param MaxHeight The maximum height that the texture atlas will use. - * @param PixelDensity Indicates the device pixel density that represents the resources that + /** Creates a new texture packer indicating the maximum size of the texture atlas. + * @param maxWidth The maximum width that the texture atlas will use. + * @param maxHeight The maximum height that the texture atlas will use. + * @param pixelDensity Indicates the device pixel density that represents the resources that *will the packer pack. * @param textureFilter Indicates with texture filter should be used when the texture of the - *atlas is loaded - * @param ForcePowOfTwo Indicates that if the max with and height must be adjusted to fit a + *atlas is loaded. + * @param forcePowOfTwo Indicates that if the max with and height must be adjusted to fit a *power of two texture. * @param scalableSVG True if SVG images are scaled to the packer PixelDensity - * @param PixelBorder Indicates how many pixels will be added to separate one image to another + * @param pixelBorder Indicates how many pixels will be added to separate one image to another *in the texture atlas. Usefull to avoid artifacts when rendered scaled TextureRegions. Use at *least 1 pixel to separate images if you will scale any TextureRegion. - * @param AllowFlipping Indicates if the images can be flipped inside the texture atlas. This + * @param allowChilds When enabled if the atlas does not have enough space left in the image to + *put more resources it will create a new image atlas and add the rest of the images in that + *images, repeating this process recursivelly until using all source images. + * @param allowFlipping Indicates if the images can be flipped inside the texture atlas. This *is not compatible with eepp ( since it can't flip the textures back to the original *orientation ). So avoid it for eepp. */ - TexturePacker( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity = PixelDensitySize::MDPI, - const bool& ForcePowOfTwo = true, const bool& scalableSVG = false, - const Uint32& PixelBorder = 0, + TexturePacker( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity = PixelDensitySize::MDPI, + const bool& forcePowOfTwo = true, const bool& scalableSVG = false, + const Uint32& pixelBorder = 2, const Texture::TextureFilter& textureFilter = Texture::TextureFilter::Linear, - const bool& AllowFlipping = false ); + const bool& allowChilds = false, const bool& allowFlipping = false ); ~TexturePacker(); @@ -102,12 +126,14 @@ class EE_API TexturePacker { /** After adding all the images that will be used to create the texture atlas. Packing the * textures will generate the texture atlas information ( it will fit the images inside the - * texture atlas, etc ). */ + * texture atlas, etc ). + * @return The amount of pixels used for the new image or the total area used. 0 means it + * failed. + */ Int32 packTextures(); - /** @brief Save the texture atlas to a file, in the indicated format. - * If PackTexture() has not been called, it will be called automatically by the function ( so - *you don't need to call it ). + /** Save the texture atlas to a file, in the indicated format. If PackTexture() has not been + *called, it will be called automatically by the function ( so you don't need to call it ). * @param Filepath The path were it will be saved the new texture atlas. * @param Format The image format of the new texture atlas. * @param SaveExtensions Indicates if the extensions of the image files must be saved. Usually @@ -121,31 +147,34 @@ class EE_API TexturePacker { /** Clear all the textures added */ void close(); - /** First of all you need to set at least the max dimensions of the texture atlas. - * If the instance of the texture packer was created without indicating this data, this must be - *called before adding any texture or image. - * @param MaxWidth The maximum width that the texture atlas will use. - * @param MaxHeight The maximum height that the texture atlas will use. - * @param PixelDensity Indicates the device pixel density that represents the resources that + /** First of all you need to set at least the max dimensions of the texture atlas. If the + *instance of the texture packer was created without indicating this data, this must be called + *before adding any texture or image. + * @param maxWidth The maximum width that the texture atlas will use. + * @param maxHeight The maximum height that the texture atlas will use. + * @param pixelDensity Indicates the device pixel density that represents the resources that *will the packer pack. - * @param scalableSVG True if SVG images are scaled to the packer PixelDensity * @param textureFilter Indicates with texture filter should be used when the texture of the - *atlas is loaded - * @param PixelBorder Indicates how many pixels will be added to separate one image to another + *atlas is loaded. + * @param forcePowOfTwo Indicates that if the max with and height must be adjusted to fit a + *power of two texture. + * @param scalableSVG True if SVG images are scaled to the packer PixelDensity + * @param pixelBorder Indicates how many pixels will be added to separate one image to another *in the texture atlas. Usefull to avoid artifacts when rendered scaled TextureRegions. Use at *least 1 pixel to separate images if you will scale any TextureRegion. - * @param ForcePowOfTwo Indicates that if the max with and height must be adjusted to fit a - *power of two texture. - * @param AllowFlipping Indicates if the images can be flipped inside the texture atlas. This + * @param allowChilds When enabled if the atlas does not have enough space left in the image to + *put more resources it will create a new image atlas and add the rest of the images in that + *images, repeating this process recursivelly until using all source images. + * @param allowFlipping Indicates if the images can be flipped inside the texture atlas. This *is not compatible with eepp ( since it can't flip the textures back to the original *orientation ). So avoid it for eepp. */ - void setOptions( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity = PixelDensitySize::MDPI, - const bool& ForcePowOfTwo = true, const bool& scalableSVG = false, - const Uint32& PixelBorder = 0, + void setOptions( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity = PixelDensitySize::MDPI, + const bool& forcePowOfTwo = true, const bool& scalableSVG = false, + const Uint32& pixelBorder = 2, const Texture::TextureFilter& textureFilter = Texture::TextureFilter::Linear, - const bool& AllowFlipping = false ); + const bool& allowChilds = false, const bool& allowFlipping = false ); /** @return The texture atlas to generate width. */ const Int32& getWidth() const; @@ -169,6 +198,7 @@ class EE_API TexturePacker { Sizei mMaxSize; bool mPacked; bool mAllowFlipping; + bool mAllowChilds; TexturePacker* mChild; Int32 mStrategy; Int32 mCount; diff --git a/include/eepp/ui/css/mediaquery.hpp b/include/eepp/ui/css/mediaquery.hpp index ce509e23b..d9d0a5860 100644 --- a/include/eepp/ui/css/mediaquery.hpp +++ b/include/eepp/ui/css/mediaquery.hpp @@ -9,21 +9,12 @@ namespace EE { namespace UI { namespace CSS { /** Media Queries support is based on the litehtml implementation: * https://github.com/litehtml/litehtml licensed under the New BSD License. */ -#define media_orientation_strings "portrait;landscape" enum MediaOrientation { media_orientation_portrait, media_orientation_landscape, }; -#define media_feature_strings \ - "none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-" \ - "width;max-device-width;device-height;min-device-height;max-device-height;orientation;" \ - "aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-" \ - "ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-" \ - "color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-" \ - "resolution" - enum MediaFeature { media_feature_none, @@ -70,9 +61,6 @@ enum MediaFeature { media_feature_max_resolution, }; -#define media_type_strings \ - "none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv" - enum MediaType { media_type_none, media_type_all, diff --git a/premake4.lua b/premake4.lua index 99324bfda..d5b1af742 100644 --- a/premake4.lua +++ b/premake4.lua @@ -299,7 +299,7 @@ function build_base_configuration( package_name ) set_ios_config() set_xcode_config() - + configuration "debug" defines { "DEBUG" } flags { "Symbols" } @@ -417,7 +417,7 @@ function build_link_configuration( package_name, use_ee_icon ) if _OPTIONS.platform == "ios-cross-x86" then extension = ".x86.ios" end - + if _OPTIONS.platform == "ios-cross-x86_64" then extension = ".x86_64.ios" end @@ -455,7 +455,7 @@ function build_link_configuration( package_name, use_ee_icon ) add_cross_config_links() configuration "emscripten" - linkoptions{ "-O2 -s TOTAL_MEMORY=67108864 -s ASM_JS=1 -s VERBOSE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_SDL=2 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s ERROR_ON_MISSING_LIBRARIES=0 -s FULL_ES3=1 -s \"BINARYEN_TRAP_MODE='clamp'\"" } + linkoptions{ "-O2 -s TOTAL_MEMORY=67108864 -s ASM_JS=1 -s VERBOSE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_SDL=2 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s FULL_ES3=1 -s \"BINARYEN_TRAP_MODE='clamp'\"" } buildoptions { "-fno-strict-aliasing -O2 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=web" } if _OPTIONS["with-gles1"] and ( not _OPTIONS["with-gles2"] or _OPTIONS["force-gles1"] ) then @@ -567,7 +567,9 @@ function add_sdl2() defines { "EE_BACKEND_SDL_ACTIVE", "EE_SDL_VERSION_2" } if not can_add_static_backend("SDL2") then - table.insert( link_list, get_backend_link_name( "SDL2" ) ) + if not os.is_real("emscripten") then + table.insert( link_list, get_backend_link_name( "SDL2" ) ) + end else insert_static_backend( "SDL2" ) end @@ -923,17 +925,44 @@ solution "eepp" files { "src/thirdparty/efsw/src/efsw/*.cpp", osfiles } if os.is("windows") then - excludes { "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } elseif os.is("linux") then - excludes { "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } elseif os.is("macosx") then - excludes { "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" + } elseif os.is("freebsd") then - excludes { "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } end build_base_cpp_configuration( "efsw" ) + -- Library project "eepp-main" kind "StaticLib" language "C++" @@ -957,63 +986,63 @@ solution "eepp" set_kind() language "C++" files { "src/test/*.cpp" } - build_link_configuration( "eetest", true ) + build_link_configuration( "eepp-test", true ) - project "eepp-es" + project "eepp-external-shader" set_kind() language "C++" files { "src/examples/external_shader/*.cpp" } - build_link_configuration( "eees", true ) + build_link_configuration( "eepp-external-shader", true ) - project "eepp-ew" + project "eepp-empty-window" set_kind() language "C++" files { "src/examples/empty_window/*.cpp" } - build_link_configuration( "eeew", true ) + build_link_configuration( "eepp-empty-window", true ) project "eepp-sound" kind "ConsoleApp" language "C++" files { "src/examples/sound/*.cpp" } - build_link_configuration( "eesound", true ) + build_link_configuration( "eepp-sound", true ) project "eepp-sprites" set_kind() language "C++" files { "src/examples/sprites/*.cpp" } - build_link_configuration( "eesprites", true ) + build_link_configuration( "eepp-sprites", true ) project "eepp-fonts" set_kind() language "C++" files { "src/examples/fonts/*.cpp" } - build_link_configuration( "eefonts", true ) + build_link_configuration( "eepp-fonts", true ) project "eepp-vbo-fbo-batch" set_kind() language "C++" files { "src/examples/vbo_fbo_batch/*.cpp" } - build_link_configuration( "eevbo-fbo-batch", true ) + build_link_configuration( "eepp-vbo-fbo-batch", true ) project "eepp-physics" set_kind() language "C++" files { "src/examples/physics/*.cpp" } - build_link_configuration( "eephysics", true ) + build_link_configuration( "eepp-physics", true ) project "eepp-http-request" kind "ConsoleApp" language "C++" files { "src/examples/http_request/*.cpp" } includedirs { "src/thirdparty" } - build_link_configuration( "eehttp-request", true ) + build_link_configuration( "eepp-http-request", true ) project "eepp-ui-hello-world" set_kind() language "C++" files { "src/examples/ui_hello_world/*.cpp" } includedirs { "src/thirdparty" } - build_link_configuration( "eeui-hello-world", true ) + build_link_configuration( "eepp-ui-hello-world", true ) -- Tools project "eepp-textureatlaseditor" @@ -1041,6 +1070,13 @@ solution "eepp" files { "src/tools/uieditor/*.cpp" } build_link_configuration( "eepp-UIEditor", true ) + project "eepp-texturepacker" + kind "ConsoleApp" + language "C++" + includedirs { "src/thirdparty" } + files { "src/tools/texturepacker/*.cpp" } + build_link_configuration( "eepp-TexturePacker", true ) + if os.isfile("external_projects.lua") then dofile("external_projects.lua") end diff --git a/premake5.lua b/premake5.lua index c68c8f394..9798828a3 100644 --- a/premake5.lua +++ b/premake5.lua @@ -35,11 +35,6 @@ function multiple_insert( parent_table, insert_table ) end end -function get_ios_arch() - local archs = string.explode( os.target(), "-" ) - return archs[ table_length( archs ) ] -end - function os_findlib( name ) if os.istarget("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then local path = "/Library/Frameworks/" .. name .. ".framework" @@ -137,7 +132,7 @@ function build_base_configuration( package_name ) filter "action:not vs*" cdialect "gnu99" - buildoptions{ "-Wall" } + buildoptions { "-Wall" } filter "action:vs*" incdirs { "src/thirdparty/libzip/vs" } @@ -151,37 +146,21 @@ function build_base_cpp_configuration( package_name ) set_ios_config() set_xcode_config() + filter "action:not vs*" + buildoptions { "-Wall" } + filter "configurations:debug" defines { "DEBUG" } symbols "On" - if not is_vs() then - buildoptions{ "-Wall" } - end targetname ( package_name .. "-debug" ) filter "configurations:release" optimize "Speed" - if not is_vs() then - buildoptions{ "-Wall" } - end targetname ( package_name ) end -function add_cross_config_links() - if not is_vs() then - if os.istarget("mingw32") or os.istarget("windows") or os.istarget("ios") then -- if is crosscompiling from *nix - linkoptions { "-static-libgcc", "-static-libstdc++" } - end - - if os.istarget("mingw32") then - linkoptions { "-Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic" } - end - end -end - function build_link_configuration( package_name, use_ee_icon ) incdirs { "include" } - local extension = ""; if package_name == "eepp" then @@ -190,10 +169,6 @@ function build_link_configuration( package_name, use_ee_icon ) defines { "EE_STATIC" } end - if not is_vs() then - buildoptions{ "-std=c++14" } - end - if package_name ~= "eepp" and package_name ~= "eepp-static" then if not _OPTIONS["with-static-eepp"] then links { "eepp-shared" } @@ -203,64 +178,47 @@ function build_link_configuration( package_name, use_ee_icon ) add_static_links() links { link_list } end - - if os.istarget("windows") and not is_vs() then - if ( true == use_ee_icon ) then - linkoptions { "../../bin/assets/icon/ee.res" } - end - end - - if os.istarget("emscripten") then - extension = ".html" - - if ( package_name ~= "eeew" and - package_name ~= "eees" and - package_name ~= "eehttp-request" and - package_name ~= "eephysics" and - package_name ~= "eevbo-fbo-batch" - ) then - linkoptions { "--preload-file assets/" } - end - end end set_ios_config() set_xcode_config() - filter "configurations:debug" - defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" } - symbols "On" - - if not is_vs() and not os.istarget("emscripten") then - buildoptions{ "-Wall -Wno-long-long" } + filter { "system:windows", "action:not vs*" } + if ( true == use_ee_icon ) then + linkoptions { "../../bin/assets/icon/ee.res" } end + filter "action:not vs*" + cppdialect "C++14" + buildoptions { "-Wall" } + + filter { "configurations:debug", "action:not vs*" } + buildoptions{ "-Wno-long-long" } + + filter { "configurations:release", "action:not vs*" } + buildoptions { "-fno-strict-aliasing -ffast-math" } + + filter { "configurations:release", "action:not vs*", "system:not macosx" } + buildoptions { "-s" } + + filter "configurations:debug" + defines { "DEBUG", "EE_DEBUG", "EE_MEMORY_MANAGER" } targetname ( package_name .. "-debug" .. extension ) filter "configurations:release" - optimize "Speed" - - if not is_vs() and not os.istarget("emscripten") then - buildoptions { "-fno-strict-aliasing -ffast-math" } - end - - if not is_vs() and not os.istarget("emscripten") and not os.istarget("macosx") then - buildoptions { "-s" } - end - targetname ( package_name .. extension ) - filter "system:windows" - add_cross_config_links() + filter { "system:windows or system:ios", "action:not vs*" } + linkoptions { "-static-libgcc", "-static-libstdc++" } - if _OPTIONS["windows-vc-build"] then - syslibdirs { "src/thirdparty/" .. remote_sdl2_version .."/lib/x86" } - end - - if is_vs() and table.contains( backends, "SDL2" ) then + filter { "system:windows", "action:vs*" } + if table.contains( backends, "SDL2" ) then links { "SDL2", "SDL2main" } end + filter { "options:windows-vc-build", "system:windows" } + syslibdirs { "src/thirdparty/" .. remote_sdl2_version .."/lib/x86" } + filter "system:emscripten" linkoptions{ "-O2 -s TOTAL_MEMORY=67108864 -s ASM_JS=1 -s VERBOSE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_SDL=2 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s ERROR_ON_MISSING_LIBRARIES=0 -s FULL_ES3=1 -s \"BINARYEN_TRAP_MODE='clamp'\"" } buildoptions { "-fno-strict-aliasing -O2 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=web" } @@ -390,7 +348,7 @@ function set_xcode_config() end function set_ios_config() - if _OPTIONS.platform == "ios-arm7" or _OPTIONS.platform == "ios-x86" then + if os.istarget("ios") then local err = false if nil == os.getenv("TOOLCHAINPATH") then @@ -495,50 +453,7 @@ function check_ssl_support() defines { "EE_SSL_SUPPORT" } end -function set_macos_and_ios_config() - if os.istarget("macosx") and ( is_xcode() or _OPTIONS["use-frameworks"] ) then - libdirs { "/System/Library/Frameworks", "/Library/Frameworks" } - end - - if _OPTIONS["use-frameworks"] then - defines { "EE_USE_FRAMEWORKS" } - end -end - function build_eepp( build_name ) - incdirs { "include", "src", "src/thirdparty", "include/eepp/thirdparty", "src/thirdparty/freetype2/include", "src/thirdparty/zlib", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include", "src/thirdparty/mbedtls/include" } - - if _OPTIONS["with-mojoal"] then - defines( "AL_LIBTYPE_STATIC" ) - incdirs { "src/thirdparty/mojoAL" } - end - - if _OPTIONS["windows-vc-build"] then - incdirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } - end - - set_macos_and_ios_config() - set_ios_config() - set_xcode_config() - - add_static_links() - - if is_vs() then - incdirs { "src/thirdparty/libzip/vs" } - end - - if not is_vs() then - buildoptions{ "-std=c++14" } - end - - if os.istarget("windows") then - files { "src/eepp/system/platform/win/*.cpp" } - files { "src/eepp/network/platform/win/*.cpp" } - else - files { "src/eepp/system/platform/posix/*.cpp" } - files { "src/eepp/network/platform/unix/*.cpp" } - end - files { "src/eepp/core/*.cpp", "src/eepp/math/*.cpp", "src/eepp/system/*.cpp", @@ -561,57 +476,74 @@ function build_eepp( build_name ) "src/eepp/maps/mapeditor/*.cpp" } + incdirs { "include", + "src", + "src/thirdparty", + "include/eepp/thirdparty", + "src/thirdparty/freetype2/include", + "src/thirdparty/zlib", + "src/thirdparty/libogg/include", + "src/thirdparty/libvorbis/include", + "src/thirdparty/mbedtls/include" + } + + add_static_links() check_ssl_support() - select_backend() - if _OPTIONS["with-dynamic-freetype"] and os_findlib("freetype") then - table.insert( link_list, get_backend_link_name( "freetype" ) ) - end - multiple_insert( link_list, os_links ) links { link_list } build_link_configuration( build_name ) - configuration "emscripten" - if _OPTIONS["force-gles1"] then - defines{ "EE_GLES1_DEFAULT" } - end -end + filter "options:use-frameworks" + defines { "EE_USE_FRAMEWORKS" } -function set_targetdir( dir ) - if os.istarget("ios") then - targetdir(dir .. get_ios_arch() .. "/" ) - else - targetdir(dir) - end + filter { "system:macosx", "action:xcode* or options:use-frameworks" } + libdirs { "/System/Library/Frameworks", "/Library/Frameworks" } + + filter "with-dynamic-freetype" + if os_findlib("freetype") then + table.insert( link_list, get_backend_link_name( "freetype" ) ) + end + + filter "system:windows" + files { "src/eepp/system/platform/win/*.cpp" } + files { "src/eepp/network/platform/win/*.cpp" } + + filter "system:not windows" + files { "src/eepp/system/platform/posix/*.cpp" } + files { "src/eepp/network/platform/unix/*.cpp" } + + filter "with-mojoal" + defines( "AL_LIBTYPE_STATIC" ) + incdirs { "src/thirdparty/mojoAL" } + + filter "options:windows-vc-build" + incdirs { "src/thirdparty/" .. remote_sdl2_version .. "/include" } + + filter "action:vs*" + incdirs { "src/thirdparty/libzip/vs" } + + filter "action:not vs*" + cppdialect "C++14" end workspace "eepp" targetdir("./bin/") configurations { "debug", "release" } rtti "On" - download_and_extract_dependencies() + generate_os_links() + parse_args() + location("./make/" .. os.target() .. "/") + objdir("obj/" .. os.target() .. "/") - if os.istarget("android") then + filter "system:android" ndkabi "arm64-v8a" ndkplatform "android-28" ndkstl "c++_static" - end - - if os.istarget("ios") then - location("./make/" .. os.target() .. "/" ) - objdir("obj/" .. os.target() .. "/" .. get_ios_arch() .. "/" ) - else - location("./make/" .. os.target() .. "/") - objdir("obj/" .. os.target() .. "/") - end - - generate_os_links() - parse_args() filter "configurations:debug" defines { "DEBUG" } @@ -621,7 +553,7 @@ workspace "eepp" project "SOIL2-static" kind "StaticLib" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/SOIL2/src/SOIL2/*.c" } incdirs { "src/thirdparty/SOIL2" } build_base_configuration( "SOIL2" ) @@ -635,7 +567,7 @@ workspace "eepp" kind "StaticLib" language "C" defines { "GLEW_NO_GLU", "GLEW_STATIC" } - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/glew/*.c" } incdirs { "include/thirdparty/glew" } build_base_configuration( "glew" ) @@ -643,7 +575,7 @@ workspace "eepp" project "mbedtls-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") incdirs { "src/thirdparty/mbedtls/include/" } files { "src/thirdparty/mbedtls/library/*.c" } build_base_cpp_configuration( "mbedtls" ) @@ -651,7 +583,7 @@ workspace "eepp" project "vorbis-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") incdirs { "src/thirdparty/libvorbis/lib/", "src/thirdparty/libogg/include", "src/thirdparty/libvorbis/include" } files { "src/thirdparty/libogg/**.c", "src/thirdparty/libvorbis/**.c" } build_base_cpp_configuration( "vorbis" ) @@ -659,21 +591,21 @@ workspace "eepp" project "pugixml-static" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/pugixml/*.cpp" } build_base_cpp_configuration( "pugixml" ) project "zlib-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/zlib/*.c" } build_base_configuration( "zlib" ) project "libzip-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/libzip/*.c" } incdirs { "src/thirdparty/zlib" } build_base_configuration( "libzip" ) @@ -681,7 +613,7 @@ workspace "eepp" project "freetype-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") defines { "FT2_BUILD_LIBRARY" } files { "src/thirdparty/freetype2/src/**.c" } incdirs { "src/thirdparty/freetype2/include" } @@ -689,7 +621,7 @@ workspace "eepp" project "chipmunk-static" kind "StaticLib" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/chipmunk/*.c", "src/thirdparty/chipmunk/constraints/*.c" } incdirs { "include/eepp/thirdparty/chipmunk" } build_base_configuration( "chipmunk" ) @@ -702,21 +634,21 @@ workspace "eepp" project "jpeg-compressor-static" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/jpeg-compressor/*.cpp" } build_base_cpp_configuration( "jpeg-compressor" ) project "imageresampler-static" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") files { "src/thirdparty/imageresampler/*.cpp" } build_base_cpp_configuration( "imageresampler" ) project "mojoal-static" kind "StaticLib" language "C" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") incdirs { "include/eepp/thirdparty/mojoAL" } defines( "AL_LIBTYPE_STATIC" ) files { "src/thirdparty/mojoAL/*.c" } @@ -727,38 +659,65 @@ workspace "eepp" project "efsw-static" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/thirdparty/") + targetdir("libs/" .. os.target() .. "/thirdparty/") incdirs { "src/thirdparty/efsw/include", "src/thirdparty/efsw/src" } files { "src/thirdparty/efsw/src/efsw/*.cpp" } build_base_cpp_configuration( "efsw" ) filter "system:windows" files { "src/thirdparty/efsw/src/efsw/platform/win/*.cpp" } - excludes { "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } filter "system:linux" - excludes { "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherKqueue.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } filter "system:macosx" - excludes { "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp" + } filter "system:bsd" - excludes { "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" } + excludes { + "src/thirdparty/efsw/src/efsw/WatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/WatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/WatcherFSEvents.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherInotify.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherWin32.cpp", + "src/thirdparty/efsw/src/efsw/FileWatcherFSEvents.cpp" + } filter "system:not windows" files { "src/thirdparty/efsw/src/efsw/platform/posix/*.cpp" } + -- Library project "eepp-main" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/") + targetdir("libs/" .. os.target() .. "/") files { "src/eepp/main/eepp_main.cpp" } project "eepp-static" kind "StaticLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/") + targetdir("libs/" .. os.target() .. "/") build_eepp( "eepp-static" ) project "eepp-shared" kind "SharedLib" language "C++" - set_targetdir("libs/" .. os.target() .. "/") + targetdir("libs/" .. os.target() .. "/") build_eepp( "eepp" ) -- Examples @@ -766,63 +725,63 @@ workspace "eepp" set_kind() language "C++" files { "src/test/*.cpp" } - build_link_configuration( "eetest", true ) + build_link_configuration( "eepp-test", true ) - project "eepp-es" + project "eepp-external-shader" set_kind() language "C++" files { "src/examples/external_shader/*.cpp" } - build_link_configuration( "eees", true ) + build_link_configuration( "eepp-external-shader", true ) - project "eepp-ew" + project "eepp-empty-window" set_kind() language "C++" files { "src/examples/empty_window/*.cpp" } - build_link_configuration( "eeew", true ) + build_link_configuration( "eepp-empty-window", true ) project "eepp-sound" kind "ConsoleApp" language "C++" files { "src/examples/sound/*.cpp" } - build_link_configuration( "eesound", true ) + build_link_configuration( "eepp-sound", true ) project "eepp-sprites" set_kind() language "C++" files { "src/examples/sprites/*.cpp" } - build_link_configuration( "eesprites", true ) + build_link_configuration( "eepp-sprites", true ) project "eepp-fonts" set_kind() language "C++" files { "src/examples/fonts/*.cpp" } - build_link_configuration( "eefonts", true ) + build_link_configuration( "eepp-fonts", true ) project "eepp-vbo-fbo-batch" set_kind() language "C++" files { "src/examples/vbo_fbo_batch/*.cpp" } - build_link_configuration( "eevbo-fbo-batch", true ) + build_link_configuration( "eepp-vbo-fbo-batch", true ) project "eepp-physics" set_kind() language "C++" files { "src/examples/physics/*.cpp" } - build_link_configuration( "eephysics", true ) + build_link_configuration( "eepp-physics", true ) project "eepp-http-request" kind "ConsoleApp" language "C++" files { "src/examples/http_request/*.cpp" } incdirs { "src/thirdparty" } - build_link_configuration( "eehttp-request", true ) + build_link_configuration( "eepp-http-request", true ) project "eepp-ui-hello-world" set_kind() language "C++" files { "src/examples/ui_hello_world/*.cpp" } incdirs { "src/thirdparty" } - build_link_configuration( "eeui-hello-world", true ) + build_link_configuration( "eepp-ui-hello-world", true ) -- Tools project "eepp-textureatlaseditor" @@ -849,6 +808,13 @@ workspace "eepp" filter { "system:not windows", "system:not haiku" } links { "pthread" } + project "eepp-texturepacker" + kind "ConsoleApp" + language "C++" + incdirs { "src/thirdparty" } + files { "src/tools/texturepacker/*.cpp" } + build_link_configuration( "eepp-TexturePacker", true ) + if os.isfile("external_projects.lua") then dofile("external_projects.lua") end diff --git a/projects/emscripten/make.sh b/projects/emscripten/make.sh index b80aa3743..a960165f3 100755 --- a/projects/emscripten/make.sh +++ b/projects/emscripten/make.sh @@ -1,5 +1,7 @@ #!/bin/sh -# Currently latest emsdk tested and working version: 1.38.33 +# Currently latest emsdk tested and working version: latest-fastcomp +# remember to first set the environment +# source /path/to/emsdk/emsdk_env.sh cd $(dirname "$0") premake4 --file=../../premake4.lua --with-gles1 --with-gles2 --with-static-eepp --platform=emscripten --with-backend=SDL2 gmake cd ../../make/emscripten/ @@ -7,4 +9,4 @@ ln -sf ../../bin/assets/ ./ sed -i 's/-rcs/rcs/g' *.make emmake make -j`nproc` $@ # Fix a bug in emscripten, see my patch: https://github.com/emscripten-core/emscripten/pull/10208 -sed 's/function _alGetSource3f(source,/function _alGetSource3f(sourceId,/' ../../bin/*.js +sed -i 's/function _alGetSource3f(source,/function _alGetSource3f(sourceId,/' ../../bin/*.js diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index bd469a6a8..ee20be591 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -77,9 +77,9 @@ Desktop Desktop {6d057187-158a-4883-8d5b-d470a6b6b025} - 12 + 10 0 - 15 + 17 ../../make/linux @@ -995,8 +995,8 @@ 2 - %{buildDir}../../../bin/eetest-debug - eetest-debug + %{buildDir}../../../bin/eepp-test-debug + eepp-test-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1071,8 +1071,8 @@ 2 - %{buildDir}../../../bin/eetest - eetest-release + %{buildDir}../../../bin/eepp-test + eepp-test-release ProjectExplorer.CustomExecutableRunConfiguration @@ -1147,8 +1147,8 @@ 2 - %{buildDir}../../../bin/eephysics-debug - eephysics-debug + %{buildDir}../../../bin/eepp-physics-debug + eepp-physics-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1223,8 +1223,8 @@ 2 - %{buildDir}../../../bin/eehttp-request-debug - eehttp-request-debug + %{buildDir}../../../bin/eepp-http-request-debug + eepp-http-request-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1603,8 +1603,8 @@ 2 - %{buildDir}../../../bin/eeui-hello-world-debug - eeui-hello-world-debug + %{buildDir}../../../bin/eepp-ui-hello-world-debug + eepp-ui-hello-world-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1619,6 +1619,82 @@ %{buildDir}../../../bin/ + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 0 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + %{buildDir}../../../bin/eepp-TexturePacker-debug + eepp-TexturePacker-debug + ProjectExplorer.CustomExecutableRunConfiguration + + -p assets/ui/uitheme/ -o textureatlas.eta -u --allow-childs + false + + true + false + false + false + false + false + %{buildDir}../../../bin/ + + dwarf @@ -1679,8 +1755,8 @@ 2 - %{buildDir}../../../bin/eeew-debug - eeew-debug + %{buildDir}../../../bin/eepp-empty-window-debug + eepp-empty-window-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1755,8 +1831,8 @@ 2 - %{buildDir}../../../bin/eeew - eeew-release + %{buildDir}../../../bin/eepp-empty-window + eepp-empty-window-release ProjectExplorer.CustomExecutableRunConfiguration @@ -1831,8 +1907,8 @@ 2 - %{buildDir}../../../bin/eees-debug - eees-debug + %{buildDir}../../../bin/eepp-external-shader-debug + eepp-external-shader-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -1907,8 +1983,8 @@ 2 - %{buildDir}../../../bin/eees - eees-release + %{buildDir}../../../bin/eepp-external-shader + eepp-external-shader-release ProjectExplorer.CustomExecutableRunConfiguration @@ -1983,8 +2059,8 @@ 2 - %{buildDir}../../../bin/eesound-debug - eesound-debug + %{buildDir}../../../bin/eepp-sound-debug + eepp-sound-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -2059,8 +2135,8 @@ 2 - %{buildDir}../../../bin/eesprites-debug - eesprites-debug + %{buildDir}../../../bin/eepp-sprites-debug + eepp-sprites-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -2135,8 +2211,8 @@ 2 - %{buildDir}../../../bin/eefonts-debug - eefonts-debug + %{buildDir}../../../bin/eepp-fonts-debug + eepp-fonts-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -2211,8 +2287,8 @@ 2 - %{buildDir}../../../bin/eevbo-fbo-batch-debug - eevbo-fbo-batch-debug + %{buildDir}../../../bin/eepp-vbo-fbo-batch-debug + eepp-vbo-fbo-batch-debug ProjectExplorer.CustomExecutableRunConfiguration @@ -2227,7 +2303,7 @@ %{buildDir}../../../bin/ - 17 + 18 diff --git a/projects/linux/ee.files b/projects/linux/ee.files index dd0e4e397..b1000cf23 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -911,4 +911,5 @@ ../../src/thirdparty/SOIL2/src/SOIL2/stbi_pvr.h ../../src/tools/mapeditor/mapeditor.cpp ../../src/tools/textureatlaseditor/textureatlaseditor.cpp +../../src/tools/texturepacker/texturepacker.cpp ../../src/tools/uieditor/uieditor.cpp diff --git a/src/eepp/graphics/fonttruetype.cpp b/src/eepp/graphics/fonttruetype.cpp index fc59924b4..88a28f575 100644 --- a/src/eepp/graphics/fonttruetype.cpp +++ b/src/eepp/graphics/fonttruetype.cpp @@ -28,7 +28,22 @@ unsigned long read( FT_Stream rec, unsigned long offset, unsigned char* buffer, } else return count > 0 ? 0 : 1; // error code is 0 if we're reading, or nonzero if we're seeking } + void close( FT_Stream ) {} + +// Helper to intepret memory as a specific type +template inline T reinterpret( const U& input ) { + T output; + std::memcpy( &output, &input, sizeof( U ) ); + return output; +} + +// Combine outline thickness, boldness and font glyph index into a single 64-bit key +EE::Uint64 combine( float outlineThickness, bool bold, EE::Uint32 index ) { + return ( static_cast( reinterpret( outlineThickness ) ) << 32 ) | + ( static_cast( bold ) << 31 ) | index; +} + } // namespace namespace EE { namespace Graphics { @@ -273,8 +288,8 @@ const Glyph& FontTrueType::getGlyph( Uint32 codePoint, unsigned int characterSiz GlyphTable& glyphs = mPages[characterSize].glyphs; // Build the key by combining the code point, bold flag, and outline thickness - Uint64 key = ( static_cast( *reinterpret_cast( &outlineThickness ) ) << 32 ) | - ( static_cast( bold ? 1 : 0 ) << 31 ) | static_cast( codePoint ); + Uint64 key = combine( outlineThickness, bold, + FT_Get_Char_Index( static_cast( mFace ), codePoint ) ); // Search the glyph into the cache GlyphTable::const_iterator it = glyphs.find( key ); diff --git a/src/eepp/graphics/textureatlasloader.cpp b/src/eepp/graphics/textureatlasloader.cpp index 85f3b399e..da90763c0 100644 --- a/src/eepp/graphics/textureatlasloader.cpp +++ b/src/eepp/graphics/textureatlasloader.cpp @@ -233,9 +233,6 @@ void TextureAtlasLoader::createTextureRegions() { // Create the Texture Atlas with the name of the real texture, not the Childs ( example // load 1.png and not 1_ch1.png ) if ( 0 == z ) { - if ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_REMOVE_EXTENSION ) - name = FileSystem::fileRemoveExtension( name ); - std::string etapath = FileSystem::fileRemoveExtension( path ) + EE_TEXTURE_ATLAS_EXTENSION; @@ -260,10 +257,6 @@ void TextureAtlasLoader::createTextureRegions() { sTextureRegionHdr* tSh = &tTexAtlas->TextureRegions[i]; std::string TextureRegionName( &tSh->Name[0] ); - - if ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_REMOVE_EXTENSION ) - TextureRegionName = FileSystem::fileRemoveExtension( TextureRegionName ); - Rect tRect( tSh->X, tSh->Y, tSh->X + tSh->Width, tSh->Y + tSh->Height ); TextureRegion* tTextureRegion = TextureRegion::New( @@ -372,8 +365,8 @@ bool TextureAtlasLoader::updateTextureAtlas() { return false; } -bool TextureAtlasLoader::updateTextureAtlas( std::string TextureAtlasPath, - std::string ImagesPath ) { +bool TextureAtlasLoader::updateTextureAtlas( std::string TextureAtlasPath, std::string ImagesPath, + Sizei maxImageSize ) { if ( !TextureAtlasPath.size() || !ImagesPath.size() || !FileSystem::fileExists( TextureAtlasPath ) || !FileSystem::isDirectory( ImagesPath ) ) return false; @@ -464,16 +457,19 @@ bool TextureAtlasLoader::updateTextureAtlas( std::string TextureAtlasPath, Image::saveTypeToExtension( mTexGrHdr.Format ) ); if ( 2 == NeedUpdate ) { - TexturePacker tp( mTexGrHdr.Width, mTexGrHdr.Height, pixelDensity, - 0 != ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_POW_OF_TWO ), - 0 != ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_SCALABLE_SVG ), - mTexGrHdr.PixelBorder, - (Texture::TextureFilter)mTexGrHdr.TextureFilter, - mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_ALLOW_FLIPPING ); + TexturePacker tp( + maxImageSize.getWidth() == 0 ? mTexGrHdr.Width : maxImageSize.getWidth(), + maxImageSize.getHeight() == 0 ? mTexGrHdr.Height : maxImageSize.getHeight(), + pixelDensity, 0 != ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_POW_OF_TWO ), + 0 != ( mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_SCALABLE_SVG ), mTexGrHdr.PixelBorder, + (Texture::TextureFilter)mTexGrHdr.TextureFilter, + mTexGrHdr.Flags & HDR_TEXTURE_ATLAS_ALLOW_FLIPPING ); tp.addTexturesPath( ImagesPath ); - tp.packTextures(); + if ( tp.packTextures() <= 0 ) { + return false; + } tp.save( tapath, (Image::SaveType)mTexGrHdr.Format ); } else if ( 1 == NeedUpdate ) { diff --git a/src/eepp/graphics/texturepacker.cpp b/src/eepp/graphics/texturepacker.cpp index 266507487..9eb73b66d 100644 --- a/src/eepp/graphics/texturepacker.cpp +++ b/src/eepp/graphics/texturepacker.cpp @@ -12,26 +12,27 @@ TexturePacker* TexturePacker::New() { return eeNew( TexturePacker, () ); } -TexturePacker* TexturePacker::New( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity, const bool& ForcePowOfTwo, - const bool& scalableSVG, const Uint32& PixelBorder, +TexturePacker* TexturePacker::New( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity, const bool& forcePowOfTwo, + const bool& scalableSVG, const Uint32& pixelBorder, const Texture::TextureFilter& textureFilter, - const bool& AllowFlipping ) { - return eeNew( TexturePacker, ( MaxWidth, MaxHeight, PixelDensity, ForcePowOfTwo, scalableSVG, - PixelBorder, textureFilter, AllowFlipping ) ); + const bool& allowChilds, const bool& allowFlipping ) { + return eeNew( TexturePacker, ( maxWidth, maxHeight, pixelDensity, forcePowOfTwo, scalableSVG, + pixelBorder, textureFilter, allowChilds, allowFlipping ) ); } -TexturePacker::TexturePacker( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity, const bool& ForcePowOfTwo, - const bool& scalableSVG, const Uint32& PixelBorder, - const Texture::TextureFilter& textureFilter, - const bool& AllowFlipping ) : +TexturePacker::TexturePacker( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity, const bool& forcePowOfTwo, + const bool& scalableSVG, const Uint32& pixelBorder, + const Texture::TextureFilter& textureFilter, const bool& allowChilds, + const bool& allowFlipping ) : mTotalArea( 0 ), mFreeList( NULL ), mWidth( 128 ), mHeight( 128 ), mPacked( false ), - mAllowFlipping( false ), + mAllowFlipping( allowFlipping ), + mAllowChilds( allowChilds ), mChild( NULL ), mStrategy( PackBig ), mCount( 0 ), @@ -39,13 +40,13 @@ TexturePacker::TexturePacker( const Uint32& MaxWidth, const Uint32& MaxHeight, mPlacedCount( 0 ), mForcePowOfTwo( true ), mPixelBorder( 0 ), - mPixelDensity( PixelDensity ), + mPixelDensity( pixelDensity ), mTextureFilter( textureFilter ), mSaveExtensions( false ), mScalableSVG( scalableSVG ), mFormat( Image::SaveType::SAVE_TYPE_PNG ) { - setOptions( MaxWidth, MaxHeight, PixelDensity, ForcePowOfTwo, scalableSVG, PixelBorder, - textureFilter, AllowFlipping ); + setOptions( maxWidth, maxHeight, pixelDensity, forcePowOfTwo, scalableSVG, pixelBorder, + textureFilter, allowChilds, allowFlipping ); } TexturePacker::TexturePacker() : @@ -131,25 +132,26 @@ Uint32 TexturePacker::getAtlasNumChannels() { return maxChannels; } -void TexturePacker::setOptions( const Uint32& MaxWidth, const Uint32& MaxHeight, - const PixelDensitySize& PixelDensity, const bool& ForcePowOfTwo, - const bool& scalableSVG, const Uint32& PixelBorder, +void TexturePacker::setOptions( const Uint32& maxWidth, const Uint32& maxHeight, + const PixelDensitySize& pixelDensity, const bool& forcePowOfTwo, + const bool& scalableSVG, const Uint32& pixelBorder, const Texture::TextureFilter& textureFilter, - const bool& AllowFlipping ) { + const bool& allowChilds, const bool& allowFlipping ) { if ( !mTextures.size() ) { // only can change the dimensions before adding any texture - mMaxSize.x = MaxWidth; - mMaxSize.y = MaxHeight; + mMaxSize.x = maxWidth; + mMaxSize.y = maxHeight; - if ( ForcePowOfTwo && !Math::isPow2( mMaxSize.x ) ) + if ( forcePowOfTwo && !Math::isPow2( mMaxSize.x ) ) mMaxSize.x = Math::nextPowOfTwo( mMaxSize.x ); - if ( ForcePowOfTwo && !Math::isPow2( mMaxSize.y ) ) + if ( forcePowOfTwo && !Math::isPow2( mMaxSize.y ) ) mMaxSize.y = Math::nextPowOfTwo( mMaxSize.y ); - mForcePowOfTwo = ForcePowOfTwo; - mAllowFlipping = AllowFlipping; - mPixelBorder = PixelBorder; - mPixelDensity = PixelDensity; + mForcePowOfTwo = forcePowOfTwo; + mAllowFlipping = allowFlipping; + mAllowChilds = allowChilds; + mPixelBorder = pixelBorder; + mPixelDensity = pixelDensity; mTextureFilter = textureFilter; mScalableSVG = scalableSVG; } @@ -397,8 +399,8 @@ void TexturePacker::insertTexture( TexturePackerTex* t, TexturePackerNode* bestF } void TexturePacker::createChild() { - mChild = eeNew( TexturePacker, ( mWidth, mHeight, mPixelDensity, mForcePowOfTwo, mScalableSVG, - mPixelBorder, mTextureFilter, mAllowFlipping ) ); + mChild = TexturePacker::New( mWidth, mHeight, mPixelDensity, mForcePowOfTwo, mScalableSVG, + mPixelBorder, mTextureFilter, mAllowFlipping ); std::list::iterator it; std::list::iterator> remove; @@ -504,8 +506,7 @@ bool TexturePacker::addTexture( const std::string& TexturePath ) { return false; } -Int32 TexturePacker::packTextures() { // pack the textures, the return code is the amount of - // wasted/unused area. +Int32 TexturePacker::packTextures() { TexturePackerTex* t = NULL; addBorderToTextures( (Int32)mPixelBorder ); @@ -569,8 +570,9 @@ Int32 TexturePacker::packTextures() { // pack the textures, the return code is t return packTextures(); } else { - eePRINTL( "Creating a new image as a child." ); - createChild(); + if ( !mAllowChilds ) { + return 0; + } } break; @@ -578,8 +580,13 @@ Int32 TexturePacker::packTextures() { // pack the textures, the return code is t } if ( mCount > 0 ) { - eePRINTL( "Creating a new image as a child. Some textures couldn't get it: %d", mCount ); - createChild(); + if ( mAllowChilds ) { + eePRINTL( "Creating a new image as a child. Some textures couldn't get it: %d", + mCount ); + createChild(); + } else { + return 0; + } } addBorderToTextures( -( (Int32)mPixelBorder ) ); @@ -594,7 +601,7 @@ Int32 TexturePacker::packTextures() { // pack the textures, the return code is t eePRINTL( "Total Area Used: %d. This represents the %4.3f percent", mTotalArea, ( (double)mTotalArea / (double)( mWidth * mHeight ) ) * 100.0 ); - return ( mWidth * mHeight ) - mTotalArea; + return mTotalArea; } void TexturePacker::save( const std::string& Filepath, const Image::SaveType& Format, @@ -671,15 +678,12 @@ Int32 TexturePacker::getChildCount() { } void TexturePacker::saveTextureRegions() { - if ( NULL != mParent ) - return; - sTextureAtlasHdr TexGrHdr; TexGrHdr.Magic = EE_TEXTURE_ATLAS_MAGIC; - TexGrHdr.Version = 1000; + TexGrHdr.Version = 2000; TexGrHdr.Date = static_cast( Sys::getSystemTime() ); - TexGrHdr.TextureCount = 1 + getChildCount(); + TexGrHdr.TextureCount = 1; TexGrHdr.Format = mFormat; TexGrHdr.Width = mWidth; TexGrHdr.Height = mHeight; @@ -706,15 +710,6 @@ void TexturePacker::saveTextureRegions() { TexHdr[0] = createTextureHdr( this ); - Int32 HdrPos = 1; - TexturePacker* Child = mChild; - - while ( NULL != Child ) { - TexHdr[HdrPos] = createTextureHdr( Child ); - Child = Child->getChild(); - HdrPos++; - } - std::vector tTextureRegionsHdr; std::string path = FileSystem::fileRemoveExtension( mFilepath ) + EE_TEXTURE_ATLAS_EXTENSION; @@ -730,24 +725,6 @@ void TexturePacker::saveTextureRegions() { if ( tTextureRegionsHdr.size() ) fs.write( reinterpret_cast( &tTextureRegionsHdr[0] ), sizeof( sTextureRegionHdr ) * (std::streamsize)tTextureRegionsHdr.size() ); - - Int32 HdrPos = 1; - TexturePacker* Child = mChild; - - while ( NULL != Child ) { - fs.write( reinterpret_cast( &TexHdr[HdrPos] ), sizeof( sTextureHdr ) ); - - createTextureRegionsHdr( Child, tTextureRegionsHdr ); - - if ( tTextureRegionsHdr.size() ) - fs.write( reinterpret_cast( &tTextureRegionsHdr[0] ), - sizeof( sTextureRegionHdr ) * - (std::streamsize)tTextureRegionsHdr.size() ); - - Child = Child->getChild(); - - HdrPos++; - } } } @@ -770,13 +747,16 @@ void TexturePacker::createTextureRegionsHdr( TexturePacker* Packer, if ( tTex->placed() ) { std::string name = FileSystem::fileNameFromPath( tTex->name() ); + if ( !mSaveExtensions ) + name = FileSystem::fileRemoveExtension( name ); + + if ( name.size() > HDR_NAME_SIZE ) + name.resize( HDR_NAME_SIZE ); + memset( tTextureRegionHdr.Name, 0, HDR_NAME_SIZE ); String::strCopy( tTextureRegionHdr.Name, name.c_str(), HDR_NAME_SIZE ); - if ( !mSaveExtensions ) - name = FileSystem::fileRemoveExtension( name ); - tTextureRegionHdr.ResourceID = String::hash( name ); tTextureRegionHdr.Width = tTex->width(); tTextureRegionHdr.Height = tTex->height(); @@ -833,7 +813,7 @@ void TexturePacker::childSave( const Image::SaveType& Format ) { if ( NULL != LastParent ) { std::string fFpath = FileSystem::fileRemoveExtension( LastParent->getFilepath() ); std::string fExt = FileSystem::fileExtension( LastParent->getFilepath() ); - std::string fName = fFpath + "_ch" + String::toStr( ParentCount ) + "." + fExt; + std::string fName = fFpath + "-ch" + String::toStr( ParentCount ) + "." + fExt; mChild->save( fName, Format, mSaveExtensions ); } diff --git a/src/eepp/system/time.cpp b/src/eepp/system/time.cpp index 617962b89..6f50b234a 100644 --- a/src/eepp/system/time.cpp +++ b/src/eepp/system/time.cpp @@ -27,7 +27,7 @@ std::string Time::toString() { if ( asSeconds() < 1 ) { return String::format( "%4.2fms", asMilliseconds() ); } else if ( totalSeconds < 60 ) { - return String::format( "%llus", totalSeconds ); + return String::format( "%lus", static_cast( totalSeconds ) ); } long minutesLeft = totalSeconds / 60; diff --git a/src/eepp/ui/css/mediaquery.cpp b/src/eepp/ui/css/mediaquery.cpp index a7e27951f..fb1b43d26 100644 --- a/src/eepp/ui/css/mediaquery.cpp +++ b/src/eepp/ui/css/mediaquery.cpp @@ -8,6 +8,19 @@ using namespace EE::Window; namespace EE { namespace UI { namespace CSS { +#define MediaOrientationStrings "portrait;landscape" + +#define MediaFeatureStrings \ + "none;width;min-width;max-width;height;min-height;max-height;device-width;min-device-" \ + "width;max-device-width;device-height;min-device-height;max-device-height;orientation;" \ + "aspect-ratio;min-aspect-ratio;max-aspect-ratio;device-aspect-ratio;min-device-aspect-" \ + "ratio;max-device-aspect-ratio;color;min-color;max-color;color-index;min-color-index;max-" \ + "color-index;monochrome;min-monochrome;max-monochrome;resolution;min-resolution;max-" \ + "resolution" + +#define MediaTypeStrings \ + "none;all;screen;print;braille;embossed;handheld;projection;speech;tty;tv" + MediaQuery::MediaQuery() { mMediaType = media_type_all; mNot = false; @@ -44,7 +57,7 @@ MediaQuery::ptr MediaQuery::parse( const std::string& str ) { String::trimInPlace( exprTokens[0] ); expr.feature = (MediaFeature)String::valueIndex( - exprTokens[0], media_feature_strings, media_feature_none ); + exprTokens[0], MediaFeatureStrings, media_feature_none ); if ( expr.feature != media_feature_none ) { if ( exprTokens.size() == 1 ) { @@ -54,7 +67,7 @@ MediaQuery::ptr MediaQuery::parse( const std::string& str ) { expr.checkAsBool = false; if ( expr.feature == media_feature_orientation ) { - expr.val = String::valueIndex( exprTokens[1], media_orientation_strings, + expr.val = String::valueIndex( exprTokens[1], MediaOrientationStrings, media_orientation_landscape ); } else { std::string::size_type slash_pos = exprTokens[1].find( '/' ); @@ -89,7 +102,7 @@ MediaQuery::ptr MediaQuery::parse( const std::string& str ) { } } else { query->mMediaType = - (MediaType)String::valueIndex( tok, media_type_strings, media_type_all ); + (MediaType)String::valueIndex( tok, MediaTypeStrings, media_type_all ); } } diff --git a/src/eepp/ui/css/stylesheetpropertytransition.cpp b/src/eepp/ui/css/stylesheetpropertytransition.cpp index a34269eb0..f92a74b28 100644 --- a/src/eepp/ui/css/stylesheetpropertytransition.cpp +++ b/src/eepp/ui/css/stylesheetpropertytransition.cpp @@ -95,10 +95,10 @@ void StyleSheetPropertyTransition::onUpdate( const Time& ) { mDuration.asMilliseconds() ); if ( mProperty->getType() == PropertyType::NumberFloat ) { node->applyProperty( - StyleSheetProperty( mProperty, String::fromFloat( value, "px" ) ) ); + StyleSheetProperty( mProperty, String::fromFloat( value ) ) ); } else { node->applyProperty( StyleSheetProperty( - mProperty, String::format( "%dpx", static_cast( value ) ) ) ); + mProperty, String::format( "%d", static_cast( value ) ) ) ); } break; } diff --git a/src/eepp/ui/css/stylesheetspecification.cpp b/src/eepp/ui/css/stylesheetspecification.cpp index a5921eb2f..f7f53435f 100644 --- a/src/eepp/ui/css/stylesheetspecification.cpp +++ b/src/eepp/ui/css/stylesheetspecification.cpp @@ -50,8 +50,8 @@ bool StyleSheetSpecification::isShorthand( const std::string& name ) const { void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "id", "", false ).setType( PropertyType::String ); registerProperty( "class", "", false ).setType( PropertyType::String ); - registerProperty( "x", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "y", "", false ).setType( PropertyType::NumberFloat ); + registerProperty( "x", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "y", "", false ).setType( PropertyType::NumberLength ); registerProperty( "width", "", false ) .setType( PropertyType::NumberLength ) .setRelativeTarget( PropertyRelativeTarget::ContainingBlockWidth ); @@ -78,10 +78,10 @@ void StyleSheetSpecification::registerDefaultProperties() { .setType( PropertyType::NumberLength ); registerProperty( "foreground-repeat", "no-repeat", false ); registerProperty( "foreground-size", "", false ).setType( PropertyType::ForegroundSize ); - registerProperty( "foreground-radius", "0px", false ).setType( PropertyType::NumberInt ); + registerProperty( "foreground-radius", "0px", false ).setType( PropertyType::NumberLength ); registerProperty( "border-color", "", false ).setType( PropertyType::Color ); - registerProperty( "border-width", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "border-radius", "0px", false ).setType( PropertyType::NumberInt ); + registerProperty( "border-width", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "border-radius", "0px", false ).setType( PropertyType::NumberLength ); registerProperty( "visible", "true", false ).setType( PropertyType::Bool ); registerProperty( "enabled", "true", false ).setType( PropertyType::Bool ); registerProperty( "theme", "", false ); @@ -166,14 +166,14 @@ void StyleSheetSpecification::registerDefaultProperties() { .addAlias( "font-name" ) .setType( PropertyType::String ); registerProperty( "font-size", "", false ) - .setType( PropertyType::NumberFloat ) + .setType( PropertyType::NumberLength ) .addAlias( "text-size" ) .addAlias( "textsize" ); registerProperty( "font-style", "", false ) .addAlias( "text-style" ) .addAlias( "text-decoration" ); registerProperty( "text-stroke-width", "", false ) - .setType( PropertyType::NumberFloat ) + .setType( PropertyType::NumberLength ) .addAlias( "fontoutlinethickness" ); registerProperty( "text-stroke-color", "", false ) .setType( PropertyType::Color ) @@ -182,8 +182,8 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "text-align", "", false ); registerProperty( "icon", "", false ); registerProperty( "min-icon-size", "", false ).setType( PropertyType::Vector2 ); - registerProperty( "icon-horizontal-margin", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "icon-auto-margin", "", false ).setType( PropertyType::NumberFloat ); + registerProperty( "icon-horizontal-margin", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "icon-auto-margin", "", false ).setType( PropertyType::NumberLength ); registerProperty( "src", "", false ).setType( PropertyType::String ); registerProperty( "scale-type", "", false ); registerProperty( "tint", "", false ).setType( PropertyType::Color ); @@ -195,15 +195,15 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "special-border-tabs", "", false ).setType( PropertyType::Bool ); registerProperty( "line-below-tabs", "", false ).setType( PropertyType::Bool ); registerProperty( "line-below-tabs-color", "", false ).setType( PropertyType::Color ); - registerProperty( "line-below-tabs-y-offset", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "tab-separation", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "line-below-tabs-y-offset", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "tab-separation", "", false ).setType( PropertyType::NumberLength ); registerProperty( "selected", "", false ).setType( PropertyType::Bool ).addAlias( "active" ); registerProperty( "popup-to-main-control", "", false ).setType( PropertyType::Bool ); registerProperty( "max-visible-items", "", false ).setType( PropertyType::NumberInt ); registerProperty( "selected-index", "", false ); registerProperty( "selected-text", "", false ); registerProperty( "scrollbar-type", "", false ); - registerProperty( "row-height", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "row-height", "", false ).setType( PropertyType::NumberLength ); registerProperty( "vscroll-mode", "", false ); registerProperty( "hscroll-mode", "", false ); @@ -222,21 +222,21 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "max-progress", "", false ).setType( PropertyType::NumberFloat ); registerProperty( "progress", "", false ).setType( PropertyType::NumberFloat ); registerProperty( "fill-color", "", false ).setType( PropertyType::Color ); - registerProperty( "radius", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "outline-thickness", "", false ).setType( PropertyType::NumberFloat ); + registerProperty( "radius", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "outline-thickness", "", false ).setType( PropertyType::NumberLength ); registerProperty( "animation-speed", "", false ).setType( PropertyType::Vector2 ); registerProperty( "arc-start-angle", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "min-width", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "min-margin-right", "", false ).setType( PropertyType::NumberInt ); - registerProperty( "min-icon-space", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "min-width", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "min-margin-right", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "min-icon-space", "", false ).setType( PropertyType::NumberLength ); registerProperty( "total-steps", "", false ).setType( PropertyType::NumberInt ); registerProperty( "vertical-expand", "", false ).setType( PropertyType::Bool ); registerProperty( "display-percent", "", false ).setType( PropertyType::Bool ); - registerProperty( "filler-padding-left", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "filler-padding-top", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "filler-padding-right", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "filler-padding-bottom", "", false ).setType( PropertyType::NumberFloat ); + registerProperty( "filler-padding-left", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "filler-padding-top", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "filler-padding-right", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "filler-padding-bottom", "", false ).setType( PropertyType::NumberLength ); registerProperty( "movement-speed", "", false ).setType( PropertyType::Vector2 ); registerProperty( "min-value", "", false ).setType( PropertyType::NumberFloat ); registerProperty( "max-value", "", false ).setType( PropertyType::NumberFloat ); @@ -257,20 +257,20 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "touch-drag-deceleration", "", false ).setType( PropertyType::NumberFloat ); registerProperty( "base-alpha", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "buttons-position-offset", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "buttons-position-offset", "", false ).setType( PropertyType::NumberLength ); registerProperty( "window-flags", "", false ).addAlias( "winflags" ); registerProperty( "decoration-size", "", false ).setType( PropertyType::Vector2 ); registerProperty( "border-size", "", false ).setType( PropertyType::Vector2 ); registerProperty( "min-window-size", "", false ).setType( PropertyType::Vector2 ); - registerProperty( "buttons-separation", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "buttons-separation", "", false ).setType( PropertyType::NumberLength ); registerProperty( "min-corner-distance", "", false ); registerProperty( "decoration-auto-size", "", false ).setType( PropertyType::Bool ); registerProperty( "border-auto-size", "", false ).setType( PropertyType::Bool ); - registerProperty( "margin-between-buttons", "", false ).setType( PropertyType::NumberInt ); - registerProperty( "button-margin", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "menu-height", "", false ).setType( PropertyType::NumberFloat ); - registerProperty( "first-button-margin-left", "", false ).setType( PropertyType::NumberInt ); + registerProperty( "margin-between-buttons", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "button-margin", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "menu-height", "", false ).setType( PropertyType::NumberLength ); + registerProperty( "first-button-margin-left", "", false ).setType( PropertyType::NumberLength ); registerProperty( "scale-origin-point", "", false ).setType( PropertyType::Vector2 ); @@ -279,10 +279,10 @@ void StyleSheetSpecification::registerDefaultProperties() { registerProperty( "hint", "", false ).setType( PropertyType::String ); registerProperty( "hint-color", "", false ).setType( PropertyType::Color ); registerProperty( "hint-shadow-color", "", false ).setType( PropertyType::Color ); - registerProperty( "hint-font-size", "", false ).setType( PropertyType::NumberFloat ); + registerProperty( "hint-font-size", "", false ).setType( PropertyType::NumberLength ); registerProperty( "hint-font-style", "", false ).setType( PropertyType::String ); registerProperty( "hint-stroke-width", "", false ) - .setType( PropertyType::NumberFloat ) + .setType( PropertyType::NumberLength ) .addAlias( "hintoutlinethickness" ); registerProperty( "hint-stroke-color", "", false ).setType( PropertyType::Color ); registerProperty( "hint-font-family", "", false ).addAlias( "hint-font-name" ); diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index a26863343..1a3aaf91a 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -404,13 +404,13 @@ void UISceneNode::loadFontFaces( const StyleSheetStyleVector& styles ) { mFontFaces.push_back( font ); } else if ( String::startsWith( path, "http://" ) || String::startsWith( path, "https://" ) ) { - - FontTrueType* font = - FontTrueType::New( String::trim( familyProp.getValue(), '"' ) ); - #if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN + std::string familyName = familyProp.getValue(); Http::getAsync( - [&, font]( const Http&, Http::Request&, Http::Response& response ) { + [&, familyName]( const Http&, Http::Request&, Http::Response& response ) { + FontTrueType* font = + FontTrueType::New( String::trim( familyName , '"' ) ); + if ( !response.getBody().empty() ) { font->loadFromMemory( &response.getBody()[0], response.getBody().size() ); diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 2312c6b10..300837c1b 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -989,7 +989,7 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef ) case PropertyId::Scale: return String::fromFloat( getScale().x ) + " " + String::fromFloat( getScale().y ); case PropertyId::Opacity: - return String::fromFloat( getAlpha() ); + return String::fromFloat( getAlpha() / 255.f ); case PropertyId::Cursor: return "arrow"; case PropertyId::Visible: diff --git a/src/eepp/window/backend/SDL2/displaymanagersdl2.cpp b/src/eepp/window/backend/SDL2/displaymanagersdl2.cpp index 7218c6eed..47f2a348f 100644 --- a/src/eepp/window/backend/SDL2/displaymanagersdl2.cpp +++ b/src/eepp/window/backend/SDL2/displaymanagersdl2.cpp @@ -1,6 +1,10 @@ #include #include +#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN +#include +#endif + namespace EE { namespace Window { namespace Backend { namespace SDL2 { DisplaySDL2::DisplaySDL2( int index ) : Display( index ) {} @@ -17,12 +21,16 @@ Rect DisplaySDL2::getBounds() { } Float DisplaySDL2::getDPI() { +#if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN + return 96.f * emscripten_get_device_pixel_ratio(); +#else #if SDL_VERSION_ATLEAST( 2, 0, 4 ) float ddpi, hdpi, vdpi; if ( 0 == SDL_GetDisplayDPI( 0, &ddpi, &hdpi, &vdpi ) ) return ddpi; #endif - return 92.f; + return 96.f; +#endif } const int& DisplaySDL2::getIndex() const { diff --git a/src/eepp/window/backend/SDL2/windowsdl2.cpp b/src/eepp/window/backend/SDL2/windowsdl2.cpp index b8d4b3e1d..8c37f6530 100644 --- a/src/eepp/window/backend/SDL2/windowsdl2.cpp +++ b/src/eepp/window/backend/SDL2/windowsdl2.cpp @@ -23,8 +23,8 @@ #endif #if EE_PLATFORM == EE_PLATFORM_WIN -#include #include +#include #include #include @@ -266,7 +266,8 @@ bool WindowSDL::create( WindowSettings Settings, ContextSettings Context ) { SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, mWindow.ContextConfig.Multisamples ); } -#if EE_PLATFORM != EE_PLATFORM_MACOSX && EE_PLATFORM != EE_PLATFORM_IOS +#if EE_PLATFORM != EE_PLATFORM_MACOSX && EE_PLATFORM != EE_PLATFORM_IOS && \ + EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN mWindow.WindowConfig.Width *= mWindow.WindowConfig.PixelDensity; mWindow.WindowConfig.Height *= mWindow.WindowConfig.PixelDensity; #endif diff --git a/src/tools/mapeditor/mapeditor.cpp b/src/tools/mapeditor/mapeditor.cpp index 4e95b80c2..031ef351d 100644 --- a/src/tools/mapeditor/mapeditor.cpp +++ b/src/tools/mapeditor/mapeditor.cpp @@ -1,4 +1,20 @@ -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace EE; +using namespace EE::Graphics; +using namespace EE::Maps; +using namespace EE::Scene; +using namespace EE::Window; +using namespace EE::UI; +using namespace EE::UI::Tools; EE::Window::Window* win = NULL; UIMessageBox* MsgBox = NULL; diff --git a/src/tools/textureatlaseditor/textureatlaseditor.cpp b/src/tools/textureatlaseditor/textureatlaseditor.cpp index cc79b8834..20238facd 100644 --- a/src/tools/textureatlaseditor/textureatlaseditor.cpp +++ b/src/tools/textureatlaseditor/textureatlaseditor.cpp @@ -1,4 +1,19 @@ -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace EE; +using namespace EE::Graphics; +using namespace EE::Scene; +using namespace EE::Window; +using namespace EE::UI; +using namespace EE::UI::Tools; EE::Window::Window* win = NULL; UIMessageBox* MsgBox = NULL; diff --git a/src/tools/texturepacker/texturepacker.cpp b/src/tools/texturepacker/texturepacker.cpp new file mode 100644 index 000000000..cd8871cb6 --- /dev/null +++ b/src/tools/texturepacker/texturepacker.cpp @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include + +using namespace EE; +using namespace EE::System; +using namespace EE::Graphics; + +int main( int argc, char* argv[] ) { + args::ArgumentParser parser( "Texture Packer - eepp texture atlas creator." ); + args::HelpFlag help( parser, "help", "Display this help menu", {'h', "help"} ); + args::ValueFlag texturesPath( parser, "textures-path", "Textures directory path.", + {'p', "textures-path"} ); + args::ValueFlagList images( parser, "image-path", "Input image path.", + {'i', "image-path"} ); + args::ValueFlag outputFile( + parser, "output-file", "Texture atlas file output path. Extension must be: \".eta\"", + {'o', "output-file"}, "", args::Options::Required | args::Options::Single ); + std::unordered_map saveTypeFormat{ + {"PNG", Image::SaveType::SAVE_TYPE_PNG}, + {"DDS", Image::SaveType::SAVE_TYPE_DDS}, + {"TGA", Image::SaveType::SAVE_TYPE_TGA}, + {"BMP", Image::SaveType::SAVE_TYPE_BMP}, + {"JPG", Image::SaveType::SAVE_TYPE_JPG}}; + args::MapFlag saveType( + parser, "image-format", "Output image format.", {'f', "image-format"}, saveTypeFormat, + Image::SaveType::SAVE_TYPE_PNG, args::Options::Single ); + std::unordered_map pixelDensityMap{ + {"MDPI", PixelDensitySize::MDPI}, + {"HDPI", PixelDensitySize::HDPI}, + {"XHDPI", PixelDensitySize::XHDPI}, + {"XXHDPI", PixelDensitySize::XXHDPI}, + {"XXXHDPI", PixelDensitySize::XXXHDPI}}; + args::MapFlag pixelDensity( + parser, "pixel-density", + "Source images pixel density size. Valid values are: MDPI (1dp = 1px), HDPI (1dp = 1.5px), " + "XHDPI (1dp = 2px), XXHDPI (1dp = 3px) and XXXHDPI (1dp = 4px).", + {'d', "pixel-density"}, pixelDensityMap, PixelDensitySize::MDPI, args::Options::Single ); + args::Flag forcePow2( parser, "force-power-of-two-texture", "Force power of two texture.", + {"force-power-of-two"}, args::Options::Single ); + args::Flag scalableSVG( parser, "scalable-svg", + "Scale SVG source files using the pixel-density provided.", + {"scalable-svg"}, args::Options::Single ); + args::Flag saveExtensions( parser, "save-extensions", + "Save the file extensions as part of the texture regions names.", + {"save-extensions"} ); + args::Flag allowChilds( + parser, "allow-childs", + "When enabled in the case of an atlas not having enough space in the image to fit all the " + "source input images it will create new child atlas images to save them.", + {"allow-childs"} ); + args::ValueFlag height( parser, "max-width", "Texture Atlas maximum allowed height.", + {'h', "max-height"}, 4096, args::Options::Single ); + args::ValueFlag width( parser, "max-width", "Texture Atlas maximum allowed width.", + {'w', "max-width"}, 4096, args::Options::Single ); + args::ValueFlag pixelsBorder( + parser, "pixels-border", + "Number of pixels used as border of each image. The border is the separator between images " + "and it's recommended that at least there's a 2 pixel border (default value) to avoid " + "rendering problems.", + {'b', "pixels-border"}, 2, args::Options::Single ); + args::Flag update( parser, "update", "Update texture atlas if output file already exists.", + {'u', "update"}, args::Options::Single ); + std::unordered_map textureFilterMap{ + {"linear", Texture::TextureFilter::Linear}, {"nearest", Texture::TextureFilter::Nearest}}; + args::MapFlag textureFilter( + parser, "texture-filter", + "Texture filter to use with the texture atlas. Available filters: \"linear\" or " + "\"nearest\".", + {"texture-filter"}, textureFilterMap, Texture::TextureFilter::Linear, + args::Options::Single ); + + try { + parser.ParseCLI( argc, argv ); + } catch ( const args::Help& ) { + std::cout << parser; + return EXIT_SUCCESS; + } catch ( const args::ParseError& e ) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return EXIT_FAILURE; + } catch ( args::ValidationError& e ) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return EXIT_FAILURE; + } + + bool hasImages = false; + auto imagesPaths = args::get( images ); + std::map> imagesList; + if ( !imagesPaths.empty() ) { + for ( auto image : images ) { + if ( !Image::isImage( image ) ) { + std::cout << "Image: \"" << image << "\" is invalid." << std::endl + << "Operation cancelled." << std::endl; + return EXIT_FAILURE; + } + + if ( imagesList.find( image ) == imagesList.end() ) { + imagesList[image] = std::make_unique( image ); + } + } + hasImages = true; + } + + std::string texturesPathSafe( texturesPath.Get() ); + FileSystem::dirPathAddSlashAtEnd( texturesPathSafe ); + if ( !FileSystem::isDirectory( texturesPathSafe ) && !hasImages ) { + std::cout << "textures-path is invalid."; + return EXIT_FAILURE; + } + + auto filesInPath = FileSystem::filesGetInPath( texturesPathSafe ); + if ( !hasImages ) { + for ( auto& file : filesInPath ) { + if ( Image::isImage( texturesPathSafe + file ) ) { + hasImages = true; + break; + } + } + if ( !hasImages ) { + std::cout << "textures-path must contain at least one image."; + return EXIT_FAILURE; + } + } + + if ( pixelsBorder.Get() > 32 ) { + std::cout << "pixels-border value invalid, try a smaller number." << std::endl; + return EXIT_FAILURE; + } + + if ( FileSystem::fileExtension( outputFile.Get() ).empty() || + FileSystem::fileExtension( outputFile.Get() ) != "eta" ) { + std::cout << "output-file must have an extension."; + return EXIT_FAILURE; + } + + if ( !FileSystem::fileExists( outputFile.Get() ) ) { + TexturePacker tp( width.Get(), height.Get(), pixelDensity.Get(), forcePow2.Get(), + scalableSVG.Get(), pixelsBorder.Get(), textureFilter.Get(), + allowChilds.Get() ); + std::cout << "Packing directory: " << texturesPathSafe << std::endl; + tp.addTexturesPath( texturesPathSafe ); + for ( auto& image : imagesList ) { + tp.addImage( image.second.get(), image.first ); + } + if ( tp.packTextures() <= 0 ) { + goto exit_error; + } + std::string outputTexturePath( FileSystem::fileRemoveExtension( outputFile.Get() ) + "." + + Image::saveTypeToExtension( saveType.Get() ) ); + tp.save( outputTexturePath, saveType.Get(), saveExtensions.Get() ); + std::cout << "Texture Atlas created." << std::endl; + } else if ( update.Get() ) { + TextureAtlasLoader tgl; + std::cout << "Texture Atlas is already present, updating it." << std::endl; + if ( !tgl.updateTextureAtlas( outputFile.Get(), texturesPathSafe, + Sizei( width, height ) ) ) { + goto exit_error; + } + std::cout << "Texture Atlas updated." << std::endl; + } + return EXIT_SUCCESS; +exit_error: + std::cout << "Texture Atlas creation failed.\nTry allowing bigger images modifying the " + "max-width and max-height, or try removing some images from the images " + "directory." + << std::endl; + return EXIT_FAILURE; +}