Amaze 2
; Amaze (fixed version) : 128-byte intro Wolfenstein 3D raycasting engine (fasm 1.70.03/WinXP 5.1.2600) ; fixed : 1)divide overflow error bug 2)flickering/tearing /w double-buffer 3)speed 4)viewpoint angle bug ; compatibility : XP/Win7 DOS ntvdm or size coding competition compliant systems (retrolandia.net/hugi/showthread.php?tid=4) ; credit : written by Olivier Poudade 2013 aka baudsurfer^red sector incorporated 1985 (olivier.poudade.free.fr) ; credit (auxilliary) : inspired by Justin Frankel^Nullsoft's 256-byte intro gaycast (www.1014.org/code) ; credit (auxilliary) ; original algorithm written by John Carmack^id Software (www.armadilloaerospace.com/n.x/johnc) ; credit (auxilliary) ; feedback (thank you) provided by Photon, Pirx, rain_strom, Sensenstahl, Shockwave, zorke ; greets : Adok, Frag, lordKelvin, Pirx, Rudi, Shockwave, y0bi ; shouts : dark bit factory forum users (www.dbfinteractive.com) org 100h ; program startup : start binary at psp+256 pop cx ; program setup : startup assumed sp=fffeh / cx=[sp]=[fffeh]=0 / sp=sp+2=0 pop es ; program setup : es=[sp]=20cdh double-buffer / sp=sp+2=0 pop fs ; program setup : fs=[sp]=ff9fh=a000h-16=(mode 13h video memory)-16 / sp=sp+2 / [sp+2]=9a00h mov al,13h ; program setup : set vga chained mode 320x256x8 and clear screen funtion int 10h ; program setup : vga video bios api clear screen function fldz ; maze angle : st0=ANGBEG fldz ; maze angle : st0=ANGVAL st1=ANGBEG BEGANG: es lodsb ; buffer to screen : al=[es:si++] mov [fs:si+7d0fh],al ; buffer to screen : 7d0fh=32015b=middle of *this column's screen offset (width*height/2) with ff9fh fixup / si=[32335;32015] loop BEGANG ; buffer to screen : 1st time cx=0=>no loop / after cx=[0ffffh;0]=[65535b;O] from "loop BEGANG" salc ; clear buffer : al=cf=0 fixed palette index color pixel dec cx ; clear buffer : cx-=1=>cx=0ffffh=65535b rep stosb ; clear buffer : [es:di++]=0 65535 times fadd dword [ANGADD] ; maze angle : st0=ANGVAL*ANGADD st1=ANGBEG / [cs:ANGADD]=3bb90372h=0.0056f as angle stepping fld st0 ; maze angle : st0=ANGVAL*ANGADD st1=ANGVAL*ANGADD st2=ANGBEG fld1 ; maze angle : st0=1 st1=ANGVAL*ANGADD st2=ANGVAL*ANGADD st3=ANGBEG faddp st3,st0 ; maze angle : st0=ANGVAL*ANGADD st1=ANGVAL*ANGADD st2=ANGBEG++ mov bp,319 ; column to screen : bp=screen width-1=xloop viewport index ADDANG: fadd dword [ANGADD] ; viewport angle : st0=(ANGVAL+ANGBEG)*ANGADD st1=ANGBEG*ANGADD st2=ANGBEG fld st0 ; viewport angle : st0=(ANGVAL+ANGBEG)*ANGADD st1=(ANGVAL+ANGBEG)*ANGADD st2=ANGBEG*ANGADD st3=ANGBEG fsincos ; viewport angle : st0=cos((ANGVAL+ANGBEG)*ANGADD) st1=sin((ANGVAL+ANGBEG)*ANGADD) st2=(ANGVAL+ANGBEG)*ANGADD st3=ANGBEG*ANGADD st4=ANGBEG fld st4 ; viewport angle : st0=ANGBEG st1=cos((ANGVAL+ANGBEG)*ANGADD) st2=sin((ANGVAL+ANGBEG)*ANGADD) st3=(ANGVAL+ANGBEG)*ANGADD st4=ANGBEG*ANGADD st5=ANGBEG fld st5 ; viewport angle : st0=ANGBEG st1=ANGBEG st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG mov cx,7e0h ; viewport angle : 07e0h=2016b=32*63 size of maze portion to cast ADDRAY: fadd st0,st3 ; raycast depth : st0=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) st1=ANGBEG st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG fist dword [si] ; raycast depth : [si]=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) fxch ; raycast depth : st0=ANGBEG st1=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG fadd st0,st2 ; raycast depth : st0=ANGBEG+cos((ANGVAL+ANGBEG)*ANGADD) st1=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG mov bx,[si] ; raycast depth : bh=[si+1]=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) fist dword [si] ; raycast depth : [si]=ANGBEG+cos((ANGVAL+ANGBEG)*ANGADD) fxch ; raycast depth : st0=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) st1=ANGBEG+cos((ANGVAL+ANGBEG)*ANGADD) st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG mov bl,[si+1] ; raycast depth : bl=[si+1]=ANGBEG+cos((ANGVAL+ANGBEG)*ANGADD) cmp byte [bx],ah ; raycast depth : test map wall hit ([bx]=0) at ray from null bitmask in code segment loopnz ADDRAY ; raycast depth : 1)if wall found exit raycast loop 2)ANGVAL++ 3)07e0h=2016b=32*63=maze portion to cast 4)else continue RAYHIT: neg cx ; wall found : cx=[1;2016] equivalent / fixup divide overflow add cx,7f0h ; wall found ; 07f0h=2032=32*63+16 / was add cx,10h when counter register increased mov ax,[ANGMUL] ; depth to height : [cs:ANGMUL]=3bb9h=15289d as zscale divisor lower word cwd ; depth to height : dx=0 divisor upper word div cx ; depth to height : cx=divisor=distance ax=result=wall height/2 dx=remainder mov cx,4 ; wall found : reset fpu stack state ... POPFPU: fstp st0 ; wall found : ... from : st0=ANGBEG+sin((ANGVAL+ANGBEG)*ANGADD) st1=ANGBEG+cos((ANGVAL+ANGBEG)*ANGADD) st2=cos((ANGVAL+ANGBEG)*ANGADD) st3=sin((ANGVAL+ANGBEG)*ANGADD) st4=(ANGVAL+ANGBEG)*ANGADD st5=ANGBEG*ANGADD st6=ANGBEG loop POPFPU ; wall found : ... to : st0=(ANGVAL+ANGBEG)*ANGADD st1=ANGBEG*ANGADD st2=ANGBEG xchg ax,cx ; depth to height : ax=0 cx=result=wall height/2 (dx=remainder) xchg ax,si ; height to screen : ax=previous column's lowest vertical pixel si=0 (dx=remainder) mov di,bp ; height to screen : di= this column's xloop viewport index cmp cx,3ch ; height to screen : clipping test (wall<120 ?) ANGADD: jc ADDTEX ; height to screen : no clipping needed ANGMUL: mov cx,3bh ; height to screen : clipping (-1 byte candidate with glitchy mov cl,3bh) ADDTEX: mov ax,cx ; height to screen : note this is where ah is nulled for test byte [bx],ah above ADDCOL: stosb ; column to screen : plot upper vertical pixel sub di,321 ; column to screen : get next upper vertical pixel mov [es:si+bp],al ; column to screen : plot lower vertical pixel add si,320 ; column to screen : get next lower vertical pixel loop ADDCOL ; column to screen : repeat until all pixels of *this column wall processed dec bp ; column to screen : decrement screen column index jnz ADDANG ; column to screen : repeat until all 320 columns [319,0] of this screen processed fstp st0 ; maze angle : st0=ANGBEG*ANGADD st1=ANGBEG loop BEGANG ; maze angle : process next frame / cx=0ffffh for next clear screen
[ back to the prod ]