home *** CD-ROM | disk | FTP | other *** search
- ; \|/
- ; O O
- ; --------------------------------oOO--U--OOo--------------------------------
- ; - -
- ; - - 2nd Intro for Coder's Revenge - -
- ; - © Alain BROBECKER (baah/Arm'sTeack) -
- ; - Oct 96 -
- ; ---------------------------------------------------------------------------
- ;
- ; Again a small demo for the fantastic "Coder's Revenge" disc magazine,
- ; by the Archiologics. ThanX to them for providing us this masterpiece,
- ; and don' t forget to contribute articles!
- ;
- ; This source is given for free and is widely commented, so I hope some
- ; people will look at it and (maybe) improve their own code. Re-use of my
- ; routines is allowed (though not recommended, cos you' ll understand more
- ; if you write your owns...) as long as it is not for commercial purposes,
- ; as long as you credit me and send me a free copy of your proggy. Oh, btw
- ; the assembler I used is ExtASM 0.50b. You' ll have to make changes in
- ; macros if you use a newer version of ExtASM.
- ;
- ; Alain BROBECKER Dracula / Positivity (STe)
- ; rte de Dardagny baah / Arm's Tech (Archie)
- ; 01630 CHALLEX baah (PC)
- ; FRANCE
-
- #name 2ndIntroCR ; tHa iNcReDibLe kEwl diScMaG...
-
- ;------ Constants -----------------------------------------------------------
- #set screennb = 3 ; Nb of mode13 screens.
- #set sin_N = 14 ; Shift for fixed point sinuses.
- #set sin_shift = 10 ; 2^sin_shift is the nb of angles.
- #set sin_nb = 1<<(sin_shift-3) ; Nb of angles between [0;pi/4[.
- #set tx_N = 7 ; Well, texture must be a power of 2, so
- #set tx_S = 1<<tx_N ; tx_S=2^tx_N is the size of texture.
- #set tx_Middle = 17 ; Intensity for null relief*2.
- #set fractal = 30 ; Value for shift of rnd nb in fracland.
-
- #set quad_N = 8 ; Shift for fixed point quadsplines.
- #set zoom_N = 7 ; Zoom is a 2<<zoom_N.
-
- ;------ BSS Offsets ---------------------------------------------------------
- #set stack = 4*128 ; Top of stack.
- #set sinus = stack ; Sinus table.
- #set edges = sinus+10*sin_nb*4 ; Source coords for scanline edges.
- #set end = edges+256*4*4+4096
-
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** 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
- }
- ;====> Swap32 <====================
- ; This macro exchanges two registers.
- macro swap32 m0,m1
- { add m0,m0,m1 ; m0=a+b.
- sub m1,m0,m1 ; m1=a+b-b=a.
- sub m0,m0,m1 ; m0=a+b-a=b.
- }
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** CODE *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- ;----------------------------------------------------------------------------
- ; Initialise stack, ask for slot+screen memory, switch to good video mode...
- .proggy_start
- adr r13,bss+stack ; Initialise stack pointer.
- mov r0,#bss+end-&8000 ; Ask for needed slot memory.
- mov r1,#-1 ; Don' t change next slot size.
- swi Wimp_SlotSize
- mov r0,#2 ; Ask for ScreenMem size.
- swi OS_ReadDynamicArea ; r1=current ScreenMem size.
- rsbS r1,r1,#(screennb+1)*81920 ; r1=needed-curent screenmem.
- movGT r0,#2 ; Ask for it if we don' t have enough.
- swiGT OS_ChangeDynamicArea
- swi 256+22 ; Vdu 22, set screenmode.
- swi 256+13 ; Switch to mode 13.
- swi OS_RemoveCursors ; Who needs them?
- adr r0,videoram_adress ; Get videoram adress.
- mov r1,r0
- swi OS_ReadVduVariables
- ;----------------------------------------------------------------------------
- ; Clear the bss section, since some routines need it. I assume that bss+end
- ; is longword aligned. (So you must take care when defining bss offsets)
- ; And then do the same with videoram.
- adr r0,bss+stack ; Begin to clear here.
- mov r1,#end-stack ; Nb of bytes to clear.
- bl clear_mempart
- ldr r0,videoram_adress ; Begin to clear here.
- mov r1,#(screennb+1)*81920 ; Nb of bytes to clear.
- bl clear_mempart
- ;----------------------------------------------------------------------------
- ; Creates the sinus table. As for the inverses creation, the routine has
- ; already been released through "Memory War".
- .make_sinus
- adr r0,bss+sinus
- 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
- ;----------------------------------------------------------------------------
- ; Creates the texture with the nice CR logo in it. Main idea is (as usual) to
- ; make a N*N fractal landscape, take the modulo of it, expand pixels which
- ; are in the logo, emboss and re-smooth.
- .make_fracland
- ldr r0,videoram_adress ; We create texture in videoram,
- add r0,r0,#screennb*81920 ; just after screenbanks.
- ldr r1,random_germ ; Load the random germ.
- mov r2,#1 ; This will be used by routine.
- strB r2,[r0] ; Also save 1 as upper left pixel.
- mov r3,#tx_N ; Iteration=tx_N.
- mov r4,#0 ; Position of upper left pixel.
- mov r5,#0
- bl recursive_landscape
- ldr r1,videoram_adress ; Adress of a second buffer.
- add r1,r1,#81920
- bl smooth_texture ; Smooth texture.
- ; Take the modulo(32) of whole image.
- mov r2,#tx_S*tx_S ; Nb of pixels to compute.
- ._modulo_one
- subS r2,r2,#1 ; One pixel will be computed.
- ldrB r3,[r1,r2] ; Load pixel.
- and r3,r3,#&1f ; Modulo operation.
- strB r3,[r1,r2] ; Save it.
- bNE _modulo_one
- ; Draw the logo on the texture by expanding the pixel in logoCR.
- mov r2,r1
- adr r3,logoCR
- ._logo_draw
- ldrB r4,[r3],#1 ; r4=offset.
- cmp r4,#&ff
- bEQ _end_logo
- add r2,r2,r4 ; r2 points on good offset.
- ldrB r4,[r3],#1 ; r4=nb_bytes.
- ._logo_draw_byte
- ldrB r5,[r2] ; Load value.
- mov r5,r5,lsl #5 ; Expand it.
- strB r5,[r2],#1 ; Save one pixel.
- subS r4,r4,#1
- bNE _logo_draw_byte
- b _logo_draw
- ._end_logo
- ; Emboss the texture and then smooth it again.
- ldr r1,videoram_adress ; Adress of the second buffer.
- add r1,r1,#81920
- .emboss_texture
- mov r2,#0 ; r2=y counter<<(32-tx_N).
- ._emboss_one_line
- sub r3,r2,#1<<(32-tx_N) ; r3=(y-1) mod tx_S <<(32-tx_N). (Wrapping)
- add r4,r3,#1<<(32-tx_N) ; r4=(y+1) mod tx_S <<(32-tx_N). (Wrapping)
- add r3,r1,r3,lsr #(32-2*tx_N); r3 points on src_line up.
- add r4,r1,r4,lsr #(32-2*tx_N); r4 points on src_line down.
- mov r5,#tx_S ; r5=nb of pixels per line.
- ._emboss_one
- ldrB r14,[r3],#1 ; r14=pixie up.
- ldrB r6,[r4],#1 ; r6=pixie down.
- sub r6,r6,r14 ; r6=delta.
- addS r6,r6,#tx_Middle ; Add the middle constant.
- movMI r6,#0 ; Make sure intensity is between 0-63.
- cmp r6,#63
- movGE r6,#63
- strB r6,[r0],#1 ; Save it.
- subS r5,r5,#1 ; One pixel done
- bNE _emboss_one
- addS r2,r2,#1<<(32-tx_N) ; Line done.
- bNE _emboss_one_line
- sub r0,r0,#tx_S*tx_S ; r0 points back on buffer.
- bl smooth_texture ; Smooth texture.
- swap32 r0,r1
- bl smooth_texture ; Smooth texture.
- swap32 r0,r1
- bl smooth_texture ; Smooth texture.
- ; Convert the texture using colormap.
- adr r2,tx_colors
- mov r3,#tx_S ; y counter.
- ._tx_convert_line
- mov r4,#tx_S ; x counter.
- ._tx_convert_one
- ldrB r5,[r1],#1 ; Load pixel.
- ldrB r5,[r2,r5] ; Convert it.
- strB r5,[r0],#1 ; Draw it.
- subS r4,r4,#1 ; One pixel done.
- bNE _tx_convert_one
- subS r3,r3,#1 ; One line done.
- bNE _tx_convert_line
- ;----------------------------------------------------------------------------
- ; Clear the screenbanks.
- ldr r0,videoram_adress
- mov r1,#screennb*81920 ; Nb of bytes to clear.
- bl clear_mempart
- ;----------------------------------------------------------------------------
- ; Enables our Vertical Blanking (VBl) interrupt.
- mov r0,#&10 ; Claim event vector. (&10)
- adr r1,vbl_routine ; Adress of claiming routine.
- adr r2,workscr_nb ; Value to pass in r12 when rout is called.
- swi OS_Claim
- mov r0,#&e ; Enable an event.
- mov r1,#4 ; Event 4=VBl.
- swi OS_Byte
- ;----------------------------------------------------------------------------
- .one_frame
- bl get_workscr_adr ; r0=workscreen adress.
- add r0,r0,#(320-168)/2 ; Recenter.
- ldr r1,videoram_adress ; Adress of texture.
- add r1,r1,#screennb*81920 ; In videoram, just after screenbanks.
- adr r2,bss+sinus
- str r13,old_stack ; Save stack.
- b rotozoom
- .back_from_rotozoom
- ldr r13,old_stack ; Restore stack.
- bl vsync_routine ; Wait until next workscr is ready.
- swi OS_ReadEscapeState ; Escape key pressed?
- bCC one_frame ; No, then loop.
- ;---------------------------------------------------------------------------
- ; Disables our Vertical Blanking interrupt and then quit.
- mov r0,#&d ; Disable an event.
- mov r1,#4 ; Event 4=VBl.
- swi OS_Byte
- mov r0,#&10 ; Release Event Vector. (&10)
- adr r1,vbl_routine ; Give same values as when claiming.
- adr r2,workscr_nb
- swi OS_Release
- swi OS_Exit
-
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** MAIN DATAS *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- .old_stack
- .sinA dcd 1647089 ; sin((pi/4)/sin_nb)*2^28.
- .cosA dcd 268430403 ; cos((pi/4)/sin_nb)*2^28.
-
- .random_germ dcd &eb1a2c34 ; The magical random number.
-
- .videoram_adress dcd 148,-1 ; Values for the swi.
-
- .tx_colors
- dcb &d4,&d5,&d6,&d7 ; Brown cycle.
- dcb &d7,&d6,&d5,&d4,&3b,&3a,&39,&38,&07,&06,&05,&04
- dcb &0c,&0d,&0e,&0f,&b0,&b1,&b2,&b3,&dc,&dd,&de,&df ; Purple cycle.
- dcb &df,&de,&dd,&dc,&b3,&b2,&b1,&b0,&0f,&0e,&0d,&0c
- dcb &08,&09,&0a,&0b,&a4,&a5,&a6,&a7,&d8,&d9,&da,&db ; Blue cycle.
- dcb &db,&da,&d9,&d8,&a7,&a6,&a5,&a4,&0b,&0a,&09,&08
-
- .workscr_nb dcd 2 ; This two variables must be left together.
- .displayscr_nb dcd 1
-
- .logoCR incbin "LogoCR"
- ALIGN
-
- ;****************************************************************************
- ;****************************************************************************
- ;***** *****
- ;***** ROUTINES *****
- ;***** *****
- ;****************************************************************************
- ;****************************************************************************
-
- ; ---------------------------------------------------------------------------
- ; --- Routine for Vertical Blank interrupt. ---
- ; ---------------------------------------------------------------------------
- ; We check if the next screen which will be displayed is entirely drawn
- ; (ie display_scr_nb-1<>workscr_nb), and in this case we use a swi to change
- ; the screen bank to display_scr_nb-1. When displayscr_nb-1 reachs 0 it is
- ; set back to ScreenNb by using self-modified code. (Op2 in vbl_screennb_mov
- ; was changed to ScreenNb)
- ; At first I was accessing directly the MemC to change the display screen,
- ; but since this isn' t compatible coding, I had to spent some time with
- ; ArmOric and his PRMs in order to use a swi during this interrupt, and I
- ; recommend you get a look at PRMs.
- ; When this routine is called we must have r12 pointing on a buffer which
- ; contains workscr_nb and displayscr_nb.
- .vbl_routine
- cmp r0,#4 ; Event=VBl?
- movNE pc,r14 ; No, then it' s none of our business.
- stmfd r13!,{r0,r1,r14} ; Save registers.
- ldmia r12,{r0,r1} ; r0=workscr_nb | r1=displayscr_nb.
- subS r1,r1,#1 ; r1=displayscr_nb-1.
- movEQ r1,#screennb ; If r1=0 then back to ScreenNb.
- cmp r0,r1 ; Flags=workscr_nb-(displayscr_nb-1).
- ldmEQfd r13!,{r0,r1,pc} ; If equal don' t show next screen.
- str r1,[r12,#4] ; Save new displayscr_nb.
- mov r12,pc ; Keep current status/mode.
- orr r0,r12,#3 ; Derive supervisor version of it.
- teqp r0,#0 ; Enter supervisor mode.
- mov r0,r0
- stmfd r13!,{r14} ; Save Supervisor R14
- mov r0,#&71 ; Next showscreen.
- swi OS_Byte
- ldmfd r13!,{r14} ; Restore Supervisor R14
- teqp r12,#0 ; Re-enter original processor mode.
- mov r0,r0
- ldmfd r13!,{r0,r1,pc} ; Could have been so short and so good.
-
- ; ---------------------------------------------------------------------------
- ; --- Routine for Vertical Synchronisation. ---
- ; ---------------------------------------------------------------------------
- ; When this routine is called, this means we have just finished to draw the
- ; workscr_nb, and we notify it by setting new workscreen to old workscr_nb-1.
- ; (As for the vbl_routine, we loop if workscr_nb-1 reaches 0, and this is
- ; performed with modification of vsync_screennb_mov)
- ; Once the notification has been made, we wait until the new workscr_nb is
- ; different from the displayscr_nb.
- .vsync_routine
- stmdb r13!,{r0,r14}
- ldr r0,workscr_nb ; Load workscr_nb.
- subS r0,r0,#1 ; r0=workscr_nb-1.
- movEQ r0,#screennb ; If r0=0 then back to ScreenNb.
- str r0,workscr_nb ; Save new workscr_nb.
- ._wait_vsync
- ldr r14,displayscr_nb ; Load displayscr_nb.
- cmp r0,r14 ; displayscr_nb=new_workscr_nb?
- bEQ _wait_vsync ; Then wait.
- ldmia r13!,{r0,pc}
-
- ; ---------------------------------------------------------------------------
- ; --- Routine to get WorkScreen adress. ---
- ; ---------------------------------------------------------------------------
- ; This routine returns the workscreen adress in r0.
- .get_workscr_adr
- stmdb r13!,{r14}
- ldr r0,videoram_adress
- ldr r14,workscr_nb
- sub r14,r14,#1 ; RiscOS is an OS for coders... ;)
- add r14,r14,r14,lsl #2 ; r14=workscr_nb*5.
- add r0,r0,r14,lsl #6+8 ; r0=video+workscr_nb*320*256.
- ldmia r13!,{pc}
-
- ; ---------------------------------------------------------------------------
- ; --- Routine to clear a memory part. ---
- ; ---------------------------------------------------------------------------
- ; Beware, this routine kills r2, r1 and since it works with longwords, you
- ; must make sure evrything is multiple of 4.
- ; Parameters are...
- ; r0=adress to clear. (Must be longword aligned)
- ; r1=nb of bytes to clear. (Must be multiple of 4)
- .clear_mempart
- mov r2,#0 ; Fill with zeroes.
- ._clear
- subS r1,r1,#4 ; One longword will be cleared.
- str r2,[r0,r1] ; Clear it.
- bNE _clear ; Continue until r1=0.
- mov pc,r14
-
- ; ---------------------------------------------------------------------------
- ; --- Routine smoothing a texture ---
- ; --- © Alain BROBECKER ---
- ; ---------------------------------------------------------------------------
- ; This routines works by applying the following 3*3 convolution matrix...
- ; ( 1 2 1 ) ( pix0 pix1 pix2 )
- ; 1/16 * ( 2 4 2 ) * ( pix3 pix4 pix5 ) = new pix.
- ; ( 1 2 1 ) ( pix6 pix7 pix8 )
- ; Parameters are...
- ; r0 = adress of initial N*N texture.
- ; r1 = adress of N*N buffer for smoothed result.
- .smooth_texture
- stmfd r13!,{r0-r9,r14}
- mov r2,#0 ; r2=y counter.
- ._smooth_line
- mov r3,#0 ; r3=x counter.
- sub r4,r2,#1<<(32-tx_N) ; r4=(y-1) mod N <<(32-M). (Wrapping)
- add r6,r2,#1<<(32-tx_N) ; r6=(y+1) mod N <<(32-M). (Wrapping)
- add r4,r0,r4,lsr #(32-2*tx_N) ; r4 points on src_line up.
- add r5,r0,r2,lsr #(32-2*tx_N) ; r5 points on src_line.
- add r6,r0,r6,lsr #(32-2*tx_N) ; r6 points on src_line down.
- ._smooth_one
- sub r7,r3,#1<<(32-tx_N) ; r7=(x-1) mod N <<(32-M). (Wrapping)
- add r8,r3,#1<<(32-tx_N) ; r8=(x+1) mod N <<(32-M). (Wrapping)
- ldrB r9,[r5,r3,lsr #(32-tx_N)] ; Load all the pixels, and add them
- ldrB r14,[r4,r3,lsr #(32-tx_N)] ; with the good coefficients in r9.
- add r9,r14,r9,lsl #1
- ldrB r14,[r6,r3,lsr #(32-tx_N)]
- add r9,r9,r14
- ldrB r14,[r5,r7,lsr #(32-tx_N)]
- add r9,r9,r14
- ldrB r14,[r5,r8,lsr #(32-tx_N)]
- add r9,r9,r14
- ldrB r14,[r4,r7,lsr #(32-tx_N)]
- add r9,r14,r9,lsl #1
- ldrB r14,[r4,r8,lsr #(32-tx_N)]
- add r9,r9,r14
- ldrB r14,[r6,r7,lsr #(32-tx_N)]
- add r9,r9,r14
- ldrB r14,[r6,r8,lsr #(32-tx_N)]
- add r9,r9,r14
- mov r9,r9,lsr #4 ; r9=smoothed intensity.
- strB r9,[r1],#1 ; Save new pixel value.
- addS r3,r3,#1<<(32-tx_N) ; Next pixel.
- bNE _smooth_one
- addS r2,r2,#1<<(32-tx_N) ; Next line.
- bNE _smooth_line
- ldmfd r13!,{r0-r9,pc}
-
- ; ---------------------------------------------------------------------------
- ; --- Routine creating a fractal landscape ---
- ; --- © Alain BROBECKER ---
- ; ---------------------------------------------------------------------------
- ; Recursive landscape creation. Considering a point in the landscape and the
- ; iteration (=width of square) we construct the points m4-m8 and go on
- ; recursively on all resulting four squares.
- ; m0--m4--m1 h4=0.5*(h0+h1)+rnd
- ; | | | h5=0.5*(h1+h2)+rnd
- ; m7--m8--m5 h6=0.5*(h2+h3)+rnd
- ; | | | h7=0.5*(h3+h0)+rnd
- ; m3--m6--m2 h8=0.25*(h0+h1+h2+h3)+rnd
- ; Parameters are...
- ; r0=adress of buffer for landscape.
- ; r1=random number.
- ; r2=1.
- ; r3=iteration.
- ; r4=posx.
- ; r5=posy.
- .recursive_landscape
- stmfd r13!,{r3-r5,r14}
- ; At first, we calculate h4,h5,h6,h7 and h8.
- add r6,r4,r2,lsl r3
- and r6,r6,#tx_S-1 ; r6=(posx+2^iteration) mod(tx_S).
- add r7,r5,r2,lsl r3
- and r7,r7,#tx_S-1 ; r7=(posy+2^iteration) mod(tx_S).
- add r9,r4,r7,lsl #tx_N ; r9 points on m3.
- add r8,r6,r7,lsl #tx_N ; r8 points on m2.
- add r7,r6,r5,lsl #tx_N ; r7 points on m1.
- add r6,r4,r5,lsl #tx_N ; r6 points on m0.
- ldrB r6,[r0,r6] ; r6=h0.
- ldrB r7,[r0,r7] ; r7=h1.
- ldrB r8,[r0,r8] ; r8=h2.
- ldrB r9,[r0,r9] ; r9=h3.
- sub r10,r3,#1
- mov r10,r2,lsl r10 ; r10=2^(iteration-1).
- ; Calculation of m8.
- add r14,r6,r7
- add r14,r14,r8
- add r14,r14,r9 ; r14=h0+h1+h2+h3.
- mov r14,r14,asr #2 ; r14=0.25*(h0+h1+h2+h3).
- random32 r1 ; New random number.
- rsb r11,r3,#fractal+1 ; r11=fractal+1-iteration=shift for rnd.
- addS r14,r14,r1,asr r11 ; r14=0.25*(h0+h1+h2+h3)+rnd.
- movLE r14,#1 ; Make sure 0<r14<256.
- cmp r14,#255
- movGE r14,#255
- add r12,r5,r10 ; Make r12 point on m8.
- add r12,r4,r12,lsl #tx_N
- add r12,r12,r10
- strB r14,[r0,r12] ; Save h8.
- ; Calculation of m6.
- add r14,r8,r9 ; r14=h2+h3.
- mov r14,r14,asr #1 ; r14=0.5*(h2+h3).
- random32 r1 ; New random number.
- rsb r11,r3,#fractal ; r11=fractal-iteration=shift for rnd.
- addS r14,r14,r1,asr r11 ; r14=0.5*(h2+h3)+rnd.
- movLE r14,#1 ; Make sure 1<r14<256.
- cmp r14,#255
- movGE r14,#255
- add r12,r5,r2,lsl r3 ; Make r12 point on m6.
- add r12,r4,r12,lsl #tx_N
- add r12,r12,r10
- strB r14,[r0,r12] ; Save h6.
- ; Calculation of m5.
- add r14,r7,r8 ; r14=h1+h2.
- mov r14,r14,asr #1 ; r14=0.5*(h1+h2).
- random32 r1 ; New random number.
- addS r14,r14,r1,asr r11 ; r14=0.5*(h1+h2)+rnd.
- movLE r14,#1 ; Make sure 1<r14<256.
- cmp r14,#255
- movGE r14,#255
- add r12,r4,r2,lsl r3 ; Make r12 point on m5.
- add r12,r12,r5,lsl #tx_N
- add r12,r12,r10,lsl #tx_N
- ldrB r8,[r0,r12] ; Load value at m5.
- cmp r8,#0 ; Pixel already set?
- strEQB r14,[r0,r12] ; Else save h5.
- ; Calculation of m4.
- add r14,r6,r7 ; r14=h0+h1.
- mov r14,r14,asr #1 ; r14=0.5*(h0+h1).
- random32 r1 ; New random number.
- addS r14,r14,r1,asr r11 ; r14=0.5*(h0+h1)+rnd.
- movLE r14,#1 ; Make sure 1<r14<256.
- cmp r14,#255
- movGE r14,#255
- add r12,r4,r10 ; Make r12 point on m4.
- add r12,r12,r5,lsl #tx_N
- ldrB r8,[r0,r12]
- cmp r8,#0
- strEQB r14,[r0,r12] ; Save h4.
- ; Calculation of m7.
- add r14,r6,r9 ; r14=h0+h3.
- mov r14,r14,asr #1 ; r14=0.5*(h0+h3).
- random32 r1 ; New random number.
- addS r14,r14,r1,asr r11 ; r14=0.5*(h0+h3)+rnd.
- movLE r14,#0 ; Make sure 1<r14<256.
- cmp r14,#255
- movGE r14,#255
- add r12,r5,r10 ; Make r12 point on m7.
- add r12,r4,r12,lsl #tx_N
- ldrB r8,[r0,r12]
- cmp r8,#0
- strEQB r14,[r0,r12] ; Save h7.
- ; Second part, recursive call.
- subS r3,r3,#1
- ldmEQfd r13!,{r3-r5,pc} ; Stop recusrion when iter=0.
- bl recursive_landscape ; Else go on with four subsquares.
- add r4,r4,r2,lsl r3 ; start pos=m4.
- bl recursive_landscape
- add r5,r5,r2,lsl r3 ; start pos=m8.
- bl recursive_landscape
- sub r4,r4,r2,lsl r3 ; start pos=m7.
- bl recursive_landscape
- ldmfd r13!,{r3-r5,pc}
-
- ; ---------------------------------------------------------------------------
- ; --- Rotozoom with edges as quadratic splines. ---
- ; --- © Alain BROBECKER ---
- ; ---------------------------------------------------------------------------
- ; I won' t explain much about rotozoom in here, just let you know that for
- ; each destination scanline we calculate the edges' positions in src bitmap,
- ; thus giving us xleft_src,yleft_src,xright_src,yright_src. Then we perform
- ; a linear interpolation to know the source coord of each pixel in scanline.
- ; The important thing for the beauty of the effect stands in the way edges
- ; are computed. Classical method is to caclulate the brows of the rotozoom
- ; box and linearly (again) interpolate to know scanlines' edges src_pos. But
- ; this don' t give very original (and nice) results, so I dwelt far in maths
- ; and used quadratic splines instead. I define 6 control points and use a
- ; quadratic interpolation to know edges' src_pos. Maybe reminding you some
- ; things about quadsplines will be good. A quadspline is an equation in the
- ; form m(t)=a0+a1*t+a2*t^2. Given m0,m1,m2 the control brows, consider we
- ; want m(0)=m0, m(1/2)=m1 and m(1)=m2, thus gives us the coefs a0,a1,a2.
- ; (I let you solve this system with 3 equations and 3 parameters) Once done
- ; we compute m(k/2^n) where 0=<k=<2^n in an incremental way.
- ; The result is a realtime, fairly optimised, routine running quite fast,
- ; on my Arm2 at least. Scanline interpolation just fits in cache memory, but
- ; we' ll need to declare texture as uncachable in order to have max speed on
- ; cached processor. (When a ldrB is performed, a whole cache line=4 longs is
- ; loaded from memory and this is a disadvantage for rotozoom/mapping since
- ; we are not interested in consecutive source pixels) In order to have the
- ; texture uncacheable, quite simply I put it in videoram.
- ; Ok, as usual the source is widely commented, so I even wonder why I made
- ; this boring foreword! =) EnjOY!
- ;
- ; Parameters are...
- ; r0=videoram adress.
- ; r1=adress of source bitmap.
- ; r2=adress of sinus table.
-
- ;====> Quad_Coef <=================
- ; This macro computes coefs for quadratic splines in incremental mode.
- ; m0=a0<<2N | m1=a1<<N-a2 | m2=a2.
- ; Where a0=m0, a1=-3m0+4m1-m2, and a2=2m0-4m1+2m2.
- ; It destroys m0,m1,m2.
- macro quad_coef m0,m1,m2
- { rsb m1,m0,m1,lsl #1 ; m1=-m0+2m1.
- rsb m1,m2,m1,lsl #1 ; m1=-2m0+4m1-m2.
- rsb m2,m1,m2 ; m2=a2=2m0-4m1+2m2.
- sub m1,m1,m0 ; m1=a1=-3m0+4m1-m2.
- mov m0,m0,asr #2*sin_N-2*quad_N-zoom_N ; m0=a0<<2N.
- mov m1,m1,asr #2*sin_N-quad_N-zoom_N ; m1=a1<<N.
- add m1,m1,m2,asr #2*sin_N-zoom_N ; m1=inc1=a1<<N+a2.
- }
- ;====> rotozoom4 <==================
- ; This macro computes a dest longword and put it in m6.
- ; Needs m0=src_img, m1..m4=x,y,dx,dy and m5 as temp register.
- ; Last linear interpolation is active if notlast=1.
- macro rotozoom4 m0,m1,m2,m3,m4,m5,m6
- { and m5,m2,#&ff<<(32-tx_N) ; m5=int(y)<<(32-tx_N).
- add m5,m5,m1,lsr #tx_N ; m5=(int(y)*tx_S+x)<<(32-2*tx_N).
- ldrB m6,[m0,m5,lsr #32-2*tx_N] ; Load byte.
- add m1,m1,m3 ; x+=dx.
- add m2,m2,m4 ; y+=dy.
- and m5,m2,#&ff<<(32-tx_N) ; Do the same for 2nd pixel.
- add m5,m5,m1,lsr #tx_N
- ldrB m5,[m0,m5,lsr #32-2*tx_N]
- add m6,m6,m5,lsl #8 ; Merge pixels in longword.
- add m1,m1,m3
- add m2,m2,m4
- and m5,m2,#&ff<<(32-tx_N) ; 3rd pixel...
- add m5,m5,m1,lsr #tx_N
- ldrB m5,[m0,m5,lsr #32-2*tx_N]
- add m6,m6,m5,lsl #16
- add m1,m1,m3
- add m2,m2,m4
- and m5,m2,#&ff<<(32-tx_N) ; 4th pixel...
- add m5,m5,m1,lsr #tx_N
- ldrB m5,[m0,m5,lsr #32-2*tx_N]
- add m6,m6,m5,lsl #24
- #if notlast
- add m1,m1,m3 ; Not needed in last long.
- add m2,m2,m4
- #endif
- }
-
- ; Storage and variables for the rotozoom effect. Note that in splines_angles
- ; the angle is in sin_nb_shift+3 upper bits, and increment in lower bits,
- ; thus allowing to have the modulo operation gratuitous.
- .rotozoom_temp dcd 0,0 ; Temporary storage.
- .splines_angles
- dcd &80000005,3,3,23 ; Angles and angle_inc for splines mvts.
- dcd bss+edges ; Easier and faster than an adr.
-
- ; Here comes the core of the rotozoom, needs r0=@video, r1=@src, r2=@sinus.
- ; At first we calculate the src_pos of all 6 control brows.
- .rotozoom
- adr r13,rotozoom_temp
- stmia r13!,{r0-r1} ; Save workscreen+source.
- ldmia r13,{r5-r7,r9,r14} ; Load splines_angles+@edges
- add r5,r5,r5,lsl #32-sin_shift ; Angles+=inc_angles.
- add r6,r6,r6,lsl #32-sin_shift
- add r7,r7,r7,lsl #32-sin_shift
- add r9,r9,r9,lsl #32-sin_shift
- stmia r13,{r5-r7,r9} ; Save new angles.
- ldr r6,[r2,r6,lsr #32-sin_shift-2] ; r6=sin(a0).
- add r6,r6,#3<<(sin_N-1) ; r6=??+sin(a0).
- ldr r7,[r2,r7,lsr #32-sin_shift-2] ; r7=sin(a1).
- add r7,r7,#3<<(sin_N-1) ; r7=??+sin(a1).
- ldr r8,[r2,r9,lsr #32-sin_shift-2] ; r8=sin(a2).
- ldr r12,[r2,r5,lsr #32-sin_shift-2] ; r12=sin(b).
- add r2,r2,#2*sin_nb ; r2 points on cosinus table.
- ldr r13,[r2,r5,lsr #32-sin_shift-2] ; r13=cos(b).
- ldr r9,[r2,r9,lsr #32-sin_shift-2] ; r9=cos(a2).
- mul r0,r12,r6 ; r0=x0=(??+sin(a0))*sin(b).
- mul r1,r13,r6 ; r1=y0=(??+sin(a0))*cos(b).
- rsb r10,r0,#0 ; r10=x2'=-x0.
- rsb r11,r1,#0 ; r11=y2'=-y0.
- mul r4,r13,r7 ; r4=x2=(??+sin(a1))*cos(b).
- mul r5,r12,r7 ; r5=(??+sin(a1))*sin(b).
- rsb r5,r5,#0 ; r5=y2=-(??+sin(a1))*sin(b).
- rsb r6,r4,#0 ; r6=x0'=-x2.
- rsb r7,r5,#0 ; r7=y0'=-y2.
- add r2,r0,r4 ; r2=(x0+x2).
- mov r2,r2,asr #1 ; r2=(x0+x2)/2.
- add r2,r2,r8,lsl #sin_N-2 ; r2=x1=(x0+x2)/2+k*sin(a2).
- add r3,r1,r5
- mov r3,r3,asr #1
- add r3,r3,r9,lsl #sin_N-2 ; r3=y1=(y0+y2)/2+k*cos(a2).
- add r12,r6,r10
- mov r12,r12,asr #1
- add r8,r12,r8,lsl #sin_N-2 ; r8=x1'=(x0'+x2')/2+k*sin(a2).
- add r12,r7,r11
- mov r12,r12,asr #1
- sub r9,r12,r9,lsl #sin_N-2 ; r9=y1'=(x0'+x2')/2-k*cos(a2).
- ; Here we have r0..r11=x0,y0,...,x2',y2'. Time now to compute the coefs
- ; for the incremental spline calculation, and with this we calculate the
- ; xl_src,yl_src,dx_src/168,dy_src/168 for all scanline. In the particular
- ; case when tx_N=7 and quad_N=8, the shift for "wiped" instructions is 0.
- quad_coef r0,r2,r4 ; r2=inc1x | r4=a2x.
- quad_coef r1,r3,r5 ; r3=inc1y | r5=a2y.
- quad_coef r6,r8,r10 ; r8=inc1x' | r10=a2x'.
- quad_coef r7,r9,r11 ; r9=inc1y' | r11=a2y'.
- mov r13,#256 ; Nb of lines to compute.
- .spline_one
- mov r12,r0,lsl #32-tx_N-2*quad_N ; r12=xleft<<(32-tx_N).
- str r12,[r14],#4
- mov r12,r1,lsl #32-tx_N-2*quad_N ; r12=yleft<<(32-tx_N).
- str r12,[r14],#4
- sub r12,r6,r0 ; r12=(mx'-mx)<<2N.
- add r12,r12,r12,lsl #1 ; r12=(mx'-mx)*3<<2N.
- add r12,r12,r12,asr #6 ; r12=(mx'-mx)/168<<(9+2N).
- ; mov r12,r12,asr #tx_N-(32-9-2*quad_N) ; r12=(mx'-mx)/168<<(32-tx_N).
- str r12,[r14],#4
- sub r12,r7,r1 ; r12=(my'-my)<<2N.
- add r12,r12,r12,lsl #1 ; r12=(my'-my)*3<<2N.
- add r12,r12,r12,asr #6 ; r12=(my'-my)/168<<(9+2N).
- ; mov r12,r12,asr #tx_N-(32-9-2*quad_N) ; r12=(my'-my)/168<<(32-tx_N).
- str r12,[r14],#4
- add r0,r0,r2 ; mx+=inc1x.
- add r2,r2,r4,asr #2*sin_N-1-zoom_N ; inc1x+=inc2x. (inc2x=2a2x)
- add r1,r1,r3 ; my+=inc1y.
- add r3,r3,r5,asr #2*sin_N-1-zoom_N ; inc1y+=inc2y.
- add r6,r6,r8 ; mx'+=inc1x'.
- add r8,r8,r10,asr #2*sin_N-1-zoom_N ; inc1x'+=inc2x'.
- add r7,r7,r9 ; my'+=inc1y'.
- add r9,r9,r11,asr #2*sin_N-1-zoom_N ; inc1y'+=inc2y'.
- subS r13,r13,#1 ; One line performed.
- bNE spline_one
- ; Now we go on with the rotozoom linear interpolation. Comments can be
- ; found in the rotozoom4 macro.
- adr r0,rotozoom_temp
- ldmia r0,{r0,r1} ; r0=videoram adress | r1=source.
- sub r2,r14,#256*4*4 ; r2 points back on edges.
- mov r3,#256 ; Nb of lines.
- .rotozoom_line
- ldmia r2!,{r4-r7} ; Load x,y,dx,dy.
- #set notlast = 1 ; We need the final interpolation.
- #rept 6
- rotozoom4 r1,r4,r5,r6,r7,r14,r8
- rotozoom4 r1,r4,r5,r6,r7,r14,r9
- rotozoom4 r1,r4,r5,r6,r7,r14,r10
- rotozoom4 r1,r4,r5,r6,r7,r14,r11
- rotozoom4 r1,r4,r5,r6,r7,r14,r12
- rotozoom4 r1,r4,r5,r6,r7,r14,r13
- stmia r0!,{r8-r13}
- #endr
- rotozoom4 r1,r4,r5,r6,r7,r14,r8
- rotozoom4 r1,r4,r5,r6,r7,r14,r9
- rotozoom4 r1,r4,r5,r6,r7,r14,r10
- rotozoom4 r1,r4,r5,r6,r7,r14,r11
- rotozoom4 r1,r4,r5,r6,r7,r14,r12
- #set notlast = 0 ; No more final linear interpolation.
- rotozoom4 r1,r4,r5,r6,r7,r14,r13
- stmia r0!,{r8-r13}
- add r0,r0,#320-168 ; Next dest line.
- subS r3,r3,#1 ; One line rotozoomED.
- bNE rotozoom_line
- b back_from_rotozoom
- ;-----------------------> THIS MUST BE AT VERY END <-----------------------
- .bss
-