home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / demos / baah / Damn! / damn!src / damn!src < prev    next >
Encoding:
Text File  |  1997-02-15  |  93.5 KB  |  1,997 lines

  1. ;                                     \|/
  2. ;                                     O O
  3. ; --------------------------------oOO--U--OOo--------------------------------
  4. ; -                                                                         -
  5. ; -                                damn!demo                                -
  6. ; -                   © Alain BROBECKER (baah/Arm'sTeack)                   -
  7. ; -                                                            July-Sept 96 -
  8. ; ---------------------------------------------------------------------------
  9. ;
  10. ;   This source is given for free and is widely commented, so I hope some
  11. ; people will look at it and (maybe) improve their own code. Re-use of my
  12. ; routines is allowed (though not recommended, cos you' ll understand more
  13. ; if you write your owns...) as long as it is not for commercial purposes,
  14. ; as long as you credit me and send me a free copy of your proggy. Oh, btw
  15. ; the assembler I used is ExtASM 0.50b. You' ll have to make changes in
  16. ; macros if you use a newer version of ExtASM.
  17. ;
  18. ;           Alain BROBECKER         Dracula / Positivity (STe)
  19. ;           rte de Dardagny         baah / Arm's Tech (Archie)
  20. ;            01630 CHALLEX                       baah (PC-C64)
  21. ;               FRANCE
  22. ;
  23. ; 15 Feb 97 - StrongARM compatible version... FastBox and CopyBox routines
  24. ;             are no more using generated code when SA is detected.
  25. ;           - Added exit handler.
  26.  
  27. #name       damn!
  28. #set        zizik = 1               ; 1 for the beauty, 0 for the beast.
  29.  
  30. ;------ Constants -----------------------------------------------------------
  31. #set        XScreenBlanker_Control = &ef063100 ; Value of the swi.
  32. #set        XOS_PlatformFeatures = &2006d ; Value for the swi.
  33. #set        screennb_min = 3        ; Minimum number of mode13 screens.
  34. #set        screennb_max = 8        ; Maximum number.
  35. #set        inv_N = 18              ; Shift for fixed point inverses.
  36. #set        inv_nb = 4096+1024      ; Nb of inverses to calculate.
  37. #set        sin_N = 14              ; Shift for fixed point sinuses.
  38. #set        sin_pow = 10            ; 2^sin_pow is the nb of angles.
  39. #set        sin_nb = 1<<(sin_pow-3) ; Nb of angles between [0;pi/4[.
  40. #set        bg_M = 8                ; Well, texture must be a power of 2, so
  41. #set        bg_N = 1<<bg_M          ;   bg_N=2^bg_M is the size of texture.
  42. #set        bg_middle = 8           ; Intensity for null relief*2.
  43. #set        fractal = 30            ; Value for shift of rnd nb in fracland.
  44.  
  45. #set        hclip = 304             ; Values for horizontal and vertical
  46. #set        vclip = 200             ;   clipping in poly rout.
  47. #set        max_checker_height = 7
  48. #set        nb_pts_objects = 13+9+8+1 ; Nb of points for objects.
  49. #set        nb_pts = 1024           ; Total nb of points for vectorworld.
  50. #set        nb_faces = 1024         ; And the total nb of faces.
  51.  
  52. ;------ BSS Offsets ---------------------------------------------------------
  53. #set        stack = 128*4           ; Top of stack.
  54. #set        extra = stack           ; Extra storage, just before inverses.
  55. #set        inverses = extra+12*4   ; Inverses table.
  56. #set        sinus = inverses+inv_nb*4 ; Sinus table.
  57. #set        background = sinus+10*sin_nb*4 ; Background.
  58. #set        clsboxes = background+320*256 ; Coords for clear boxes.
  59. #set        misc = clsboxes+4*screennb_max*4 ; Extra.
  60. #set        end = misc+8*1024
  61.  
  62. #set        screen_xy = background  ; Projected x&y coords.
  63. #set        space_z = screen_xy+2*nb_pts*4 ; z coord of points.
  64. #set        static_sort = space_z+nb_pts*4 ; Z table.
  65. #set        dynamic_sort = static_sort+inv_nb*4 ; Faces table with link.
  66. #set        end3d = dynamic_sort+nb_faces*2*4
  67.  
  68.  
  69. ;****************************************************************************
  70. ;****************************************************************************
  71. ;*****                                                                  *****
  72. ;*****                              MACROS                              *****
  73. ;*****                                                                  *****
  74. ;****************************************************************************
  75. ;****************************************************************************
  76.  
  77. ;====> Umul64 <=====================
  78. ; This macro performs an unsigned 32*32 bits multiply.
  79. ;   [m0|m1]=m2*m3. You can choose [m2|m3]=[m0|m1]
  80. ;   It destroys m0,m1,m4,m5,m6 and the flags. (C is the carry flag)
  81. macro umul64 m0,m1,m2,m3,m4,m5,m6
  82. { mov       m4,m2,lsr #16           ; m4=up(m2).
  83.   sub       m5,m2,m4,lsl #16        ; m5=down(m2).
  84.   mov       m0,m3,lsr #16           ; m0=up(m3).
  85.   sub       m1,m3,m0,lsl #16        ; m1=down(m3).
  86.   mul       m6,m5,m0                ; m6=down(m2)*up(m3).
  87.   mul       m0,m4,m0                ; m0=up(m2)*up(m3).
  88.   mlaS      m6,m1,m4,m6             ; C+m6=up(m2)*down(m3)+down(m2)*up(m3).
  89.   adc       m0,m0,m6,lsr #16
  90.   mul       m1,m5,m1                ; m1=down(m2)*down(m3).
  91.   addS      m1,m1,m6,lsl #16
  92.   adc       m0,m0,#0                ; [m0|m1]=m2*m3.
  93. }
  94. ;====> Adjust64 <===================
  95. ; This macro adjusts the 64 bits result to 32 bits, according to the fixed
  96. ; point shift factor. (c0)
  97. ;   m0=[m1|m2]>>c0. You can choose m1=m0.
  98. ;   It destroys m0.
  99. macro adjust64 m0,m1,m2,c0
  100. { mov       m0,m1,lsl #32-c0
  101.   add       m0,m0,m2,lsr #c0
  102. }
  103. ;====> Add64 <======================
  104. ; This macro performs a 64 bits addition.
  105. ;   [m0|m1]=[m2|m3]+[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
  106. ;   It destroys [m0|m1] and the flags.
  107. macro add64 m0,m1,m2,m3,m4,m5
  108. { addS      m1,m3,m5
  109.   adc       m0,m2,m4
  110. }
  111. ;====> Sub64 <======================
  112. ; This macro performs a 64 bits substract.
  113. ;   [m0|m1]=[m2|m3]-[m4|m5]. You can choose [m2|m3] or [m4|m5]=[m0|m1].
  114. ;   It destroys [m0|m1] and the flags.
  115. macro sub64 m0,m1,m2,m3,m4,m5
  116. { subS      m1,m3,m5
  117.   sbc       m0,m2,m4
  118. }
  119. ;====> Sqrt32 <=====================
  120. ; This macro extracts the squareroot of a 32 bits register.
  121. ;  m0=sqrt(m1).
  122. ;  It destroys m0,m1,m2 and the flags.
  123. macro sqrt32 m0,m1,m2
  124. { mov       m0,#0                   ; This is ripped from Jan/BASS.
  125.   mov       m2,#1<<30               ;  |
  126.   cmp       m1,m2                   ;  |
  127.   subCS     m1,m1,m2                ;  |
  128.   adc       m0,m0,m0                ;  |
  129. #set N=2
  130. #rept 15
  131.   add       m2,m0,#1<<30            ;  |
  132.   cmp       m1,m2,ror #N            ;  |
  133.   subCS     m1,m1,m2,ror #N         ;  |
  134.   adc       m0,m0,m0                ; End of ripped code.
  135. #set N=N+2
  136. #endr
  137.   cmp       m1,m0                   ; Flags=val-root.
  138.   addPL     m0,m0,#1                ; Round to nearest integer.
  139. }
  140. ;====> Random32 <===================
  141. ; This macro takes a random number, and makes a new one.
  142. macro random32 m0
  143. { eor       m0,m0,m0,rrx
  144.   adc       m0,m0,m0,ror #7
  145. }
  146. ;====> Swap32 <=====================
  147. ; This macro exchanges the contents of m0 and m1.
  148. macro swap32 m0,m1
  149. { add       m0,m0,m1                ; m0=a+b.
  150.   sub       m1,m0,m1                ; m1=a+b-b=a.
  151.   sub       m0,m0,m1                ; m0=a+b-a=b.
  152. }
  153. ;====> YX Matrix <==================
  154. ; This macro calculates the coefficient of the XY rotation matrix.
  155. ; IN  - m0 adress of sinus table
  156. ;       m1=ay. (In top bits (for modulo) other bits set to 0)
  157. ;       m4=ax.
  158. ; OUT - m1=A | m2=C | m3=D | m4=E | m5=F | m6=G | m7=H | m8=I
  159. macro yx_matrix m0,m1,m2,m3,m4,m5,m6,m7,m8
  160. { sub       m3,m1,m4                ; m3=ay-ax.
  161.   add       m8,m1,m4                ; m8=ay+ax.
  162.   ldr       m2,[m0,m1,lsr #32-sin_pow-2] ; m2=sin(ay)=-C.
  163.   rsb       m2,m2,#0                ; m2=-sin(ay)=C.
  164.   ldr       m7,[m0,m4,lsr #32-sin_pow-2] ; m7=sin(ax)=-H.
  165.   rsb       m7,m7,#0                ; m7=-sin(ax)=H.
  166.   ldr       m6,[m0,m3,lsr #32-sin_pow-2] ; m6=sin(ay-ax).
  167.   ldr       m5,[m0,m8,lsr #32-sin_pow-2] ; m5=sin(ay+ax).
  168.   sub       m5,m5,m6                ; m5=sin(ay+ax)-sin(ay-ax)=2*F.
  169.   mov       m5,m5,asr #1            ; m5=int((sin(ay+ax)-sin(ay-ax))/2)=F.
  170.   add       m6,m5,m6                ; m6=int((sin(ay+ax)+sin(ay-ax))/2)=G.
  171.   add       m0,m0,#2*sin_nb*4       ; m0 points on cosinus table.
  172.   ldr       m1,[m0,m1,lsr #32-sin_pow-2] ; m1=cos(ay)=A.
  173.   ldr       m4,[m0,m4,lsr #32-sin_pow-2] ; m4=cos(ax)=E.
  174.   ldr       m3,[m0,m3,lsr #32-sin_pow-2] ; m3=cos(ay-ax).
  175.   ldr       m8,[m0,m8,lsr #32-sin_pow-2] ; m8=cos(ay+ax).
  176.   sub       m3,m3,m8                ; m3=cos(ay-ax)-cos(ay+ax)=2*D.
  177.   mov       m3,m3,asr #1            ; m3=int((cos(ay-ax)-cos(ay+ax))/2)=D.
  178.   add       m8,m3,m8                ; m8=int((cos(ay-ax)+cos(ay+ax))/2)=I.
  179. }
  180.  
  181. ;****************************************************************************
  182. ;****************************************************************************
  183. ;*****                                                                  *****
  184. ;*****                               CODE                               *****
  185. ;*****                                                                  *****
  186. ;****************************************************************************
  187. ;****************************************************************************
  188.  
  189. ; Initialise stack, deinit screen blanker and ask for slot+screen memory.
  190. .proggy_start
  191.   adr       r13,bss+stack           ; Initialise stack pointer.
  192.   mov       r0,#1                   ; Read screenblanker control.
  193.   swi       XScreenBlanker_Control  ; r0=screenblanker infos.
  194.   movVS     r0,#0                   ; Error, then set them to 0.
  195.   str       r0,old_scrblank         ; Save infos.
  196.   mov       r0,#3                   ; Write screenblanker control.
  197.   mov       r1,#0                   ; Set it to 0.
  198.   swi       XScreenBlanker_Control
  199.   mov       r0,#bss+end-&8000       ; Ask for needed slot memory.
  200.   mov       r1,#-1                  ; Don' t change next slot size.
  201.   swi       Wimp_SlotSize
  202.   mov       r0,#2                   ; Ask for ScreenMem size.
  203.   swi       OS_ReadDynamicArea      ; r1=current ScreenMem size.
  204.   rsbS      r1,r1,#screennb_min*81920 ; r1=minimum-curent screenmem.
  205.   movGT     r0,#2                   ; Ask for it if we don' t have enough.
  206.   swiGT     OS_ChangeDynamicArea
  207.   mov       r0,#screennb_min        ; Count the number of screen banks.
  208. ._count_screens
  209.   addS      r1,r1,#81920            ; r1+=size of one mode13 screen.
  210.   addLE     r0,r0,#1                ; If r1 still <=0, we have one more bank.
  211.   bLT       _count_screens          ; If r1<0, maybe there is even more...
  212.   cmp       r0,#screennb_max        ; More than the maximum amount?
  213.   movGE     r0,#screennb_max        ; Then don' t use extra ones.
  214.   strB      r0,vbl_screennb_mov     ; Modify code which needs ScreenNb
  215.   strB      r0,vsync_screennb_mov   ;   for multiple buffering,
  216.   strB      r0,clear_one_screen_mov ;   and for screen clearing.
  217. ;----------------------------------------------------------------------------
  218. ; If StrongARM is not there, modify branches in routines so that we use
  219. ; versions with generated code.
  220.   mov        r0,#0
  221.   swi       XOS_PlatformFeatures    ; Read platform feature.
  222.   bvs       noStrongARM             ; If swi is unknown, no StrongARM.
  223.   tst       r0,#1            ; Separated instruction and data caches.
  224.   bne        StrongARMed
  225. .noStrongARM
  226.   mov       r0,#&e0800002           ; r0="add r0,r0,r2".
  227.   str       r0,StrongBranch2
  228.   eor       r0,r0,#&02042003        ; r0=&e2842001="add r2,r4,#1".
  229.   str       r0,StrongBranch1
  230. .StrongARMed
  231. ;----------------------------------------------------------------------------
  232. ; Switch to the good video mode, and some more stupid bits.
  233.   swi       256+22                  ; Vdu 22, set screenmode.
  234.   swi       256+13                  ; Switch to mode 13.
  235.   swi       OS_RemoveCursors        ; Who needs them?
  236.   adr       r0,videoram_adress      ; Get videoram adress.
  237.   mov       r1,r0
  238.   swi       OS_ReadVduVariables
  239. #if zizik
  240.   mov       r0,#0                   ; Load music from memory.
  241.   adr       r1,music                ; Start of music.
  242.   mov       r2,r1                   ; It is not packed.
  243.   mov       r3,#bss-music           ; Length of dest adress.
  244.   adr       r4,bss+background       ; Adress of a 32Kb buffer.
  245.   mov       r11,#0                  ; DSym_Load=swi#0.
  246.   bl        player+&3C8             ; Jump into symphony's swi-jumptable.
  247. #endif
  248. ;----------------------------------------------------------------------------
  249. ; Clear the bss section, since some routines need it. I assume that bss+end
  250. ; is longword aligned. (So you must take care when defining bss offsets)
  251.   adr       r0,bss+stack            ; Begin to clear here.
  252.   mov       r1,#end-stack           ; Nb of bytes to clear.
  253.   mov       r2,#0
  254. .clear_bss
  255.   subS      r1,r1,#4                ; One long will be cleared.
  256.   str       r2,[r0,r1]
  257.   bNE       clear_bss
  258. ;----------------------------------------------------------------------------
  259. ; Creates the inverses table. This routine has been previously released
  260. ; through the "Memory War" article. (October 95)
  261. .make_inverses
  262.   adr       r0,bss+inverses+4       ; Create table here.
  263.   mov       r1,#1                   ; Used by the division routine.
  264.   mov       r2,#1                   ; r2 is the current divisor.
  265. ._make_one_inverse
  266.   mov       r3,#1<<inv_N            ; r3=dividend.
  267.   mov       r4,#0                   ; r4 will contain the quotient.
  268.   mov       r5,#15                  ; r5=Shift for the division.
  269. ._divide_one_step
  270.   cmp       r3,r2,lsl r5            ; dividend bigger than divisor<<r5?
  271.   subGE     r3,r3,r2,lsl r5         ; Yes, then dividend-=divisor<<r5,
  272.   addGE     r4,r4,r1,lsl r5         ;   and add 1<<r5 to the quotient.
  273.   subS      r5,r5,#1                ; Next shift.
  274.   bGE       _divide_one_step
  275.   cmp       r2,r3,lsl #1            ; Flags=divisor-2*rest.
  276.   addLE     r4,r4,#1                ; Round to nearest integer.
  277.   str       r4,[r0],#4              ; Save dividend/divisor.
  278.   add       r2,r2,#1                ; One inverse calculated.
  279.   cmp       r2,#inv_nb              ; It was the last one?
  280.   bNE       _make_one_inverse
  281. ;----------------------------------------------------------------------------
  282. ; Creates the sinus table. As for the inverses creation, the routine has
  283. ; already been released through "Memory War".
  284. .make_sinus
  285.   adr       r0,bss+sinus
  286.   ldr       r1,sinA                 ; r1=sinA*2^28.
  287.   ldr       r2,cosA                 ; r2=cosA*2^28.
  288.   mov       r3,#0                   ; r3=sin0*2^28.
  289.   mov       r4,#1<<28               ; r4=cos0*2^28.
  290.   mov       r5,#sin_nb+1
  291. .make_one_sinus
  292.   mov       r6,r4,lsr #28-sin_N     ; r6=cosN*2^sin_N.
  293.   str       r6,[r0,#sin_nb*2*4]     ; Save sin(N+pi/2)=cosN.
  294.   mov       r6,r3,lsr #28-sin_N     ; r6=sinN*2^sin_N.
  295.   str       r6,[r0],#4              ; Save sinN.
  296.   umul64 r6,r7,r1,r3,r8,r9,r10      ; [r6|r7]=sinN*sinA.
  297.   umul64 r8,r9,r2,r4,r10,r11,r12    ; [r8|r9]=cosN*cosA.
  298.   sub64 r6,r7,r8,r9,r6,r7           ; [r6|r7]=cos(N+1)=cosN*sin1-sinN*sin1.
  299.   umul64 r3,r8,r3,r2,r9,r10,r11     ; [r3|r8]=sinN*cosA.
  300.   umul64 r4,r9,r4,r1,r10,r11,r12    ; [r4|r9]=cosN*sinA.
  301.   add64 r3,r8,r3,r8,r4,r9           ; [r3|r8]=sin(N+1)=sinN*cos1+cosN*sin1.
  302.   adjust64 r3,r3,r8,28              ; r1=sin(N+1)=sinN*cos1+cosN*sin1.
  303.   adjust64 r4,r6,r7,28              ; r2=cos(N+1)=cosN*sin1-sinN*sin1.
  304.   subS      r5,r5,#1                ; One sinus processed.
  305.   bNE       make_one_sinus
  306.   sub       r0,r0,#4                ; Complete the table by stupid copy.
  307.   mov       r1,r0                   ; Point on the position which are like
  308.   add       r2,r0,#sin_nb*8         ;  (pi/4+k*(pi/2))   0<=k<=4
  309.   mov       r3,r2
  310.   add       r4,r2,#sin_nb*8
  311.   mov       r5,r4
  312.   add       r6,r4,#sin_nb*8
  313.   mov       r7,r6
  314.   add       r8,r6,#sin_nb*8
  315.   mov       r9,r8
  316.   mov       r10,#sin_nb+1           ; Copy sin_nb+1 values.
  317. ._make_sinus_copy
  318.   ldr       r11,[r0],#-4
  319.   str       r11,[r3],#4             ; sin(pi-X)=sinX.
  320.   str       r11,[r8],#-4            ; sin(2*pi+X)=sinX.
  321.   rsb       r11,r11,#0
  322.   str       r11,[r4],#-4            ; sin(pi+X)=-sinX.
  323.   str       r11,[r7],#4             ; sin(2*pi-X)=-sinX.
  324.   ldr       r11,[r2],#-4
  325.   str       r11,[r1],#4             ; cos(-X)=cosX.
  326.   subS      r10,r10,#1              ; One value copied.
  327.   strNE     r11,[r9],#4             ; cos(2*pi+X)=cosX. No copy if r10=0.
  328.   rsb       r11,r11,#0
  329.   str       r11,[r5],#4             ; cos(pi-X)=-cosX.
  330.   str       r11,[r6],#-4            ; cos(pi+X)=-cosX.
  331.   bNE       _make_sinus_copy
  332. ;----------------------------------------------------------------------------
  333. ; Creates the background texture. The main idea is to make a N*N fractal
  334. ; landscape, take the modulo of it, smooth, emboss and re-smooth it. The
  335. ; emboss and smoothing routines where already released in "Graphics War".
  336. .make_fracland
  337.   adr       r0,bss+background
  338.   ldr       r1,random_germ          ; Load the random germ.
  339.   mov       r2,#1                   ; This will be used by routine.
  340.   strB      r2,[r0]                 ; Also save 1 as upper left pixel.
  341.   mov       r3,#bg_M                ; Iteration=bg_M.
  342.   mov       r4,#0                   ; Position of upper left pixel.
  343.   mov       r5,#0
  344.   bl        recursive_landscape
  345.   ldr       r1,videoram_adress      ; Adress of a second buffer.
  346.   add       r1,r1,#320*256
  347.   bl        smooth_texture          ; Smooth texture.
  348. .emboss_texture
  349.   mov       r2,#0                   ; r2=y counter<<(32-bg_M).
  350. ._emboss_one_line
  351.   sub       r3,r2,#1<<(32-bg_M)     ; r3=(y-1) mod bg_N <<(32-bg_M). (Wrapping)
  352.   add       r4,r3,#1<<(32-bg_M)     ; r4=(y+1) mod bg_N <<(32-bg_M). (Wrapping)
  353.   add       r3,r1,r3,lsr #(32-2*bg_M); r3 points on src_line up.
  354.   add       r4,r1,r4,lsr #(32-2*bg_M); r4 points on src_line down.
  355.   mov       r5,#bg_N                ; r5=nb of pixels per line.
  356. ._emboss_one
  357.   ldrB      r14,[r3],#1             ; r14=pixie up.
  358.   ldrB      r6,[r4],#1              ; r6=pixie down.
  359.   and       r14,r14,#&1f            ; Take the modulo(32).
  360.   and       r6,r6,#&1f
  361.   sub       r6,r6,r14               ; r6=delta.
  362.   addS      r6,r6,#bg_middle        ; Add the middle constant.
  363.   movMI     r6,#0                   ; Make sure intensity is between 0-31.
  364.   cmp       r6,#31
  365.   rsbGE     r6,r6,#63
  366.   strB      r6,[r0],#1              ; Save it.
  367.   subS      r5,r5,#1                ; One pixel done
  368.   bNE       _emboss_one
  369.   addS      r2,r2,#1<<(32-bg_M)     ; Line done.
  370.   bNE       _emboss_one_line
  371.   sub       r0,r0,#bg_N*bg_N        ; r0 points back on buffer.
  372.   bl        smooth_texture          ; Smooth texture.
  373.   swap32    r0,r1
  374.   bl        smooth_texture
  375.   swap32    r0,r1
  376.   bl        smooth_texture
  377. ; Now convert the texture to 320*256 with bg_colors.
  378.   adr       r2,bg_colors
  379.   mov       r3,#bg_N                ; y counter.
  380. ._bg_convert_line
  381.   mov       r4,#bg_N                ; x counter.
  382. ._bg_convert_one
  383.   ldrB      r5,[r1],#1              ; Load pixel.
  384.   ldrB      r5,[r2,r5]              ; Load color.
  385.   cmp       r4,#bg_N-(320-bg_N)     ; If x<2*bg_N-320, then
  386.   strGTB    r5,[r0,#bg_N]           ;   copy pixel at r0+bg_N.
  387.   strB      r5,[r0],#1              ; Draw pixel.
  388.   subS      r4,r4,#1                ; One pixel done.
  389.   bNE       _bg_convert_one
  390.   add       r0,r0,#320-bg_N         ; Next line.
  391.   subS      r3,r3,#1                ; One line done.
  392.   bNE       _bg_convert_line
  393. ; Copy the arm's tech logo on background.
  394.   adr       r0,bss+background+10*320+64 ; Adress where to copy logo.
  395.   adr       r1,logo191_24
  396.   mov       r2,#24                  ; Nb of lines to copy.
  397. ._copy_logo_line
  398.   mov       r3,#191                 ; Nb of bytes to copy.
  399. ._copy_logo_byte
  400.   ldrB      r4,[r1],#1              ; Load one byte.
  401.   cmp       r4,#0                   ; Transparent pixel?
  402.   strNEB    r4,[r0,r3]              ; No, then copy it.
  403.   subS      r3,r3,#1                ; One byte drawn.
  404.   bNE       _copy_logo_byte
  405.   add       r0,r0,#320              ; Next line.
  406.   subS      r2,r2,#1
  407.   bNE       _copy_logo_line
  408. ;----------------------------------------------------------------------------
  409. ; Clear all screen banks.
  410.   ldr       r0,videoram_adress      ; Set parameters for the FastBox
  411.   mov       r1,#0                   ;   routine, so that it clears the
  412.   mov       r2,#0                   ;   whole screen.
  413.   mov       r3,#0
  414.   mov       r4,#319
  415.   mov       r5,#255
  416. .clear_one_screen_mov
  417.   mov       r6,#0                   ; r6=ScreenNb.
  418. .clear_one_screen
  419.   bl        FastBox256
  420.   add       r0,r0,#320*256          ; Next screen bank.
  421.   subS      r6,r6,#1                ; One screen copies.
  422.   bNE       clear_one_screen
  423. ;----------------------------------------------------------------------------
  424. ; Enables our Vertical Blanking (VBl) interrupt and change exit handler.
  425.   mov       r0,#&10                 ; Claim event vector. (&10)
  426.   adr       r1,vbl_routine          ; Adress of claiming routine.
  427.   adr       r2,workscr_nb           ; Value to pass in r12 when rout is called.
  428.   swi       OS_Claim
  429.   mov       r0,#&e                  ; Enable an event.
  430.   mov       r1,#4                   ; Event 4=VBl.
  431.   swi       OS_Byte
  432.   mov        r0,#11            ; Assign exit handler.
  433.   adr        r1,proggy_exit          ; This is the terminal routine.
  434.   mov        r2,r13            ; Will be in r12 when OS_Exit called.
  435.   swi        OS_ChangeEnvironment
  436.   stmfd        r13!,{r1-r3}            ; Save old environment.
  437.  
  438. ;############################################################################
  439. ;#####                        CRASHING LOGO PART                        #####
  440. ;############################################################################
  441. ; At first we create the movements for the crashing 'pixels' of the logo.
  442.   adr       r0,bss+misc             ; Store calculi here.
  443.   adr       r1,bss+inverses
  444.   ldr       r2,random_germ
  445.   adr       r3,logo_1bpp            ; Here is the logo.
  446.   mov       r4,#1                   ; Counter for 1bpp logo longs.
  447.   mov       r5,#-8<<9               ; r5=y_counter*4*256.
  448. .calc_crash_y
  449.   mov       r6,#-35<<9              ; r6=x_counter*4*256.
  450.   mul       r7,r5,r5                ; r7=y_counter^2*(4*256)^2.
  451. .calc_crash_x
  452.   add       r8,r6,#158<<8           ; Recenter.
  453.   add       r9,r5,#124<<8
  454.   mla       r10,r6,r6,r7            ; r10=(x^2+y^2)*(4*256)^2.
  455.   sqrt32    r11,r10,r12             ; r11=sqrt(x^2+y^2)*4*256=dist*4*256.
  456.   mov       r11,r11,lsr #6
  457.   ldr       r12,[r1,r11,lsl #2]     ; r12=inv_N/(dist*4*16).
  458.   mul       r10,r12,r6              ; r10=x*4*256*inv_N/(dist*4*16).
  459.   mul       r11,r12,r5              ; r11=x*4*256*inv_N/(dist*4*16).
  460.   mov       r10,r10,asr #inv_N-2    ; r10=256*x/dist.
  461.   add       r10,r10,r2,asr #32-6    ; r10=256*x/dist+rnd(64)=vx.
  462.   random32  r2
  463.   mov       r11,r11,asr #inv_N-2    ; r11=256*y/dist.
  464.   add       r11,r11,r2,asr #32-7    ; r11=256*y/dist+rnd(128)=vy.
  465.   random32  r2
  466.   subS      r4,r4,#1                ; All pixels in long seen?
  467.   ldrEQ     r14,[r3],#4             ; Then load a new logo long,
  468.   movEQ     r4,#32                  ;   and reinit counter.
  469.   addS      r14,r14,r14             ; Put pixel in carry.
  470.   movCS     r12,#0                  ; Set color according to pixel.
  471.   movCC     r12,#-1
  472.   stmia     r0!,{r8-r12}            ; Save x,y,vx,vy,color.
  473.   add       r6,r6,#2<<9             ; Next x.
  474.   cmp       r6,#35<<9
  475.   bLE       calc_crash_x
  476.   add       r5,r5,#2<<9             ; Next y.
  477.   cmp       r5,#8<<9
  478.   bLE       calc_crash_y
  479. ; Logo is falling on the floor.
  480. .falling_logo
  481.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  482.   ldmia     r1,{r2-r5}              ; Load xleft,yup,xright,ydown.
  483.   sub       r2,r2,#1                ; Always better to clear a bigger box.
  484.   sub       r3,r3,#1
  485.   mov       r1,r0
  486.   adr       r0,bss+background
  487.   bl        CopyBigBox256           ; Go for clearing.
  488.   ldr       r5,fall_height          ; r5=old height.
  489.   cmp       r5,#512                 ; Is it last one?
  490.   bEQ       crashing_logo           ; In such case this part is over.
  491.   add       r5,r5,#4                ; r5=new height.
  492.   str       r5,fall_height          ; Save it.
  493.   adr       r6,bss+inverses
  494.   ldr       r6,[r6,r5,lsl #1]       ; r6=2^inv_N/(height/2).
  495.   rsb       r5,r5,#512              ; r5=512-height=shadow position.
  496.   adr       r7,logo_definition
  497.   ldmia     r7!,{r8-r11}            ; Load x1,y1,x2,y2.
  498.   mul       r8,r6,r8                ; Multiply x1 by zoom coef.
  499.   mov       r8,r8,asr #inv_N-10     ;   ..re-scale..
  500.   add       r8,r8,#160              ;   ..recenter..
  501.   mul       r9,r6,r9                ; Do the same for y1.
  502.   mov       r9,r9,asr #inv_N-10
  503.   add       r9,r9,#128
  504.   mul       r10,r6,r10              ; .. for x2..
  505.   mov       r10,r10,asr #inv_N-10
  506.   add       r10,r10,#159
  507.   mul       r11,r6,r11              ; .. and for y2..
  508.   mov       r11,r11,asr #inv_N-10
  509.   add       r11,r11,#127
  510.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  511.   stmia     r1!,{r8,r9}             ; Save minimum x,y.
  512.   add       r2,r8,r5                ; r2=x1 of shadow.
  513.   add       r3,r9,r5                ; r3=y1.
  514.   add       r4,r10,r5               ; r4=x2.
  515.   add       r5,r11,r5               ; r5=y2.
  516.   stmia     r1!,{r4,r5}             ; Save maximum x,y.
  517.   ldr       r1,[r7],#4              ; Load shadow color.
  518.   bl        FastBox256              ; Draw shadow.
  519.   mov       r2,r8                   ; r2=x1 of logo box.
  520.   mov       r3,r9                   ; r3=y1.
  521.   mov       r4,r10                  ; r4=x2.
  522.   mov       r5,r11                  ; r5=y2.
  523.   mov       r1,#-1                  ; White color.
  524.   bl        FastBox256              ; Draw logo box.
  525.   ldr       r8,[r7],#4              ; Load nb of boxes.
  526.   mov       r1,#0                   ; Black color for all other boxes.
  527.   mov       r9,#160<<(inv_N-10)     ; Values used for boxes recentering.
  528.   mov       r10,#128<<(inv_N-10)
  529.   mov       r11,#159<<(inv_N-10)
  530.   mov       r12,#127<<(inv_N-10)
  531. ._one_box
  532.   ldmia     r7!,{r2-r5}             ; Load x1,y1,x2,y2.
  533.   mla       r2,r6,r2,r9             ; Multiply x1 by zoom coef and recenter.
  534.   mov       r2,r2,asr #inv_N-10     ;   ..re-scale..
  535.   mla       r3,r6,r3,r10            ; Do the same for y1.
  536.   mov       r3,r3,asr #inv_N-10
  537.   mla       r4,r6,r4,r11            ; .. for x2..
  538.   mov       r4,r4,asr #inv_N-10
  539.   mla       r5,r6,r5,r12            ; .. and for y2..
  540.   mov       r5,r5,asr #inv_N-10
  541.   bl        FastBox256
  542.   subS      r8,r8,#1                ; One box drawn.
  543.   bNE       _one_box
  544.   adr       r14,falling_logo        ; Return adress is this one.
  545.   b         vsync_routine           ; Wait until next workscr is ready.
  546. ; The logo eventually hits the floor, and breaks into several parts.
  547. ; At the same time, the music begins.
  548. .crashing_logo
  549. #if zizik
  550.   mov       r11,#1                  ; DSym_RestartSong=swi#1.
  551.   bl        player+&3C8             ; Jump into symphony's swi-jumptable.
  552. #endif
  553. .logo_breaks
  554.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  555.   ldmia     r1,{r2-r5}              ; Load xleft,yup,xright,ydown.
  556.   sub       r2,r2,#1                ; Always better to clear a bigger box.
  557.   sub       r3,r3,#1
  558.   mov       r1,r0
  559.   adr       r0,bss+background
  560.   bl        CopyBigBox256           ; Go for clearing.
  561.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  562.   adr       r2,bss+misc             ; Here are points coords.
  563.   mov       r3,#36*9                ; Nb of blocks.
  564.   mov       r4,#320                 ; r4=xmin.
  565.   mov       r5,#256                 ; r5=ymin.
  566.   mov       r6,#0                   ; r6=xmax.
  567.   mov       r7,#0                   ; r7=ymax.
  568. ._one_block
  569.   ldmia     r2,{r8-r12}             ; Load x,y,vx,vy,color.
  570.   add       r8,r8,r10               ; x+=vx.
  571.   add       r9,r9,r11               ; y+=vy.
  572.   cmp       r4,r8,asr #8            ; Flags=xmin-x.
  573.   movPL     r4,r8,asr #8
  574.   cmp       r5,r9,asr #8            ; Flags=ymin-y.
  575.   movPL     r5,r9,asr #8
  576.   cmp       r6,r8,asr #8            ; Flags=xmax-x.
  577.   movMI     r6,r8,asr #8
  578.   cmp       r7,r9,asr #8            ; Flags=ymax-y.
  579.   movMI     r7,r9,asr #8
  580.   cmp       r10,#0                  ; Check sign of vx.
  581.   bGE       _vxpos
  582.   addS      r10,r10,#4              ; If vx<0, then substract 4 to it,
  583.   movPL     r10,#0                  ;   and stop when vx>0.
  584.   b         _vxok
  585. ._vxpos
  586.   subS      r10,r10,#4              ; If vx>0, then add 4 to it,
  587.   movMI     r10,#0                  ;   and stop when vx<0.
  588. ._vxok
  589.   cmp       r11,#0                  ; Same kind of things with vy.
  590.   bGE       _vypos
  591.   addS      r11,r11,#5
  592.   movPL     r11,#0
  593.   b         _vyok
  594. ._vypos
  595.   subS      r11,r11,#5
  596.   movMI     r11,#0
  597. ._vyok
  598.   stmia     r2!,{r8-r12}            ; Save with new values.
  599.   mov       r9,r9,asr #8            ; r9=int(pos_y).
  600.   add       r9,r9,r9,lsl #2
  601.   add       r8,r8,r9,lsl #6+8       ; r8=256*(x+320*int(y)).
  602.   add       r8,r0,r8,asr #8
  603.   strB r12,[r8]:strB r12,[r8,#1]:strB r12,[r8,#2]:strB r12,[r8,#3]
  604.   strB r12,[r8,#320]:strB r12,[r8,#321]:strB r12,[r8,#322]:strB r12,[r8,#323]
  605.   strB r12,[r8,#640]:strB r12,[r8,#641]:strB r12,[r8,#642]:strB r12,[r8,#643]
  606.   strB r12,[r8,#960]:strB r12,[r8,#961]:strB r12,[r8,#962]:strB r12,[r8,#963]
  607.   subS      r3,r3,#1
  608.   bNE       _one_block
  609.   add       r6,r6,#3                ; Add size of block to xmax, ymax.
  610.   add       r7,r7,#3
  611.   stmia     r1,{r4-r7}              ; Save cls_box coords.
  612.   bl        vsync_routine           ; Wait until next workscr is ready.
  613. #if zizik
  614.   mov       r0,#-1                  ; Read pattern pos.
  615.   mov       r1,#-1                  ; Read pos in pattern.
  616.   mov       r11,#12                 ; DSym_SongPos=swi#12.
  617.   bl        player+&3C8             ; Jump into symphony's swi-jumptable.
  618.   cmp       r0,#2                   ; Reached pattern 2?
  619.   bNE       logo_breaks             ; No, then continue.
  620. #else
  621.   ldrB      r12,crash_counter
  622.   subS      r12,r12,#1
  623.   strB      r12,crash_counter
  624.   bNE       logo_breaks
  625. #endif
  626. ;############################################################################
  627. ;#####                        SENTINEL LIKE PART                        #####
  628. ;############################################################################
  629. .sentinel_one_frame
  630.   bl        get_workscr_adr         ; r0=workscr_adr | r1=clsbox adress.
  631.   mov       r1,#&0a                 ; r1=sky color.
  632.   add       r1,r1,r1,lsl #8
  633.   add       r1,r1,r1,lsl #16
  634.   mov       r2,#(320-hclip)/2       ; Clear 3d screen.
  635.   mov       r3,#256-8-vclip
  636.   mov       r4,#(320-hclip)/2+hclip-1
  637.   mov       r5,#256-8-vclip+vclip-1
  638.   bl        FastBox256
  639.   adr       r0,bss+static_sort      ; Clear the static sort table.
  640.   mov       r1,#1<<30               ; Fill it with end marker.
  641.   mov       r2,#0                   ; 320*64/4=5120 longwords.
  642.   mov       r3,#0
  643.   mov       r4,#319
  644.   mov       r5,#63
  645.   bl        FastBox256              ; It was not is primary purpose, wow!
  646. ; Perform movements of viewer. For each mvt we have a control long containing
  647. ; nb_steps*2 and bit0 contains 0 for a linear head mvt, and 1 for a jump.
  648. ; (Performed with cubic splines) In first case, control long is followed by
  649. ; add_ax&add_ay, else by a0x,a2x,a3x,a0y,a1y,a2y,a3y,a0z a2z,a3z,a,b,c which
  650. ; are the coefficients for the movements splines. (a1x,a1z are null)
  651.   adr       r0,viewer_angles        ; Points on ax,ay.
  652.   ldr       r1,mvt_counter          ; Load mvt_counter.
  653.   add       r1,r1,#1                ; Increment it.
  654.   ldr       r2,mvt_pointer          ; r2 points on current mvt in mvt_table.
  655.   ldr       r3,[r2],#4              ; r3=control for this mvt.
  656.   cmp       r1,r3,lsr #1            ; Flags=mvt_counter-mvt_length.
  657.   bMI       no_mvt_change           ; If mvt_counter<mvt_length, no change.
  658.   add       r2,r2,#2*4              ; Head mvts, so pass 2 longs.
  659.   movS      r3,r3,asr #1            ; Carry=bit 0 of control.
  660.   addCS     r2,r2,#11*4             ; Mvt was a jump so pass more longs.
  661. .mvt_change_next
  662.   str       r2,mvt_pointer          ; Save new mvt pointer.
  663.   ldr       r3,[r2],#4              ; Load new control byte.
  664.   cmp       r3,#0                   ; Flags=control-0.
  665.   adrMI     r2,mvts_table           ; If control=-1, reinit mvts and
  666.   bMI       mvt_change_next         ;   re-load control byte.
  667.   mov       r1,#0                   ; Reinit mvt_counter.
  668. .no_mvt_change
  669.   str       r1,mvt_counter          ; Save modified mvt_counter.
  670.   movS      r3,r3,lsr #1            ; Carry=bit 0 of control.
  671.   bCS       jumping_mvt
  672.   ldmia     r2,{r3-r4}              ; Head_mvt, load add_ax,add_ay.
  673.   ldmia     r0,{r5-r6}              ; Load ax,ay.
  674.   add       r5,r5,r3                ; ax+=add_ax.
  675.   add       r6,r6,r4                ; ay+=add_ay.
  676.   stmia     r0,{r5-r6}              ; Save new ones.
  677.   b         mvts_done
  678. .jumping_mvt
  679. ; Fixed point shift is indicated in parenthesis.
  680.   mul       r3,r1,r1                ; r3=mvt_counter^2. (14)
  681.   mul       r4,r3,r1                ; r4=mvt_counter^3. (21)
  682.   mov       r1,r1,lsl #4            ; r1=mvt_counter. (11)
  683.   mov       r3,r3,lsr #3            ; r3=mvt_counter^2. (11)
  684.   mov       r4,r4,lsr #7+3          ; r4=mvt_counter^3. (11)
  685.   ldmia     r2!,{r5-r11}            ; Load a0x,...,a3y. (18,7,7,18,7,7,7)
  686.   mla       r5,r3,r6,r5             ; r5+=a2x*t^2. (18)
  687.   mla       r5,r4,r7,r5             ; r5+=a3x*t^3. (18)
  688.   mla       r8,r1,r9,r8             ; r8=a1y*t+a0y. (18)
  689.   mla       r8,r3,r10,r8            ; r8+=a2y*t^2. (18)
  690.   mla       r8,r4,r11,r8            ; r8+=a3y*t^3. (18)
  691.   mov       r8,r8,asr #18           ; r8=new_y.
  692.   mov       r9,r5,asr #18           ; r9=new_x.
  693.   ldmia     r2!,{r5-r7}             ; Load a0z,a2z,a3z. (18,7,7)
  694.   mla       r5,r3,r6,r5             ; r5+=a2z*t^2. (18)
  695.   mla       r5,r4,r7,r5             ; r5+=a3z*t^3. (18)
  696.   mov       r5,r5,asr #18           ; r5=new_z.
  697.   mul       r10,r5,r9               ; r10=x*z.
  698.   add       r9,r5,r9,lsl #16        ; r9=x|z.
  699.   adr       r5,viewer_pos+4
  700.   stmia     r5,{r8-r10}             ; Save y, x|z, x*z.
  701.   ldmia     r2!,{r5-r7}             ; Load a,b,c. (18,7,7)
  702.   mla       r5,r1,r6,r5             ; r5=a+b*t. (18)
  703.   mla       r5,r3,r7,r5             ; r5+=c*t^2. (18)
  704.   mov       r5,r5,lsl #32-sin_pow-18 ; r5=ax. (32-sin_pow)
  705.   str       r5,[r0]                 ; Save it.
  706.   ldr       r6,[r0,#4]              ; Load ay. (32-sin_pow)
  707. ; Here we have r5=ax, r6=ay. Calculate the rotation matrix and rotate points
  708. ; for all the objects which will be at a given position on the checkerboard.
  709. .mvts_done
  710.   str       r13,old_stack           ; What about an Arm with 32 registers?
  711.   mov       r1,r6,lsr #32-sin_pow   ; r1=ay. (Frac part removed)
  712.   mov       r1,r1,lsl #32-sin_pow   ; Back in upper bits. (easier modulo)
  713.   mov       r4,r5,lsr #32-sin_pow   ; r4=ax. (idem)
  714.   mov       r4,r4,lsl #32-sin_pow
  715.   adr       r0,bss+sinus
  716.   yx_matrix r0,r1,r6,r2,r4,r7,r3,r5,r8 ; r1=A,r2=D,r3=G,r4=E,r5=H,r6=C,r7=F,r8=I
  717.   adr       r0,bss+inverses-4*4     ; We' ll use this buffer.
  718.   stmia     r0,{r6-r8}              ; Save C,F,I.
  719.   str       r1,[r0,#12]             ; Save A.
  720.   mul       r7,r2,r7                ; r7=D*F.
  721.   rsb       r7,r7,#0                ; r7=-D*F.
  722.   mul       r8,r3,r8                ; r8=G*I.
  723.   rsb       r8,r8,#0                ; r8=-G*I.
  724.   stmdb     r0,{r4,r5,r7-r8}        ; Save E,H,-D*F,-G*I.
  725.   mul       r1,r6,r1                ; r1=A*C.
  726.   rsb       r1,r1,#0                ; r1=-A*C.
  727.   adr       r4,objects_pts_src      ; Adress of source coords,
  728.   adr       r5,objects_pts_dest     ;   and of destination.
  729. .rotate_one_y_set
  730.   ldmia     r4!,{r6,r7}             ; r6=nb pts with this y | r7=y.
  731.   cmp       r6,#0                   ; No more points?
  732.   bEQ       _rotate_end
  733.   ldmdb     r0,{r8-r11}             ; Load E,H,-D*F,-G*I.
  734.   mla       r8,r7,r8,r10            ; r8=-D*F+E*y.
  735.   mla       r7,r9,r7,r11            ; r7=-G*I+H*y.
  736. ._rotate_one_point
  737.   ldmia     r4!,{r9,r10}            ; r9=[x|z] | r10=x*z.
  738.   ldmia     r0,{r11-r14}            ; Load C,F,I,A.
  739.   add       r11,r11,r9,asr #16      ; r11=C+x.
  740.   add       r12,r12,r9,asr #16      ; r12=F+x.
  741.   add       r13,r13,r9,asr #16      ; r13=I+x.
  742.   mov       r9,r9,lsl #16           ; r9=z<<16.
  743.   add       r14,r14,r9,asr #16      ; r14=A+z.
  744.   mla       r11,r14,r11,r1          ; r11=(A+z)*(C+x)-A*C.
  745.   sub       r11,r11,r10             ; r11=x'=A*x+C*z.
  746.   mov       r11,r11,asr #sin_N
  747.   add       r14,r2,r9,asr #16       ; r14=D+z.
  748.   mla       r12,r14,r12,r8          ; r12=(D+z)*(F+x)-D*F+E*y.
  749.   sub       r12,r12,r10             ; r12=y'=D*x+E*y+F*z.
  750.   mov       r12,r12,asr #sin_N
  751.   add       r14,r3,r9,asr #16       ; r14=G+z.
  752.   mla       r13,r14,r13,r7          ; r13=(G+z)*(I+x)-G*I+H*y.
  753.   sub       r13,r13,r10             ; r13=z'=G*x+H*y+I*z.
  754.   mov       r13,r13,asr #sin_N
  755.   stmia     r5!,{r11-r13}           ; Save x',y',z'.
  756.   subS      r6,r6,#1                ; One point rotated.
  757.   bNE       _rotate_one_point
  758.   b         rotate_one_y_set        ; Next y set.
  759. ._rotate_end
  760. ; Here r11-r13=coord of checkerboard extremity, because last object was the
  761. ; viewer' s position. We now compute and store all possible heights for
  762. ; checkerboard points, and we also fill the extra storage buffer with:
  763. ;    wx=C*3,wy=F*3,wz=I*3,?,?,?,?,@checker_height,ux=A*3,uy=D*3,uz=G*3
  764. ; (Note that all values A-I are fixed point real with shift=sin_N.)
  765.   mov       r11,r11,lsl #sin_N-6    ; Convert current coord to fixed point.
  766.   mov       r12,r12,lsl #sin_N-6
  767.   mov       r13,r13,lsl #sin_N-6
  768.   adr       r1,checker_heights      ; Adress of precalculated heights buffer.
  769.   ldmia     r0,{r4-r7}              ; Load C,F,I,A.
  770.   add       r4,r4,r4,lsl #1         ; r4=C*3.
  771.   add       r5,r5,r5,lsl #1         ; r5=F*3.
  772.   add       r6,r6,r6,lsl #1         ; r6=I*3.
  773.   add       r7,r7,r7,lsl #1         ; r7=A*3.
  774.   stmia     r0!,{r1,r7}             ; Save @checker_heights and A*3.
  775.   add       r2,r2,r2,lsl #1         ; r2=D*3.
  776.   add       r3,r3,r3,lsl #1         ; r3=G*3.
  777.   stmia     r0!,{r2-r3}             ; Save D*3,G*3 & r0 points on inverses.
  778.   sub       r2,r0,#6*4
  779.   ldmdb     r2!,{r7-r8}             ; Load E,H.
  780.   add       r7,r7,r7,lsl #1
  781.   add       r8,r8,r8,lsl #1
  782.   stmdb     r2,{r4-r6}              ; Save C*3, F*3, I*3.
  783.   mov       r4,#0                   ; First height is null.
  784.   mov       r5,#0
  785.   stmia     r1!,{r4-r5}             ; Save first height.
  786.   mov       r6,#max_checker_height  ; Nb of height to compute.
  787. ._one_checker_height
  788.   sub       r4,r4,r7                ; r4-=E.
  789.   sub       r5,r5,r8                ; r5-=H.
  790.   stmia     r1!,{r4-r5}             ; Save heights.
  791.   subS      r6,r6,#1
  792.   bNE       _one_checker_height
  793. ; Here' s the last part related to vectorworld rotations and translations.
  794. ; Main idea is to go through a grid (with v=0) and for each point of this
  795. ; board adding its height by using the checker_heights table. Also we can
  796. ; have an object on this square, and in such case we translate the coords of
  797. ; object at origin (computed before) by simply adding the grid point coords.
  798.   adr       r1,heights&objects_nb
  799.   adr       r2,bss+screen_xy        ; Will contain x&y screen coords.
  800.   adr       r3,bss+space_z          ; Will contain z spatial coord.
  801.   mov       r7,#17                  ; w_counter.
  802.   sub       r0,r0,#16               ; r0 points on the 4 empty longs.
  803. ._checker_w_loop
  804.   stmdb     r0,{r7,r11-r13}         ; Save w_counter and current row.
  805.   mov       r4,#17                  ; u_counter.
  806.   ldr       r5,[r0],#16             ; r5=@checker_heights & restore r0.
  807. ._checker_u_loop
  808.   ldrB      r6,[r1],#1              ; r6=height | object_nb.
  809.   and       r7,r6,#&f0              ; r7=height<<4.
  810.   add       r7,r5,r7,lsr #1         ; r7 points on good height vector.
  811.   ldmia     r7,{r7-r8}              ; r7=vy | r8=vz.
  812.   add       r7,r12,r7,asr #1        ; r7=current_y+vy*96.
  813.   add       r8,r13,r8,asr #1        ; r8=current_z+vz*96.
  814.   andS      r6,r6,#&f               ; r6=object_nb.
  815.   bEQ       _no_object_here
  816.   sub       r5,r5,r6,lsl #3         ; r5 points on object block.
  817.   ldmia     r5,{r5-r6}              ; r5=@objects_coords | r6=nb_pts.
  818. ._object_one_point
  819.   ldmia     r5!,{r9-r10,r14}        ; Load coords of point.
  820.   add       r9,r9,r11,asr #sin_N-6  ; r9=x=int(object_x+current_x).
  821.   add       r10,r10,r7,asr #sin_N-6 ; r10=y=int(object_y+current_y+vy).
  822.   add       r14,r14,r8,asr #sin_N-6 ; r14=z=int(object_z+current_z+vz).
  823.   addS      r14,r14,#256            ; z+=dist.
  824.   str       r14,[r3],#4             ; Save it in space_z.
  825.   bLE       _object_point_next      ; We won' t need x'&y' if z+dist<=0.
  826.   ldr       r14,[r0,r14,lsl #2]     ; r14=inv_N/(z+dist).
  827.   mul       r9,r14,r9               ; r9=x*inv_N/(z+dist).
  828.   mov       r9,r9,asr #inv_N-8      ; r9=x'=x*dist/(z+dist).
  829.   add       r9,r9,#hclip/2          ; Recenter.
  830.   mul       r10,r14,r10             ; r10=y*inv_N/(z+dist).
  831.   mov       r10,r10,asr #inv_N-8    ; r10=y'=y*dist/(z+dist).
  832.   add       r10,r10,#vclip/2        ; Recenter.
  833.   stmia     r2,{r9-r10}             ; Save screen x&y.
  834. ._object_point_next
  835.   add       r2,r2,#8                ; Next position for screen_xy.
  836.   subS      r6,r6,#1                ; One point performed.
  837.   bNE       _object_one_point
  838. ._no_object_here
  839.   mov       r8,r8,asr #sin_N-6      ; r8=int(z).
  840.   addS      r8,r8,#256              ; checker_z+=dist.
  841.   str       r8,[r3],#4              ; Save it in space_z.
  842.   bLE       _next_u                 ; We won' t need x'&y' if z+dist<=0.
  843.   ldr       r8,[r0,r8,lsl #2]       ; r8=inv_N/(z+dist).
  844.   mov       r6,r11,asr #sin_N-6     ; r6=int(x).
  845.   mul       r6,r8,r6                ; r6=checker_x*inv_N/(z+dist).
  846.   mov       r6,r6,asr #inv_N-8      ; r6=x'=checker_x*dist/(z+dist).
  847.   add       r6,r6,#hclip/2          ; Recenter.
  848.   mov       r7,r7,asr #sin_N-6      ; r7=int(y).
  849.   mul       r7,r8,r7                ; r7=checker_y*inv_N/(z+dist).
  850.   mov       r7,r7,asr #inv_N-8      ; r7=y'=checker_y*dist/(z+dist).
  851.   add       r7,r7,#vclip/2          ; Recenter.
  852.   stmia     r2,{r6-r7}              ; Save screen x&y.
  853. ._next_u
  854.   add       r2,r2,#8                ; Next position for screen_xy.
  855.   ldmdb     r0,{r5-r8}              ; Load @checker_heights, ux, uy, uz.
  856.   add       r11,r11,r6              ; current_x+=ux*192.
  857.   add       r12,r12,r7              ; current_y+=uy*192.
  858.   add       r13,r13,r8              ; current_z+=uz*192.
  859.   subS      r4,r4,#1                ; One checker point done.
  860.   bNE       _checker_u_loop
  861.   sub       r0,r0,#16               ; r0 points on middle of storage.
  862.   ldmdb     r0,{r4-r7,r11-r13}      ; Load w(x,y,z);w_counter;row(x,y,z).
  863.   add       r11,r11,r4              ; row_x+=wx*192.
  864.   add       r12,r12,r5              ; row_y+=wy*192.
  865.   add       r13,r13,r6              ; row_z+=wz*192.
  866.   subS      r7,r7,#1                ; One checker row done.
  867.   bNE       _checker_w_loop
  868. ;  Eliminate backfaces (z coord of vectorial product of two edges is <0) and
  869. ; invisible polygons, (one z is <=0) then sort visible polys according to
  870. ; (zmax+sum(z)/nb_points)/2. (sorting with only zmax or sum(z)/nb_points is
  871. ; not as good, so..) The method used to sort the polygons is one I invented
  872. ; some years ago when doing vectorballs on my STe. (In the demo "CakeHead",
  873. ; yup the first one). I' ve now greatly improved it, and also discovered
  874. ; other fellows invented the same method which is called "Counting Sort".
  875. ; But enough bullshits, here are the explanations...
  876. ;  I suppose all the polygons have a z-coord between zmin and zmax, (not
  877. ; very restrictive for 3d) and we have a table with one pointer for each z,
  878. ; called the static table, which is initialised with an end marker. We also
  879. ; have another table, called the dynamic one, which will contain couples of
  880. ; pointers to a polygon definition and to the next couple with a polygon
  881. ; having the same z-coord. For each visible polygon, we calculate its z-coord
  882. ; we save adress of the polygon definition & static(z) in the dynamic table,
  883. ; and we save the dynamic adress of the couple in static(z). I think you got
  884. ; the point, for each z-coord we have a chained list containing adresses
  885. ; of the polygons. Then, using the sorted datas won' t be very hard, since
  886. ; we' ll only need to go through a list until we reach the end-marker. In
  887. ; case you don' t know what a chained list is, I recommend you get a look
  888. ; in computer science books since it is a classical datatype.
  889. .faces_sorting
  890.   adr       r0,bss+inverses
  891.   adr       r2,bss+space_z
  892.   adr       r3,faces_definition
  893.   adr       r4,bss+dynamic_sort
  894.   adr       r5,bss+static_sort
  895.   adr       r6,bss+screen_xy
  896.   ldmia     r3!,{r1,r7-r9}          ; Load nb_points-2 and 3 first points.
  897. ; I assume there is at least one valid polygon, (what would be the need of
  898. ; sorting, else?) so I don' t check here if nb_points-3 is positive.
  899. ._sort_one_face
  900.   ldr       r10,[r2,r7,lsl #2]      ; r10=z1.
  901.   cmp       r10,#0                  ; Is z1<=0?
  902.   ldrGT     r11,[r2,r8,lsl #2]      ; r11=z2.
  903.   cmpGT     r11,#0                  ; ..or z2<=0?
  904.   ldrGT     r12,[r2,r9,lsl #2]      ; r12=z3.
  905.   cmpGT     r12,#0                  ; ..or z3<=0?
  906.   bLE       _sort_invisible         ; Then face is invisible.
  907.   mov       r13,r10,lsr #1          ; r13 will contain zmax/2.
  908.   cmp       r13,r11,lsr #1          ; Flags=zmax/2-z2/2.
  909.   movMI     r13,r11,lsr #1          ; If z2/2>zmax/2, then it' s new zmax/2.
  910.   cmp       r13,r12,lsr #1          ; Idem with z3.
  911.   movMI     r13,r12,lsr #1
  912.   add       r10,r10,r11             ; r10=z1+z2.
  913.   add       r10,r10,r12             ; r10=z1+z2+z3.
  914.   add       r7,r6,r7,lsl #3         ; r7=@screen_xy(pt0)
  915.   ldmia     r7,{r7,r11}             ; r7=x0 | r11=y0.
  916.   add       r8,r6,r8,lsl #3         ; r8=@screen_xy(pt1)
  917.   ldmia     r8,{r8,r12}             ; r8=x1 | r12=y1.
  918.   sub       r7,r7,r8                ; r7=x0-x1.
  919.   sub       r11,r12,r11             ; r11=y0-y1.
  920.   add       r9,r6,r9,lsl #3         ; r9=@screen_xy(pt2)
  921.   ldmia     r9,{r9,r14}             ; r9=x2 | r14=y2.
  922.   sub       r9,r9,r8                ; r9=x2-x1.
  923.   mul       r9,r11,r9               ; r9=(x2-x1)*(y0-y1).
  924.   sub       r14,r14,r12             ; r14=y2-y1.
  925.   mlaS      r7,r14,r7,r9            ; r7=(x0-x1)*(y2-y1)+(x2-x1)*(y0-y1).
  926.   bMI       _sort_invisible         ; Result<0, then it is a backface.
  927.   mov       r7,r3                   ; r7=r3=face_definition+16.
  928.   subS      r8,r1,#2                ; r8=nb_points-4.
  929.   bMI       _sort_compute_z         ; No more if nb_points=3.
  930. ._sort_one_point
  931.   ldr       r9,[r7],#4              ; Load point nb.
  932.   ldr       r9,[r2,r9,lsl #2]       ; r9=z of point.
  933.   cmp       r9,#0                   ; z<0?
  934.   bLE       _sort_invisible         ; Then face is invisible.
  935.   cmp       r13,r9,lsr #1           ; Flags=zmax/2-z/2.
  936.   movMI     r13,r9,lsr #1           ; If z/2>zmax/2, then it' s new zmax/2.
  937.   add       r10,r10,r9              ; r10+=z.
  938.   subS      r8,r8,#1                ; One point seen.
  939.   bGE       _sort_one_point
  940. ._sort_compute_z
  941.   add       r7,r1,#2                ; r7=nb_points.
  942.   ldr       r7,[r0,r7,lsl #2]       ; r7=2^inv_N/nb_points.
  943.   mul       r10,r7,r10              ; r10=sum(z)*2^inv_N/nb_points.
  944.   mov       r7,r10,lsr #inv_N       ; r7=sum(z)/nb_points.
  945.   add       r7,r13,r7,lsr #1        ; r7=(zmax+sum(z)/nb_points)/2.
  946.   ldr       r8,[r5,r7,lsl #2]       ; Load static(z)=@previous_dynamic.
  947.   str       r4,[r5,r7,lsl #2]       ; static(z)=@this_dynamic.
  948.   stmia     r4!,{r3,r8}             ; Save face_adress & static(z).
  949. ._sort_invisible
  950.   add       r3,r3,r1,lsl #2         ; Pass nb_points-3*points and color.
  951.   ldmia     r3!,{r1,r7-r9}          ; Load nb_points-2 and 3 first points.
  952.   subS      r10,r1,#1               ; r10=nb_points-3.
  953.   bGE       _sort_one_face          ; No, then this is a valid polygon.
  954.   ldr       r13,old_stack           ; Pfiuu, he' s back.
  955. ; Last, but not least we have to draw the polygons on screen. As stated
  956. ; above, we go through the chained lists corresponding to the z-coords of
  957. ; faces. The important part for drawing is the polygon routine. Here we
  958. ; have r5=bss+static_sort and r6=bss+screen_xy.
  959.   bl        get_workscr_adr         ; r0=videoram adress.
  960.   add       r0,r0,#320*48+8
  961.   adr       r2,bss+extra            ; r2 points on extra+inverses.
  962.   adr       r3,poly_coords          ; Save coords here.
  963.   mov       r7,#inv_nb-1            ; r7=z counter.
  964. ._draw_one_z
  965.   ldr       r9,[r5,r7,lsl #2]       ; Load static(r7).
  966.   cmp       r9,#1<<30               ; static(r7)=end marker?
  967.   subGES    r7,r7,#1                ; Then next z.
  968.   bGT       _draw_one_z             ; And continue if z>0.
  969.   cmp       r7,#0                   ; z=0?
  970.   bLE       _drawing_end            ; Then we have finished to draw.
  971. ._one_face_z
  972.   ldmia     r9,{r8,r9}              ; r8=polygon adress | r9=@next.
  973.   mov       r1,r3                   ; Don' t modify r3.
  974.   ldmdb     r8,{r10-r12,r14}        ; Load nb_points-2 & 3 first points.
  975.   add       r4,r6,r11,lsl #3        ; r4=@screen_xy(pt0).
  976.   ldmia     r4,{r4,r11}             ; r4=x0 | r11=y0.
  977.   stmia     r1!,{r4,r11}            ; Save them in coords table.
  978.   add       r4,r6,r12,lsl #3        ; r4=@screen_xy(pt1).
  979.   ldmia     r4,{r4,r11}             ; r4=x1 | r11=y1.
  980.   add       r12,r6,r14,lsl #3       ; r12=@screen_xy(pt2).
  981.   ldmia     r12,{r12,r14}           ; r12=x2 | r14=y2.
  982.   stmia     r1!,{r4,r11-r12,r14}    ; Save them.
  983.   add       r4,r10,#2               ; r4=nb_points.
  984.   subS      r10,r10,#2              ; r10=nb_points-4.
  985.   bMI       _draw_face              ; No more points if nb_points=3.
  986. ._copy_face_one
  987.   ldr       r11,[r8],#4             ; Load point nb.
  988.   add       r11,r6,r11,lsl #3       ; r11=@screen_xy(pt).
  989.   ldmia     r11,{r11,r12}           ; r11=x | r12=y.
  990.   stmia     r1!,{r11,r12}           ; And copy them.
  991.   subS      r10,r10,#1              ; One point left?
  992.   bGE       _copy_face_one
  993. ._draw_face
  994.   ldr       r1,[r8],#4              ; Load face color.
  995.   bl        FastPoly256             ; And draw the polygon.
  996.   cmp       r9,#1<<30               ; @next=end marker?
  997.   bNE       _one_face_z             ; Else we have continue in this list.
  998.   subS      r7,r7,#1                ; No more face with this z, so next z.
  999.   b         _draw_one_z
  1000. ._drawing_end
  1001.   bl        vsync_routine           ; Wait until next workscr is ready.
  1002.   swi       OS_ReadEscapeState      ; Escape key pressed?
  1003.   bCC       sentinel_one_frame      ; No, then loop.
  1004.   swi       OS_Exit
  1005.  
  1006. ;****************************************************************************
  1007. ;****************************************************************************
  1008. ;*****                                                                  *****
  1009. ;*****                            MAIN DATAS                            *****
  1010. ;*****                                                                  *****
  1011. ;****************************************************************************
  1012. ;****************************************************************************
  1013.  
  1014. .old_stack                          ; 15 registers are not enough.
  1015. .random_germ dcd &eb1a2c34          ; The magical random number.
  1016.  
  1017. .old_scrblank dcd 0
  1018.  
  1019. .bg_colors
  1020.   dcb &08,&09,&0a,&0b,&a4,&a5,&a6,&a7,&d8,&d9,&da,&db ; Blue.
  1021.   dcb &db,&da,&d9,&d8,&a7,&a6,&a5,&a4,&0b,&0a,&09,&08
  1022.  
  1023. .sinA       dcd 1647089             ; sin((pi/4)/sin_nb)*2^28.
  1024. .cosA       dcd 268430403           ; cos((pi/4)/sin_nb)*2^28.
  1025.  
  1026. .crash_counter                      ; Contains
  1027. .logo_1bpp
  1028.   dcd %00000000000000000000000000000000,%00000000001100000000000000000000
  1029.   dcd %00000110000000110000000000000000,%00000000011000111011001111100111
  1030.   dcd %11100110111001100110011101100011,%01101011011100110110011000110110
  1031.   dcd %00110110101101100011000001100011,%01100111011010110110001101100011
  1032.   dcd %11100011101101100011011000110110,%00000000000000000000000000000000
  1033.   dcd %00000000000000000000000000000000
  1034.  
  1035. .fall_height
  1036.   dcd       0
  1037. .logo_definition
  1038.   dcd       -18,-5,18,4             ; Coords of 1st box.
  1039.   dcd       &0a0a0a0a               ; Color of shadow box.
  1040.   dcd       20                      ; Nb of boxes
  1041.   dcd -17,-1,-15,2, -16,2,-11,3, -13,-1,-12,0, -12,-4,-10,2, -16,-2,-13,-1
  1042.   dcd -9,-1,-7,2, -8,2,-5,3, -5,1,-4,2, -4,-1,-2,3, -8,-2,-3,-1
  1043.   dcd -1,-2,1,3, 1,-2,5,-1, 4,-1,6,3, 2,-1,3,2
  1044.   dcd 7,-2,9,3, 9,-1,10,0, 10,-2,13,-1, 12,-1,14,3
  1045.   dcd 15,-4,17,0, 15,1,17,3
  1046.  
  1047. ; ....................................
  1048. ; ......XX.........................XX.
  1049. ; ......XX.........................XX.
  1050. ; ..XXX.XX..XXXXX..XXXXXX..XX.XXX..XX.
  1051. ; .XX..XXX.XX...XX.XX.X.XX.XXX..XX.XX.
  1052. ; .XX...XX.XX...XX.XX.X.XX.XX...XX....
  1053. ; .XX...XX.XX..XXX.XX.X.XX.XX...XX.XX.
  1054. ; ..XXXXX...XXX.XX.XX...XX.XX...XX.XX.
  1055. ; ....................................
  1056.  
  1057. .viewer_angles dcd &20000000,&80000000 ; ax,ay (<<32-sin_pow).
  1058. .mvt_counter dcd -1                 ; Counter for current mvt.
  1059. .mvt_pointer dcd mvts_table         ; Points on current mvt.
  1060. ; Table containing movements datas, in the following way.
  1061. ;   1 long = nb_steps*2 + bit0
  1062. ;   If bit0=0, then we have add_ax, add_ay. (Head mvt)
  1063. ;   If bit0=1, we have a0x,a2x,...,a2z,a3z,a,b,c. (Splines coefs for jump)
  1064. .mvts_table
  1065.   incbin    "mvts"
  1066.   dcd  -1               ; End marker.
  1067.  
  1068. ; Coords for objects' points. They are arranged in the following way:
  1069. ;   1 long = nb of points with this y.
  1070. ;   1 long = y position.
  1071. ;   nb_pts * 1 long = [x|z] (16 bits each)
  1072. ;            1 long = x*z.
  1073. ; Last point is the checkerboard extremity. (relative position to viewer)
  1074. .objects_pts_src
  1075.   dcd 4,   0, ( 86<<16)+ 86, 86* 86, ( 86<<16)+106, 86*106 ; Obj1 = Tree.
  1076.   dcd         (106<<16)+106,106*106, (106<<16)+ 86,106* 86
  1077.   dcd 8, -48, ( 86<<16)+ 86, 86* 86, ( 86<<16)+106, 86*106
  1078.   dcd         (106<<16)+106,106*106, (106<<16)+ 86,106* 86
  1079.   dcd         ( 96<<16)+ 10, 96* 10, (182<<16)+ 96,182* 96
  1080.   dcd         ( 96<<16)+182, 96*182, ( 10<<16)+ 96, 10* 96
  1081.   dcd 1,-256, ( 96<<16)+ 96, 96* 96
  1082. ; Polys for Tree - 4,5,1,0  5,6,2,1  6,7,3,2  7,4,0,3 (trunk)
  1083. ;   11,10,9,8 (underneath) 8,9,12  9,10,12  10,11,12  11,8,12 (leaves)
  1084.   dcd 4,   0, ( 66<<16)+ 66, 66* 66, (126<<16)+ 66,126* 66 ; Obj2 = Monolith.
  1085.   dcd         (126<<16)+126,126*126, ( 66<<16)+126, 66*126
  1086.   dcd 4,-192, ( 76<<16)+ 76, 76* 76, (116<<16)+ 76,116* 76
  1087.   dcd         (116<<16)+116,116*116, ( 76<<16)+116, 76*116
  1088.   dcd 1,-256, ( 96<<16)+ 96, 96* 96
  1089. ; Polys for Monolith - 0,1,5,4  1,2,6,5  2,3,7,6  3,0,4,7 (body)
  1090. ;   4,5,8  5,6,8  6,7,8  7,4,8 (hat)
  1091.   dcd 4,   0, ( 36<<16)+ 36, 36* 36, (156<<16)+ 36,156* 36 ; Obj3 = Block.
  1092.   dcd         (156<<16)+156,156*156, ( 36<<16)+156, 36*156
  1093.   dcd 4, -64, ( 96<<16)+ 12, 96* 12, (180<<16)+ 96,180* 96
  1094.   dcd         ( 96<<16)+180, 96*180, ( 12<<16)+ 96, 12* 96
  1095. ; Polys for Block - 0,1,4  1,2,5  2,3,6  3,0,7
  1096. ;   4,1,5  5,2,6  6,3,7  7,0,4  4,5,6,7
  1097. .viewer_pos
  1098.   dcd 1, 96*2+112, ((-96*9)<<16)-96*3,96*9*96*3 ; Checkerboard start pos.
  1099.   dcd 0                 ; End marker.
  1100.  
  1101. ; Table containing for each object the pointer to its rotated coords and its
  1102. ; nb_points. Will be accessed from checker_heights with inverse offset.
  1103.   dcd       objects_pts_dest+(13+9)*12,8        ; Block.
  1104.   dcd       objects_pts_dest+13*12,9            ; Monolith.
  1105.   dcd       objects_pts_dest,13                 ; Tree.
  1106. .checker_heights        ; Will contain the vectors for checker heights.
  1107.   dbd       (max_checker_height+1)*2
  1108.  
  1109. .heights&objects_nb     ; Table containing heights&objects_nb. (nibbles)
  1110.   incbin "heights"
  1111. ALIGN
  1112.  
  1113. ; Table containing the faces definition... nb_points-2, points and color.
  1114. .faces_definition
  1115.   incbin "polys"
  1116.   dcd -1                ; End marker.
  1117.  
  1118. .objects_pts_dest       ; Will contain rotated coords of 3d objects.
  1119. .poly_coords            ; Will contain brows coords of poly.
  1120. .logo191_24             ; Not very mysterious.
  1121.   incbin    "mirrorlogo"
  1122.  
  1123. ;****************************************************************************
  1124. ;****************************************************************************
  1125. ;*****                                                                  *****
  1126. ;*****                             ROUTINES                             *****
  1127. ;*****                                                                  *****
  1128. ;****************************************************************************
  1129. ;****************************************************************************
  1130.  
  1131. .videoram_adress dcd 148,-1         ; Values for the swi.
  1132. .workscr_nb dcd 2                   ; This two vars must be left together.
  1133. .displayscr_nb dcd 1
  1134.  
  1135. ; ---------------------------------------------------------------------------
  1136. ; ---              Routine for Vertical Blank interrupt.                  ---
  1137. ; ---------------------------------------------------------------------------
  1138. ;   We check if the next screen which will be displayed is entirely drawn
  1139. ; (ie display_scr_nb-1<>workscr_nb), and in this case we use a swi to change
  1140. ; the screen bank to display_scr_nb-1. When displayscr_nb-1 reachs 0 it is
  1141. ; set back to ScreenNb by using self-modified code. (Op2 in vbl_screennb_mov
  1142. ; was changed to ScreenNb)
  1143. ;   At first I was accessing directly the MemC to change the display screen,
  1144. ; but since this isn' t compatible coding, I had to spent some time with
  1145. ; ArmOric and his PRMs in order to use a swi during this interrupt, and I
  1146. ; recommend you get a look at PRMs.
  1147. ;   When this routine is called we must have r12 pointing on a buffer which
  1148. ; contains workscr_nb and displayscr_nb.
  1149. .vbl_routine
  1150.   cmp       r0,#4                   ; Event=VBl?
  1151.   movNE     pc,r14                  ; No, then it' s none of our business.
  1152.   stmfd     r13!,{r0,r1,r14}        ; Save registers.
  1153.   ldmia     r12,{r0,r1}             ; r0=workscr_nb | r1=displayscr_nb.
  1154.   subS      r1,r1,#1                ; r1=displayscr_nb-1.
  1155. .vbl_screennb_mov
  1156.   movEQ     r1,#0                   ; If r1=0 then back to ScreenNb.
  1157.   cmp       r0,r1                   ; Flags=workscr_nb-(displayscr_nb-1).
  1158.   ldmEQfd   r13!,{r0,r1,pc}         ; If equal don' t show next screen.
  1159.   str       r1,[r12,#4]             ; Save new displayscr_nb.
  1160.   mov        r12,pc            ; Keep current status/mode.
  1161.   orr        r0,r12,#3            ; Derive supervisor version of it.
  1162.   teqp        r0,#0            ; Enter supervisor mode.
  1163.   mov          r0,r0
  1164.   stmfd        r13!,{r14}            ; Save Supervisor R14
  1165.   mov       r0,#&71                 ; Next showscreen.
  1166.   swi       OS_Byte
  1167.   ldmfd        r13!,{r14}            ; Restore Supervisor R14
  1168.   teqp      r12,#0            ; Re-enter original processor mode.
  1169.   mov        r0,r0
  1170.   ldmfd     r13!,{r0,r1,pc}         ; Could have been so short and so good.
  1171.  
  1172. ; ---------------------------------------------------------------------------
  1173. ; ---                Routine for Vertical Synchronisation.                ---
  1174. ; ---------------------------------------------------------------------------
  1175. ;   When this routine is called, this means we have just finished to draw the
  1176. ; workscr_nb, and we notify it by setting new workscreen to old workscr_nb-1.
  1177. ; (As for the vbl_routine, we loop if workscr_nb-1 reaches 0, and this is
  1178. ; performed with modification of vsync_screennb_mov)
  1179. ;   Once the notification has been made, we wait until the new workscr_nb is
  1180. ; different from the displayscr_nb.
  1181. .vsync_routine
  1182.   stmdb     r13!,{r0,r14}
  1183.   ldr       r0,workscr_nb           ; Load workscr_nb.
  1184.   subS      r0,r0,#1                ; r0=workscr_nb-1.
  1185. .vsync_screennb_mov
  1186.   movEQ     r0,#0                   ; If r0=0 then back to ScreenNb.
  1187.   str       r0,workscr_nb           ; Save new workscr_nb.
  1188. ._wait_vsync
  1189.   ldr       r14,displayscr_nb       ; Load displayscr_nb.
  1190.   cmp       r0,r14                  ; displayscr_nb=new_workscr_nb?
  1191.   bEQ       _wait_vsync             ; Then wait.
  1192.   ldmia     r13!,{r0,pc}
  1193.  
  1194. ; ---------------------------------------------------------------------------
  1195. ; ---                  Routine to get WorkScreen adress.                  ---
  1196. ; ---------------------------------------------------------------------------
  1197. ; This routine returns the workscreen adress in r0, and also the adress of
  1198. ; the clsbox buffer corresponding to this workscreen. (The clsboxes buffer
  1199. ; contains a succession of xleft,yup,xright,ydown used for cls)
  1200. .get_workscr_adr
  1201.   stmdb     r13!,{r14}
  1202.   ldr       r0,videoram_adress
  1203.   adr       r1,bss+clsboxes
  1204.   ldr       r14,workscr_nb
  1205.   sub       r14,r14,#1              ; RiscOS is an OS for coders... ;)
  1206.   add       r1,r1,r14,lsl #4        ; 16 longs per cls boxes.
  1207.   add       r14,r14,r14,lsl #2      ; r14=workscr_nb*5.
  1208.   add       r0,r0,r14,lsl #6+8      ; r0=video+workscr_nb*320*256.
  1209.   ldmia     r13!,{pc}
  1210.  
  1211. ; ---------------------------------------------------------------------------
  1212. ; ---                            Exit Handler.                            ---
  1213. ; ---------------------------------------------------------------------------
  1214. ; Restore exit handler, disable our VBl interrupt, stop music and then quit.
  1215. .proggy_exit
  1216.   ldmdb        r12,{r1-r3}             ; Load old exit handler environment.
  1217.   mov        r0,#11            ; ReAssign it.
  1218.   swi        OS_ChangeEnvironment
  1219.   mov       r0,#&d                  ; Disable an event.
  1220.   mov       r1,#4                   ; Event 4=VBl.
  1221.   swi       OS_Byte
  1222.   mov       r0,#&10                 ; Release Event Vector. (&10)
  1223.   adr       r1,vbl_routine          ; Give same values as when claiming.
  1224.   adr       r2,workscr_nb
  1225.   swi       XOS_Release
  1226. #if zizik
  1227.   mvn       r0,#0                   ; Deinit symphony replayrout.
  1228.   bl        player+&9F0C
  1229. #endif
  1230.   mov       r0,#3                   ; Write screenblanker control.
  1231.   ldr       r1,old_scrblank         ; Load old infos.
  1232.   add       r1,r1,r1,lsl #2
  1233.   mov       r1,r1,lsl #2            ; r1=infos*5*4.
  1234.   swi       XScreenBlanker_Control
  1235.   mvn       r0,#0
  1236.   swi       Wimp_CommandWindow        ; Avoid the 'Press Space' from Wimp
  1237.   swi       OS_Exit
  1238.  
  1239. ; ---------------------------------------------------------------------------
  1240. ; ---                    Routine smoothing a texture                      ---
  1241. ; ---                          © Alain BROBECKER                          ---
  1242. ; ---------------------------------------------------------------------------
  1243. ; This routines works by applying the following 3*3 matrix...
  1244. ;         ( 1 2 1 )   ( pix0 pix1 pix2 )
  1245. ;  1/16 * ( 2 4 2 ) * ( pix3 pix4 pix5 ) = new pix.
  1246. ;         ( 1 2 1 )   ( pix6 pix7 pix8 )
  1247. ; Parameters are...
  1248. ;     r0 = adress of initial N*N texture.
  1249. ;     r1 = adress of N*N buffer for smoothed result.
  1250. .smooth_texture
  1251.   stmfd     r13!,{r0-r9,r14}
  1252.   mov       r2,#0                   ; r2=y counter.
  1253. ._smooth_line
  1254.   mov       r3,#0                   ; r3=x counter.
  1255.   sub       r4,r2,#1<<(32-bg_M)     ; r4=(y-1) mod N <<(32-M). (Wrapping)
  1256.   add       r6,r2,#1<<(32-bg_M)     ; r6=(y+1) mod N <<(32-M). (Wrapping)
  1257.   add       r4,r0,r4,lsr #(32-2*bg_M) ; r4 points on src_line up.
  1258.   add       r5,r0,r2,lsr #(32-2*bg_M) ; r5 points on src_line.
  1259.   add       r6,r0,r6,lsr #(32-2*bg_M) ; r6 points on src_line down.
  1260. ._smooth_one
  1261.   sub       r7,r3,#1<<(32-bg_M)     ; r7=(x-1) mod N <<(32-M). (Wrapping)
  1262.   add       r8,r3,#1<<(32-bg_M)     ; r8=(x+1) mod N <<(32-M). (Wrapping)
  1263.   ldrB      r9,[r5,r3,lsr #(32-bg_M)] ; Load all the pixels, and add them
  1264.   ldrB      r14,[r4,r3,lsr #(32-bg_M)] ;   with the good coefficients in r9.
  1265.   add       r9,r14,r9,lsl #1
  1266.   ldrB      r14,[r6,r3,lsr #(32-bg_M)]
  1267.   add       r9,r9,r14
  1268.   ldrB      r14,[r5,r7,lsr #(32-bg_M)]
  1269.   add       r9,r9,r14
  1270.   ldrB      r14,[r5,r8,lsr #(32-bg_M)]
  1271.   add       r9,r9,r14
  1272.   ldrB      r14,[r4,r7,lsr #(32-bg_M)]
  1273.   add       r9,r14,r9,lsl #1
  1274.   ldrB      r14,[r4,r8,lsr #(32-bg_M)]
  1275.   add       r9,r9,r14
  1276.   ldrB      r14,[r6,r7,lsr #(32-bg_M)]
  1277.   add       r9,r9,r14
  1278.   ldrB      r14,[r6,r8,lsr #(32-bg_M)]
  1279.   add       r9,r9,r14
  1280.   mov       r9,r9,lsr #4            ; r9=smoothed intensity.
  1281.   strB      r9,[r1],#1              ; Save new pixel value.
  1282.   addS      r3,r3,#1<<(32-bg_M)     ; Next pixel.
  1283.   bNE       _smooth_one
  1284.   addS      r2,r2,#1<<(32-bg_M)     ; Next line.
  1285.   bNE       _smooth_line
  1286.   ldmfd     r13!,{r0-r9,pc}
  1287.  
  1288. ; ---------------------------------------------------------------------------
  1289. ; ---                Routine creating a fractal landscape                 ---
  1290. ; ---                          © Alain BROBECKER                          ---
  1291. ; ---------------------------------------------------------------------------
  1292. ; Recursive landscape creation. Considering a point in the landscape and
  1293. ; the iteration (=width of square) we construct the points m4-m8 and
  1294. ; go on recursively on all resulting four squares.
  1295. ;    m0--m4--m1         h4=0.5*(h0+h1)+rnd
  1296. ;    |   |   |          h5=0.5*(h1+h2)+rnd
  1297. ;    m7--m8--m5         h6=0.5*(h2+h3)+rnd
  1298. ;    |   |   |          h7=0.5*(h3+h0)+rnd
  1299. ;    m3--m6--m2         h8=0.25*(h0+h1+h2+h3)+rnd
  1300. ; Parameters are...
  1301. ;     r0=adress of buffer for landscape.
  1302. ;     r1=random number.
  1303. ;     r2=1.
  1304. ;     r3=iteration.
  1305. ;     r4=posx.
  1306. ;     r5=posy.
  1307. .recursive_landscape
  1308.   stmfd     r13!,{r3-r5,r14}
  1309. ; At first, we calculate h4,h5,h6,h7 and h8.
  1310.   add       r6,r4,r2,lsl r3
  1311.   and       r6,r6,#bg_N-1           ; r6=(posx+2^iteration) mod(bg_N).
  1312.   add       r7,r5,r2,lsl r3
  1313.   and       r7,r7,#bg_N-1           ; r7=(posy+2^iteration) mod(bg_N).
  1314.   add       r9,r4,r7,lsl #bg_M      ; r9 points on m3.
  1315.   add       r8,r6,r7,lsl #bg_M      ; r8 points on m2.
  1316.   add       r7,r6,r5,lsl #bg_M      ; r7 points on m1.
  1317.   add       r6,r4,r5,lsl #bg_M      ; r6 points on m0.
  1318.   ldrB      r6,[r0,r6]              ; r6=h0.
  1319.   ldrB      r7,[r0,r7]              ; r7=h1.
  1320.   ldrB      r8,[r0,r8]              ; r8=h2.
  1321.   ldrB      r9,[r0,r9]              ; r9=h3.
  1322.   sub       r10,r3,#1
  1323.   mov       r10,r2,lsl r10          ; r10=2^(iteration-1).
  1324. ; Calculation of m8.
  1325.   add       r14,r6,r7
  1326.   add       r14,r14,r8
  1327.   add       r14,r14,r9              ; r14=h0+h1+h2+h3.
  1328.   mov       r14,r14,asr #2          ; r14=0.25*(h0+h1+h2+h3).
  1329.   random32  r1                      ; New random number.
  1330.   rsb       r11,r3,#fractal+1       ; r11=fractal+1-iteration=shift for rnd.
  1331.   addS      r14,r14,r1,asr r11      ; r14=0.25*(h0+h1+h2+h3)+rnd.
  1332.   movLE     r14,#1                  ; Make sure 0<r14<256.
  1333.   cmp       r14,#255
  1334.   movGE     r14,#255
  1335.   add       r12,r5,r10              ; Make r12 point on m8.
  1336.   add       r12,r4,r12,lsl #bg_M
  1337.   add       r12,r12,r10
  1338.   strB      r14,[r0,r12]            ; Save h8.
  1339. ; Calculation of m6.
  1340.   add       r14,r8,r9               ; r14=h2+h3.
  1341.   mov       r14,r14,asr #1          ; r14=0.5*(h2+h3).
  1342.   random32  r1                      ; New random number.
  1343.   rsb       r11,r3,#fractal         ; r11=fractal-iteration=shift for rnd.
  1344.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h2+h3)+rnd.
  1345.   movLE     r14,#1                  ; Make sure 1<r14<256.
  1346.   cmp       r14,#255
  1347.   movGE     r14,#255
  1348.   add       r12,r5,r2,lsl r3        ; Make r12 point on m6.
  1349.   add       r12,r4,r12,lsl #bg_M
  1350.   add       r12,r12,r10
  1351.   strB      r14,[r0,r12]            ; Save h6.
  1352. ; Calculation of m5.
  1353.   add       r14,r7,r8               ; r14=h1+h2.
  1354.   mov       r14,r14,asr #1          ; r14=0.5*(h1+h2).
  1355.   random32  r1                      ; New random number.
  1356.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h1+h2)+rnd.
  1357.   movLE     r14,#1                  ; Make sure 1<r14<256.
  1358.   cmp       r14,#255
  1359.   movGE     r14,#255
  1360.   add       r12,r4,r2,lsl r3        ; Make r12 point on m5.
  1361.   add       r12,r12,r5,lsl #bg_M
  1362.   add       r12,r12,r10,lsl #bg_M
  1363.   ldrB      r8,[r0,r12]             ; Load value at m5.
  1364.   cmp       r8,#0                   ; Pixel already set?
  1365.   strEQB    r14,[r0,r12]            ; Else save h5.
  1366. ; Calculation of m4.
  1367.   add       r14,r6,r7               ; r14=h0+h1.
  1368.   mov       r14,r14,asr #1          ; r14=0.5*(h0+h1).
  1369.   random32  r1                      ; New random number.
  1370.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h0+h1)+rnd.
  1371.   movLE     r14,#1                  ; Make sure 1<r14<256.
  1372.   cmp       r14,#255
  1373.   movGE     r14,#255
  1374.   add       r12,r4,r10              ; Make r12 point on m4.
  1375.   add       r12,r12,r5,lsl #bg_M
  1376.   ldrB      r8,[r0,r12]
  1377.   cmp       r8,#0
  1378.   strEQB    r14,[r0,r12]            ; Save h4.
  1379. ; Calculation of m7.
  1380.   add       r14,r6,r9               ; r14=h0+h3.
  1381.   mov       r14,r14,asr #1          ; r14=0.5*(h0+h3).
  1382.   random32  r1                      ; New random number.
  1383.   addS      r14,r14,r1,asr r11      ; r14=0.5*(h0+h3)+rnd.
  1384.   movLE     r14,#0                  ; Make sure 1<r14<256.
  1385.   cmp       r14,#255
  1386.   movGE     r14,#255
  1387.   add       r12,r5,r10              ; Make r12 point on m7.
  1388.   add       r12,r4,r12,lsl #bg_M
  1389.   ldrB      r8,[r0,r12]
  1390.   cmp       r8,#0
  1391.   strEQB    r14,[r0,r12]            ; Save h7.
  1392. ; Second part, recursive call.
  1393.   subS      r3,r3,#1
  1394.   ldmEQfd   r13!,{r3-r5,pc}         ; Stop recusrion when iter=0.
  1395.   bl        recursive_landscape     ; Else go on with four subsquares.
  1396.   add       r4,r4,r2,lsl r3         ;   start pos=m4.
  1397.   bl        recursive_landscape
  1398.   add       r5,r5,r2,lsl r3         ;   start pos=m8.
  1399.   bl        recursive_landscape
  1400.   sub       r4,r4,r2,lsl r3         ;   start pos=m7.
  1401.   bl        recursive_landscape
  1402.   ldmfd     r13!,{r3-r5,pc}
  1403.  
  1404. ; ---------------------------------------------------------------------------
  1405. ; ---                Routine copying an aligned 8 bpp box                 ---
  1406. ; ---                          © Alain BROBECKER                   May 96 ---
  1407. ; ---------------------------------------------------------------------------
  1408. ; * This routine copies the box between (x1-x1mod8;y1) and (x2+8-x2mod8;y2)
  1409. ; from the source to the destination. This routine is mostly aimed at
  1410. ; screenparts clearing.
  1411. ; * r13 is saved just after the generated code, so we can use it for the
  1412. ; ldmia-stmia copy. But we have to generate the instructions which will
  1413. ; restore it at the end of routine.
  1414. ; * There are many other tricks (for the generation of 'bGE'...) but I won' t
  1415. ; explain them since code is widely commented.
  1416. ;
  1417. ; Parameters are...
  1418. ;     r0 = source adress.
  1419. ;     r1 = destination adress.
  1420. ;     r2 = x1.    1------+
  1421. ;     r3 = y1.    |      |
  1422. ;     r4 = x2.    |      |
  1423. ;     r5 = y2.    +------2
  1424. .CopyBigBox256
  1425.   cmp       r2,#320                 ; At first check if the box is
  1426.   cmpLT     r3,#256                 ;   completly out of screen, and in
  1427.   movGE     pc,r14                  ;   such case we quit.
  1428.   cmp       r4,#0
  1429.   cmpGE     r5,#0
  1430.   movLT     pc,r14
  1431.   stmfd     r13!,{r0-r12,r14}       ; Be clean or die.
  1432.   cmp       r2,#0                   ; Perform the clipping.
  1433.   movLT     r2,#0
  1434.   cmp       r3,#0
  1435.   movLT     r3,#0
  1436.   cmp       r4,#320
  1437.   movGE     r4,#319
  1438.   cmp       r5,#256
  1439.   movGE     r5,#255
  1440.   mov       r2,r2,lsr #2            ; r2=x1>>2.
  1441.   rsbS      r4,r2,r4,lsr #2         ; r4=x2>>2-x1>>2=nb_longs-1.
  1442.   subGES    r14,r5,r3               ; r14=dy=y2-y1.
  1443.   ldmMIfd   r13!,{r0-r12,pc}        ; Quit if nb_longs-1<0 or dy<0.
  1444.   add       r3,r3,r3,lsl #2         ; r3=y1*5.
  1445.   add       r3,r2,r3,lsl #4         ; r3=y1*80+x1>>2.
  1446.   add       r0,r0,r3,lsl #2         ; r0=source+y1*320+4*(x1>>2).
  1447.   add       r1,r1,r3,lsl #2         ; r1=dest+y1*320+4*(x1>>2).
  1448. .StrongBranch1
  1449.   b         _StrongCopyBox          ; If SA is absent, will be replaced by...
  1450. ;  add       r2,r4,#1                ; r2=nb_longs.
  1451.   rsb       r3,r2,#80               ; r3=nb longs to pass each line=offset/4.
  1452.   adr       r4,_code+4              ; Code will be generated here.
  1453.   adr       r5,_opcodes
  1454.   ldmia     r5,{r6-r11}             ; Load some opcodes.
  1455. ._one_copy_max
  1456.   subS      r2,r2,#12               ; More than 12 longs left?
  1457.   stmGEia   r4!,{r6-r7}             ; Yes then save one ldmia+stmia max.
  1458.   bGT       _one_copy_max           ; r2>0? Then test again.
  1459.   bEQ       _generate_add           ; r2=0? Then no more copy.
  1460.   add       r5,r5,r2,lsl #3         ; r5 point on opcodes for last copy.
  1461.   ldmda     r5,{r6-r7}              ; Load them.
  1462.   cmp       r2,#-11                 ; Last fill instruction is a str?
  1463.   addEQ     r6,r6,r3,lsl #2         ; Then r6='ldr r2,[r0],#offset+4',
  1464.   addEQ     r7,r7,r3,lsl #2         ;   and r7='str r2,[r1],#offset+4'.
  1465.   stmia     r4!,{r6-r7}             ; Save last fill instruction.
  1466.   bEQ       _end_generate_add       ; No need of an add if we have an str.
  1467. ._generate_add
  1468.   cmp       r3,#0                   ; Offset is null?
  1469.   addNE     r8,r8,r3                ; No, then r8='add r0,r0,#(offset/4)<<2',
  1470.   addNE     r9,r9,r3                ;   r9='add r1,r1,#(offset/4)<<2',
  1471.   stmNEia   r4!,{r8-r9}             ;   and save instructions.
  1472. ._end_generate_add
  1473.   adr       r9,_code-2*4            ; Beware the pipeline.
  1474.   sub       r9,r9,r4                ; r9=offset for the bGE.
  1475.   mov       r9,r9,asr #2            ; r9=offset/4. (higher byte=&ff)
  1476.   eor       r9,r9,#&55<<24          ; r9=&AAxxxxxx='bGE offset'.
  1477.   stmia     r4!,{r9-r11,r13}        ; Save instructions and stack.
  1478. ._code
  1479.   subS      r14,r14,#1              ; One line will be drawn.
  1480.   dbd       8*2+4                   ; Space for the code and stack.
  1481.  
  1482.   ldr       r2,[r0],#4              ; Opcodes for last copy instruction.
  1483.   str       r2,[r1],#4
  1484.   ldmia     r0!,{r2-r3}
  1485.   stmia     r1!,{r2-r3}
  1486.   ldmia     r0!,{r2-r4}
  1487.   stmia     r1!,{r2-r4}
  1488.   ldmia     r0!,{r2-r5}
  1489.   stmia     r1!,{r2-r5}
  1490.   ldmia     r0!,{r2-r6}
  1491.   stmia     r1!,{r2-r6}
  1492.   ldmia     r0!,{r2-r7}
  1493.   stmia     r1!,{r2-r7}
  1494.   ldmia     r0!,{r2-r8}
  1495.   stmia     r1!,{r2-r8}
  1496.   ldmia     r0!,{r2-r9}
  1497.   stmia     r1!,{r2-r9}
  1498.   ldmia     r0!,{r2-r10}
  1499.   stmia     r1!,{r2-r10}
  1500.   ldmia     r0!,{r2-r11}
  1501.   stmia     r1!,{r2-r11}
  1502.   ldmia     r0!,{r2-r12}
  1503.   stmia     r1!,{r2-r12}
  1504.   stmia     r0!,{r1-r12}
  1505. ._opcodes
  1506.   ldmia     r0!,{r2-r13}            ; Maximum copying instructions.
  1507.   stmia     r1!,{r2-r13}
  1508.   dcd       &e2800f00               ; Opcode of 'add r0,r0,#0<<2'.
  1509.   dcd       &e2811f00               ; Opcode of 'add r1,r1,#0<<2'.
  1510.   ldr       r13,[pc,#0]             ; Load stack which is 8 bytes after.
  1511.   ldmfd     r13!,{r0-r12,pc}        ; And quit.
  1512.  
  1513. ;---- StongARM version. No generated code. ----------------------------------
  1514. ._StrongCopyBox
  1515.   adr        r6,_next_hline
  1516.   add        r14,r14,#1
  1517. ._one_hline
  1518.   mov        r2,r0
  1519.   mov        r3,r1
  1520.   sub       pc,r6,r4,lsl #3
  1521. #rept 79
  1522.   ldr        r5,[r2],#4
  1523.   str        r5,[r3],#4
  1524. #endr
  1525. ._next_hline
  1526.   ldr        r5,[r2],#4
  1527.   str        r5,[r3],#4
  1528.   add        r0,r0,#320
  1529.   add        r1,r1,#320
  1530.   subS        r14,r14,#1
  1531.   bNE        _one_hline
  1532.   ldmfd        r13!,{r0-r12,pc}
  1533.  
  1534.  
  1535. ; ---------------------------------------------------------------------------
  1536. ; ---                     Routine drawing a 8 bpp box                     ---
  1537. ; ---                          © Alain BROBECKER                   May 96 ---
  1538. ; ---------------------------------------------------------------------------
  1539. ; * This routine draws the box between (x1;y1) and (x2;y2) on the mode13
  1540. ; screen with the given filling pattern.
  1541. ; * r13 is saved just after the generated code, so we can use it for the
  1542. ; ldmia-stmia copy. But we have to generate the instructions which will
  1543. ; restore it at the end of routine.
  1544. ; * The last filling instruction (str, strB or add, to modify the adress)
  1545. ; is generated with the stmia used for the endcode generation.
  1546. ; * Most times (>75%) we won' t need an add to modify offsets, so I choosed
  1547. ; to branch in such cases instead of cases when we have a str(B).
  1548. ; * There are many other tricks (for the generation of 'bGE'..) but I won' t
  1549. ; explain them since code is widely commented.
  1550. ;
  1551. ; Parameters are...
  1552. ;     r0 = screen adress.
  1553. ;     r1 = filling pattern.
  1554. ;     r2 = x1.    1------+
  1555. ;     r3 = y1.    |      |
  1556. ;     r4 = x2.    |      |
  1557. ;     r5 = y2.    +------2
  1558. .FastBox256
  1559.   cmp       r2,#320                 ; At first check if the box is
  1560.   cmpLT     r3,#256                 ;   completly out of screen, and in
  1561.   movGE     pc,r14                  ;   such case we quit.
  1562.   cmp       r4,#0
  1563.   cmpGE     r5,#0
  1564.   movLT     pc,r14
  1565.   stmfd     r13!,{r0-r12,r14}       ; Be clean or die.
  1566.   cmp       r2,#0                   ; Perform the clipping.
  1567.   movLT     r2,#0
  1568.   cmp       r3,#0
  1569.   movLT     r3,#0
  1570.   cmp       r4,#320
  1571.   movGE     r4,#319
  1572.   cmp       r5,#256
  1573.   movGE     r5,#255
  1574.   subS      r14,r5,r3               ; r14=dy=y2-y1.
  1575.   subGES    r5,r4,r2                ; r5=dx=x2-x1.
  1576.   ldmMIfd   r13!,{r0-r12,pc}        ; Quit if dy<0 or dx<0.
  1577.   add       r3,r3,r3,lsl #2         ; r3=y1*5.
  1578.   add       r0,r0,r3,lsl #6         ; r0=screen+y1*320.
  1579. .StrongBranch2
  1580.   b         _StrongFastBox          ; If SA is absent, will be replaced by...
  1581. ;  add       r0,r0,r2                ; r0=screen+y1*320+x1.
  1582.   mov       r3,r2,lsr #2            ; r3=x1/4.
  1583.   rsbS      r3,r3,r4,lsr #2         ; r3=x2/4-x1/4=nb_longs.
  1584.   adr       r7,_small_adr           ; r7 points on adresses for small boxes.
  1585.   ldrEQ     pc,[r7,r5,lsl #2]       ; nb_longs=0, then execute small box rout.
  1586.   rsb       r5,r5,#319              ; r5=319-dx=nb of bytes to pass each line.
  1587.   adr       r6,_code+4              ; Generate code here.
  1588.   ldmdb     r7!,{r8-r11}            ; Load some opcodes.
  1589. ; Here we begin to care about first longword filling.
  1590.   andS      r2,r2,#%11              ; r2=x1 mod(3).
  1591.   bEQ       _first_long_full        ; If x1 mod(3)=0, first long is full.
  1592.   sub       r3,r3,#1                ; Else first long mustn' t be drawn.
  1593.   tst       r2,#%01                 ; Down bit of x1 set?
  1594.   strNE     r8,[r6],#4              ; Then we have an odd nb of strB.
  1595.   tst       r2,r2,lsl #1            ; bit1 AND bit0 of x1 cleared?
  1596.   strEQ     r8,[r6],#4              ; Then x1 mod(3)=1 or 2, so we must
  1597.   strEQ     r8,[r6],#4              ;   generate two strB more.
  1598. ._first_long_full
  1599.   and       r4,r4,#%11              ; r4=x2 mod(3).
  1600.   and       r2,r4,r4,lsr #1         ; r2=bit1 AND bit0 of x2 mod(3).
  1601.   addS      r3,r3,r2                ; If x2 mod(3)=%11, last long is full.
  1602.   bEQ       _last_longword          ; If nb_longs=0 go to last long.
  1603. ._one_stmia_max
  1604.   subS      r3,r3,#13               ; More than 13 longs left?
  1605.   strGE     r9,[r6],#4              ; Yes, then save one stmia max.
  1606.   bGT       _one_stmia_max          ; r3>0? Then test again.
  1607.   ldrMI     r9,[r7,r3,lsl #2]       ; If r3<0 then load opcode of last long
  1608.   strMI     r9,[r6],#4              ;   fill instruction and save it.
  1609. ._last_longword
  1610.   teq       r4,#%11                 ; x2 mod(3)=%11?
  1611.   bEQ       _last_long_full         ; Then last long is full.
  1612.   tst       r4,#%01                 ; Down bit clear?
  1613.   strEQ     r8,[r6],#4              ; Then we have an odd nb of strB.
  1614.   teq       r4,r4,lsl #1            ; bit1 EOR bit0<>0?
  1615.   strNE     r8,[r6],#4              ; Then x2 mod(3)=1 or 2, then there
  1616.   strNE     r8,[r6],#4              ;   are two strB more.
  1617. ._last_long_full
  1618.   ldr       r8,[r6,#-4]!            ; Load last saved instruction.
  1619.   tst       r8,#1<<26               ; Is it a str or strB?
  1620.   bEQ       _generate_add           ; No, then we' ll need an add.
  1621.   add       r8,r8,r5                ; Yes, then add to 319-dx to offset.
  1622. ._generate_endcode
  1623.   adr       r9,_code-3*4            ; Beware the pipeline and last instruction.
  1624.   sub       r9,r9,r6                ; r9=offset for the bGE.
  1625.   mov       r9,r9,asr #2            ; r9=offset/4. (higher byte=&ff)
  1626.   eor       r9,r9,#&55<<24          ; r9=&AAxxxxxx='bGE offset'.
  1627.   stmia     r6!,{r8-r11,r13}        ; Save instructions and stack.
  1628.   mov       r2,r1                   ; Put pattern in other longwords.
  1629.   mov       r3,r1
  1630.   mov       r4,r1
  1631.   mov       r5,r1
  1632.   mov       r6,r1
  1633.   mov       r7,r1
  1634.   mov       r8,r1
  1635.   mov       r9,r1
  1636.   mov       r10,r1
  1637.   mov       r11,r1
  1638.   mov       r12,r1
  1639.   mov       r13,r1
  1640. ._code
  1641.   subS      r14,r14,#1              ; One line will be drawn.
  1642.   dbd       3+6+3+4                 ; Space for the code and stack.
  1643.  
  1644. ._generate_add
  1645.   cmp       r5,#0                   ; Offset is null?
  1646.   bEQ       _generate_endcode       ; Then go on...
  1647.   add       r6,r6,#4                ; Don' t modify loaded instruction.
  1648.   mov       r8,#&e28<<20            ; r8=opcode of 'add r0,r0,#0'.
  1649.   cmp       r5,#255                 ; Offset bigger than 255?
  1650.   addGE     r2,r8,#255              ; Then generate an 'add r0,r0,#255'
  1651.   strGE     r2,[r6],#4
  1652.   subGE     r5,r5,#255              ;   and substract 255 to offset.
  1653.   add       r8,r8,r5                ; r8='add r0,r0,#offset'.
  1654.   b         _generate_endcode
  1655.  
  1656.   str       r1,[r0],#4              ; Opcodes for lasts longs filling.
  1657.   stmia     r0!,{r1-r2}
  1658.   stmia     r0!,{r1-r3}
  1659.   stmia     r0!,{r1-r4}
  1660.   stmia     r0!,{r1-r5}
  1661.   stmia     r0!,{r1-r6}
  1662.   stmia     r0!,{r1-r7}
  1663.   stmia     r0!,{r1-r8}
  1664.   stmia     r0!,{r1-r9}
  1665.   stmia     r0!,{r1-r10}
  1666.   stmia     r0!,{r1-r11}
  1667.   stmia     r0!,{r1-r12}
  1668. ._opcodes
  1669.   strB      r1,[r0],#1              ; Byte filling instruction.
  1670.   stmia     r0!,{r1-r13}            ; Maximum filling instruction.
  1671.   ldr       r13,[pc,#0]             ; Load stack which is 8 bytes after.
  1672.   ldmfd     r13!,{r0-r12,pc}        ; And quit.
  1673. ._small_adr
  1674.   dcd       _small1                 ; Adresses for the routines corresponding
  1675.   dcd       _small2                 ;   to x1-x2 being in same longword.
  1676.   dcd       _small3
  1677.   dcd       _small4
  1678. ; Here are the routine for small boxes.
  1679. ._small1
  1680.   strB      r1,[r0],#320
  1681.   subS      r14,r14,#1
  1682.   bGE       _small1
  1683.   ldmfd     r13!,{r0-r12,pc}
  1684. ._small2
  1685.   strB      r1,[r0],#1
  1686.   strB      r1,[r0],#319
  1687.   subS      r14,r14,#1
  1688.   bGE       _small2
  1689.   ldmfd     r13!,{r0-r12,pc}
  1690. ._small3
  1691.   strB      r1,[r0],#1
  1692.   strB      r1,[r0],#1
  1693.   strB      r1,[r0],#318
  1694.   subS      r14,r14,#1
  1695.   bGE       _small3
  1696.   ldmfd     r13!,{r0-r12,pc}
  1697. ._small4
  1698.   str       r1,[r0],#320
  1699.   subS      r14,r14,#1
  1700.   bGE       _small4
  1701.   ldmfd     r13!,{r0-r12,pc}
  1702.  
  1703. ;---- StongARM version. No generated code. ----------------------------------
  1704. ._StrongFastBox
  1705.   adr        r6,_next_hline
  1706.   add        r4,r4,#1
  1707.   add        r14,r14,#1
  1708. ._one_hline
  1709.   add       r3,r0,r2                ; r3=@xleft.
  1710.   add        r5,r0,r4            ; r5=@xright.
  1711.   cmp       r5,r3                   ; xright=<xleft?
  1712.   bLE       _next_hline
  1713.   tst       r3,#%01
  1714.   strNEB    r1,[r3],#1
  1715.   tst       r5,#%01
  1716.   strNEB    r1,[r5,#-1]!
  1717.   cmp       r5,r3
  1718.   bLE       _next_hline
  1719.   tst       r3,#%10
  1720.   strNEB    r1,[r3],#1
  1721.   strNEB    r1,[r3],#1
  1722.   tst       r5,#%10
  1723.   strNEB    r1,[r5,#-1]!
  1724.   strNEB    r1,[r5,#-1]!
  1725.   sub       r5,r5,r3                ; r5=nb of longs to fill*4.
  1726.   sub       pc,r6,r5
  1727. #rept 80
  1728.   str        r1,[r3],#4
  1729. #endr
  1730. ._next_hline
  1731.   add        r0,r0,#320
  1732.   subS        r14,r14,#1
  1733.   bNE        _one_hline
  1734.   ldmfd        r13!,{r0-r12,pc}
  1735.  
  1736. ; ---------------------------------------------------------------------------
  1737. ; ---                     256 colors Polygon routine.                     ---
  1738. ; ---                          © Alain BROBECKER            ???-August 96 ---
  1739. ; ---------------------------------------------------------------------------
  1740. ; * The hline filling part is greatly inspired from the one by Jan/BASS.
  1741. ; (Some will say entirely =) Too bad, but when writing my own I got a look
  1742. ; at Jan' s routine, and I must admit I can' t do better. I was not all
  1743. ; that far behind though, but having lotsa problems with clipping and Jan
  1744. ; has solved them in an elegant way. (drawing from xleft to xright-1 instead
  1745. ; of xright) ThanX again, Jan...
  1746. ; * The routine expects you to give a list of the polygon brows in anticlock
  1747. ; cycle, and have extra storage just after the list. (Because I copy the
  1748. ; brows one more time)
  1749. ; * The upper clipping is performed by calculating slopes of the first partly
  1750. ; visibles edges, and passing all invisibles lines with a multiply. The lower
  1751. ; clipping is made by just reducing the nb of hlines to draw.
  1752. ; * Horizontal clipping (performed while drawing) depends upon hclip and vclip
  1753. ; parameters, but I assume the screen is 320 bytes wide anyway.
  1754. ;
  1755. ; Parameters are...
  1756. ;     r0 = videoram adress.
  1757. ;     r1 = filling pattern.
  1758. ;     r2 = adress of 12 longs for storage + inverses table.
  1759. ;     r3 = brows coords in anticlock cycle. (+extra storage)
  1760. ;     r4 = nb of brows.
  1761. .FastPoly256
  1762.   stmia     r2!,{r0,r3-r14}         ; Save registers | r2 point on inverses.
  1763. ; Copy the brows a second time and search bounding box coords. Also since
  1764. ; we want r3 to point on upper_left brow (anticlock cycle) and r4 point on
  1765. ; upper_right brow, (clock) we already prepare for this. (will be continued
  1766. ; a bit after)
  1767.   add       r5,r3,r4,lsl #3         ; r5 points after coords table.
  1768.   ldmia     r3!,{r6,r7}             ; Load first brow.
  1769.   stmia     r5!,{r6,r7}             ; And copy it.
  1770.   mov       r8,r6                   ; r6=xmax | r8=xmin.
  1771.   mov       r10,r7                  ; r7=ymax | r10=ymin.
  1772.   sub       r9,r3,#8                ; r9 will point on upper_left brow.
  1773.   sub       r11,r5,#8               ; r11 will point on upper_right brow.
  1774.   sub       r4,r4,#1                ; First brow copied.
  1775. ._copy_and_search
  1776.   ldmia     r3!,{r12,r13}           ; Load brow.
  1777.   stmia     r5!,{r12,r13}           ; Copy it.
  1778.   cmp       r6,r12                  ; Flags=xmax-x.
  1779.   movMI     r6,r12                  ; If xmax-x<0 then x is new xmax.
  1780.   cmp       r12,r8                  ; Flags=x-xmin.
  1781.   movMI     r8,r12                  ; If x-xmin<0 then x is new xmin.
  1782.   cmp       r7,r13                  ; Flags=ymax-y.
  1783.   movMI     r7,r13                  ; If ymax-y<0 then y is new ymax.
  1784.   cmp       r13,r10                 ; Flags=y-ymin.
  1785.   movMI     r10,r13                 ; If y-ymin<0 then y is new ymin.
  1786.   subLE     r9,r3,#8                ; y<=ymin => it' s new upper_left brow.
  1787.   subMI     r11,r5,#8               ; y<ymin => it' s new upper_right brow.
  1788.   subS      r4,r4,#1                ; One brow copied.
  1789.   bNE       _copy_and_search
  1790. ; Now, according to xmin,xmax,ymin & ymax, we can see if the polygon is
  1791. ; totally out of the screen and in such case we quit. Also we quit if
  1792. ; ymin=ymax or ymax-ymin>=inv_nb.
  1793.   cmp       r6,#0                   ; Flags=xmax-0.
  1794.   cmpGE     r7,#0                   ; If xmax>=0, then flags=ymax-0.
  1795.   ldmMIdb   r2!,{r0,r3-r13,pc}      ; Quit if xmax<0 or ymax<0.
  1796.   cmp       r8,#hclip               ; Flags=xmin-hclip.
  1797.   cmpMI     r10,#vclip              ; If xmin<hclip, then flags=ymin-vclip.
  1798.   ldmGEdb   r2!,{r0,r3-r13,pc}      ; Quit if xmin>=hclip or ymin>=vclip,.
  1799.   subS      r14,r10,r7              ; r14=ymin-ymax.
  1800.   cmnNE     r14,#inv_nb             ; If ymin<>ymax, check ymin-ymax+inv_nb.
  1801.   ldmLEdb   r2!,{r0,r3-r13,pc}      ; Quit if ymin=ymax or ymax-ymin>=inv_nb.
  1802. ; We made r9 point on the last upper brow we saw, but if next point has the
  1803. ; same y (can happen when 1st brow(s) and last one(s) are ymin) then this
  1804. ; one is on the left, so we must take it as new upper_left brow.
  1805.   ldr       r14,[r9,#12]!           ; Load next_y coord. (anticlock)
  1806. ._upleft_search
  1807.   cmp       r10,r14                 ; next_y=ymin?
  1808.   ldrEQ     r14,[r9,#8]!            ; Then this point is on the left, take
  1809.   bEQ       _upleft_search          ; it as new upper_left brow and go on..
  1810.   subS      r3,r9,#12               ; r3 points on upper_left brow. (anticlock)
  1811. ; Same comment for upper_right brow except that we go in clock cycle.
  1812.   ldr       r14,[r11,#-4]!          ; Load next y coord. (clock)
  1813. ._upright_search
  1814.   cmp       r10,r14                 ; next_y=ymin?
  1815.   ldrEQ     r14,[r11,#-8]!          ; Then this point is on the right, take
  1816.   bEQ       _upright_search         ; it as new upper_right brow and go on..
  1817.   addS      r4,r11,#4               ; r4 points on upper_right brow. (clock)
  1818. ; Some more inits, and checking for upper clipping.
  1819.   adr       r13,_draw_hline         ; Adress for filling jump.
  1820.   mov       r14,r1                  ; Two registers for stmia2 filling.
  1821.   addS      r11,r10,r10,lsl #2      ; r11=ymin*5.
  1822.   bMI       _upclip                 ; Perform up clipping if ymin<0.
  1823.   add       r0,r0,r11,lsl #6        ; r0=video+320*ymin.
  1824.   ldr       r9,[r3],#8              ; r9=upper_left x and r3 points after.
  1825.   ldr       r11,[r4]                ; r11=upper_right x.
  1826.   b         _change_both
  1827.  
  1828. ; Poly is clipped up!. At first we search the first left edge which is partly
  1829. ; visible, we compute its slope and its intersection with the upper border.
  1830. ._upclip
  1831.   mov       r11,r10                 ; r11=r10=ymin.
  1832.   ldr       r5,[r3],#8              ; r5=xleft.
  1833. ._upclip_search_left
  1834.   ldmia     r3!,{r7,r9}             ; Load next_xleft,next_yelft.
  1835.   cmp       r9,#0                   ; next_yleft>=0?
  1836.   movLT     r5,r7                   ; No, continue to search.
  1837.   movLT     r10,r9
  1838.   bLT       _upclip_search_left
  1839.   sub       r7,r7,r5                ; r7=dxleft.
  1840.   mov       r5,r5,lsl #inv_N        ; r5=xleft<<inv_N.
  1841.   subS      r12,r9,r10              ; r12=dyleft.
  1842.   ldmLEdb   r2!,{r0,r3-r13,pc}      ; Quit if dyleft=<0.
  1843.   ldr       r12,[r2,r12,lsl #2]     ; r12=2^inv_N/dyleft.
  1844.   mul       r7,r12,r7               ; r7=int(dxleft)/dyleft<<inv_N.
  1845.   rsb       r10,r10,#0              ; r10=nb of lines to pass (>=0).
  1846.   mla       r5,r10,r7,r5            ; r5=clipped_xleft<<inv_N.
  1847. ; Do the upper clipping with right edge in the same way.
  1848.   ldr       r6,[r4]                 ; r6=xright.
  1849. ._upclip_search_right
  1850.   ldmdb     r4!,{r8,r10}            ; Load next_xright,next_yright.
  1851.   cmp       r10,#0                  ; next_yright>=0?
  1852.   movLT     r6,r8                   ; No, then continue to search.
  1853.   movLT     r11,r10
  1854.   bLT       _upclip_search_right
  1855.   sub       r8,r8,r6                ; r8=dxright.
  1856.   mov       r6,r6,lsl #inv_N        ; r6=xright<<inv_N.
  1857.   sub       r12,r10,r11             ; r12=dyright.
  1858.   ldr       r12,[r2,r12,lsl #2]     ; r12=2^inv_N/dyright.
  1859.   mul       r8,r12,r8               ; r8=int(dxright)/dyright<<inv_N.
  1860.   rsb       r11,r11,#0              ; r11=nb of lines to pass (>=0).
  1861.   mla       r6,r11,r8,r6            ; r6=clipped_xright<<inv_N.
  1862. ; While making the upclip we have computed the slopes, so we can now use
  1863. ; them for edges tracking and begin directly by drawing the poly.
  1864.   cmp       r9,r10                  ; Flags=next_yleft-next_yright.
  1865.   movGE     r9,r10                  ; Minimum in r9=nb of lines to draw.
  1866.   cmp       r9,#vclip               ; Is it greater than vclip?
  1867.   movGE     r9,#vclip               ; Then we won' t go after vclip-1.
  1868.   add       r10,r0,r5,asr #inv_N    ; r10=adress of xleft pixel.
  1869.   cmp       r5,#0                   ; Flags=xleft-0.
  1870.   movLT     r10,r0                  ; If xleft<0, then clip to left.
  1871.   b         _slopes_changed         ; And start to draw.
  1872.  
  1873. ; Here are the routines for edges tracking and polygon drawing.
  1874. ;   r0=adress of first hline    | r1 & r14=filling pattern
  1875. ;   r2=inverses table adress    | r3=left edge ymin
  1876. ;   r4=right edge ymin          | r5=xleft<<inv_N
  1877. ;   r6=xright<<inv_N            | r7=dxleft/dyleft<<inv_N
  1878. ;   r8=dxright/dyright<<inv_N   | r9=nb of lines to draw
  1879. ;   r10 & r11 used as temp      | r13=adress of _draw_hline
  1880. ._change_slopes
  1881.   ldmdb     r3,{r9,r10}             ; r9=xleft | r10=yleft.
  1882.   ldmia     r4,{r11,r12}            ; r11=xright | r12=yright.
  1883.   cmp       r10,r12
  1884.   bGT       _change_right
  1885.   bEQ       _change_both
  1886. ; Here we have r10=yleft<r12=yright.
  1887. ._change_left
  1888.   cmp       r10,#vclip              ; Current yleft is out of screen?
  1889.   ldmGEdb   r2!,{r0,r3-r13,pc}      ; Then quit.
  1890.   mov       r5,r9,lsl #inv_N        ; r5=xleft<<inv_N.
  1891.   ldmia     r3!,{r7,r11}            ; r7=next_xleft | r11=next_yleft.
  1892.   sub       r7,r7,r5,asr #inv_N     ; r7=int(dxleft).
  1893.   sub       r9,r11,r10              ; r9=next_yleft-yleft=dyleft.
  1894.   ldr       r9,[r2,r9,lsl #2]       ; r9=2^inv_N/dyleft.
  1895.   mul       r7,r9,r7                ; r7=int(dxleft)/dyleft<<inv_N.
  1896.   cmp       r11,r12                 ; Flags=next_yleft-yright.
  1897.   movGT     r11,r12                 ; r11=min(next_yleft;yright).
  1898.   cmp       r11,#vclip              ; Is it greater than hclip?
  1899.   movGE     r11,#vclip              ; Then we won' t go after hclip-1.
  1900.   sub       r9,r11,r10              ; r9=dy=min(...)-yleft.
  1901.   add       r10,r0,r5,asr #inv_N    ; r10=adress of xleft pixel.
  1902.   cmp       r5,#0                   ; Flags=xleft-0.
  1903.   movLT     r10,r0                  ; If xleft<0, then clip to left.
  1904.   b         _slopes_changed
  1905. ; Here we have r12=yright<r10=yleft.
  1906. ._change_right
  1907.   cmp       r12,#vclip              ; Current yright is out of screen?
  1908.   ldmGEdb   r2!,{r0,r3-r13,pc}      ; Then quit.
  1909.   mov       r6,r11,lsl #inv_N       ; r6=xright<<inv_N.
  1910.   ldmdb     r4!,{r8,r9}             ; r8=next_xright | r9=next_yright.
  1911.   subS      r8,r8,r6,asr #inv_N     ; r8=int(dxright).
  1912.   sub       r11,r9,r12              ; r11=next_yright-yright.
  1913.   subPL     r11,r11,#1              ; This is for better result.
  1914.   ldr       r11,[r2,r11,lsl #2]     ; r11=2^inv_N/(dyright).
  1915.   mul       r8,r11,r8               ; r8=int(dxright)/dyright<<inv_N.
  1916.   cmp       r9,r10                  ; Flags=next_yright-yleft.
  1917.   movGT     r9,r10                  ; r9=min(next_yright;yleft).
  1918.   cmp       r9,#vclip               ; Is it greater than hclip?
  1919.   movGE     r9,#vclip               ; Then we won' t go after hclip-1.
  1920.   sub       r9,r9,r12               ; r9=dy=min(...)-yright.
  1921.   add       r10,r0,r5,asr #inv_N    ; r10=adress of xleft pixel.
  1922.   cmp       r5,#0                   ; Flags=xleft-0.
  1923.   movLT     r10,r0                  ; If xleft<0, then clip to left.
  1924.   b         _slopes_changed
  1925. ; Here we have r10=yleft=r12=yright=y.
  1926. ._change_both
  1927.   cmp       r10,#vclip              ; Current y is out of screen?
  1928.   ldmGEdb   r2!,{r0,r3-r13,pc}      ; Then quit.
  1929.   mov       r5,r9,lsl #inv_N        ; r5=xleft<<inv_N.
  1930.   mov       r6,r11,lsl #inv_N       ; r6=xright<<inv_N.
  1931.   ldmia     r3!,{r7,r9}             ; r7=next_xleft | r9=next_yleft.
  1932.   ldmdb     r4!,{r8,r11}            ; r8=next_xright | r11=next_yright.
  1933.   sub       r7,r7,r5,asr #inv_N     ; r7=int(dxleft).
  1934.   subS      r12,r9,r10              ; r12=next_yleft-y=dyleft.
  1935.   ldmLEdb   r2!,{r0,r3-r13,pc}      ; Quit if dyleft=<0.
  1936.   ldr       r12,[r2,r12,lsl #2]     ; r12=2^inv_N/dyleft.
  1937.   mul       r7,r12,r7               ; r7=int(dxleft)/dyleft<<inv_N.
  1938.   subS      r8,r8,r6,asr #inv_N     ; r8=int(dxright).
  1939.   sub       r12,r11,r10             ; r12=next_yright-y=dyright.
  1940.   subPL     r12,r12,#1              ; This is for better result.
  1941.   ldr       r12,[r2,r12,lsl #2]     ; r12=2^inv_N/(dyright).
  1942.   mul       r8,r12,r8               ; r8=int(dxright)/dyright<<inv_N.
  1943.   cmp       r9,r11                  ; Flags=next_yleft-next_yright.
  1944.   movGT     r9,r11                  ; r9=min(next_yleft;next_yright).
  1945.   cmp       r9,#vclip               ; Is it greater than hclip?
  1946.   movGE     r9,#vclip               ; Then we won' t go after hclip-1.
  1947.   sub       r9,r9,r10               ; r9=dy=min(...)-y.
  1948.   add       r10,r0,r5,asr #inv_N    ; r10=adress of xleft pixel.
  1949.   cmp       r5,#0                   ; Flags=xleft-0.
  1950.   movLT     r10,r0                  ; If xleft<0, then clip to left.
  1951.   b         _slopes_changed
  1952.  
  1953. ; Here' s the filling routine, inspired (ripped?) from the one by Jan/BASS.
  1954. ; The main difference being it is commented! =)
  1955. #rept 40
  1956.   stmia     r10!,{r1,r14}
  1957. #endr
  1958. ._draw_hline
  1959.   add       r0,r0,#320              ; Next hline.
  1960.   addS      r5,r5,r7                ; xleft+=dxleft/dyleft.
  1961.   add       r10,r0,r5,asr #inv_N    ; r10=adress of xleft pixel.
  1962.   movLT     r10,r0                  ; If xleft<0, then clip to left.
  1963.   add       r6,r6,r8                ; xright+=dxright/dyright.
  1964.   subS      r9,r9,#1                ; One line drawn.
  1965.   bLE       _change_slopes
  1966. ._slopes_changed
  1967.   add       r11,r0,r6,asr #inv_N    ; r11=adress of xright pixel.
  1968.   cmp       r6,#hclip<<inv_N        ; xrigth>hclip?
  1969.   addGT     r11,r0,#hclip           ; Then clip to right.
  1970.   cmp       r11,r10                 ; xright=<xleft?
  1971.   bLE       _draw_hline
  1972.   tst       r10,#%01
  1973.   strNEB    r1,[r10],#1
  1974.   tst       r11,#%01
  1975.   strNEB    r1,[r11,#-1]!
  1976.   cmp       r11,r10
  1977.   bLE       _draw_hline
  1978.   tst       r10,#%10
  1979.   strNEB    r1,[r10],#1
  1980.   strNEB    r1,[r10],#1
  1981.   tst       r11,#%10
  1982.   strNEB    r1,[r11,#-1]!
  1983.   strNEB    r1,[r11,#-1]!
  1984.   sub       r11,r11,r10             ; r11=nb of longs to fill.
  1985.   movS      r11,r11,lsr #3
  1986.   strCS     r1,[r10],#4
  1987.   sub       pc,r13,r11,lsl #2
  1988.  
  1989. #if zizik
  1990. .player incbin "DSymPlay"           ; BASS' productions are so good.
  1991. ALIGN
  1992. .music incbin "z00m!n"              ; Wow!
  1993. ALIGN
  1994. #endif
  1995. ;----------------------->  THIS MUST BE AT VERY END  <-----------------------
  1996. .bss
  1997.