From d28c3cfb1f6814cda067127daf66708bbdd1060c Mon Sep 17 00:00:00 2001 From: ZILtoid1991 Date: Sat, 12 Oct 2019 22:36:53 +0200 Subject: [PATCH] TileLayer fix and restructuring Editor mostly implemented, RasterWindow is buggy --- ETML.md | 40 ++ assets/_system/OpenSans-reg-14_0.tga | Bin 65580 -> 34206 bytes assets/_system/concreteGUIE0.tga | Bin 0 -> 4057 bytes assets/_system/concreteGUIE1.tga | Bin 0 -> 4257 bytes assets/_system/concreteGUIE2.tga | Bin 0 -> 4962 bytes assets/_system/concreteGUIE3.tga | Bin 0 -> 4691 bytes assets/_system/scp-14-reg_0.tga | Bin 66322 -> 49650 bytes assets/collisionTest.xmp | Bin 2245 -> 0 bytes assets/d-man.tga | Bin 0 -> 2387 bytes assets/sci-fi-tileset.png | Bin 0 -> 1793 bytes assets/tiletest.xmp | Bin 191861 -> 0 bytes dub.sdl | 3 +- dub.selections.json | 8 +- .../src/PixelPerfectEditor/app.d | 77 ++-- .../src/PixelPerfectEditor/document.d | 58 ++- .../src/PixelPerfectEditor/editorEvents.d | 39 +- .../src/PixelPerfectEditor/materialList.d | 14 + .../src/PixelPerfectEditor/newTileLayer.d | 7 +- .../src/PixelPerfectEditor/rasterWindow.d | 18 +- .../PixelPerfectEngine/concrete/elements.d | 27 +- .../concrete/eventChainSystem.d | 10 +- .../PixelPerfectEngine/concrete/interfaces.d | 91 ++++ .../src/PixelPerfectEngine/concrete/text.d | 387 ++++++++++++++++++ .../src/PixelPerfectEngine/concrete/window.d | 11 +- .../PixelPerfectEngine/graphics/fontsets.d | Bin 10258 -> 18954 bytes .../src/PixelPerfectEngine/graphics/layers.d | 169 ++++---- .../src/PixelPerfectEngine/map/mapformat.d | 57 ++- .../src/PixelPerfectEngine/system/file.d | 34 +- 28 files changed, 836 insertions(+), 214 deletions(-) create mode 100644 ETML.md create mode 100644 assets/_system/concreteGUIE0.tga create mode 100644 assets/_system/concreteGUIE1.tga create mode 100644 assets/_system/concreteGUIE2.tga create mode 100644 assets/_system/concreteGUIE3.tga delete mode 100644 assets/collisionTest.xmp create mode 100644 assets/d-man.tga create mode 100644 assets/sci-fi-tileset.png delete mode 100644 assets/tiletest.xmp create mode 100644 pixelperfectengine/src/PixelPerfectEngine/concrete/interfaces.d create mode 100644 pixelperfectengine/src/PixelPerfectEngine/concrete/text.d diff --git a/ETML.md b/ETML.md new file mode 100644 index 0000000..900a7f7 --- /dev/null +++ b/ETML.md @@ -0,0 +1,40 @@ +Purpose of the ETML (Embedded Text Markup Language): + +* Provide some familiar way to format text +* Provide some basic compatibility with HTML + +# Markup tags + +## Tags with the same behavior as their HTML counterpart + +* `

