Game Duenix for Amiga computers/PutPixel.s

From Wikiversity
Jump to navigation Jump to search
;------------------------------------------------------------------------------
; DrawPixel - for Duenix for the Amiga
;------------------------------------------------------------------------------
; A set of procedures to draw 1 and 2x2 pixels of a given color.
; It also supports drawing a big (2x2) pixel with conditionally present
; dark boundary pixels around it.
; The logic deals with 5 bitplans; placing a pixel means modifying
; the corresponding bit in each of the 5 bitplans.
; The job seems rather trivial; one has to wonder why doing the same
; in AMOS was too slow (2024).
; This is Motorola 68000 assembly for the Amiga.
;------------------------------------------------------------------------------

;----------------------------------------------------------
; Interface variables
;----------------------------------------------------------
Bitplan0    dc.l 0,0,0,0     ;Addresses of bitplans 0-3
Bitplan4    dc.l 0,0,0,0     ;Address of bitplan 4 and three dummy zeros
pq_x_addr   dc.l 0           ;Pixel queue x address
pq_y_addr   dc.l 0           ;Pixel queue y address
pq_colour_addr  dc.l 0       ;Pixel queue color address
pq_top      dc.l 0           ;Top index of the item in the pixel queue
putpix_type dc.b 0
        dc.b 0,0,0

;----------------------------------------------------------
; Entry points for procedures
;----------------------------------------------------------
    bra Draw_queue_of_pixels
    bra Draw_Small_Pixel_Conditioned
    bra Draw_Big_Pixel_Conditioned
    bra DSP_Conditioned_BigScreen
    bra DBP_Conditioned_BigScreen

;----------------------------------------------------------
; Procedure Draw_One_Pixel_BigScreen
; Procedure Draw_One_Pixel
;----------------------------------------------------------
; d0: xcoord (input, does not change)
; d1: ycoord (input, does not change)
; d2: color (input, does not change)
; more input: Bitplan0
;
; used registers: d0-d7 but for d6, a0, a1, a2
;----------------------------------------------------------

Draw_One_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3
    Move.l  d1,d4
    Mulu    #80,d4
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 80 + xcoord / 8, which is the offset of the pixel address
    bra dop_address_known

Draw_One_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3
    Move.l  d1,d4
    Mulu    #40,d4
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 40 + xcoord / 8, which is the offset of the pixel address
dop_address_known
    Move.l  d0,d3
    And.l   #7,d3       
    Sub.l   #7,d3
    Neg.l   d3               ;d3 := 7 - (xcoord band 0b111), which is the bit number

    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0 address
    Moveq   #4,d5            ;d5 := bitplan number, and a loop control register (we have 5 bitplans)
    Move.l  d2,d7            ;d7 := color
dop_Loop_Start
    Move.l  (a1)+,a2         ;a2 := current bitplan address
    Add.l   a0,a2
    Move.b  (a2),d4          ;d4 := the value of the byte of the pixel in the bitplane
    Bclr.l  d3,d4
    Btst    #0,d7
    Beq dop_Zero
    Bset.l  d3,d4            ;clear the pixel bit or set it to 1 as applicable
dop_Zero
    Move.b  d4,(a2)          ;write d4 back to the bitplane
    Lsr.b   #1,d7
    DBra    d5,dop_Loop_Start
    Rts 

;--------------------------------------------------------------
; Procedure Draw_Conditioned_Pixel_BigScreen
; Procedure Draw_Conditioned_Pixel
; DCP: Draw conditioned pixel.
; Draw using the color of 1.
; "conditioned" means draw the pixel only if its bitplan 4
; bit is empty.
;--------------------------------------------------------------
; d0: xcoord
; d1: ycoord
;-------------------------------------------------------------

Draw_Conditioned_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #80,d4           ;d4 := ycoord * 80 
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 80 + xcoord / 8, which is offset of the pixel address
    bra dcp_address_known

Draw_Conditioned_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #40,d4           ;d4 := ycoord * 40 
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 40 + xcoord / 8, which is offset of the pixel address
dcp_address_known
    Move.l  d0,d3
    And.l   #7,d3
    Sub.l   #7,d3
    Neg.l   d3               ;d3 := 7 - (xcoord band 0b111), which is the bit number
    Move.l  Bitplan4(pc),a1
    Btst.b  d3,(a1,a0.l)
    Bne dcp_Finished         ;If bitplan 4 is non-zero, do not draw anything
    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0 address
    ;The first round outside of the loop
    Move.l  (a1)+,a2
    Bset.b  d3,(a2,a0.l)
    Moveq   #2,d2            ;Only 3 bitplans remain
dcp_Loop_Start
    Move.l  (a1)+,a2
    Bclr.b  d3,(a2,a0.l)
    DBra    d2,dcp_Loop_Start
dcp_Finished
    Rts 

;--------------------------------------
; Procedure DSP_Conditioned_BigScreen
; DSP: Draw small pixel
;--------------------------------------

DSP_Conditioned_BigScreen
    ;Draw classical pixel
    Bsr Draw_One_Pixel_BigScreen
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Rts

Draw_Small_Pixel_Conditioned
    ;Draw classical pixel
    Bsr Draw_One_Pixel
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Rts

