From 13aad50ab71f1676e693c4182b7ed3bbd8d8bee4 Mon Sep 17 00:00:00 2001 From: lephe Date: Fri, 6 May 2016 20:47:15 +0200 Subject: [PATCH] Began to re-write bopti. Bitmap tests changed. Added a continuous integration file. --- .gitlab-ci.yml | 3 + Makefile | 22 +- TODO | 4 + ginttest.c | 59 +++-- ginttest.g1a | Bin 14384 -> 14124 bytes libc.a | Bin 1770 -> 1770 bytes libgint.a | Bin 24660 -> 25114 bytes resources/bitmap_opt.bmp | Bin 0 -> 2810 bytes sprites.bmp => resources/sprites.bmp | Bin swords.bmp => resources/swords.bmp | Bin symbol.bmp => resources/symbol.bmp | Bin symbol2.bmp => resources/symbol2.bmp | Bin 242 -> 242 bytes src/bopti.c | 299 ++++++++++++++++++++++ src/display.c | 354 --------------------------- 14 files changed, 366 insertions(+), 375 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 resources/bitmap_opt.bmp rename sprites.bmp => resources/sprites.bmp (100%) rename swords.bmp => resources/swords.bmp (100%) rename symbol.bmp => resources/symbol.bmp (100%) rename symbol2.bmp => resources/symbol2.bmp (73%) create mode 100644 src/bopti.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..9be67b4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,3 @@ +build: + script: + - make diff --git a/Makefile b/Makefile index 9fdcb10..a4f7209 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ lib = -lgcc -L. -lgint -lc # Gint library. src-lib = crt0.c syscalls.s \ gint.c gint_vbr.s gint_7705.c gint_7305.c \ - mpu.c keyboard.c screen.c display.c gray.c timer.c + mpu.c keyboard.c screen.c display.c bopti.c gray.c timer.c hea-lib = 7305.h 7705.h gint.h \ stdlib.h \ mpu.h keyboard.h screen.h display.h gray.h timer.h @@ -52,7 +52,8 @@ hdr-std = $(addprefix include/, $(hea-std)) # Test application. src-app = ginttest.c -res-app = icon.o swords.o sprites.o symbol.o symbol2.o +img-app = bitmap_opt.bmp swords.bmp sprites.bmp symbol.bmp symbol2.bmp +res-app = $(addprefix build/, $(addsuffix .o, $(img-app))) # @@ -81,11 +82,23 @@ ginttest.g1a: libgint.a $(src-app) $(res-app) @ echo "\033[32;1mBinary file size: "`stat -c %s $(bin)`" bytes\033[0m" # @ sh3eb-elf-objdump -h build/ginttest.elf + + +# +# Resource management. +# + build/%.c.o: src/%.c $(hdr-lib) $(hdr-std) $(cc) $(cflags) -O2 -c $< -o $@ + build/%.s.o: src/%.s $(as) -c $^ -o $@ +build/%.bmp.o: resources/%.bmp + fxconv $^ -o $@ + +# File gint.c should not be optimized... looks like attribute((interrupt_ +# handler)) doesn't like it. (It could be a gint bug also, I should check.) build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) $(cc) $(cflags) -c $< -o $@ @@ -93,8 +106,6 @@ build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) $(cc) $(cflags) -c $< -o $@ %.s.o: %.s $(as) -c $^ -o $@ -%.o: %.bmp - fxconv $^ @@ -103,7 +114,8 @@ build/gint.c.o: src/gint.c $(hdr-lib) $(hdr-std) # clean: - @ rm -f $(obj-lib) $(obj-std) $(obj-app) $(bin) $(elf) + @ rm -f $(obj-lib) $(obj-std) $(obj-app) $(res-app) + @ rm -f $(bin) $(elf) mrproper: clean @ rm -f build/* @ rm -f ginttest.g1a libc.a libgint.a diff --git a/TODO b/TODO index 8e540a7..8b252f5 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,6 @@ - multi-getkey repeats (if possible, which doesn't seem likely) +- it appears that multi-getkey does not always trigger rectangle effects on + sh7305 - write and test gray engine - full rtc driver (time) @@ -7,5 +9,7 @@ - exhaustive save for setjmp() - registers that need to be saved when configuring gint +- check possible bug for optimization of __attribute__((interrupt_handler)) + _ 7305.h _ libc diff --git a/ginttest.c b/ginttest.c index 5b5781a..c0c4a78 100644 --- a/ginttest.c +++ b/ginttest.c @@ -5,11 +5,11 @@ #include #include -extern unsigned int gint_vbr, bgint, egint, gint_data; +extern unsigned int bgint, egint; -/* - A few procedures for displaying text in the system's vram. -*/ +//--- +// A few procedures for displaying text in the system's vram. +//--- extern void __Print(const char *msg, int x, int y); @@ -283,16 +283,45 @@ void btest_gint_icon(void) void bitmap_test(void) { - extern Image binary_symbol_start; - extern Image binary_symbol2_start; - extern Image binary_icon_start; - extern Image binary_sprites_start; - extern Image binary_swords_start; + extern Image binary_resources_bitmap_opt_start; + extern Image binary_resources_symbol_start; + extern Image binary_resources_symbol2_start; + extern Image binary_resources_sprites_start; + extern Image binary_resources_swords_start; - extern const void *vrams[4]; + Image *opt = &binary_resources_bitmap_opt_start; + Image *sprites = &binary_resources_sprites_start; + Image *sybl = &binary_resources_symbol_start; + Image *sybl2 = &binary_resources_symbol2_start; - Image *sybl = &binary_symbol_start; - Image *sybl2 = &binary_symbol2_start; + enum BlendingMode blend = Blend_Or; + uint32_t a32 = 0xffffffff; + int key; + + while(1) + { + dclear(); + + if(blend != Blend_Or) dreverse_area(0, 0, 127, 63); + dimage(opt, 0, 57, Blend_Invert); + + dimage(sprites, 2 & a32, 2, blend); + dimage(sybl, 98 & a32, 4, blend); + dimage(sybl2, 98 & a32, 24, blend); + + dupdate(); + + key = getkey(); + if(key == KEY_EXIT) break; + + if(key == KEY_F1) blend = Blend_Or; + if(key == KEY_F2) blend = Blend_And; + if(key == KEY_F3) blend = Blend_Invert; + + if(key == KEY_F4) a32 ^= 31; + } + + return; dclear(); dreverse_area(0, 0, 127, 30); @@ -308,10 +337,8 @@ void bitmap_test(void) dimage(sybl2, 40, 20, Blend_Or | Blend_And); dimage(sybl2, 90, 20, Blend_Or | Blend_Invert); - dimage(&binary_icon_start, 2, 35, Blend_Or); - dreverse_area(35, 31, 127, 63); - dimage(&binary_sprites_start, 50, 31, Blend_And); + dimage(&binary_resources_sprites_start, 50, 31, Blend_And); dupdate(); /* @@ -333,7 +360,7 @@ void bitmap_test(void) while(getkey() != KEY_EXE); dclear(); - dimage(&binary_swords_start, 20, 20, Blend_Or); + dimage(&binary_resources_swords_start, 20, 20, Blend_Or); dupdate(); while(getkey() != KEY_EXE); diff --git a/ginttest.g1a b/ginttest.g1a index 4e1da8246c504857e8af6bc5545e2ed1cf52ff87..923559a4f2a2161d04cd5e28e178e5765a509f94 100644 GIT binary patch delta 2071 zcmZ`)eN0=|6~FJp@En_9o7uI&@N8qJY3%S`3|k-&)rO{l1~s{LZ=Oo^#K+_ucLeb!p!ZeH^|r@T);(`fGTH(&_ZnOx`cFT*mi`oV>I2_b-eQ zn@MI(Oi0^%*#!4AgR7j`g; z0o(5&UfG6ts|Tn9Xas0jV5nCztoOi$RcNEC2&)jH67ao3N8tOMY=*E#^ci^s5sj2& zRuVe%7Z5wPgFce$mLmcT;ST0`R1+37mLRh$tw3@t`Pew&R9(#Y>e;2hB3eM=^Shd_$fdGHbShu0+C{tt39``8 zn0Rd#W(H`2XtlpwAWUST7#H-?qdXv*I(7J*78D z0UF|mAwVfLpCNwEsk%gAJg}P&fTwrCd3q;Dz-pdgq@ny5CnqcJ0;J#!l<;XP);a`$myHj)ZP7+2VG_}HqSyv?qJgOPt<-I+U1Ocn} z3-|V(FR=IFC81Tv!CN(68u)Y2k1oKX!t2>~83dUfjf`d|sSKSFGS^40=R79%SXLom z9Q2kjqCHMjM3%J&NQ+Jn7GQ;7pU^N6q^G?dBNma%zMzBghESqk7P<{TBy}bsX3*v8 zOd^34=1RQ7czlm^+hMJa!uIvL+@-vQLk^U!(PH zHuSq0r=Hc-sDpK^wNvqqDW3K#nsVI#WQnRQ&!ZK@7Wft3&8{14;3!M6T6Vf<+4Cq! z@~b0L-v7*}%jSY4XBmmsZC7hAIecp?=m+cd-;_Hl9G#OLiLOXH<(LYR{>Vr;fv5-G zWL19Ir-N9&xrk(6dLJIkZ%x|DXTCq@Z;oVcS1H~iN=Jf=Z_}Rju1Rmo_YH4kX{V93 z^%8-)wX#G{dhoAov1h}?TvT{BJpXRW@jd4CaTD*DXD#w#NAXja|#w594c;;Q1Og8n#jAFa^w%`;mr<58t&V>MmAzd`Y;sW!jSUVE@w8=T`N_CEBj9dfYhcZjB>C)txeijD*moHKm>^g84yyRQoW zdWCHHTlh~cXYT96S67Jenbu^uuI$rr1*Zug;hfMy*BBK&iun9tq1s$dxP%Ml!s8_a zWYFR-oKlHJ!58Q0SP}GzX8K?=RjFVLy~(rvt&=U0<{PZ&R&YbH{VwQC-&&=jnerwv zdbXb%!WP1cIbZhCJQ@D8ptQWydCQx`-JidVcyk}D46B+u@C_8BPFk=Jk!+^i_LKWS zcNyzN(ytLo7Xvm05ak$LB~v0bO*d%V%pnI-c+~i0eT#!_H+h$W^G0G!h*_GlqN6p4 z27;fIDkQiHIr!Oh7qX;Gg>NNc*k;j~#|F?phDE|{UqI5?)C*I#LiJ_57Wjedivd!G zB3m{;5$MY#?!dK#UL&rf=Sd%Ge9MO_$$E607{ajhtWvh|pV5CXO|1XUbRqMm>F4y# z@o!ZqfBaUr%Jti7{g*Y>z`NDsx2kt_)R=OW+^;!6*{2)H(gG{VXdYnQ%PP$sL?HrY yqsX17@6Z_?pMNmRs3NaBdNLrNW#?I%hzg#=#d2wb@bw~GK73V5UP>Hq!hZoP_pN*Y delta 2337 zcmaJ@e@q+K9e;N|=sCt>YNBa>kV0G35J-Db^GCA|g{mW3t8syCsEa0yfuvo#5kp)D5Z?C=>T23F zoxbr)m|ghBM?gl5UZdN8##km{iomu^Qbdh zn1Tl1Zx9;+zL`G<=?9qvxx>?ny6{X$qmJX770(lK{D{H}?@N>b@3OFIB2GvMPbP?4 zLg6!|#7^B5WTX+B6$fK8j2VcH9p`)LyKcSNuyj=C4z#a0y{9MdAB{H1h7biHb%2zF5Mn8A(T$F! zihDy41yCFy#{WRHfaHacF!0F+WOoQr08$4?hJ=V2Kv2I(HpGf)lK$`@d;nh1i(1*5 z@{n4>i$<^}O1fK2k_HHq)p~^|-KhChK-9?245R`=;2bIIQQN+<_PsAsUZ8*GJ(|_- zN013x25n^K5Ss+8Od3LLx^=7Vu~7KLRm3J_)0*fEsp{=3qVU%phlq--LgwVQ~IG4Ye?E0Pwq4E6xu9N8(` zBEU0&Ux@r=YVJje065%)Wvmhr7|UQ^vVh& zIG_(Cc4hE4nL|Xb5McI@I%XL>zzbah=?A%rSY}{~SVZQWg`F^e#Fr&J;`>wVBop9s z6JItmfhj_&yYx|LNQAi~M*hHnG*2)6em+B5a=?q#pW*K$rb^Kd61$X8_k@eEWPo=h zwPuDikGpVZUzq3Mb35N4#jQYj320!4u$*+3kOC8-K?xUy4y}%GGXcZvbH@yC&1($r zde#jewR9RjtI!($BA>0#=}kxHJ&X^tyKpT&%aJ&I;FDL07wA31eT}%q7O=0GwZ;fr z;2ut+!J2uk%oFsYs;BkcrF4Ea&Zvmys&I@`bvkW6=ujDAoO+8I6JH^m>{OgK=NFf{ zQ*f^RDb`yVr2Od{cWnXETs9v@Cj3%sSO_+3_Blf+=-L*0{e;WP9p{l3!d)0n2$@X0-T@x^BJv3Wf z5YN@JZ9nmUjrS-$xM-v(zK`^*4}5TZ?WCf5?XY&A$s2TDcNCaYoSmoVoXO9p7|0Vv zZG)}XalVx~zsza7*y7%H{ao#VUiD^+e%9UgNBm&}?|jEK-Re$h6q+_&c_ccFAVPx;&Yt^OAONjRv@e!2X<|5g5h-`o64sM{=#IB)^3MicdCx0$l)tTZWQ-!Cy?UdctHH0 zrT9>^AEKQ|iIXcBuE74(G1w7wc4KO;)xtpq(+$%up@|P0tyEngisv~0YgE-^`$~Q;jy~bD`8o-f zg|hn(>^d2AeqkKQg<_mMU0qwg=G(T^69be0pfhS%rU4R0BE zeOe)LfUix{yNx|0m*&tYx#gIJG6i^_0$D%%XF z+P=~-Smkqd>&T`FEH(;;%NAAPH*U>;@0fWFyNml|o*cU~PsuAVeJWS?JOvqJaC*~( z;c}zEZ>H^MhO2xMy_8wR>V~D;1;&2fmL6}J0@9B}(h(z)W*V-oR9Zs~!Cn5TsJKr# zV=Q!jE>hW|rAuoY2j33zo&v5iQo{J*^b_jwp~Hv*f&T-|FrT0^5aWVXhsiMcCxdUx z(8cJcdeE2sB4No{kV~aE^8*?B=qYI}$OEiskceSnCc{C5r^XVu5qh)Y1RCTLcWV4#`(&<1xlH(e3AC-y&`jwc}Sf84Szf@EC2ui diff --git a/libc.a b/libc.a index 8bf5347854d0f179da6ae1713aa3df6e30812b36..5af40679f3942db5591d73e281f48b63275d40a2 100644 GIT binary patch delta 39 jcmaFG`-*ph44bK`1rSbD%7L;rPAOu7GB@)u-(v;<=F+wN=No^h)^|2xJ$i9+wvnnB4ryorDT{5 zBUs{RHe>uDVY{gerjfaRLC4#5AloaF%I&HT4%iqXwC>Hgg+L;wWLU4(@T zAVVBp1T4)hT8%}sgYq97I;_-m9Xiakj8ykL;nollha1Db!Z{4*2^YGvWnH1c*!8%B zyx1o91vwGS^K0*_h9q;jG45+gDk8ws{Bf~PFXOnoIOjTdEq{#ArKfA5UbX@of;DTW z+~@NzVK{i;Ze6$AzfTk-V({I_YN#qv$1&*bVdw>;WAHBm5dlJK*jhq5GElGpv9QR1 zsu*phJYI!3!{Z+yUXOSLr*B8tzaj!#4~p+WP|n4VAdU>|^F0lpHPM-G(q zGNB*wv&cU83#_&Frh4-(jRjPit=r$Tw}8rOTT6r4UT23#=`S285nGGuVGCq2jXF4p z%X$799&SP19MrV(^oQp(II0HcH24A@j^%0g0kH9(%m0V2rcmpZ7AJ>}G=wRY&)8SQkq!ES&E& zkxLq+dlkd8jMNg9^DBwvh0~K`fJ|VdhUvyWauw+ikkRBV%>#PUiEAJA4jTR*na%V# zaZ1^H*)&rSeL!s-9|L6*<p*qi{aN9O z_0l#h!{hYrAq-EA4r{$9-DrM>pqRlqr#LFrr{ZJ9td3Li$ej*sECpIqPCDjvqV zJ{!Ya6;)oBDf6l;n~HR;q;$cqV|UoKAq&&P!40Z)shzk}$*2Y+ZfcyxBg732>XXP@ zNmfCwlvEkK)g4s>Hn+8pyqP1V4&6x9OM%2Vo-4Hq3|`h--9a5<6;M+gFYF(|UEe{v zc(dfR!Hb#{fKo_D+8r!nS1C6PqXN`FEC__-*ckc@Q@J=7W;-4T5m5vkXfUuV18LFs zhoy33P4D-jA1+?)%B z_&Xf~yEeCS0~_tC-9so2A+(Sv9M=N%=}~&XD^~fh8FU&Gf0T8 q4OaSR5W$|W2bmZu!V*Np9|$(V^3o-9e|9nMkuvg delta 2290 zcmb7F3rtg27(VxMi+zEBgDNeaN)^$8w-h3ER&5bxYpOH=GTHxaGJjHm4S?6#E+qh7W7Jq!2&=TZ zrmlj{C)#4m4%A84m948LJqjY#($>qos?y@!0=inXg(+qci$dpPF-$%G1RjiKi<`N@ z`2Mm(LF)phTD0|F{9hykoIt*Sxt1&;0yu`5O;Iim#>J}dgX+Z)X(_4e>E*1ocz8Qq zk~u+#?OFItIuWyzM~4c?wvh<(?C>;s*;-59%odTqk&k!8+wZVv z4Yju++%8=W3*kWuhoO${dhBiX+Vd@DXw^*Urj#NXUo&wVirHv&)yd4^xly2+o)HJ_NxDfWQAY#Lu2)q0#uM*3 zUx1SFM#9)}gs}Ek_1KoIX{T^Y|HaU`@Mz zdfTQJ)~W_YD}_Iva{&EJ-n#+IG60!L^)WnErLTpambE zc6?hjRS}XuwOzD9F*;|wU`SQQ8Ef|s8HHQpNW3iF)=_x@rl_ME|Dr?2sEFXrJ)D@gjm@Z0Br#6mGSA=X=$^*^beSNb< zQ%c1KzQ*-@&MGY9%mbFuti-IPCUenfzHd10N|i|_6d1(WSVRv&sym(wK8loeNQXdD*FVd#0JT&h`wYh zcZBFoR`Oufy(CMM)>+;YkDD1&2b91*6^}gDo2cXgj&9u4p>nx*k@+QW3)mS z$Lb!zyROnDx}72CwNAP+5WSoyh)e+Jz{pUhdxYoGH}Vp2ZX^B7J9YCCLc diff --git a/resources/bitmap_opt.bmp b/resources/bitmap_opt.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d3eb2328782b8ef0ff921ed9463e96fd123270af GIT binary patch literal 2810 zcmeH^F-`+f5JMB1NTH<3dD5h!;T&{yR5^DVu-4+q^6UZ?H2Kp0cs$SEC^weX9)pO9Z-<@=8*8b_y&tm90UtZq6^lv{O3jDaA|NaH^kMI@vcW_d8YljpfNpx-< zPiJD@!Z1o$6Dg6~g30h@GHnpK`780K`e!nDxs;}tqd7iwiuH@<}%FbifZpvJ_q z5X_=RQYm0Cr=wLC0$@s5Q!+&Y3%(v)vsJ#e%{DZ! z9Yzbr`7RtWWGz>R8wl*oZz$~8^5ywH0wWtxS1ep8^CJ6?EAebVv)-me zCL=v1vbK7X1VhkVDUCjkOJ`5&!g5S3wHbGQ&*#>>dNPQa{br*I^D Rwjw5HdHS>e?)>F1@Cgpt7LNb` literal 0 HcmV?d00001 diff --git a/sprites.bmp b/resources/sprites.bmp similarity index 100% rename from sprites.bmp rename to resources/sprites.bmp diff --git a/swords.bmp b/resources/swords.bmp similarity index 100% rename from swords.bmp rename to resources/swords.bmp diff --git a/symbol.bmp b/resources/symbol.bmp similarity index 100% rename from symbol.bmp rename to resources/symbol.bmp diff --git a/symbol2.bmp b/resources/symbol2.bmp similarity index 73% rename from symbol2.bmp rename to resources/symbol2.bmp index 949376085f1327189a40236ae9406bba668da36a..be7ac38829e7e0f9666885700224813c2d84abd8 100644 GIT binary patch delta 18 acmeyw_=$1Co{7`tC(h@b*vG@fzyJVH^9JAm delta 13 Vcmeyw_=$1C9_Ii5|4-a+3;;AO2etqJ diff --git a/src/bopti.c b/src/bopti.c new file mode 100644 index 0000000..19725fd --- /dev/null +++ b/src/bopti.c @@ -0,0 +1,299 @@ +#include +#include +#include + +//--- +// Image drawing. There is only one public function dimage(), but there +// are lots of local methods and optimizations. +// +// Some expressions may look nonsense sometimes. The procedure is always +// the same : get a part of the image in an operator, shift it depending +// on the drawing x-coordinate, compute a mask that indicates which bits +// of the operator contain information, and modify a vram long using the +// operator and the mask. +//--- + +// This pointer is set by bopti(). +static int *vram; + +/* + bopti_op() + Operates on a vram long. The operator will often not contain 32 bits of + image information. In this case, the bits outside the image must be set + to 0 for Or and Invert operations... 1 for And operations. Which means + that the calling procedure must indicate what part of the operator + belongs to the image, which is done through the image_mask argument. + + @arg offset Vram offset where edition is planned. + @arg operator Longword to operate with. + @arg image_mask Part of the operator that is inside the image. + @arg mode Operation mode. +*/ +static void bopti_op(int offset, uint32_t operator, uint32_t image_mask, + enum BlendingMode mode) +{ + if(mode & Blend_Checker) operator &= 0x55555555; + if(mode & Blend_Or) vram[offset] |= operator; + if(mode & Blend_Invert) vram[offset] ^= operator; + operator |= ~image_mask; + if(mode & Blend_And) vram[offset] &= operator; +} + +/* + bopti_grid() -- general form + bopti_grid_a32() -- when x is a multiple of 32 + + Draws a layer whose length is a multiple of 32. + The need for bopti_grid_a32() is not only linked to optimization, + because one of the bit shifts in bopti_grid() will reach 32 when x is + a multiple of 32, which is undefined behavior. + + @arg layer Raw column data (column data is located at the + beginning of layer data). + @arg x + @arg y + @arg column_number + @arg height + @arg mode +*/ + +static void bopti_grid_a32(const uint32_t *layer, int x, int y, + int column_number, int height, enum BlendingMode mode) +{ + int vram_column_offset = (y << 2) + (x >> 5); + int vram_offset = vram_column_offset; + int column, row; + + for(column = 0; column < column_number; column++) + { + for(row = 0; row < height; row++) + { + bopti_op(vram_offset, *layer, 0xffffffff, mode); + layer++; + vram_offset += 4; + } + + vram_column_offset++; + vram_offset = vram_column_offset; + } +} + +static void bopti_grid(const uint32_t *layer, int x, int y, int column_number, + int height, enum BlendingMode mode) +{ + const uint32_t *p1, *p2; + uint32_t l1, l2; + int right_column, line; + + int vram_column_offset = (y << 2) + (x >> 5); + int vram_offset = vram_column_offset; + + int shift1 = 32 - (x & 31); + int shift2 = (x & 31); + + uint32_t operator, and_mask; + uint32_t and_mask_0 = 0xffffffff >> shift2; + uint32_t and_mask_1 = 0xffffffff << shift1; + + if(!column_number) return; + if(!(x & 31)) + { + bopti_grid_a32(layer, x, y, column_number, height, mode); + return; + } + + // Initializing two pointers. Since the columns are written one after + // another, they will be updated directly to parse the whole grid. + p1 = layer - height; + p2 = layer; + + // Drawing vram longwords, using pairs of columns. + for(right_column = 0; right_column <= column_number; right_column++) + { + and_mask = 0xffffffff; + if(right_column == 0) and_mask &= and_mask_0; + if(right_column == column_number) and_mask &= and_mask_1; + + for(line = 0; line < height; line++) + { + l1 = (right_column > 0) ? (*p1) : (0); + l2 = (right_column < column_number) ? (*p2) : (0); + p1++, p2++; + + operator = (l1 << shift1) | (l2 >> shift2); + bopti_op(vram_offset, operator, and_mask, mode); + vram_offset += 4; + } + + vram_column_offset++; + vram_offset = vram_column_offset; + } +} + +/* + bopti_rest_get() + Returns the line of a bitmap, whose width is lower than 32. The given + pointer is read and set according to the bitmap width. + + @arg ptr Address of data pointer. + @arg size Element size (should be 1, 2, or 4 bytes). +*/ +static uint32_t bopti_rest_get(const unsigned char **data, int size) +{ + uint32_t line; + + if(size == 4) + { + line = *((uint32_t *)*data); + *data += 4; + return line; + } + + else if(size == 2) + { + line = *((uint16_t *)*data); + *data += 2; + return line; + } + + else + { + line = **data; + (*data)++; + return line; + } +} + +/* + bopti_rest() -- general form + bopti_rest_nover() -- when the bitmap does not overlap two longs + + Draws a bitmap, whose width is lower than 32. It is called the 'rest' + since the biggest part will be drawn by bopti_grid(). + + @arg rest Ending data. Encoded on 1, 2 or 4 bytes per line + depending on the rest width. + @arg x + @arg y + @arg width Rest width. + @arg height + @arg mode +*/ + +static void bopti_rest_nover(const unsigned char *rest, int x, int y, + int width, int height, enum BlendingMode mode) +{ + int element_size = (width > 16) ? (4) : (width > 8) ? (2) : (1); + int vram_offset = (y << 2) + (x >> 5); + int row; + + // We *have* shift > 0 because of this function's 'no overlap' + // requirement. + int shift_base = (4 - element_size) << 3; + int shift = shift_base - (x & 31); + + uint32_t and_mask = (0xffffffff << (32 - width)) >> (x & 31); + uint32_t operator; + + for(row = 0; row < height; row++) + { + operator = bopti_rest_get(&rest, element_size); + operator <<= shift; + + bopti_op(vram_offset, operator, and_mask, mode); + vram_offset += 4; + } +} + +static void bopti_rest(const unsigned char *rest, int x, int y, int width, + int height, enum BlendingMode mode) +{ + if((x & 31) + width <= 32) + { + bopti_rest_nover(rest, x, y, width, height, mode); + return; + } +} + +/* + bopti() + Draws an image layer in the video ram. + + @arg bitmap Raw layer data. + @arg x + @arg y + @arg width + @arg height + @arg mode +*/ + +static void bopti(const unsigned char *layer, int x, int y, int width, + int height, enum BlendingMode mode) +{ + int column_number = width >> 5; + int rest_width = width & 31; + + vram = display_getCurrentVRAM(); + + // Skipping 'column_number' columns of 'height' longs. + const unsigned char *rest = layer + ((column_number * height) << 2); + int rest_x = x + (width - rest_width); + + bopti_grid((const uint32_t *)layer, x, y, column_number, height, mode); + if(!rest_width) return; + bopti_rest(rest, rest_x, y, rest_width, height, mode); +} + +/* + dimage() + Displays an image in the vram. + + @arg image + @arg x + @arg y + @arg mode +*/ + +void dimage(struct Image *image, int x, int y, enum BlendingMode mode) +{ + int width = image->width; + int height = image->height; + const unsigned char *data = (const unsigned char *)&(image->data); + + // Computing the layer size. + int columns = image->width >> 5; + int rest = image->width & 31; + int rest_size = + !rest ? 0 : + rest <= 8 ? 1 : + rest <= 16 ? 2 : + 4; + int layer_size = ((columns << 2) + rest_size) * image->height; + // The layer size must be a multiple of 4. + if(layer_size & 3) layer_size += 4 - (layer_size & 3); + + switch(image->format & ImageFormat_ColorMask) + { + case ImageFormat_Mono: + if(image->format & ImageFormat_Alpha) + { + bopti(data + layer_size, x, y, width, height, + Blend_And); + } + bopti(data, x, y, width, height, mode); + break; + + case ImageFormat_Gray: + if(image->format & ImageFormat_Alpha) + { + bopti(data + 2 * layer_size, x, y, width, height, + Blend_And); + } + + display_useVRAM(gray_darkVRAM()); + bopti(data, x, y, width, height, mode); + display_useVRAM(gray_lightVRAM()); + bopti(data + layer_size, x, y, width, height, mode); + break; + } +} diff --git a/src/display.c b/src/display.c index d004b1e..e6d2d48 100644 --- a/src/display.c +++ b/src/display.c @@ -370,357 +370,3 @@ void dline(int x1, int y1, int x2, int y2, enum Color color) dpixel(x2, y2, color); } - - - -//--- -// Image drawing. There is only one public function dimage(), but there -// are lots of local methods and optimizations. -// -// Some expressions may look nonsense sometimes. The procedure is always -// the same : get a part of the image in an operator, shift it depending -// on the drawing x-coordinate, compute a mask that indicates which bits -// of the operator contain information, and modify a vram long using the -// operator and the mask. -//--- - -/* - bopti_op() - Operates on a vram long. The operator will often not contain 32 bits of - image information. In this case, the bits outside the image must be set - to 0 for Or and Invert operations... 1 for And operations. Which means - that the calling produre must indicate what part of the operator - belongs to the image, which is done through the image_mask argument. - - @arg offset Vram offset where edition is planned. - @arg operator Longword to operate with. - @arg image_mask Part of the operator that is inside the image. - @arg mode Operation mode. -*/ -static void bopti_op(int offset, uint32_t operator, uint32_t image_mask, - enum BlendingMode mode) -{ - if(mode & Blend_Checker) operator &= 0x55555555; - if(mode & Blend_Or) vram[offset] |= operator; - if(mode & Blend_Invert) vram[offset] ^= operator; - operator |= ~image_mask; - if(mode & Blend_And) vram[offset] &= operator; -} - -/* - bopti_grid() -- general form - bopti_grid_a32() -- when x is a multiple of 32 - - Draws a layer, whose width is a multiple of 32, in the vram. - The need for bopti_grid_a32() is not only linked to optimization, - because one of the bit shifts in bopti_grid() will reach 32 when x is - a multiple of 32, which is undefined behavior. - - @arg layer Raw column data (column data is located at the - beginning of layer data). - @arg column_number - @arg width - @arg height - @arg x - @arg y - @arg mode -*/ - -static void bopti_grid_a32(const uint32_t *layer, int column_number, int width, - int height, int x, int y, enum BlendingMode mode) -{ - int vram_column_offset = (y << 2) + (x >> 5); - int vram_offset = vram_column_offset; - - int column, line; - uint32_t operator, and_mask; - uint32_t rightest_and_mask; - - if(width & 31) rightest_and_mask = ~(0xffffffff >> (width & 31)); - else rightest_and_mask = 0xffffffff; - - for(column = 0; column < column_number; column++) - { - for(line = 0; line < height; line++) - { - operator = *layer++; - - and_mask = (column < column_number - 1) ? - (0xffffffff) : (rightest_and_mask); - bopti_op(vram_offset, operator, and_mask, mode); - vram_offset += 4; - } - - vram_column_offset++; - vram_offset = vram_column_offset; - } -} - -static void bopti_grid(const uint32_t *layer, int column_number, int width, - int height, int x, int y, enum BlendingMode mode) -{ - const uint32_t *p1, *p2; - uint32_t l1, l2; - int right_column, line; - - int vram_column_offset = (y << 2) + (x >> 5); - int vram_offset = vram_column_offset; - - int shift1 = 32 - (x & 31); - int shift2 = (x & 31); - int combined_shift_last = shift1 + 32 - (width & 31); - - uint32_t operator, and_mask; - uint32_t and_mask_0 = 0xffffffff >> shift2; - uint32_t and_mask_1 = (0xffffffff) << combined_shift_last; - - if(!column_number) return; - if(!(x & 31)) - { - bopti_grid_a32(layer, column_number, width, height, x, y, - mode); - return; - } - - // Initializing two pointers. Since the columns are written one after - // another, they will be updated directly to parse the whole grid. - p1 = layer - height; - p2 = layer; - - // Drawing vram longwords, using pairs of columns. - for(right_column = 0; right_column <= column_number; right_column++) - { - for(line = 0; line < height; line++) - { - l1 = (right_column > 0) ? (*p1) : (0); - l2 = (right_column < column_number) ? (*p2) : (0); - p1++, p2++; - - operator = (l1 << shift1) | (l2 >> shift2); - - and_mask = 0xffffffff; - if(!right_column) and_mask &= and_mask_0; - if(right_column == column_number) - and_mask &= and_mask_1; - - bopti_op(vram_offset, operator, and_mask, mode); - vram_offset += 4; - } - - vram_column_offset++; - vram_offset = vram_column_offset; - } -} - -/* - bopti_rest8() -- general form, width below 8 - bopti_rest8_nover() -- when the rest does not meet two longs - bopti_rest16() -- general form, width below 16 - bopti_rest16_nover() -- when the rest does not meet two longs - - Draw rests of row size of 8 and 16 bits, respectively. - - @arg rest Rest data, located at the end of the layer data. - @arh width - @arg height - @arg x - @arg y - @arg mode -*/ - -static void bopti_rest8_nover(const uint8_t *rest, int width, int height, - int x, int y, enum BlendingMode mode) -{ - int vram_offset = (y << 2) + (x >> 5); - int shift = x & 31; - - uint32_t operator; - uint32_t and_mask = ~(0xffffffff >> width) >> shift; - int line; - - for(line = 0; line < height; line++) - { - operator = *rest++; - // Optimization possible ? Probably not. - operator <<= 24; - operator >>= shift; - - bopti_op(vram_offset, operator, and_mask, mode); - vram_offset += 4; - } -} - -static void bopti_rest8(const uint8_t *rest, int width, int height, int x, - int y, enum BlendingMode mode) -{ - if((x & 31) + width < 32) - { - bopti_rest8_nover(rest, width, height, x, y, mode); - return; - } - - int vram_offset = (y << 2) + (x >> 5); - int shift1 = (x & 31) - 24; - int shift2 = 56 - (x & 31); - uint32_t and_mask_1 = 0xffffffff >> (x & 31); - uint32_t and_mask_2 = ~(0xffffffff >> ((x & 31) + width - 32)); - - uint32_t operator; - int line; - - for(line = 0; line < height; line++) - { - operator = *rest++; - - bopti_op(vram_offset, operator >> shift1, and_mask_1, mode); - bopti_op(vram_offset + 1, operator << shift2, and_mask_2, - mode); - vram_offset += 4; - } -} - -static void bopti_rest16_nover(const uint16_t *rest, int width, int height, - int x, int y, enum BlendingMode mode) -{ - int vram_offset = (y << 2) + (x >> 5); - int shift = x & 31; - - uint32_t operator; - uint32_t and_mask = ~(0xffffffff >> width) >> shift; - int line; - - for(line = 0; line < height; line++) - { - operator = *rest++; - // As far as I know, no, we can't optimize this into a single - // shift. - operator <<= 16; - operator >>= shift; - - bopti_op(vram_offset, operator, and_mask, mode); - vram_offset += 4; - } -} - -static void bopti_rest16(const uint16_t *rest, int width, int height, int x, - int y, enum BlendingMode mode) -{ - if((x & 31) + width < 32) - { - bopti_rest16_nover(rest, width, height, x, y, mode); - return; - } - - int vram_offset = (y << 2) + (x >> 5); - int shift1 = (x & 31) - 16; - int shift2 = 48 - (x & 31); - uint32_t and_mask_1 = 0xffffffff >> (x & 31); - uint32_t and_mask_2 = ~(0xffffffff >> ((x & 31) + width - 32)); - - uint32_t operator; - int line; - - for(line = 0; line < height; line++) - { - operator = *rest++; - - bopti_op(vram_offset, operator >> shift1, and_mask_1, mode); - bopti_op(vram_offset + 1, operator << shift2, and_mask_2, - mode); - vram_offset += 4; - } -} - -/* - bopti() - Draws an image layer in the video ram. - - @arg bitmap Raw layer data. - @arg x - @arg y - @arg width - @arg height - @arg mode -*/ -void bopti(const unsigned char *layer, int x, int y, int width, int height, - enum BlendingMode mode) -{ - int column_number = width >> 5; - int rest_width = width & 31; - int grid_width = width & ~31; - - if(rest_width > 16) - { - column_number++; - rest_width = 0; - grid_width = width; - } - - const unsigned char *rest = layer + ((column_number * height) << 2); - int rest_x = x + (width - rest_width); - - bopti_grid((const uint32_t *)layer, column_number, grid_width, height, - x, y, mode); - if(!rest_width) return; - - if(rest_width <= 8) - bopti_rest8((const uint8_t *)rest, rest_width, height, rest_x, - y, mode); - else - bopti_rest16((const uint16_t *)rest, rest_width, height, - rest_x, y, mode); -} - -/* - dimage() - Displays an image in the vram. - - @arg image - @arg x - @arg y - @arg mode -*/ - -void dimage(struct Image *image, int x, int y, enum BlendingMode mode) -{ - int width = image->width; - int height = image->height; - const unsigned char *data = (const unsigned char *)&(image->data); - - // Computing the layer size. - int columns = image->width >> 5; - int rest = image->width & 31; - int rest_size = - !rest ? 0 : - rest <= 8 ? 1 : - rest <= 16 ? 2 : - 4; - int layer_size = ((columns << 2) + rest_size) * image->height; - // The layer size must be a multiple of 4. - if(layer_size & 3) layer_size += 4 - (layer_size & 3); - - switch(image->format & ImageFormat_ColorMask) - { - case ImageFormat_Mono: - if(image->format & ImageFormat_Alpha) - { - bopti(data + layer_size, x, y, width, height, - Blend_And); - } - bopti(data, x, y, width, height, mode); - break; - - case ImageFormat_Gray: - if(image->format & ImageFormat_Alpha) - { - bopti(data + 2 * layer_size, x, y, width, height, - Blend_And); - } - - display_useVRAM(gray_darkVRAM()); - bopti(data, x, y, width, height, mode); - display_useVRAM(gray_lightVRAM()); - bopti(data + layer_size, x, y, width, height, mode); - break; - } -}