` +* `` +* `` +* `` + +Note: `u` and `s` (and `o`) can be formatted with attributes +* `style` (possible values: `single`, `double`, `triple`, `quad`), +* `lines` (possible values: `normal`, `dotted`, `wavy`, `wavySoft`, `stripes`), +* and `perWord` (possible values: `true`, `false`). + +## Tags special to ETML + +* `` + +Turns the text overstriken (puts a line on top of the selected text). + +* `` + +Marks the text as italic. The amount can be set with the attribute `amount`. + +* `` + +Sets the type of the font. + +* `` + +Inserts a tabulator at the given position. + +* `` + +Inserts an image at the current position. diff --git a/assets/_system/OpenSans-reg-14_0.tga b/assets/_system/OpenSans-reg-14_0.tga index ab17ab72311dbc48d723e8a5d81534a877470778..77d21931c81098c4d34c47f845d787a598eb8f50 100644 GIT binary patch literal 34206 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 J=YRU`e*wedherSa diff --git a/assets/_system/concreteGUIE0.tga b/assets/_system/concreteGUIE0.tga new file mode 100644 index 0000000000000000000000000000000000000000..effc369b70ab99938ff9751f2c40d2fc71ca7eba GIT binary patch literal 4057 zcmeHJyKWOv5S_g<7lncvN`F8|MT;zofGi=1cvB`(coZZkBuyH7*J~3cA^8Iez9D^D zN;*D)l20(_%)Pb~Ohgodl)_$lwVs(fk8{sG>!P?SBE=2dq#+%d;e!nD`Fv~e{maW) z`LRiZNc-505z=l;dmznryFKu$EpjB%Ja&^ov)N4F0b=-s=%XWqO+QlvE*An@OScaX z54V<{AJ~Bw8tM>?_tJVXsKq*Vl36Wi=(=4sTI>!TW&xhcJ*E+^YUnB~lmSUgcNQAU zSQu_OCEQhrii)fQcNI}Frh0I8*~-w@jlssQI;ajkSZbp+b*Ruea@DaM8Ij12C(>~u zG=Tnxsn7r>7_CF|oPb!Q<~c!bo@29rIypAGA4A3F=|MV;BdB0;YpFfN?(2bd@Xffx zn4DPViMp5($Z{`g0yEl-inwG?H=_5kE5q#@Sz49g2Ikzxw5Z~SFsJW@N6_h|xTXy;($;q2Li-5uv)eIholPt5W<7&F@04NvAvrXZ$vrm=TS z?M%xqAVqd&q{zl$Fe)9VCZItESxYDYWudQiJ)h$ z00@S$C%Of$rlqDik($KFR7u#7baloiv(C8>a4yEx*E00AOyj*eJ9K~ z2PMVC0)}zXRSp9gqj4unX9cIeSaZjwFTBL97%5hxC_TfaTA%6 zEeQw4N9L@HYXJ>So^eM73YDq z#0Bd%t?+YtSUVELwZcSPE0jTdl&83tTE!2DJbqXZby*QHmlbAIW@Jqe2^kF;nVr?u zduDY*Bs!(y!HP~Pgx&}HbLr(&iLQvm^n8(Udh#22fQ$ke>q~ww{Ube4^}l3D6#iLU zu0K=LZcam>^=|R?%Dt7v_1VUq<>k!}Yp*sMt<~kZiTLZWLEBecr+%J1dOH8C^|QIE;mPEtjMTzMo8 zc?F(?+K6h=>h7l+cKp!q9TLJUu;KEEc=FyX|&c z6p)F2f+HF_hK9@G5UhWOqIEJjsPT3>9dTc}I%_q^slX}PNM$8)fu34vi%CGhT(FmPUQ9+t6E{zw zUUeZdSTBlr!ZvCM6e}JGtu<&D(a0MSN6{(+4i((``| znEJ?;jD>uI4mEq1E~MJ&bEjcSscQ>p(J3a*8IAPkeRchO43%Onq=dXOl=_=5D=-+FF=vQkY&aTy*ZdnL9O8r+*Kjc9_nUV{(N z!g?S#$GcKpsd7Ilzj%ZH7;aN5A<+HUdw2Ncuy_0*dDQQJ`8;@gl5~&yJ0%y--qndP zKk!@oynOL$?{)W}`~2C%H;=nd_jc&&gK%%{s$0YVKw!W3;pikect7}*>>m%Vx#RcP I2UZ8+HXaE2J literal 0 HcmV?d00001 diff --git a/assets/_system/concreteGUIE2.tga b/assets/_system/concreteGUIE2.tga new file mode 100644 index 0000000000000000000000000000000000000000..259d52d66bf7dbb3e23944be83974e45d1d1c266 GIT binary patch literal 4962 zcmeHKJ8~025M9kj*dY;+=>R}PO1TJtQWXUhe}}eK(te1#LeyYGCs;4RLJgP!FoVJL zK;#=`0Hg#X#TzLtW$*k>7~}euM|kn%GKC3z@-i;H2ejHn2%xNS2TB#>Ke^z^RdRhw zn4}m2nJ_8zF=#@i?9(U`R4aRdta*A>A$|f@1^*NQEGIXjW5wN)65G4yIC^-I`L6 zW!))NMO6t^Mb(W_g(%%diVMAE6(@bLZ+;wNY@~Y_ehiKDPtW#(#9gL#ON0U~*+gI0 z>=OKvY>7#7%YrD|Btj~Tm^SU8))7<6PAZJ7g^)sX1bzv+Fd?$6XDby-O;c8DI~4|2 zU)cf+5MW`#K&_4}2nI^zg%MZ*WEnRj*@$7*H3D^9AlraC);36Y!Ahym5e(HHJ{qu! z=bv>Ir?9OizAtk*aT1UMUl4fjiraOC_P@VUtD@5H1il3K3KbZ`~2;-$Hxa}Ha4C;*}U^~FnqXi@;mz@alo;U_|E-Y zyK?>Pjp5bdrHdzSof}>_d$L-*5RT3DdZ73d3|wBj|M2PH>b=cJgUgRMe{;pv!#eT% GLih?)-HQPL literal 0 HcmV?d00001 diff --git a/assets/_system/concreteGUIE3.tga b/assets/_system/concreteGUIE3.tga new file mode 100644 index 0000000000000000000000000000000000000000..1d0189e4678b285e60933c041080856df874b226 GIT binary patch literal 4691 zcmeHJ&2A($5O&#ZXK*;6xq#e?c9b*hB@YmBSXP4&tXM!?qiFd#utCeB922{HhRy75 z@>(473OoakFnm>R&vNPAaulY27rov#c0ptuaPxm6UFM8{4QXyKQA4YZ{}K zf;V~Jx>hk_&@JoMSOD4`AT$8cjWVRNXn+t%?ZlnF9hEsmYw8*1?RxCIEu-4hQov=% zPOWt$=Ono{#E@E_t3z^GmjXvzAX}t9W+mFFB2UQ$5A?vUI;aW$1i#3cxuj>RgSoS~ zXH%j2+*~xL_zVAM+LEw)W(|Q^tiwV##B?pJMyj$fbK+&0ldRLG|DMrQeR&{NUzwmp z2AhOsCeoZSBHNiIvS~BFn?!Bb*>O-`<@QG0o8@K8=r9h!Z>R0|Q8n{YbY{pJEO9pY z=y|2K20yDH1pNzl4AIBHZo}?Dgkjc&z>^M~Jq6>g0592s)RtQYL zG6)2#5XPxOXe2P`0>J(WV@_$61XoxLt30kvvfBJ>=IFo{{dv^725eV znpt{Rnm5Ok-jxQ)F>e5{8Lhfd!)$w&P$vrW zz3c=lJk`m-7~9SJAjW9$;MP=wkEIMkf!WGo7F=Y|3hn7Y5Sc)-V+>U5}A!K$303D$5L93AU1JSS=?uSKiBWA6dE= z$c{T8x-;1tEWktt0%&ZKTS)%SF{@2r0?nN5NX|LFtX^Pl69k3yTun|E)%0A=Dpk}%N$SY}Y%tdAY9e(y68BNE zkntbhG2TJd733D`^LqSExA;~5F13n*=`ROAK6&`$;MvEMPY(}&|Ly39=acEv!}}E^ ziyztv3xDE!?dO}XzkTrC^zrnoFF*PIv*{NP?yI{-xR$J2=6H1Q^V8>($3GqYI(hW$ P=sza+`3HI6+l}xK)`X$? literal 0 HcmV?d00001 diff --git a/assets/_system/scp-14-reg_0.tga b/assets/_system/scp-14-reg_0.tga index 7859da5cdc86f0e0bd4ef5afee12db6a7f5e6c2e..ea3635f7a0d702234d2259cc9678b330f4b04528 100644 GIT binary patch literal 49650 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 XXL9(d^;P!Ut-p+Jw>CZa@I$x-MTdf% literal 0 HcmV?d00001 diff --git a/assets/sci-fi-tileset.png b/assets/sci-fi-tileset.png new file mode 100644 index 0000000000000000000000000000000000000000..5a61fe0f854243e56ec64257166871498db0b584 GIT binary patch literal 1793 zcmV+c2mbhpP)C00007bV*G`2jd3` z6%#eSowPgv000SaNLh0L03N{r03N{s!)a7g00004XF*Lt006O%3;baP0000#P)t-s z|Ns9XAu<1@7$H(QDO$$fIU#cpDgV|&5Tz+0*2WlnIU$_h|7!@fAt{{RLZ$!SdpU$c zF;eeqbG=HO_obAu`V5W$00u=#L_t(|+U=R^a^pG(fK7UHQ*R?jdH-iUx(kpj3n~3^ zX2Q&FgC{nhK_F0;1&A=U)b|rvqyq53LbXB%cs_u!p|gOdLUi-h1i(B47yvpY06cW> z4f>G)KqG)`)|+@z}$jw1Dyz*ecdIVzyX{E)=LI(_Nj9sfdw$Z>JURP z3gGMq=f}U1zya9RdM1W|0<^!50fPOz6#(}q6L!U)%0R{_^DIiUN%3h#-#+LxLI%sJr9twf410_JM4xDX9 zLyNE*pkq7!O90xC-0Ka=p8}AUEcFefB^w0jTZA1=>EA9w<^%Hnb9JDz5T(HcbvSr1 z8LtDKrTA<#8xKL}X4ICMexR`(<9^`D0H_~mG$gqnpxt)Wz<3&l0VH?DQ9&VC$cX_w z7oevpg$EhSp$Rb3l)6zMw&hOI3_$0A>o$PAE!TMz&{*LBu@7hi2nUnS(F}YO>e`Ve zfOs^k52yaZoddYEXaR_a)1&b`UP$A4CxCc7?>?aD1dtz4bcg_84`V5tGfgh9cH&bMR05gY;N zO90$(F#d;5UK#`7Em)z`f>Z-Q&GCo_@S>_Tr5yn1&|JO5^|DFiA3z?YZIAAin?dOR_U0HQ;xJ?_A0Hdc8ZIQy5&wwZsB>{}B$x)kh5iJ#Ry zfb5tqcK~S+Qjjq$z=Z>72C!lP=|LsxK*IS%3ZRMr7QrxNfP4PM!vVO1tLrs>p;O$K zNe85WmSW}Cz~%)fk?)V99(#jjK6917m6>uWL{uWpSKTF`hZ1R>X+Y@ zl=|iNP4%w})whp10w51G_U$P!wtxHn#=0$zSl_mfDFXNc$Pcvk?I~PJb7TMKI}=#@ zrZ8TzzHR?LrU(dtvwzJ5&i+p(aQ3%M;OzgKA~4$xq#y+Qi6Gcd1i^kH2==E42*3jV z4D{{oEf5*Y#{T>Jd(hp!uqAt7J{kL;pPv)Mwc8 jOJ4Glm%QX9{~!4eIvAr2O*0f)00000NkvXXu0mjfAz2Up literal 0 HcmV?d00001 diff --git a/assets/tiletest.xmp b/assets/tiletest.xmp deleted file mode 100644 index d104cbdc11bd01dc455fad0b6f3f510aa10eab27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191861 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 BLXiLf diff --git a/dub.sdl b/dub.sdl index 2372fd6..3b96525 100644 --- a/dub.sdl +++ b/dub.sdl @@ -10,12 +10,13 @@ targetPath "./pixelperfectengine/lib/" dependency "sdlang-d" version="*" dependency "bindbc-sdl" version="*" versions "SDL_205" "BindSDL_Mixer" -dependency "dimage" version="==0.2.0" +dependency "dimage" version="==0.2.2" //dependency "datapak" version="==0.1.0-beta" dependency "cpublit" version="*" dependency "intel-intrinsics" version="*" dependency "libpcm" version="==0.2.2" dependency "bmfont" version="==0.1.0" +dependency "std-experimental-xml" version="*" subPackage{ name "pixelperfecteditor" targetType "executable" diff --git a/dub.selections.json b/dub.selections.json index 79976da..0c73438 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -2,17 +2,19 @@ "fileVersion": 1, "versions": { "bindbc-loader": "0.2.1", - "bindbc-sdl": "0.9.0", + "bindbc-sdl": "0.13.0", "bmfont": "0.1.0", "cpublit": "0.3.2", "derelict-fi": "2.0.3", "derelict-sdl2": "2.1.4", "derelict-util": "2.0.6", - "dimage": "0.2.0", - "intel-intrinsics": "1.1.1", + "dimage": "0.2.2", + "intel-intrinsics": "1.2.0", "libinputvisitor": "1.2.2", "libpcm": "0.2.2", "sdlang-d": "0.10.5", + "std-experimental-xml": "0.1.7", + "stdx-allocator": "2.77.5", "taggedalgebraic": "0.11.4", "unit-threaded": "0.7.55", "vfile": "0.1.2" diff --git a/pixelperfecteditor/src/PixelPerfectEditor/app.d b/pixelperfecteditor/src/PixelPerfectEditor/app.d index 3c71d93..81866d2 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/app.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/app.d @@ -38,14 +38,14 @@ public Editor prg; int main(string[] args){ initialzeSDL(); - /+if(args.length > 1){ + if(args.length > 1){ if(args[1] == "--test"){ TileLayerTest prg = new TileLayerTest(); prg.whereTheMagicHappens; - writeln(prg.isRunning); + //writeln(prg.isRunning); return 0; } - }+/ + } prg = new Editor(args); prg.whereTheMagicHappens; @@ -80,9 +80,9 @@ class TileLayerTest : SystemEventListener, InputListener{ OutputScreen output; Raster r; TileLayer t; - TransformableTileLayer!(Bitmap16Bit,32,32) tt; - ABitmap[] tiles; - Bitmap16Bit dlangMan; + TransformableTileLayer!(Bitmap8Bit,16,16) tt; + Bitmap8Bit[] tiles; + Bitmap8Bit dlangMan; SpriteLayer s; //Bitmap16Bit[wchar] tiles; InputHandler ih; @@ -91,43 +91,44 @@ class TileLayerTest : SystemEventListener, InputListener{ this(){ theta = 0; isRunning = true; - ExtendibleBitmap tileSource = new ExtendibleBitmap("../assets/tiletest.xmp"); - ExtendibleBitmap spriteSource = new ExtendibleBitmap("../assets/collisionTest.xmp"); - //t = new TileLayer(32,32, LayerRenderingMode.COPY); - tt = new TransformableTileLayer!(Bitmap16Bit,32,32)(LayerRenderingMode.COPY); + Image tileSource = loadImage(File("../assets/sci-fi-tileset.png")); + Image spriteSource = loadImage(File("../assets/d-man.tga")); + t = new TileLayer(16,16, LayerRenderingMode.COPY); + tt = new TransformableTileLayer!(Bitmap8Bit,16,16)(LayerRenderingMode.COPY); s = new SpriteLayer(LayerRenderingMode.ALPHA_BLENDING); //c = new CollisionDetector(); - dlangMan = loadBitmapFromXMP!Bitmap16Bit(spriteSource,"DLangMan"); + dlangMan = loadBitmapFromImage!Bitmap8Bit(spriteSource); //CollisionModel cm = new CollisionModel(dlangMan.width, dlangMan.height, dlangMan.generateStandardCollisionModel()); dlangMan.offsetIndexes(256,false); - s.addSprite(dlangMan,0,0,0); + s.addSprite(dlangMan, 0, 0, 0, 1); //s.scaleSpriteHoriz(0,-1024); //s.scaleSpriteVert(0,-1024); - for(int i = 1 ; i < 2 ; i++){ - s.addSprite(dlangMan,i,uniform(-31,320),uniform(-31,240)); + for(int i = 1 ; i < 10 ; i++){ + s.addSprite(dlangMan, i, uniform(-31,320), uniform(-31,240), 1); } //s.collisionDetector[1] = c; //c.source = s; //c.addCollisionModel(cm,0); //c.addCollisionModel(cm,1); //c.addCollisionListener(this); - tiles.length = tileSource.bitmapID.length; - for(int i; i < tileSource.bitmapID.length; i++){ - string hex = tileSource.bitmapID[i]; + //tiles.length = tileSource.bitmapID.length; + tiles = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, 16, 16);//loadBitmapSheetFromFile!Bitmap8Bit("../assets/sci-fi-tileset.png",16,16); + for(int i; i < tiles.length; i++){ + //string hex = tileSource.bitmapID[i]; //writeln(hex[hex.length-4..hex.length]); - ABitmap ab = loadBitmapFromXMP!Bitmap16Bit(tileSource, hex); - tiles[i] = ab; - tt.addTile(ab, to!wchar(parseHex(hex[hex.length-4..hex.length]))); + //ABitmap ab = loadBitmapFromXMP!Bitmap16Bit(tileSource, hex); + //tiles[i] = ab; + t.addTile(tiles[i], cast(wchar)i); } //wchar[] mapping; MappingElement[] mapping; - mapping.length = 16*16; + mapping.length = 64*64; //attrMapping.length = 256*256; for(int i; i < mapping.length; i++){ //mapping[i] = to!wchar(uniform(0x0000,0x00AA)); - int rnd = uniform(0,1024); + const int rnd = uniform(0,1024); //attrMapping[i] = BitmapAttrib(rnd & 1 ? true : false, rnd & 2 ? true : false); - mapping[i] = MappingElement(to!wchar(uniform(0x0000,0x00AA)), BitmapAttrib(rnd & 1 ? true : false, rnd & 2 ? true : false)); + mapping[i] = MappingElement(cast(wchar)(rnd & 63), BitmapAttrib(rnd & 1024 ? true : false, rnd & 512 ? true : false)); } ih = new InputHandler(); ih.sel ~= this; @@ -161,26 +162,32 @@ class TileLayerTest : SystemEventListener, InputListener{ ih.kb ~= KeyBinding(0, ScanCode.Q,0, "HM", Devicetype.KEYBOARD, KeyModifier.ANY); ih.kb ~= KeyBinding(0, ScanCode.W,0, "VM", Devicetype.KEYBOARD, KeyModifier.ANY); - tt.loadMapping(16,16,mapping); - tt.setWarpMode(true); - //tt.hBlankInterrupt = &ttlHBlankInterrupt; + t.loadMapping(64,64,mapping); + t.setWarpMode(false); + //t.setWrapMode(true); //tt.D = -256; output = new OutputScreen("TileLayer test", 1280,960); r = new Raster(320,240,output); output.setMainRaster(r); - loadPaletteFromXMP(tileSource, "default", r); + //loadPaletteFromXMP(tileSource, "default", r); + /*for(int y ; y < 240 ; y++){ for(int x ; x < 240 ; x++){ writeln('[',x,',',y,"] : ", t.transformFunc([x,y])); } }*/ - r.addLayer(tt, 0); + r.addLayer(t, 0); r.addLayer(s, 1); - r.palette ~= cast(Color[])spriteSource.getPalette("default"); - r.palette[0].alpha = 255; + Color[] localPal = loadPaletteFromImage(tileSource); + localPal.length = 256; + r.palette ~= localPal; + localPal = loadPaletteFromImage(spriteSource); + localPal.length = 256; + r.palette ~= localPal; + //r.palette[0].alpha = 255; r.palette[256].raw = 0; - writeln(tt); + //writeln(tt); //r.palette[0] = 255; //r.addRefreshListener(output, 0); @@ -196,10 +203,10 @@ class TileLayerTest : SystemEventListener, InputListener{ if(down) s.relMoveSprite(0,0,1); if(left) s.relMoveSprite(0,-1,0); if(right) s.relMoveSprite(0,1,0); - if(scrup) tt.relScroll(0,-1); - if(scrdown) tt.relScroll(0,1); - if(scrleft) tt.relScroll(-1,0); - if(scrright) tt.relScroll(1,0); + if(scrup) t.relScroll(0,-1); + if(scrdown) t.relScroll(0,1); + if(scrleft) t.relScroll(-1,0); + if(scrright) t.relScroll(1,0); //t.relScroll(1,0); } } diff --git a/pixelperfecteditor/src/PixelPerfectEditor/document.d b/pixelperfecteditor/src/PixelPerfectEditor/document.d index 6c72e96..68ca226 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/document.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/document.d @@ -38,12 +38,13 @@ public class MapDocument { * Loads the document from disk. */ public this(string filename) @trusted { - + events = new UndoableStack(20); } ///New from scratch public this(string docName, int resX, int resY) @trusted { events = new UndoableStack(20); mainDoc = new MapFormat(docName, resX, resY); + mode = EditMode.tilePlacement; } ///Returns the next available layer number. public int nextLayerNumber() @safe { @@ -93,6 +94,7 @@ public class MapDocument { } break; case EditMode.tilePlacement: + switch (button) { case MouseButton.LEFT: //Record the first cursor position upon mouse button press, then initialize either a single or zone write for the selected tile layer. @@ -100,11 +102,12 @@ public class MapDocument { prevMouseX = x; prevMouseY = y; } else { + ITileLayer target = cast(ITileLayer)(mainDoc[selectedLayer]); - x = (x + mainDoc[selectedLayer].getSX) / target.getTX; - y = (y + mainDoc[selectedLayer].getSY) / target.getTY; - prevMouseX = (prevMouseX + mainDoc[selectedLayer].getSX) / target.getTX; - prevMouseY = (prevMouseY + mainDoc[selectedLayer].getSY) / target.getTY; + x = (x - mainDoc[selectedLayer].getSX) / target.getTileWidth; + y = (y - mainDoc[selectedLayer].getSY) / target.getTileHeight; + prevMouseX = (prevMouseX - mainDoc[selectedLayer].getSX) / target.getTileWidth; + prevMouseY = (prevMouseY - mainDoc[selectedLayer].getSY) / target.getTileHeight; Coordinate c; if (x > prevMouseX){ c.left = prevMouseX; @@ -122,28 +125,32 @@ public class MapDocument { } if (voidfill) { - if (c.width == 1 && c.height == 1) { + if (c.width == 0 && c.height == 0) { if (target.readMapping(c.left, c.top).tileID == 0xFFFF) - target.writeMapping(c.left, c.top, selectedMappingElement); + events.addToTop(new WriteToMapSingle(target, c.left, c.top, selectedMappingElement)); + /+ target.writeMapping(c.left, c.top, selectedMappingElement);+/ + } else { - for (int y0 = c.top ; y0 <= c.bottom ; y0++){ + /+for (int y0 = c.top ; y0 <= c.bottom ; y0++){ for (int x0 = c.left ; x0 <= c.right ; x0++) { if (target.readMapping(x0, y0).tileID == 0xFFFF) target.writeMapping(x0, y0, selectedMappingElement); } - } + }+/ + events.addToTop(new WriteToMapVoidFill(target, c, selectedMappingElement)); } } else { - if (c.width == 1 && c.height == 1) { - target.writeMapping(c.left, c.top, selectedMappingElement); + if (c.width == 0 && c.height == 0) { + events.addToTop(new WriteToMapSingle(target, c.left, c.top, selectedMappingElement)); + } else { - for (int y0 = c.top ; y0 <= c.bottom ; y0++){ - for (int x0 = c.left ; x0 <= c.right ; x0++) { - target.writeMapping(x0, y0, selectedMappingElement); - } - } + events.addToTop(new WriteToMapOverwrite(target, c, selectedMappingElement)); } } + debug { + import std.stdio : writeln; + writeln(events.events); + } } break; case MouseButton.MID: @@ -161,6 +168,8 @@ public class MapDocument { default: break; } + outputWindow.draw(); + //outputWindow.updateRaster(); break; case EditMode.spritePlacement: break; @@ -188,4 +197,21 @@ public class MapDocument { updateLayerList; updateMaterialList; } + public void tileMaterial_FlipHorizontal() { + selectedMappingElement.attributes.horizMirror = !selectedMappingElement.attributes.horizMirror; + } + public void tileMaterial_FlipVertical() { + selectedMappingElement.attributes.vertMirror = !selectedMappingElement.attributes.vertMirror; + } + public void tileMaterial_Select(wchar id) { + selectedMappingElement.tileID = id; + mode = EditMode.tilePlacement; + + } + public void tileMaterial_PaletteUp() { + selectedMappingElement.paletteSel++; + } + public void tileMaterial_PaletteDown() { + selectedMappingElement.paletteSel--; + } } diff --git a/pixelperfecteditor/src/PixelPerfectEditor/editorEvents.d b/pixelperfecteditor/src/PixelPerfectEditor/editorEvents.d index dfab38d..5248184 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/editorEvents.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/editorEvents.d @@ -6,6 +6,8 @@ public import PixelPerfectEngine.concrete.eventChainSystem; public import PixelPerfectEngine.graphics.layers; public import PixelPerfectEngine.map.mapformat; +import PixelPerfectEngine.system.file; + import std.stdio; import std.conv : to; import sdlang; @@ -88,6 +90,10 @@ public class WriteToMapSingle : UndoableEvent { public void redo() { original = target.readMapping(x,y); target.writeMapping(x,y,me); + debug { + import std.stdio : writeln; + writeln("Layer was written at position ", x, ";", y," with values ", me); + } } public void undo() { target.writeMapping(x,y,original); @@ -107,6 +113,7 @@ public class CreateTileLayerEvent : UndoableEvent { string res; bool embed; Tag backup; + Image tileSource; public this(MapDocument target, int tX, int tY, int mX, int mY, dstring name, string file, string res, bool embed) { @@ -128,7 +135,6 @@ public class CreateTileLayerEvent : UndoableEvent { import std.file : exists, isFile; import std.path : baseName; import std.utf : toUTF8; - import PixelPerfectEngine.system.file; import PixelPerfectEngine.system.etc : intToHex; if (backup) { //If a backup exists, then re-add that to the document, then return. target.mainDoc.addNewLayer(pri, backup, creation); @@ -175,26 +181,26 @@ public class CreateTileLayerEvent : UndoableEvent { //TODO: generate dummy tiles for nonexistent material if (exists(res)) { //load the resource file and test if it's the correct size (through an exception) - Image i = loadImage(File(res)); + tileSource = loadImage(File(res)); ABitmap[] tilesheet; - switch (i.getBitdepth()) { + switch (tileSource.getBitdepth()) { case 4: - Bitmap4Bit[] output = loadBitmapSheetFromImage!Bitmap4Bit(i, tX, tY); + Bitmap4Bit[] output = loadBitmapSheetFromImage!Bitmap4Bit(tileSource, tX, tY); foreach(p; output) tilesheet ~= p; break; case 8: - Bitmap8Bit[] output = loadBitmapSheetFromImage!Bitmap8Bit(i, tX, tY); + Bitmap8Bit[] output = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, tX, tY); foreach(p; output) tilesheet ~= p; break; case 16: - Bitmap16Bit[] output = loadBitmapSheetFromImage!Bitmap16Bit(i, tX, tY); + Bitmap16Bit[] output = loadBitmapSheetFromImage!Bitmap16Bit(tileSource, tX, tY); foreach(p; output) tilesheet ~= p; break; case 32: - Bitmap32Bit[] output = loadBitmapSheetFromImage!Bitmap32Bit(i, tX, tY); + Bitmap32Bit[] output = loadBitmapSheetFromImage!Bitmap32Bit(tileSource, tX, tY); foreach(p; output) tilesheet ~= p; break; @@ -216,7 +222,24 @@ public class CreateTileLayerEvent : UndoableEvent { } target.mainDoc.addTileInfo(nextLayer, idList, res); } - writeln(target.mainDoc.layerData[nextLayer].toSDLString); + if (tileSource.isIndexed) { + Color[] palette; + /*foreach (color ; tileSource.palette) { + palette ~= Color(color.a, color.r, color.g, color.b); + debug writeln(color); + }*/ + auto sourcePalette = tileSource.palette; + palette.reserve(sourcePalette.length); + for (ushort i ; i < sourcePalette.length ; i++){ + const auto origC = sourcePalette[i]; + const Color c = Color(origC.a, origC.r, origC.g, origC.b); + palette ~= c; + } + debug writeln(palette); + target.mainDoc.addPaletteFile(file, "", cast(int)target.outputWindow.palette.length); + target.outputWindow.palette = target.outputWindow.palette ~ palette; + } + } target.outputWindow.addLayer(nextLayer); target.selectedLayer = nextLayer; diff --git a/pixelperfecteditor/src/PixelPerfectEditor/materialList.d b/pixelperfecteditor/src/PixelPerfectEditor/materialList.d index 4e06a25..02fd81e 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/materialList.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/materialList.d @@ -1,6 +1,8 @@ import PixelPerfectEngine.concrete.window; import PixelPerfectEngine.map.mapformat; +import app; + import std.utf : toUTF32; /** @@ -10,6 +12,7 @@ public class MaterialList : Window { ListBox listBox_materials; SmallButton[] buttons; public void delegate() onClose; + protected TileInfo[] tiles; protected static immutable dstring[] tileListHeaderS = ["ID"d, "Name"d]; protected static immutable dstring[] spriteListHeaderS = ["ID"d, "Name"d, "Dim"d]; protected static immutable int[] tileListHeaderW = [32, 120]; @@ -20,6 +23,7 @@ public class MaterialList : Window { StyleSheet ss = getStyleSheet(); listBox_materials = new ListBox("listBox0", Coordinate(1, 17, 129, 218), [], new ListBoxHeader(tileListHeaderS.dup, tileListHeaderW.dup)); + listBox_materials.onItemSelect = &onItemSelect; addElement(listBox_materials); { SmallButton sb = new SmallButton("trashButtonB", "trashButtonA", "trash", Coordinate(113, 234, 129, 250)); @@ -52,12 +56,22 @@ public class MaterialList : Window { } public void updateMaterialList(TileInfo[] list) @trusted { import PixelPerfectEngine.system.etc : intToHex; + tiles = list; ListBoxItem[] output; foreach (item ; list) { output ~= new ListBoxItem ([intToHex!dstring(item.id, 4) ~ "h", toUTF32(item.name)]); } listBox_materials.updateColumns(output, new ListBoxHeader(tileListHeaderS.dup, tileListHeaderW.dup)); } + private void vertMirror_onClick(Event ev) { + prg.selDoc.tileMaterial_FlipVertical(); + } + private void horizMirror_onClick(Event ev) { + prg.selDoc.tileMaterial_FlipHorizontal(); + } + private void onItemSelect(Event ev) { + prg.selDoc.tileMaterial_Select(tiles[ev.value].id); + } } /** * Defines a single material. diff --git a/pixelperfecteditor/src/PixelPerfectEditor/newTileLayer.d b/pixelperfecteditor/src/PixelPerfectEditor/newTileLayer.d index 53a8714..b81a4c5 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/newTileLayer.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/newTileLayer.d @@ -73,9 +73,10 @@ public class NewTileLayerDialog : Window { } private void button_TSBrowse_onClick(Event ev){ parent.addWindow(new FileDialog("Import Tile Source"d, "fileDialog_TSBrowse", &fileDialog_TSBrowse_event, - [FileDialog.FileAssociationDescriptor("PPE Map file", ["*.pmp"]), - FileDialog.FileAssociationDescriptor("TGA File", ["*.tga"]), - FileDialog.FileAssociationDescriptor("PNG file", ["*.png"])], "./")); + [FileDialog.FileAssociationDescriptor("All supported formats", ["*.pmp", "*.tga", "*.png"]), + FileDialog.FileAssociationDescriptor("PPE Map file", ["*.pmp"]), + FileDialog.FileAssociationDescriptor("TGA File", ["*.tga"]), + FileDialog.FileAssociationDescriptor("PNG file", ["*.png"])], "./")); } private void fileDialog_TSBrowse_event(Event ev){ textBox_TS.setText(toUTF32(ev.getFullPath)); diff --git a/pixelperfecteditor/src/PixelPerfectEditor/rasterWindow.d b/pixelperfecteditor/src/PixelPerfectEditor/rasterWindow.d index ae7d080..e1b65ed 100644 --- a/pixelperfecteditor/src/PixelPerfectEditor/rasterWindow.d +++ b/pixelperfecteditor/src/PixelPerfectEditor/rasterWindow.d @@ -28,7 +28,7 @@ public class RasterWindow : Window { public this(int x, int y, Color* paletteShared, dstring documentName, MapDocument document){ trueOutput = new Bitmap32Bit(x + 2,y + 18); rasterOutput = new Bitmap32Bit(x + 2, y + 18); - super(Coordinate(0, 0, x + 2, y + 18), documentName, ["settingsButtonA", "rightArrowA", "leftArrowA", + super(Coordinate(0, 0, x + 2, y + 18), documentName, ["paletteButtonA", "settingsButtonA", "rightArrowA", "leftArrowA", "downArrowA", "upArrowA",]); this.paletteShared = paletteShared; this.documentName = documentName; @@ -48,6 +48,7 @@ public class RasterWindow : Window { if(y >= ss.drawParameters["WindowHeaderHeight"] && y < trueOutput.height - 1 && x > 0 && x < trueOutput.width - 1) { y -= ss.drawParameters["WindowHeaderHeight"]; x--; + //Normal mode: //left : drag layer ; right : menu ; middle : quick nav ; other buttons : user defined //Selection mode: @@ -70,6 +71,7 @@ public class RasterWindow : Window { colorLookup(output.output.getPtr + (y * position.width), trueOutput.getPtr + (y * position.width), paletteShared, position.width); } + updateRaster(); /*if(drawHeaderOnly) return;*/ //draw the borders. we do not need fills or drawing elements @@ -88,17 +90,19 @@ public class RasterWindow : Window { public void updateRaster() { //update each layer individually for(int i ; i < layerList.length ; i++){ - document.mainDoc[layerList[i]].updateRaster(rasterOutput.getPtr, rasterX * 4, paletteLocal.ptr); + //document.mainDoc[layerList[i]].updateRaster(rasterOutput.getPtr, rasterX * 4, paletteLocal.ptr); + document.mainDoc[layerList[i]].updateRaster((trueOutput.getPtr + (17 * trueOutput.width) + 1), trueOutput.width * 4, + paletteLocal.ptr); } //copy the raster output to the target - Color* p0 = rasterOutput.getPtr, p1 = trueOutput.getPtr + (17 * trueOutput.width); - const int x = rasterOutput.width; - p1++; - for (int y ; y < rasterY; y++) { + //Color* p0 = rasterOutput.getPtr, p1 = trueOutput.getPtr + (17 * trueOutput.width); + //const int x = rasterOutput.width; + //p1++; + /*for (int y ; y < rasterY; y++) { helperFunc(p0, p1, x); p0 += x; p1 += trueOutput.width; - } + }*/ } /** * Adds a new layer then reorders the display list. diff --git a/pixelperfectengine/src/PixelPerfectEngine/concrete/elements.d b/pixelperfectengine/src/PixelPerfectEngine/concrete/elements.d index 933c51a..09c9b18 100644 --- a/pixelperfectengine/src/PixelPerfectEngine/concrete/elements.d +++ b/pixelperfectengine/src/PixelPerfectEngine/concrete/elements.d @@ -1900,10 +1900,32 @@ public class ListBoxHeader{ return textInputType[column]; } } +/** + * Defines a single row of a ListBox. Can be passed through the Event class. + */ +public class NewListBoxItem { + +} +/** + * Defines a single cell in a NewListBoxItem. + */ +public struct ListBoxCell { + /** + * Defines the currently held type of the cell. + */ + public enum TypeID : ubyte { + text, + decimalI, + decimalF, + hexadecimal, + bitmap, + } +} /** * Defines an item in the row of a ListBox. Can be passed through the Event class + * TO BE DEPRECATED. */ - public class ListBoxItem{ +public class OldListBoxItem { private dstring[] text; private uint[] textInputType; ///If value or array is null, the ListBoxHeader's textInputType is referred private Bitmap8Bit icon; /// If used, replaces the texts in the column defined by the ListBoxHeader, otherwise defaults to the text. @@ -1939,7 +1961,8 @@ public class ListBoxHeader{ result ~= ws; return to!string(result); } - } +} +alias ListBoxItem = OldListBoxItem; /* * For use with ListBoxes and similar types. Currently left here for legacy purposes, being replaced with the classes ListBoxHeader and ListBoxElement * diff --git a/pixelperfectengine/src/PixelPerfectEngine/concrete/eventChainSystem.d b/pixelperfectengine/src/PixelPerfectEngine/concrete/eventChainSystem.d index 870afcf..1bebda5 100644 --- a/pixelperfectengine/src/PixelPerfectEngine/concrete/eventChainSystem.d +++ b/pixelperfectengine/src/PixelPerfectEngine/concrete/eventChainSystem.d @@ -11,7 +11,7 @@ public interface UndoableEvent{ * Implements an undoable event list with automatic handling of undo/redo commands */ public class UndoableStack{ - protected UndoableEvent[] events; + public UndoableEvent[] events; protected size_t currentPos, currentCap, maxLength; public this(size_t maxElements) @safe pure nothrow{ @@ -41,7 +41,7 @@ public class UndoableStack{ /** * Redos top event. */ - public void redo(){ + public void redo() { if(currentPos >= 0){ if(events[currentPos]){ currentPos--; @@ -49,4 +49,10 @@ public class UndoableStack{ } } } + /** + * Returns the length of the current stack + */ + public size_t length() { + return events.length; + } } diff --git a/pixelperfectengine/src/PixelPerfectEngine/concrete/interfaces.d b/pixelperfectengine/src/PixelPerfectEngine/concrete/interfaces.d new file mode 100644 index 0000000..7e4f6ab --- /dev/null +++ b/pixelperfectengine/src/PixelPerfectEngine/concrete/interfaces.d @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015-2019, by Laszlo Szeremi under the Boost license. + * + * Pixel Perfect Engine, concrete.interfaces module + */ + +module PixelperfectEngine.concrete.interfaces; + +public import PixelPerfectEngine.graphics.fontsets; +public import PixelPerfectEngine.graphics.bitmap; +public import PixelPerfectEngine.graphics.common; +public import PixelPerfectEngine.concrete.text; + +/** + * Radio button interface. Can be used to implement radio button style behavior on almost any component that implements this interface. + */ +public interface IRadioButton { + /** + * If the radio button is pressed, then it sets to unpressed. Does nothing otherwise. + */ + public void latchOff() @trusted; + /** + * Sets the radio button into its pressed state. + */ + public void latchOn() @trusted; + /** + * Returns the current state of the radio button. + * True: Pressed. + * False: Unpressed. + */ + public void state() @safe @property const; + /** + * Sets the group of the radio button. + */ + public void setGroup(IRadioButtonGroup group) @safe @property; +} +/** + * Implements the basis of a radio button group. + */ +public interface IRadioButtonGroup { + /** + * Adds a radio button to the group. + */ + public void add(IRadioButton rg) @safe; + /** + * Removes a radio button from the group. + */ + public void remove(IRadioButton rg) @safe; + /** + * Groups receive latch signals here. + */ + public void latch(IRadioButton sender) @safe; +} +/** + * IMPORTANT: This will replace the current drawing methods by version 1.0.0 + * The older method of using multiple BitmapDrawer class will be removed by that point. + *
+ * Implements the frontend of a drawable canvas, primarily for GUI elements. + * Mostly limited to 256 colors, certain methods (eg. blitting) might enable more. + */ +public interface Canvas { + ///Draws a line. + public void drawLine(int x0, int y0, int x1, int y1, ubyte color, int lineWidth = 1) @trusted; + ///Draws an empty rectangle + public void drawRectangle(int x0, int y0, int x1, int y1, ubyte color, int lineWidth = 1) @trusted; + ///Draws a filled rectangle + public void drawFilledRectange(int x0, int y0, int x1, int y1, ubyte color, int lineWidth = 1) @trusted; + ///Fills an area with the specified color + public void fill(int x0, int y0, ubyte color, ubyte background = 0) @trusted; + ///Draws a text with the specified data. Can be multiline. + public void drawText(int x0, int y0, Fontset!Bitmap8Bit font, dstring text, ubyte color) @trusted; + ///Draws a fully formatted text. Can be multiline. + public void drawText(int x0, int y0, Text!Bitmap8Bit text) @trusted; + ///Draws a text within the given area with the specified data. Can be multiline. + public void drawText(Coordinate c, Fontset!Bitmap8Bit font, dstring text, ubyte color) @trusted; + ///Draws a fully formatted text within the specified area. Can be multiline. + public void drawText(Coordinate c, Text!Bitmap8Bit text) @trusted; + ///Draws a text with the specified data and offset from the upper-left corner. Can be multiline. + public void drawText(int x0, int y0, int sliceX, int sliceY, Fontset!Bitmap8Bit font, dstring text, ubyte color) + @trusted; + ///Draws a fully formatted text with offset from the upper-left corner. Can be multiline. + public void drawText(int x0, int y0, int sliceX, int sliceY, Text!Bitmap8Bit text) @trusted; + public void drawText(Coordinate c, int sliceX, int sliceY, Fontset!Bitmap8Bit font, dstring text, ubyte color) + @trusted; + public void drawText(Coordinate c, int sliceX, int sliceY, Text!Bitmap8Bit text) @trusted; + public void bitBLiT(int x0, int y0, ABitmap source) @trusted; + public void bitBLiT(int x0, int y0, int x1, int y1, ABitmap source) @trusted; + public void bitBLiT(int x0, int y0, Coordinate slice, ABitmap source) @trusted; + public void xorBLiT(int x0, int y0, int x1, int y1, ubyte color) @trusted; + public void xorBLiT(int x0, int y0, ABitmap source) @trusted; +} diff --git a/pixelperfectengine/src/PixelPerfectEngine/concrete/text.d b/pixelperfectengine/src/PixelPerfectEngine/concrete/text.d new file mode 100644 index 0000000..bbc4780 --- /dev/null +++ b/pixelperfectengine/src/PixelPerfectEngine/concrete/text.d @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2015-2019, by Laszlo Szeremi under the Boost license. + * + * Pixel Perfect Engine, concrete.text module + */ + +module PixelPerfectEngine.concrete.text; + +public import PixelPerfectEngine.graphics.fontsets; +public import PixelPerfectEngine.graphics.bitmap; + +//import std.xml; +import std.experimental.xml.sax; +import dom = std.experimental.xml.dom; +import std.experimental.xml.lexers; +import std.experimental.xml.parser; + +/** + * Implements a formatted text chunk, that can be serialized in XML form. + * Has a linked list structure to easily link multiple chunks after each other. + */ +public class Text(BitmapType = Bitmap8Bit) { + + public dstring text; ///The text to be displayed + public CharacterFormattingInfo!BitmapType formatting; ///The formatting of this text block + public Text next; ///The next piece of formatted text block + public int frontTab; ///Space before the text chunk in pixels. Can be negative. + public BitmapType icon; ///Icon inserted in front of the text chunk. + public byte iconOffsetX; ///X offset of the icon if any + public byte iconOffsetY; ///Y offset of the icon if any + /** + * Creates a unit of formatted text from the supplied data. + */ + public this(dstring text, CharacterFormattingInfo!BitmapType formatting, Text next = null, int frontTab = 0, + BitmapType icon = null) @safe pure @nogc nothrow { + this.text = text; + this.formatting = formatting; + this.next = next; + this.frontTab = frontTab; + this.icon = icon; + } + /** + * Parses formatted text from binary. + * Header is the first 4 bytes of the stream. + */ + public this(ubyte[] stream, Fontset!BitmapType[uint] fonts) @safe pure { + import PixelPerfectEngine.system.etc : reinterpretCast, reinterpretGet; + assert (stream.length > 4, "Bytestream too short!"); + const uint header = reinterpretGet!uint(stream[0..4]); + stream = stream[4..$]; + switch (header & 0xF) { + case TextType.UTF8: + __ctor(TextType.UTF8, stream, fonts); + break; + case TextType.UTF32: + __ctor(TextType.UTF32, stream, fonts); + break; + default: + throw new Exception ("Binary character formatting stream error!"); + } + } + private this(TextType type, ubyte[] stream, Fontset!BitmapType[uint] fonts) @safe pure { + import PixelPerfectEngine.system.etc : reinterpretCast, reinterpretGet; + import std.utf : toUTF32; + //uint header = reinterpretGet!uint(stream[0..4]); + //stream = stream[4..$]; + if (stream[0] == FormattingCharacters.binaryCFI) { + stream = stream[1..$]; + Fontset!BitmapType fontType = fonts[reinterpretGet!uint(stream[0..4])]; + const ubyte color = stream[7]; + const uint formatFlags = reinterpretGet!uint(stream[8..12]); + const ushort paragraphSpace = reinterpretGet!ushort(stream[12..14]); + const short rowHeight = reinterpretGet!short(stream[14..16]); + formatting = new CharacterFormattingInfo!BitmapType(fontType, color, formatFlags, paragraphSpace, rowHeight); + stream = stream[16..$]; + } else throw new Exception("Binary character formatting stream error!"); + if (stream[0] == FormattingCharacters.binaryLI) { + stream = stream[1..$]; + const uint charStrmL = reinterpretGet!uint(stream[0..4]); + if (charStrmL <= stream.length) { + stream = stream[4..$]; + if(type == TextType.UTF8) + text = toUTF32(reinterpretCast!char(stream[0..charStrmL])); + else if(type == TextType.UTF32) + text = reinterpretCast!dchar(stream[0..charStrmL]); + stream = stream[charStrmL..$]; + } else throw new Exception("Binary character formatting stream error!"); + if (stream.length) { + next = new Text!BitmapType(type, stream, fonts); + } + } + } + /** + * Returns the text as a 32bit string without the formatting. + */ + public dstring toDString() @safe pure nothrow { + if (next) + return text ~ next.toDString; + else + return text; + } +} + +/** + * Parses text from XML/ETML + * + * See "ETML.md" for info. + */ +public class TextParser(BitmapType = Bitmap8Bit, StringType = string) + /+if((typeof(BitmapType) is Bitmap8Bit || typeof(BitmapType) is Bitmap16Bit || + typeof(BitmapType) is Bitmap32Bit) && (typeof(StringType) is string || typeof(StringType) is dstring))+/ { + private Text!BitmapType current; ///Current element + //private Text!BitmapType _output; ///Root/output element + private Text!BitmapType[] stack; ///Mostly to refer back to previous elements + private CharacterFormattingInfo!BitmapType currFrmt;///currently parsed formatting + public CharacterFormattingInfo!BitmapType[] chrFrmt;///All character format, that has been parsed so far + private CharacterFormattingInfo!BitmapType defFrmt;///Default character formatting. Must be set before parsing + public Fontset!BitmapType[string] fontsets;///Fontset name association table + public BitmapType[string] icons; ///Icon name association table + private StringType _input; ///The source XML/ETML document + ///Constructor with no arguments + public this() @safe pure nothrow { + reset(); + } + ///Creates a new instance with a select string input. + public this(StringType _input) @safe pure nothrow { + this._input = _input; + __ctor(); + } + ///Resets the output, but keeps the public parameters. + ///Input must be set to default or to new target separately. + public void reset() @safe pure nothrow { + current = new Text!BitmapType("", null); + //_output = current; + stack ~= current; + } + ///Sets the default formatting + public CharacterFormattingInfo!BitmapType defaultFormatting(CharacterFormattingInfo!BitmapType val) @property @safe + pure nothrow { + if (stack[0].formatting is null) { + stack[0].formatting = val; + } + defFrmt = val; + return defFrmt; + } + ///Gets the default formatting + public CharacterFormattingInfo!BitmapType defaultFormatting()@property @safe pure nothrow @nogc { + return defFrmt; + } + ///Returns the root/output element + public Text!BitmapType output() @property @safe @nogc pure nothrow { + return stack[0]; + } + ///Sets/gets the input + public StringType input() @property @safe @nogc pure nothrow inout { + return _input; + } + /** + * Parses the formatted text, then returns the output. + */ + public Text!BitmapType parse() @trusted { + import std.conv : to; + static struct XMLHandler(T) { + private void finalizeFormatting() { + if (current.text.length) { //finalize text chunk if new format is used + //check for duplicates in the previous ones, if there's none, then add the new one + CharacterFormattingInfo!BitmapType f0; + foreach (f; chrFrmt) { + if (f == currFrmt) { + f0 = f; + } + } + if (f0) { + current.formatting = f0; + } else { + current.formatting = currFrmt; + chrFrmt ~= currFrmt; + } + + Text!BitmapType nextChunk = new Text!BitmapType(null, current.formatting, null); + current.next = nextChunk; + current = nextChunk; + } + } + //Create a new text instance for every new tag + void onElementStart (ref T node) { + import std.ascii : toLower; + dom.Element!StringType node0 = cast(dom.Element!StringType)node; + void parseLineStrikeFormatting() { + bool updateFormat; + if (node0.hasAttribute("style")) { + switch (toLower(node0.getAttribute("style"))) { + case "normal": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineStyle); + //currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags. + break; + case "dotted": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineStyle); + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineDotted; + break; + case "wavy": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineStyle); + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineWavy; + break; + case "wavySoft": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineStyle); + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineWavySoft; + break; + case "stripes": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineStyle); + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineStripes; + break; + default: + break; + } + updateFormat = true; + } + if (node0.hasAttribute("lines")) { + switch (toLower(node0.getAttribute("lines"))) { + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineMultiplier); + /+case "single": + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulLineMultiplier); + break;+/ + case "double": + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineDouble; + break; + case "triple": + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineTriple; + break; + case "quad", "quadruple": + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.underlineQuadruple; + break; + default: + break; + } + updateFormat = true; + } + if (node0.hasAttribute("perWord")) { + if (toLower(node0.getAttribute("perWord")) == "true") { + currFrmt.formatFlags = currFrmt.formatFlags | FormattingFlags.ulPerWord; + } else { + currFrmt.formatFlags = currFrmt.formatFlags & (uint.max ^ FormattingFlags.ulPerWord); + } + updateFormat = true; + } + return updateFormat; + } + void parseFontFormatting() { + bool updateFormat; + if (node0.hasAttribute("type")) { + currFrmt.fontType = fontsets[node0.getAttribute("type")]; + updateFormat = true; + } + if (node0.hasAttribute("color")) { + static if(BitmapType.stringof == Bitmap32Bit.stringof) { + //currFrmt.color = + } else static if(BitmapType.stringof == Bitmap8Bit.stringof) { + currFrmt.color = to!ubyte(node0.getAttribute("color")); + } else static if(BitmapType.stringof == Bitmap16Bit.stringof) { + currFrmt.color = to!ushort(node0.getAttribute("color")); + } + updateFormat = true; + } + return updateFormat; + } + switch (node0.localName) { + case "p": + if (node0.hasAttributes) { + parseFontFormatting(); + } + break; + case "u": + currFrmt.formatFlags |= FormattingFlags.underline; + parseLineStrikeFormatting(); + break; + case "o": + currFrmt.formatFlags |= FormattingFlags.overline; + parseLineStrikeFormatting(); + break; + case "s": + currFrmt.formatFlags |= FormattingFlags.strikeThrough; + parseLineStrikeFormatting(); + break; + case "font": + parseFontFormatting(); + break; + default: + break; + } + //Start new chunk on beginning then push it to the stack + Text!BitmapType nextChunk = new Text!BitmapType(null, current.formatting, null); + current.next = nextChunk; + current = nextChunk; + stack ~= current; + } + //Finalize the current text instance + void onElementEnd (ref T node) { + //if (node.localName == "p") {//Insert new paragraph character at the end of a paragraph + current ~= FormattingCharacters.newParagraph; + //} else if (node.localName == "font") { + + //} + finalizeFormatting(); + if(stack.length > 1) + stack.length = stack.length - 1; + } + void onElementEmpty (ref T node) { + + dom.Element!StringType node0 = cast(dom.Element!StringType)node; + switch (node0.localName) { + case "br": + current ~= FormattingCharacters.newLine; + break; + case "icon": + if (node0.hasAttributes) { + + if (node0.hasAttribute("src")) { + string a = to!string(node0.getAttribute("src")); + if (current.text == "") { + current.icon = icons[a]; + } else { + Text!BitmapType nextChunk = new Text!BitmapType(null, current.formatting, null, 0, icons[a]); + current.next = nextChunk; + current = nextChunk; + //stack[$-1] = current; + } + } else { + throw new XMLTextParsingException("Missing src attribute from tag \"\"!"); + } + if (node0.hasAttribute("offsetX")) { + current.iconOffsetX = to!byte(node0.getAttribute("offsetX")); + } + if (node0.hasAttribute("offsetY")) { + current.iconOffsetY = to!byte(node0.getAttribute("offsetY")); + } + } else { + throw new XMLTextParsingException("Missing src attribute from tag \"\"!"); + } + break; + default: + break; + } + } + void onProcessingInstruction (ref T node) { } + // + void onText (ref T node) @safe { + import std.utf : toUTF32; + dom.Text!StringType text = cast(dom.Text!StringType)node; + current.text = text.data; + } + void onDocument (ref T node) { } + void onComment (ref T node) { } + } + /+auto xmlParser = xml.lexer.parser.cursor.saxParser!XMLHandler; + xmlParser.setSource(_input); + xmlParser.processDocument();+/ + return stack[0]; + } +} + +static TextParser!(Bitmap8Bit) test; + +unittest { + TextParser!(Bitmap8Bit) parser; + string exampleFormattedText = ` + + +

+ This is an example formatted text for the PixelPerfectEngine's "concrete" module. + + This example contains italic, underline, overline, and strike out text. + + This text has the color 15. + + + ` + parser = new TextParser!(Bitmap8Bit)(exampleFormattedText); +} +public class XMLTextParsingException : Exception { + @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) { + super(msg, file, line, nextInChain); + } + + @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__) { + super(msg, file, line, nextInChain); + } +} diff --git a/pixelperfectengine/src/PixelPerfectEngine/concrete/window.d b/pixelperfectengine/src/PixelPerfectEngine/concrete/window.d index f9cd81b..d09d1c3 100644 --- a/pixelperfectengine/src/PixelPerfectEngine/concrete/window.d +++ b/pixelperfectengine/src/PixelPerfectEngine/concrete/window.d @@ -696,7 +696,7 @@ public class FileDialog : Window{ /** * Creates an action event, then closes the window. */ - private void fileEvent(Event ev){ + private void fileEvent(Event ev) { //wstring s = to!wstring(directory); filename = to!string(tb.getText); //al.actionEvent("file", EventType.FILEDIALOGEVENT, 0, s); @@ -704,10 +704,11 @@ public class FileDialog : Window{ onFileselect(new Event(source, "", directory, filename, null, selectedType, EventType.FILEDIALOGEVENT)); parent.closeWindow(this); } - private void event_fileSelector(Event ev){ + private void event_fileSelector(Event ev) { selectedType = ev.value; + spanDir(); } - private void button_type_onMouseLClickRel(Event ev){ + private void button_type_onMouseLClickRel(Event ev) { PopUpMenuElement[] e; for(int i ; i < filetypes.length ; i++){ e ~= new PopUpMenuElement(filetypes[i].types[0],filetypes[i].description, filetypes[i].getTypesForSelector()); @@ -716,10 +717,10 @@ public class FileDialog : Window{ p.onMouseClick = &event_fileSelector; parent.addPopUpElement(p); } - private void button_close_onMouseLClickRel(Event ev){ + private void button_close_onMouseLClickRel(Event ev) { parent.closeWindow(this); } - private void listBox_onItemSelect(Event ev){ + private void listBox_onItemSelect(Event ev) { try{ if(pathList.length == 0) return; if(isDir(pathList[ev.value])){ diff --git a/pixelperfectengine/src/PixelPerfectEngine/graphics/fontsets.d b/pixelperfectengine/src/PixelPerfectEngine/graphics/fontsets.d index 4ff0776ae6233c9f2783cb44686fefc72c770238..ef72d1ef4f7a0dad1d11ef978db5829deb1033c2 100644 GIT binary patch literal 18954 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 T^^6$rd(9o{199j56CL~q)6TZ2 delta 159 zcmeC0!Z;~lgB9!M6RcItlP_`ROm^T3+dP9yk7@D=9v#kV1}+9p5S;ADB|lk?H*0bi zuhQmqyjF~pA6RHjb`ap0{J=(Jvl0I^#>st_Zj-qz= mX || y >= mY || x < 0 || y < 0) return MappingElement(0xFFFF); + if(x >= mX || y >= mY) return MappingElement(0xFFFF); return mapping[x + y*mX]; } public @nogc override void updateRaster(void* workpad, int pitch, Color* palette){ - //import core.stdc.stdio; - int y = sY < 0 && !warpMode ? sY * -1 : 0; - int sY0 = cast(int)(cast(uint)(sY) & 0b0111_1111_1111_1111_1111_1111_1111_1111); - int offsetP = y*pitch; // The offset of the line that is being written - const int offsetY = sY0 % tileY; //Scroll offset upwards - const int offsetY0 = (sY + rasterY) % tileY; - const int offsetXA = sX%tileX; // tile offset of the first column - //for( ; y < rasterY ; y+=tileY){ - while(y < rasterY){ - //int offsetY = tileX * ((y + sY)%tileY); - const int offsetYA = !y ? offsetY : 0; //top offset for first tile, 0 otherwise - const int offsetYB = y + tileY > rasterY ? offsetY0 : tileY; //bottom offset of last tile, equals tileY otherwise - uint x = (cast(uint)(sY) & 0b0111_1111_1111_1111_1111_1111_1111_1111); - const int targetX = totalX - sX > rasterX && !warpMode ? rasterX : rasterX - (totalX - sX); - void *p0 = (workpad + (x*Color.sizeof) + offsetP); - while(x < targetX){ - MappingElement currentTile = tileByPixel(x+sX,y+sY); - int tileXtarget = x + tileX < rasterX ? tileX : tileX - ((x + tileX) - rasterX) ; // the length of the displayed tile - int xp = (offsetXA != 0 && x == 0) ? offsetXA : 0; // offset of the first column - tileXtarget -= xp; // length of the first tile - if(currentTile.tileID != 0xFFFF){ // skip if tile is null - //BitmapAttrib tileAttrib = tileAttributeByPixel(x+sX,y+sY); - const DisplayListItem d = displayList[currentTile.tileID]; // pointer to the current tile's pixeldata - int tileYOffset = tileY; - tileYOffset *= currentTile.attributes.vertMirror ? -1 : 1; //vertical mirroring - //int pitchOffset = pitch * threads.length; - void* p1 = p0; - switch(d.wordLength){ - case 4: - ubyte* c = cast(ubyte*)d.pixelDataPtr; - c += currentTile.attributes.vertMirror ? ((tileY - offsetYA - 1) * tileX)>>1 : (offsetYA * tileX)>>1; - for(int y0 = offsetYA ; y0 < offsetYB ; y0++){ - main4BitColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)(palette + (currentTile.paletteSel<<4)), tileX, - x & 1); + int sX0 = sX, sY0 = sY; + if (hBlankInterrupt !is null) + hBlankInterrupt(-1, sX0, sY0); + + for (int line ; line < rasterY ; line++) { + if (hBlankInterrupt !is null) + hBlankInterrupt(line, sX0, sY0); + if ((sY0 >= 0 && sY0 < totalY) || warpMode) { + int sXAbs = warpMode ? sX0 & int.max : sX0, sYAbs = sY0 & int.max; + const sizediff_t offsetP = line * pitch; // The offset of the line that is being written + void* w0 = workpad + offsetP; + const int offsetY = sYAbs % tileY; //Offset of the current line of the tiles in this line + const int offsetX0 = tileX - ((sXAbs + rasterX) % tileX); //Scroll offset of the rightmost column + const int offsetX = (sXAbs & int.max) % tileX; //Scroll offset of the leftmost column + int tileXLength = offsetX ? tileX - offsetX : tileX; + for (int col ; col < rasterX ; ) { + const MappingElement currentTile = tileByPixel(sXAbs, sYAbs); + if (currentTile.tileID != 0xFFFF) { + const DisplayListItem tileInfo = displayList[currentTile.tileID]; + const int offsetX1 = col ? 0 : offsetX; + const int offsetY0 = currentTile.attributes.vertMirror ? tileY - offsetY : offsetY; + if (col + tileXLength > rasterX) { + tileXLength -= offsetX0; + } + final switch (tileInfo.wordLength) { + case 4: + ubyte* tileSrc = cast(ubyte*)tileInfo.pixelDataPtr + (offsetX1 + (offsetY0 * tileX)>>>1); + main4BitColorLookupFunction(tileSrc, cast(uint*)src, (cast(uint*)palette) + (currentTile.paletteSel<<4), + tileXLength, offsetX1 & 1); if(currentTile.attributes.horizMirror){//Horizontal mirroring flipHorizontal(cast(uint*)src.ptr, tileX); } - mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget); - c += tileYOffset>>>1; - p1 += pitch; - } - break; - case 8: - ubyte* c = cast(ubyte*)d.pixelDataPtr; - c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX; - for(int y0 = offsetYA ; y0 < offsetYB ; y0++){ - main8BitColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)(palette + (currentTile.paletteSel<<4)), tileX); + mainRenderingFunction(cast(uint*)src,cast(uint*)w0,tileXLength); + break; + case 8: + ubyte* tileSrc = cast(ubyte*)tileInfo.pixelDataPtr + offsetX1 + (offsetY0 * tileX); + main8BitColorLookupFunction(tileSrc, cast(uint*)src, (cast(uint*)palette) + (currentTile.paletteSel<<8), tileXLength); if(currentTile.attributes.horizMirror){//Horizontal mirroring flipHorizontal(cast(uint*)src.ptr, tileX); } - mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget); - c += tileYOffset; - p1 += pitch; - } - break; - case 16: - ushort* c = cast(ushort*)d.pixelDataPtr; - c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX; - for(int y0 = offsetYA ; y0 < offsetYB ; y0++){ - mainColorLookupFunction(c, cast(uint*)src.ptr, cast(uint*)palette, tileX); + mainRenderingFunction(cast(uint*)src,cast(uint*)w0,tileXLength); + break; + case 16: + ushort* tileSrc = cast(ushort*)tileInfo.pixelDataPtr + offsetX1 + (offsetY0 * tileX); + mainColorLookupFunction(tileSrc, cast(uint*)src, (cast(uint*)palette), tileXLength); if(currentTile.attributes.horizMirror){//Horizontal mirroring flipHorizontal(cast(uint*)src.ptr, tileX); } - mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget); - c += tileYOffset; - p1 += pitch; - } - break; - case 32: - Color* c = cast(Color*)d.pixelDataPtr; - c += currentTile.attributes.vertMirror ? (tileY - offsetYA - 1) * tileX : offsetYA * tileX; - for(int y0 = offsetYA ; y0 < offsetYB ; y0++){ - if(currentTile.attributes.horizMirror){//Horizontal mirroring - copy32bit(cast(uint*)c, cast(uint*)src.ptr, tileX); + mainRenderingFunction(cast(uint*)src,cast(uint*)w0,tileXLength); + break; + case 32: + Color* tileSrc = cast(Color*)tileInfo.pixelDataPtr + offsetX1 + (offsetY0 * tileX); + if(!currentTile.attributes.horizMirror) { + mainRenderingFunction(cast(uint*)tileSrc,cast(uint*)w0,tileXLength); + } else { + CPUblit.composing.copy32bit(cast(uint*)tileSrc, cast(uint*)src, tileXLength); flipHorizontal(cast(uint*)src.ptr, tileX); - mainRenderingFunction(cast(uint*)src.ptr + xp, cast(uint*)p1, tileXtarget); - }else{ - mainRenderingFunction(cast(uint*)(c + xp), cast(uint*)p1, tileXtarget); + mainRenderingFunction(cast(uint*)src,cast(uint*)w0,tileXLength); } - c += tileYOffset; - p1 += pitch; - } - break; - default: - break; + break; + + } + } + sXAbs += tileXLength; + col += tileXLength; + w0 += tileXLength<<2; + tileXLength = tileX; } - p0 += tileXtarget * Color.sizeof; - x+=tileXtarget; } - offsetP += !y ? pitch * (tileY - offsetY) : pitch * tileY; - /*if(y + tileY > y) y += tileY - offsetY0; - else if(y) y += tileY; - else y += (tileY - offsetY);*/ - y += !y ? (tileY - offsetY) : tileY; + sY0++; } - - } public MappingElement[] getMapping(){ return mapping; @@ -938,7 +925,7 @@ public class SpriteLayer : Layer, ISpriteLayer{ this.width = sprite.width; this.height = sprite.height; this.priority = priority; - //this.attributes = attributes; + this.paletteSel = paletteSel; this.scaleVert = scaleVert; this.scaleHoriz = scaleHoriz; slice = Coordinate(0,0,sprite.width,sprite.height); @@ -1290,7 +1277,7 @@ public class SpriteLayer : Layer, ISpriteLayer{ case 4: ubyte* p0 = cast(ubyte*)i.pixelData + i.width * ((i.scaleVert < 0 ? (i.height - offsetYA0 - 1) : offsetYA0)>>1); for(int y = offsetYA ; y < i.slice.height - offsetYB ; ){ - horizontalScaleNearest4BitAndCLU(p0, src.ptr, palette + (i.paletteSel << 4), scalelength, offsetXA & 1, + horizontalScaleNearest4BitAndCLU(p0, src.ptr, palette + (i.paletteSel<<4), scalelength, offsetXA & 1, i.scaleHoriz); prevOffset += offsetAmount; for(; offset < prevOffset; offset += scaleVertAbs){ @@ -1305,7 +1292,7 @@ public class SpriteLayer : Layer, ISpriteLayer{ case 8: ubyte* p0 = cast(ubyte*)i.pixelData + i.width * (i.scaleVert < 0 ? (i.height - offsetYA0 - 1) : offsetYA0); for(int y = offsetYA ; y < i.slice.height - offsetYB ; ){ - horizontalScaleNearestAndCLU(p0, src.ptr, palette + (i.paletteSel << 8), scalelength, i.scaleHoriz); + horizontalScaleNearestAndCLU(p0, src.ptr, palette + (i.paletteSel<<8), scalelength, i.scaleHoriz); prevOffset += 1024; for(; offset < prevOffset; offset += scaleVertAbs){ y++; diff --git a/pixelperfectengine/src/PixelPerfectEngine/map/mapformat.d b/pixelperfectengine/src/PixelPerfectEngine/map/mapformat.d index a9586e5..f7b8340 100644 --- a/pixelperfectengine/src/PixelPerfectEngine/map/mapformat.d +++ b/pixelperfectengine/src/PixelPerfectEngine/map/mapformat.d @@ -23,21 +23,24 @@ public class MapFormat { public Tag[int] layerData; ///Layerdata stored as SDLang tags. protected Layer[int] layeroutput; ///Used to fast map and object data pullback in editors protected Tag metadata; ///Stores metadata. + protected Tag root; ///Root tag for common information. public TileInfo[][int] tileDataFromExt;///Stores basic TileData that are loaded through extensions /** * Creates new instance from scratch. */ public this (string name, int resX, int resY) @trusted { - metadata = new Tag(null, null, "Metadata"); + root = new Tag("", "", null); + metadata = new Tag(root, null, "Metadata"); new Tag(metadata, null, "Name", [Value(name)]); new Tag(metadata, null, "resX", [Value(resX)]); new Tag(metadata, null, "resY", [Value(resY)]); + } /** * Serializes itself from string. */ public this (string source) @trusted { - Tag root = parseSource(source); + root = parseSource(source); //Just quickly go through the tags and sort them out foreach (Tag t0 ; root.all.tags) { switch (t0.namespace) { @@ -106,9 +109,7 @@ public class MapFormat { if(list.length == 0) throw new Exception("Empty list!"); Tag t; foreach (Tag t0 ; layerData[pri].namespaces["File"].tags) { - // Bug: Tag.getAttribute generates an out of memory bound error. - // Current solution: wait until it gets fixed. - if (t0.name == "TileSource" && t0.values[0] == source/+ && t.getAttribute!string("dataPakSrc", null) == dpkSource+/) { + if (t0.name == "TileSource" && t0.values[0] == source && t0.getAttribute!string("dataPakSrc", null) == dpkSource) { t = t0.getTag("Embed:TileInfo", null); if (t is null) t = new Tag(t0, "Embed", "TileInfo"); break; @@ -124,7 +125,7 @@ public class MapFormat { ///Ditto, but from preexisting Tag. public void addTileInfo(int pri, Tag t, string source, string dpkSource = null) @trusted { foreach (Tag t0 ; layerData[pri].namespaces["File"].tags) { - if (t0.name == "TileSource" && t0.values[0] == source && t.getAttribute!string("dataPakSrc", null) == dpkSource) { + if (t0.name == "TileSource" && t0.values[0] == source && t0.getAttribute!string("dataPakSrc", null) == dpkSource) { t0.add(t); return; } @@ -188,7 +189,7 @@ public class MapFormat { */ public void addNewTileLayer(int pri, int tX, int tY, int mX, int mY, string name, TileLayer l) @trusted { layeroutput[pri] = l; - layerData[pri] = new Tag(null, "Layer", "Tile", [Value(name), Value(pri), Value(tX), Value(tY), Value(mX), Value(mY)]); + layerData[pri] = new Tag(root, "Layer", "Tile", [Value(name), Value(pri), Value(tX), Value(tY), Value(mX), Value(mY)]); //new Tag(null, null, "priority", [Value(pri)]); } /** @@ -276,9 +277,9 @@ public class MapFormat { * Adds a TileData file to a TileLayer. * Filename must contain relative path. */ - public void addMapDataFile(int pri, string filename, string dpkSource = null) @trusted { + public void addMapDataFile(int pri, string filename, string dataPakSrc = null) @trusted { Attribute[] a; - if (dpkSource !is null) a ~= new Attribute("dpkSource", Value(dpkSource)); + if (dataPakSrc !is null) a ~= new Attribute("dataPakSrc", Value(dataPakSrc)); new Tag(layerData[pri], "File", "MapData", [Value(filename)], a); } /+///Ditto, but for files found in DataPak archives @@ -319,9 +320,9 @@ public class MapFormat { /** * Adds a tile source file to a TileLayer. */ - public void addTileSourceFile(int pri, string filename, string dpkSource = null, int offset = 0) @trusted { + public void addTileSourceFile(int pri, string filename, string dataPakSrc = null, int offset = 0) @trusted { Attribute[] a; - if (dpkSource !is null) a ~= new Attribute("dataPakSrc", Value(dpkSource)); + if (dataPakSrc !is null) a ~= new Attribute("dataPakSrc", Value(dataPakSrc)); if (offset) a ~= new Attribute("offset", Value(offset)); new Tag(layerData[pri], "File", "TileSource", [Value(filename)], a); } @@ -329,18 +330,12 @@ public class MapFormat { * Removes a tile source. * Returns a backup copy. */ - public Tag removeTileSourceFile(int pri, string filename, string dataPakPath = null) @trusted { + public Tag removeTileSourceFile(int pri, string filename, string dataPakSrc = null) @trusted { try { auto namespace = layerData[pri].namespaces["File"]; foreach (t ; namespace.tags) { - if (t.name == "TileSource") { - if (dataPakPath) { - if (t.values[0] == dataPakPath && t.values[1] == filename) - return t.remove; - } else { - if (t.values[0] == filename) - return t.remove; - } + if (t.name == "TileSource" && t.values[0] == filename && t.getAttribute!string("dataPakSrc", null) == dataPakSrc) { + return t.remove; } } } catch (DOMRangeException e) { @@ -353,11 +348,11 @@ public class MapFormat { /** * Accesses tile source tags in documents for adding extra data (eg. tile names). */ - public Tag getTileSourceTag(int pri, string filename, string dataPakPath = null) @trusted { + public Tag getTileSourceTag(int pri, string filename, string dataPakSrc = null) @trusted { try { auto namespace = layerData[pri].namespaces["File"]; foreach (t ; namespace.tags) { - if (t.name == "TileSource" && t.values[0] == filename && t.getAttribute!string("dataPakSrc", null) == dataPakPath) { + if (t.name == "TileSource" && t.values[0] == filename && t.getAttribute!string("dataPakSrc", null) == dataPakSrc) { return t; } } @@ -388,6 +383,24 @@ public class MapFormat { } return result; } + /** + * Adds a palette file source to the document. + */ + public void addPaletteFile (string filename, string dataPakSrc, int offset) @trusted { + Attribute[] a; + if (offset) a ~= new Attribute("offset", Value(offset)); + if (dataPakSrc.length) a ~= new Attribute("dataPakSrc", Value(dataPakSrc)); + new Tag(root, "File", "Palette", [Value(filename)], a); + } + /** + * Adds an embedded palette to the document. + */ + public void addEmbeddedPalette (Color[] c, string name, int offset) @trusted { + import PixelPerfectEngine.system.etc : reinterpretCast; + Attribute[] a; + if (offset) a ~= new Attribute("offset", Value(offset)); + new Tag(root, "Embed", "Palette", [Value(name), Value(reinterpretCast!ubyte(c))], a); + } } /** * Represents a single object within a layer, that can represent many different things. diff --git a/pixelperfectengine/src/PixelPerfectEngine/system/file.d b/pixelperfectengine/src/PixelPerfectEngine/system/file.d index e7dab52..713d59f 100644 --- a/pixelperfectengine/src/PixelPerfectEngine/system/file.d +++ b/pixelperfectengine/src/PixelPerfectEngine/system/file.d @@ -189,35 +189,31 @@ public Color[] loadPaletteFromFile(string filename) { switch(extension(filename)){ case ".tga", ".TGA": TGA imageFile = TGA.load(f); - Color[] result; - ubyte[] src = imageFile.getPaletteData; - switch(imageFile.getPaletteBitdepth){ - case 24: - for(ushort i; i < src.length; i+=3){ - result ~= Color(255, src[i + 2], src[i + 1], src[i]); - } - break; - case 32: - for(ushort i; i < src.length; i+=4){ - result ~= Color(src[i + 3], src[i + 2], src[i + 1], src[i]); - } - break; - default: - return []; - } - return result; + return loadPaletteFromImage(imageFile); case ".png", ".PNG": PNG imageFile = PNG.load(f); - return cast(Color[])(cast(void[])imageFile.getPaletteData); + return loadPaletteFromImage(imageFile); default: throw new Exception("Unsupported file format!"); } } +/** + * Loads a palette from image. + */ +public Color[] loadPaletteFromImage (Image img) { + Color[] result; + result.reserve(img.palette.length); + for (ushort i ; i < img.palette.length ; i++) { + auto origin = img.palette[i]; + result ~= Color(origin.a, origin.r, origin.g, origin.b); + } + return result; +} /** * Gets a bitmap from the XMP file. * DEPRECATED! Recommended to use *.tga with devarea extensions or even *.png files. */ -T loadBitmapFromXMP(T)(ExtendibleBitmap xmp, string ID){ +deprecated T loadBitmapFromXMP(T)(ExtendibleBitmap xmp, string ID){ static if(T.stringof == Bitmap4Bit.stringof || T.stringof == Bitmap8Bit.stringof){ T result = new T(cast(ubyte[])xmp.getBitmap(ID),xmp.getXsize(ID),xmp.getYsize(ID),null); return result;