;--------------------------------------
; Procedure DBP_Conditioned_BigScreen
; DBP: Draw big pixel.
; The boundary pixels are drawn in
; color 1 and are drawn only
; if the pixel being overwritten
; has color less than 16.
;--------------------------------------

DBP_Conditioned_BigScreen
    ;Draw classical pixel
    Bsr Draw_Big_Pixel_BigScreen    
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Rts

Draw_Big_Pixel_Conditioned
    ;Draw classical pixel
    Bsr Draw_Big_Pixel
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Rts

;================================================
; Second, perhaps better take at big pixel
;================================================

;------------------------------------------------
; Procedure Draw_Big_Pixel_BigScreen
;------------------------------------------------
; d0: xcoord
; d1: ycoord
; d2: color
; used: d3, d4, d6, a0
;------------------------------------------------
Draw_Big_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #80,d4           ;d4 := ycoord * 80
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := xcoord / 8 + ycoord * 80

    Move.l  d0,d4
    And.w   #$7,d4           ;d4 := xcoord band 0b111 (the bit number)
    Move.w  #$C000,d3
    Lsr.w   d4,d3            ;d3 := 0xC000 >> (xcoord band 0b111), which is the oring word 
    Move.w  d3,d6
    Eor.w   #$FFFF,d6        ;d6 := oring word XOR FFFF, which is the anding word   

    Bsr dbp_Double_Pixel    ;using a0, d2, d3 and d6
    Add #80,a0
    Bsr dbp_Double_Pixel    ;using a0, d2, d3 and d6
    Rts

;------------------------------------------------
; Procedure Draw_Big_Pixel
; Draws a "big pixel" consisting of 2x2 pixels
;------------------------------------------------
; d0: xcoord
; d1: ycoord
; d2: color
; used: d3, d4, d6, a0
;------------------------------------------------
Draw_Big_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4
    Mulu    #40,d4           ;d4 := ycoord * 40
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := xcoord / 8 + ycoord * 40

    Move.l  d0,d4
    And.w   #$7,d4           ;d4 := xcoord band 0b111 (the bit number)
    Move.w  #$C000,d3
    Lsr.w   d4,d3            ;d3 := 0xC000 >> (xcoord band 0b111), which is the oring word 
    Move.w  d3,d6
    Eor.w   #$FFFF,d6        ;d6 := oring word XOR FFFF, which is the anding word

    Bsr dbp_Double_Pixel     ;using a0, d2, d3 and d6
    Add #40,a0
    Bsr dbp_Double_Pixel     ;using a0, d2, d3 and d6
    Rts

;------------------------------------------------------------------------------
; Procedure dbp_Double_Pixel
; Draws two pixels horizontally next to each other. To be called two times,
; to draw the complete 2x2 big pixel.
;------------------------------------------------------------------------------
; a0: offset of the word to be modified, against the base of the bitplans
; d2: color
; d3: oring word
; d6: anding word    
;------------------------------------------------------------------------------
dbp_Double_Pixel
    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0
    Moveq   #4,d5            ;d5 := bitplan number, and a loop control register (we have 5 bitplans)
    Move.l  d2,d7            ;d7 := color
dbp_Loop_Start
    Move.l  (a1)+,a2         ;a2 := a1; a1 += 1
    Add.l   a0,a2            ;a2 := start of the current bitplan + offset of the byte to be modified
    Move.w  (a2),d4          ;d4 := content of the byte to be modified
    And.w   d6,d4
    Btst    #0,d7
    Beq dbp_Zero
    Or.w    d3,d4
dbp_Zero
    Move.w  d4,(a2)          ;write d4 back to the bitplane
    Lsr.b   #1,d7
    DBra    d5, dbp_Loop_Start
    Rts

;============================================================

;------------------------------------------------
; Procedure Draw_queue_of_pixels
;------------------------------------------------
; input:
;   pq_x_addr
;   pq_y_addr
;   pq_colour_addr
;   pq_top
;   putpix_type
; local:
;   d0, d1, d2, d3, a0
;   a6: index of the current element in the queue
;------------------------------------------------

Draw_queue_of_pixels
    Move.l pq_x_addr(pc),a3
    Move.l pq_y_addr(pc),a4
    Move.l pq_colour_addr(pc),a5

    Move.l #-1,a6            ;for each item in the queue (d6 := queue_item_idx)
dq_Loop 
    Addq   #1,a6
    Move.l pq_top(pc),a0
    Cmp.l  (a0),a6
    Bge    dq_finished       ;if queue_item_idx >= pq_top: go to dq_finished

    Move.l a6,d0
    Asl.w  #2,d0
    Move.l (a5,d0),d2
    Move.l (a4,d0),d1
    Move.l (a3,d0),d0

    Moveq  #0,d3
    Move.b putpix_type(pc),d3
    Lea.l  putpix(pc),a0
    Jsr    (a0,d3)

    Bra    dq_Loop
dq_finished
    Rts

putpix
    Bra Draw_Small_Pixel_Conditioned
    Bra Draw_Big_Pixel_Conditioned
    Bra DSP_Conditioned_BigScreen
    Bra DBP_Conditioned_BigScreen