From b50a0eb714c64dee65050539243e02ef2aa308b5 Mon Sep 17 00:00:00 2001 From: sparky4 <sparky4@4ch.maidlab.jp> Date: Fri, 13 Jun 2014 12:06:51 -0500 Subject: [PATCH] modified: 16/DOS_GFX.EXE modified: 16/DOS_GFX.OBJ modified: 16/Project 16.bfproject modified: 16/dos_gfx.cpp modified: 16/dos_gfx.h new file: 16/lib/x/MODEX.BAK new file: 16/scrasm/80X86.ASC new file: 16/scrasm/80X86.TXT new file: 16/scrasm/CONSTANT.INC new file: 16/scrasm/DIAGONAL.MAP new file: 16/scrasm/DIAGONAL.PAL new file: 16/scrasm/DIAGONAL.TIL new file: 16/scrasm/GENMAP.C new file: 16/scrasm/GENMAP.EXE new file: 16/scrasm/GENMAP.LNK new file: 16/scrasm/GENMAP.OBJ new file: 16/scrasm/GENPAL.C new file: 16/scrasm/GENPAL.EXE new file: 16/scrasm/GENPAL.LNK new file: 16/scrasm/GENPAL.OBJ new file: 16/scrasm/GENSQ.C new file: 16/scrasm/GENSQ.EXE new file: 16/scrasm/GENSQ.LNK new file: 16/scrasm/GENSQ.OBJ new file: 16/scrasm/INIT.INC new file: 16/scrasm/KEYB.INC new file: 16/scrasm/LZTIMER.ASM new file: 16/scrasm/LZTIMER.OBJ new file: 16/scrasm/MAIN.ASM new file: 16/scrasm/MAIN.OBJ new file: 16/scrasm/MAKEFILE new file: 16/scrasm/MAP.INC new file: 16/scrasm/MODEX.INC new file: 16/scrasm/PAGE.INC new file: 16/scrasm/PALETTE.INC new file: 16/scrasm/SCROLL.DOC new file: 16/scrasm/SCROLL.EXE new file: 16/scrasm/SCROLL.INC new file: 16/scrasm/SCROLL.LNK new file: 16/scrasm/SCROLL.MAP new file: 16/scrasm/SCROLL.PAL new file: 16/scrasm/SCROLL.TIL new file: 16/scrasm/SPRITE.INC --- 16/DOS_GFX.EXE | Bin 35702 -> 35970 bytes 16/DOS_GFX.OBJ | Bin 5389 -> 5583 bytes 16/Project 16.bfproject | 24 +- 16/dos_gfx.cpp | 55 ++-- 16/dos_gfx.h | 8 +- 16/lib/x/MODEX.BAK | Bin 0 -> 25600 bytes 16/scrasm/80X86.ASC | 164 +++++++++++ 16/scrasm/80X86.TXT | 494 +++++++++++++++++++++++++++++++ 16/scrasm/CONSTANT.INC | 127 ++++++++ 16/scrasm/DIAGONAL.MAP | Bin 0 -> 65057 bytes 16/scrasm/DIAGONAL.PAL | Bin 0 -> 768 bytes 16/scrasm/DIAGONAL.TIL | Bin 0 -> 65536 bytes 16/scrasm/GENMAP.C | 99 +++++++ 16/scrasm/GENMAP.EXE | Bin 0 -> 18664 bytes 16/scrasm/GENMAP.LNK | 1 + 16/scrasm/GENMAP.OBJ | Bin 0 -> 2543 bytes 16/scrasm/GENPAL.C | 51 ++++ 16/scrasm/GENPAL.EXE | Bin 0 -> 17676 bytes 16/scrasm/GENPAL.LNK | 1 + 16/scrasm/GENPAL.OBJ | Bin 0 -> 1895 bytes 16/scrasm/GENSQ.C | 102 +++++++ 16/scrasm/GENSQ.EXE | Bin 0 -> 18916 bytes 16/scrasm/GENSQ.LNK | 1 + 16/scrasm/GENSQ.OBJ | Bin 0 -> 2977 bytes 16/scrasm/INIT.INC | 375 +++++++++++++++++++++++ 16/scrasm/KEYB.INC | 237 +++++++++++++++ 16/scrasm/LZTIMER.ASM | 636 ++++++++++++++++++++++++++++++++++++++++ 16/scrasm/LZTIMER.OBJ | Bin 0 -> 3231 bytes 16/scrasm/MAIN.ASM | 134 +++++++++ 16/scrasm/MAIN.OBJ | Bin 0 -> 18324 bytes 16/scrasm/MAKEFILE | 47 +++ 16/scrasm/MAP.INC | 413 ++++++++++++++++++++++++++ 16/scrasm/MODEX.INC | 88 ++++++ 16/scrasm/PAGE.INC | 109 +++++++ 16/scrasm/PALETTE.INC | 239 +++++++++++++++ 16/scrasm/SCROLL.DOC | 297 +++++++++++++++++++ 16/scrasm/SCROLL.EXE | Bin 0 -> 33596 bytes 16/scrasm/SCROLL.INC | 441 ++++++++++++++++++++++++++++ 16/scrasm/SCROLL.LNK | 2 + 16/scrasm/SCROLL.MAP | Bin 0 -> 344 bytes 16/scrasm/SCROLL.PAL | Bin 0 -> 768 bytes 16/scrasm/SCROLL.TIL | Bin 0 -> 9984 bytes 16/scrasm/SPRITE.INC | 280 ++++++++++++++++++ 43 files changed, 4385 insertions(+), 40 deletions(-) create mode 100644 16/lib/x/MODEX.BAK create mode 100644 16/scrasm/80X86.ASC create mode 100644 16/scrasm/80X86.TXT create mode 100644 16/scrasm/CONSTANT.INC create mode 100644 16/scrasm/DIAGONAL.MAP create mode 100644 16/scrasm/DIAGONAL.PAL create mode 100644 16/scrasm/DIAGONAL.TIL create mode 100644 16/scrasm/GENMAP.C create mode 100644 16/scrasm/GENMAP.EXE create mode 100644 16/scrasm/GENMAP.LNK create mode 100644 16/scrasm/GENMAP.OBJ create mode 100644 16/scrasm/GENPAL.C create mode 100644 16/scrasm/GENPAL.EXE create mode 100644 16/scrasm/GENPAL.LNK create mode 100644 16/scrasm/GENPAL.OBJ create mode 100644 16/scrasm/GENSQ.C create mode 100644 16/scrasm/GENSQ.EXE create mode 100644 16/scrasm/GENSQ.LNK create mode 100644 16/scrasm/GENSQ.OBJ create mode 100644 16/scrasm/INIT.INC create mode 100644 16/scrasm/KEYB.INC create mode 100644 16/scrasm/LZTIMER.ASM create mode 100644 16/scrasm/LZTIMER.OBJ create mode 100644 16/scrasm/MAIN.ASM create mode 100644 16/scrasm/MAIN.OBJ create mode 100644 16/scrasm/MAKEFILE create mode 100644 16/scrasm/MAP.INC create mode 100644 16/scrasm/MODEX.INC create mode 100644 16/scrasm/PAGE.INC create mode 100644 16/scrasm/PALETTE.INC create mode 100644 16/scrasm/SCROLL.DOC create mode 100644 16/scrasm/SCROLL.EXE create mode 100644 16/scrasm/SCROLL.INC create mode 100644 16/scrasm/SCROLL.LNK create mode 100644 16/scrasm/SCROLL.MAP create mode 100644 16/scrasm/SCROLL.PAL create mode 100644 16/scrasm/SCROLL.TIL create mode 100644 16/scrasm/SPRITE.INC diff --git a/16/DOS_GFX.EXE b/16/DOS_GFX.EXE index 13b89317f3689d21e6f85000608aff996db46f4b..d4df1da3e32f74f72ff89c6c72677496f5b37b9e 100644 GIT binary patch delta 15833 zcmZu&3tW^%*PmyXU6$L5irfWMR4xiA$W;&!R!~6XCf-<)i=f<u1@A7Vrt2b+kG^I0 zy-D<$Z(3Sfk@^;?rKJ_T`72W2qQb%?HS>Z>@cqv`3+nG{^}lE4%$YN1X3or<XP)KW zKV;ABk?E7?FA;p%R_4k6!TS3X6imffy%l2~O!{03VeAfI9m<$JFd3Kyh`{?w#=ZhN zfd_!voUt*$XTXoZ17HaBxdVq}3dK7>3ewwv=YS>^)3Y`tegs^?81qNN@ql9jW9vZO ztr>e07-PfO8sMM6$3QpGmcm#w6n+S_0)MC(OC7@43R}jU>=>H@tO9lb-vB=WeL$lF zV=s(kZ1*VW9j#~Vh$myw;~2{T76BE&Y9IkhlYqlWn~i5|ED!*!19k!*0DfMKg#c$D z_a|t$H)D0cmp}*53yk%_DEKl~4lIP+V!(0&W3Ce!+pNde=U|iupkbg6cop~=xB+M; zF;)re1-=G;25tj(lhGJ3A1DXvfOmoFKo}l`&H#D9HsCqnUEoV#>=eiYCxPpL-aMGG zP+$@88VorD`Ze$?Aj7<?0Usa>C<hEcBk&gR5kQ}2Gp3H}id3n)^s0tQEx}FgGUTgN zl)NN6pV}Ni<s((u>2uOD4OcgHyKZTz_EdL;g*Aw4WiI+ai|cuj0;|sXRP*PM9XXx$ z>2+;8a&9-<GIf`OMZ<PYXFz9g(|=^@uDziR&2p9sZB60LwL)rhgDh3uHDPK)v%tCU zPo30~n)<lJFS4Q8gQY?yKdQmdz3AGTW~t4VWX)>xY{?ecHqlCMGqeG`Rux3%pKn&7 z-8rJSJVG|YTr89a2|tK?<$*HSD6v)UCwwgS%e@7Zn<WoRR5t86A!qj=1sm)y!oD!2 zxXo<pkZI-(*S?W$>Qh!vfZE^1ugwgyT0zWFxC#N{T7{Qotx#<dyfNyMEI@oy5$1@j zy1BnUxap!Sxak|&M*=ey_9>i6cDN}!TKTSRtx%(s#@NLCRT-#n4d2u!tM))+d*yph z)C%_>r6K(s(gBplps2eJg*R;KvxQLCN;#~Sgu0efdQd2;>sivIv)t5Yrc;pkNa&dX zJ&!vX)fFP&!+ZRVEVy6!GP`ar?lB*x=ac-I40D_{m(Q}@S<P)T_K^oO^kI4onmY!~ zJ$2W{hw836MFTv*!l=2e?uzQYe&ej>A!GeD4`FBX5I&K&!;o#h$p-R2h4pJ5Zrt#& zR#^A#Sxqlv5bdw&HA$ZdYo4YTo?sk<c<;syy#ZXjhm`j`R{jqt?`igj`$&yF3+bMX z8+s(=eYYg#eWuc)ux74%AfFBCzKt9DNVmGH-K+r)mD+5k=XS@$&fT%O1)c3qZH`6* z0W6i;T}*B|b9%$v{+jM5_~ghB;&#Lf2F(pv-`#uz?r9E1U3+62`fG0N*nAGEZl!WQ zRH?f*nfR?}l7!=VtEI91HF`+5o49EtI?p89VPa~z=yZrevdhFQAxZz(h8^)L7;uX( zmSziXw7N?h7YqY?<fa}B7*3r4e_gD)>x!HtTI85beK4QSs)uv4z}gog-*87>gZaJ} z*RZL7nqIM~Usx}{pL1tp-zx%geZu-r@8{gR{;|62MR`Ny3Z_#<x-gymTIXMrTF`V4 zEp5J#shhjW%<b}qO=nci0T@<V`o#a3_?4W$xcL_PL}N|`SEyh<FHm=Fj%$#(@F#Uw z9C4Lg%1S^!i1KEWT4;L+{Y%=>=)2DTRdznCqsrC0!!5O0p%9}j9feA9o~8Rph2k{a z96a>fruj7nf;BmR-h%Tax7%{UFkWOK70IxrC=^G(woH;?gB3^F*bxb_nL?z@rjf`{ zHI5r=ae+FPa<8a$L`Dqp(En-E)WYi2r&!Y&kWX3DIgroUq~Ec`ns3`QT|o9r*4&RR zD^f<2(I%uGS19T)_3ntmNq*`BTh=THe;&@(1sF~@cUskbe)2W5^whNDD7<vs$+}sH z{9=^hwEKL+H@%0Zvg${MKfK!#k41kmDx1`Z$A);pl%wAdF&Bh<@fX|qPT;m1-E8GX z^)Pv(o&2maPR3~Gu{=6&s7fHa^M?5g4~~k%YUGr&vUesj-af`bp)e#XQQQ6}S!1WH zKBvzRFQXCD+t2V(DAZjeA2eLwc~;Y>P+T`Y-bc*dmK#og{j+d-(r0Zy(@5U3Z={ht zDmvX!kZObb0e!IhHBaNHS)+`ju6aKF@1rr4e`}B*J^JZ#%H17Z>bY<9K>dABNc4_= zTwmfxk2dXZ&c+&*LDOr<>Z|`wJmR5~#kd_EH%iMVdFz-uvT%f_kz4xexOyRi2JU!2 z>vz-0_|evUtpUBMZ|4jtF;iw}zo!1x(2{02^<<g2+$)HB+US)|<erzi4ONIxr^!}Y z(g=?Bp6N&&qoyZ9nJud+GODv=TRzj3QQ>Cqu~h4zca;@pp#A#M>*I*+?Q@*iSAF7% zOz=%5vcWex077>4?Tx?4jP_l!`tJ<pkT%Sf)wdhmevui}T{0{cZ4SJh=I8_}-S8bx zbsZ*j5fLWl5Xqgm2jpn)L|g6@YX3sY*7*M_3sESbvHtR;exqB8Y|CYxP1yI97Eu3# zQEPVnCY7}t*2xSD&9?OGVhz=1TP|0}kj1+uPviYItdw1UH=Q^gle4I;&_Ev|`GMSy z9f854pyQH3(`RbHitF5@H)GWaXirO3I|DtajxxxT$b=v_xF-!@pTW#<%kXE{Uw;|S z8a^e-+#nYc*$~9FzaB&(r?_-V8}<R6*QCqpuI7i*Oh#bPb;Ikwn{@dDNMr_&u}~<^ zH+z_2C5an@JzW%vjb~lu-X9+kVrJBzn)~M)TJ5~kbJFHgc}s96sdWgUxKqpxnMLHS zkcmY88^V{+gAjkp`Gk%kGCQ;&i7am1FEiNh$0n1;*S%c%7WM)en@_W2@}da)W>%SC z`1)<LO{a%^eI3IoKf!GInAAocL)2&sdv}KMMqI;uU}ya$WAJFRE%$U$VV|y48SRAI zVW(EkCp&Y)97B2eN-DN~qS%YKZwyYAZMj$NVai~B@9AC)`?SWID!(1(M5gD4*)MRE z1h|&Bpydszk(yV*H~fin<DN982G|h+omCdbILinn9NsQx{(|#TZON`LuC4EHN|Rmx zmAXt578$OgX10WXs&WZ4YI>WT!o>85_w+A?eIB+G&l!R8p9LncXyF!nDeRJom8WEu zU^NINwS7QJ237}HmrSgsF3gS<3Fp`wCSC2aUoG&^R0Lgbm~^$vAms&CgFsTGi%aQk z!Rr7|Qr0eOqH`u%I1DR}o2+<>C0X%0Nl6tYsdm{@ER%kL$ykGsE&C14JtsR5ZW}%( z{6u(gcw+dM;S0md!+#7P|4jJq@H^p%puey^t9%A>XO-LVeLB<Fy{VhIWhv+S)w{Wb ziGGpJGI@kJGjhV*&0%jgJqy%^wRN?1HEl!knK0w`$1lo_A=9U0ZdGq?Y0>?8^LkHz zaBWzBh`Q^paQuwCSvKTmz0xTxu>S*A8`$#aK~y+0^hRvAb?uG7md0A~i%7>2n422q zraqgMOQ0twrR^8vF|_(Ha;(kcR?(a|A<8ShHcV@t<8HjV=yMqxF!z%hOTWg=VFt5L zYLtGB&mtj7sGgRn9guiN+!HlchW@ogdDyp1HFc=13qioXAq_^2vgwp~FUsArWhyiq z%={WpiSE;a%3Q)4QzMOTX^}>CMx@a`E3$TjQqT=)OaOBxm`Px!L^ef78r)(d4eGc^ zgS{qlyGHq}GCOi|r^#l&eUv$GGMx`|U`ta%WD_)KR0&N`qERL^r9_G!Pjm7lueEMM zs~XEDw5w6cHP#7DXkDX}Yb+C*vLg3oi+$5Z>Qf`nY#27qpzv!<LrTq48IgXz%GAi{ zGaD><K8x~clvh%o8=^I*p|oXz_xy}ev5^sH*W3B__<p-#rtz%t;r$<tw~XKVHO5Aw zP=i8!;0)h~zCG(@@^8V3j*R$Wy^Zf9->)_-bdlfpGrC2SU>w+bs~O-wfZ$g>ryrai z&~3?eM?I-=(*M(F#WgxTRwv$z_Ryope)q?13o~Y^+J0;MO@0cKwb_OOoqC(&m*m~Y zTjWOqZ*147Jmsw&a4qVV87-JW9{{gL<rfhg9l0(XBrZ}PXv|UiMPRbld4p&o^`noN zZ7)>ScFK=`DZh!iaSAh@=B>7gnKABTQFE$Pa|))yFG7i$z96XS$)!p5=$@GID!pyA z3Y&p#G{ZOj>xUt#$Hwq^$J8QVjK<vJp|?^N*wWU~)?sWnZnaHlvQMZ}J0@)3IxJyw zXOnY6lV`&A7ltQHzGtv^O}PJ4lN)j1H{%knhv9+In4{YC$abZlF-y7Wp~uQ`2EChe z0*M+=E6f@BcUu>)MSf(TKtAP&>f9v<7m3LxRg(t<lue@t1k7jzH+IWpd|&t^*ggS1 zJ-HKobxV-ns%x!p+3_Lk^E29eB=|MDCK#UW`^(SFsCG^ePtEkVc24l?4|b)m(Fx*T zGyUgyCI}j9zs7MOmi_g8e^p-!Y#CUtPb~`!F*-@6j7#8_azpt3<k#q#U|O2v62$eh z{4Gw*3_pd#Z1_y^-C1L8oWknc>syQ(HBE^4>#R}2Hqjz!48A8OdEq-NDR|UVGT4A@ z+itYokl!-Y+%vhF_-4{f$o3@Z1WU0r*&!Y^TI$<-@sMhqbym|;I}3tS<ttsMGM!^< z2mRaLafG`LL|!J5owK$V_E~o79Iz7}k=?`?Z4*CBp6I+SY-aT>t$c&^_QGBi+dolk zo8n<b{(L~CdvqSxYs*unh_$H!*1bt~$y1WEl2;~gOBN5M92x!ZTUGLFA2LIhN~p1= zeufzzwcTvHDep0CxaUWEuDD?~PB!tQ*@@Ks)TvRAMK=8`_uIa8TT0u{e!kDurmP=g z{BHVmztLM8QYLo>es*1L{Ekb!UYF8#t?k-rT<zc(J(~KuwWhkH#3Q!4u&|)gL!3Xy z1=w!^zm`6tkmi2WJ#D<qDIAw&geO0RxcDj*wHfig3I&ecXetvtqOmLlt5)3N2_80f z_zqoz`zyg?H*UlPk7Y-{$}kt~cj2mwJ_4JbB}hpYtP;C3$2n2`II!eZy5&!bY!-d9 zT!apBMwYw&56GNFp?PtcZdCwXb3Im7i-Rv(j@6l*ou2HMTUAPh_zX1FGL^Af<WZiL z{x{{(k+|Z6O(>t9_BZ7o(^v$HmK3C>{EYw}vzY_R%?nElN~;QVNDel>c-qdnZo*fh z`&<{9pOrXuuCqSQiZN%1D3%uJ@`_0Ku{iBFtxyMBW@r3OQyqzn?UQVcjs2VQ+F4u~ z)z|!Oc@hg}wvd6q+`sE=4vfQXB~w;ZVyFv|dTd;SI3(L$s2BaSeT7zWLAHx<M_ifh z>+FaNTSv&ri-Y*s4-9;OT0EJJ{-W3e#pYE7ODhX<^N}1Jo_$GD8O%wG`J4W<pnSmG zxW6fHeOy2N@9N)5Vm^qacz;t9|3*PA+!p_7JQ9*b{XBO(8^1EoMV2^3JUP!z(21A9 zDia^g^9?VDA!Df@1!cN|%KRly_G1^yR>KFC`Q;e4N-7%cqm7-oc)pwPi>ROP0)>0$ zyM)Kt<02R$=Edc?B_-u~Pm2G5GA|67Sw*F3{2!|_A1mIPA0-PPCk8C=6Sj!j1ujCC zxORa{c)l0r0R2=J=9QFJ6_CO~1J-%tnizRyVP!!<VZ~Erp*~{k0yp7#@g`KA6s;Dz z%)5$f?u`&KE7q0ga^c6SXa^V$o~o?8pm1qnDfe~c2c~>A%4fg~MM=qE<$<ymQNPed z_(|Nm&|jz(&o6WrUKX$8`;ut2$YorJA8J99qOfXp86S|xTBo9nLIG9T&K!HEXynGr z;BHuLU=FsuR9w5rU05UT#kXEOvB*VOA%45aU8V{WdltEcSq0&7ff~@}m6!%-uxb>_ zG*nhdLqtj+tKBTl&T$cTipz8Sg}21LIWA%6aoxTQ5}53&N@=+dYMO$r32T%oi_1&P z^PirF4dP8`Y7wopF5zvETLU?>swI`nLFqFvP_u9w{|I?S+5fjj6Dls&x(TO5z1H16 z7`q|{n**C1|L{%KSuU_+Vw*Nm|8Fo)1DAm=;CJ9YKy~Z@Ctwud1xyCQffOJe$N|cL zm4E@*3+w~_1-u2|E|}r*i**Bk0V6Oe-oPXv7>JVLt<VA_mI6AU7T5*s0p0~Z0losh z1%3i<1NQ-jmE;PH0s??(Knjot6ai}h5jY5(0{#m;0QvwK9K{kC0u04nE*p-7Bj5py z1-t+sz#o_lL;|tEOdthF1Lgu+ARj0KmI0MO4Nwbg0d@d8ffs<6frG$t;3MD@-~#X^ z?kQL+@C#rC_YMFS0=d94pbXFfTY);@IpBHV1>hy%pTO(DTfh<EUEmCG5%?bX8MqC| zlz6cR3<W%Z03aODPs3LVkOLF}rNA2C1>g{H8n_JH0uX63XTTqr0VDzWKrv7WtOja< zO~A8&5qJ?e0K5sj0~`lhfOg=PIkRFa_^2D;rxI(IcrFOR`4h{g<G`Q660lNcvRN#d zrLs9Jon^30HlHnE3z?SXvOJd03Rod4VkK+^t7bK9C0oT-v-NBP+^QB^)H7@o-gj<e z2DY6US)JIw#7X}Wdzt+Y`zL#aHL_P(6MLN<VE<xou!HOndy~Dzj<C1cJM1WXm%Yc{ zXCJT=>?8Iu`-GiiU$XzOcJ?FtiT%ocW7k<XyT$IX9`=Ae#A@uL2LQoF7%tceBLsWF zL2wkj1s}mz@Dl=rNy20yP?#bF>xB>@R0tO$gsDQLFinUSVua~Jyr2<g2#LZ>VV002 zBnv6RY#~*cBcux%!UAETkRxb?B|^SXAQTD3!ZM*mC>6?ta-l+4Ayf%+EC+;J{L_yQ zB|1{DNI36?*#K`T^4=0tp%`EWSYtUbYi4Z+kHnmGW1gK+^|a`p@8aYokPe%<)AGto z$}87+7J7MC*`u^u%*)>t9Iv8Mg;txMF-r}uQOZ~5mgQ@QAzu|n<;vvjjQF%<q)0EG z$z2PaNBqG>DOw8+UZs_ac8aqKTxLGQD-B7`)}~KSi;qu9h)<l6kii%!^p7Bg7Kr2G zGm>Y=#gi!&Q;BDloIN8xBPKmHemZ2`sG&&lNP(Md6kg>OAjZH07_X_Fo|KrHJ(;w{ zKE<0iiL{-IB00<S%vh3(ot=#w$<7;)Maxt|-SwD8vWn#F)R+{i`yS6*BA=O&nwTAr z(1X|g%0j?4gVUg(BzHCX%9(LiR9VSGJmQgpJ&DA#;oZxK&(28Ch)<<4JCQ(q^&o%x z?4;Rg;E-X9cpVJM?92?RL%jc;Me^Wj5|fh9hhfZCF68hA&84tSE814OmHvzNQD&~y zVj9ZIC4Kc=Or_1M(&bj_w7iW~Hlz=71*?j|;=JDmco_D$bZG+baNf}AIM<SalH}s5 z(p-eF)Q3Cbb2^9NWZhf5Rh3qoS6zv-O<bfKsXjSiNnTNLNxnEi=O#X^auvU?a&@4A zxyXyHwA!SK)TN~<xupe6e7kBy6sdc6KwUz5QE{P;(aboi$zV8UW>7N8#PPh!6klrj zV7DZRsa5vlcPEpmG--*+F*D+kqbluOtx}7@DPMxq#Hngj_6A9fR$EA+m!#(K5ME!a zO)M+crRmD5P@hb;v^DWH#bw1$@XH4HakJB5kCx_Me5uk)e74d~PZe$G)MeI^LQQc= zL6w#-oMj`3KLm~A0S!hCOa|47vo|$n3Ks{Q%zP~IG1P@6)m25(WZKDT(!tYeV=9;C z@wE~@j^u`UX|-isd6{l<;DCNU8YNsnIlvP?STT0U1(``vJeGTQqWJuZ5%y$E3g=_8 zv}HvFxfM$amWrt>eDpM^S>vf4^HLtu!blR&;^H<CFC_7_@|uE5;^%vr`jlVJBi4aF zP4ebCq%amt(z}lHETDo1uv)4g>O*oEM?7$83o1ufmX%90mct9sAQi-?#iY!L*OG^B z5nrir@FaC7xrF)3JY9L|5;Q?B73)jt6cqAm#hePqu_Tx?ftX4j%MRH0lf<j0_*N^r zS2&2u3J?2B6G;*lu2@-FtSjIaPW2Nz%I!y3`kRW93raPxpKK`>50^V6QaAJzbTLb< zc1C6S%5*pka>Q2!5g(&W&y-~a1^K3-h~j*6Ee}+|BW;LK%Uv?v%xJzahm{x#q^JWs zCF$a-T%C@#CgR=VJeXR#1g@*&rk<Z7Ss?|qxwK<*&EJYYlsPD9yPYq7ROTYSTIQ%A z>o$nbl{v)j4IZqeEw3mj8>qFPPdQv!OEa!5D9c?^QjjmT{v)r0b%(7%%S4Z|(ZQrp z6DoC=`^ZuZ1#}Vrl!>o}W$0LWrHMZyRO~3V*Gttbc{`?BypOX&NS(Qs2hgZOGu*~o zR#3dn``p6w*1WD{qU1kyCO%r!=9QP0(w0c3yvlopnWDuh#r9%MsgrC<uozHkZ`;a; z(1HxbGeLk>>??8P>!oI3bJNC@R21bdDbR@*N}O|PP>p;lhHJGrCQLnq7gy-0mt?Xu z*$VP{e&AYhdD>d(8Ba26MW8ft(2fU5$%9Du8gXukyS_WXRGO4qr6ccyW^$QmKjN#k zS~w-In5!$Nr&e;15MHL_&tVYfyqCFuqh&lg6=33MKx#S9N{drq2_`s~T$HSy!}$tY zAl}^U7QST6t8|ss71T9qWHn!J=GcyC9bu2GU+x%7wXgEUsi-D42|myBaM!$|<>bWF za>Y|iJTWCJCW-Tte8lMG_QCi0c7d6ysIFX!2VUv~b=sb9jp(#Ctu&*wf;L}G8Omt5 z9K6NuWzOQK%REL=s~LQ<X&2=l$xW7aHw$f{xOUliuPuDbw9uBBc0005+A`5_IzL?J z(Sx8EwanF1Gq?%jC^qfA)Y%BGM8VHpv9H)MhT67$Y6q|3ZU0~|IkZ+fnK)0!PYh*Y zMYS%Ex=0q}iHD0FM(pB;kV+d@o|ux6CY>+kqQ2NcoL}q_OLEfjh3!T2`1~TiblegD z@p(r!CGuksA;R?J+~P8^r)czuXx=BV3Z=zBqqtK%T;wimO%hv+?DeE?UlQ4EjoY2s zb7SJ-(&E$8xsL?!qgFw8C0ZJY!4o}EI?;~}ociTeTsztD4(GuWz{_1$&QFonfyI?n zF}*ZDskp2_n$9y!j!O@QrBzu_1=lXnme-VM5%c8XVVfE}!Yd+#sHmzCZ!ER<py$TN zA8PM77eNQ}maNtlh%HN<Jw}85z=pbHkACOsa!a(8)n&Tk(gNCc%PYmor4x9+rBKOI zyQFw2Hj#W<cHGTg;FayPSnbkbyRukUq%EzYK!FCZz?zf~*QS)?>?$j-URp#ew7ha) z^L~Td1iwUgY6|kW9~|I38kd@q!jfG5QX2S%fq_T-mKC3to;W*2TC|*x7<6t-Vn$kg zMq14Dc<O8ik27%#7Mqw6o0P#7d-1qb3dc3GQ+VuoWq^lxbb3Ne8nxBT>p~~m%7_>1 z3N2&&c$leNzNCmpl)UN11MxG&o{XQHEvU~}S2*eD%%*WTEdEgK9(iCODn|{9%E?g8 z0FOud^LV5m{S+^I5-s))F`~xBX*rMgtxfU16abR`Gh%s-J8q$#t8vkH@uv>>DEfn7 zfgU{gcCl^nNhNk(Mm!!p(vlKW5I>R?MsBl`Ki>>&FHVE<S&4D+v(w{eB*&+io@_=A zJSruoB!b0te4(O#E7eu}feJ}7yFd(CY4q0d=RHL!)*9c~a`<za)!b=SRrz>GtMaaq zq<<H$uUs2xi-SKJ*ax%%bi+Zn7B2!v0J?y<1vuiOAQd<OIN~|50(enuS`{Ifi9f8G zuFrss`3&LcA<&;Lym$Bx=%FoM@=i<KcsRY{egr?ty;>W1{o*h<bKS#$4A?LH_mD#c z+FY?_?Y#!*ySQNM-a~lKT%WjhIiCNS)0h46w=B@ET}j|M^wD!>XIv7lcyz8VQ(SQ^ zuz7RK+v`BX96r_`S%`)XMa8CE#BJ)%2+OshXy{)hMWgC)<(QV~GxQt`s&)>4=MXyJ zwCvJ5Eugd3`Yfl5jR4hx_+HS_@j07aVQBQG#-LUh`0TlbpZAiXUN4`uMZ*_ASB#)1 zx9UGaW}Kw*^9wI620!tte)rfe^rUXdgJE}|_>ORScPcDH50cMV;U;9|=U3Z7l~&iA z>ueZ{8I!*MHPFfvV=F7r;MRjKF0G(<|5q`kXefTXdv$k#84M4~o!Pk<4SqH8#+6Pq zxOJPwQctvVr*V?GhnlgqTGckX&Y7zJ-fqGwJg)cb{peUN6dbF#ylXKOj0~Aos=^RP z-hFd-9Y)CK#l2Qo3T%j{!*{K)yy1JxWiOM$ldD?-Fhbv)kFf59VKdkIL?oesZ`T}5 z?*+~KcSzZ0$i;Y`aCi+PHPq$ek0qF*$@{auTnu^rmNUm!AH&cG{MnMY3kEQoji)<6 zF?3%agCWDCYc?K0gFD*Ry%UFq{%FpO&&G%tZcOmG00l+=dAoWW8v6R?mPvFWeyjbb za!1tjtQ+;hDjMR4HODTZ;ryi=57wbWcRyU?xes(h{|Dc<Ti{Y>O}uxM4n6$$&94p~ zfa2dz-Tv<ZjL3>L89@_Zh;`A+N)>vJIlWW?y6ZiwJ13#oY{l0n%wSN)@=t$v1>L&m z#EC<gy4{PDT+C4ajLTiS3oy*)+X+^VFf7{h<O{FCu#2;Hb+)6Q7r#+us^}s9`P;6S zrlNvJZq^MuG-&tNC&TS9M8jRa_l$<6uZMloSpiz_boG-K$PHcQ+noW0zaRdfs}2T@ z$gLk21ch_o7*|a<rB2=dmDB3Hds4WZ0ebvMxcw^3b(dN5k90Bi{D!rTEui0ap0{Yx zLvgBIe&A+uCZ|UyT%pjh`@hp$K%c+uvLy%>pBU#f2Kw1W*H30sXuK=)^9nE2b4%&D zn*oC|obTGvZ|8TPh#Q-M4h;3VvfwqyyN1jvr0w9&@%MLMM1w2SwDavS!e+M<hh0Iv zBV%&r=wC#|{8O1<bb#LZ{q~(ZL=WZWMw1V$JM_K|2K=EoXWm6ar|Y`03X1<ww41xa zko5m4p5cM1u(jEE@d$bvrr2Lbdr;BGBgS^4!P5P$M^u>F`1OHDl29K`U092HE^uPH zQ62iqXZkq&(E_V#>yM!e!~-Aw@=P`jd8fPcIt=kq|7$i4Qcp_g4cZ6GE#L0~f9JZr z3p`QpU{XT(V$h;%yT|pSM-GW?TUucFuz70RR5;!FM78Ta7|`9>^<_8e7l(hA-2<n+ z+c<sANtCboUVo>e3kma#h}a@neAi>t+Bj6GSiI{-D4gezOYU*}8Vl?8@<9*q@9rD5 z7C#tfm6>d25ESOG&CCdZ!YyasSzQEqhq&ZN&7gOVt$QgHBl5z=4_976PcLVBTTewh zmIps?O+ZI=tCVkS20f$S;&QhEiga3iNIrV-SDf=V)=*F|!!mv!8SqMGKo==IKI-`Z z^t^D+sUM3lglwe0eJBizv)OA$x9heGZO&gngJ(xv3EG7bS<rsw-zqeCO5bzCi#L3! zbs-wug;nt)b<}0~STD4v&)mMnr2z@y>WqXq^kiMn;g4Q}^Hn~7Jm41S#V<bY>_r1H zYnA)0p?K|-%zz0{<bUF0t00U-&>GKodqLO41?5(tBe#QktaQ*5Gdg{LD12$xH-BXG z!tlu>#$CLFslnF!`33mG(pihOu4td#u!{OK6c+6-nKJAG6n%2P=}T8AIBhj+!68&= z2pVqDj1J%Za7uhP=;X%ePP%~3*z9um3TV}C7c)C_V9JP<mM2j!^YZSv#c24C=G}1^ z5dNV9k?;>wJ`R)|+8yol&uM&<RlkG6D*k4Kc0YO>LTkGllr|3?Mu3cohrzVV6@Z>Y z-Uv$j{uiKh!qcm3TEa#+Gj)RA7SnWn1zL-|A4ZB!#5g??w42c@SQ=*f;~m<L3(zCl zL{_0kw5`4XN(abqptPyn0VM|`N-KpZ`NsoL>OH-lrR|z1?F|8-bkx&(SvpZSfRdx? z6H!Qxb{LdAl_<pkmQY6fI#HVUGEh2L=!Iw~C>cddk6!-MiIz74#v;EAlpI(GN{&cx zJ!#4P07^%=`B?ZADE-U;)1_w-NZbLV1e8vsEugfdvc_ZXl@g`3n(qYzF)9w;P=Nd- zP+Ge5qLa>x`=AsHg!-T!@=2hyjpu;U30nb5j=KevR@(ER3FesplSt4udKHwGNUSgB zA9;GMNozD`0u&+N0!ohe6DS=pb0)$sFkQ8v6eGM0N)CAmlwt>Zxk=Fwy~w14jb35W z{%`3I1Cj3zfUoJnD4qoCz@T4H&`QvQ(h<8N5OasT3LZ$iAHB?^O^RMz(&j^y!l=!l zw67aM=>*&fN(am>P}=wD)g^6Ot)R3me+x>xBE7cMQ;;zq2|DREfKoVC2TI%UUQpT% zTR>^8)B8(0!+!*&-H_f{(*CXqg$(#aDejvAinE=a0;Rao2|w28#wwvd5~Dq3BxpPG zRbiNaI@9Ub9CWhLj~Z$7p`SHUpy?lh29fUqrCqNAFFfhs*$J8o{uxkypy1aW6eG~D zIw<~&1*JGI4wN<>4QMa&^FTY0KLASS#NkNHKOMOpVC;jyDE#W40?_546t|rNr2rB? z2VuKVVKFG3c<+HmBkz>}=R*DjC>_05KxsQ(ln7bSJ)jg9HiJ?yLqFx9XzG7wVakxN z)hEF+ETsle+Ait05p;yoZy+e5rQbT#BELHsa#&V7Q^11)`gCIGYd|4_7ho7EY(W16 zr4#Z1QONxZ^dj<afKtf*7AOU*M?fj&(7%HOg-=IG0E}ax6i~hkN@3G`pcFthgHmjO zzdT?Rc%B5MnBhZEI(S+@k05^rlp^YLln1>4N-;(&D1~bmDGy5XkAqFmqG2V)0I{GH zP~z_q7=_pxP&&b8g3?)@0!jx|Drgb%X`pmYWPnm+n*~ZSKsM-9(D|Sg>E?jaxv~V5 zB59f~ik{Yh>MSw;uOdP5-F^~)LYkip^!yko9i10I=|m&C7*_uWl+JRZ6dhdzT?PI( zRE~T*Xan+>Kq>0E0{R;A--A*(*8$3(wm>grVorZSf`W(NKq;zGW7sH`r~SVLc{`%$ zkv-@k^vId=p!Bw!&T=;lCmq2apcGn<HWMeM`zUPj22d+LdbTRk1Fd@qmdq0#?aI?u z_}wyiJZ;Su5Ato;y1}%Xy+~>C;8uUVBsrV~!9+=e9iIq^KY~>Z^6gn2(ilFp=)hhc z<U8WeJqPMK@iCKRoLMLMj$Gb_AAyp7SLTTBN$HW|ylqoVHjHK$!N+Jo{}|RWDC5a` zk(TTk%RO33k7H9YERvq_EE{R5UHrg%knhbl52k(CKBT3(zN}@CKS9rrM@i8{)-zb( z$Lugi65pS{>zC32ED3z6u}S>>za2MvGOHMr59IIvC4LawH^`sDP7bDnSvya|Q$2(b zepE^ggfd%rp=4<ofB7%*!&wseQaXY!6)8QHZ61`5<V!~4N3oVc`DyIRU^<%hAT1de z!>s8?0a9bJ{2Z0i)A<huBt>zoh`f^bGM*oul8lDE2EH`KGuX*NJqi4{lw=ZFFVz*x zw>y|7I*Db&w<T@K`1`VfbP8)2OwZ=$og|aW&VetPJBM8vlu2VfgXwf;hxH-JXRv_5 zbS6t0OlPfUMT42SZ1Z3`n=dZO+<E-Gqx5*((sV#(6&zxs(BGepg&YmO57I9peQ`8i f&?8+kNpc2Xq}L%0n^+Lin@#+b*nlt(oU8u_r2CQI delta 15694 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 diff --git a/16/DOS_GFX.OBJ b/16/DOS_GFX.OBJ index 35e3f4ed617b65a74bc2c2ce1950811062822244..f17a0b16baf7f45788d4f3ee34931c1803b59d5c 100644 GIT binary patch delta 3006 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 B(Q^O* delta 2788 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 O>V=3F1hq19`F{altb02E diff --git a/16/Project 16.bfproject b/16/Project 16.bfproject index b5009ceb..378d9de2 100644 --- a/16/Project 16.bfproject +++ b/16/Project 16.bfproject @@ -1,7 +1,7 @@ c2e.convert_special: 0 e2c.convert_num: 0 -openfiles: /dos/z/16/16/dos_gfx.cpp:8135:7436:1: -openfiles: /dos/z/16/16/dos_gfx.h:327:0:0: +openfiles: /dos/z/16/16/dos_gfx.cpp:1620:647:1: +openfiles: /dos/z/16/16/dos_gfx.h:665:373:0: openfiles: /dos/z/16/16/dos_kb.c:1039:46:0: openfiles: /dos/z/16/16/dos_kb.h:23:0:0: openfiles: /dos/z/16/16/lib/lib_com.cpp:0:0:0: @@ -80,25 +80,25 @@ recent_files: file:///dos/z/16/16/xx.bat recent_files: file:///dos/z/16/16/lib/x/MXPN.ASM recent_files: file:///dos/z/4x4_16/!/c/TUT10.C recent_files: file:///dos/z/16/16/lib/x/MXVS.ASM -recent_files: file:///dos/z/16/16/lib/x/MODEX.H -recent_files: file:///dos/z/4x4_16/modex/DEMO01.PAS -recent_files: file:///dos/z/4x4_16/modex/DEMO07.PAS +recent_files: file:///dos/z/16/16/lib/x/MAKEFILE +recent_files: file:///dos/z/16/16/lib/x/MODEX.DEF recent_files: file:///dos/z/16/16/dos_gfx.h +recent_files: file:///dos/z/16/16/dos_gfx.cpp recent_files: file:///dos/z/16/16/dos_kb.c recent_files: file:///dos/z/16/16/dos_kb.h recent_files: file:///dos/z/16/16/lib/lib_com.cpp -recent_files: file:///dos/z/16/16/lib/lib_com.h recent_files: file:///dos/z/16/16/16.txt +recent_files: file:///dos/z/16/16/lib/lib_com.h recent_files: file:///dos/z/16/16/scroll.txt recent_files: file:///dos/z/16/16/project16.txt -recent_files: file:///dos/z/16/16/lib/intro/lib.c -recent_files: file:///dos/z/16/src/lib/dos_gfx.h +recent_files: file:///dos/z/16/16/lib/x/MODEX.H +recent_files: file:///dos/z/4x4_16/modex/DEMO07.PAS recent_files: file:///dos/z/16/16/lib/x/MXBB.ASM -recent_files: file:///dos/z/16/src/lib/dos_gfx.cpp +recent_files: file:///dos/z/16/src/lib/dos_gfx.h +recent_files: file:///dos/z/4x4_16/modex/DEMO01.PAS recent_files: file:///dos/z/16/16/lib/x/MXCR.ASM -recent_files: file:///dos/z/16/16/dos_gfx.cpp -recent_files: file:///dos/z/16/16/lib/x/MAKEFILE -recent_files: file:///dos/z/16/16/lib/x/MODEX.DEF +recent_files: file:///dos/z/16/16/lib/intro/lib.c +recent_files: file:///dos/z/16/src/lib/dos_gfx.cpp snr_replacetype: 0 savedir: file:///dos/z/16/16 spell_check_default: 1 diff --git a/16/dos_gfx.cpp b/16/dos_gfx.cpp index 41b7d533..52e259db 100644 --- a/16/dos_gfx.cpp +++ b/16/dos_gfx.cpp @@ -48,10 +48,11 @@ void setvideo(/*byte mode, */short vq){ mxSetMode( MX_320x240 ); // mxSetVirtualScreen(SW+(SW/4), SH+(SH/4)); // mxSetVirtualScreen(SW*2, SH*2); - mxSetVirtualScreen(VW,(VH+(TILEWH*BUFFMX))); + mxSetVirtualScreen(VW,BH); // mxSetVirtualScreen((640-(TILEWH*4)),(480-(TILEWH*4))); mxSetClip(true); - mxSetClipRegion(0, 0, VW, (VH+(TILEWH*BUFFMX))); + mxSetClipRegion(0, 0, VW, BH); + mxPan(TILEWH*2,TILEWH*2); //mxSetClipRegion(0, VH+1, VW, (TILEWH*BUFFMX)); } } @@ -212,17 +213,17 @@ short ding(int q){ } } // fixer - if(q!=16){ + if(q!=16){ #ifdef TILE if(xx<0) xx=(VW-TILEWH); if(yy<0) yy=(VH-TILEWH); if(xx>(VW-TILEWH)) xx=0; - if(yy>(VH-TILEWH)/*+(TILEWH*BUFFMX)*/) yy=0; - #else + if(yy>(VH-TILEWH)/*+(TILEWH*BUFFMX)*/) yy=0; + #else if(xx<0) xx=VW; if(yy<0) yy=VH; if(xx>VW) xx=0; - if(yy>VH) yy=0; + if(yy>VH) yy=0; #endif } @@ -272,8 +273,8 @@ int main(void) // main variables d=4; // switch variable key=4; // default screensaver number - xpos=0; - ypos=0; + xpos=TILEWH*2; + ypos=TILEWH*2; xdir=1; ydir=1; setvideo(1); @@ -319,21 +320,21 @@ int main(void) mxPutPixel(VW-1, y, 15); } - getch(); + getch(); //text box - mxSetTextColor(10, OP_TRANS); //set font - mxBitBlt(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, VH); //copy background - mxFillBox(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, OP_SET); // background for text box - //+(QUADWH*6) - mxOutText(xpos+1, ypos+SH-48, "========================================"); + mxSetTextColor(10, OP_TRANS); //set font + mxBitBlt(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, BS); //copy background + mxFillBox(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, OP_SET); // background for text box + //+(QUADWH*6) + mxOutText(xpos+1, ypos+SH-48, "========================================"); mxOutText(xpos+1, ypos+SH-40, "| |Chikyuu:$line1"); mxOutText(xpos+1, ypos+SH-32, "| |$line2"); mxOutText(xpos+1, ypos+SH-24, "| |$line3"); - mxOutText(xpos+1, ypos+SH-16, "| |$line4"); - mxOutText(xpos+1, ypos+SH-8, "========================================"); - mxFillBox(xpos+QUADWH, ypos+QUADWH+(TILEWH*12), TILEWH*2, TILEWH*2, 9, OP_SET); - getch(); - mxBitBlt(0, VH, 320, TILEWH*BUFFMX, xpos, ypos+(TILEWH*12)); //copy background + mxOutText(xpos+1, ypos+SH-16, "| |$line4"); + mxOutText(xpos+1, ypos+SH-8, "========================================"); + mxFillBox(xpos+QUADWH, ypos+QUADWH+(TILEWH*12), TILEWH*2, TILEWH*2, 9, OP_SET); //portriat~ + getch(); + mxBitBlt(0, BS, 320, TILEWH*BUFFMX, xpos, ypos+(TILEWH*12)); //copy background //mxBitBlt(0, (TILEWH*12)+1, 320, TILEWH*3, 0, 0); getch(); while(!kbhit()){ @@ -341,18 +342,19 @@ int main(void) // scrolly(1); // vScroll(1); // delay(100); - //for(int i=0;i<TILEWH;i++){ + //for(int i=0;i<TILEWH;i++){ ding(key); mxPan(xpos,ypos); //for(short o = 0; o<TILEWH; o++){ - //xpos+=xdir; - //ypos+=ydir; - if(ypos==1 || (ypos==((VH+(TILEWH*BUFFMX))-SH-1)))delay(1000); - //mxWaitRetrace(); + xpos+=xdir; + ypos+=ydir; + //if(ypos==1 || (ypos==(BH-SH-1)))delay(500); + //if((xpos>(VW-SW-1)) || (xpos<1))delay(500); + mxWaitRetrace(); //} if( (xpos>(VW-SW-1)) || (xpos<1)){xdir=-xdir;} - if( (ypos>((VH+(TILEWH*BUFFMX))-SH-1)) || (ypos<1)){ydir=-ydir;} // { Hit a boundry, change + if( (ypos>(BH-SH-1)) || (ypos<1)){ydir=-ydir;} // { Hit a boundry, change // direction! } } ch=getch(); @@ -360,7 +362,8 @@ int main(void) if(ch==0x1b)break; // 'ESC' } setvideo(0); - printf("wwww\nVirtual Resolution: %dx%d\n", VW,VH); + printf("wwww\nFull Buffer Virtual Resolution: %dx%d\n", VW,BH); + printf("Virtual Resolution: %dx%d\n", VW,VH); printf("Resolution: %dx%d\n", SW,SH); printf("Mode X Library Version: %d\n", mxGetVersion()); printf("bakapi ver. 1.04.09.04\nis made by sparky4iÖ j feel free to use it ^^\nLicence: GPL v2\n"); diff --git a/16/dos_gfx.h b/16/dos_gfx.h index b9045057..231c1061 100644 --- a/16/dos_gfx.h +++ b/16/dos_gfx.h @@ -21,8 +21,12 @@ #define SW 320 #define SH 240 -#define VW 560 -#define VH 416 +//#define VW 560 +//#define VH 416 +#define VW (SW+64) +#define VH (SH+64) +#define BS (VH*2) // buffer space! not BULLSHIT +#define BH BS+(TILEWH*BUFFMX) // buffer resolution //void drawChar(int x, int y, int color, byte c); //void drawText(int x, int y, int color, byte string); diff --git a/16/lib/x/MODEX.BAK b/16/lib/x/MODEX.BAK new file mode 100644 index 0000000000000000000000000000000000000000..560a1c68304c56844f41325820f296a21192ac4e GIT binary patch literal 25600 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 aYMYlCQRoM`ir$`=9Z}>r1>yg*e*Xh>)L^y% literal 0 HcmV?d00001 diff --git a/16/scrasm/80X86.ASC b/16/scrasm/80X86.ASC new file mode 100644 index 00000000..e16af972 --- /dev/null +++ b/16/scrasm/80X86.ASC @@ -0,0 +1,164 @@ +_80x86 OPTIMIZATION_ +by Michael Abrash + + +[LISTING ONE] + +; Copies one string to another string, converting all characters to +; uppercase in the process, using a loop containing LODSB and STOSB. +; Adapted from Zen of Assembly Language, by Michael Abrash; not a +; standalone program, but designed to be used with the Zen timer from +; that book via the Zen timer's PZTIME.BAT batch file: ZTimerOn starts +; the clock, ZTimerOff stops it, and the test-bed program linked in by +; PZTIME.BAT starts the program, reports the results, and ends. + + jmp Skip ;skip over data in CS and subroutine + +SourceString label word ;sample string to copy + db 'This space intentionally left not blank',0 +DestString db 100 dup (?) ;destination for copy + +; Copies one zero-terminated string to another string, +; converting all characters to uppercase. +; Input: DS:SI = start of source string; DS:DI = start of destination buffer +; Output: none +; Registers altered: AX, BX, SI, DI, ES +; Direction flag cleared + +CopyStringUpper: + mov ax,ds + mov es,ax ;for STOS + mov bl,'a' ;set up for fast register-register + mov bh,'z' ; comparisons + cld +StringUpperLoop: + lodsb ;get next character and point to following character + cmp al,bl ;below 'a'? + jb IsUpper ;yes, not lowercase + cmp al,bh ;above 'z'? + ja IsUpper ;yes, not lowercase + and al,not 20h ;is lowercase-make uppercase +IsUpper: + stosb ;put character into new string and point to + ; following location + and al,al ;is this the zero that marks end of the string? + jnz StringUpperLoop ;no, do the next character + ret + +; Calls CopyStringUpper to copy & convert SourceString->DestString. +Skip: + call ZTimerOn ;start timing + mov si,offset SourceString ;point SI to the string to copy from + mov di,offset DestString ;point DI to the string to copy to + call CopyStringUpper ;copy & convert to uppercase + call ZTimerOff ;stop timing + + +[LISTING TWO] + +; Copies one string to another string, converting all characters to +; uppercase in the process, using no string instructions. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + jmp Skip ;skip over data in CS and subroutine + +SourceString label word ;sample string to copy + db 'This space intentionally left not blank',0 +DestString db 100 dup (?) ;destination for copy + +; Copies one zero-terminated string to another string, +; converting all characters to uppercase. +; Input: DS:SI = start of source string; DS:DI = start of destination string +; Output: none +; Registers altered: AL, BX, SI, DI + +CopyStringUpper: + mov bl,'a' ;set up for fast register-register + mov bh,'z' ; comparisons +StringUpperLoop: + mov al,[si] ;get the next character and + inc si ; point to the following character + cmp al,bl ;below 'a'? + jb IsUpper ;yes, not lowercase + cmp al,bh ;above 'z'? + ja IsUpper ;yes, not lowercase + and al,not 20h ;is lowercase-make uppercase +IsUpper: + mov [di],al ;put the character into the new string and + inc di ; point to the following location + and al,al ;is this the zero that marks the end of the string? + jnz StringUpperLoop ;no, do the next character + ret + +; Calls CopyStringUpper to copy & convert SourceString->DestString. +Skip: + call ZTimerOn + mov si,offset SourceString ;point SI to the string to copy from + mov di,offset DestString ;point DI to the string to copy to + call CopyStringUpper ;copy & convert to uppercase + call ZTimerOff + + +[LISTING THREE] + +; Clears a buffer using MOV/ADD in a loop. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + mov dx,2 ;repeat the test code twice, to make + ; sure it's in the cache (if there is one) + mov bx,dx ;distance from the start of one word + ; to the start of the next + sub ax,ax ;set buffer to zeroes +TestTwiceLoop: + mov cx,1024 ;clear 1024 words starting at address + mov di,8000h ; DS:8000h (this is just unused memory + ; past the end of the program) + call ZTimerOn ;start timing (resets timer to 0) +StoreLoop: + mov [di],ax ;clear the current word + add di,bx ;point to the next word + dec cx ;count off words to clear until none + jnz StoreLoop ; remain + call ZTimerOff ;stop timing + dec dx ;count off passes through test code + jz StoreDone ;that was the second pass; we're done + jmp TestTwiceLoop ;that was first pass; do second pass with all + ; instructions and data in the cache +StoreDone: + + +[LISTING FOUR] + +; Clears a buffer using MOV/ADD in an unrolled loop. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + mov dx,2 ;repeat the test code twice, to make + ; sure it's in the cache (if there is one) + mov bx,dx ;distance from the start of one word + ; to the start of the next + sub ax,ax ;set buffer to zeroes +TestTwiceLoop: + mov si,1024 ;clear 1024 words starting at address + mov di,8000h ; DS:8000h (this is just unused memory + ; past the end of the program) + call ZTimerOn ;start timing (resets timer to 0) + mov cl,4 ;divide the count of words to clear by + shr si,cl ; 16, because we'll clear 16 words + ; each time through the loop +StoreLoop: + REPT 16 ;clear 16 words in a row without looping + mov [di],ax ;clear the current word + add di,bx ;point to the next word + ENDM + dec si ;count off blocks of 16 words to clear + jnz StoreLoop ; until none remain + call ZTimerOff ;stop timing + dec dx ;count off passes through test code + jz StoreDone ;that was the second pass; we're done + jmp TestTwiceLoop ;that was the first pass; do the second pass + ; with all instructions and data in the cache +StoreDone: + diff --git a/16/scrasm/80X86.TXT b/16/scrasm/80X86.TXT new file mode 100644 index 00000000..afba3707 --- /dev/null +++ b/16/scrasm/80X86.TXT @@ -0,0 +1,494 @@ +Journal: Dr. Dobb's Journal March 1991 v16 n3 p16(8) +----------------------------------------------------------------------------- +Title: 80x86 optimization: aim down the middle and pray. (80x86 family of + microprocessors) (tutorial) +Author: Abrash, Michael. +AttFile: Program: 80X86.ASC Source code listing. + +Summary: Optimizing code for 8088, 80286, 80386 and 80486 microprocessors + is difficult because the chips use significantly different memory + architectures and instruction execution times. Code cannot be + optimized for the 80x86 family; rather, code must be designed to + produce good performance on a range of systems or optimized for + particular combinations of processors and memory. Programmers + must avoid the unusual instructions supported by the 8088, which + have lost their performance edge in subsequent chips. String + instructions should be used but not relied upon. Registers should + be used rather than memory operations. Branching is also slow for + all four processors. Memory accesses should be aligned to improve + performance. Generally, optimizing an 80486 requires exactly the + opposite steps as optimizing an 8088. +----------------------------------------------------------------------------- +Descriptors.. +Company: Intel Corp. (Products). +Ticker: INTC. +Product: Intel 80286 (Microprocessor) (Programming) + Intel 80386 (Microprocessor) (Programming) + Intel 80486 (Microprocessor) (Programming) + Intel 8088 (Microprocessor) (Programming). +Topic: Microprocessors + Optimization + Programming + Tutorial + Assembly Language + Guidelines + Type-In Programs + Microcode + Processor Architecture. +Feature: illustration + graph. +Caption: Official and actual cycles per binary-to-hex ASCII conversion. + (graph) + Actual performance in microseconds of two solutions to a problem. + (graph) + Actual performance of three clearing approaches across the 80x86 + family. (graph) + +----------------------------------------------------------------------------- +Full Text: + +Optimization + +Picture this: You're an archer aiming at a target 100 feet away. A strong +wind comes up and pushes each arrow to the left as it flies. Naturally, you +compensate by aiming farther to the right. That's what it's like optimizing +for the 8088; once you learn to compensate for the strong but steady effects +of the prefetch queue and the 8-bit bus, you can continue merrily on your +programming way. + +Now the wind starts gusting unpredictably. There's no way to compensate, so +you just aim for the bull's-eye and hope for the best. That's what it's like +writing code for good performance across the entire 80x86 family, or even for +the 286/386SX/386 heart of today's market. You just aim down the middle and +pray. + +The New World of the 80x86 + +In the beginning, the 8088 was king, and that was good. The optimization +rules weren't obvious, but once you learned them, you could count on them +serving you well on every computer out there. + +Not so these days. There are four major processor types--8088, 80286, 80386, +and 80486--with a bewildering array of memory architectures: cached (in +several forms), page mode, static-column RAM, interleaved, and, of course, +the 386SX, with its half-pint memory interface. The processors offer wildly +differing instruction execution times, and memory architectures warp those +times further by affecting the speed of instruction fetching and access to +memory operands. Because actual performance is a complex interaction of +instruction characteristics, instruction execution times, and memory access +speed, the myriad processor-memory combinations out there make "exact +performance" a meaningless term. A specific instruction sequence may run at +a certain speed on a certain processor in a certain system, but that often +says little about the performance of the same instructions on a different +processor, or even on the same processor with a different memory system. The +result: Precise optimization for the general PC market is a thing of the +past. (We're talking about optimizing for speed here; optimizing for size is +the same for all processors so long as you stick to 8088-compatible code.) + +So there is no way to optimize performance ideally across the 80x86 family. +An optimization that suits one processor beautifully is often a dog on +another. Any 8088 programmer would instinctively replace: + +DEC CX JNZ LOOPTOP + +with: + +LOOP LOOPTOP + +because LOOP is significantly faster on the 8088. LOOP is also faster on the +286. On the 386, however, LOOP is actually two cycles slower than DEC/JNZ. +The pendulum swings still further on the 486, where LOOP is about twice as +slow as DEC/JNZ--and, mind you, we're talking about what was originally +perhaps the most obvious optimization in the entire 80x86 instruction set. + +In short, there is no such thing as code that's truly optimized for the +80x86. Instead, code is either optimized for specific processor-memory +combinations, or aimed down the middle, designed to produce good performance +across a range of systems. Optimizing for the 80x86 family by aiming down +the middle is quite different from optimizing for the 8088, but many PC +programmers are inappropriately still applying the optimization lore they've +learned over the years on the PC (or AT). The world has changed, and many of +those old assumptions and tricks don't hold true anymore. + +You will not love the new world of 80x86 optimization, which is less precise +and offers fewer clever tricks than optimizing for the 8088 alone. Still, +isn't it better to understand the forces affecting your code's performance +out in the real world than to optimize for a single processor and hope for +the best? + +Better, yes. As much fun, no. Optimizing for the 8088 was just about as +good as it gets. So it goes. + +Optimization Rules for a New World + +So, how do you go about writing fast code nowadays? One way is to write +different versions of critical code for various processors and memory access +speeds, selecting the best version at runtime. That's a great solution, but +it requires an awful lot of knowledge and work. + +An alternative is to optimize for one particular processor and settle for +whatever performance you get on the others. This might make sense when the +8088 is the target processor because it certainly needs the optimization more +than any other processor. However, 8088 optimization works poorly at the +upper end of the 80x86 family. + +Nowadays, though, most of us want to optimize for the 286 and 386 systems +that dominate the market, or across all 80x86 processors, and that's a tough +nut to crack. The 286 and 386 come in many configurations, and you can be +sure, for example, that a 386SX, an interleaved 386, and a cached 386 have +markedly different performance characteristics. There are, alas, no hard and +fast optimization rules that apply across all these environments. + +My own approach to 80x86 optimization has been to develop a set of general +rules that serve reasonably well throughout the 80x86 line, especially the +286 and 386, and to select a specific processor (in my case a cached 386, for +which cycle times tend to be accurate) to serve as the tiebreaker when +optimization details vary from one processor to another. (Naturally, it's +only worth bothering with these optimizations in critical code.) The rules +I've developed are: + +* Avoid accessing memory operands; use the registers to the max. + +* Don't branch. + +* Use string instructions, but don't go much out of your way to do so. + +* Keep memory accesses to a minimum by avoiding memory operands and keeping +instructions short. + +* Align memory accesses. + +* Forget about many of those clever 8088 optimizations, using oddball +instructions such as DAA and XLAT, that you spent years learning. + +Next I'll discuss each of these rules in turn in the context of +8088-compatible real mode, which is still the focus of the 80x86 world. +Later, I'll touch on protected mode. + +Let's start by looking at the last--and most surprising--rule. + +Kiss Those Tricks Goodbye + +To skilled assembly language programmers, the 8088 is perhaps the most +wonderful processor ever created, largely because the instruction set is +packed with odd instructions that are worthless to compilers but can work +miracles in the hands of clever assembly programmers. Unfortunately, each +new generation of the 80x86 has rendered those odd instructions and marvelous +tricks less desirable. As the execution time for the commonly used +instruction ADD BX, 4 has gone down from four cycles (8088) to three cycles +(286) to two cycles (386) to one cycle (486), the time for the less +frequently used instruction CBW has gone from two cycles (8088 and 286) up to +three cycles (386 and 486)! + +Consider this ancient optimization for converting a binary digit to hex +ASCII: + +ADD AL,90H DAA ADC AL,40H DAA + +Now consider the standard alternative: + +ADD AL,'0' CMP AL,'9' JBE HaveAscii ADD AL,'A'-('9'+1) HaveAscii: + +As Figure 1 indicates, the standard code should be slower on an 8088 or 286, +but faster on a 386 or a 486--and real-world tests confirm those results, as +shown in Figure 2. (All "actual performance" timings in this article were +performed with the Zen timer from Zen of Assembly Language, see "References" +for details. The systems used for the tests were: 8088, standard 4.77 MHz PC +XT; 80286, standard one-wait-state, 8 MHz PC AT; 386SX, 16 MHz noncached; +80386, 20 MHz externally cached with all instructions and data in external +cache for all tests except Listings One and Two; 80486, 25 MHz internally +cached, with all instructions and data in internal cache for all tests except +Listings One and Two.) + +In other words, this nifty, time-tested optimization is an anti-optimization +on the 386 and 486. + +Why is this? On the 386, DAA--a rarely used instruction--takes four cycles, +and on the 486 it takes two cycles, in both cases twice as long as the more +common instructions CMP and ADD; in contrast, on the 8088 all three +instructions are equally fast at four cycles. Also, the instruction-fetching +advantage that the 1-byte DAA provides on the 8088 means nothing on a cached +386. + +Nor is this an isolated example. Most oddball instructions, from AAA to +XCHG, have failed to keep pace with the core instructions--ADC, ADD, AND, +CALL, CMP, DEC, INC, Jcc, JMP, LEA, MOV, OR, POP, PUSH, RET, SBB, SUB, TEST, +and XOR--during the evolution from 8088 to 486. As we saw earlier, even LOOP +lags behind on the 386 and 486. Check your favorite tricks for yourself; +they might or might not hold up on the 386, but will most likely be +liabilities on the 486. Sorry, but I just report the news, and the news is: +Kiss most of those tricks goodbye as the 386 and 486 come to dominate the +market. (This means that hand-optimization in assembly language yields less +of a performance boost nowadays than it did when the 8088 was king; the +improvement is certainly significant, but rarely in the 200-500 percent range +anymore. Sic transit gloria mundi.) Most startling of all, string +instructions lose much of their allure as we move away from the 8088, hitting +bottom on the 486. + +The 486: All the Rules Change + +The 486 represents a fundamental break with 8088-style optimization. +Virtually all the old rules fail on the 486, where, incredibly, a move to or +from memory often takes just one cycle, but exchanging two registers takes +three cycles. The nonbranching core instructions mentioned earlier take only +one cycle on the 486 when operating on registers; MOV can, under most +conditions, access memory in one cycle; and CALL and JMP take only three +cycles, given a cache hit. However, noncore instructions take considerably +longer. XLAT takes four cycles; even STC and CLC take two cycles each. The +486's highly asymmetric execution times heavily favor core instructions and +defeat most pre-486 optimizations. + +Core instructions do have a weakness on the 486. While 486 MOVs involving +memory are remarkably fast, accessing memory for an operand to OR, ADD, or +the like costs cycles. Even with the 8K internal cache, memory is not as +fast as registers, except when MOV is used (and sometimes not even then), so +registers are still preferred operands. (AND [BX],1 is fast, at only three +cycles, but AND BX,1 takes only one cycle--three times as fast.) + +OUT should be avoided whenever possible on the 486, and likewise for IN. OUT +takes anywhere from 10 to 31 cycles, depending on processor mode and +privileges, more than an order of magnitude slower than MOV. The lousy +performance of OUT -- true on the 386 as well -- has important implications +for graphics applications. + +String instructions are so slow on the 486 that you should check cycle times +before using any string instruction other than the always superior REP MOV's. +For example, LODSB takes five cycles on the 486, but MOV AL,[SI]/INC SI takes +only two cycles; likewise for STOSB and MOV [DI],AL/INC DI. Listing One +(page 73) uses LODSB/STOSB to copy a string, converting lowercase to +uppercase while copying; Listing Two (page 73) uses MOV/INC instead. Figure +3 summarizes the performance of the two routines on a variety of processors; +note the diminishing effectiveness of string instructions on the newer +processors. Think long and hard before using string instructions other than +REP MOVS on the 486. + +Optimization for the 486 is really a whole new ball game. When optimizing +across the 80x86 family, the 486 will generally be the least of your worries +because it is so much faster than the rest of the family; anything that runs +adequately on any other processor will look terrific on the 486. Still, the +future surely holds millions of 486s, so it wouldn't hurt to keep one eye on +the 486 as you optimize. + +String Instructions: Fading Stars + +On the 8088, string instructions are so far superior to other instructions +that it's worth going to great lengths to use them, but they lose much of +that status on newer processors. One of the best things about string +instructions on the 8088 is that they require little instruction fetching, +because they're 1-byte instructions and because of the REP prefix; however, +instruction fetching is less of a bottleneck on newer processors. String +instructions also have superior cycle times on the 8088, but that advantage +fades on the 286 and 386 as well. + +On the 286, string instructions (when they do exactly what you need) are +still clearly better than the alternatives. On the 386, however, some string +instructions are, even under ideal circumstances, the best choice only by a +whisker, if at all. For example, since Day One, clearing a buffer has been +done with REP STOS. That's certainly faster than the looping MOV/ADD +approach shown in Listing Three (page 73), but on the 386 and 486 it's no +faster than the unrolled loop MOV/ADD approach of Listing Four (page 73), as +shown in Figure 4. (Actually, in my tests REP STOS was a fraction of a cycle +slower on the 386, and fractionally faster on the 486.) REP STOS is much +easier to code and more compact, so it's still the approach of choice for +buffer clearing--but it's not necessarily fastest on a 486 or fast-memory +386. This again demonstrates just how unreliable the old optimization rules +are on the newer processors. + +The point is not that you shouldn't use string instructions on the 386. REP +MOVs is the best way to move data, and the other string instructions are +compact and usually faster, especially on uncached systems. However, on the +386 it's no longer worth going to the trouble of juggling registers and +reorganizing data structures to use string instructions. Furthermore, when +you truly need maximum performance on the 386, check out nonstring +instructions in unrolled loops. It goes against every lesson learned in a +decade of 8088 programming, but avoiding string instructions sometimes pays +on the 386. + +The Siren Song of Memory Accesses + +Finally, here's a rule that's constant from the 8088 to the 486: Use the +registers. Avoid memory. + +Don't be fooled by the much faster memory access times of the 286 and 386. +The effective address calculation time of the 8088 is mostly gone, so MOV +AX,[BX] takes only five cycles on the 286, and ADD [SI],DX takes only seven +on the 386. That's so much faster than the 17 and 29 cycles, respectively, +that they take on the 8088 that you might start thinking that memory is +pretty much interchangeable with registers. + +Think again. MOV AX,BX is still more than twice as fast as MOV AX,[BX] on +the 286, and ADD SI,DX is more than three times as fast as ADD [SI],DX on the +386. Memory operands can also reduce performance by slowing instruction +fetching. Memory is fast on the 286 and 386. Registers are faster. Use +them as heavily as possible. + +Don't Branch + +Here's another rule that stays the same across the 80x86 family: Don't +branch. Branching suffers on the 8088 from lengthy cycle counts and emptying +the prefetch queue. Emptying the prefetch queue is a lesser but nonetheless +real problem in the post-8088 world, and the cycle counts of branches are +still killers. As Figure 4 indicates, it pays to eliminate branches by +unrolling loops or using repeated string instructions. + +Modern-Day Instruction Fetching + +Instruction fetching is the bugbear of 8088 performance; the 8088 simply +can't fetch instruction bytes as quickly as it can execute them, thanks to +its undersized bus. Minimizing all memory accesses, including instruction +fetches, is paramount on the 8088. + +Instruction fetching is less of a problem nowadays. Figure 5 shows the +maximum rates at which various processors can fetch instruction bytes; +clearly, matters have improved considerably since the 8088, although +instructions also execute in fewer cycles on the newer processors. Fetching +problems can occur on any 80x86 processor, even the 486, but the only +processors other than the 8088 that face major instruction fetching problems +are the one-wait-state 286 and the 386SX, although uncached 386s may also +outrun memory. However, the problems here are different from and less +serious than with the 8088. + +Consider: An 8088 executes a register ADD in three cycles, but requires eight +cycles to fetch that instruction, a fetch/execute ratio of 2.67. A +one-wait-state 286 requires three cycles to fetch a register ADD and executes +it in two cycles, a ratio of 1.5. A 386SX can fetch a register ADD in two +cycles, matching the execution time nicely, and a cached 386 can fetch two +register ADDs in the two cycles it takes to execute just one. For +register-only code--the sort of code critical loops should contain--the 386 +generally runs flat out, and the 286 and 386SX usually (not always, but +usually) outrun memory by only a little at worst. Greater fetching problems +can arise when working with large instructions or instruction sequences that +access memory nonstop, but those are uncommon in critical code. This is a +welcome change from the 8088, where small, register-only instructions tend to +suffer most from inadequate instruction fetching. + +Also, uncached 386 systems often use memory architectures that provide +zero-wait-state performance when memory is accessed sequentially. In +register-only code, instruction fetches are the only memory accesses, so +fetching proceeds at full speed when the registers are used heavily. + +So, is instruction fetching a problem in the post-8088 world? Should +instructions be kept short? + +Yes. Smaller instructions can help considerably on the one-wait-state 286 +and on the 386SX. Not as much as on the 8088, but it's still worth the +trouble. Even a cached 386 can suffer from fetching problems, although +that's fairly uncommon. For example, when several MOV WORD PTR [MemVar],0 +instructions are executed in a row, as might happen when initializing memory +variables, performance tends to fall far below rated speed, as shown in +Figure 6. The particular problem with MOV WORD PTR [MemVar],0 is that it +executes in just two (386) or three (286) cycles, yet has both an addressing +displacement field and a constant field. This eats up memory bandwidth by +requiring more instruction fetching. It also accesses memory, eating up +still more bandwidth. We'll see this again, and worse, when we discuss +protected mode. + +Generally, though, post-8088 processors with fast memory systems and +full-width buses run most instructions at pretty near their official cycle +times; for these systems, optimization consists mostly of counting cycles. +Slower memory or constricted buses (as in the 386SX) require that memory +accesses (both instruction fetches and operand accesses) be minimized as +well. Fortunately, the same sort of code--register only--meets both +requirements. + +Use the registers. Avoid constants. Avoid displacements. Don't branch. +That's the big picture. Don't sweat the details. + +Alignment: The Easy Optimization + +The 286, 386SX, and 386 take twice as long to access memory words at odd +addresses as at even addresses. The 386 takes twice as long to access memory +dwords at addresses that aren't multiples of four as those that are. You +should use ALIGN 2 to word align all word-sized data, and ALIGN 4 to dword +align all data that's accessed as a dword operand, as in: + +ALIGN 4 MemVar dd ? : MOV EAX,[MemVar] + +Alignment also applies to code; you may want to word or dword align the +starts of procedures, labels that can only be reached by branching, and the +tops of loops. (Code alignment matters only at branch targets, because only +the first instruction fetch after a branch can suffer from nonalignment.) +Dword alignment of code is optimal, and will help on the 386 even in real +mode, but word alignment will produce nearly as much improvement as dword +alignment without wasting nearly as many bytes. + +Alignment improves performance on many 80x86 systems without hindering it on +any. Recommended. + +Protected Mode + +There are two sorts of protected mode, 16-bit and 32-bit. The primary +optimization characteristic of 16-bit protected mode (OS/2 1.X, Rational DOS +Extender) is that it takes an ungodly long time to load a segment register +(for example, MOV ES,AX takes 17 cycles on a 286) so load segment registers +as infrequently as possible in 16-bit protected mode. + +Optimizing for 32-bit protected mode (OS/2 2.0, SCO Unix, Phar Lap DOS +Extender) is another matter entirely. Typically, no segment loads are needed +because of the flat address space. However, 32-bit protected mode code can +be bulky, and that can slow instruction fetching. Constants and addressing +displacements can be as large as 4 bytes each, and an extra byte, the SIB +byte, is required whenever two 32-bit registers are used to address an +operand or scaled addressing is used. So, for example, MOV DWORD PTR +[MemVar],0 is a 10-byte instruction in 32-bit protected mode. The +instruction is supposed to execute in two cycles, but even a 386 needs four +to six cycles to fetch it, plus another two cycles to access memory; a few +such instructions in a row can empty the prefetch queue and slow performance +considerably. The slowdown occurs more quickly and is more acute on a 386SX, +which needs 14 cycles to perform the memory accesses for this nominally +2-cycle instruction. + +Code can get even larger when 32-bit instructions are executed in 16-bit +segments, adding prefix bytes. (Avoid prefix bytes if you can; they increase +instruction size and can cost cycles.) Figure 7 shows actual versus nominal +cycle times of multiple MOV DWORD PTR [EBX*4+MemVar],0 instructions running +in a 16-bit segment. Although cache type (write-back, write-through) and +main-memory write time also affect the performance of stores to memory, there +is clearly a significant penalty for using several large (in this case, +13-byte) instructions in a row. + +Fortunately, this is a worst case, easily avoided by keeping constants and +displacements out of critical loops. For example, you should replace: + +ADDLOOP: MOV DWORD PTR BaseTable[EDX+EBX],0 ADD EBX,4 DEC ECX JNZ ADDLOOP + +with: + +LEA EBX,BaseTable[EDX+EBX] SUB EAX,EAX ADDLOOP: MOV [EBX],EAX ADD EBX,4 +DEC ECX JNZ ADDLOOP + +Better yet, use REP STOSD or unroll the loop! + +Happily, register-only instructions are no larger in 32-bit protected mode +than otherwise and run at or near their rated speed in 32-bit protected mode +on all processors. All in all, in protected mode it's more important than +ever to avoid large constants and displacements and to use the registers as +much as possible. + +Conclusion + +Optimization across the 80x86 family isn't as precise as 8088 optimization, +and it's a lot less fun, with fewer nifty tricks and less spectacular +speed-ups. Still, familiarity with the basix 80x86 optimization rules can +give you a decided advantage over programmers still laboring under the +delusion that the 286, 386, and 486 are merely faster 8088s. + +References + +Abrash, Michael. Zen of Assembly Language. Glenview, Ill.: Scott, Foresman, +1990. + +Barrenechea, Mark. "Peak Performance: On to the 486." Programmer's Journal, +(November-December 1990). + +Paterson, Tim. "Assembly Language Tricks of the Trade." Dr. Dobb's Journal +(March 1990). + +Turbo Assembler Quick Reference Guide. Borland International, 1990. + +i486 Microprocessor Programmer's Reference Manual. Intel Corporation, 1989. + +80386 Programmer's Reference Manual. Intel Corporation, 1986. + +Microsystems Components Handbook: Microprocessors Volume I. Intel +Corporation, 1985. diff --git a/16/scrasm/CONSTANT.INC b/16/scrasm/CONSTANT.INC new file mode 100644 index 00000000..02ce404b --- /dev/null +++ b/16/scrasm/CONSTANT.INC @@ -0,0 +1,127 @@ +PEL_READ_REG EQU 03C7h ;Color register, read address +PEL_WRITE_REG EQU 03C8h ;Color register, write address +PEL_DATA_REG EQU 03C9h ;Color register, data port +SC_INDEX equ 03C4h ;Sequence Controller Index +CRTC_INDEX equ 03D4h ;CRT Controller Index +MISC_OUTPUT equ 03C2h ;Miscellaneous Output register +SCREEN_SEG equ 0a000h ;segment of display memory in mode X +INPUT_STATUS_1 equ 03DAh ;Input Status 1 register +ATC_INDEX equ 03C0h ;Attribute Controller +START_ADDRESS_HIGH equ 0Ch ;bitmap start address high byte +START_ADDRESS_LOW equ 0Dh ;bitmap start address low byte +GC_INDEX EQU 03CEh +BIT_MASK EQU 08h +MAP_MASK EQU 02h + +ALL_COPY_BITS EQU 00000h+BIT_MASK +ALL_DRAW_BITS EQU 0FF00h+BIT_MASK + +SQUARE_WIDTH EQU 16 +SQUARE_HEIGHT EQU 16 +SCREEN_WIDTH EQU 320 +SCREEN_HEIGHT EQU 240 +VIRTUAL_WIDTH EQU 352 +VIRTUAL_HEIGHT EQU 240 + +PAGE_0 EQU 0 +PAGE_1 EQU 05540h ;05470h ;5540h +PAGE_2 EQU 0AA80h ;0A8E0h ;AA80h + +SCROLL_SPEED EQU 1 ; Don't let it go above 8! +MAGIC_NUM EQU 100 + +CPU8086 EQU 0 +CPU80286 EQU 1 +CPU80386 EQU 2 +CPU80486 EQU 3 + +;====================================================================== +; Key Assignments +;====================================================================== +kESC EQU 2 +kONE EQU 4 +kTWO EQU 6 +kTHREE EQU 8 +kFOUR EQU 10 +kFIVE EQU 12 +kSIX EQU 14 +kSEVEN EQU 16 +kEIGHT EQU 18 +kNINE EQU 20 +kZERO EQU 22 +kMINUS EQU 24 +kEQUAL EQU 26 +kBACKSPACE EQU 28 +kTAB EQU 30 +kQ EQU 32 +kW EQU 34 +kE EQU 36 +kR EQU 38 +kT EQU 40 +kY EQU 42 +kU EQU 44 +kI EQU 46 +kO EQU 48 +kP EQU 50 +kL_BRACE EQU 52 +kR_BRACE EQU 54 +kENTER EQU 56 +kCTRL EQU 58 +kA EQU 60 +kS EQU 62 +kD EQU 64 +kF EQU 66 +kG EQU 68 +kH EQU 70 +kJ EQU 72 +kK EQU 74 +kL EQU 76 +kSEMICOLON EQU 78 +kQUOTE EQU 80 +kBACKQUOTE EQU 82 +kL_SHIFT EQU 84 +kBACKSLASH EQU 86 +kZ EQU 88 +kX EQU 90 +kC EQU 92 +kV EQU 94 +kB EQU 96 +kN EQU 98 +kM EQU 100 +kCOMMA EQU 102 +kPERIOD EQU 104 +kSLASH EQU 106 +kR_SHIFT EQU 108 +kGREY_STAR EQU 110 +kALT EQU 112 +kSPACE EQU 114 +kCAPSLOCK EQU 116 +kF1 EQU 118 +kF2 EQU 120 +kF3 EQU 122 +kF4 EQU 124 +kF5 EQU 126 +kF6 EQU 128 +kF7 EQU 130 +kF8 EQU 132 +kF9 EQU 134 +kF10 EQU 136 +kNUMLOCK EQU 138 +kSCRLLOCK EQU 140 +kHOME EQU 142 +kUP EQU 144 +kPAGE_UP EQU 146 +kGREY_MINUS EQU 148 +kLEFT EQU 150 +kPAD_FIVE EQU 152 +kRIGHT EQU 154 +kGREY_PLUS EQU 156 +kEND EQU 158 +kDOWN EQU 160 +kPAGE_DOWN EQU 162 +kINSERT EQU 164 +kDELETE EQU 166 + +kF11 EQU 174 +kF12 EQU 176 + \ No newline at end of file diff --git a/16/scrasm/DIAGONAL.MAP b/16/scrasm/DIAGONAL.MAP new file mode 100644 index 0000000000000000000000000000000000000000..1fb5529e33c171ad8bbb93d881bd8933412de427 GIT binary patch literal 65057 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/DIAGONAL.PAL b/16/scrasm/DIAGONAL.PAL new file mode 100644 index 0000000000000000000000000000000000000000..5dee1969fc3e9dfe5bee855460c512ba3a850e69 GIT binary patch literal 768 zcmWO4fugA}007W2rBcR}O4&6{OBqvI%Gm$^)qCd~4gg>dt%dE`E^_?PL#dC+Ix03v zg)<S7c29?d=>s=;JrU8Lq&#;GQ)M~QO6RqSZwB9WAV;TF@YMk&t+()|8fhN>SZXNw zlH!w9V<LvA?eWkd{q)VlorK*tP+md9L3x3+uyg9he?C5<Aj3`?!8id?X6=Z#r3kSw z;OVL+t|*qWvN{1(I~xa}_1u_+nQYxVqx4kccja2rjmU8whaB%&kWlA9V4eYzSf|K4 zW5iHc`f25o+AeOex&t9W+rr^xYvr1^KTW9DSpK5MB;_}wACiwW9vJR<(ACaUz=s5) zvl``HN5pk_F==54)y3af9hJzsHkCsxbX1!ipSG+=R0gD3Wu=?YWt3Yuh6vC60JzTF zh6@O6U^&3^AoA^S?WP-_U{r*-+D9Tu+Cw(vL=$RGY&!Fv)v^>#CCj>_H<jPVSZdsw z;AI@8;d=y=vUKPDBr+oW*6D|nkre~2dLp{4eI~;r(gK?XO;^9?uDsYy0ZR(#AIOg| z&TO2zLF_vbf;$Yhk%ba3$k2*}E=`w=SiFFBH4_5JcHRvOrR~u;dh$%~8@blaW-PIy zVVCb^oCtiVgPc2r!4m~%VzJCC6I4ZEjnf+<cfXKs)!O0(TLp$U&=WM;o_=m`eECJq z2bW{?KVsfzaYyiz1`p;44x1WWg~g?J=}@6UI;MY`98Hm#D%Bz$+ei(&PH&|_VhZYh R#ih%dB`qyNVV2L5_#e4jUwr@o literal 0 HcmV?d00001 diff --git a/16/scrasm/DIAGONAL.TIL b/16/scrasm/DIAGONAL.TIL new file mode 100644 index 0000000000000000000000000000000000000000..95eee9f2380ee2728299c37abc96e010bb2187eb GIT binary patch literal 65536 zcmY+90}usKvO{<O+O}=mwr$(CZQHhO+qP}n|D5FZR87B^zKtZ+^S}Qc-~jvqzg5#6 zuwY??;Ou~aNN%b&Q+Renj1H*mfWZOLrmB2wU^;E2Xt(6E;l&FJFKAHU=wh$;)QvRc zz7lgqzCpDn#Q}Mzr>6VAB8^Mn?Ee6f+>}*@Bn^!i|DUq|3;qvns>;U(rqf1>c1u1R zUc9jIf(8YSF7|p)-AF_3D=}B(8&qpj{2%Z1)N}_b(zpc94g`qgrmQj~X=udwK*|mj z90+Zy%Etz#(?*JROFkQ3ys+?s1_h2T_Igj<NJH)`F<0apRBKWkh<AEwx&s$!TmokY z21IgGRvD5sG-7;UWd{xpj5bx}V*}G^BSpI<pA9cwSa?B$0!J5ny{B%ZA@`M-EAkDh zH7O3vJ3TesL5egkfwO}EBDpE63`rUqF+Pa0g9Habo2v4$f$6l7qTQ0uh8Hg^yr4mW zql>-XQ#aC(`%26e`3BXR6bIp*o|^8UMH-jD*+Bu3+>}*@Bn^!iA5_^vgM*??Rr%P! zblOPKZpmlEix(DN(4fH4#a{2J8)?XWCFY8JgKABRgYr&KO?R*&jZ5I{V1P(&$|^&W zhDMAJrtDzB!O*6vd~9GkZKP<o<g?+$3kxr3P~hldulLlAG~~V#b49*EwI;>Ec&DeP zJ9v@CC2)3dKqNP1l_5z(BgO|;cJScfXj4@_HZYwwQnXw0+3@0pg%>m^aCEWPd+J6S za$kwLBHy4|lj7jK(^JzOqDbQsI6DL&lAE&1kffmz<3lJrL~sbSsVW~Em`)oh+AaBP zc=5u*3mOzSy4dSIbt4VAuf$xDZ&0mCaR}b&sp$?`q;UzH9TE`9O<83~($I+UA(b66 zI3(Ism5𝔚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𝔚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𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(H 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𝔚QZtmV7q6cwylM4GJ7x?Dd|y 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𝔚QZtmV7q6cwylM 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𝔚QZt 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𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe(TB=7Xpbe}5HxCG8V1&HLP ztTH5NXvFwa%03l*3T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dvSL7R1Yf^lQ zcY12NPZw!i0%xBFL~>JB8Im+KV*F`kpAJ5aHdW<g1Jh|EMY|=R4KH3;ctL{#M;Cj& zr*5Pn_m!9{@(rprDL&0RJvH5DiZm{Pv(Eq`xhbm*Ng5h4{*1EE1fM~hs`9ac>9moe z-IC9S7cVTlph1D7i@n}cH`0*%O3W4c2GyDrpW&UJn(nhj8kfM?X91DilvRc#4UHIo zR@rBR&!SCL`Pjg8+DOrE$!Eih7ZzU7puo|^Uhk<JX~=yg=8AlSYE6pI@=i}p_qigC zOW^EtfJko2DnpWnMvOnF>~q2A(59+<Y+yQVq-eL~v*E=H3omF;;OJtn_tcFv<h~Mf zMZQ6`CdKD?r>Ca-e38Z_aQ1mXBsXQ1AxT3c#-CUA`QY<tQ&m1TFr7A1v|IAo@ZyDq z7c?kvbg|ca>P8xJUx~RQ-=JEP;`6-IQ`3E+NaGSX`vM@6o3hG~q@fYxFDUy$@CCG~ zDjyq|P8%uOE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0Sv1>WhY>AqN`aS5D#5fI5u zS!GDl(1`IDm3=YzBHC1yj}1(xjTG&cd^WszVc`W03LIVR^`5$shTK<TuE;m2)};6% z@ATAkUn<hL1kSz$h~%cMG9+ne#Q00fz7%{3ZK}%02By<Sigrsr8(zGy@PY;fjxP3k zPu)mE?kh1@<Qr6LQhbSbdTP2a7inAqXI}<Ha#L0rk~B18{AFcd4!(>wRpny?(`h3` zyCt6uFJ4%9L4yKE7kj;@Zlodim6$8?4XQOMzRWv4HQiT=G%kU&uK*&sDXR=g8X7VF zin6Z+UqPFy^09&Gw2`9SlFx=0FD$&EL4l)-z1~wd(vbT~%oX_t)tVGv;hmnE?yE%_ zm%!Oq0g>F4RfZ%DjTnDb*;j+FqD@u#*uZq!NYQS|XTysZ7GBVxz|qBC@2MMU$bBW| zihP4=O^UDbPESquwIYp6;OuLFNN&n1Lz0F@jK8MrYr)shrmB2wU^;E2Xt(6E;l&FJ zFKAHU=wh$;)QvRcz7lgqzCpDn#n*VJr>6UQk;Wx(_H{rcH)WL}Nkb#XUsv|^;Ol5p zRX#Q_oi<XmTk_fP;)R75G$?R%vDbU*MjCQoiMb-*pjwmS>%7xb(|w~z;}SUg1|X7~ zvdWO8p%LS6DEmh64Ya8$9~+oX8!6f?`D}Rc!omw06gaxr>pgWN4Y{wxT#;{3tx53> z-s!37zFDMk37mZs5XnthWk}M{i19a-eKYtb+EkT~4NRwv6z!ILHoSOY;ROu}99``7 zp1P5S+*e|*$Tz6gr1&Q9^wf0UD$=+F&b|eR<fg1LBxz{G_*=@p6?_YAs>;U(rqf1> zc1u1RUc9jIf(8YSF7|p)-AF_3D=}B(8&qpje2aH_YPxS1X<Pzl-v&f-Q&t(0G&ExT zZDrpMzKu3j<zoZWX(L6uC7%s1URZcRg91kvd%dS_q#^f}m@D!Psx>LT%{x6c-FJ#K zE`hV}03x|5s|-mR8ZrKkvhM`nL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP-cvWyko!u^ z75N6$niSvRot~QRyG0t8z}a^Jk=&G3h9nJ*7=KsUcZ2VuO;!2Wz;xP3(Qe6S!;2Rd zUeKVx(ZycxsT*m?eI@3Ke1mFDitqAHPfho|B8^Mn?0bMnZptb{l7>c%zo+bb!S~Rn zs(fr<I&GwAx8$?o#S05BXi(tjVz2kqjWp!G5_3hqLA55u_jsqLru%-8#wBp}eLy5P zWtAaGLnFrDSN8qj`)E^DJ~l9&Hd3@(^4aj>g@qS1C~$PK*L&(l8ggHWxgy`7T9e}Y zywg+D{h&zW5;*$-Ad;K1%8;a?5#t{y`$6ynw5ci|8<<WTDcUXhY<Tg)!V4M{IJ(&D zJ#`}uxv#`rk#A6~N$~^T>8a^{Sfp_Yoc$0G$xT^hNYc=V@eh^#F!&+bRF#hnOs9<$ z?UsBtym(>Z1q})uUF`Lqx{-$5S7NTnH>lR6_#yA~)O0^8(zpc9eguf*rmQj~X=udw zN6LN_{0MET%Etz#(?*JROFkQ3ys+?s1_h2T_Igj<NJH)`F<0apRBKZFh<AEwx*r#5 zTmol521IgGRvD5sG-CW?Wj_vnj5bx}V*}G^BSpI<pA9cwSa?B$0!J5ny{B%ZA@`M- zEAkDhH7S0~J3TesPl_}yfwP|gBDpE63`rUqG5(3Np9DWao2v4$f$6l7qTQ0uh8Hg^ zyr4mWql>-XQ#aC(`%26e`3BXR6hGmeo|^8bMH-jD*-rtH+>}*@Bn^!i|5VvegP)>J zRr%P!blOPKZpmlEix(DN(4fH4#a{2J8)?XWCFY8JgKABRpYl#mP4}}RjZ5I{XMjj< z$|^&WhDMBkrtD|I&(Nl-d~9GkZKP<o<g?+$3kxr3P~hldulLlAG~~V#b49*EwI;>S zc&DeP`+1SZC2;n0KqNP1l_5z(BgQ{h_VeK9Xj4@_HZYwwQnXw0+3@0pg%>m^aCEWP zd+J6Sa$kwLBHy4|lj7&R(^J#^qDbQsIQs=4lAE&1kffmz<6kKIMeqx>sVW~Em`)oh z+AaBPc=5u*3mOzSy4dSIbt4VAuf$xDZ&0mC@eAJRsp)=Mq;UzH{Spw#O<83~($I+U zFO~f=_$As@m5𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe(TCGYgqbiXRn zxCG9A1&HLPtTH5NXvFwe%6=963T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dv zSL7R1Yf}7*cY12NUl(ay0%yMlL~>JB8Im+KV*G1mzYczlHdW<g1Jh|EMY|=R4KH3; zctL{#M;Cj&r*5Pn_m!9{@(rprDSpj6JvH5LiZm{Pv)=$Bxhbm*Ng5h4{*AKV1iwL> zs`9ac>9moe-IC9S7cVTlph1D7i@n}cH`0*%O3W4c2GyDrzu}#pn(ntn8kfM?Zvm0q zlvRc#4UHK8R@rZZ-=a-b`Pjg8+DOrE$!Eih7ZzU7puo|^Uhk<JX~=yg=8AlSYE6pY z@=i}p_q!sEOW^ExfJko2DnpWnMvQ-_?03QM(59+<Y+yQVq-eL~v*E=H3omF;;OJtn z_tcFv<h~MfMZQ6`CdKb~r>Ca-eUZi`aQ1sZBsXQ1AxT3c#=lqg`{4IzQ&m1TFr7A1 zv|IAo@ZyDq7c?kvbg|ca>P8xJUx~RQ-=JEP;`hAMQ`7ySNaGSX`vV}7o3hG~q@fYx zKPdY{@CUT1Djyq|P8%uOE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0Sv2j1za>Hb)x zaS5FL5fI5uS!GDl(1`ILmHjdJBidAzj}1(xjTG&cd^WszVc`W03LIVR^`5$shTK<T zuE;m2)};6&@ATAke=5?r1kU~hh~%cMG9+ne#Q0Cj{uKNPZK}%02By<Sigrsr8(zGy z@PY;fjxP3kPu)mE?kh1@<Qr6LQv8W`dTP2q7inAqXMYAna#L0rk~B18{AXo<4*rZb zRpny?(`h3`yCt6uFJ4%9L4yKE7kj;@Zlodim6$8?4XQOM{>(c)HQir|G%kU&zW^e+ zDXR=g8X7VFi?Y82e?gn7^09&Gw2`9SlFx=0FD$&EL4l)-z1~wd(vbT~%oX_t)tVH4 z;hmnE?yp4}m%!Oy0g>F4RfZ%DjTrw`*<XXdqD@u#*uZq!NYQS|XTysZ7GBVxz|qBC z@2MMU$bBW|ihP4=O^UzrPESquw<3*8;OuXJNN&n1Lz0F@jQ^(WZ^7TtrmB2wU^;E2 zXt(6E;l&FJFKAHU=wh$;)QvRcz7lgqzCpDn#ou_Rr>6URk;Wx(_IE%eH)WL}Nkb#X ze^>VR;O}TtRX#Q_oi<XmTk_fP;)R75G$?R%vDbU*MjCQoiMb-*pjwmS@4VAf)BU4J z;}SUg2OyH0vdWO8p%LSMDEmk7545Q&9~+oX8!6f?`D}Rc!omw06gaxr>pgWN4Y{wx zT#;{3tx53@-s!37{#m4P37q{C5XnthWk}M{i19y_{WJI{+EkT~4NRwv6z!ILHoSOY z;ROu}99``7p1P5S+*e|*$Tz6gr1&TA^wf0!D$=+F&i)06<fg1LBxz{G_+QHY75ocr zs>;U(rqf1>c1u1RUc9jIf(8YSF7|p)-AF_3D=}B(8&qpj{EK&bYPx?HX<Pzl{{}>I zQ&t(0G&ExTZ)N`u{*5+O<zoZWX(L6uC7%s1URZcRg91kvd%dS_q#^f}m@D!Psx>M8 z%{x6c-G7QSE`hWE03x|5s|-mR8ZrKlvi}7CL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP z-cvWyko!u^75N6$niT)xot~QRzeO6Cz}bHRk=&G3h9nJ*82?w<e}n&`O;!2Wz;xP3 z(Qe6S!;2RdUeKVx(ZycxsT*m?eI@3Ke1mFDivRLXPfho~B8^Mn?0<krZptb{l7>c% z|EKJK!T->vs(fr<I&GwAx8$?o#S05BXi(tjVz2kqjWp!G5_3hqLA55u|9GdTraM59 z#wBoe06-)+WtAaGLnFoqP<DXe0BBQHJ~l9&Hd3@(^4aj>g@qS1C~$PK*L&(l8ggHW Mxgy`7T9X6(KVmnBasU7T literal 0 HcmV?d00001 diff --git a/16/scrasm/GENMAP.C b/16/scrasm/GENMAP.C new file mode 100644 index 00000000..01652048 --- /dev/null +++ b/16/scrasm/GENMAP.C @@ -0,0 +1,99 @@ +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdlib.h> + +#define WIDTH 255 + +#define MAPNAME "Diagonal" +#define FILENAME "%s.MAP" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef BYTE ROW[WIDTH]; + +ROW r; + +#define MAGIC_NUM 100 +#define SQUARE_WIDTH 16 +#define SQUARE_HEIGHT 16 +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 200 +#define VIRTUAL_WIDTH 352 +#define VIRTUAL_HEIGHT 240 +typedef struct MAPHEADER { + BYTE name[12]; /* 12 Includes [n]=0 and [n+1]=26 */ + WORD width; /* 2 */ + WORD height; /* 2 */ + WORD extent; /* 2 */ + WORD off_x1; /* 2 */ + WORD off_y1; /* 2 */ + WORD off_x2; /* 2 */ + WORD off_y2; /* 2 */ + WORD x_wrap; /* 2 */ + WORD y_wrap; /* 2 */ + WORD magic; /* 2 */ + } MAPHEADER, far *LPMAPHEADER; +MAPHEADER mh; + +void main(int argc, char *argv[]) + { + FILE *fp; + int i,j; + BYTE b; + int width = WIDTH; + int height = WIDTH; + + if (argc > 1) { + width = atoi(argv[1]); + if (width > WIDTH) + width = WIDTH; + printf("Width = %d\n",width); + height=width; + if (argc > 2) { + height = atoi(argv[2]); + if (height > WIDTH) + height = WIDTH; + printf("Height = %d\n",height); + } + } + + sprintf(fn,FILENAME,MAPNAME); + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + + memset(&mh, 0xFF, sizeof(MAPHEADER)); /* Will reveal missing initializing */ + strcpy((char *)mh.name,MAPNAME); + mh.name[8]=0; + mh.name[9]=26; /* Ctrl-Z */ + mh.width = (WORD)width; + mh.height = (WORD)height; + mh.extent = (WORD)((WORD)width * (WORD)height); + mh.off_x1 = (WORD)0; + mh.off_y1 = (WORD)0; + mh.off_x2 = (WORD)(((VIRTUAL_WIDTH / SQUARE_WIDTH) - 1) % width); + mh.off_y2 = (WORD)((((VIRTUAL_HEIGHT / SQUARE_HEIGHT) - 1) % height) * width); + mh.x_wrap = (WORD)width; + mh.y_wrap = (WORD)height; + mh.magic = MAGIC_NUM; + fwrite(&mh, 1, sizeof(MAPHEADER), fp); + + for (i = 0; i<width; i++) { + b = (BYTE)(i%width); + for (j = 0; j<width; j++) { + r[j] = b; + b = (BYTE)(((int)b+1) % width); + } + r[0]=1; + if (i == 0) r[0]=0; + fwrite(r, width,1, fp); + printf("Map row %d\r",i); + } + fclose(fp); + printf("All done! \n"); + exit(0); + } + \ No newline at end of file diff --git a/16/scrasm/GENMAP.EXE b/16/scrasm/GENMAP.EXE new file mode 100644 index 0000000000000000000000000000000000000000..258ec9f10f79802f2e19e884e9ec945c534c1675 GIT binary patch literal 18664 zcmeHveRx#Wwf8<Bb7nI6VEBrN7=};L01X6FDFGoQ6Ho|&;3P=O5b^=he0Anbf);UT zd`gl7n5#a$*z413r7cplv@f?eh!+B(30SFszM6_v1lpc)s6|YZ5W}4JxAvJyqVfLm z{_%c1@AHmbbN2b|wb$Nz?X}ikdr#=fhv%?S%)*@PS!NiCBC|2(5E)Bij0r3WrN4q? z39sy^kS??eRQms)|5r8ekan#lf$5F1JHNx#Wv~ucpTX+4%fgdVu#{;V6r)bm|Dx2N z5*uAzJGO%Z6&A3eWYl)GWUySl0M)YQ>S}cLp`{3hWV5BL|H^FHw_`iRMp~j|)b_RH zpk)%ZY+288TS`EOfNTe%v^*Ml(`D2*x^C2Ozrj=~IF1odOBML8TBxOfk}P3xEl%JD zC}7Feo4E`v^43k9?Mj1%wJVL5@fhdJyDXZk@8v!C?$UDldV()ETRN0yER1z1&*8ge zEPK9Zdsk!Pk1Ws)ihbJ2o~o{w_fmtGf6N=dfEGWolwc+|c;6Ta@B0Ca*w*3dXDp~P z&DBqW8r<C-u3jKXP)l!<tGi)mK*nR5!7Kvr3LN#WUIF6gyLz9Hg6|vcN<bFsxA)Vu zY2*Q!cZF`igs$XV{bNkrX4Lk#JO?ejOPZ>8^_w#KA!CPuvFWEp($0(E_$@fZ7KYLV z0VU4{?JwVLV~11DPD&Sjmef`y_YcS45VSOrCHL$IGly3?#vFZn-rsTRCzdaLj>L(2 z8Mt!wi`Eun#o0+|FBb?}`)}lTE-g!Yd7N-`ypXo*w)(5#w8qVHOW4T8)82EA9ty~o z);N8PAoVmt{I0g-k9sa1egHCdCAoz}YyWYteB?z-^4qDcUmQrBs3mx%E242;KdtBs zEUACjb6Mg<BW<f-q}75{L0^6=SC1FkX1^p$dpcVrEL)<`Ddo=Ak^o%%@mf1$`Vm>5 zW8JYxmEL>LuN34OiCZNy5F;^BctdDm_nw{9n3N&xQZj{vi7jl}>u-r?CnZj-U-Scs zsdIKEJSFW)*d^^z+`@D%Z6<r^hmw}qAf;Y3l71lhq~Q1Emzsd=l8#D@Ad@j+CcCm| z&xurHdSD?_=N*Y>$L0xN{6dXAVmz7JdgC?!q|jfKB<n=2=lDk9H}b)mOT6(HE<Hm} zi~Zz*&}WGgkIF3Y%Z<YE7M6K-lGomSGN4)lPj3_!Kls?+j_r|-?~(K~EK>LlJJu{6 zZ<h4`U~TZ@)H9*+cpMQ}XcV6A{3A>V+02q4G|b*9thS%=-*xP9`S|0quChqsaV`#0 zHnE7hWFzr$DI$7hw2wTd?~-C$)sY4EtGWJII6CuNI$W~BbO!_Gw`wl=Fbu=9;k#`b z^moO2ROGrz`h8*sG(PR@q={_{dVKa(tF-tl-NyOQ4SG$e|A(wuVzWf`hH+=;vo^L) z`!KoFYhRGmBzR@*it)+n)YjnSFvCRZuO;NWj~fPh(ynWr-Py`w)z+S^u;A0IxjR#- z_rvU&TYt$01J`=Bk9LHf6SST8A$En``h1E-O_|nvuIB3BPe3`gb=&It?O~?owCoac zcf+srGjI)gx2qd5C$PP%P<6EIiPZdZ1ZqN(k#nQP4l}B~Vbq58=?+9I-mnBE2vj8u zuRT*?TE_+tIT)#5zZkDwkL~uueL^Ff-9|0ERxxU2{X9aGjr(CU_~2X-{ER_O39G+` zz^u8Ho-&(u`br_@p>2@0TKn;NqSij^IYH{hwB!7iZi}E=v@9_swJ^-KAE?bl=V+NU zu6q`os1>ynxp}K|^Ne|VBW9zlTVIfT`tD3o>J%`uU=xcy<8Kf77UcAMU4sJR^H#g{ zRn~{st&eT>yHhV{Cwgl8wG+uFxvbPyXf#)UFrLeMxW3m=XD6RtaMC|R>J0rFwN^CG z)&GoGC9hjg)uWd#$3P)VSd4*&w7?3*c_mJBg_BRDUg)V+LXzgPMWU0bfqeI|7X-I{ z7TUt9?sh5Alic!xkgFfGqFYFzmwf$B+D#C12Q;s}uYIJ|Dq46~=bqNo)+2^-<F%gi z+ICs%*e|H!zUAkGU;KRZnJ@NfUub>bZ3{{Xrj?2L?sjFXoB=y~xmG^rl^f*_MU{;w zce`w~Mp}C=f(yFVdW{5C-kP8#d1XWK%I#JbifwjNm<%ECqMspSp+QjJA8R?bD`T5n zO4FsD4uPrS0UF1zFpdLS-?NCxm~~4(;`H~#`bEuPfIl`16ufkgNQTiOvf#)s-KpJ2 zGT7X!{Rih>y8LCJ>mfB>KV|SO@jelc4Q)>=&j>FS2(Jq)T~zPpA!?5@lkHNr38}5m zA7O!1=;Jm2m)Y5kiyjxE+Btt*V8?c_JqXPQ)1B&<=`m_gdc0a~Z&e@7&LKz#bQMq` zpn~+t>eTc?RmuomO+B;ZAc}o}Wa)h99qq*V;OO)F1^=5N0S)8TWHh)7wXd5E5V5|} z;Nn1o3!#5aoY=TX6{PpG&;Lz&KO=BCoP1e3^>VGCbxL0*TGJZuU%K@7X^#sB57=A% zeQ7jW3_2vGwjLNd>TT$8D`(~-{{$odGX}B=@CFRzE*i*zuZ&zdRQSb#(D_4!Sd#-j z<<R5<q2Ket&qkYj(B?nPHbVz*w)s<}&5x+fSqvm`VuzJ6WBM}!Ry4`nB9dmZJ#DG2 zsokjt6drp~O_&~7gyd3HZoKAt&EKbWES?&6Y2ovKJrcw8330hvyPg>L@>YTG8*gi! zsokFCSEg%n+5%;s;CHNc=O3RZ98uU8zw~Tar&^|yVoar6{$P6Jh>4~>x$~2(np-}$ zS9*29N!79VM{3-^MjS%x359;d{q3Ykrk78V=??~ChVvP%Z@_DoBbpEH54F<a#R&DV zMl|{ZHA9%HRhlxD{XbB*>|g9J>Bz)60$vuo-=XGfE9Azwso^+r>OUGX;g381@tm-u zW1g6Lv8m9y-{xPjU-l;<hWVH72)`hxaXZ5M1XbA)J}mgBcJIXQr{0NeZTEJ0b$*`y zF`~OdyWFA{!=UI9D$H~1PsFZYPeDt4Pm9ym%E@nLG>*|85+7(>D_(J~UTvsyp8j)c zxlY?ALlq5U7o6}PLx6J0p$Vz2)QeNSdPHQab93|b@5LfAr?zURL+5EfqxosIGEJ{u zy?wt;9SeE7J7Ha*MCnOwZOlZ3Xv`E%&iZR{`R*6jN)4`lWYdgN;U??eg>_6_TW6bD zq!!E^sVdmhdRTL6ce^VrAUPD6;ZndDxSwGUYeWX#ON9WVmMT-z>l`za)u}VTtu6|m zR$Vh=)wMjO44rO1CP)w>hK@8JixEOy%{}cR^Ixw2qgemfFe(C}pZB!0R{yyje`Je8 z&-3yrlmnsN_1pWHzXf9ySRki=aq#;FM}A=<W&Ov4<wnas0TIuJO-t54vO_72uI|`Y zq?Zc~Ls^4RZP$9S4_W5X`Jf5g)5i_jm|UZ!F^f{%hAeB7t6$sD)nEmfB{pUcjfrG4 z^3nH1zUZTlcA|iFk2(4Q3RwDOgNA~Yjq~3}7Lux2VVZYvm6MH$9a;E-8HnwckqCRC zF?rYmbM+76)?>p`<wk4hoz&LoB9f5~k!o?MQ@9P9Ms}N9FJlFi+Ng1<tqquiNb4$7 zYi{E_>w#V5>Tj^nw@D{y%-r`au*J|cOlQYuFzxnvVz<0l9gEGnDVrx8H83b~p}_um zM=Rg(VNvzhu+OAMlbNPfigrHmi4?dg`m?%E+WfJUymarJCkpDlnw$(1bA@ADx8I!$ z(~D#={~bG`vcMJg$3s5>H38OmD`aaXpP(#>tdhH7bQ@~syMw^9Mc(_d=Y&+FaeFwF z#Ah}ZVnlU>TOVa$w2LXf3mZm#yKR2jyP|hIcm)4@;Hg*7x%JP&#G`(a9r~!5*I;F7 z?+)`V4`HGCLc*UDK2Ml7V)cl1BYrUA@CeMgWsIob+3n7UF}QjgTwh{24mQ>*4X!Yv zt3p=)grd26gFlmxekjg#rWe#%-k&-mBpzbFkuF>kU0=Q*K5;=u!@XMP`75)HUsfbE zxx)ws`V=|zTatPm2HNQQ3`xN<SY+rYu*vjUegy_DhyEo!nU{pn&UB~W3QP=cGt#H< zVj%cE1Bfm7h|!c24&1!QKSFmS<9+P5o=)C+L?D<l_wSmk`>37uT#-(oqu?R~Ct;lI z(xPqR^vTp_44Ff;LDxWou3)@D1FGP|aD*nOyLibN8ke3!rCW|rLi!3`l0!1yZNZCS zYEj~sf_sGYay)hl>3%$(64DFss29?=;_(9^y&8`fg!E!{e7X-iTa~&xy++-bo~2sT zvvG<%%7XvS^ryt#$FAK<v>sRmr3FKRzEg}f{G)cYA|Z=QvL3%z(h?R(!3#pZmeX~` zI+so@!m4%2H+Q}r{7*q&Ct`Je)$QtcsMu<M6<icXImK_$XNsZu`nSYx*R65>ly;Y4 zJ>p=A)-|aYb|34ybxdaZPemZRkNx9TLFxs1e_Cw+;q_bJ!7djXH^5Kq|KRL3;t?6_ z*KP%~1;h0j7GN>d5a-;hU9aEX#hx6kTA_J`h3xgco5@hSus?v^sQnDr5^ii_HjG79 z?MC88sorI?hipcon@ZRN>=-oMg#`I+`9@+PT_MzmH~UBQpu)r+CM?m4liV!7B^xV2 z2~z$ccH^~(Hh#^6X1lA;9=ew%5R&nI7neM;!*yL`?XDXszg;c5jRyA@V8hDtN?KJB z?-(DnXwmyvC_(=_!`ot2dOjqkUf{(Mu@|0*rEYsV>o2gL4`{GY(3}zC<Um<}kJcIc z0Zsfm!^Rj&v^M4R!8&WZ^m_%&TvQXTC>VT-s;rvcZb?}ZGJBYVI&8`q+blGNEGK$1 zfn*aH0YFq^z~STo3_kfpvg`U2BJK$CSEDu#XT8(Eb?Uf_Nwn_XenZQ-uK$n~pvI=g z<6GwSDS9(o=fT<FQC=mhW~1-3U`)SOYkRe^*49Q(?cA%+P#F!Ks!b0WdroS-ZTdw+ z>xE59ds^F)tZjSq5lW3!;#RwMzhP~_Ny^ivtX`9stJn7+&whBF6-NtyFciFUht?zH z^ycFXeo#Mc#P(k9i8VYb^wet@ZC7qL>zYpL2fto-EC1Qp?kDZB7yU}?1-}>?{|t^J zpFi94`7=A;kyFy=*Gi(xIG~-(33aYZemlFrEpkS|>4c(aNNyeoloTTUpVKig6}f@P z_p0_xtD%J{5>qyT*(^xfAb6D)7IQNcdw3BJ`<8a(AS}2-<a>iH%3>v!;Dh4O<jc%f zVq3(F)HB+7wEdWnfLf)wktd>4R~P}XKi{qOX*U|ndg;V*-yu7E`2pM%E!@v)U5NkM zhp#hn;SA9yy&hmluiw@B60Kl8m~L0&7JRARe&BMKKAD9cITXL(OTVPw#ts~^8#uFF z(c@U?@&-?6LrcG*ue^?vp!Rn1n^#7y#-J%NT<47!T;T<$>*$QB^|k#Ji36Rq{S$xU zlMly)lFa=!mS;TU{Zelz?q&;{5JKz^CnH}d>)qf9;(jT|h9jv(I}uzVU}hwlH@^zQ zxMYg3Yaaye=MvuL63);*P3OMIX)BVy?)Dqnb|rGeK`;yBXxGzDhp(?60(lBd$sUeK zsTT*%61nNKR2ka`&P4O;CeBRp-f{lQ`3u?~v_5(gNq-vszC^wn`mi8<*0X+V#Bn!x z%=|I`ztMcqZ|a5mn|8nOJO&gzE`4RZNKWW*O3Rh-O(#^En_E7-<m{y2G{*9j)km1T zGoeOWovVK;t$$jnk=E_{09lV@UEc<+UAxA-W0A$;%;@XQ)yK1fxmWp%RZn2pp`NFg zxmR^$1V1YjaECKFu&6+gym9H1eR1hduYAZ7Qqo7)iibuYT_nA~_vKunt?5*#hsLb` zw&%s20(Nal-!Bhj$UOD(NbAh2mmO{M=<XpF35l&E8);f74n-M71nX>p=T;qbPKe}J zxb28qy#-bunp3~10@rb?dR#UZP?yzjw=;D-S$vC-0i%Dg$7M&Zn;^NA(QeygGg?^U z%}`pSn`|FEB6uQI@mfw;bN9C}K%q{U5;WZ8vL7ZX7P@b{75p@E!z9l&OeIK7+p${q zMwg9WqG4=vjfU+o97Q|bjtkybSitXig)R15yOl?!fFI$%KY-PlD%m>@FNCFzs_zy3 zF+C@kfZg|}>}GIh_*w15G-g@IEdCgB`4%=Zq_-m=^V>eU>%->IzZj7aTS4$0+#f5i zFj1ZG3X~9&dWP&j_@9hgqMsJF6q6|ha{wFvFW4(kg%tb=gONuj-}9&4ZsYL%XD49| z#s;<<<FUW}DN<)j<GSQZ*^FT@Xhq-08gsBUg$)?6OCgzoPoO*ba5|<W1>0^tJG3%| z27{{%Od7dAxG-_=2Vl7+_{U(`;9>EBGjLwq)nmBc<1{z_!szg|6LZhhU&2+)Zye~% z##AYA#>oSt-PF&xU`N=V(+?31xCGVOxWS$YefZKEq37I`6RBtRWAdnNTlZ3vu;7$W zNj}xnX?%i<wm#S>;$N*C+r3ShpSD4GGOk0(6=KNlLut)?jq73qi`EHAKKOcQO7~M6 z1wkF@)^E}EI5r<cjc;63D44A%pN?GSG;29_x`BihZMWfE-Ty4SU^Mx3LhOad?1yF@ z=()(ZY^?`d2y`!gWg8LYyReJIw)rnNSXLeUp`{_y*qtdX=<wbs7`*jz!w-&)7v>i# zzW4_p42(d@Rx33Ynzx0R8jemma{W!cZWM0b^#Z{+NuR>J7ClGs-Im%qU#XJR1e{Nd z#45^T5HHU?&rdO{^Sj}FYO#KSVK<TyWTfQN%a<(C>Yylfh4e>XOls@v*NrPFq5F~j zyi_ACWKK2lbrx7~&a0gN)ZZJLT;FH&-g*AAc5<0^PCDU3UeI%4%E>kQZ1%7(zP|6e zYH4v`f4CXCLpzt8FXPPD_@qs%vp>){CPTW>A%~5|I=g3Gn|2Okk<}3op!1vs@6}r7 z=ZAf18F{OBeYA&uS<wBs&2(@cyVS1XiYK{kPn*_BKOL-F?{#P=d7b<~V}7_dB;0Jv z*XnEw>g;|=t5aUB?+vRqEj%?WT@T&BopX<;jbX2TgZAnX&2Ig*AQZD$6|y7Sw(lC> zoaxq;cCjt+wKIKe39LV_A96L19Sx^wZR>HNm63-YG>>h;M{3%Gfa98XuMIDF$M=bJ z-8<z~DD}D)Ubf(bZwlT=Bf$akk#w@YRn&SKGsB^)TI+f(TWQR;-3;BnzHvoZjgf99 zpIFvtNxmuFBxSYl`k=Rsesg@|zxe%iWu9}5ziQUn^2$=@it<g~BJX3)S<a=^HII4A zH*Zm$Gm7ta&Y3@d?o8*(@?vkbuewY{t+!@8%P%icw>TF%r<K^*vQo}$zGRjcZLY2= zs$kQ6vsW(3Wp$g_(rSN2N!4Adv%03V$~n#FEUWf9>%8S^>1;b2;9pr(<MdY7L1H{x zQc>Y7sje!W<irQR!$f4!RQ?x!KIXqy<EOiC{CJjnT+3Hvd6wt6RxSKSjwm>W?bxwH z_-2)F$L~f_KHTaVFDiwsa1g++=jI1{8~=#nO6+Va#i#h#7!&0P!~aE(=$QY{4rwOz zL?4Czhaowbq%cKv$XQug7W&+q!g7hh=}gHju-aHkN=kk%u2!8+LYZwN|1eflvlSm3 zIGB~$Y<Sq{?;C70s{9odcSAf&6vc7zF>!HmR$F4CA;ymq4U%xmI`lt620l(I{XwMv z2C#vGD=|GiXJuaYB3$9FNyD(>?X#RdwW#<}XLW6<x2&SNF5b>0UYAOB<yC6w=2EY- zq`bDgq|~|TF(;a^7|t-C7^<pOXK7WnfAbcnucoNDlzUuhRc*Pqx~j6YN(Fa6!<WIl zaDSEDztro6S2B?cnM*>@Z;@JFwRu)eH9B<q{53VzUX{y6O-X491PGjc4(}7%adK9S ztjOmp-yH4AFpQjx6#VbL!&A&j3v8*Iti}N{P_S<<t*R`lnO(i<5g;POM(UxhZXj_b z)xN@FubMKu$XAJX;t?Y}3OwWAAS0?+dX9+lmlUaHlR=q3g9qIP9((bYM}6v}5s8EK zucQ8VsJE3BS5*5-XBVS9bWAk}5a~dyWfab+da&(5)RE)c%gpd*j&`vAHCPX|wbgi` z(z0Q)KSljq)Z2Zkx47o9VPl&BbH#L-tw^mdAEJw>zMQCcqdvwrw1dI^Yf(Ro<X4tf z`bs0J88ZHT<PNAG&|jr*^Vjuv3OwWlc3O|Jnqgyn6ZMmMJ@o6Z99Dk~^-a(b@585- z6nQt-e!Y*{7{;E6jsrX}-AG4+bLj%l#wbq}2D+uh`*k_=8$P;Xv1LVGpX%Qft!J<u ztEa5If-mo&OgH#15x=Lb!nes^7UhrXH!YU2dr%+eDf5<=4ln>2l(CU`(5clk+&-G( z82dGs?<-RWnh&=9PCV8hZEa;`6@K5AVfImxz}R14pZ03MTH_zSerraX_G5$nlonME zYyTALo#;QF`v*7gh(isIVIO#K#mr)cn(&bMT^_^O{gA<JH0oYM>L-t7Y%S`^Mz@*@ z#M_|!TGZb`_2p`H(KpmTgZh~yA2#|;K5z{6P!mg_Iryt8%BzO^@LS-S0v-qPkd0MT zR2P3kU)RC+P*fIpz2D#yu0)2vbt9W7HW!6!Y;ZmWs9(bCH<y0Xn*JE|J5bMcUg0Y( zjShE+P9`8AQC`5~95<W6I2X0O&T-~A;`q)`R6A66WY2L`#nqLS)g`4v=1I7{a_H<S zIxcnF$b7%X7gt<a?kgS$nBW_n<EQBRVIVf@qFfzjSDCjn=ArtnUtLq`D^}gA4i3xg zKaSK;R^*FX@X)^YLDqW6ip7pFxNL)CVdELQMfIDJE&57_#iuapr=s4@!#70m(GIqs z4C5pF;kHrYiOguYzEi-r4SX1Dk+*nDG!XK5V#nV;(%yw7L#)G}U*WTlzVI=GSawrz zpiXo!xw5Fd3bqPX#7u`w!45q1E;BEqcWfYx!c@QEWkR`G*N3vQg{RfLu9xZ_G5NX; zClfZAd|kjTb(D&mbvF!)LoBPo$|>lBhGnzK-=3Y4f|7v$;JSR=30MZIC89c-3t_g% zK1^d0*c^_NuR1}vDq^!il>26bR)E%lXx-60s{`!-{Sfpl=;xr{fsTXDg5C!OK|P>; z5bcvzP&{ZHC<!zb^exaLP$uXBP%fwxR0*mBJqc<AJrCLsdKGjObPn`q&^6FML6ld- zU`{g-O=hugVV-lax2Cdr>|U0}zRm7q^D&o2h-Hi6znLtHxiGI~Y&m;?J&4(@WI1dV zGRD<x4dU5D*jMve0cQL#th11Pmu<kzH?ktO33Cyd%$`Hs--Z6>NwhW+dQYYrj~Czc zUd4A!$y3Jd0rdjaOP)$7&*Z15Cwoe(O87fj5Mve(SrFCBWI=fMlob`z`vg)R-YFFr zY>#>fp!YRV{_^Tg^xjEB0)Oe&a+Ti4MC)sOHKXuudX3^KMF=PYCt)`@kK*w_2IVD$ z?d9gKczF5~!4e{TNFuAMBUtTN>W|tYCPc8b+aegnxCr(!9~by&U=i$fnfS0nb00SQ zHOFTKpE*Dp%R=5Su;MM{6(uI$cgUcqEsxeFHUmci!aQXZiA?MnK0d3*+-6Lymg|&b zNRLcxLbQ)6$`?%RSfs7Dv=SM*iS4`H?AKF8!PUerk1;Vy=ZYfo4s!ire0+a3`F@-j zY0LKq6MIcDF*B1hv8P5y_=f1^%eV-}GYXSW;W{O~lvj~bNmp~D^YEBKhp=T4EN|_D z%T}*8`TjQ0)?5(c%Z<*hm;$`XH#wpM4`x=q)x;Vix<~qi^u@%QqT}<??r35YxE)}8 zKGP7Wk541>HB(=cZ*g?Y$d<{lh;Lt12SfBXKFWuL-3x~!zIjoM=8K?9*fs8hHjk$W z8^@M%j_n#x`U6&8RScA4pAF@!sOFeyL&R6jjfmtG@O1-bZvC8ZI=406NBQHWOF4Ge zSFlWux$TjD%~X?PNqo#`TkYe<MtwM<ZO!z9^EtVl+B}gopJU?&+YXHHXWWk<&phjJ zzE3IG(tORGk7J{vZ4nEKO1vBsaiHXUWi{N0Xe>3{cG0%XTsXo`MaJSOt5Lm0HN5S6 zgZe9fyu`<`CDA^rYb$C?i#g`t*Bp?CRG`SKa?JECU}kQ|u?qw8)M^ZoWA{bn)oiXr z&m8-l+b+$`j3zX`Z3&V2nmIG)%i(Qf&~M46%{V#`-woaeVZ~+TRb|zL$y^>V3OO(i z!qQ?%9<ay}fUxV_7l@DNkST<X;_C)1l9mznd+tZTBDoD=_eaM9y_8iH@jh;kV#PIn zT1?`5Mx+>qwiQqo;xS=7s~`+}go@h$!rqFGrSdVJKM_{D7fm@I4sDV7zQuJ<<3rob z<!<6z%WV=^<h(>!VstFkzRIFUs=b6=<7*B+L`m{4!mda4SC(1r%i5|E#<*{RFOsVf zmKK#4xsM>MHYTD|$fL6!VYfy3&~JHFwKoyiJzS@D=ztPP7&T@^_(r}az$u)VVVdJv zTn2CoWu)8)|9kI|K7bcxW?;$cY9jcb`FMfD0!m2F5#016;?IeAlG(3|`#;IAD#0<M zoc2B%PngF+l0$J2%MiiMbs#xd2fwcrTNdY^9i3NE<)(^9edUiw@Jwzm;4iK~-1Ye> z*C6={T}aXRX#$ablW<3LzW&N0-=np-g*ExhcpM-(YN@w!P|m36_;LBdFMuNamMCu8 za}mNj@7Ij8kOMrr*Hgcg0nrJ`lU11sPsu|V<@_mk(7FPT<j_$(%=HZ1+~B!_NY0zw zu7J~3Tk)3CVk|J>Q@MUfPWfh7Yjqj+5yIE-y#P4kuX*G(@yTE1r?AfXWv(~ylis}0 z1@;P(lYxAmkF$t6hW@dC6Mm8V2>6TOG?4^_@Luj?z)k)5y+~#VH+=<owGS6}zVhk_ z{x0_ol0%E-@v0FVIf>b?=X=GE<4TD3YLe5%{Q>-RE$CUBRj}5?J9+GmgC6L15NE*h z3eMlj<pZzUQd(5wDJk_8bDaOfEZkP``NGV}V@N*YI{F>N%PKZ=+{Nt&cu`RW6#8g& zt(W7I`8oo}e53mY$(hLG1#mvj{58whW^w+RT>tSNPfgX992}pPVN}FFCW>P(Q;Ta= zk6N^ea8qyKhkPiG#~H%S7%+%a92gILAGebPkH_WmKtmZza&ofPU`ABe!F4newqB5x zv%Em9&Rms8F*E`71t9WiI;))nQHt#Z6@nT-`#`5by`Tv&=@p<YAS;Vwu^<~8fu|Ka zV;m<cZG@Qnz^{VFfOiIH8<w>KDs}*C#(4n$x`b88jN#wku)Q!f9kc@Byc5(9zD#Vj z`#_5!s~MCI8Mz?(7j(~|%|`HD13d@12T67;V=sd5E!6KveIexagH-U4Nzol$A>_RQ znuo*XDG<fD6385fHgBNKInWsJJ%#?SfzOG0(!o~n&^cx%_%4CEKv%&_cbg56{{rX` z=tH!90d4UE5I;jsMcc*TrTfuVkOMp=;87u42G56}IE;G*_+9|*1FsEodqFe6w+noS zfS&@bMcoA8agg&AXewlNf#)#k6ywxEbcWmrUMK43f!+nhp?)f81^Vg&HK4y-@VyJ_ z1n-NOR|@22g5Cn(bKqGEo@=N(jJngHE$Dk2Xc^?4Lci(gHyyldL1Qq+nV?q4qmXwM z*aXPf2AT>v>7W3r4uL*IJ^p@+6`-&CAcuZxco%ICf|pKulope%(C-#eN<o>{+y<g` zn()7orlPO^ipUnS83v4xfb+9}^RD^Eq5p|5OmN7DZt-b-X#L2hNI$fWWPdLLC%>XK zAsZlDBby_CAR8i^)WJhKBwyjShj;QbvLW&jvMus0@*P^os9n&yk{ysAZUaubCc7v5 zC;gKhk)M+7lFyJ$kZ;p^l24PJlFg8fkWY~Bkq?ngk&TkAlHZUYlkUhj$QH?0$Y05p z$Uex1$hOH3DMparl6{e{kgZW{ARl&um3*9RjeLUaZ6El_|H<FU-^lkj;+6b@e42cm z?2uv%*(LcP**e)F#UYA6WWQwV<QwD@FJe3tugD+Ck13{+?UFw_@%|j}Q;<WxLh+y( z^2xU-K9QZ1&yydJFH`&>|0X{sf4>A76b~o{kUvpeB3~dMq}W#hjABwN$pgOw&lJ#N zPymE3nGBqA8v587ZO+Lo#vynUP^SA88*aa_wc`E+b+})NbBJ`k0$v$>(wbHIX4%Q) zjCI(n2%p5{{8ei*(MD#nL!qk<I;QgXQA{bT!InpR2G#qRLdn6v`)KeZ?H+ia#H@A2 zTZ+5{5Pywetu69Ylv5%}?^cJ^QxR!E?{SV8{6@YkYe{C-8hRh$u;Ev4N)c4fKf)2? zi2|cgKhj~xy-SqC{2gWn#zuO&53~%l0#pbh-y$!?tk_1pzX)mtT?eIuh&KSb1ZoC3 zKodY~L5DyTqiR6sKoEn4TeTuHXUWQ}yxA+3XV~-bwKQvXMfs*k^%y*9f87Y8HKLsH zEzniaH4w!+@`DsmI%pZFA2bdN>jY5@oCjJAS_awzQZNUMLa;GG6meflgS2B8hAE*& zaO5&sROA|g-enI?fnVJCT#>z~$J{-|RVsg{dKougn{b4q`Wn<Lc&7tF^xaDD{C;OF zv*14oJ<-R88!Xcz%(2LhB;F@ZD5#ac=dU*Vpm&)`xDZN2YuvvMw2!WM3^;1oNLGS& zRCc0l3@OK<e2B}oJGktsqRLV}{z>4Di`?_lc<DVMdOsX_cQB=NE6z@8<Q<laEZMVl zPUL-z`Tkh+Juy;0H&Q<?QXhRE&y=m6I-KVt^%I!#*wFVRW~nUNTwaXz!+c{|Y-GMp zHfYh%57rIS;%kQ0!zUggf}jKkts`!=2QYy-BD$sZ8>(A#JxRB;HX<7p=}X4in9ei{ zaRA|n-?*Ayf!KnJYZE&v#4`M-fDiQ?#gf=`{!X}wy&=rzo<WF-&BU)VS-20TPX-9# z3x3fmtbwJItP~8?#J&)|i<@A=h@#kLRs|iv_6M*o!N(rM8^wbtUzf0*)$@14&9+@a z1KTwW`xo}3Vc5U1pAN(Jv0o0u4#K*qPx?gr_;+?>7<P=E;Mm|i{wcJxH_e6vZT~5} z&E6S?b+U`YuuD7wn6TOJKZPLsY#84ctZx`*AfJzd(Y7{$AFeqZ#YPF^hVk7gOdf{a zCCnU#&B2Yt*ZWu?EE$Hm1j;(hPqg1Pf}3MDz)|dBVFTh7V|2w}VxqW7C=*EcgF2PO zM}%tLmcC3rN%RR@xx);~lf-R8K)@EsKT*D?1pLwL*Dy_ZdKmVsuy+{tg7D%nY@hJT z*DzUpRrnnrpA+9^zlq}O(f=n843IDZ{?RTN6vo)|_)*O~sxDoXnZ>eJKD1)V+Er_Y zKubMY{3x51llfJa%q44=FxQeb9$v_KXvGSak(JF~Oo$f?maksQcquc(d{DEcgT;d7 zt_+g_rGY|Lv@}o`1)?>%(VE;yO>VSiX|yKNalz7ont`sCx|Xh48)>*S+U-(TlySLh zK*(~}L(#5XD+Wp{2TD=lOIPLOt!3u-vdlFMC)@$bU6RSmS<!+gBQK8;6|BmLJR^^+ z$P*(q>s`^OSyOD@OjdC;Z|#z$4>I#RGkeXdhjM969f(}??@FT|Cw{ae+nfk;!cu48 zIf<7go_D11vdn)sHF+%T1z>k_Tw!nENjZj7u(D1(O&%NTMcL$u;lBl%xSi+!CLYTQ zV24S(Z5-Q*vdI(A_M$wM;|csXbQ2%JJ{;h2@I1rh8Od`EvpkAr!XeG_Xr6C4xtuYq z0XS_kPGKzDi?WF)vKEvlar`!(zngOz$9e~NZs%tSbIjw}eb^t&@!Y`*P&V-iY%9u> zxtu%M3n-iON@8ye@K0nP4)8l!|3G;X&!<h9lUcfK{+)wUn8G%qJdMko${GgnY3v}% z=J=<xw+700v1=%sW0=7l*Z|FW-ObNpX89gg033fJ0X-!1^8o%d1m&6hJT{V-XYq5A z$upZB0>3%OZ?SU&<rH=uWy%ko!W<^!j9~K5WfM?#ay*r#50vMzLX^!p-pjV3JdN|D zv3)4h*ro{rJB@M+%6Fk0Krkv4=<jX}<3ku|2?lpJ%8T*000H1LP;Ny&Kv_UC@t_>Q bn$1GF5Xx_WerKb66~fPgpZ~4ebjJP%cYq1R literal 0 HcmV?d00001 diff --git a/16/scrasm/GENMAP.LNK b/16/scrasm/GENMAP.LNK new file mode 100644 index 00000000..95ee9882 --- /dev/null +++ b/16/scrasm/GENMAP.LNK @@ -0,0 +1 @@ +genmap.obj; diff --git a/16/scrasm/GENMAP.OBJ b/16/scrasm/GENMAP.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..6f1e7a9dc563d3e5bf1a4ff8a99df366280a0329 GIT binary patch literal 2543 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/GENPAL.C b/16/scrasm/GENPAL.C new file mode 100644 index 00000000..f913ae07 --- /dev/null +++ b/16/scrasm/GENPAL.C @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdlib.h> + +#define COLORS 256 +#define PALNAME "Diagonal" +#define FILENAME "%s.PAL" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef struct COLOR { + BYTE r,g,b; + } COLOR, far *LPCOLOR; + +void main() /* int argc, char *argv[]) */ + { + FILE *fp; + int i; + int colors = COLORS; + COLOR c; + int r,dr,g,dg,b,db; + + sprintf(fn,FILENAME,PALNAME); + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + + r=0; dr=2; + g=0; dg=3; + b=0; db=5; + for (i = 0; i < colors; i++) { + c.r = (BYTE)r; r+=dr; + if (r > 63) { r = 63; dr = -dr; } + else if (r < 0) { r = 0; dr = -dr; } + c.g = (BYTE)g; g+=dg; + if (g > 63) { g = 63; dg = -dg; } + else if (g < 0) { g = 0; dg = -dg; } + c.b = (BYTE)b; b+=db; + if (b > 63) { b = 63; db = -db; } + else if (b < 0) { b = 0; db = -db; } + fwrite(&c, sizeof(c),1, fp); + printf("Palette %d\r",i); + } + fclose(fp); + printf("All done! \n"); + exit(0); + } + \ No newline at end of file diff --git a/16/scrasm/GENPAL.EXE b/16/scrasm/GENPAL.EXE new file mode 100644 index 0000000000000000000000000000000000000000..c242a3d46e6f1999bc6a3190db1193e9a7c694dd GIT binary patch literal 17676 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/GENPAL.LNK b/16/scrasm/GENPAL.LNK new file mode 100644 index 00000000..4b4ff212 --- /dev/null +++ b/16/scrasm/GENPAL.LNK @@ -0,0 +1 @@ +genpal.obj; diff --git a/16/scrasm/GENPAL.OBJ b/16/scrasm/GENPAL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ae94092e11c393af00468d5bbde72ee8db2d69b4 GIT binary patch literal 1895 zcmZ8hQD|Fb6#o8uZ*FeVWxZ{;;@sR)*E-#_tL{P6Nllwvr=&|*vdqD@YntA4aaj`Y zz3t}EZjd0ES)dOxR64AJK8qmaRSe9By}MT*gjPzavD8pH;`wh9DF$-+&iT&y|MUOn z`_COOlvyKJNM=V<D9gY%Y%+oS<A5|735KL#ARcf{M$X3K;zTT_Xn}J&cX@_~V;83; zBH@@E3{4Pp4-dyLMnjHC0QZl;rN=|>#a&K(dkIOWHRRyi=OX8$_`;1dw^@(C9P|VB zh;0P;q%PX)V))X7p=k!Vl{PjAd%O%^Dd=qpEwLqGsRt_S6Z*vgDacTE0T0G3lzV}% zBjMoLz*HzU8h&R2We<5`geF5+z5oFTW|Fh{Tr!IhYcv`N<Hj^5^K;pm+%emqFBm!h zh~-b`P5%uuV;iGhM3Y&=whjNtj1Pfq)<2Wa8AE>hdC^@0-+Cd$a2WtqdT00jF7|*4 zqMpu$vDk}yK6rIKnKJD;%a{R{6;S1r1Kd05P-jzDuUYmrD7sZJGdVjASx@t_;MO}1 zmu}q5*pw_W$~<3Ls{t!O;=)614UCLv%|rh%qU0^s<(j(7lJ06-#f2@{;wr#nY6G1( zsm3};c&Kdy549bEK244`Mfx;2T6fWB1EB1Rwq4d%D%uXywu=kf<G1;elsZn#&OeXu zYCB{TfsZ=`PiYesty$JqE7~U0n#F}?H?_%AH+kx&liKX2QW0IEqBY9epA~JLX^rAS zV;oDzQF14QdSA7^zgj;~Ej^PE>qo2gW7X1$gj9dCS`So9p@gdxNyxZ2K=+t-TFXHy zo3{+Q$tQ40@Pnkc>qkn(M~+8UAze>qavti{PRoQaV=4r<2{H#YIhy74R*R`Zy1?P4 z6FJKx8=Rl!XoI5+r`H{N+DCAWpq$EQ^QOgPR$8LUQUYY`fdrrG*0VF2dEM@Tz`|5u zFYQ3J@QS60i}8?`ps3P&3rEiF#y#Y>AX}MRhHmqv3d}v9)Uz3jmXZKf)-(C(xipsC zcr<wF(RWoWUxMoiINJ|7UC3MQ#38tEq^>4S-QG)-qIz_C1SCS;?j_r+dP$=lhtCO6 zx+Y($hc<E!faM~Ioppply`whrZm+L$p)|VPCZTnS*8CQiWlco1s;#sIt+eJhYGYm1 z7PSpl(bitmHa-zo54R{`g{xkuo$jiczlgR^zf$?*@-J9Ah|(JgcRg4wogrPkpHS-Q zYUu-lHc4cWcf_Uheglg#KDWs3qif$s_wp1}9Kf@98mDj&r*R1H;t1l@i7ObwRbosW z#VriuQ;c8<&*3K=!_Rmgzu^UJ;5c@00{!eooM12EEjEfNb`qD^7!39@^6V8yaSIGT zo&sa9(|%Rj@q7620E76I@b82l6Be0@L(GQ(Hi(<Fx<s*9mKn`+uG#%GSX>a)ww@K5 zB2KGiJ^`uoQAmO;6_`kdq!(=S@5W!UWI`lf(o;Fxu{kf%P@hg(2ImXJ%Vejs$=R;$ z=5{7)?4#`{y0f8(wj76@ef-2wStifnm^9$zb1cxqkZ48%G&Y?$z@>6*@=6J}Yj$^h z{BUg_gGc4Z6tJhWt3=1_2yGU!zz#dR^Hb3&Kb*_APt`u9Xd2fCo$S5;T~ha<we$M_ lm&a{-Xq4w6R6rkSf@8T4uJbf0cwLGjy*fHJhR+0y;a}|M+Pwe( literal 0 HcmV?d00001 diff --git a/16/scrasm/GENSQ.C b/16/scrasm/GENSQ.C new file mode 100644 index 00000000..402853f3 --- /dev/null +++ b/16/scrasm/GENSQ.C @@ -0,0 +1,102 @@ +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdlib.h> + +#define WIDTH 256 + +#define FILENAME "DIAGONAL.TIL" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef BYTE ROW[16]; +typedef ROW BITMAP[16]; + +BITMAP b; +BITMAP c; + +BITMAP pattern={{1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0}, + {1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0}, + {1,0,0,1,0,0,0,0,0,0,0,2,0,0,0,0}, + {0,0,1,0,0,1,1,0,1,1,0,0,2,0,0,0}, + {0,0,1,0,0,1,2,0,1,2,0,0,2,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0}, + {0,1,0,0,1,2,0,0,0,1,2,0,0,2,0,0}, + {0,0,1,0,1,2,1,1,1,1,2,0,2,0,0,0}, + {0,0,1,0,0,2,2,2,2,2,0,0,2,0,0,2}, + {0,0,0,1,0,0,0,0,0,0,0,2,0,0,0,2}, + {0,0,0,0,2,2,0,0,0,2,2,0,0,0,0,2}, + {0,0,0,0,0,0,2,2,2,0,0,0,0,0,2,2}, + {0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2}}; + +void copy_pattern(BITMAP b,BITMAP patt, BYTE l, BYTE m, BYTE h) + { + int x,y; + + for (y=0; y<16; y++) { + for (x=0; x<16; x++) { + switch (patt[y][x]) { + case 0: + b[y][x] = m; + break; + case 1: + b[y][x] = l; + break; + case 2: + b[y][x] = h; + break; + } + } + } + } + +/* Transforms linear to planar */ +void transform(BITMAP b,BITMAP c) + { + int x,y,p; + BYTE *pb = (BYTE *)c; + + for (p=0; p<4; p++) { + for (y=0; y<16; y++) { + for (x=0; x<16; x+=4) { + *(pb++) = b[y][x+p]; + } + } + } + } + +void main(int argc,char *argv[]) + { + FILE *fp; + int i; + int width = WIDTH; + + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + if (argc > 1) { + width = atoi(argv[1]); + if (width > WIDTH) + width = WIDTH; + printf("Width = %d\n",width); + } + + for (i = 0; i< width; i++) { + BYTE less,more; + + less = (BYTE)((i + width - 1) % width); + more = (BYTE)((i + 1) % width); + copy_pattern(b, pattern, less, (BYTE)i, more); + transform(b,c); + fwrite(c, 16,16, fp); + printf("Square %d\r",i); + } + fclose(fp); + printf("All done! \n"); + exit(0); + } + \ No newline at end of file diff --git a/16/scrasm/GENSQ.EXE b/16/scrasm/GENSQ.EXE new file mode 100644 index 0000000000000000000000000000000000000000..71cf2657d4497bdedfdf4c4c967725933c1a712d GIT binary patch literal 18916 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/GENSQ.LNK b/16/scrasm/GENSQ.LNK new file mode 100644 index 00000000..a9d9b795 --- /dev/null +++ b/16/scrasm/GENSQ.LNK @@ -0,0 +1 @@ +gensq.obj; diff --git a/16/scrasm/GENSQ.OBJ b/16/scrasm/GENSQ.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..7166ee65a0b5b4b887152b5f1a6c063a68ee08d3 GIT binary patch literal 2977 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/INIT.INC b/16/scrasm/INIT.INC new file mode 100644 index 00000000..eddeeed4 --- /dev/null +++ b/16/scrasm/INIT.INC @@ -0,0 +1,375 @@ +;; Error messages +ERR_OK EQU 0 +msgErr0 db 'Later!',13,10,'$' +ERR_MEM EQU 1 +msgErr1 db 'Error 001: Out of memory?',13,10,'$' +ERR_CPU EQU 2 +msgErr2 db 'Error 002: CPU must be at least an 80386.',13,10,'$' +ERR_FILE EQU 3 +msgErr3 db 'Error 003: File error.',13,10,'$' +ERR_FILENOTFOUND EQU 4 +msgErr4 db 'Error 004: File not found.',13,10,'$' +msgtblError dw offset msgErr0, offset msgErr1, offset msgErr2, + offset msgErr3, offset msgErr4 +nError db 0 + +;; CPU name strings +CPUName86 DB "8088/8086$" +CPUName286 DB "80286DX/SX$" +CPUName386 DB "80386DX/SX$" +CPUName486 DB "80486DX/SX or better$" +CPUNameTable DW CPUName86,CPUName286,CPUName386,CPUName486 + +EVEN +msgCPUTypeIs DB "Your CPU type: $" +EVEN +msgCPUTypeIsEnd DB 13,10,'$' +nCPU DB 0 + +EVEN +msgPages DB 'Pages displayed: ' +strNumPages DB 6 dup (?),13,10,'$' + +EVEN +bufText DW 80*50 DUP (?) ; Needs this much to hold + ; a 50-line screen... +wCPos DW 0 +nDisplay DB 0 + +EVEN +fnMap1 db 'DIAGONAL.MAP',0 +fnTiles1 db 'DIAGONAL.TIL',0 +fnPalette db 'DIAGONAL.PAL',0 ; only one allowed, for now +fnMap2 db 'SCROLL.MAP',0 +fnTiles2 db 'SCROLL.TIL',0 + +fntblMap dw offset fnMap1,offset fnMap2 +fntblTiles dw offset fnTiles1,offset fnTiles2 +nMap dw 0 + +;; CPUType routine snatched from Ray Duncan's _Power Programming MASM_ +;; chapter 14. Reformatted to my style, but I left the code alone +;; except that it used to push a bunch of stuff, but doesn't any more +;; because I don't care what gets destroyed. +CPUType PROC near + pushf ; now try to clear bits 12-15 + pop ax ; of CPU flags + and ax,0fffh + push ax ; set modified CPU flags + popf + pushf + pop ax ; get flags again + and ax,0f000h ; if bits 12-15 are still + cmp ax,0f000h ; set, this is 8086/88 + jne cpu1 ; jump, not 8086/88 + mov nCPU,CPU8086 ; set nCPU = 86/88 CPU type + jmp cpux ; and exit + +cpu1: or ax,0f000h ; must be 286 or later, + push ax ; now try to set bits 12-15 + popf ; of CPU flags + pushf + pop ax ; if bits 12-15 can't be + and ax,0f000h ; set, this is a 286 + jnz cpu2 ; jump, not 80286 + mov nCPU,CPU80286 ; set nCPU = 286 CPU type + jmp cpux ; and exit + +cpu2: mov bx,sp ; 386 or later, save SP + and sp,not 3 ; avoid stack alignment fault + pushfd ; get value of EFLAGS + pop eax + mov ecx,eax ; save copy of EFLAGS + xor eax,40000h ; flip AC bit in EFLAGS + push eax ; try and force EFLAGS + popfd + pushfd ; get back EFLAGS value + pop eax + mov sp,bx ; restore old stack pointer + xor eax,ecx ; can AC bit be changed? + jnz cpu3 ; no, jump, not a 386 + mov nCPU,CPU80386 ; set nCPU = 386 CPU type + jmp cpux ; and exit + +cpu3: mov nCPU,CPU80486 ; set nCPU = 486 CPU type + +cpux: mov bl,nCPU + xor bh,bh + shl bx,1 + DOSPRINT <offset msgCPUTypeIs> + DOSPRINT CPUNameTable[bx] + DOSPRINT <offset msgCPUTypeIsEnd> + ret ; return with nCPU = CPU type +CPUType ENDP + +;; Initialize: So far, all it does is make sure you have a 386 + +;; (because that's what I assembled the code for). +Initialize PROC near + ; Set DS = CS in this program, since data is local + mov ax,cs + mov segCode,ax ; Store the Code Segment + mov bx,ds + mov segPSP,bx ; Store the PSP Segment + mov ds,ax ; Set DS = CS + + ; Resize code to 64K + CODE_SIZE EQU 64 ; <- this is arbitrary. + ; ES already -> allocated segment + mov ah,4ah + mov bx,64*CODE_SIZE + int 21h + mov nError,ERR_MEM + jc TerminateError + +;; I've chosen not to implement sprites yet so that I can get this out +;; the door... +;; ; 320x200 buffer for sprite drawing. To draw sprites, first draw them +;; ; into this buffer, adding rectangles to the current rectangle list. +;; ; Then, use BUFFER_COPY to put out the buffers with the current +;; ; rectangle list to the screen. BUFFER_COPY will ensure minimal VGA +;; ; writing. +;; ; Create a buffer segment +;; mov bx,(320 * 200) / 16 +;; mov ah,48h +;; int 21h +;; mov nError,ERR_MEM +;; jc TerminateError +;; mov segBuffer,ax + + call CPUType + mov nError,ERR_CPU + cmp nCPU,2 + jl TerminateError + + mov ds,segCode + mov dx,offset fnPalette + call LoadPaletteFile + jc TerminateError + + call LoadIndex + jc TerminateError + + KEYB_START + + call Beginning ; Can display an entry screen here + + ; This is linked in from Michael Abrash's zen timer code. + ; (But I wrote the Click myself) + call Click + call ZTimerOn + + call MainLoop + + call ZTimerOff + call Click + + call Ending ; Can display an exit screen here + + KEYB_END + +Terminate: mov nError,ERR_OK +TerminateError: + mov ax,cs ;DOS functions require that DS point + mov ds,ax ; to text to be displayed on the screen + mov bh,0 + mov bl,nError + shl bx,1 + DOSPRINT msgtblError[bx] + + mov ax,pages + mov ds,segCode + mov si,offset strNumPages + call Int2Ascii + DOSPRINT <offset msgPages> + + call ZTimerReport + + mov al,nError + mov ah,4ch ; DOS Terminate + int 21h + ; Don't need to RET! We're outta here +Initialize ENDP + +;; Clicks the internal speaker. I use this to indicate that page timing +;; has started. +Click PROC + in al,61h + mov ah,al + or al,3 + out 61h,al + + mov cx,5000 ; (this is an arbitrary delay!) +spkr_on: loop spkr_on + mov al,ah + out 61h,al + ret +Click ENDP + +;; Copied from an old 8088 "Learn Assembly" book and changed a bit +Int2Ascii PROC + mov cx,6 + mov byte ptr cs:[si],' ' + mov byte ptr cs:[si+1],'0' + mov byte ptr cs:[si+2],'0' + mov byte ptr cs:[si+3],'0' + mov byte ptr cs:[si+4],'0' + mov byte ptr cs:[si+5],'0' + add si,6 + mov cx,10 + or ax,ax + jns clear_divide + neg ax + mov byte ptr cs:[si-6],'-' +clear_divide: mov dx,0 + div cx + add dx,'0' + dec si + mov cs:[si],dl + or ax,ax + jnz clear_divide + ret +Int2Ascii ENDP + +;; Given a filename at DS:DX, reads the file into memory and returns +;; a pointer to it as DX:0000. +;; Note that this routine obviously will only work correctly for +;; a file < 640k in size, but you can bring in files bigger than 64k. +;; This code comes from Future Crew's STMIK sampler "Mental Surgery" +;; and I commented it up to make it fit in with my stuff a little better. +;; Thank you, FC, for releasing that code! Several of the routines +;; in this program were inspired or helped along by having that source... +;; Most recently, added in error codes. +EVEN +LoadFile PROC NEAR + ;set: DX=offset to filename + ;return: DX=segment of file + + ; Open the datafile at DS:DX. + mov ax,3D00h ; 3D,00 -> Open file, read only + ; DS:DX already points at filename + int 21h ; returns AX=file handle + mov cl,ERR_FILENOTFOUND + jc ferror + mov bx,ax ; Store file handle in BX + mov si,bx ; and also in a variable + + ; Get the length of the file so we know how much to allocate + mov ax,4202h ; 42,02 -> Seek, signed from end + mov cx,0 ; CX:DX is a long file offset, + ; BX is already set as file handle + mov dx,0 ; zero in this case = end of file + int 21h ; (returns long offset in DX:AX) + mov cl,ERR_FILE + jc ferror + +;;; shr dx,1 ; This is original FC code, +;;; rcr ax,1 ; which I removed because the +;;; shr dx,1 ; 386 has a nice instruction +;;; rcr ax,1 ; to do this all! +;;; shr dx,1 ; But 286 users will want to +;;; rcr ax,1 ; return to this code, instead +;;; shr dx,1 ; of SHRD dx,ax,4 +;;; rcr ax,1 ; + + ; Now turn that long DX:AX into a number of paragraphs to allocate + ; for when we read the file. + shrd ax,dx,4 ; Divides long DX:AX by 4, + mov bx,ax ; and stores this in BX + inc bx ; HHMMMM? One more needed for small #'s + mov ah,48h ; 48 -> Allocate memory + ; BX already = # of paragraphs + int 21h + mov cl,ERR_MEM + jc ferror + mov di,ax ; store this in a variable + + ; Seek the file back to the beginning in order to read it into + ; the memory we just allocated. + mov ax,4200h ; 42,00 -> Seek, absolute offset + mov bx,si ; BX is the file handle. + mov cx,0 ; CX:DX is a long offset + mov dx,0 + int 21h + jc ferror + + ; Now read the file into memory + mov ds,di ; DS points at alloc'd memory +ReadBlock: mov ah,3fh ; 3F -> Read file + mov cx,32768 ; read 32768 bytes at a time + mov dx,0 ; DS:DX points at beginning of + int 21h ; this block of memory. + mov cl,ERR_FILE + jc ferror + mov dx,ds ; Offset DS by (32768/16), which + add dx,800h ; is the number of paragraphs in + mov ds,dx ; each block of 32768 bytes. + cmp ax,32768 ; Did we actually read 32768 bytes? + je ReadBlock ; If so, there's more to read... + ; Otherwise, we've read all the + ; data in the file. + + ; So now, close the file handle. + mov ah,3Eh ; 3E -> Close file + ; BX still is the file handle + int 21h + + ; Everything went ok. Return the segment in DX. + mov dx,di + mov nError,ERR_OK + ret +ferror: mov nError,cl + ret +LoadFile ENDP + +;; Eventually, this should load in an index of all data files to +;; allow for filenames to be specified outside of the program. The +;; goal is to make the program have no hardcoded filenames... +;; Of course, the structure of this index and its entries will be +;; hardcoded, as will the structures of all of the files it includes. +LoadIndex PROC near + ret +LoadIndex ENDP + +;; Save the current video mode and cursor position with standard +;; BIOS calls +SaveVideo PROC near + mov ah,0Fh + int 10h ; Get current display Mode + mov nDisplay,al + mov ah,03h + mov bh,0 + int 10h + mov wCPos,dx + + mov ds,segText + mov si,0 + mov es,segCode + mov di,offset bufText + mov cx,80*50 + rep movsw + ret +SaveVideo ENDP + +;; Restore the current video mode and cursor position with standard +;; BIOS calls +RestoreVideo PROC near + mov ah,00h + mov al,nDisplay + int 10h ; Get current display Mode + mov ah,02h + mov bh,0 + mov dx,wCPos + int 10h + + PAL_UPDATE ; When flipping into text mode, re-do the + ; palette because the BIOS changes it. + + mov es,segText + mov di,0 + mov ds,segCode + mov si,offset bufText + mov cx,80*50 + rep movsw + ret +RestoreVideo ENDP + \ No newline at end of file diff --git a/16/scrasm/KEYB.INC b/16/scrasm/KEYB.INC new file mode 100644 index 00000000..ef730cf0 --- /dev/null +++ b/16/scrasm/KEYB.INC @@ -0,0 +1,237 @@ +;; ==================================================================== +;; Macros +;; ==================================================================== +;; Jump if key pressed +JKEYP MACRO key,label + cmp byte ptr cs:_keyFlags[key+1],1 + je label + ENDM +;; Jump if key not pressed +JKEYNP MACRO key,label + cmp byte ptr cs:_keyFlags[key+1],1 + jne label + ENDM + +;; Note that JNKEY and JKEY both modify _flKeyChanged, so you cannot +;; use one after the other! In other words, +;; JKEYNP no_key +;; JKEYP yes_key ;<-- this will fail +;; will not work like you'd think it would. The second call (JKEYP) +;; will not know that a key has been pressed! +;; Jump if no key pressed: +JNKEY MACRO label + cmp cs:_flKeyChanged,0 + je label + mov cs:_flKeyChanged,0 ; <--- important! + ENDM +;; Jump if key pressed: +JKEY MACRO label + cmp cs:_flKeyChanged,0 + mov cs:_flKeyChanged,0 + jne label + ENDM + +;; Start keyboard interrupts +KEYB_START MACRO + call SwapInt9 + mov cs:_flKeyChanged,0 + ENDM + +;; Clear keyboard interrupts +KEYB_END MACRO + call SwapInt9 + ENDM + +;; Credit for these routines: Steve Dollins, Brown Computer Group. +;; I didn't write any of the code below -- just heisted it from some +;; stuff that he wrote and released! Very useful keyboard routines. +;; Any comments prefixed SDE were added by me. +_keyFlags dw 256 dup (0) ; SDE: since they only use 2 bits + ; per word, this is a tradeoff, + ; space for time + +oldint9_offset dw offset newint9 +oldint9_segment dw seg newint9 + +_flKeyChanged dw 0 + +;----------------------------------------------------------------------- +; void SwapInt9( void ) +; +; SwapInt9() exchanges the vector in oldint9_segment:oldint9_offset +; with the vector in the interrupt table for INT 9h. +;----------------------------------------------------------------------- + +SwapInt9 PROC far + mov ax,cs + mov ds,ax + + mov ax,03509h ; Get interrupt 09h + int 21h ; return in ES:BX + + mov ax,oldint9_segment + mov dx,oldint9_offset + push ds + mov ds,ax + mov ax,02509h ; Set new interrupt + int 21h ; to address in DS:DX + pop ds + + mov oldint9_segment,es ; Save the old interrupt + mov oldint9_offset,bx + ret +SwapInt9 ENDP + + +;----------------------------------------------------------------------- +; newint9 is the new keyboard interrupt (INT 9h). +; +; Reads the scan code from the keyboard and modifies the key +; flags table. The high byte is set to the position of the key, +; pressed=1, release=0. The low byte is set to 1 when the key +; is pressed and left unmodified when the key is released. +;----------------------------------------------------------------------- +newint9 PROC far + push ax + push bx + push ds + + mov ax,cs + mov ds,ax + + JKEYNP kCTRL,not_ctrlaltdel ; SDE code + JKEYNP kALT,not_ctrlaltdel ; To still allow ctrl- + JKEYNP kDELETE,not_ctrlaltdel ; alt-delete. Nothing + jmp ctrlaltdel ; worse than a total lockup! +not_ctrlaltdel: + + in ax,60h ; get scan code in AL, control byte in AH + mov bx,ax ; save a copy in BX + xchg ah,al ; swap to get control byte in AL + or al,80h ; clear keyboard + out 61h,al ; of interrupt + and al,7Fh + out 61h,al + mov al,20h ; send generic EOI to + out 20h,al ; PIC + + and bx,0007fh ; strip all but the scan code + shl bx,1 ; multiply by two to get our offset + + ; if the key was released, the high bit is set in the scan code + bt ax,15 ; move this high bit into the carry flag + setnc byte ptr [_keyFlags+bx+1] ; set "Is being pressed" flag + jc short int09done ; if the key was released, we're done + mov byte ptr [_keyFlags+bx],1 ; set "Has been pressed" flag + mov _flKeyChanged,1 ; state of keyboard has changed +int09done: + mov _flKeyChanged,1 ; state of keyboard has changed + pop ds + pop bx + pop ax + iret +ctrlaltdel: int 19h ; SDE -- added this. + ; Allows a reboot. +newint9 ENDP + +;; Defines the current key procedure (used as a jump-through) +kprocCur dw KprocDirect + +;; This is a keyboard procedure. Normally, this would control some +;; sprite, or something, and the screen would follow the sprite. For +;; the purposes of this code, though (namely, sprite-less scrolling) +;; it just directly affects ScrollDX and ScrollDY. +;; This keyproc is inertialess, use + and - to increase speed and +;; the up/down/left/right keys to move directions. +;; Pressing K will switch to the other keyprocedure on the fly. +;; P pauses the screen -- note that this is just for completely +;; freezing the screen... it doesn't return until you let go! + +EVEN +scroll_speed_x dw SCROLL_SPEED ; (defaults) +scroll_speed_y dw SCROLL_SPEED * VIRTUAL_WIDTH ; (defaults) +KprocDirect PROC near +chk_leftright: mov ax,0 + JKEYNP kRIGHT,not_right + mov ax,scroll_speed_x + mov ScrollDX,ax + jmp chk_updown +not_right: JKEYNP kLEFT,not_left + sub ax,scroll_speed_x + mov ScrollDX,ax + jmp chk_updown +not_left: mov ScrollDX,ax + +chk_updown: mov ax,0 + JKEYNP kUP,not_up + sub ax,scroll_speed_y + mov ScrollDY,ax + jmp chk_other +not_up: JKEYNP kDOWN,not_down + mov ax,scroll_speed_y + mov ScrollDY,ax + jmp chk_other +not_down: mov ScrollDY,ax + +chk_other: JKEYNP kK,not_k + mov kprocCur,KprocInertia +not_k: JKEYNP kM,not_m + mov bDoTransition,1 +not_m: JKEYNP kGREY_MINUS,not_minus + cmp scroll_speed_x,1 + jle not_minus + dec scroll_speed_x + sub scroll_speed_y,VIRTUAL_WIDTH +not_minus: JKEYNP kGREY_PLUS,not_plus + cmp scroll_speed_x,16 + jge not_plus + inc scroll_speed_x + add scroll_speed_y,VIRTUAL_WIDTH +not_plus: + +pause_key: JKEYP kP,pause_key + + ret +KprocDirect ENDP + +;; This keyproc has inertia, so + and - don't work. +;; Use up/down/left/right keys to increase speed in those directions. +;; Pressing K will switch to the other keyprocedure on the fly. +;; P pauses the screen -- note that this is just for completely +;; freezing the screen... it doesn't return until you let go! +KprocInertia PROC near +chk2_leftright: JKEYNP kRIGHT,not2_right + cmp ScrollDX,16 + je not2_right + inc ScrollDX + jmp chk2_updown +not2_right: JKEYNP kLEFT,not2_left + cmp ScrollDX,-16 + je not2_left + dec ScrollDX + jmp chk2_updown +not2_left: + +chk2_updown: JKEYNP kUP,not2_up + cmp ScrollDY,-VIRTUAL_WIDTH * 16 + je not2_up + add ScrollDY,-VIRTUAL_WIDTH + jmp chk2_other +not2_up: JKEYNP kDOWN,not2_down + cmp ScrollDY,VIRTUAL_WIDTH * 16 + je not2_down + add ScrollDY,VIRTUAL_WIDTH + jmp chk2_other +not2_down: + +chk2_other: JKEYNP kK,not2_k + mov kprocCur,KprocDirect +not2_k: JKEYNP kM,not2_m + mov bDoTransition,1 +not2_m: + +pause2_key: JKEYP kP,pause2_key + + ret +KprocInertia ENDP + \ No newline at end of file diff --git a/16/scrasm/LZTIMER.ASM b/16/scrasm/LZTIMER.ASM new file mode 100644 index 00000000..5fed7be1 --- /dev/null +++ b/16/scrasm/LZTIMER.ASM @@ -0,0 +1,636 @@ +; +; *** Listing 2-5 *** +; +; The long-period Zen timer. (LZTIMER.ASM) +; Uses the 8253 timer and the BIOS time-of-day count to time the +; performance of code that takes less than an hour to execute. +; Because interrupts are left on (in order to allow the timer +; interrupt to be recognized), this is less accurate than the +; precision Zen timer, so it is best used only to time code that takes +; more than about 54 milliseconds to execute (code that the precision +; Zen timer reports overflow on). Resolution is limited by the +; occurrence of timer interrupts. +; +; By Michael Abrash 4/26/89 +; +; Externally callable routines: +; +; ZTimerOn: Saves the BIOS time of day count and starts the +; long-period Zen timer. +; +; ZTimerOff: Stops the long-period Zen timer and saves the timer +; count and the BIOS time-of-day count. +; +; ZTimerReport: Prints the time that passed between starting and +; stopping the timer. +; +; Note: If either more than an hour passes or midnight falls between +; calls to ZTimerOn and ZTimerOff, an error is reported. For +; timing code that takes more than a few minutes to execute, +; either the DOS TIME command in a batch file before and after +; execution of the code to time or the use of the DOS +; time-of-day function in place of the long-period Zen timer is +; more than adequate. +; +; Note: The PS/2 version is assembled by setting the symbol PS2 to 1. +; PS2 must be set to 1 on PS/2 computers because the PS/2's +; timers are not compatible with an undocumented timer-stopping +; feature of the 8253; the alternative timing approach that +; must be used on PS/2 computers leaves a short window +; during which the timer 0 count and the BIOS timer count may +; not be synchronized. You should also set the PS2 symbol to +; 1 if you're getting erratic or obviously incorrect results. +; +; Note: When PS2 is 0, the code relies on an undocumented 8253 +; feature to get more reliable readings. It is possible that +; the 8253 (or whatever chip is emulating the 8253) may be put +; into an undefined or incorrect state when this feature is +; used. +; +; *************************************************************** +; * If your computer displays any hint of erratic behavior * +; * after the long-period Zen timer is used, such as the floppy * +; * drive failing to operate properly, reboot the system, set * +; * PS2 to 1 and leave it that way! * +; *************************************************************** +; +; Note: Each block of code being timed should ideally be run several +; times, with at least two similar readings required to +; establish a true measurement, in order to eliminate any +; variability caused by interrupts. +; +; Note: Interrupts must not be disabled for more than 54 ms at a +; stretch during the timing interval. Because interrupts +; are enabled, keys, mice, and other devices that generate +; interrupts should not be used during the timing interval. +; +; Note: Any extra code running off the timer interrupt (such as +; some memory-resident utilities) will increase the time +; measured by the Zen timer. +; +; Note: These routines can introduce inaccuracies of up to a few +; tenths of a second into the system clock count for each +; code section timed. Consequently, it's a good idea to +; reboot at the conclusion of timing sessions. (The +; battery-backed clock, if any, is not affected by the Zen +; timer.) +; +; All registers and all flags are preserved by all routines. +; + DOSSEG + .model small + .code + public ZTimerOn, ZTimerOff, ZTimerReport + +; +; Set PS2 to 0 to assemble for use on a fully 8253-compatible +; system; when PS2 is 0, the readings are more reliable if the +; computer supports the undocumented timer-stopping feature, +; but may be badly off if that feature is not supported. In +; fact, timer-stopping may interfere with your computer's +; overall operation by putting the 8253 into an undefined or +; incorrect state. Use with caution!!! +; +; Set PS2 to 1 to assemble for use on non-8253-compatible +; systems, including PS/2 computers; when PS2 is 1, readings +; may occasionally be off by 54 ms, but the code will work +; properly on all systems. +; +; A setting of 1 is safer and will work on more systems, +; while a setting of 0 produces more reliable results in systems +; which support the undocumented timer-stopping feature of the +; 8253. The choice is yours. +; +PS2 equ 1 +; +; Base address of the 8253 timer chip. +; +BASE_8253 equ 40h +; +; The address of the timer 0 count registers in the 8253. +; +TIMER_0_8253 equ BASE_8253 + 0 +; +; The address of the mode register in the 8253. +; +MODE_8253 equ BASE_8253 + 3 +; +; The address of the BIOS timer count variable in the BIOS +; data segment. +; +TIMER_COUNT equ 46ch +; +; Macro to emulate a POPF instruction in order to fix the bug in some +; 80286 chips which allows interrupts to occur during a POPF even when +; interrupts remain disabled. +; +MPOPF macro + local p1, p2 + jmp short p2 +p1: iret ;jump to pushed address & pop flags +p2: push cs ;construct far return address to + call p1 ; the next instruction + endm + +; +; Macro to delay briefly to ensure that enough time has elapsed +; between successive I/O accesses so that the device being accessed +; can respond to both accesses even on a very fast PC. +; +DELAY macro + jmp $+2 + jmp $+2 + jmp $+2 + endm + +StartBIOSCountLow dw ? ;BIOS count low word at the + ; start of the timing period +StartBIOSCountHigh dw ? ;BIOS count high word at the + ; start of the timing period +EndBIOSCountLow dw ? ;BIOS count low word at the + ; end of the timing period +EndBIOSCountHigh dw ? ;BIOS count high word at the + ; end of the timing period +EndTimedCount dw ? ;timer 0 count at the end of + ; the timing period +ReferenceCount dw ? ;number of counts required to + ; execute timer overhead code +; +; String printed to report results. +; +OutputStr label byte + db 0dh, 0ah, 'Timed count: ' +TimedCountStr db 10 dup (?) + db ' microseconds', 0dh, 0ah + db '$' +; +; Temporary storage for timed count as it's divided down by powers +; of ten when converting from doubleword binary to ASCII. +; +CurrentCountLow dw ? +CurrentCountHigh dw ? +; +; Powers of ten table used to perform division by 10 when doing +; doubleword conversion from binary to ASCII. +; +PowersOfTen label word + dd 1 + dd 10 + dd 100 + dd 1000 + dd 10000 + dd 100000 + dd 1000000 + dd 10000000 + dd 100000000 + dd 1000000000 +PowersOfTenEnd label word +; +; String printed to report that the high word of the BIOS count +; changed while timing (an hour elapsed or midnight was crossed), +; and so the count is invalid and the test needs to be rerun. +; +TurnOverStr label byte + db 0dh, 0ah + db '****************************************************' + db 0dh, 0ah + db '* Either midnight passed or an hour or more passed *' + db 0dh, 0ah + db '* while timing was in progress. If the former was *' + db 0dh, 0ah + db '* the case, please rerun the test; if the latter *' + db 0dh, 0ah + db '* was the case, the test code takes too long to *' + db 0dh, 0ah + db '* run to be timed by the long-period Zen timer. *' + db 0dh, 0ah + db '* Suggestions: use the DOS TIME command, the DOS *' + db 0dh, 0ah + db '* time function, or a watch. *' + db 0dh, 0ah + db '****************************************************' + db 0dh, 0ah + db '$' + +;******************************************************************** +;* Routine called to start timing. * +;******************************************************************** + +ZTimerOn proc near + +; +; Save the context of the program being timed. +; + push ax + pushf +; +; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause +; linear counting rather than count-by-two counting. Also stops +; timer 0 until the timer count is loaded, except on PS/2 +; computers. +; + mov al,00110100b ;mode 2 + out MODE_8253,al +; +; Set the timer count to 0, so we know we won't get another +; timer interrupt right away. +; Note: this introduces an inaccuracy of up to 54 ms in the system +; clock count each time it is executed. +; + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + out TIMER_0_8253,al ;msb +; +; In case interrupts are disabled, enable interrupts briefly to allow +; the interrupt generated when switching from mode 3 to mode 2 to be +; recognized. Interrupts must be enabled for at least 210 ns to allow +; time for that interrupt to occur. Here, 10 jumps are used for the +; delay to ensure that the delay time will be more than long enough +; even on a very fast PC. +; + pushf + sti + rept 10 + jmp $+2 + endm + MPOPF +; +; Store the timing start BIOS count. +; (Since the timer count was just set to 0, the BIOS count will +; stay the same for the next 54 ms, so we don't need to disable +; interrupts in order to avoid getting a half-changed count.) +; + push ds + sub ax,ax + mov ds,ax + mov ax,ds:[TIMER_COUNT+2] + mov cs:[StartBIOSCountHigh],ax + mov ax,ds:[TIMER_COUNT] + mov cs:[StartBIOSCountLow],ax + pop ds +; +; Set the timer count to 0 again to start the timing interval. +; + mov al,00110100b ;set up to load initial + out MODE_8253,al ; timer count + DELAY + sub al,al + out TIMER_0_8253,al ;load count lsb + DELAY + out TIMER_0_8253,al ;load count msb +; +; Restore the context of the program being timed and return to it. +; + MPOPF + pop ax + ret + +ZTimerOn endp + +;******************************************************************** +;* Routine called to stop timing and get count. * +;******************************************************************** + +ZTimerOff proc near + +; +; Save the context of the program being timed. +; + pushf + push ax + push cx +; +; In case interrupts are disabled, enable interrupts briefly to allow +; any pending timer interrupt to be handled. Interrupts must be +; enabled for at least 210 ns to allow time for that interrupt to +; occur. Here, 10 jumps are used for the delay to ensure that the +; delay time will be more than long enough even on a very fast PC. +; + sti + rept 10 + jmp $+2 + endm + +; +; Latch the timer count. +; + +if PS2 + + mov al,00000000b + out MODE_8253,al ;latch timer 0 count +; +; This is where a one-instruction-long window exists on the PS/2. +; The timer count and the BIOS count can lose synchronization; +; since the timer keeps counting after it's latched, it can turn +; over right after it's latched and cause the BIOS count to turn +; over before interrupts are disabled, leaving us with the timer +; count from before the timer turned over coupled with the BIOS +; count from after the timer turned over. The result is a count +; that's 54 ms too long. +; + +else + +; +; Set timer 0 to mode 2 (divide-by-N), waiting for a 2-byte count +; load, which stops timer 0 until the count is loaded. (Only works +; on fully 8253-compatible chips.) +; + mov al,00110100b ;mode 2 + out MODE_8253,al + DELAY + mov al,00000000b ;latch timer 0 count + out MODE_8253,al + +endif + + cli ;stop the BIOS count +; +; Read the BIOS count. (Since interrupts are disabled, the BIOS +; count won't change.) +; + push ds + sub ax,ax + mov ds,ax + mov ax,ds:[TIMER_COUNT+2] + mov cs:[EndBIOSCountHigh],ax + mov ax,ds:[TIMER_COUNT] + mov cs:[EndBIOSCountLow],ax + pop ds +; +; Read the timer count and save it. +; + in al,TIMER_0_8253 ;lsb + DELAY + mov ah,al + in al,TIMER_0_8253 ;msb + xchg ah,al + neg ax ;convert from countdown + ; remaining to elapsed + ; count + mov cs:[EndTimedCount],ax +; +; Restart timer 0, which is still waiting for an initial count +; to be loaded. +; + +ife PS2 + + DELAY + mov al,00110100b ;mode 2, waiting to load a + ; 2-byte count + out MODE_8253,al + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + mov al,ah + out TIMER_0_8253,al ;msb + DELAY + +endif + + sti ;let the BIOS count continue +; +; Time a zero-length code fragment, to get a reference for how +; much overhead this routine has. Time it 16 times and average it, +; for accuracy, rounding the result. +; + mov cs:[ReferenceCount],0 + mov cx,16 + cli ;interrupts off to allow a + ; precise reference count +RefLoop: + call ReferenceZTimerOn + call ReferenceZTimerOff + loop RefLoop + sti + add cs:[ReferenceCount],8 ;total + (0.5 * 16) + mov cl,4 + shr cs:[ReferenceCount],cl ;(total) / 16 + 0.5 +; +; Restore the context of the program being timed and return to it. +; + pop cx + pop ax + MPOPF + ret + +ZTimerOff endp + +; +; Called by ZTimerOff to start the timer for overhead measurements. +; + +ReferenceZTimerOn proc near +; +; Save the context of the program being timed. +; + push ax + pushf +; +; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause +; linear counting rather than count-by-two counting. +; + mov al,00110100b ;mode 2 + out MODE_8253,al +; +; Set the timer count to 0. +; + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + out TIMER_0_8253,al ;msb +; +; Restore the context of the program being timed and return to it. +; + MPOPF + pop ax + ret + +ReferenceZTimerOn endp + +; +; Called by ZTimerOff to stop the timer and add the result to +; ReferenceCount for overhead measurements. Doesn't need to look +; at the BIOS count because timing a zero-length code fragment +; isn't going to take anywhere near 54 ms. +; + +ReferenceZTimerOff proc near +; +; Save the context of the program being timed. +; + pushf + push ax + push cx + +; +; Match the interrupt-window delay in ZTimerOff. +; + sti + rept 10 + jmp $+2 + endm + + mov al,00000000b + out MODE_8253,al ;latch timer +; +; Read the count and save it. +; + DELAY + in al,TIMER_0_8253 ;lsb + DELAY + mov ah,al + in al,TIMER_0_8253 ;msb + xchg ah,al + neg ax ;convert from countdown + ; remaining to elapsed + ; count + add cs:[ReferenceCount],ax +; +; Restore the context and return. +; + pop cx + pop ax + MPOPF + ret + +ReferenceZTimerOff endp + +;******************************************************************** +;* Routine called to report timing results. * +;******************************************************************** + +ZTimerReport proc near + + pushf + push ax + push bx + push cx + push dx + push si + push di + push ds +; + push cs ;DOS functions require that DS point + pop ds ; to text to be displayed on the screen + assume ds:_TEXT +; +; See if midnight or more than an hour passed during timing. If so, +; notify the user. +; + mov ax,[StartBIOSCountHigh] + cmp ax,[EndBIOSCountHigh] + jz CalcBIOSTime ;hour count didn't change, + ; so everything's fine + inc ax + cmp ax,[EndBIOSCountHigh] + jnz TestTooLong ;midnight or two hour + ; boundaries passed, so the + ; results are no good + mov ax,[EndBIOSCountLow] + cmp ax,[StartBIOSCountLow] + jb CalcBIOSTime ;a single hour boundary + ; passed-that's OK, so long as + ; the total time wasn't more + ; than an hour + +; +; Over an hour elapsed or midnight passed during timing, which +; renders the results invalid. Notify the user. This misses the +; case where a multiple of 24 hours has passed, but we'll rely +; on the perspicacity of the user to detect that case. +; +TestTooLong: + mov ah,9 + mov dx,offset TurnOverStr + int 21h + jmp short ZTimerReportDone +; +; Convert the BIOS time to microseconds. +; +CalcBIOSTime: + mov ax,[EndBIOSCountLow] + sub ax,[StartBIOSCountLow] + mov dx,54925 ;number of microseconds each + ; BIOS count represents + mul dx + mov bx,ax ;set aside BIOS count in + mov cx,dx ; microseconds +; +; Convert timer count to microseconds. +; + mov ax,[EndTimedCount] + mov si,8381 + mul si + mov si,10000 + div si ;* .8381 = * 8381 / 10000 +; +; Add timer and BIOS counts together to get an overall time in +; microseconds. +; + add bx,ax + adc cx,0 +; +; Subtract the timer overhead and save the result. +; + mov ax,[ReferenceCount] + mov si,8381 ;convert the reference count + mul si ; to microseconds + mov si,10000 + div si ;* .8381 = * 8381 / 10000 + sub bx,ax + sbb cx,0 + mov [CurrentCountLow],bx + mov [CurrentCountHigh],cx +; +; Convert the result to an ASCII string by trial subtractions of +; powers of 10. +; + mov di,offset PowersOfTenEnd - offset PowersOfTen - 4 + mov si,offset TimedCountStr +CTSNextDigit: + mov bl,'0' +CTSLoop: + mov ax,[CurrentCountLow] + mov dx,[CurrentCountHigh] + sub ax,PowersOfTen[di] + sbb dx,PowersOfTen[di+2] + jc CTSNextPowerDown + inc bl + mov [CurrentCountLow],ax + mov [CurrentCountHigh],dx + jmp CTSLoop +CTSNextPowerDown: + mov [si],bl + inc si + sub di,4 + jns CTSNextDigit +; +; +; Print the results. +; + mov ah,9 + mov dx,offset OutputStr + int 21h +; +ZTimerReportDone: + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax + MPOPF + ret + +ZTimerReport endp + + end + \ No newline at end of file diff --git a/16/scrasm/LZTIMER.OBJ b/16/scrasm/LZTIMER.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..0511b4d5a24855619e478e21e5ac23c289a35415 GIT binary patch literal 3231 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 JHR2C~^>0nZe=Yz3 literal 0 HcmV?d00001 diff --git a/16/scrasm/MAIN.ASM b/16/scrasm/MAIN.ASM new file mode 100644 index 00000000..1c33a0fb --- /dev/null +++ b/16/scrasm/MAIN.ASM @@ -0,0 +1,134 @@ +;;=======================================================================;; +;; ;; +;; Scrolling Routines -- main program ;; +;; ;; +;; All other INC files are included here. The main routines for the ;; +;; frame-by-frame execution loop are also here. Finally I tried to keep ;; +;; global variables stored in this file as well. ;; +;; ;; +;;=======================================================================;; + dosseg + .model small + .386 + + .code + extrn ZTimerOn:far, ZTimerOff:far, ZTimerReport:far + +INCLUDE constant.inc + + +DW_TABLE MACRO inc,num + count = 0 + number = 0 + WHILE (count LT num) + DW number + count = count + 1 + number = number + inc + ENDM + ENDM + +DOSPRINT MACRO st + mov ah,9 + mov dx,st + int 21h + ENDM + +EVEN +Mult320 label WORD +MultBufWidth label WORD + DW_TABLE 320,200 +MultVirtWidth label WORD + DW_TABLE (VIRTUAL_WIDTH/4),200 + +INCLUDE palette.inc +INCLUDE keyb.inc +INCLUDE modex.inc +INCLUDE page.inc +INCLUDE init.inc +INCLUDE map.inc +;INCLUDE sprite.inc NOT FOR NOW +INCLUDE scroll.inc + +;; Various segments that need to be filled in later... +EVEN +segVideo dw 0A000h ; videoram segment +segText dw 0B800h ; text segment +segMap dw -1 ; Map info segment +segTiles dw -1 ; Tile bitmap segment +segBuffer dw -1 ; Local 320x200 buffer segment +segCode dw -1 ; Code segment +segPSP dw -1 ; PSP segment +segPalette dw -1 ; Palette segment +segTextPal dw -1 ; Saved text palette + +EVEN +bDoTransition db 0 + +;; This routine is called for each frame. +;; Right now it just scrolls, but later all sprite animation would +;; occur here too. +EVEN +OneFrame PROC near + call Scroll ; Scrolls the screen +; call AnimateSprites ; prepares sprites on drawpage + jmp FlipPage ; shows drawpage... + ; no RET necessary +OneFrame ENDP + +;; Each frame -- call the frame motion code, then check for keyhit. +EVEN +MainLoop PROC NEAR +next_frame: call OneFrame + JNKEY next_frame + JKEYP kESC,all_done ; ESC -> quit, always + call kprocCur + mov al,bDoTransition + cmp al,0 + je next_frame +transition: FLASH_OFF 16,segPalette + mov bDoTransition,0 + mov ax,1 + sub ax,nMap + mov nMap,ax ; Flip maps + + call LoadData + call update_full ;<<<< + call OneFrame + FLASH_ON 16,segPalette + jmp next_frame +all_done: ret +MainLoop ENDP + +;; Beginning code -- Leaves text mode (saving the text screen) via +;; a fade. It loads the map data and draws one +;; frame before it fades on. +Beginning PROC near + NEW_PAL segTextPal + PAL_SAVE segTextPal + FADE_OFF 1,segTextPal + call SaveVideo + MODEX_START ; 320x200 Mode X graphics mode + PAL_BLACK + + call LoadData ; This call will change... + + call update_full ;<<<< + call OneFrame + FADE_ON 1,segPalette + ret +Beginning ENDP + +;; Ending code -- restore to text mode via a flash +Ending PROC near + FLASH_OFF 8,segPalette + call RestoreVideo + FLASH_ON 8,segTextPal + ret +Ending ENDP + + .data + + .stack 2048 + + END Initialize + \ No newline at end of file diff --git a/16/scrasm/MAIN.OBJ b/16/scrasm/MAIN.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ff612818dd2a95532fff4a45d6d644adbf8a1b90 GIT binary patch literal 18324 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/MAKEFILE b/16/scrasm/MAKEFILE new file mode 100644 index 00000000..8b9557ae --- /dev/null +++ b/16/scrasm/MAKEFILE @@ -0,0 +1,47 @@ +OBJS=main.obj lztimer.obj +INCLUDES=modex.inc keyb.inc palette.inc page.inc scroll.inc map.inc \ + constant.inc init.inc +PROGRAM=scroll + +.c.obj: + cl -c -Zi -Od -W4 $*.c + +.asm.obj: + masm -ml -zi $*.asm + +.obj.exe: + link /CO @$*.lnk + +project: scroll.exe gensq.exe genmap.exe genpal.exe + +main.asm: $(INCLUDES) + +scroll.lnk: makefile + echo $(OBJS: =+) > $*.lnk + echo $(PROGRAM); >> $*.lnk + +scroll.exe: $(OBJS) scroll.lnk + link /CO @$*.lnk + +gensq.obj: $*.c + +gensq.lnk: makefile + echo $*.obj; > $*.lnk + +gensq.exe: $*.obj $*.lnk + +genmap.obj: $*.c + +genmap.lnk: makefile + echo $*.obj; > $*.lnk + +genmap.exe: $*.obj $*.lnk + +genpal.obj: $*.c + +genpal.lnk: makefile + echo $*.obj; > $*.lnk + +genpal.exe: $*.obj $*.lnk + + \ No newline at end of file diff --git a/16/scrasm/MAP.INC b/16/scrasm/MAP.INC new file mode 100644 index 00000000..c87494c2 --- /dev/null +++ b/16/scrasm/MAP.INC @@ -0,0 +1,413 @@ +;; MAP in own segment allows map of tiles to be up to 65536 tiles in area +;; which translates to about 16.8 million pixels of virtual screen. This +;; can be represented in almost any rectangle -- just set MAP_WIDTH. + +;; Sorry this code isn't commented -- I was working on it right up until +;; the point that I released this. You have any questions? Ask away +;; (my internet address is in the DOC file). + +MAPHEADER STRUCT, NONUNIQUE + MapName BYTE "" + Wid WORD 2 + Ht WORD 3 + Extent WORD 4 + OffX1 WORD 5 + OffY1 WORD 6 + OffX2 WORD 7 + OffY2 WORD 8 + WrapX WORD 9 + WrapY WORD 10 + Magic WORD 11 +MAPHEADER ENDS +MapInfo MAPHEADER <> + + +; In: DS:DX = offset of filename +LoadMapFile PROC near + mov ax,segMap + cmp ax,-1 + je map_not_loaded + sub ax,(SIZEOF MAPHEADER) / 16 + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lm_err + mov segMap,-1 + +map_not_loaded: call LoadFile + jc lm_err + + mov ds,dx + mov si,0 + mov ax,cs + mov es,ax + lea di,MapInfo + mov cx,(SIZEOF MAPHEADER) / 4 + rep movsd + + add dx,(SIZEOF MAPHEADER) / 16 + mov cs:segMap,dx + + mov BlankPage.Valid,0 + mov ShowPage.Valid,0 + mov DrawPage.Valid,0 + + mov upper_left,0 + mov ScrollPosX,0 + mov ScrollPosY,0 + mov ScrollDX,0 + mov ScrollDY,0 + +lm_err: ret +LoadMapFile ENDP + +LoadTilesFile PROC near + mov ax,segTiles + cmp ax,-1 + je tiles_not_loaded + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lt_err + mov segMap,-1 + +tiles_not_loaded: call LoadFile + jc lm_err + mov segTiles,dx + + mov BlankPage.Valid,0 + mov ShowPage.Valid,0 + mov DrawPage.Valid,0 + +lt_err: ret +LoadTilesFile ENDP + +EVEN +LoadData PROC near + ; Load squares from data file + mov bx,nMap + shl bx,1 + mov dx,fntblTiles[bx] + mov ds,segCode + call LoadTilesFile + ; returns Carry if error + jc load_error + + ; Load map from data file + mov ds,segCode + mov bx,nMap + shl bx,1 + mov dx,fntblMap[bx] + call LoadMapFile + ; returns Carry if error + +load_error: ret +LoadData ENDP + +EVEN +update_full PROC + mov ds,segTiles + mov es,segVideo + mov fs,segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,DrawPage.Address + add di,upper_left + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + + mov dx,MapInfo.WrapX + + mov ch,(VIRTUAL_WIDTH/SQUARE_WIDTH) +draw_full_loop: push cx + push si + push dx + + mov al,11h + mov si,0 + +update_f_loop: mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_f_loop + + pop dx + dec dx + jnz update_f_go_on + mov dx,MapInfo.Wid + sub bp,dx +update_f_go_on: inc bp + pop si + add di,(SQUARE_WIDTH/ 4) + pop cx + dec ch + jnz draw_full_loop + + + + + + + + + + + + mov dx,GC_INDEX + mov ax,ALL_COPY_BITS + out dx,ax + + mov dx,SC_INDEX + mov ax,0F02h + out dx,ax + + mov ds,segVideo + mov si,DrawPage.Address + add si,upper_left + mov es,segVideo + mov di,BlankPage.Address + add di,upper_left + mov cx,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + rep movsb + mov si,DrawPage.Address + add si,upper_left + mov di,ShowPage.Address + add di,upper_left + mov cx,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + rep movsb + + mov dx,GC_INDEX + mov ax,ALL_DRAW_BITS + out dx,ax + + ret +update_full ENDP + +EVEN +update_left PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov al,011h + mov si,0 + mov di,cs:DrawPage.Address + add di,cs:upper_left ; becomes DI later + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + +update_l_loop: mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_l_loop + + ret +update_left ENDP + +EVEN +update_right PROC near + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov bp,MapInfo.OffX2 + add bp,MapInfo.OffY1 + + mov al,011h + mov si,0 + + mov di,cs:DrawPage.Address ; becomes DI + add di,cs:upper_left + add di,(VIRTUAL_WIDTH - SQUARE_WIDTH) / 4 + +update_r_loop: mov dx,SC_INDEX + 1 + out dx,al + + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_r_loop + + ret +update_right ENDP + +EVEN +update_top PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,cs:DrawPage.Address + add di,cs:upper_left + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + + mov al,011h + mov si,0 + +update_top_loop: + mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_row + pop bp + sub di,VIRTUAL_WIDTH / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_top_loop + + ret +update_top ENDP + +EVEN +update_bottom PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,cs:DrawPage.Address + add di,cs:upper_left + add di,(VIRTUAL_WIDTH * (VIRTUAL_HEIGHT - SQUARE_HEIGHT)) / 4 + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY2 + + mov al,011h + mov si,0 + +update_bottom_loop: + mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_row + pop bp + sub di,VIRTUAL_WIDTH / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_bottom_loop + + ret +update_bottom ENDP + +; Draws ONE plane of a single col +EVEN +draw_col PROC near + ; DI->upper left corner of col to draw + ; BP->col of map to draw + ; SI used to point at tiles + ; AX,CX used + ; BX used to push SI + ; DX unused + shl eax,16 ; save it + mov ax,MapInfo.WrapY + + mov cl,(VIRTUAL_HEIGHT / SQUARE_HEIGHT) +do_col_loop: mov bx,si + mov bh,byte ptr fs:[bp] ; change tile # + + mov ch,SQUARE_HEIGHT +do_col_sq_loop: mov dl,byte ptr ds:[bx+2] + mov dh,byte ptr ds:[bx+3] + shl edx,16 + mov dl,byte ptr ds:[bx+0] + mov dh,byte ptr ds:[bx+1] + mov es:[di],edx ; 32-bit write + add di,VIRTUAL_WIDTH / 4 + add bx,4 + dec ch + jnz do_col_sq_loop + + add bp,MapInfo.Wid + dec ax + jnz yayaya + mov ax,MapInfo.Ht + sub bp,MapInfo.Extent +yayaya: + + dec cl + jnz do_col_loop + + shr eax,16 ; restore it + + ret +draw_col ENDP + +; Draws ONE plane of a single row +EVEN +draw_row PROC near + push ax +; shl eax,16 ; save ax + + mov ax,MapInfo.WrapX + + ; DI->upper left corner of row to draw + ; BP->row of map to draw + ; SI used to point at tiles + ; AX,CX used + ; BX used to push SI + ; DX unused + + mov cl,(VIRTUAL_WIDTH / SQUARE_WIDTH) +do_row_loop: mov bx,si + mov bh,byte ptr fs:[bp] ; change tile # + + mov ch,SQUARE_HEIGHT +do_row_sq_loop: mov dl,byte ptr ds:[bx+2] + mov dh,byte ptr ds:[bx+3] + shl edx,16 + mov dl,byte ptr ds:[bx+0] + mov dh,byte ptr ds:[bx+1] + mov es:[di],edx + add di,(VIRTUAL_WIDTH / 4) + add bx,4 + dec ch + jnz do_row_sq_loop + + add di,(-VIRTUAL_WIDTH*SQUARE_HEIGHT + SQUARE_WIDTH) / 4 + inc bp + dec ax + jnz yayaya2 + mov ax,MapInfo.Wid + sub bp,ax +yayaya2: + dec cl + jnz do_row_loop + +; shr eax,16 ; restore it + pop ax + ret +draw_row ENDP + \ No newline at end of file diff --git a/16/scrasm/MODEX.INC b/16/scrasm/MODEX.INC new file mode 100644 index 00000000..174aa354 --- /dev/null +++ b/16/scrasm/MODEX.INC @@ -0,0 +1,88 @@ +; ==================================================================== +; Entry points: +; ==================================================================== +MODEX_START MACRO + mov ax,13h ;let the BIOS set standard 256-color + int 10h ; mode (320x200 linear) +; PALETTE_BLACK + call ModifyForX + ENDM + +; ==================================================================== +; This is MODE-X code from Dr. Dobb's Journal, by Michael Abrash. +; I modified it from 320x240 back to 320x200, and then to 512 virtual +; width, for scrolling purposes. +; ==================================================================== + +; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs. +; **************************************************************** +; * Revised 6/19/91 to select correct clock; fixes vertical roll * +; * problems on fixed-frequency (IBM 851X-type) monitors. * +; **************************************************************** +; Modified from public-domain mode set code by John Bridges. + +; Index/data pairs for CRT Controller registers that differ between +; mode 13h and mode X. +CRTParms label word +; dw 00d06h ;vertical total +; dw 03e07h ;overflow (bit 8 of vertical counts) +; dw 04109h ;cell height (2 to double-scan) +; dw 0ea10h ;v sync start +; dw 0ac11h ;v sync end and protect cr0-cr7 +; dw 0df12h ;vertical displayed = 480 + dw 00014h ;turn off dword mode * +; dw 0e715h ;v blank start +; dw 00616h ;v blank end + dw 0e317h ;turn on byte mode * + + dw (VIRTUAL_WIDTH*32)+13h ; width of screen = VWid NEW +; dw 09012h ;vertical displayed = 400 (already like this) +CRT_PARM_LENGTH equ (($-CRTParms)/2) + +ModifyForX PROC near + mov dx,SC_INDEX + mov ax,0604h + out dx,ax ;disable chain4 mode + mov ax,0100h + out dx,ax ;synchronous reset while setting Misc + ; Output for safety, even though clock + ; unchanged + mov dx,MISC_OUTPUT + mov al,0e3h + out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate + + mov dx,SC_INDEX + mov ax,0300h + out dx,ax ;undo reset (restart sequencer) + + mov dx,CRTC_INDEX ;reprogram the CRT Controller + mov al,11h ;VSync End reg contains register write + out dx,al ; protect bit + inc dx ;CRT Controller Data register + in al,dx ;get current VSync End register setting + and al,7fh ;remove write protect on various + out dx,al ; CRTC registers + dec dx ;CRT Controller Index + cld + push cs + pop ds + mov si,offset CRTParms ;point to CRT parameter table + mov cx,CRT_PARM_LENGTH ;# of table entries +SetCRTParmsLoop: + lodsw ;get the next CRT Index/Data pair + out dx,ax ;set the next CRT Index/Data pair + loop SetCRTParmsLoop + + mov dx,SC_INDEX + mov ax,0f02h + out dx,ax ;enable writes to all four planes + mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels + mov es,ax ; at a time + sub di,di ;point ES:DI to display memory + sub ax,ax ;clear to zero-value pixels + mov cx,8000h ;# of words in display memory + rep stosw ;clear all of display memory + + ret +ModifyForX ENDP + \ No newline at end of file diff --git a/16/scrasm/PAGE.INC b/16/scrasm/PAGE.INC new file mode 100644 index 00000000..a55bdf0b --- /dev/null +++ b/16/scrasm/PAGE.INC @@ -0,0 +1,109 @@ +;; ==================================================================== +;; (Code follows) +;; ==================================================================== + +EVEN +upper_left dw 0 ; Stores upper left corner offset + ; relative to page offset. +pages dw 0 ; for counting frame-per-sec + +PAGE_INFO STRUCT 2,NONUNIQUE + Address dw 0 + UpperLeftAddress dw 0 + MapPosX dw 0 + MapPosY dw 0 + Alignment db 0 + AlignmentMask db 0 + ScrollOffset dw 0 + Rectangles dw 0 + Valid db 0 +PAGE_INFO ENDS + +DrawPage PAGE_INFO <PAGE_0,PAGE_0> +ShowPage PAGE_INFO <PAGE_1,PAGE_1> +BlankPage PAGE_INFO <PAGE_2,PAGE_2> + +ROTATE3 MACRO reg,item + mov reg,cs:ShowPage.item + xchg reg,cs:BlankPage.item + xchg reg,cs:DrawPage.item + mov cs:ShowPage.item,reg + ENDM ; Leaves ShowPage.item in reg! + +;; This procedure is used to flip between the three available pages. +;; Originally from Dr. Dobb's Journal's Graphics Programming column by +;; Michael Abrash, I've reworked the code to be more specific to my +;; own purposes, and commented it more. +EVEN +FlipPage PROC near + ; This series of instructions circles the show_page, blank_page, + ; and draw page appropriately and leaves the current page to show + ; in AX. Note that it's a lot more instructions than it looks like, + ; but I unrolled the copy loop for speed. So-so good idea, because + ; if you add a field and forget to rotate it, it could mean trouble! + ROTATE3 ax,Rectangles + ROTATE3 ax,ScrollOffset + ROTATE3 ax,MapPosX + ROTATE3 ax,MapPosY +; ROTATE3 al,AlignmentMask SPRITES ... + ROTATE3 al,Alignment + mov di,ax ; DI = scroll offset low, and + ; garbage in the high bits... + and di,3 ; DI = pixel pan, 0 to 3. + shl di,1 ; Mode X requires 0 2 4 or 6. + ROTATE3 ax,Address + ROTATE3 al,Valid + ROTATE3 ax,UpperLeftAddress ; Leaves AX=ShowPage.ULAddr + + add ax,cs:ShowPage.ScrollOffset + + ; AX is set up to be the current show page already. + ; By pre-loading BX with the low-address set code, and CX with + ; the high-address set code, we can more quickly flip the page + ; after the vertical retrace period. + mov bl,START_ADDRESS_LOW ;preload for fastest + mov bh,al ; flipping once display + mov cl,START_ADDRESS_HIGH ; enable is detected + mov ch,ah + + ; Wait for display enable to be active (status is active low), to be + ; sure both halves of the start address will take in the same frame. + mov dx,INPUT_STATUS_1 +WaitDE: in al,dx + test al,01h + jnz WaitDE ;display enable is active low (0 = active) + + ; Set the start offset in display memory of the page to display. + mov dx,CRTC_INDEX + mov ax,bx + out dx,ax ;start address low + mov ax,cx + out dx,ax ;start address high + + ; Now wait for vertical sync, so the other page will be invisible when + ; we start drawing to it. + mov dx,INPUT_STATUS_1 +WaitVS: in al,dx + test al,08h + jz WaitVS ;vertical sync is active high (1 = active) + + ; Finally, have to adjust the pixel panning register in order + ; to fine-tune the starting address on a pixel level. + ; This pixel pan value is the scroll offset mod 4 -- but since + ; Mode X's pixel pan works by values of 2 (0, 2, 4 or 6) we + ; have to shift appropriately. + mov dx,ATC_INDEX + mov al,13h ; 13h = set pixel pan + out dx,al + mov ax,di ; DI = pixel pan calculated above + out dx,al + mov dx,ATC_INDEX + mov al,32 ; Allows the computer to use this register + out dx,al ; again. Without this OUT, the screen will + ; remain blank! + + ; Increment the page counter now! + inc cs:pages + ret +FlipPage ENDP + \ No newline at end of file diff --git a/16/scrasm/PALETTE.INC b/16/scrasm/PALETTE.INC new file mode 100644 index 00000000..e3bd381e --- /dev/null +++ b/16/scrasm/PALETTE.INC @@ -0,0 +1,239 @@ +;; Palette operations +;; Note that where needed in the macros, a "palette" refers to +;; the segment handle to a 768-byte piece of memory. So palettes +;; can be loaded and freed, they're not permanent, but if you want +;; to use a fixed (not allocated) palette you'd better make sure +;; it's segment aligned or else you can't use these macros. If it +;; is, you can just supply "seg myPalette" as the 'palette' argument +;; to any of these macros. + +;; Fade from a palette to black +FADE_OFF MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,fade ; positive -> Gets dimmer... + mov bl,0 ; Starts exact + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Fade from black to a palette +FADE_ON MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,-fade ; negative -> Gets brighter... + mov bl,64 ; Starts totally dimmed + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Flash from a palette to white +FLASH_OFF MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,-fade ; negative -> gets brighter + mov bl,0 ; Starts exact + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Flash from white to a palette +FLASH_ON MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,fade ; positive -> Gets dimmer... + mov bl,-64 ; Starts totally bright + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Save a palette into a palette-sized piece of memory +PAL_SAVE MACRO palette + mov es,palette + mov di,0 + call SavePalette + ENDM + +; Returns AX = a new segment for a palette +NEW_PAL MACRO palette + mov bx,(256 * 3) / 16 + mov ah,48h + int 21h + mov palette,ax + ENDM + +;; Black the entire palette temporarily. Used to blank the screen while +;; drawing a frame before fading in. +PAL_BLACK MACRO + mov ax,seg tmppal + mov ds,ax + mov si,OFFSET tmppal + mov bh,-1 ; Doesn't really matter... + mov bl,64 ; Starts totally dimmed + mov cx,1 ; Just one time -- to leave it black + call FadePalette + ENDM + +;; drawing a frame before fading in. +PAL_WHITE MACRO + mov ax,seg tmppal + mov ds,ax + mov si,OFFSET tmppal + mov bh,-1 ; Doesn't really matter... + mov bl,-64 ; Starts totally dimmed + mov cx,1 ; Just one time -- to leave it black + call FadePalette + ENDM + +;; Black the entire palette temporarily. Used to blank the screen while +;; drawing a frame before fading in. +PAL_UPDATE MACRO + mov cx,0 ; 0 times = update + call FadePalette + ENDM + +WAITBORDER MACRO + LOCAL wbr1,wbr2 + mov dx,INPUT_STATUS_1 +wbr1: in al,dx + test al,8 + jnz wbr1 +wbr2: in al,dx + test al,8 + jz wbr2 + ENDM + +;; Fade Palette: +;; The following code is modified greatly from the Future Crew's palette +;; fading code. Works on blocks of 256 colors only, so far, but I might +;; change it later. Also, it theoretically could "anti-fade" -- fade to +;; white -- which I call flashing, so I added that ability, which was +;; missing from FC's code. +EVEN +tmppal DB 768 dup (?) ; Stores old palette +FadePalette PROC NEAR + mov ax,seg tmppal + mov es,ax + +FadeLoop: push cx + push si + + cmp cx,0 + je JustUpdate + + ; Load in the colors in the palette + mov di,OFFSET tmppal ; ES:DI -> temp palette + mov cx,768 ; Reads 256*3 bytes at a time. +loadpal_loop: mov al,ds:[si] ; Load one color byte + inc si + sub al,bl ; Subtract the fade amount + jge pal_more ; Limit the range by clipping + xor al,al ; to between 0 and 63 + jmp pal_ok ; (there's probably a faster +pal_more: cmp al,63 ; way to do it than this, + jle pal_ok ; but I don't know it) + mov al,63 +pal_ok: mov es:[di],al ; Store that byte in the new + inc di + dec cx ; temp palette and loop. + jnz loadpal_loop + + ; Get ready to move this block of palette values +JustUpdate: sti ; Let interrupts happen now, + WAITBORDER ; while waiting for a retrace, + cli ; instead of more critical times + + mov dx,PEL_WRITE_REG; Set up to write to color register, + xor al,al ; starting at palette entry 0. + out dx,al + mov dx,PEL_DATA_REG ; Point at color port + + ; Quickly put out the first half of the color palette + mov di,OFFSET tmppal + mov cl,(768/6)/2 ; Does 2 loops of 128 colors each. + cli ; Waits a retrace inbetween... +FirstHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the + mov al,es:[di] ; number of LOOP instructions + inc di + out dx,al + ENDM + dec cl + jnz FirstHalfLoop + sti + + WAITBORDER ; Waits one retrace -- less flicker + mov dx,PEL_DATA_REG ; Reset DX + + ; Now, quickly put out the other half of the colors. + mov cl,(768/6)/2 + cli +SecondHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the + mov al,es:[di] ; number of LOOP instructions + inc di + out dx,al + ENDM + dec cl + jnz SecondHalfLoop + + ; For the next iteration, restore everything and loop + pop si + pop cx + + cmp cx,0 + je JustUpdated + + add bl,bh ; Change brightness by BH + + dec cx + jnz FadeLoop + + ; All done, re-enable interrupts and return +JustUpdated: sti + ret +FadePalette ENDP + +;; Saves the palette into the memory pointed at by DS:SI. That memory +;; must be at least 768 bytes long... +SavePalette PROC NEAR + mov dx,PEL_READ_REG ; Set up to read from color register, + xor al,al ; starting at palette entry 0. + out dx,al + mov dx,PEL_DATA_REG + + ; Quickly read in the first half of the color palette + mov cl,(768/6) + cli +ReadPalLoop: REPEAT 6 ; Steps of 6 -- reduces the + in al,dx ; number of LOOP instructions + mov es:[di],al + inc di + ENDM + dec cl + jnz ReadPalLoop + ; All done, re-enable interrupts and return + sti + ret +SavePalette ENDP + +;; Load a palette from a file. Opens the file and reads it into +;; memory (standard LoadFile) and then points the palette at that +;; newly allocated memory. Also, frees old memory before it does +;; any loading ... +LoadPaletteFile PROC near + mov ax,segPalette + cmp ax,-1 + je pal_not_loaded + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lp_err + mov segPalette,-1 + +pal_not_loaded: call LoadFile + jc lp_err + + mov segPalette,dx +lp_err: ret +LoadPaletteFile ENDP + \ No newline at end of file diff --git a/16/scrasm/SCROLL.DOC b/16/scrasm/SCROLL.DOC new file mode 100644 index 00000000..0893db36 --- /dev/null +++ b/16/scrasm/SCROLL.DOC @@ -0,0 +1,297 @@ + ________________________________________________ + |+----------------------------------------------+| + || I N T R O D U C I N G : || + |+----------------------------------------------+| + || Steve's 4-Way || + || ___ ___ ____ ___ _ _ || + || / __| / __| | _ \ / _ \ | | | | || + || | <_ | | | |_> | | | | | | | | | || + || \_ \ | | | / | | | | | | | | || + || __> | | |__ | |\ \ | |_| | | |__ | |__ || + || |___/ \___| |_| \_| \___/ |____| |____| || + |+______________________________________________+| + +------------------------------------------------+ + + There, now that I have the hype outta the way, let me explain what +this program is. I'm releasing the source code to my 4-way scrolling +code so that others can learn from it. There aren't enough really +good resources out there for someone learning to program games, so I'm +trying to do my part to help. + +WHAT IT IS: + + The code is 100% assembly, for which I use MASM 6.0, so there may +be a few problems converting to Turbo Assembler. I also use the ".386" +directive, meaning that you can't run this code with a 286 or earlier. +But most of the code should be easily convertible. I haven't been +programming for 386's much so I really don't make the use of the 386 +registers like I could have. Mostly I just did it for some extra 386 +instructions. + + You'll need a VGA which can support mode 13h, the MCGA mode. This +code runs in "tweaked" MCGA mode, or what is called "Mode X". For more +information on Mode X, check out the 1991 - 1992 issues of Doctor Dobbs +Journal, wherein you will find Michael Abrash's excellent Graphics +Programming column. This is where I (and many others) found out about +Mode X, which is an excellent graphics mode for fast 256-color graphics. +Also, you can take a look at XLIB, YakIcons, FastGraph, etc which are all +graphics libraries (public domain or otherwise) which support Mode X +graphics and probably have some good documentation on programming the mode. +Additionally, check out _The Programmer's Guide to the EGA and VGA Cards_, +by Richard Ferraro, and _Power Graphics Programming_ (out of print, but +available directly from Que Books) by Michael Abrash. Finally, you can +ask about graphics programming on many newsgroups such as +"rec.games.programmer"... + +WHAT IT DOES: + + The code will allow you to create "tiled" background patterns and then +to omnidirectionally scroll over them. You could implement sprite routines +and then animate them over the background, but I haven't gotten this far +yet. The scrolling is always relational -- ie no "jump-to"'s, just "scroll +left", "scroll up", etc. Jump to would be very easy to implement, I just +haven't done it yet. + + It runs at about 60-70 fps on a 386/20, which means that it is operating +in under the time of one vertical refresh (_just_ under, according to some +timing I've done). This could probably be reduced, but the best way to +reduce it is to limit the speed at which it scrolls -- if you stick to +scrolling at most 8 pixels at a time in two axes or 16 pixels at a time +in one axis, it is very fast. More than that, and it occasionally takes +more than one refresh period even on my 486. Still, that should be +fast enough for just about any game. + + I also included some routines to generate maps, tiles, and palettes +so you can see the file formats. These are in C, and the executables +are around in case you don't care to recompile. None of the utilities +are exactly production quality. You'll have to look at the code to +figure out the arguments! Luckily you can just run them with no args +and they perform default behavior. + + Lastly, the program SCROLL.EXE is a demo of what it can do. In this +demo you can use one of two sets of keyboard controls to scroll around. +One, the default set of commands, lets you press up/down/left/right and +scroll in that direction. The other has "intertia" -- pressing up/down +left/right will accelerate you in that direction. You'll see what I +mean, just experiment. You can switch keyhandlers by pressing K. +You can also switch between the diagonal pattern map and a logo map +by pressing M. (By the way, it will eventually run out of memory loading +the maps and the diagonal map will screw up... don't worry about it, +it'd be fixed if I had more time). Try it out. + +CREDIT WHERE CREDIT IS DUE: + + People who (unknowingly) helped me out: + + Keyboard by Steven Dollins, Brown Computer Group. From his + KEYINT routines, which is an INT 9 handler to let you + keep track of many keys being pressed at the same time. + Graphics, basically, by Michael Abrash, whose Mode X columns + influenced me greatly. + Palette fades and file I/O by the Future Crew. Thanks for + letting out the Mental Surgery code! + CPU detection by Ray Duncan, taken from one of his books. + + Obviously I haven't just pirated the code, it's all from publicly +released source code and I modified it a bit. But I wouldn't have come +up with this whole thing without those helping hands. Thanks. + +HOW IT WORKS: + + Here's how the scrolling works. I'll explain it from a single-page +point of view, although it actually uses several pages of video memory. +The video memory is laid out like this: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍ» ÄÄÄ +º ³ / / / / º ³ +º ³/ / / / º ³ +º ³ / / / /º ³ +º Visible page ³ / Not / / º ³ +º ³/ visible/ º ³ +º ³ / / / /º 64K +º ³ / / / / º ³ +ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ/ / / / º ³ +º / / / / / / / / / / / / / / /º ³ +º / / / / / / / / / / / / / / / º ³ +º/ / / / / / / / / / / / / / / º ³ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +In other words, it has a virtual width greater than the actual screen +width, and a virtual height higher than the actual screen height. The +VGA hardware allows hardware panning around within the virtual area, so +that makes panning much easier: you only have to draw the information +that is coming on to the screen with each pan. + +What is Happening: What the user sees: +ÉÍÍÍÍÍÍÍÍÑÍÍÍÍ» ÚÄÄÄÄÄÄÄÄ¿ +º hel³////º ³ hel³ The picture that is +ÇÄÄÄÄÄÄÄÄÙ////º ÀÄÄÄÄÄÄÄÄÙ coming on to the screen +º/////////////º ("hello") appears to +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ the user to be scrolling +ÉÍÑÍÍÍÍÍÍÍÑÍÍÍ» ÚÄÄÄÄÄÄÄÄ¿ left, although it is +º/³ hell³///º ³ hell³ actually at a stationary +º/ÀÄÄÄÄÄÄÄÙ///º ÀÄÄÄÄÄÄÄÄÙ location in memory... +º/////////////º Each time the frame moves, +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ it is not necessary to +ÉÍÍÑÍÍÍÍÍÍÍÑÍÍ» ÚÄÄÄÄÄÄÄÄ¿ redraw the parts that stay +º//³ hello³//º ³ hello³ on the screen, just the +º//ÀÄÄÄÄÄÄÄÙ//º ÀÄÄÄÄÄÄÄÄÙ parts that become visible. +º/////////////º +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ + + The same works up&down too, or even left/right and up/down at the same +time. The problem occurs when you scroll enough to hit the edge of the +virtual space. Luckily, video memory increases and wraps at the right +edge to one line down on the left edge. So you end up with a situation +like this after scrolling too far right: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍ» ÄÄÄ +ÇÄÄÄÄÄÄÄ¿//////³ º ³ User sees: +º ³//////³ Thº ³ ÚÄÄÄÄÄÄÄÄÄÄÄ¿ +ºe quick³//////³ º 64K ³ ³ +º ³//////ÀÄÄÄĶ ³ ³ The quick³ +ÇÄÄÄÄÄÄÄÙ///////////º ³ ³ ³ +º///////////////////º ³ ÀÄÄÄÄÄÄÄÄÄÄÄÙ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +The wrapping is transparent to the user. So, it appears that you can +scroll left & right infinitely, by simply always updating the amount of +memory that has scrolled into view. + + But what happens when you scroll too far down? Now Intel segments come +to the rescue! Because the video memory is 64K, and that is also the +largest amount of memory you can access in a segment, the segment arithmetic +performs the top-to-bottom wrapping for me. It results in a similar +situation as is pictured above, but with the screen split horizontally +instead of vertically. Again, it's completely transparent to the user. + + One performance optimization that I've done is to organize the background +picture that is being scrolled into quantitized "tiles" -- 16x16 pixels in +area. This means that you can store a large amount of picture data if that +data is repetitive -- as the backgrounds of many video games are. This also +helps when figuring out how much new stuff to draw on the screen. I can wait +until the panning crosses a 16-pixel border, then draw another 16-pixel +strip, and then wait for another tile crossing, etc. You can see this in +the MAP.INC and SCROLL.INC code. 16x16 pixels also leads to 256-pixel-square +tiles, which is always a convenient number in assembly... it helps out in +several places in the code. + + So, the display page is "wandering" around the video memory, only drawing +what is necessary at any time. Meanwhile you can animate sprites over the +background, etc. The only problem is that with one page, information is +constantly being drawn to that page and you can never guarantee that it is in +a correct state at the time of a vertical refresh period. Instead, I actually +use several pages, so that one can be shown while the other is worked on. +This guarantees a perfect picture at any time. So for now, let's ignore the +scrolling for a second, and talk about the paging, because it's easier to +understand the paging if scrolling isn't happening. + + Here's a basic explanation of how the paging works. I use three separate +pages, a Draw page, a Show page, and a Blank page. The Show page refers to +the page that is currently showing, the Draw page to the page that is +under construction (to be shown next frame), and the Blank page should always +be maintained as an up-to-date blank background page. (The Blank page is +useful for sprite programming which I am going to be doing next.) Each +of the pages is 352x240, although the screen resolution is only 320x200. + + Each frame, the pages rotate DrawPage->ShowPage->BlankPage->DrawPage. +This means that at the beginning of the frame, the Draw Page is already +blank, so all that is necessary is to draw on a bunch of sprites. The +BlankPage, though, is no longer blank (it's still got stuff from what +was the ShowPage) so we have to erase it, by blanking out the sprites +(luckily the new DrawPage _is_ empty, so we can use a Mode X 32-bit video- +to-video copy to blank it). Hope you're still with me. + + So, this loop continues with each frame, and the loop invariants are +maintained: Show Page is always a "good" frame -- don't touch it. Blank +Page is always blank. Draw Page can look like anything. Now to include +the scrolling again: + + The way I do scrolling with several pages is that the pages ALL wander +around video memory, only they're smaller (1/3 of the size that they could +have been, to be exact!). Here's a picture of the situation at its worst: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ÄÄÄ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º ³ +º/////ÚÄÄÄÄÄÄÄĺ ³ +ºÄÄ¿//³PAGE 0 º ³ +º ³//³ (Draw) º ³ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º 64K +º/////ÚÄÄÄÄÄÄÄĺ (21K each page) +ºÄÄ¿//³PAGE 1 º ³ +º ³//³ (Show) º ³ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º ³ +º/////ÚÄÄÄÄÄÄÄĺ ³ +ºÄÄ¿//³PAGE 2 º ³ +º ³//³ (Blank)º ³ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +The pages always maintain an equal distance apart as they wander. Since +all pages move in parallel, the way it used to work is that as soon as the +pages scrolled, I would draw the newly-visible picture information on +all three of the pages. This worked great, except that it resulted in +a slight pause every time the screen scrolled because it was doing hardware +pan most of the time (which is very fast) and the drawing routines were +slow. Now, I've spread the copying over successive frames to allow a +smoother scrolling rate. This is possible because it's not really necessary +to draw the new information to a page before that page becomes the show +page... + + I hope that this has made some sense. It's pretty complicated stuff. +Take a look at the code and maybe that will help. Or, write me mail +(my email address is below). Or, design your own way and ignore this +whole thing. + +COMING SOON: + + Next up are Sprite routines. I threw in what I started as SPRITE.INC, +although it's not included in the project right now. + Sound support + + Who knows what else? Depends on what people send me! + +------------------------------------------------------------------------- + R E A D T H I S +------------------------------------------------------------------------- + R E A D T H I S +------------------------------------------------------------------------- + + This code is being released as "SwapWare". That means that if you wanted +to go ahead and use my code directly, I really wouldn't care. But I ask +that you send me some of your code that you think is neat. Especially if +it's modifications that you make to this code, such as quick sprite drawing +or optimizations. + + I'm not going to brag and say that I "threw this together in a few hours". +I didn't, it took me many days of work to get it working properly. But +I'm also not looking for money as recompensation for my labor. I make +great money at my real day job and you probably have a better use for your +donations, such as legitimizing your unregistered shareware and pirated +games. I'm in this for the knowledge ... so my best payback would be to +get lots of code from people out there, stuff to really help make a great +game. In particular, these would be great: + * 32-bit code + * Tricky optimizations + * Fast BitBlt/masked BitBlt code + * Useful File I/O functions + * 3D polygon and texture mapping code + * Maintenance routines -- like numeric conversions, etc. + * Hardware access code like timing routines and interrupt + handlers +Any of those would be very helpful when writing a fast scrolling game. + +You can contact me (for the rest of this term only) at + seisner@athena.mit.edu +Feel free to ask any questions you want! I check my mail about once or +twice a week so don't expect instant turnaround... If you're desperate +to talk to me, say if you work at Origin and want to give me the source +code to Strike Commander or whatnot, you can also reach me at: + Steve Eisner + (617) 247-8691 +and leave a message. But I'd rather you wrote e-mail. + + Thanks, + Steve Eisner + +* Read rec.games.programmer! And for those who already do: + I dream of a world where no one argues over why Wolfenstein + 3-D sucks or why it doesn't. Would people just give it a + break? + \ No newline at end of file diff --git a/16/scrasm/SCROLL.EXE b/16/scrasm/SCROLL.EXE new file mode 100644 index 0000000000000000000000000000000000000000..8181acf10f9d8d572a19b978175493810c0e29c9 GIT binary patch literal 33596 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 Lze7_yL8<=(g0?ev literal 0 HcmV?d00001 diff --git a/16/scrasm/SCROLL.INC b/16/scrasm/SCROLL.INC new file mode 100644 index 00000000..be58c025 --- /dev/null +++ b/16/scrasm/SCROLL.INC @@ -0,0 +1,441 @@ +;; Global variables used here ... +EVEN +ScrollPosX dw 0 ; Scroll origin, upper-left X +ScrollPosY dw 0 ; Scroll origin, upper-left Y +ScrollDX dw 0 ; Amount to change scroll origin, X +ScrollDY dw 0 ; Amount to change scroll origin, Y + +;; SCROLL: +;; This routine takes care of all of the scrolling, however it calls +;; outside drawing routines to update the screen. Scrollx and +;; Scrolly determine the amount to scroll by. +;; Note that this does only RELATIVE scrolling, not absolute scrolling. +;; Scroll saves time by updating only up to the one row or column of +;; tiles which have come into view due to a change in scroll offset. +;; In other words, it's not good for "jumping" to a particular point, +;; although this effect can be accomplished in other ways -- the draw_full +;; routine is available to draw a full screen again. +;; Sometimes this means that you will have to calculate values ahead of +;; time, for instance if you wish the scrolling to keep a certain sprite +;; in the center of the screen. In this case, just set ScrollDX and +;; ScrollDY to the delta-x and delta-y of the sprite. +;; * Newly added: +;; Since there are three pages, it is necessary to keep each one of them +;; up to date with each scroll. Recently, I was doing some fast (8+ +;; pixels per frame) scrolling and noticed that there was a significant +;; pause when the screen snapped to a new origin. (The origin is always +;; at a square's corner, even though it may not look like it because it +;; disguises things by smooth-panning the hardware.) Every time it +;; scrolled, it was drawing the new information and copying it to the +;; two other planes. I've now distributed the load over successive +;; pages, in other words it doesn't copy the new info all at once, but +;; over several frames. This really smoothed out the scrolling so that +;; while there are still some jumps, they only occur very infrequently +;; and then only at 15 or 16 pixel/frame scroll rates...) That's the +;; "catchup" code at the bottom, and that's why it's more complex than +;; it maybe could be... +EVEN +Scroll PROC near + ; Using the ScrollDX variable as delta-x, move the scroll-origin + ; in the x direction. Then, if the visible screen is now + ; viewing invalid data, snap the origin to a new point and + ; draw any new columns that are necessary. +do_x_scroll: mov ax,cs:ScrollPosX + add ax,cs:ScrollDX ; ScrollDX is a delta-x + jl wrap_l ; wrap left if negative + cmp ax,VIRTUAL_WIDTH - SCREEN_WIDTH ; too far right? + jge wrap_r ; wrap right if too big + mov cs:ScrollPosX,ax ; Stores new scroll-x + ; (just like above, for y:) + ; Using the ScrollDY variable as delta-y, move the scroll-origin + ; in the y direction. Then, if the visible screen is now + ; viewing invalid data, snap the origin to a new point and + ; draw any new rows that are necessary. +do_y_scroll: mov ax,cs:ScrollPosY + add ax,cs:ScrollDY ; ScrollDY is a delta-y + jl wrap_t ; wrap top if negative + cmp ax,(VIRTUAL_HEIGHT - SCREEN_HEIGHT) * VIRTUAL_WIDTH + jge wrap_b ; wrap bottom if too big + mov cs:ScrollPosY,ax ; Store the new scroll-y + jmp calculate + + ; To wrap to the right: + ; Add a square's width to the origin's upper left corner, and + ; subtract the same amount from the scroll origin's upper left + ; corner. This makes no difference on the screen but allows + ; us to forget about the leftmost column on the screen (it's + ; offscreen now...) so we can take over the right column. + ; See any documentation I included for an explanation of the +EVEN ; scrolling... +wrap_r: add cs:upper_left,SQUARE_WIDTH / 4 + sub ax,SQUARE_WIDTH + mov cs:ScrollPosX,ax + + mov dx,MapInfo.Wid + mov bp,MapInfo.OffX1 + inc bp + cmp bp,dx + jb wrap_r1_ok + sub bp,dx +wrap_r1_ok: mov MapInfo.OffX1,bp + + mov bp,MapInfo.OffX2 + inc bp + cmp bp,dx + jb wrap_r2_ok + sub bp,dx +wrap_r2_ok: mov MapInfo.OffX2,bp + + mov bp,MapInfo.WrapX + dec bp + jnz wrap_r3_ok + add bp,dx +wrap_r3_ok: mov MapInfo.WrapX,bp + + call update_right + jmp do_y_scroll ; Jump back to do Y + +EVEN ; Same for left side +wrap_l: sub cs:upper_left,SQUARE_WIDTH / 4 + add ax,SQUARE_WIDTH + mov cs:ScrollPosX,ax + + mov dx,MapInfo.Wid + mov bp,MapInfo.OffX1 + dec bp + cmp bp,dx + jb wrap_l1_ok + add bp,dx +wrap_l1_ok: mov MapInfo.OffX1,bp + + mov bp,MapInfo.OffX2 + dec bp + cmp bp,dx + jb wrap_l2_ok + add bp,dx +wrap_l2_ok: mov MapInfo.OffX2,bp + + mov bp,MapInfo.WrapX + inc bp + cmp bp,dx + jbe wrap_l3_ok + sub bp,dx +wrap_l3_ok: mov MapInfo.WrapX,bp + + call update_left + jmp do_y_scroll ; Jump back to do Y + +EVEN ; Same for bottom +wrap_b: add cs:upper_left,(SQUARE_HEIGHT * VIRTUAL_WIDTH) / 4 + sub ax,SQUARE_HEIGHT * VIRTUAL_WIDTH + mov cs:ScrollPosY,ax + + mov bp,MapInfo.OffY1 + mov dx,MapInfo.Extent + add bp,MapInfo.Wid + cmp bp,dx + jb wrap_b1_ok + sub bp,dx +wrap_b1_ok: mov MapInfo.OffY1,bp + + mov bp,MapInfo.OffY2 + add bp,MapInfo.Wid + cmp bp,dx + jb wrap_b2_ok + sub bp,dx +wrap_b2_ok: mov MapInfo.OffY2,bp + + mov dx,MapInfo.Ht + mov bp,MapInfo.WrapY + dec bp + jg wrap_b3_ok + add bp,dx +wrap_b3_ok: mov MapInfo.WrapY,bp + + call update_bottom + mov ax,cs:ScrollPosY + jmp calculate ; Jump down to calc new offsets + +EVEN ; Same for top +wrap_t: sub cs:upper_left,(SQUARE_HEIGHT * VIRTUAL_WIDTH) / 4 + add ax,SQUARE_HEIGHT * VIRTUAL_WIDTH + mov cs:ScrollPosY,ax + + mov bp,MapInfo.OffY1 + mov dx,MapInfo.Extent + sub bp,MapInfo.Wid + cmp bp,dx + jb wrap_t1_ok + add bp,dx +wrap_t1_ok: mov MapInfo.OffY1,bp + + mov bp,MapInfo.OffY2 + sub bp,MapInfo.Wid + cmp bp,dx + jb wrap_t2_ok + add bp,dx +wrap_t2_ok: mov MapInfo.OffY2,bp + + mov bp,MapInfo.WrapY + mov dx,MapInfo.Ht + inc bp + cmp bp,dx + jbe wrap_t3_ok + sub bp,dx +wrap_t3_ok: mov MapInfo.WrapY,bp + + call update_top + mov ax,cs:ScrollPosY + jmp calculate ; Jump down to calc new offsets + +EVEN +align_mask_table DB 11h,22h,44h,88h +calculate: + ; Calculate the scroll offset + ; AX already = ScrollPosY + add ax,cs:ScrollPosX ;Now AX = scroll offset + + ; Calculate the plane alignment + mov bl,al + and bx,0003h + mov cs:DrawPage.Alignment,bl +; mov bl,cs:align_mask_table[bx] +; mov cs:DrawPage.AlignmentMask,bl + + ; Now we don't need Scroll Offset on a pixel level any more, + ; so shift it to a byte level (/4) and store it away. + shr ax,2 + mov cs:DrawPage.ScrollOffset,ax + + ; Calculate the actual upper left corner address + mov si,cs:DrawPage.Address + add si,cs:upper_left + mov cs:DrawPage.UpperLeftAddress,si + + ; And the map offset: + mov bx,MapInfo.WrapX + mov cs:DrawPage.MapPosX,bx + mov di,MapInfo.WrapY + mov cs:DrawPage.MapPosY,di + + mov cs:DrawPage.Valid,1 + cmp cs:BlankPage.Valid,0 + je no_catch_up + + ; Lastly, update dirty area (if any) on blank page. + ; BP still contains the draw page's mapoffset. + sub bx,cs:BlankPage.MapPosX + sub di,cs:BlankPage.MapPosY + jnz yes_catch_up + cmp bx,0 + jnz yes_catch_up + ; No catchup necessary -- return. +no_catch_up: ret + +;; Okay, this stuff is a mess. I've registerized everything except +;; for the video data itself. I'll try to comment it best I can. +EVEN +yes_catch_up: + ; First, switch into full-copy mode. This means latching the + ; bit mask as coming entirely from the local 32-bit registers + ; and then setting the map mask to write to all 4 planes. This + ; is Mode X's greatest advantage, when you can do it! It + ; provides a 2x speedup or so... + mov dx,SC_INDEX ; Select Sequencer input + mov ax,0F02h + out dx,ax ; set map mask = all bits + + mov dx,GC_INDEX + mov ax,ALL_COPY_BITS + out dx,ax + + JKEYNP kB,isntbp +isbp: nop +isntbp: + ; Next, calculate the amount to catch up the top/bottom rows + ; If we just wrapped over the edge, it is possible that the + ; distance traveled will be as high as MapInfo.Ht - 1. So, + ; in the fashion of signed numbers, if the number is greater + ; than MapInfo.Ht / 2, we take it to mean negative. To convert + ; it to signed, we have to shift it into the proper range. But + ; if it's less than MapInfo.Ht / 2, then it's okay as it is. + mov ax,di + cmp ax,0 + je y_mod + + mov cx,MapInfo.Ht + cwd ; DX = -1 or 0 based on AX's sign. + and dx,cx ; DX = Ht or 0 + add ax,dx ; AX = 0 ... Ht (unsigned) + + mov di,ax + shl di,1 + cmp di,cx + jb y_signed + sub ax,cx +y_signed: neg ax + + ; Find DI MOD MapInfo.Wid, and then convert to it into virtual + ; coordinates from map offset coordinates. + ; This routine also calculates BP, which will be used as a loop + ; counter to determine how many rows to draw on the left/right + ; column copy. +y_mod: mov bp,ax + cwd + add bp,dx + xor bp,dx + shl bp,3 ; BP = (SQUARE_HEIGHT / 2) * dX + mov di,cs:MultVirtWidth[bp] ; Use multiplication table + add di,dx ; to calculate new DI, then + xor di,dx ; restore the sign. + sub bp,VIRTUAL_HEIGHT / 2 + ; Out: DI = # of pixels traveled, + ; BP = (VIRTUAL_HEIGHT - # of rows) / 2 + + ; Change BX (delta-x) to signed from unsigned, store in AX + mov ax,bx + mov cx,MapInfo.Wid + cwd + and dx,cx ; DX = Wid or 0 + add ax,dx ; AX = 0 ... Wid + + mov bx,ax + shl bx,1 + cmp bx,cx + jb x_signed + sub ax,cx +x_signed: + + ; The following is an optimization which would slow down on + ; normal memory, but I believe it will be okay on VGA memory, + ; which is so incredibly slow. Basically, I've replaced all + ; "rep movsb"'s with a loop that first calculates "bx = di - si", + ; and then loops performing "mov ds:[si],es:[si+bx]". Why? + ; Because of several reasons, none of which I'm sure actually + ; help out, but they do make for smaller code. 1) It means that + ; I only have to maintain SI, and "DI" is maintained automatically + ; (because DI - SI should remain constant). 2) Don't have to + ; calculate DS. Not much gain here. 3) Because I'd already + ; unrolled the loops, and the "rep movsb"'s had become instead + ; "mov al, ds:[si] / mov es:[di], al / mov al, ds:[si + 1] / + ; mov es:[di + 1],al ... etc ... add si, 4 / add di, 4". In + ; other words, I wasn't using MOVSB anyway. The only advantage + ; I can see in MOVSB is that it doesn't have to store the answer + ; in AL so it could be slightly faster. By unrolling the loops, + ; I'd already made up for that, I think. 4) Normally, using + ; [SI + BX + 1] would incur a penalty of an additional clock + ; cycle (because it has to add two indexs + an offset). But + ; the VGA memory and the '86 CPU can multi-task, and the VGA + ; is very slow. So by the time the VGA is ready to write the + ; next byte, the one extra clock cycle has already passed. + ; + ; Am I right? Does this make things faster? I have no idea. + ; I haven't bothered to check both ways. Please let me know + ; if I've missed something important... + ; + ; Here's the calculation of BX. SI is already set. + ; si already = DrawPage.UpperLeftAddress + mov bx,cs:BlankPage.Address + sub bx,cs:DrawPage.Address + + ; Now, converts SI into "1/4" units. I do all the calculations + ; in "1/4" scale and then scale back up, mostly because it saved + ; me some instructions elsewhere. + shr si,2 + ; Stores this value of SI. This will be restored after doing + ; the top/bottom copying. + mov dx,si + + ; Check if it's necessary to catch up the top or bottom. +catchup_tb: cmp di,0 + je catchup_tb_end + jl catchup_t +catchup_b: ; COPY BOTTOM + ; Move SI to point at the bottom of the screen - # of rows + ; to update. + add si,((VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4) / 4 + sub si,di + jmp copy_tb +catchup_t: ; COPY_TOP + ; Leave SI, but add to the "pushed" value of SI the number of + ; rows that will be drawn. This prevents overlap between top + ; and right/left when moving diagonally. Also, DI = |DI| + neg di + add dx,di + + ; Now do the actual copying. Shifts SI back into scale "1", + ; then performs an unrolled loop to copy the entire virtual + ; width * # of pixel rows. Since DI is already in "1/4" scale, + ; it is only decremented once for each four pixels drawn. +copy_tb: shl si,2 +copy_tb_loop: mov cl,es:[si] + mov es:[si+bx],cl + mov cl,es:[si+1] + mov es:[si+bx+1],cl + mov cl,es:[si+2] + mov es:[si+bx+2],cl + mov cl,es:[si+3] + mov es:[si+bx+3],cl + add si,4 + dec di + jnz copy_tb_loop +catchup_tb_end: + + ; Next, check to see if it's necessary to draw the right or + ; the left side. +catchup_rl: cmp ax,0 + je catchup_rl_end + jg catchup_l +catchup_r: ; COPY RIGHT + ; Adds to the "pushed" SI the width of the screen, minus + ; the number of rows to be drawn. + neg ax + add dx,(VIRTUAL_WIDTH / 4) / 4 + sub dx,ax +catchup_l: ; COPY LEFT (or nothing) + + ; Does the actual copying. First pops SI from its stored value + ; and shifts it back into scale "1" +copy_rl: mov si,dx + shl si,2 + + ; This is a loop over BP -- which has already been set as + ; VIRTUAL_HEIGHT - (# of bytes drawn in vertical update) + ; Again, this loop is unrolled such that it does two rows @ + ; 4 bytes each with every iteration. + ; This LEA instruction is just a quick MOV DI, SI + 2 *y + ; DI is used to push the next value of SI for each iteration + ; of the loop. +copy_rl_loop: lea di,[si + 2*(VIRTUAL_WIDTH/4)] + mov cx,ax +copy_rl_col: mov dl,es:[si] + mov es:[si+bx],dl + mov dl,es:[si+1] + mov es:[si+bx+1],dl + mov dl,es:[si+2] + mov es:[si+bx+2],dl + mov dl,es:[si+3] + mov es:[si+bx+3],dl + mov dl,es:[si+VIRTUAL_WIDTH/4] + mov es:[si+bx+VIRTUAL_WIDTH/4],dl + mov dl,es:[si+VIRTUAL_WIDTH/4+1] + mov es:[si+bx+VIRTUAL_WIDTH/4+1],dl + mov dl,es:[si+VIRTUAL_WIDTH/4+2] + mov es:[si+bx+VIRTUAL_WIDTH/4+2],dl + mov dl,es:[si+VIRTUAL_WIDTH/4+3] + mov es:[si+bx+VIRTUAL_WIDTH/4+3],dl + add si,4 + dec cx + jnz copy_rl_col + mov si,di ; SI = pop (SI + VIRTUAL_WIDTH/4) + inc bp ; (BP is negative, so INC it) + jnz copy_rl_loop +catchup_rl_end: + + ; Switch back to all-draw mode. + mov dx,GC_INDEX + mov ax,ALL_DRAW_BITS + out dx,ax + ret +Scroll ENDP + \ No newline at end of file diff --git a/16/scrasm/SCROLL.LNK b/16/scrasm/SCROLL.LNK new file mode 100644 index 00000000..275ba401 --- /dev/null +++ b/16/scrasm/SCROLL.LNK @@ -0,0 +1,2 @@ +main.obj+lztimer.obj +scroll; diff --git a/16/scrasm/SCROLL.MAP b/16/scrasm/SCROLL.MAP new file mode 100644 index 0000000000000000000000000000000000000000..0b18f2bfd53fc0be47f22d8f609a476a270c1ee1 GIT binary patch literal 344 zcmbV{T?)c55QL|7+xU}Mt*zDguhA3u-~qfyK@dUo{!ewcRj8sbE(|kYW?9JblArIl z{0dtX78(Z+JSp}NIthFq2hVSmN_@j^kPJ}Dfm$6<pOsqBxC!D$<Pa%Sk(z+AdZXJ+ zJq;R8L8E78=4*;cB>S(-{$CS>T|{AwAdA_nEbQLDIm3LhT&*|!`q9+(-1gV(9&^$W A(f|Me literal 0 HcmV?d00001 diff --git a/16/scrasm/SCROLL.PAL b/16/scrasm/SCROLL.PAL new file mode 100644 index 0000000000000000000000000000000000000000..5dee1969fc3e9dfe5bee855460c512ba3a850e69 GIT binary patch literal 768 zcmWO4fugA}007W2rBcR}O4&6{OBqvI%Gm$^)qCd~4gg>dt%dE`E^_?PL#dC+Ix03v zg)<S7c29?d=>s=;JrU8Lq&#;GQ)M~QO6RqSZwB9WAV;TF@YMk&t+()|8fhN>SZXNw zlH!w9V<LvA?eWkd{q)VlorK*tP+md9L3x3+uyg9he?C5<Aj3`?!8id?X6=Z#r3kSw z;OVL+t|*qWvN{1(I~xa}_1u_+nQYxVqx4kccja2rjmU8whaB%&kWlA9V4eYzSf|K4 zW5iHc`f25o+AeOex&t9W+rr^xYvr1^KTW9DSpK5MB;_}wACiwW9vJR<(ACaUz=s5) zvl``HN5pk_F==54)y3af9hJzsHkCsxbX1!ipSG+=R0gD3Wu=?YWt3Yuh6vC60JzTF zh6@O6U^&3^AoA^S?WP-_U{r*-+D9Tu+Cw(vL=$RGY&!Fv)v^>#CCj>_H<jPVSZdsw z;AI@8;d=y=vUKPDBr+oW*6D|nkre~2dLp{4eI~;r(gK?XO;^9?uDsYy0ZR(#AIOg| z&TO2zLF_vbf;$Yhk%ba3$k2*}E=`w=SiFFBH4_5JcHRvOrR~u;dh$%~8@blaW-PIy zVVCb^oCtiVgPc2r!4m~%VzJCC6I4ZEjnf+<cfXKs)!O0(TLp$U&=WM;o_=m`eECJq z2bW{?KVsfzaYyiz1`p;44x1WWg~g?J=}@6UI;MY`98Hm#D%Bz$+ei(&PH&|_VhZYh R#ih%dB`qyNVV2L5_#e4jUwr@o literal 0 HcmV?d00001 diff --git a/16/scrasm/SCROLL.TIL b/16/scrasm/SCROLL.TIL new file mode 100644 index 0000000000000000000000000000000000000000..3b47a8e16873aff2b8cfc2bb04cbd1e44b8e4db0 GIT binary patch literal 9984 zcmeH}>vpR+3`YH{A-DDwc&TZ^J$?U|nElC!m;^{jyVjYmIcim7<1NXuY#PG<UOqzj z$V13;nw(}*d6iEo*^B%Ho6ZNH6ma;lZ|5d~n?d6f-(uIu2eM}V?cBfoe<FWgGOOFw z00odTxApMb`srF$KmR>DO4-Zu+wYE-7ycLg$qcMMwm451?r(j8`H-i|kUs2#rtj?8 zzS_F`$GkJ3Bk}Q^QB&u2hxB8b^GGx&cNN?7&#-QLu%QFE&i%-Q*o0SD&xDb>SN7nB z6u6BkI~p5UF=8ip*+}i&aGpNr_5auFq6EH9vx+~=|K`|#B6sn>?~lNp;HtafY3cua z4^$#LvhkE1D`@`Q@NP>sTzR~gD?e)^KuO)sZOf~tMQn)rLG8-tQ{p}~A62eY`-{9Y ziO;KVOvKAzeqFsUXS|KRoll*l&ogk&wL|0<J*|4vvS`a}*qt}ar&iroV9?a~n89@3 zqi5MMUai@Pmyc@bR<*cEwLMb?tlou9N@_1>#z@V^GM^fCTZ0YbEe5@MS~NL#H5>YR z=v-WDVtDWK`c~|e4!rCwFua-+eA`YC!oa(qN#JJC_#5_S%3_!JUl!fJFT;R8#P@rs zeO#yV@40@pT}<vTcxgFUo49m72I#&l^8Ydn_yfEhJ@$W1E!d|^p-b6jSC!Et(VScw z`JCrF8&h^PHn3upIq3~g-|YK*Z+*OPuRLFJ&w<)Cd0?{q-^JiQ31wNd`MA%YSi_{D zD?e)k+d=9vjoMLXZqmXyul}@rYYET7Ijc-m1*6lap{K<C<Z+`x*YP+p6a3LeqwKuZ z&Gf$d{G<hoONcfiZ${$hfASD|+;eThE3V<};Oi;T8f-1ZrnrFI)hfPc#k;zl#TM^> zQndQDBE~f&&p!636_YAm6XyawwEv&b+F`!WF`)nBV=%)!p5e7AW8UXDqt?fgw)buP ztc_%TYQy7(8~8;VgzzoV8ona|IL*geTjEnqZ9ROxJ7j#6!~6Stct5^};~@lo!yeuB zdIyXLbl9N7@rd$s*zdz0-R)2_GM<0iGhQ~(LpU7w{EZf#<aGln02F>?UQ1XM{t>{j zTob*5kIs2k2DTwH-S9ju<c`$6M;OTS*0<X%glwMX^1R{kVm6}pkZs|oJ=^Fwd<B2# za~=cG0yaw)v~sD7$M1dN`k4`1J9WdpYv1<l`3~7`gEZT2VBg+mV1~t$JxWLWzTZ<X zyIt6tZo_uF$+ED>V?()j>C@(2Tl*#~1mMNzgbYYsl>FJ%$B&<t9@7-Zf%0P!R`qOM zAp8gWA4}I*@u-KO+9iq0Jaf|R6Q9<+Vps@Yuzs%Yb>v8VZ)OXu^vx!)-#x2;#m$jt z_pa;TY&O~38&xnP&MR(@-PTP%=5Is&%vV4RUm1uNsG+|8WhJxfUnt-BpT{_XcKHCu zG(OmW9bj7nmCV^Y9QFqS(8Wgya}Kg>n~{RqBkbp&b-*7fA8t;L5Q&tHZMNkMg!%kk z%QtReygP}$mq+3EyDvD(js$Xe>0H-8yZiC{a(X$x7Q0^nI{!P$D9czo+qbm;;iwyc z`-8O~a1W=i1`9WSlTiTkd|$xV@QwAZ-F$c9x8*6c)n{mE8`{`s%=+=&=)LAvn%i@Q z*ndKeHU%yHx<obJ_x0XXecsu)jeTCKB3$Y-N?UoW=OT2BONaNGgLZny+>Ym#_bt!f zYFvG9TMP5r?`nk|?Y2C-T)r-suDf(?*L7{vwsl=M{M2<-*JW8%MNyPz$?1GLeSUsA z=k3?!>q|TagtrX>U03i`S(Rm36z6jR%rD}cw-*yR@45y9313CJEYFw#KjZ(7|N628 zz$<`;_~pK7DgrQG5fFg*&(wdv{}=YZWB=Q>gs<RB*012Je*O4ws`HszI8E&T7yI8e zMaQ1BO<fW~k*pu*4elG_uglYEdjBu%zj(sHMm6NmA}DI|UyCo!?Eh(E|1a!o$9UIP atiQrNHf;SQpfEib>_1C5pHx@c|9=5^-};gO literal 0 HcmV?d00001 diff --git a/16/scrasm/SPRITE.INC b/16/scrasm/SPRITE.INC new file mode 100644 index 00000000..9c3f2e48 --- /dev/null +++ b/16/scrasm/SPRITE.INC @@ -0,0 +1,280 @@ +; SPRITE routines +MAX_SPRITE EQU 100 + +RECTANGLE STRUCT 2,NONUNIQUE + X WORD 0 + Y WORD 0 + Wid4 BYTE 0 + Ht BYTE 0 + Color BYTE 0 + Next WORD 0 + ; DrawMe is used to not bother with sprites that you know + ; are contained totally within another, allowing animated + ; eyes, etc to be stored in separate sprites. These will be + ; drawn to the local buffer but skipped when copying to the + ; screen, so if they are not TOTALLY contained, they will + ; just get clipped away. + DrawMe BYTE 1 ; default, yes draw me. + ; (Storage from this point on ... NEVER provide anything but + ; default for these values!) + address_virt WORD 0 + address_buf WORD 0 + next_line_virt WORD 0 + next_line_buf WORD 0 +RECTANGLE ENDS + +SPRITE STRUCT 2, NONUNIQUE + RECTANGLE <> ; Contains rectangle info +SPRITE ENDS + +EVEN +rect5 SPRITE <<40 ,60 , 2,8, C_TRANSPARENT, 0 , 0>> +rect4 SPRITE <<80 ,30 , 2,8, C_TRANSPARENT, offset rect5, 0>> +rect3 SPRITE <<120,60 , 2,8, C_TRANSPARENT, offset rect4, 0>> +rect2 SPRITE <<55 ,100, 2,8, C_TRANSPARENT, offset rect3, 0>> +rect1 SPRITE <<105,100, 2,8, C_TRANSPARENT, offset rect2, 0>> + +rect6 SPRITE <<36 ,56 , 4,16, C_BLUE, offset rect1, 1>> +rect7 SPRITE <<76 ,26 , 4,16, C_BLUE, offset rect6, 1>> +rect8 SPRITE <<116,56 , 4,16, C_BLUE, offset rect7, 1>> +rect9 SPRITE <<51 ,96 , 4,16, C_BLUE, offset rect8, 1>> +rect10 SPRITE <<101,96 , 4,16, C_BLUE, offset rect9, 1>> + +;; Simply adding in these 5 rectangles (~20000 pixels for both +;; drawing and erasing) really slows things down! That's why +;; it's important to optimize the sprite drawing routines! +rect11 SPRITE <<35 ,55 ,14,36, C_GREEN, offset rect10, 1>> +rect12 SPRITE <<75 ,25 ,14,36, C_GREEN, offset rect11, 1>> +rect13 SPRITE <<115,55 ,14,36, C_GREEN, offset rect12, 1>> +rect14 SPRITE <<50 ,95 ,14,36, C_GREEN, offset rect13, 1>> +rect15 SPRITE <<100,95 ,14,36, C_GREEN, offset rect14, 1>> + +FIRST_SPRITE EQU rect10 + +EVEN +AnimateSprites PROC near + ret + ; Blank out the draw page, by copying from the blank page + ; to the draw page all rectangles which had changed. The + ; blank page must always be entirely blank if this is going + ; to work! + mov di,cs:DrawPage.UpperLeftAddress + add di,cs:DrawPage.ScrollOffset + mov si,cs:BlankPage.UpperLeftAddress + add si,cs:BlankPage.ScrollOffset + mov bp,cs:BlankPage.Rectangles + call CopyRectangles + + ; Now draw the sprites. Uses a temporary buffer to ensure + ; minimal drawing to the screen, but that's not really necessary, + ; if memory is at a minimum. It's just faster... + mov bp,offset FIRST_SPRITE + mov cs:DrawPage.Rectangles,bp + call do_fill_buffer + mov di,cs:DrawPage.UpperLeftAddress + add di,cs:DrawPage.ScrollOffset + mov bh,cs:DrawPage.AlignmentMask + mov bp,offset FIRST_SPRITE + jmp smart_rects ; "call" +AnimateSprites ENDP + +smart_dest DW 0 +out_di DW 0 +out_si DW 0 + +EVEN +smart_rects PROC near + add di,cs:DrawPage.Address + mov ds,cs:segBuffer + mov es,cs:segVideo + mov dx,3c4h + mov al,02h + out dx,al + inc dx + mov cs:smart_dest,di + + ; === Beginning of loop through rectangles! === +sp_nextrect: + cmp cs:[bp].RECTANGLE.DrawMe,1 + jne sp_next + ; Draw this rectangle from the buffer to screen memory. + ; Calculate the output address. + mov si,cs:[bp].RECTANGLE.address_buf + mov di,cs:[bp].RECTANGLE.address_virt + add di,cs:smart_dest + + ; Loop over 4 planes + mov bl,4 +sp_plane_loop: mov al,bh + out dx,al + + mov cs:out_di,di + mov cs:out_si,si + + ; Loop over height + mov ch,cs:[bp].RECTANGLE.Ht +sp_row_loop: + + ; Loop over width of rectangle (Wid4 is actually width/4) + mov cl,cs:[bp].RECTANGLE.Wid4 +sp_col_loop: + + ; Read a byte from the buffer + ; Is it transparent (no-modify)? If so, just jump over the draw + mov al,byte ptr ds:[si] + cmp al,C_TRANSPARENT + je sp_next_pixel + ; Otherwise, draw it on the spreen, and mark it transparent + ; so that it won't be drawn again. + mov byte ptr es:[di],al + mov byte ptr ds:[si],C_TRANSPARENT + + ; Skip to next 4-byte group (next column that can be drawn in + ; Mode X) Also increment spreen draw address, but only by 1 + ; because ModeX is 4 pixels per byte +sp_next_pixel: + add si,4 + inc di + + dec cl + jnz sp_col_loop + + ; End of row. Skip space to get to left edge of next row down + ; Skip SI = (SCREEN_WIDTH - #bytesdrawn) + ; Only draw up to height of rectangle + add si,cs:[bp].RECTANGLE.next_line_buf + add di,cs:[bp].RECTANGLE.next_line_virt + dec ch + jnz sp_row_loop + + mov di,cs:out_di + mov si,cs:out_si + inc si + rol bh,1 + adc di,0 + + dec bl + jnz sp_plane_loop + + ; Follow chain to next rectangle +sp_next: mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne sp_nextrect + ; All done +sp_end: ret +smart_rects ENDP + +; BP -> first rectangle. Follows BP->next, stops when BP = 0 +EVEN +do_fill_buffer PROC near + mov es,cs:segBuffer + + cmp bp,0 + je fill_end +fill_loop: + + mov bx,cs:[bp].RECTANGLE.Y + shl bx,1 ; BX = word index y + mov di,cs:MultBufWidth[bx] ; DI = SW * y + mov cx,cs:[bp].RECTANGLE.X ; CX = x + add di,cx ; DI = (SW * y) + x + mov cs:[bp].RECTANGLE.address_buf,di ; (DI used later) + + mov ax,cs:MultVirtWidth[bx] ; AX = (VW/4) * y + shr cx,2 ; CX = (x / 4) + add ax,cx ; AX = (VW * y + x)/4 + mov cs:[bp].RECTANGLE.address_virt,ax + + mov dx,(VIRTUAL_WIDTH / 4) + sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (VW - w) / 4 + mov cs:[bp].RECTANGLE.next_line_virt,dx + + mov dx,(SCREEN_WIDTH / 4) + sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (SW - w) / 4 + shl dx,2 ; DX = SW - w + mov cs:[bp].RECTANGLE.next_line_buf,dx + + mov ah,cs:[bp].RECTANGLE.Color + mov al,cs:[bp].RECTANGLE.Color + + mov ch,cs:[bp].RECTANGLE.Ht +fill_row_loop: mov cl,cs:[bp].RECTANGLE.Wid4 +fill_col_loop: mov es:[di],ax + mov es:[di+2],ax + add di,4 + dec cl + jnz fill_col_loop + add di,dx + dec ch + jnz fill_row_loop + + mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne fill_loop +fill_end: ret +do_fill_buffer ENDP + +EVEN +CopyRectangles PROC near + mov ax,cs:segVideo + mov ds,ax + mov es,ax + + ; Calculate the difference between the source and destination + ; pages. Since in a movsb loop the two would remain a constant + ; distance apart, we can just calculate a displacement and then + ; not have to worry about SI; instead use DI and DI+BX, thanks + ; to the thoughtful x86 ALU! + mov bx,di + sub bx,si + + mov dx,GC_INDEX + mov ax,ALL_COPY_BITS + out dx,ax + + mov dx,SC_INDEX + mov ax,0F02h + out dx,ax + mov si,di ;store destination + + ; === Beginning of loop through rectangles! === +cr_nextrect: cmp cs:[bp].RECTANGLE.DrawMe,1 + jne cr_next + ; Draw this rectangle from the buffer to screen memory. + ; Calculate the output address. + mov di,cs:[bp].RECTANGLE.address_virt + mov dx,cs:[bp].RECTANGLE.next_line_virt + add di,si + + ; Loop over height + mov ch,cs:[bp].RECTANGLE.Ht +cr_row_loop: + + ; Loop over width of rectangle (Wid4 is actually width/4) + mov cl,cs:[bp].RECTANGLE.Wid4 +cr_col_loop: mov al,ds:[di + bx] + stosb + dec cl + jnz cr_col_loop + mov al,ds:[di + bx] + mov es:[di],al + + ; End of row. Skip space to get to left edge of next row down + ; Only draw up to height of rectangle + add di,dx + dec ch + jnz cr_row_loop + + ; Follow chain to next rectangle +cr_next: mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne cr_nextrect + ; All done +cr_end: + mov dx,GC_INDEX + mov ax,ALL_DRAW_BITS + out dx,ax + ret +CopyRectangles ENDP + + \ No newline at end of file -- 2.39.5