home *** CD-ROM | disk | FTP | other *** search
- ; \|/
- ; O O
- ; --------------------------------oOO--U--OOo--------------------------------
- ; - -
- ; - 3d Starfield in 1Kb.
- ; - © Alain BROBECKER (baah/Arm's Tech) -
- ; - April-Sept 1996 -
- ; ---------------------------------------------------------------------------
- ; Wow, a nice starfield in 1Kb, with a bitplane effect, depth shading and a
- ; small logo. Some will say it could be even smaller, but please consider I
- ; don' t use FPU for creating tables and it runs at 50Hz on my 8Mhz Arm2 with
- ; 118*16=1888 stars drawn each VBl. (I went up to 2048 stars by unrolling the
- ; drawing loop and a faster CLS) In order to have the demo under 1Kb, I had
- ; to avoid the 'adr' and remove some tidies. (random germ, division rounding)
- ; By setting the 'normal' var to 1, you' ll have it assembled normally, else
- ; you' ll have the 1Kb tweaked version.
-
- #name 3dStars1Kb
- #set normal = 0 ; 1 for normal code, 0 for 1Kb.
-
- ;------ Constants -----------------------------------------------------------
- #set inv_N = 18 ; Shift for fixed point inverses.
- #set inv_nb = 2048 ; Nb of inverses to calculate.
- #set sin_N = 16 ; Shift for fixed point sinuses.
- #set sin_pow = 10 ; 2^sin_pow is the nb of angles.
- #set sin_nb = 1<<(sin_pow-3) ; Nb of angles between [0;pi/4[.
- #set eye2 = 8
- #set eye = 1<<(eye2-1) ; Distance between eye and camera.
- ;------ BSS Offsets ---------------------------------------------------------
- #set inverses = 0 ; Inverses table.
- #set sinus = inverses+4*inv_nb ; Sinus table.
- #set stars = sinus+4*sin_nb*10 ; Stars coords.
- #set end = stars+4*512*2*4
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** MACROS *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- ;====> Umul64 <=====================
- ; This macro performs an unsigned 32*32 bits multiply.
- ; [m0|m1]=m2*m3. You can choose [m2|m3]=[m0|m1]
- ; It destroys m0,m1,m4,m5,m6 and the flags. (C is the carry flag)
- macro umul64 m0,m1,m2,m3,m4,m5,m6
- { mov m4,m2,lsr #16 ; m4=up(m2).
- sub m5,m2,m4,lsl #16 ; m5=down(m2).
- mov m0,m3,lsr #16 ; m0=up(m3).
- sub m1,m3,m0,lsl #16 ; m1=down(m3).
- mul m6,m5,m0 ; m6=down(m2)*up(m3).
- mul m0,m4,m0 ; m0=up(m2)*up(m3).
- mlaS m6,m1,m4,m6 ; C+m6=up(m2)*down(m3)+down(m2)*up(m3).
- adc m0,m0,m6,lsr #16
- mul m1,m5,m1 ; m1=down(m2)*down(m3).
- addS m1,m1,m6,lsl #16
- adc m0,m0,#0 ; [m0|m1]=m2*m3.
- }
- ;====> Adjust64 <===================
- ; This macro adjusts the 64 bits result to 32 bits, according to the fixed
- ; point shift factor. (c0)
- ; m0=[m1|m2]>>c0. You can choose m1=m0.
- ; It destroys m0.
- macro adjust64 m0,m1,m2,c0
- { mov m0,m1,lsl #32-c0
- add m0,m0,m2,lsr #c0
- }
- ;====> Add64 <======================
- ; This macro performs a 64 bits addition.
- ; [m0|m1]=[m2|m3]+[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
- ; It destroys [m0|m1] and the flags.
- macro add64 m0,m1,m2,m3,m4,m5
- { addS m1,m3,m5
- adc m0,m2,m4
- }
- ;====> Sub64 <======================
- ; This macro performs a 64 bits substract.
- ; [m0|m1]=[m2|m3]-[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
- ; It destroys [m0|m1] and the flags.
- macro sub64 m0,m1,m2,m3,m4,m5
- { subS m1,m3,m5
- sbc m0,m2,m4
- }
- ;====> Random32 <===================
- ; This macro takes a random number, and makes a new one.
- macro random32 m0
- { eor m0,m0,m0,rrx
- adc m0,m0,m0,ror #7
- }
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** CODE *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- .proggy_start
- swi OS_WriteS ; Switch to mode 12 and then 9.
- dcb 22,12,22,9,0
- ALIGN
- swi OS_RemoveCursors ; Who needs them?
- adr r0,videoram_adress ; Get videoram adress.
- mov r1,r0
- swi OS_ReadVduVariables
- ; Change colors.
- adr r0,setpal_string ; Use this color format.
- mov r2,r0 ; r2 points on colors.
- mov r1,#6 ; Write 6 bytes.
- mov r14,#&f ; Nb of colors to change.
- ._one_color
- strB r14,[r0,#1] ; Save color number.
- ldrB r3,[r2,#-1]! ; Load value.
- strB r3,[r0,#3] ; Copy it as red.
- strB r3,[r0,#4] ; .. green.
- strB r3,[r0,#5] ; .. blue.
- swi OS_WriteN
- subS r14,r14,#1 ; One color changed.
- bGE _one_color
- #if normal
- adr r1,mouse_pointer ; Mouse pointer block.
- #else
- add r1,r0,#6
- #endif
- mov r0,#&15 ; Mouse pointer redefinition.
- swi OS_Word
- mov r0,#&6a ; Plot pointer.
- mov r1,#2 ; number 2 (delinked)
- swi OS_Byte
- ;----------------------------------------------------------------------------
- ; Creates the inverses table. This routine has been previously released
- ; through the "Memory War" article. (October 95)
- .make_inverses
- #if normal
- adr r0,bss+inverses+4 ; Create table here.
- #else
- mov r0,#&8400 ; Or here.
- #endif
- mov r1,#1 ; Used by the division routine.
- mov r2,#1 ; r2 is the current divisor.
- ._make_one_inverse
- mov r3,#1<<inv_N ; r3=dividend.
- mov r4,#0 ; r4 will contain the quotient.
- mov r5,#inv_N ; r5=Shift for the division.
- ._divide_one_step
- cmp r3,r2,lsl r5 ; dividend bigger than divisor<<r5?
- subGE r3,r3,r2,lsl r5 ; Yes, then dividend-=divisor<<r5,
- addGE r4,r4,r1,lsl r5 ; and add 1<<r5 to the quotient.
- subS r5,r5,#1 ; Next shift.
- bGE _divide_one_step
- #if normal
- cmp r2,r3,lsl #1 ; Flags=divisor-2*rest.
- addLE r4,r4,#1 ; Round to nearest integer.
- #endif
- str r4,[r0],#4 ; Save dividend/divisor.
- add r2,r2,#1 ; One inverse calculated.
- cmp r2,#inv_nb ; It was the last one?
- bNE _make_one_inverse
- ;----------------------------------------------------------------------------
- ; Creates the sinus table. As for the inverses creation, the routine has
- ; already been released through "Memory War".
- .make_sinus
- #if normal
- adr r0,bss+sinus ; Create table here.
- #endif
- ldr r1,sinA ; r1=sinA*2^28.
- ldr r2,cosA ; r2=cosA*2^28.
- mov r3,#0 ; r3=sin0*2^28.
- mov r4,#1<<28 ; r4=cos0*2^28.
- mov r5,#sin_nb+1
- .make_one_sinus
- mov r6,r4,lsr #28-sin_N ; r6=cosN*2^sin_N.
- str r6,[r0,#sin_nb*2*4] ; Save sin(N+pi/2)=cosN.
- mov r6,r3,lsr #28-sin_N ; r6=sinN*2^sin_N.
- str r6,[r0],#4 ; Save sinN.
- umul64 r6,r7,r1,r3,r8,r9,r10 ; [r6|r7]=sinN*sinA.
- umul64 r8,r9,r2,r4,r10,r11,r12 ; [r8|r9]=cosN*cosA.
- sub64 r6,r7,r8,r9,r6,r7 ; [r6|r7]=cos(N+1)=cosN*sin1-sinN*sin1.
- umul64 r3,r8,r3,r2,r9,r10,r11 ; [r3|r8]=sinN*cosA.
- umul64 r4,r9,r4,r1,r10,r11,r12 ; [r4|r9]=cosN*sinA.
- add64 r3,r8,r3,r8,r4,r9 ; [r3|r8]=sin(N+1)=sinN*cos1+cosN*sin1.
- adjust64 r3,r3,r8,28 ; r1=sin(N+1)=sinN*cos1+cosN*sin1.
- adjust64 r4,r6,r7,28 ; r2=cos(N+1)=cosN*sin1-sinN*sin1.
- subS r5,r5,#1 ; One sinus processed.
- bNE make_one_sinus
- sub r0,r0,#4 ; Complete the table by stupid copy.
- mov r1,r0 ; Point on the position which are like
- add r2,r0,#sin_nb*8 ; (pi/4+k*(pi/2)) 0<=k<=4
- mov r3,r2
- add r4,r2,#sin_nb*8
- mov r5,r4
- add r6,r4,#sin_nb*8
- mov r7,r6
- add r8,r6,#sin_nb*8
- mov r9,r8
- mov r10,#sin_nb+1 ; Copy sin_nb+1 values.
- ._make_sinus_copy
- ldr r11,[r0],#-4
- str r11,[r3],#4 ; sin(pi-X)=sinX.
- str r11,[r8],#-4 ; sin(2*pi+X)=sinX.
- rsb r11,r11,#0
- str r11,[r4],#-4 ; sin(pi+X)=-sinX.
- str r11,[r7],#4 ; sin(2*pi-X)=-sinX.
- ldr r11,[r2],#-4
- str r11,[r1],#4 ; cos(-X)=cosX.
- subS r10,r10,#1 ; One value copied.
- strNE r11,[r9],#4 ; cos(2*pi+X)=cosX. No copy if r10=0.
- rsb r11,r11,#0
- str r11,[r5],#4 ; cos(pi-X)=-cosX.
- str r11,[r6],#-4 ; cos(pi+X)=-cosX.
- bNE _make_sinus_copy
- ;----------------------------------------------------------------------------
- ; Randomly create starfield. (4 stars for each z)
- #if normal
- adr r0,bss+stars ; Create stars here.
- #else
- mov r0,#&8400+stars
- #endif
- add r1,r0,#4*512*4 ; We' ll copy them here too.
- mov r2,#512*4 ; Nb of stars to create.
- ldr r3,random_germ ; Load random germ.
- mvn r4,#&7f0000 ; Put &ff8001ff in r4.
- sub r4,r4,#&fe00
- .make_one_star
- and r5,r4,r3 ; r5=y|x. (Both in [0;511])
- str r5,[r0],#4 ; Save it.
- str r5,[r1],#4 ; Twice.
- random32 r3 ; Next random numbers.
- subS r2,r2,#1 ; One star created.
- bNE make_one_star
- ;----------------------------------------------------------------------------
- ; The demo begins here.
- .one_frame
- mov r0,#&13 ; Wait for Vsync.
- swi OS_Byte
- ldrB r12,workscreen_nb ; Load nb of previous workscreen.
- eor r12,r12,#1 ; New workscreen_nb.
- strB r12,workscreen_nb ; Save it.
- rsb r1,r12,#2 ; r1=new showscreen_nb.
- mov r0,#&71 ; And show it.
- swi OS_Byte
- ldr r1,videoram_adress
- add r0,r12,r12,lsl #2
- add r0,r1,r0,lsl #5+8 ; r0=video+workscreen*160*256.
- add r0,r0,#8*160
- ; Clear plane(0) and copy plane(i) to plane(i+1).
- mov r1,#%11101110 ; Put mask in r1.
- add r1,r1,r1,lsl #8
- add r1,r1,r1,lsl #16
- mov r2,#800
- ._clear_many
- ldmia r0,{r3-r14}:and r3,r1,r3,lsl #1:and r4,r1,r4,lsl #1
- and r5,r1,r5,lsl #1:and r6,r1,r6,lsl #1:and r7,r1,r7,lsl #1
- and r8,r1,r8,lsl #1:and r9,r1,r9,lsl #1:and r10,r1,r10,lsl #1
- and r11,r1,r11,lsl #1:and r12,r1,r12,lsl #1:and r13,r1,r13,lsl #1
- and r14,r1,r14,lsl #1:stmia r0!,{r3-r14}
- subS r2,r2,#1
- bNE _clear_many
- sub r0,r0,#160*240 ; r0 back to workscreen adress.
- ; Calculate addx,addy and addz.
- adr r1,addz
- ldmia r1,{r2-r3} ; r2=addz | r3=alpha.
- sub r2,r2,#3<<(32-9) ; addz-=3.
- add r3,r3,#1<<(32-sin_pow) ; alpha+=1.
- stmia r1,{r2-r3}
- add r1,r3,r3 ; r1=2*alpha.
- add r4,r1,r3 ; r4=3*alpha.
- #if normal
- adr r5,bss+sinus
- #else
- mov r5,#&8400+sinus
- #endif
- ldr r3,[r5,r3,lsr #32-sin_pow-2] ; r3=sin(alpha)<<sin_N.
- add r5,r5,#128*4 ; r5 points on cos table.
- ldr r1,[r5,r1,lsr #32-sin_pow-2] ; r1=cos(2*alpha)<<sin_N.
- ldr r4,[r5,r4,lsr #32-sin_pow-2] ; r4=cos(3*alpha)<<sin_N.
- mul r4,r3,r4 ; r4=cos(3*alpha)*sin(alpha)<<2*sin_N.
- mul r1,r3,r1 ; r1=cos(2*alpha)*sin(alpha)<<2*sin_N.
- mov r1,r1,lsr #2*sin_N-9
- mov r4,r4,asr #2*sin_N-9
- add r1,r1,r4,lsl #32-9 ; r1=addy | addx.
- ; Now we can draw the stars.
- ; r0=videoram adress r1=addy|addx r2=addz (bits 23-31)
- #if normal
- adr r3,bss+stars ; Make r3 points on first stars to draw.
- #else
- mov r3,#&8400+stars
- #endif
- add r2,r3,r2,lsr #32-9-4
- #if normal
- adr r3,bss+inverses+(512+eye)*4 ; r3 points on first z to use.
- #else
- mov r3,#&8400+inverses+(512+eye)*4
- #endif
- mov r4,#120<<(inv_N-eye2) ; For screen recentering.
- mov r5,#160<<(inv_N-eye2)
- mov r6,#%1000 ; Color to draw with.
- ._one_color
- mov r7,#118 ; draw 118 z with this color.
- ._four_stars
- ldr r8,[r3],#-4 ; r8=2^inv_N/(z+eye).
- mov r9,#4 ; Draw 4 stars with same z.
- ._one_star
- ldr r10,[r2],#4 ; r10=y|x.
- add r10,r10,r1 ; y+=addy | x+=addx.
- mov r11,r10,asr #32-9 ; r11=y+addy. (-256;255)
- mov r10,r10,lsl #32-9 ; Wrap x values.
- mov r10,r10,asr #32-9 ; r10=x+addx. (-256;255)
- mlaS r11,r8,r11,r4 ; r11=((y+addy)*eye/(z+eye))+120.
- mlaGES r10,r8,r10,r5 ; r10=((x+addx)*eye/(z+eye))+120.
- bMI _next_star ; Stop if x<0 or y<0.
- cmp r11,#240<<(inv_N-eye2)
- cmpMI r10,#320<<(inv_N-eye2)
- bGE _next_star ; Stop if x>=320 or y>=240.
- mov r11,r11,lsr #(inv_N-eye2) ; r11=y_screen. (0;255)
- add r11,r11,r11,lsl #2
- add r11,r0,r11,lsl #5 ; r11 points on good hline.
- tst r10,#1<<(inv_N-eye2) ; x odd or even?
- ldrB r10,[r11,r10,lsr #(inv_N+1-eye2)]! ; r11=(x/2;y) and load byte.
- orrEQ r10,r10,r6 ; If x even.
- orrNE r10,r10,r6,lsl #4 ; If x odd.
- strB r10,[r11] ; Save modified byte.
- ._next_star
- subS r9,r9,#1 ; One star drawn.
- bNE _one_star
- subS r7,r7,#1 ; Four stars drawn.
- bNE _four_stars
- movS r6,r6,lsr #1 ; Next color.
- bNE _one_color ; If color<>0 we continue to draw,
- swi OS_ReadEscapeState ; Escape key pressed?
- bCC one_frame ; No, so we continue.
- swi OS_Exit ; That' s all folks.
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** MAIN DATAS *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- .videoram_adress dcd 148,-1 ; Values for swi OS_ReadVduVariables.
-
- .random_germ ; The magical random number.
- #if normal
- dcd &eb1a2c37
- #endif
- .cosA dcd 268430403 ; cos((pi/4)/sin_nb)*2^28.
- .sinA dcd 1647089 ; sin((pi/4)/sin_nb)*2^28.
-
- .addz dcd 0 ; Speed along the z-axis.
- .alpha dcd 0 ; Angle for stars movements.
-
- dcb &00,&bb,&77,&ee,&55,&dd,&99,&ff ; Colors.
- dcb &44,&cc,&88,&ff,&66,&ee,&aa,&ff
- .setpal_string dcb 19,0,16,0,0,0 ; String format to set palette.
- .workscreen_nb ; Next byte will be used as this.
- .mouse_pointer
- dcb 0,2 ,8,7, 0,0 ; Redefine Mouse shape nb2 with Widht=32 | Height=7.
- dcd mouse_shape
- .mouse_shape
- dcb %00001010,%00000000,%00000000,%00000000 ; Here' s the logo.
- dcb %00000000,%00000000,%00001010,%00000000
- dcb %00001010,%00000000,%00000000,%00000000
- dcb %00000000,%00000000,%00001010,%00000000
- dcb %10001010,%00001010,%10101000,%00001010
- dcb %10101000,%00001010,%10001010,%00001010
- dcb %00101010,%00101000,%00001010,%00101000
- dcb %00001010,%00101000,%00101010,%00101000
- dcb %00001010,%00101000,%00001010,%00101000
- dcb %00001010,%00101000,%00001010,%00101000
- dcb %00001010,%00101000,%00001010,%00101010
- dcb %00001010,%00101010,%00001010,%00001010
- dcb %10101000,%00001010,%10101000,%00101000
- dcb %10101000,%00101000,%00001010,%00101010
-
- ;-----------------------> THIS MUST BE AT VERY END <-----------------------
- .bss
-