Elite on the BBC Micro and NES

# Drawing pixels: PIX

```       Name: PIX                                                     [Show more]
Type: Subroutine
Category: Drawing pixels
Summary: Draw a single pixel at a specific coordinate
Deep dive: Drawing pixels in the Electron version
Context: See this subroutine in context in the source code
Variations: See code variations for this subroutine in the different versions
References: This subroutine is called as follows:
* PLL1 (Part 1 of 3) calls PIX
* PLL1 (Part 2 of 3) calls PIX
* PLL1 (Part 3 of 3) calls PIX

Draw a pixel at screen coordinate (X, -A). The sign bit of A gets flipped
before drawing, and then the routine uses the same approach as the PIXEL
routine in the main game code, except it plots a single pixel from TWOS
instead of a two pixel dash from TWOS2. This applies to the top part of the
screen (the space view).

See the PIXEL routine in the main game code for more details.

Arguments:

X                    The screen x-coordinate of the pixel to draw

A                    The screen y-coordinate of the pixel to draw, negated

Other entry points:

PIX-1                Contains an RTS

.PIX

LDY #128               \ Set ZP = 128 for use in the calculation below
STY ZP

TAY                    \ Copy A into Y, for use later

EOR #%10000000         \ Flip the sign of A

CMP #248               \ If the y-coordinate in A >= 248, then this is the
BCS PIX-1              \ bottom row of the screen, which we want to leave blank
\ as it's below the bottom of the dashboard, so return
\ from the subroutine (as PIX-1 contains an RTS)

\ We now calculate the address of the character block
\ containing the pixel (x, y) and put it in ZP(1 0), as
\ follows:
\
\   ZP = &5800 + (y div 8 * 256) + (y div 8 * 64) + 32
\
\ See the deep dive on "Drawing pixels in the Electron
\ version" for details

LSR A                  \ Set A = A >> 3
LSR A                  \       = y div 8
LSR A                  \       = character row number

\ Also, as ZP = 128, we have:
\
\   (A ZP) = (A 128)
\          = (A * 256) + 128
\          = 4 * ((A * 64) + 32)
\          = 4 * ((char row * 64) + 32)

STA ZP+1               \ Set ZP+1 = A, so (ZP+1 0) = A * 256
\                           = char row * 256

LSR A                  \ Set (A ZP) = (A ZP) / 4
ROR ZP                 \            = (4 * ((char row * 64) + 32)) / 4
LSR A                  \            = char row * 64 + 32
ROR ZP

ADC ZP+1               \ Set ZP(1 0) = (A ZP) + (ZP+1 0) + &5800
ADC #&58               \             = (char row * 64 + 32)
STA ZP+1               \               + char row * 256
\               + &5800
\
\ which is what we want, so ZP(1 0) contains the address
\ of the first visible pixel on the character row
\ containing the point (x, y)

TXA                    \ To get the address of the character block on this row
EOR #%10000000         \ that contains (x, y):
AND #%11111000         \
ADC ZP                 \   ZP(1 0) = ZP(1 0) + (X >> 3) * 8
STA ZP

BCC P%+4               \ If the addition of the low bytes overflowed, increment
INC ZP+1               \ the high byte

\ So ZP(1 0) now contains the address of the first pixel
\ in the character block containing the (x, y), taking
\ the screen borders into consideration

TYA                    \ Set Y = Y AND %111
AND #%00000111
TAY

TXA                    \ Set X = X AND %111
AND #%00000111
TAX

LDA TWOS,X             \ Fetch a pixel from TWOS and OR it into ZP+Y
ORA (ZP),Y
STA (ZP),Y

RTS                    \ Return from the subroutine
```