mcleod_ideafix

Sliding overlapping rectangles demo effect for the ZX Spectrum

Sep 23rd, 2021
971
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;    Technical demo: sliding overlapping rectangles
  2. ;    (C)2021 Miguel A. Rodriguez-Jodar ( mcleod_ideafix )
  3. ;            ZX Projects.
  4. ;
  5. ;    This program is free software: you can redistribute it and/or modify
  6. ;    it under the terms of the GNU General Public License as published by
  7. ;    the Free Software Foundation, either version 3 of the License, or
  8. ;    (at your option) any later version.
  9. ;
  10. ;    This program is distributed in the hope that it will be useful,
  11. ;    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;    GNU General Public License for more details.
  14. ;
  15. ;    You should have received a copy of the GNU General Public License
  16. ;    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  17.  
  18. ;    Assemble using PASMO: pasmo --tapbas sliding_rectangles.asm sliding_rectangles.tap
  19.  
  20.  
  21. X                       equ 0                     ; offset to X and Y coordinate
  22. Y                       equ 1                     ; of top left pixel of rectangle
  23. WIDTH                   equ 2                     ; offset to width and height
  24. HEIGHT                  equ 3                     ;
  25. SPEEDPAT                equ 4                     ; offset to binary pattern indicating which frame the rectangle is animated
  26. SPEEDMULT               equ 5                     ; offset to value indicating how many pixels the rectangle is moved
  27. LSTRU                   equ 6                     ; length of all fields above.
  28.  
  29. PIXEL_ADDRESS           equ 22B1h                 ; C=x, B=y, A=y. Returns HL=address, A=x mod 8
  30.  
  31.                         org 49152
  32.  
  33. Main                    proc
  34.                         xor a                     ;
  35.                         out (254),a               ;
  36.                         ld hl,16384               ;
  37.                         ld de,16385               ; Clear screen to bright B/W
  38.                         ld bc,6143                ;
  39.                         ld (hl),a                 ;
  40.                         ldir                      ;
  41.                         inc hl                    ;
  42.                         inc de                    ;
  43.                         ld (hl),71                ;
  44.                         ld bc,767                 ;
  45.                         ldir                      ;
  46.                         ld (23560),a              ; Clear 1-byte keyboard buffer
  47.  
  48.                         ld ix,RectTable           ; RectTable contains a list of rectangles
  49. InitialParseTable       ld a,(ix+HEIGHT)
  50.                         inc a
  51.                         jr z,EndInitialDrawing    ; A rectangle with height=255 marks the end of the list
  52.                         call DrawInitialRectangle ; Draws rectangle
  53.                         ld de,LSTRU
  54.                         add ix,de                 ; next rectangle
  55.                         jr InitialParseTable
  56. EndInitialDrawing
  57.  
  58. LoopMoveAll             ld a,(23560)              ; Read last pressed key
  59.                         cp 32                     ; if SPACE is presssed, then
  60.                         ret z                     ; return to BASIC
  61.  
  62.                         ld ix,RectTable           ; Now we parse RectTable to move the rectangles
  63. ParseTable              ld a,(ix+HEIGHT)
  64.                         inc a                     ;
  65.                         jr z,LoopMoveAll          ; if we reach the end of the table, start it all over again
  66.                         call MoveOneRectangle     ; move one rectangle
  67.                         ld de,LSTRU
  68.                         add ix,de                 ; next rectangle
  69.                         jr ParseTable
  70.                         endp
  71.  
  72. DrawInitialRectangle    proc
  73.                         ld d,(ix+HEIGHT)          ;
  74.                         ld c,(ix+X)               ; Retrieve rectangle parameters
  75.                         ld b,(ix+Y)               ; from the current entry of RectTable
  76.                         ld e,(ix+WIDTH)           ;
  77. DrawOneLine             call DrawLine             ;
  78.                         inc b                     ; simple loop to draw a rectangle by drawing all the horizontal
  79.                         dec d                     ; lines that comprises it.
  80.                         jr nz,DrawOneLine         ;
  81.                         ret
  82.                         endp
  83.  
  84. MoveOneRectangle        proc
  85.                         ld a,(ix+SPEEDPAT)        ; load SPEEDPAT for current rect
  86.                         rrc (ix+SPEEDPAT)         ; and rotate it for the next frame
  87.                         bit 0,a                   ; time to animate this rect?
  88.                         ret z
  89.  
  90.                         ld b,(ix+SPEEDMULT)       ; load how many pixels we have to move this rectangle
  91. Move1PixelDown          push bc
  92.  
  93.                         ld d,(ix+HEIGHT)
  94.                         ld c,(ix+X)
  95.                         ld b,(ix+Y)
  96.                         ld e,(ix+WIDTH)
  97.                         call DrawLine             ; Draws the top line of the rectangle (actually erasing it)
  98.                         ld a,b
  99.                         add a,d
  100.                         call AdjustBottomScreen
  101.                         ld b,a                    ; Move to the line below the last line of the rectangle and draws it
  102.                         call DrawLine
  103.  
  104.                         ld a,(ix+Y)
  105.                         inc a                     ; This rectangle has moved 1 pixel.
  106.                         call AdjustBottomScreen
  107.                         ld (ix+Y),a
  108.  
  109.                         pop bc
  110.                         djnz Move1PixelDown       ; Go back to move it again, if needed
  111.  
  112.                         ret
  113.                         endp
  114.  
  115. AdjustBottomScreen      proc
  116.                         jr nc,NoAdjustOverflow    ;
  117.                         sub 192                   ; Computes A mod 192
  118.                         ret                       ; even if A overflowed
  119. NoAdjustOverflow        cp 192                    ; after an addition (i.e.
  120.                         ret c                     ; 180 + 100 = 280, which
  121.                         sub 192                   ; doesn't fit in 8 bits)
  122.                         ret                       ; This is to roll back to the top of the screen
  123.                         endp
  124.  
  125. DrawLine                proc
  126.                         push bc
  127.                         push de
  128.  
  129.                         ld a,b                    ; The next routine needs this
  130.                         call PIXEL_ADDRESS        ; Calculate screen address (ROM routine)
  131.                         ld c,a                    ;
  132.                         or a                      ; Pixel 0 of this byte?
  133.                         ld a,0FFh                 ; Assume we fill the entire 8-pixel row
  134.                         jr z,DontShiftRight       ; So there's no need to shift the 8-pixel row
  135.                         ld b,a                    ;
  136. ShiftRight              srl a                     ; Not pixel 0, so we shift to the right until pixel B
  137.                         djnz ShiftRight           ;
  138. DontShiftRight          xor (hl)                  ; OVER 1 with screen
  139.                         ld (hl),a                 ; and store
  140.  
  141.                         ld a,8                    ;
  142.                         sub c                     ; Compute how many pixels we painted in the code before
  143.                         ld c,a                    ; and update E (line width) so there are less pixels to paint
  144.                         ld a,e                    ;
  145.                         sub c                     ;
  146.  
  147. Paint8Pixels            cp 9                      ; If there are less than 9 pixels still to paint...
  148.                         ld e,a
  149.                         inc hl
  150.                         jr c,PaintRightSide       ; then go calculate how many of them and paint them
  151.                         ld a,(hl)                 ; If there are more than 8 pixels, then a complete 8-pixel row can be painted
  152.                         cpl                       ; just by OVERing 1 the current 8-pixel row
  153.                         ld (hl),a                 ; and storing it again
  154.                         ld a,e                    ;
  155.                         sub 8                     ; 8 more pixels painted
  156.                         jr Paint8Pixels           ; go see if there are still more than 8 pixels
  157.  
  158. PaintRightSide          ld a,128                  ; We generate a value in A with just one high bit at the left (bit 7)
  159. ShiftRightSide          dec e                     ; If this is was the only pixel to paint
  160.                         jr z,FinishShift          ; then go paint it
  161.                         sra a                     ; If not, first replicate the 1-bit at bit 7 as much times as pixels are left to paint
  162.                         jr ShiftRightSide
  163. FinishShift             xor (hl)                  ; combine it with the current screen contents
  164.                         ld (hl),a                 ; and store it
  165.  
  166.                         pop de
  167.                         pop bc
  168.                         ret
  169.                         endp
  170.  
  171.                         ; Format: each db line is a rectangle.
  172.                         ; x-coordinate (0-246), y coordinate (0-191), width (must be > 8), height (1-191), animation pattern, animation mutiplier
  173.                         ; Rectangle must initially fit on screen
  174.                         ; Animation pattern: each frame, bit 0 of this value is checked. If 0, the rectangle is not moved down. If 1, it is moved down.
  175.                         ; Whether it has been moved or not, this value rotates one bit to the right
  176.                         ; Animation multiplier: if the animation pattern bit is 1, this value indicates how many pixels the rectangle has to be moved.
  177.                         ;
  178.                         ; Animation pattern can be crafted to get slower than 1 pixel/frame moving
  179.                         ; For fast moving rectangles, use a higher animation multiplier
  180. RectTable               db 18,0,80,100,   01010101b,1
  181.                         db 32,70,30,80,   11111111b,3
  182.                         db 128,88,100,46, 11111111b,5
  183.                         db 190,38,30,150, 11111111b,1
  184.                         db 150,40,20,90,  10101010b,2
  185.                         db 85,120,80,40,  11111111b,3
  186.                         db 130,10,50,130, 00010001b,1
  187.                         db 20,88,24,64,   11111111b,4
  188.                         db 140,2,30,130,  11111111b,2
  189.                         db 255,255,255,255,255         ; end of table
  190.  
  191.                         end Main
  192.  
RAW Paste Data