home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / demos / baah / TinyDemos / IntroCR / CRintroSRC next >
Encoding:
Text File  |  1997-02-15  |  49.7 KB  |  1,102 lines

  1. ;                                     \|/
  2. ;                                     O O
  3. ; --------------------------------oOO--U--OOo--------------------------------
  4. ; -                                                                         -
  5. ; -                      - Intro for Coder's Revenge -                      -
  6. ; -                   © Alain BROBECKER (baah/Arm'sTeack)                   -
  7. ; -                                                                 June 96 -
  8. ; ---------------------------------------------------------------------------
  9. ;
  10. ;   Mega THANX to Mr Hill of Archiologics for the 2nd Mb. (Yup it' s easier
  11. ; now to code all I have dreamt of...) Keep on being so kind and on coding!
  12. ;
  13. ;   This source is given for free and is widely commented, so I hope some
  14. ; people will look at it and (maybe) improve their own code. Re-use of my
  15. ; routines is allowed (though not recommended, cos you' ll understand more
  16. ; if you write your owns...) as long as it is not for commercial purposes,
  17. ; as long as you credit me and send me a free copy of your proggy. Oh, btw
  18. ; the assembler I used is ExtASM 0.50b. You' ll have to make changes in
  19. ; macros if you use a newer version of ExtASM.
  20. ;
  21. ; Briefly, this code features...
  22. ;   * Smart N-uple (N>1) buffering management using self-modifyed code.
  23. ;     Totally unusefull here, cos only half a VBl is used on my Arm2, but
  24. ;     you' ll certainly be interested in it if you code 3d.
  25. ;   * Sinus-cosinus code generator.
  26. ;   * Background texture generator. (Don' t you find this texture nice?)
  27. ;   * Smart background restoring. I restore only the part which has been
  28. ;     modified, and again this shall interest 3d coders.
  29. ;   * Fast box filling and big box copying using self-generated code.
  30. ;
  31. ;   I must say that everything is optimised for speed primarily, then for
  32. ; size. Also I' ve left some 'mistakes' in the code (for example, there' s
  33. ; a branch for vsync_routine though it' s used only once) just to increase
  34. ; readability. (Maybe some others are here by accident) Time now to let you
  35. ; enjoy the code, don' t hesitate to write me...
  36. ;
  37. ;           Alain BROBECKER         Dracula / Positivity (STe)
  38. ;           rte de Dardagny         baah / Arm's Tech (Archie)
  39. ;            01630 CHALLEX                           baah (PC)
  40. ;               FRANCE
  41. ;
  42. ; 15 Feb 97 - StrongARM compatible version... FastBox and CopyBox routines
  43. ;             are no more using generated code when SA is detected.
  44. ;           - Added exit handler.
  45.  
  46. #name       IntroCR                 ; tHa iNcReDibLe kEwl diScMaG...
  47.  
  48. ;------ Constants -----------------------------------------------------------
  49. #set        XOS_PlatformFeatures = &2006d ; Value for the swi.
  50. #set        screennb_min = 3        ; Minimum number of mode13 screens.
  51. #set        screennb_max = 8        ; Maximum number.
  52. #set        shift = 16              ; Shift for fixed point values.
  53. #set        sin_shift = 10          ; 2^sin_shift is the nb of angles.
  54. #set        sin_nb = 1<<(sin_shift-3) ; Nb of angles between [0;pi/4[.
  55. #set        bg_M = 8                ; Well, texture must be a power of 2, so
  56. #set        bg_N = 1<<bg_M          ;   bg_N=2^bg_M is the size of texture.
  57. #set        bg_middle = 11          ; Intensity for null relief*2.
  58. #set        fractal = 29            ; Value for shift of rnd nb in fracland.
  59. #set        nb_letters = 14         ; Nb of crazy letters.
  60.  
  61. ;------ BSS Offsets ---------------------------------------------------------
  62. #set        stack = 4*128           ; Top of stack.
  63. #set        sinus = stack           ; Sinus table.
  64. #set        background = sinus+10*sin_nb*4 ; Background.
  65. #set        clsboxes = background+320*256 ; Coords for clear boxes.
  66. #set        letters_coefs = clsboxes+4*screennb_max*4 ; Coefs for letters.
  67. #set        end = letters_coefs+6*nb_letters*4
  68.  
  69.  
  70. ;****************************************************************************
  71. ;****************************************************************************
  72. ;*****                                                                  *****
  73. ;*****                              MACROS                              *****
  74. ;*****                                                                  *****
  75. ;****************************************************************************
  76. ;****************************************************************************
  77.  
  78. ;====> Umul64 <=====================
  79. ; This macro performs an unsigned 32*32 bits multiply.
  80. ;   [m0|m1]=m2*m3. You can choose [m2|m3]=[m0|m1]
  81. ;   It destroys m0,m1,m4,m5,m6 and the flags. (C is the carry flag)
  82. macro umul64 m0,m1,m2,m3,m4,m5,m6
  83. { mov       m4,m2,lsr #16           ; m4=up(m2).
  84.   sub       m5,m2,m4,lsl #16        ; m5=down(m2).
  85.   mov       m0,m3,lsr #16           ; m0=up(m3).
  86.   sub       m1,m3,m0,lsl #16        ; m1=down(m3).
  87.   mul       m6,m5,m0                ; m6=down(m2)*up(m3).
  88.   mul       m0,m4,m0                ; m0=up(m2)*up(m3).
  89.   mlaS      m6,m1,m4,m6             ; C+m6=up(m2)*down(m3)+down(m2)*up(m3).
  90.   adc       m0,m0,m6,lsr #16
  91.   mul       m1,m5,m1                ; m1=down(m2)*down(m3).
  92.   addS      m1,m1,m6,lsl #16
  93.   adc       m0,m0,#0                ; [m0|m1]=m2*m3.
  94. }
  95. ;====> Adjust64 <===================
  96. ; This macro adjusts the 64 bits result to 32 bits, according to the fixed
  97. ; point shift factor. (c0)
  98. ;   m0=[m1|m2]>>c0. You can choose m1=m0.
  99. ;   It destroys m0.
  100. macro adjust64 m0,m1,m2,c0
  101. { mov       m0,m1,lsl #32-c0
  102.   add       m0,m0,m2,lsr #c0
  103. }
  104. ;====> Add64 <======================
  105. ; This macro performs a 64 bits addition.
  106. ;   [m0|m1]=[m2|m3]+[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
  107. ;   It destroys [m0|m1] and the flags.
  108. macro add64 m0,m1,m2,m3,m4,m5
  109. { addS      m1,m3,m5
  110.   adc       m0,m2,m4
  111. }
  112. ;====> Sub64 <======================
  113. ; This macro performs a 64 bits substract.
  114. ;   [m0|m1]=[m2|m3]-[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
  115. ;   It destroys [m0|m1] and the flags.
  116. macro sub64 m0,m1,m2,m3,m4,m5
  117. { subS      m1,m3,m5
  118.   sbc       m0,m2,m4
  119. }
  120. ;====> Random32 <==================
  121. ; This macro takes a random number, and makes a new one.
  122. macro random32 m0
  123. { eor       m0,m0,m0,rrx
  124.   adc       m0,m0,m0,ror #7
  125. }
  126.  
  127.  
  128. ;****************************************************************************
  129. ;****************************************************************************
  130. ;*****                                                                  *****
  131. ;*****                               CODE                               *****
  132. ;*****                                                                  *****
  133. ;****************************************************************************
  134. ;****************************************************************************
  135.  
  136. ; Initialise stack and ask for slot+screen memory.
  137. .proggy_start
  138.   adr       r13,bss+stack           ; Initialise stack pointer.
  139.   mov       r0,#bss+end-&8000       ; Ask for needed slot memory.
  140.   mov       r1,#-1                  ; Don' t change next slot size.
  141.   swi       Wimp_SlotSize
  142.   mov       r0,#2                   ; Ask for ScreenMem size.
  143.   swi       OS_ReadDynamicArea      ; r1=current ScreenMem size.
  144.   rsbS      r1,r1,#screennb_min*81920 ; r1=minimum-curent screenmem.
  145.   movGT     r0,#2                   ; Ask for it if we don' t have enough.
  146.   swiGT     OS_ChangeDynamicArea
  147.   mov       r0,#screennb_min        ; Count the number of screen banks.
  148. ._count_screens
  149.   addS      r1,r1,#81920            ; r1+=size of one mode13 screen.
  150.   addLE     r0,r0,#1                ; If r1 still <=0, we have one more bank.
  151.   bLT       _count_screens          ; If r1<0, maybe there is even more...
  152.   cmp       r0,#screennb_max        ; More than the maximum amount?
  153.   movGE     r0,#screennb_max        ; Then don' t use extra ones.
  154.   strB      r0,vbl_screennb_mov     ; Modify code which needs ScreenNb
  155.   strB      r0,vsync_screennb_mov   ;   for multiple buffering,
  156.   strB      r0,copy_one_screen_mov  ;   and for screen clearing.
  157. ;----------------------------------------------------------------------------
  158. ; Clear the bss section, since some routines need it. I assume that bss+end
  159. ; is longword aligned. (So you must take care when defining bss offsets)
  160.   adr       r0,bss+stack            ; Begin to clear here.
  161.   mov       r1,#end-stack           ; Nb of bytes to clear.
  162.   mov       r2,#0
  163. .clear_bss
  164.   subS      r1,r1,#4                ; One long will be cleared.
  165.   str       r2,[r0,r1]
  166.   bNE       clear_bss
  167. ;----------------------------------------------------------------------------
  168. ; If StrongARM is not there, modify branches in routines so that we use
  169. ; versions with generated code.
  170.   mov        r0,#0
  171.   swi       XOS_PlatformFeatures    ; Read platform feature.
  172.   bvs       noStrongARM             ; If swi is unknown, no StrongARM.
  173.   tst       r0,#1            ; Separated instruction and data caches.
  174.   bne        StrongARMed
  175. .noStrongARM
  176.   mov       r0,#&e0800002           ; r0="add r0,r0,r2".
  177.   str       r0,StrongBranch2
  178.   eor       r0,r0,#&02042003        ; r0=&e2842001="add r2,r4,#1".
  179.   str       r0,StrongBranch1
  180. .StrongARMed
  181. ;----------------------------------------------------------------------------
  182. ; Creates the sinus table. As for the inverses creation, the routine has
  183. ; already been released through "Memory War".
  184. .make_sinus
  185.   adr       r0,bss+sinus
  186.   ldr       r1,sinA                 ; r1=sinA*2^28.
  187.   ldr       r2,cosA                 ; r2=cosA*2^28.
  188.   mov       r3,#0                   ; r3=sin0*2^28.
  189.   mov       r4,#1<<28               ; r4=cos0*2^28.
  190.   mov       r5,#sin_nb+1
  191. .make_one_sinus
  192.   mov       r6,r4,lsr #28-shift     ; r6=cosN*2^shift.
  193.   str       r6,[r0,#sin_nb*2*4]     ; Save sin(N+pi/2)=cosN.
  194.   mov       r6,r3,lsr #28-shift     ; r6=sinN*2^shift.
  195.   str       r6,[r0],#4              ; Save sinN.
  196.   umul64 r6,r7,r1,r3,r8,r9,r10      ; [r6|r7]=sinN*sinA.
  197.   umul64 r8,r9,r2,r4,r10,r11,r12    ; [r8|r9]=cosN*cosA.
  198.   sub64 r6,r7,r8,r9,r6,r7           ; [r6|r7]=cos(N+1)=cosN*sin1-sinN*sin1.
  199.   umul64 r3,r8,r3,r2,r9,r10,r11     ; [r3|r8]=sinN*cosA.
  200.   umul64 r4,r9,r4,r1,r10,r11,r12    ; [r4|r9]=cosN*sinA.
  201.   add64 r3,r8,r3,r8,r4,r9           ; [r3|r8]=sin(N+1)=sinN*cos1+cosN*sin1.
  202.   adjust64 r3,r3,r8,28              ; r1=sin(N+1)=sinN*cos1+cosN*sin1.
  203.   adjust64 r4,r6,r7,28              ; r2=cos(N+1)=cosN*sin1-sinN*sin1.
  204.   subS      r5,r5,#1                ; One sinus processed.
  205.   bNE       make_one_sinus
  206.   sub       r0,r0,#4                ; Complete the table by stupid copy.
  207.   mov       r1,r0                   ; Point on the position which are like
  208.   add       r2,r0,#sin_nb*8         ;  (pi/4+k*(pi/2))   0<=k<=4
  209.   mov       r3,r2
  210.   add       r4,r2,#sin_nb*8
  211.   mov       r5,r4
  212.   add       r6,r4,#sin_nb*8
  213.   mov       r7,r6
  214.   add       r8,r6,#sin_nb*8
  215.   mov       r9,r8
  216.   mov       r10,#sin_nb+1           ; Copy sin_nb+1 values.
  217. ._make_sinus_copy
  218.   ldr       r11,[r0],#-4
  219.   str       r11,[r3],#4             ; sin(pi-X)=sinX.
  220.   str       r11,[r8],#-4            ; sin(2*pi+X)=sinX.
  221.   rsb       r11,r11,#0
  222.   str       r11,[r4],#-4            ; sin(pi+X)=-sinX.
  223.   str       r11,[r7],#4             ; sin(2*pi-X)=-sinX.
  224.   ldr       r11,[r2],#-4
  225.   str       r11,[r1],#4             ; cos(-X)=cosX.
  226.   subS      r10,r10,#1              ; One value copied.
  227.   strNE     r11,[r9],#4             ; cos(2*pi+X)=cosX. No copy if r10=0.
  228.   rsb       r11,r11,#0
  229.   str       r11,[r5],#4             ; cos(pi-X)=-cosX.
  230.   str       r11,[r6],#-4            ; cos(pi+X)=-cosX.
  231.   bNE       _make_sinus_copy
  232. ;----------------------------------------------------------------------------
  233. ; Switch to the good video mode, and some more stupid bits.
  234.   swi       256+22                  ; Vdu 22, set screenmode.
  235.   swi       256+13                  ; Switch to mode 13.
  236.   swi       OS_RemoveCursors        ; Who needs them?
  237.   adr       r0,videoram_adress      ; Get videoram adress.
  238.   mov       r1,r0
  239.   swi       OS_ReadVduVariables
  240. ;----------------------------------------------------------------------------
  241. ; Creates the background texture. The main idea is to make a N*N fractal
  242. ; landscape, take the modulo of it, smooth, emboss and re-smooth it. The
  243. ; emboss and smoothing routines where already released in "Graphics War".
  244. .make_fracland
  245.   adr       r0,bss+background
  246.   ldr       r1,random_germ          ; Load the random germ.
  247.   mov       r2,#1                   ; This will be used by routine.
  248.   strB      r2,[r0]                 ; Also save 1 as upper left pixel.
  249.   mov       r3,#bg_M                ; Iteration=bg_M.
  250.   mov       r4,#0                   ; Position of upper left pixel.
  251.   mov       r5,#0
  252.   bl        recursive_landscape
  253.   ldr       r1,videoram_adress      ; Adress of a second buffer.
  254.   add       r1,r1,#320*256
  255.   bl        smooth_texture          ; Smooth texture.
  256. .emboss_texture
  257.   mov       r2,#0                   ; r2=y counter<<(32-bg_M).
  258. ._emboss_one_line
  259.   sub       r3,r2,#1<<(32-bg_M)     ; r3=(y-1) mod bg_N <<(32-bg_M). (Wrapping)
  260.   add       r4,r3,#1<<(32-bg_M)     ; r4=(y+1) mod bg_N <<(32-bg_M). (Wrapping)
  261.   add       r3,r1,r3,lsr #(32-2*bg_M); r3 points on src_line up.
  262.   add       r4,r1,r4,lsr #(32-2*bg_M); r4 points on src_line down.
  263.   mov       r5,#bg_N                ; r5=nb of pixels per line.
  264. ._emboss_one
  265.   ldrB      r14,[r3],#1             ; r14=pixie up.
  266.   ldrB      r6,[r4],#1              ; r6=pixie down.
  267.   and       r14,r14,#&1f            ; Take the modulo(32).
  268.   and       r6,r6,#&1f
  269.   sub       r6,r6,r14               ; r6=delta.
  270.   addS      r6,r6,#bg_middle        ; Add the middle constant.
  271.   movMI     r6,#0                   ; Make sure intensity is between 0-31.
  272.   cmp       r6,#31
  273.   movGE     r6,#31
  274.   strB      r6,[r0],#1              ; Save it.
  275.   subS      r5,r5,#1                ; One pixel done
  276.   bNE       _emboss_one
  277.   addS      r2,r2,#1<<(32-bg_M)     ; Line done.
  278.   bNE       _emboss_one_line
  279.   sub       r0,r0,#bg_N*bg_N        ; r0 points back on buffer.
  280.   bl        smooth_texture          ; Smooth texture.
  281.   adr       r2,bg_colors            ; Now convert the texture.
  282.   mov       r3,#bg_N                ; y counter.
  283. ._bg_convert_line
  284.   mov       r4,#bg_N                ; x counter.
  285. ._bg_convert_one
  286.   ldrB      r5,[r1],#1              ; Load pixel.
  287.   ldrB      r5,[r2,r5]              ; Load color.
  288.   cmp       r4,#bg_N-(320-bg_N)     ; If x<2*bg_N-320, then
  289.   strGTB    r5,[r0,#bg_N]           ;   copy pixel at r0+bg_N.
  290.   strB      r5,[r0],#1              ; Draw pixel.
  291.   subS      r4,r4,#1                ; One pixel done.
  292.   bNE       _bg_convert_one
  293.   add       r0,r0,#320-bg_N         ; Next line.
  294.   subS      r3,r3,#1                ; One line done.
  295.   bNE       _bg_convert_line
  296. ;----------------------------------------------------------------------------
  297. ; Copy the whole background on all screen banks.
  298.   adr       r0,bss+background       ; Set parameters for the CopyBigBox
  299.   ldr       r1,videoram_adress      ;   routine, so that it copies the
  300.   mov       r2,#0                   ;   whole screen.
  301.   mov       r3,#0
  302.   mov       r4,#319
  303.   mov       r5,#255
  304. .copy_one_screen_mov
  305.   mov       r6,#0                   ; r6=ScreenNb.
  306. .copy_one_screen
  307.   bl        CopyBigBox256
  308.   add       r1,r1,#320*256          ; Next screen bank.
  309.   subS      r6,r6,#1                ; One screen copies.
  310.   bNE       copy_one_screen
  311. ;----------------------------------------------------------------------------
  312. ; Randomly initialise the angles_inc of each letter. In fact, I also put
  313. ; values in the multiplicators coefs and sizes since they are just after,
  314. ; but it does not matters because those coefs will be calculated.
  315.   adr       r0,bss+letters_coefs
  316.   mov       r1,#nb_letters*6        ; 6 longs per letters.
  317.   ldr       r2,random_germ
  318. .init_one_angle
  319.   and       r3,r2,#&f               ; This is the value for the increment.
  320.   add       r3,r3,#3                ; Nicer if there' s no null movements.
  321.   str       r3,[r0],#4
  322.   random32  r2
  323.   subS      r1,r1,#1
  324.   bNE       init_one_angle
  325. ;----------------------------------------------------------------------------
  326. ; Enables our Vertical Blanking (VBl) interrupt and change exit handler.
  327.   mov       r0,#&10                 ; Claim event vector. (&10)
  328.   adr       r1,vbl_routine          ; Adress of claiming routine.
  329.   adr       r2,workscr_nb           ; Value to pass in r12 when rout is called.
  330.   swi       OS_Claim
  331.   mov       r0,#&e                  ; Enable an event.
  332.   mov       r1,#4                   ; Event 4=VBl.
  333.   swi       OS_Byte
  334.   mov        r0,#11            ; Assign exit handler.
  335.   adr        r1,proggy_exit          ; This is the terminal routine.
  336.   mov        r2,r13            ; Will be in r12 when OS_Exit called.
  337.   swi        OS_ChangeEnvironment
  338.   stmfd        r13!,{r1-r3}            ; Save old environment.
  339. ;----------------------------------------------------------------------------
  340. ; This is the Crazy Letters part.
  341. .one_frame
  342. ;  swi OS_WriteS
  343. ;  dcb 19,1,24,32,32,128,0,0
  344.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  345.   ldmia     r1,{r2-r5}              ; Load xleft,yup,xright,ydown.
  346.   sub       r2,r2,#1                ; Always better to take a bigger box.
  347.   sub       r3,r3,#1
  348.   mov       r1,r0                   ; And go for clearing.
  349.   adr       r0,bss+background
  350.   bl        CopyBigBox256
  351. ;  swi OS_WriteS
  352. ;  dcb 19,1,24,128,32,32,0,0
  353. ; We calculate the sizes and multiplicator coefficients for all the letters,
  354. ; and also we compute the total width and max height.
  355.   adr       r0,bss+sinus
  356.   adr       r1,letters_sizes        ; Contains original sizes.
  357.   adr       r2,bss+letters_coefs    ; Contains angles, coefs and sizes.
  358.   mov       r3,#nb_letters
  359.   mov       r4,#0                   ; Will contain full x size.
  360.   mov       r5,#0                   ; Will contain maximum y size.
  361. .calculate_coefs_and_sizes
  362.   ldmia     r2,{r6-r7}              ; Load angles and angles_inc.
  363.   add       r6,r6,r6,lsl #32-sin_shift ; angle_x+=inc_angle_x.
  364.   add       r7,r7,r7,lsl #32-sin_shift ; angle_y+=inc_angle_y.
  365.   ldr       r8,[r0,r6,lsr #32-sin_shift-2] ; r8=sin(angle_x).
  366.   ldr       r9,[r0,r7,lsr #32-sin_shift-2] ; r9=sin(angle_y).
  367.   add       r8,r8,#7<<(shift-2)     ; r8=coef_x=(9+4*sin(angle_x))<<shift-2.
  368.   add       r9,r9,#7<<(shift-2)     ; r9=coef_y=(9+4*sin(angle_y))<<shift-2.
  369.   ldrB      r11,[r1],#1             ; r11=size_x.
  370.   ldrB      r10,[r1],#1             ; r10=size_y.
  371.   mul       r11,r8,r11              ; r11=(size_x*coef_x)<<shift-2.
  372.   mul       r10,r9,r10              ; r10=(size_x*coef_x)<<shift-2.
  373.   stmia     r2!,{r6-r11}            ; Save angles, coefs and sizes.
  374.   add       r4,r4,r11,lsr #shift-3  ; Add new size_x to full x size.
  375.   cmp       r5,r10,lsr #shift-3     ; Max_y smaller than new size_y?
  376.   movMI     r5,r10,lsr #shift-3     ; Then size_y is new max.
  377.   subS      r3,r3,#1
  378.   bNE       calculate_coefs_and_sizes
  379. ; Now we calculate the coords of cls box. Xleft=r6 will be the x position
  380. ; of the first letter we' ll draw.
  381.   ldr       r1,angle                ; Load angle for whole logo position.
  382.   add       r1,r1,r1,lsl #32-sin_shift ; angle+=inc_angle.
  383.   str       r1,angle                ; Save modified angle.
  384.   ldr       r1,[r0,r1,lsr #32-sin_shift-2] ; r1=sin(angle).
  385.   rsb       r6,r4,#320              ; r6=320-width.
  386.   mov       r6,r6,asr #1            ; r6=(320-width)/2.
  387.   add       r6,r6,r1,asr #shift-9   ; r6=?*sin(angle)+(320-width)/2=xleft.
  388.   add       r8,r6,r4                ; r8=xleft+width=xright.
  389.   rsb       r7,r5,#256              ; r7=256-height.
  390.   mov       r7,r7,asr #1            ; r7=(256-heiht)/2=yup.
  391.   add       r9,r7,r5                ; r9=yup+height=ydown.
  392.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  393.   stmia     r1,{r6-r9}              ; Save clear box coords.
  394. ; Time has come to draw the letters one after another.
  395.   mov       r1,#nb_letters
  396.   sub       r7,r2,#nb_letters*6*4   ; r7 points on letters_coefs.
  397.   adr       r8,crazy_letters        ; r8 points on letters definition.
  398. .draw_one_letter
  399.   stmfd     r13!,{r1}               ; Save the nb of letters left.
  400.   ldrB      r1,[r8],#1              ; Load the color of letter.
  401.   add       r1,r1,r1,lsl #8
  402.   add       r1,r1,r1,lsl #16
  403.   ldrB      r9,[r8],#1              ; r9=nb of boxes.
  404.   add       r7,r7,#8                ; Don' t care about angles.
  405.   ldmia     r7!,{r10-r12}           ; Load coef multiplicators and y_size.
  406.   rsb       r12,r12,#256<<(shift-3) ; r12=256-y_size.
  407.   mov       r12,r12,asr #shift-2    ; r12=(256-y_size)/2=yup.
  408. .draw_one_box
  409.   ldrB      r2,[r8],#1              ; r2=x1.
  410.   mul       r2,r10,r2               ; r2=Coef*x1.
  411.   add       r2,r6,r2,asr #shift-3   ; Recentering.
  412.   ldrB      r3,[r8],#1              ; r3=y1.
  413.   mul       r3,r11,r3               ; r3=Coef*y1.
  414.   add       r3,r12,r3,asr #shift-3  ; Recentering.
  415.   ldrB      r4,[r8],#1              ; r4=x2.
  416.   mul       r4,r10,r4               ; r4=Coef*x2.
  417.   add       r4,r6,r4,asr #shift-3   ; Recentering.
  418.   ldrB      r5,[r8],#1              ; r5=y2.
  419.   mul       r5,r11,r5               ; r5=Coef*y2.
  420.   add       r5,r12,r5,asr #shift-3  ; Recentering.
  421.   sub       r4,r4,#1                ; Nicer if we draw (x1;y1)->(x2-1;y2-1).
  422.   sub       r5,r5,#1
  423.   bl        FastBox256
  424.   subS      r9,r9,#1                ; One box drawn.
  425.   bNE       draw_one_box
  426.   ldr       r9,[r7],#4              ; r9=size_x.
  427.   add       r6,r6,r9,lsr #shift-3   ; And add it to x of current letter.
  428.   ldmfd     r13!,{r1}               ; Load the nb of letters left.
  429.   subS      r1,r1,#1                ; One letter drawn.
  430.   bNE       draw_one_letter
  431. ;  swi OS_WriteS
  432. ;  dcb 19,1,24,1,1,1,0,0
  433.   bl        vsync_routine           ; Wait until next workscr is ready.
  434.   swi       OS_ReadEscapeState      ; Escape key pressed?
  435.   bCC       one_frame               ; No, then loop.
  436.   swi       OS_Exit
  437.  
  438. ;****************************************************************************
  439. ;****************************************************************************
  440. ;*****                                                                  *****
  441. ;*****                            MAIN DATAS                            *****
  442. ;*****                                                                  *****
  443. ;****************************************************************************
  444. ;****************************************************************************
  445.  
  446. ; .............X...........X.............................................
  447. ; .............X...........X.............................................
  448. ; .XXX..XX...XXX..XX...XX.....XXX......XX...XX..X...X..XX..XXX...XX...XX.
  449. ; X....X..X.X..X.X..X.X..X...X........X..X.X..X.X...X.X..X.X..X.X..X.X..X
  450. ; X....X..X.X..X.XXXX.X.......XX......X....XXXX.X...X.XXXX.X..X.X..X.XXXX
  451. ; X....X..X.X..X.X....X.........X.....X....X.....X.X..X....X..X..XXX.X...
  452. ; .XXX..XX...XX...XX..X......XXX......X.....XX....X....XX..X..X....X..XX.
  453. ; ..............................................................XXX......
  454. .letters_sizes
  455.   dcb       5,8 ,5,8 ,5,8 ,5,8 ,5,8, 2,8, 9,8   ; coder's
  456.   dcb       5,8, 5,8, 6,8, 5,8, 5,8, 5,8, 4,8   ; revenge
  457. .crazy_letters          ; Colors, nb_boxes and boxes coords for each letter.
  458.   dcb       &da  ,3  ,1,2,4,3  ,0,3,1,6  ,1,6,4,7
  459.   dcb       &07  ,4  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,3,4,6
  460.   dcb       &f2  ,4  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,0,4,6
  461.   dcb       &0f  ,5  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,3,4,5  ,1,4,3,5
  462.   dcb       &f6  ,3  ,1,2,3,3  ,0,3,1,7  ,3,3,4,4
  463.   dcb       &2b  ,1  ,0,0,1,2
  464.   dcb       &fc  ,5  ,1,2,4,3  ,0,3,1,4  ,1,4,3,5  ,3,5,4,6  ,0,6,3,7
  465.   dcb       &0b  ,3  ,1,2,3,3  ,0,3,1,7  ,3,3,4,4
  466.   dcb       &d6  ,5  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,3,4,5  ,1,4,3,5
  467.   dcb       &23  ,5  ,0,2,1,5  ,1,5,2,6  ,2,6,3,7  ,3,5,4,6  ,4,2,5,5
  468.   dcb       &de  ,5  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,3,4,5  ,1,4,3,5
  469.   dcb       &27  ,3  ,0,2,3,3  ,0,3,1,7  ,3,3,4,7
  470.   dcb       &fa  ,5  ,1,2,3,3  ,0,3,1,5  ,1,5,3,6  ,3,3,4,7  ,0,7,3,8
  471.   dcb       &2d  ,5  ,1,2,3,3  ,0,3,1,6  ,1,6,3,7  ,3,3,4,5  ,1,4,3,5
  472.  
  473. .sinA       dcd 1647089             ; sin((pi/4)/sin_nb)*2^28.
  474. .cosA       dcd 268430403           ; cos((pi/4)/sin_nb)*2^28.
  475.  
  476. .random_germ                        ; The magical random number.
  477.   dcd       &eb1a2c34
  478.  
  479. .videoram_adress                    ; Values for the swi.
  480.   dcd       148
  481.   dcd       -1
  482.  
  483. .bg_colors
  484.   dcb &20,&2c,&21,&2d,&22,&2e,&23,&2f,&4c,&d0,&4d,&d1 ; Green+grey.
  485.   dcb &4e,&d2,&4f,&d3,&f0,&fc,&f1,&fd,&f2,&fe,&f3,&ff
  486.  
  487. ; This is the angle and angle_inc for the whole logo movement. Both these
  488. ; parameters are in the same longword, the angle is in the sin_nb_shift+3
  489. ; upper bits, and the increment is in the lower bits, this allowing to have
  490. ; the modulo operation gratuitous. The same trick is used for letters angles.
  491. .angle
  492.   dcd       3
  493.  
  494. .workscr_nb                         ; This two variables must be left together.
  495.   dcd       2
  496. .displayscr_nb
  497.   dcd       1
  498.  
  499.  
  500. ;****************************************************************************
  501. ;****************************************************************************
  502. ;*****                                                                  *****
  503. ;*****                             ROUTINES                             *****
  504. ;*****                                                                  *****
  505. ;****************************************************************************
  506. ;****************************************************************************
  507.  
  508. ; ---------------------------------------------------------------------------
  509. ; ---              Routine for Vertical Blank interrupt.                  ---
  510. ; ---------------------------------------------------------------------------
  511. ;   We check if the next screen which will be displayed is entirely drawn
  512. ; (ie display_scr_nb-1<>workscr_nb), and in this case we use a swi to change
  513. ; the screen bank to display_scr_nb-1. When displayscr_nb-1 reachs 0 it is
  514. ; set back to ScreenNb by using self-modified code. (Op2 in vbl_screennb_mov
  515. ; was changed to ScreenNb)
  516. ;   At first I was accessing directly the MemC to change the display screen,
  517. ; but since this isn' t compatible coding, I had to spent some time with
  518. ; ArmOric and his PRMs in order to use a swi during this interrupt, and I
  519. ; recommend you get a look at PRMs.
  520. ;   When this routine is called we must have r12 pointing on a buffer which
  521. ; contains workscr_nb and displayscr_nb.
  522. .vbl_routine
  523.   cmp       r0,#4                   ; Event=VBl?
  524.   movNE     pc,r14                  ; No, then it' s none of our business.
  525.   stmfd     r13!,{r0,r1,r14}        ; Save registers.
  526.   ldmia     r12,{r0,r1}             ; r0=workscr_nb | r1=displayscr_nb.
  527.   subS      r1,r1,#1                ; r1=displayscr_nb-1.
  528. .vbl_screennb_mov
  529.   movEQ     r1,#0                   ; If r1=0 then back to ScreenNb.
  530.   cmp       r0,r1                   ; Flags=workscr_nb-(displayscr_nb-1).
  531.   ldmEQfd   r13!,{r0,r1,pc}         ; If equal don' t show next screen.
  532.   str       r1,[r12,#4]             ; Save new displayscr_nb.
  533.   mov        r12,pc            ; Keep current status/mode.
  534.   orr        r0,r12,#3            ; Derive supervisor version of it.
  535.   teqp        r0,#0            ; Enter supervisor mode.
  536.   mov          r0,r0
  537.   stmfd        r13!,{r14}            ; Save Supervisor R14
  538.   mov       r0,#&71                 ; Next showscreen.
  539.   swi       OS_Byte
  540.   ldmfd        r13!,{r14}            ; Restore Supervisor R14
  541.   teqp      r12,#0            ; Re-enter original processor mode.
  542.   mov        r0,r0
  543.   ldmfd     r13!,{r0,r1,pc}         ; Could have been so short and so good.
  544.  
  545. ; ---------------------------------------------------------------------------
  546. ; ---                Routine for Vertical Synchronisation.                ---
  547. ; ---------------------------------------------------------------------------
  548. ;   When this routine is called, this means we have just finished to draw the
  549. ; workscr_nb, and we notify it by setting new workscreen to old workscr_nb-1.
  550. ; (As for the vbl_routine, we loop if workscr_nb-1 reaches 0, and this is
  551. ; performed with modification of vsync_screennb_mov)
  552. ;   Once the notification has been made, we wait until the new workscr_nb is
  553. ; different from the displayscr_nb.
  554. .vsync_routine
  555.   stmdb     r13!,{r0,r14}
  556.   ldr       r0,workscr_nb           ; Load workscr_nb.
  557.   subS      r0,r0,#1                ; r0=workscr_nb-1.
  558. .vsync_screennb_mov
  559.   movEQ     r0,#0                   ; If r0=0 then back to ScreenNb.
  560.   str       r0,workscr_nb           ; Save new workscr_nb.
  561. ._wait_vsync
  562.   ldr       r14,displayscr_nb       ; Load displayscr_nb.
  563.   cmp       r0,r14                  ; displayscr_nb=new_workscr_nb?
  564.   bEQ       _wait_vsync             ; Then wait.
  565.   ldmia     r13!,{r0,pc}
  566.  
  567. ; ---------------------------------------------------------------------------
  568. ; ---                  Routine to get WorkScreen adress.                  ---
  569. ; ---------------------------------------------------------------------------
  570. ; This routine returns the workscreen adress in r0, and also the adress of
  571. ; the clsbox buffer corresponding to this workscreen. (The clsboxes buffer
  572. ; contains a succession of xleft,yup,xright,ydown used for cls)
  573. .get_workscr_adr
  574.   stmdb     r13!,{r14}
  575.   ldr       r0,videoram_adress
  576.   adr       r1,bss+clsboxes
  577.   ldr       r14,workscr_nb
  578.   sub       r14,r14,#1              ; RiscOS is an OS for coders... ;)
  579.   add       r1,r1,r14,lsl #4        ; 16 longs per cls boxes.
  580.   add       r14,r14,r14,lsl #2      ; r14=workscr_nb*5.
  581.   add       r0,r0,r14,lsl #6+8      ; r0=video+workscr_nb*320*256.
  582.   ldmia     r13!,{pc}
  583.  
  584. ; ---------------------------------------------------------------------------
  585. ; ---                            Exit Handler.                            ---
  586. ; ---------------------------------------------------------------------------
  587. ; Restore exit handler, disable our VBl interrupt and then quit.
  588. .proggy_exit
  589.   ldmdb        r12,{r1-r3}             ; Load old exit handler environment.
  590.   mov        r0,#11            ; ReAssign it.
  591.   swi        OS_ChangeEnvironment
  592.   mov       r0,#&d                  ; Disable an event.
  593.   mov       r1,#4                   ; Event 4=VBl.
  594.   swi       OS_Byte
  595.   mov       r0,#&10                 ; Release Event Vector. (&10)
  596.   adr       r1,vbl_routine          ; Give same values as when claiming.
  597.   adr       r2,workscr_nb
  598.   swi       XOS_Release
  599.   mvn       r0,#0
  600.   swi       Wimp_CommandWindow        ; Avoid the 'Press Space' from Wimp
  601.   swi       OS_Exit
  602.  
  603. ; ---------------------------------------------------------------------------
  604. ; ---                    Routine smoothing a texture                      ---
  605. ; ---                          © Alain BROBECKER                          ---
  606. ; ---------------------------------------------------------------------------
  607. ; This routines works by applying the following 3*3 matrix...
  608. ;         ( 1 2 1 )   ( pix0 pix1 pix2 )
  609. ;  1/16 * ( 2 4 2 ) * ( pix3 pix4 pix5 ) = new pix.
  610. ;         ( 1 2 1 )   ( pix6 pix7 pix8 )
  611. ; Parameters are...
  612. ;     r0 = adress of initial N*N texture.
  613. ;     r1 = adress of N*N buffer for smoothed result.
  614. .smooth_texture
  615.   stmfd     r13!,{r0-r9,r14}
  616.   mov       r2,#0                   ; r2=y counter.
  617. ._smooth_line
  618.   mov       r3,#0                   ; r3=x counter.
  619.   sub       r4,r2,#1<<(32-bg_M)     ; r4=(y-1) mod N <<(32-M). (Wrapping)
  620.   add       r6,r2,#1<<(32-bg_M)     ; r6=(y+1) mod N <<(32-M). (Wrapping)
  621.   add       r4,r0,r4,lsr #(32-2*bg_M) ; r4 points on src_line up.
  622.   add       r5,r0,r2,lsr #(32-2*bg_M) ; r5 points on src_line.
  623.   add       r6,r0,r6,lsr #(32-2*bg_M) ; r6 points on src_line down.
  624. ._smooth_one
  625.   sub       r7,r3,#1<<(32-bg_M)     ; r7=(x-1) mod N <<(32-M). (Wrapping)
  626.   add       r8,r3,#1<<(32-bg_M)     ; r8=(x+1) mod N <<(32-M). (Wrapping)
  627.   ldrB      r9,[r5,r3,lsr #(32-bg_M)] ; Load all the pixels, and add them
  628.   ldrB      r14,[r4,r3,lsr #(32-bg_M)] ;   with the good coefficients in r9.
  629.   add       r9,r14,r9,lsl #1
  630.   ldrB      r14,[r6,r3,lsr #(32-bg_M)]
  631.   add       r9,r9,r14
  632.   ldrB      r14,[r5,r7,lsr #(32-bg_M)]
  633.   add       r9,r9,r14
  634.   ldrB      r14,[r5,r8,lsr #(32-bg_M)]
  635.   add       r9,r9,r14
  636.   ldrB      r14,[r4,r7,lsr #(32-bg_M)]
  637.   add       r9,r14,r9,lsl #1
  638.   ldrB      r14,[r4,r8,lsr #(32-bg_M)]
  639.   add       r9,r9,r14
  640.   ldrB      r14,[r6,r7,lsr #(32-bg_M)]
  641.   add       r9,r9,r14
  642.   ldrB      r14,[r6,r8,lsr #(32-bg_M)]
  643.   add       r9,r9,r14
  644.   mov       r9,r9,lsr #4            ; r9=smoothed intensity.
  645.   strB      r9,[r1],#1              ; Save new pixel value.
  646.   addS      r3,r3,#1<<(32-bg_M)     ; Next pixel.
  647.   bNE       _smooth_one
  648.   addS      r2,r2,#1<<(32-bg_M)     ; Next line.
  649.   bNE       _smooth_line
  650.   ldmfd     r13!,{r0-r9,pc}
  651.  
  652. ; ---------------------------------------------------------------------------
  653. ; ---                Routine creating a fractal landscape                 ---
  654. ; ---                          © Alain BROBECKER                          ---
  655. ; ---------------------------------------------------------------------------
  656. ; Recursive landscape creation. Considering a point in the landscape and
  657. ; the iteration (=width of square) we construct the points m4-m8 and
  658. ; go on recursively on all resulting four squares.
  659. ;    m0--m4--m1         h4=0.5*(h0+h1)+rnd
  660. ;    |   |   |          h5=0.5*(h1+h2)+rnd
  661. ;    m7--m8--m5         h6=0.5*(h2+h3)+rnd
  662. ;    |   |   |          h7=0.5*(h3+h0)+rnd
  663. ;    m3--m6--m2         h8=0.25*(h0+h1+h2+h3)+rnd
  664. ; Parameters are...
  665. ;     r0=adress of buffer for landscape.
  666. ;     r1=random number.
  667. ;     r2=1.
  668. ;     r3=iteration.
  669. ;     r4=posx.
  670. ;     r5=posy.
  671. .recursive_landscape
  672.   stmfd     r13!,{r3-r5,r14}
  673. ; At first, we calculate h4,h5,h6,h7 and h8.
  674.   add       r6,r4,r2,lsl r3
  675.   and       r6,r6,#bg_N-1           ; r6=(posx+2^iteration) mod(bg_N).
  676.   add       r7,r5,r2,lsl r3
  677.   and       r7,r7,#bg_N-1           ; r7=(posy+2^iteration) mod(bg_N).
  678.   add       r9,r4,r7,lsl #bg_M      ; r9 points on m3.
  679.   add       r8,r6,r7,lsl #bg_M      ; r8 points on m2.
  680.   add       r7,r6,r5,lsl #bg_M      ; r7 points on m1.
  681.   add       r6,r4,r5,lsl #bg_M      ; r6 points on m0.
  682.   ldrB      r6,[r0,r6]              ; r6=h0.
  683.   ldrB      r7,[r0,r7]              ; r7=h1.
  684.   ldrB      r8,[r0,r8]              ; r8=h2.
  685.   ldrB      r9,[r0,r9]              ; r9=h3.
  686.   sub       r10,r3,#1
  687.   mov       r10,r2,lsl r10          ; r10=2^(iteration-1).
  688. ; Calculation of m8.
  689.   add       r14,r6,r7
  690.   add       r14,r14,r8
  691.   add       r14,r14,r9              ; r14=h0+h1+h2+h3.
  692.   mov       r14,r14,asr #2          ; r14=0.25*(h0+h1+h2+h3).
  693.   random32  r1                      ; New random number.
  694.   rsb       r11,r3,#fractal+1       ; r11=fractal+1-iteration=shift for rnd.
  695.   addS      r14,r14,r1,asr r11      ; r14=0.25*(h0+h1+h2+h3)+rnd.
  696.   movLE     r14,#1                  ; Make sure 0<r14<256.
  697.   cmp       r14,#255
  698.   movGE     r14,#255
  699.   add       r12,r5,r10              ; Make r12 point on m8.
  700.   add       r12,r4,r12,lsl #bg_M
  701.   add       r12,r12,r10
  702.   strB      r14,[r0,r12]            ; Save h8.
  703. ; Calculation of m6.
  704.   add       r14,r8,r9               ; r14=h2+h3.
  705.   mov       r14,r14,asr #1          ; r14=0.5*(h2+h3).
  706.   random32  r1                      ; New random number.
  707.   rsb       r11,r3,#fractal         ; r11=fractal-iteration=shift for rnd.
  708.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h2+h3)+rnd.
  709.   movLE     r14,#1                  ; Make sure 1<r14<256.
  710.   cmp       r14,#255
  711.   movGE     r14,#255
  712.   add       r12,r5,r2,lsl r3        ; Make r12 point on m6.
  713.   add       r12,r4,r12,lsl #bg_M
  714.   add       r12,r12,r10
  715.   strB      r14,[r0,r12]            ; Save h6.
  716. ; Calculation of m5.
  717.   add       r14,r7,r8               ; r14=h1+h2.
  718.   mov       r14,r14,asr #1          ; r14=0.5*(h1+h2).
  719.   random32  r1                      ; New random number.
  720.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h1+h2)+rnd.
  721.   movLE     r14,#1                  ; Make sure 1<r14<256.
  722.   cmp       r14,#255
  723.   movGE     r14,#255
  724.   add       r12,r4,r2,lsl r3        ; Make r12 point on m5.
  725.   add       r12,r12,r5,lsl #bg_M
  726.   add       r12,r12,r10,lsl #bg_M
  727.   ldrB      r8,[r0,r12]             ; Load value at m5.
  728.   cmp       r8,#0                   ; Pixel already set?
  729.   strEQB    r14,[r0,r12]            ; Else save h5.
  730. ; Calculation of m4.
  731.   add       r14,r6,r7               ; r14=h0+h1.
  732.   mov       r14,r14,asr #1          ; r14=0.5*(h0+h1).
  733.   random32  r1                      ; New random number.
  734.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h0+h1)+rnd.
  735.   movLE     r14,#1                  ; Make sure 1<r14<256.
  736.   cmp       r14,#255
  737.   movGE     r14,#255
  738.   add       r12,r4,r10              ; Make r12 point on m4.
  739.   add       r12,r12,r5,lsl #bg_M
  740.   ldrB      r8,[r0,r12]
  741.   cmp       r8,#0
  742.   strEQB    r14,[r0,r12]            ; Save h4.
  743. ; Calculation of m7.
  744.   add       r14,r6,r9               ; r14=h0+h3.
  745.   mov       r14,r14,asr #1          ; r14=0.5*(h0+h3).
  746.   random32  r1                      ; New random number.
  747.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h0+h3)+rnd.
  748.   movLE     r14,#0                  ; Make sure 1<r14<256.
  749.   cmp       r14,#255
  750.   movGE     r14,#255
  751.   add       r12,r5,r10              ; Make r12 point on m7.
  752.   add       r12,r4,r12,lsl #bg_M
  753.   ldrB      r8,[r0,r12]
  754.   cmp       r8,#0
  755.   strEQB    r14,[r0,r12]            ; Save h7.
  756. ; Second part, recursive call.
  757.   subS      r3,r3,#1
  758.   ldmEQfd   r13!,{r3-r5,pc}         ; Stop recusrion when iter=0.
  759.   bl        recursive_landscape     ; Else go on with four subsquares.
  760.   add       r4,r4,r2,lsl r3         ;   start pos=m4.
  761.   bl        recursive_landscape
  762.   add       r5,r5,r2,lsl r3         ;   start pos=m8.
  763.   bl        recursive_landscape
  764.   sub       r4,r4,r2,lsl r3         ;   start pos=m7.
  765.   bl        recursive_landscape
  766.   ldmfd     r13!,{r3-r5,pc}
  767.  
  768. ; ---------------------------------------------------------------------------
  769. ; ---                Routine copying an aligned 8 bpp box                 ---
  770. ; ---                          © Alain BROBECKER                   May 96 ---
  771. ; ---------------------------------------------------------------------------
  772. ; * This routine copies the box between (x1-x1mod8;y1) and (x2+8-x2mod8;y2)
  773. ; from the source to the destination. This routine is mostly aimed at
  774. ; screenparts clearing.
  775. ; * r13 is saved just after the generated code, so we can use it for the
  776. ; ldmia-stmia copy. But we have to generate the instructions which will
  777. ; restore it at the end of routine.
  778. ; * There are many other tricks (for the generation of 'bGE'...) but I won' t
  779. ; explain them since code is widely commented.
  780. ;
  781. ; Parameters are...
  782. ;     r0 = source adress.
  783. ;     r1 = destination adress.
  784. ;     r2 = x1.    1------+
  785. ;     r3 = y1.    |      |
  786. ;     r4 = x2.    |      |
  787. ;     r5 = y2.    +------2
  788. .CopyBigBox256
  789.   cmp       r2,#320                 ; At first check if the box is
  790.   cmpLT     r3,#256                 ;   completly out of screen, and in
  791.   movGE     pc,r14                  ;   such case we quit.
  792.   cmp       r4,#0
  793.   cmpGE     r5,#0
  794.   movLT     pc,r14
  795.   stmfd     r13!,{r0-r12,r14}       ; Be clean or die.
  796.   cmp       r2,#0                   ; Perform the clipping.
  797.   movLT     r2,#0
  798.   cmp       r3,#0
  799.   movLT     r3,#0
  800.   cmp       r4,#320
  801.   movGE     r4,#319
  802.   cmp       r5,#256
  803.   movGE     r5,#255
  804.   mov       r2,r2,lsr #2            ; r2=x1>>2.
  805.   rsbS      r4,r2,r4,lsr #2         ; r4=x2>>2-x1>>2=nb_longs-1.
  806.   subGES    r14,r5,r3               ; r14=dy=y2-y1.
  807.   ldmMIfd   r13!,{r0-r12,pc}        ; Quit if nb_longs-1<0 or dy<0.
  808.   add       r3,r3,r3,lsl #2         ; r3=y1*5.
  809.   add       r3,r2,r3,lsl #4         ; r3=y1*80+x1>>2.
  810.   add       r0,r0,r3,lsl #2         ; r0=source+y1*320+4*(x1>>2).
  811.   add       r1,r1,r3,lsl #2         ; r1=dest+y1*320+4*(x1>>2).
  812. .StrongBranch1
  813.   b         _StrongCopyBox          ; If SA is absent, will be replaced by...
  814. ;  add       r2,r4,#1                ; r2=nb_longs.
  815.   rsb       r3,r2,#80               ; r3=nb longs to pass each line=offset/4.
  816.   adr       r4,_code+4              ; Code will be generated here.
  817.   adr       r5,_opcodes
  818.   ldmia     r5,{r6-r11}             ; Load some opcodes.
  819. ._one_copy_max
  820.   subS      r2,r2,#12               ; More than 12 longs left?
  821.   stmGEia   r4!,{r6-r7}             ; Yes then save one ldmia+stmia max.
  822.   bGT       _one_copy_max           ; r2>0? Then test again.
  823.   bEQ       _generate_add           ; r2=0? Then no more copy.
  824.   add       r5,r5,r2,lsl #3         ; r5 point on opcodes for last copy.
  825.   ldmda     r5,{r6-r7}              ; Load them.
  826.   cmp       r2,#-11                 ; Last fill instruction is a str?
  827.   addEQ     r6,r6,r3,lsl #2         ; Then r6='ldr r2,[r0],#offset+4',
  828.   addEQ     r7,r7,r3,lsl #2         ;   and r7='str r2,[r1],#offset+4'.
  829.   stmia     r4!,{r6-r7}             ; Save last fill instruction.
  830.   bEQ       _end_generate_add       ; No need of an add if we have an str.
  831. ._generate_add
  832.   cmp       r3,#0                   ; Offset is null?
  833.   addNE     r8,r8,r3                ; No, then r8='add r0,r0,#(offset/4)<<2',
  834.   addNE     r9,r9,r3                ;   r9='add r1,r1,#(offset/4)<<2',
  835.   stmNEia   r4!,{r8-r9}             ;   and save instructions.
  836. ._end_generate_add
  837.   adr       r9,_code-2*4            ; Beware the pipeline.
  838.   sub       r9,r9,r4                ; r9=offset for the bGE.
  839.   mov       r9,r9,asr #2            ; r9=offset/4. (higher byte=&ff)
  840.   eor       r9,r9,#&55<<24          ; r9=&AAxxxxxx='bGE offset'.
  841.   stmia     r4!,{r9-r11,r13}        ; Save instructions and stack.
  842. ._code
  843.   subS      r14,r14,#1              ; One line will be drawn.
  844.   dbd       8*2+4                   ; Space for the code and stack.
  845.  
  846.   ldr       r2,[r0],#4              ; Opcodes for last copy instruction.
  847.   str       r2,[r1],#4
  848.   ldmia     r0!,{r2-r3}
  849.   stmia     r1!,{r2-r3}
  850.   ldmia     r0!,{r2-r4}
  851.   stmia     r1!,{r2-r4}
  852.   ldmia     r0!,{r2-r5}
  853.   stmia     r1!,{r2-r5}
  854.   ldmia     r0!,{r2-r6}
  855.   stmia     r1!,{r2-r6}
  856.   ldmia     r0!,{r2-r7}
  857.   stmia     r1!,{r2-r7}
  858.   ldmia     r0!,{r2-r8}
  859.   stmia     r1!,{r2-r8}
  860.   ldmia     r0!,{r2-r9}
  861.   stmia     r1!,{r2-r9}
  862.   ldmia     r0!,{r2-r10}
  863.   stmia     r1!,{r2-r10}
  864.   ldmia     r0!,{r2-r11}
  865.   stmia     r1!,{r2-r11}
  866.   ldmia     r0!,{r2-r12}
  867.   stmia     r1!,{r2-r12}
  868.   stmia     r0!,{r1-r12}
  869. ._opcodes
  870.   ldmia     r0!,{r2-r13}            ; Maximum copying instructions.
  871.   stmia     r1!,{r2-r13}
  872.   dcd       &e2800f00               ; Opcode of 'add r0,r0,#0<<2'.
  873.   dcd       &e2811f00               ; Opcode of 'add r1,r1,#0<<2'.
  874.   ldr       r13,[pc,#0]             ; Load stack which is 8 bytes after.
  875.   ldmfd     r13!,{r0-r12,pc}        ; And quit.
  876.  
  877. ;---- StongARM version. No generated code. ----------------------------------
  878. ._StrongCopyBox
  879.   adr        r6,_next_hline
  880.   add        r14,r14,#1
  881. ._one_hline
  882.   mov        r2,r0
  883.   mov        r3,r1
  884.   sub       pc,r6,r4,lsl #3
  885. #rept 79
  886.   ldr        r5,[r2],#4
  887.   str        r5,[r3],#4
  888. #endr
  889. ._next_hline
  890.   ldr        r5,[r2],#4
  891.   str        r5,[r3],#4
  892.   add        r0,r0,#320
  893.   add        r1,r1,#320
  894.   subS        r14,r14,#1
  895.   bNE        _one_hline
  896.   ldmfd        r13!,{r0-r12,pc}
  897.  
  898.  
  899. ; ---------------------------------------------------------------------------
  900. ; ---                     Routine drawing a 8 bpp box                     ---
  901. ; ---                          © Alain BROBECKER                   May 96 ---
  902. ; ---------------------------------------------------------------------------
  903. ; * This routine draws the box between (x1;y1) and (x2;y2) on the mode13
  904. ; screen with the given filling pattern.
  905. ; * r13 is saved just after the generated code, so we can use it for the
  906. ; ldmia-stmia copy. But we have to generate the instructions which will
  907. ; restore it at the end of routine.
  908. ; * The last filling instruction (str, strB or add, to modify the adress)
  909. ; is generated with the stmia used for the endcode generation.
  910. ; * Most times (>75%) we won' t need an add to modify offsets, so I choosed
  911. ; to branch in such cases instead of cases when we have a str(B).
  912. ; * There are many other tricks (for the generation of 'bGE'..) but I won' t
  913. ; explain them since code is widely commented.
  914. ;
  915. ; Parameters are...
  916. ;     r0 = screen adress.
  917. ;     r1 = filling pattern.
  918. ;     r2 = x1.    1------+
  919. ;     r3 = y1.    |      |
  920. ;     r4 = x2.    |      |
  921. ;     r5 = y2.    +------2
  922. .FastBox256
  923.   cmp       r2,#320                 ; At first check if the box is
  924.   cmpLT     r3,#256                 ;   completly out of screen, and in
  925.   movGE     pc,r14                  ;   such case we quit.
  926.   cmp       r4,#0
  927.   cmpGE     r5,#0
  928.   movLT     pc,r14
  929.   stmfd     r13!,{r0-r12,r14}       ; Be clean or die.
  930.   cmp       r2,#0                   ; Perform the clipping.
  931.   movLT     r2,#0
  932.   cmp       r3,#0
  933.   movLT     r3,#0
  934.   cmp       r4,#320
  935.   movGE     r4,#319
  936.   cmp       r5,#256
  937.   movGE     r5,#255
  938.   subS      r14,r5,r3               ; r14=dy=y2-y1.
  939.   subGES    r5,r4,r2                ; r5=dx=x2-x1.
  940.   ldmMIfd   r13!,{r0-r12,pc}        ; Quit if dy<0 or dx<0.
  941.   add       r3,r3,r3,lsl #2         ; r3=y1*5.
  942.   add       r0,r0,r3,lsl #6         ; r0=screen+y1*320.
  943. .StrongBranch2
  944.   b         _StrongFastBox          ; If SA is absent, will be replaced by...
  945. ;  add       r0,r0,r2                ; r0=screen+y1*320+x1.
  946.   mov       r3,r2,lsr #2            ; r3=x1/4.
  947.   rsbS      r3,r3,r4,lsr #2         ; r3=x2/4-x1/4=nb_longs.
  948.   adr       r7,_small_adr           ; r7 points on adresses for small boxes.
  949.   ldrEQ     pc,[r7,r5,lsl #2]       ; nb_longs=0, then execute small box rout.
  950.   rsb       r5,r5,#319              ; r5=319-dx=nb of bytes to pass each line.
  951.   adr       r6,_code+4              ; Generate code here.
  952.   ldmdb     r7!,{r8-r11}            ; Load some opcodes.
  953. ; Here we begin to care about first longword filling.
  954.   andS      r2,r2,#%11              ; r2=x1 mod(3).
  955.   bEQ       _first_long_full        ; If x1 mod(3)=0, first long is full.
  956.   sub       r3,r3,#1                ; Else first long mustn' t be drawn.
  957.   tst       r2,#%01                 ; Down bit of x1 set?
  958.   strNE     r8,[r6],#4              ; Then we have an odd nb of strB.
  959.   tst       r2,r2,lsl #1            ; bit1 AND bit0 of x1 cleared?
  960.   strEQ     r8,[r6],#4              ; Then x1 mod(3)=1 or 2, so we must
  961.   strEQ     r8,[r6],#4              ;   generate two strB more.
  962. ._first_long_full
  963.   and       r4,r4,#%11              ; r4=x2 mod(3).
  964.   and       r2,r4,r4,lsr #1         ; r2=bit1 AND bit0 of x2 mod(3).
  965.   addS      r3,r3,r2                ; If x2 mod(3)=%11, last long is full.
  966.   bEQ       _last_longword          ; If nb_longs=0 go to last long.
  967. ._one_stmia_max
  968.   subS      r3,r3,#13               ; More than 13 longs left?
  969.   strGE     r9,[r6],#4              ; Yes, then save one stmia max.
  970.   bGT       _one_stmia_max          ; r3>0? Then test again.
  971.   ldrMI     r9,[r7,r3,lsl #2]       ; If r3<0 then load opcode of last long
  972.   strMI     r9,[r6],#4              ;   fill instruction and save it.
  973. ._last_longword
  974.   teq       r4,#%11                 ; x2 mod(3)=%11?
  975.   bEQ       _last_long_full         ; Then last long is full.
  976.   tst       r4,#%01                 ; Down bit clear?
  977.   strEQ     r8,[r6],#4              ; Then we have an odd nb of strB.
  978.   teq       r4,r4,lsl #1            ; bit1 EOR bit0<>0?
  979.   strNE     r8,[r6],#4              ; Then x2 mod(3)=1 or 2, then there
  980.   strNE     r8,[r6],#4              ;   are two strB more.
  981. ._last_long_full
  982.   ldr       r8,[r6,#-4]!            ; Load last saved instruction.
  983.   tst       r8,#1<<26               ; Is it a str or strB?
  984.   bEQ       _generate_add           ; No, then we' ll need an add.
  985.   add       r8,r8,r5                ; Yes, then add to 319-dx to offset.
  986. ._generate_endcode
  987.   adr       r9,_code-3*4            ; Beware the pipeline and last instruction.
  988.   sub       r9,r9,r6                ; r9=offset for the bGE.
  989.   mov       r9,r9,asr #2            ; r9=offset/4. (higher byte=&ff)
  990.   eor       r9,r9,#&55<<24          ; r9=&AAxxxxxx='bGE offset'.
  991.   stmia     r6!,{r8-r11,r13}        ; Save instructions and stack.
  992.   mov       r2,r1                   ; Put pattern in other longwords.
  993.   mov       r3,r1
  994.   mov       r4,r1
  995.   mov       r5,r1
  996.   mov       r6,r1
  997.   mov       r7,r1
  998.   mov       r8,r1
  999.   mov       r9,r1
  1000.   mov       r10,r1
  1001.   mov       r11,r1
  1002.   mov       r12,r1
  1003.   mov       r13,r1
  1004. ._code
  1005.   subS      r14,r14,#1              ; One line will be drawn.
  1006.   dbd       3+6+3+4                 ; Space for the code and stack.
  1007.  
  1008. ._generate_add
  1009.   cmp       r5,#0                   ; Offset is null?
  1010.   bEQ       _generate_endcode       ; Then go on...
  1011.   add       r6,r6,#4                ; Don' t modify loaded instruction.
  1012.   mov       r8,#&e28<<20            ; r8=opcode of 'add r0,r0,#0'.
  1013.   cmp       r5,#255                 ; Offset bigger than 255?
  1014.   addGE     r2,r8,#255              ; Then generate an 'add r0,r0,#255'
  1015.   strGE     r2,[r6],#4
  1016.   subGE     r5,r5,#255              ;   and substract 255 to offset.
  1017.   add       r8,r8,r5                ; r8='add r0,r0,#offset'.
  1018.   b         _generate_endcode
  1019.  
  1020.   str       r1,[r0],#4              ; Opcodes for lasts longs filling.
  1021.   stmia     r0!,{r1-r2}
  1022.   stmia     r0!,{r1-r3}
  1023.   stmia     r0!,{r1-r4}
  1024.   stmia     r0!,{r1-r5}
  1025.   stmia     r0!,{r1-r6}
  1026.   stmia     r0!,{r1-r7}
  1027.   stmia     r0!,{r1-r8}
  1028.   stmia     r0!,{r1-r9}
  1029.   stmia     r0!,{r1-r10}
  1030.   stmia     r0!,{r1-r11}
  1031.   stmia     r0!,{r1-r12}
  1032. ._opcodes
  1033.   strB      r1,[r0],#1              ; Byte filling instruction.
  1034.   stmia     r0!,{r1-r13}            ; Maximum filling instruction.
  1035.   ldr       r13,[pc,#0]             ; Load stack which is 8 bytes after.
  1036.   ldmfd     r13!,{r0-r12,pc}        ; And quit.
  1037. ._small_adr
  1038.   dcd       _small1                 ; Adresses for the routines corresponding
  1039.   dcd       _small2                 ;   to x1-x2 being in same longword.
  1040.   dcd       _small3
  1041.   dcd       _small4
  1042. ; Here are the routine for small boxes.
  1043. ._small1
  1044.   strB      r1,[r0],#320
  1045.   subS      r14,r14,#1
  1046.   bGE       _small1
  1047.   ldmfd     r13!,{r0-r12,pc}
  1048. ._small2
  1049.   strB      r1,[r0],#1
  1050.   strB      r1,[r0],#319
  1051.   subS      r14,r14,#1
  1052.   bGE       _small2
  1053.   ldmfd     r13!,{r0-r12,pc}
  1054. ._small3
  1055.   strB      r1,[r0],#1
  1056.   strB      r1,[r0],#1
  1057.   strB      r1,[r0],#318
  1058.   subS      r14,r14,#1
  1059.   bGE       _small3
  1060.   ldmfd     r13!,{r0-r12,pc}
  1061. ._small4
  1062.   str       r1,[r0],#320
  1063.   subS      r14,r14,#1
  1064.   bGE       _small4
  1065.   ldmfd     r13!,{r0-r12,pc}
  1066.  
  1067. ;---- StongARM version. No generated code. ----------------------------------
  1068. ._StrongFastBox
  1069.   adr        r6,_next_hline
  1070.   add        r4,r4,#1
  1071.   add        r14,r14,#1
  1072. ._one_hline
  1073.   add       r3,r0,r2                ; r3=@xleft.
  1074.   add        r5,r0,r4            ; r5=@xright.
  1075.   cmp       r5,r3                   ; xright=<xleft?
  1076.   bLE       _next_hline
  1077.   tst       r3,#%01
  1078.   strNEB    r1,[r3],#1
  1079.   tst       r5,#%01
  1080.   strNEB    r1,[r5,#-1]!
  1081.   cmp       r5,r3
  1082.   bLE       _next_hline
  1083.   tst       r3,#%10
  1084.   strNEB    r1,[r3],#1
  1085.   strNEB    r1,[r3],#1
  1086.   tst       r5,#%10
  1087.   strNEB    r1,[r5,#-1]!
  1088.   strNEB    r1,[r5,#-1]!
  1089.   sub       r5,r5,r3                ; r5=nb of longs to fill*4.
  1090.   sub       pc,r6,r5
  1091. #rept 80
  1092.   str        r1,[r3],#4
  1093. #endr
  1094. ._next_hline
  1095.   add        r0,r0,#320
  1096.   subS        r14,r14,#1
  1097.   bNE        _one_hline
  1098.   ldmfd        r13!,{r0-r12,pc}
  1099.  
  1100. ;----------------------->  THIS MUST BE AT VERY END  <-----------------------
  1101. .bss
  1102.