394 lines
9.5 KiB
PHP
394 lines
9.5 KiB
PHP
; i'm so sorry for this file
|
|
|
|
PUSHS "Graphics Variables", WRAM0[PRINTER_VARS_START+$80]
|
|
vCurrentLineOAMOffsets: ds 16 ; 10 bytes which each store an offset into MY_OAM
|
|
vCurrentScanline: db ; what scanline are we looknig at
|
|
vCurrentDotX: db ; what x position we're looknig at
|
|
vCurrentPixelColor: db ; the pixel we're looking at's color value, 2 bits
|
|
vTopHalfOfSprite: ds $20 ; two tiles of tile data for the top half of a sprite
|
|
vBottomHalfOfSprite: ds $20 ; two tiles of tile data for the bottom half of a sprite
|
|
POPS
|
|
|
|
BuildRelevantSpritesList:
|
|
ld a, 0 ; a should now hold how many sprites we've looked at for this row
|
|
push af
|
|
|
|
ld de, vCurrentLineOAMOffsets
|
|
ld a, $ff
|
|
ld b, 14
|
|
; populatte oam offsets with $ff, an indicator that no sprite is found
|
|
.buildBlankList
|
|
ld [de], a
|
|
inc de
|
|
dec b
|
|
jp nz, .buildBlankList
|
|
|
|
ld de, vCurrentLineOAMOffsets
|
|
ld bc, $0000 ; starting offset
|
|
|
|
.loop
|
|
pop af ; counter for how many sprites we've added on thiis row
|
|
call IsThisSpriteRelevant
|
|
call c, AddThisSpriteToDE ; if it is relevant tthen add it
|
|
push af ; save the counter for the next row
|
|
cp a, 10 ; if the new counter is 10, then we're full up! and done w sprites
|
|
jp z, .doneWithOAM
|
|
inc c
|
|
inc c
|
|
inc c
|
|
inc c
|
|
ld a, c
|
|
cp a, $A0
|
|
jp z, .doneWithOAM
|
|
jp .loop
|
|
.doneWithOAM
|
|
pop af
|
|
ld a, [vCurrentScanline]
|
|
ret
|
|
|
|
IsThisSpriteRelevant:
|
|
push af ; don't wanna squash a
|
|
; bc is an offset into an OAM
|
|
; set the carry flag if we have to draw the sprite at OAM+bc on ths line.
|
|
|
|
ld hl, MY_OAM
|
|
|
|
ld a, [vCurrentScanline]
|
|
add hl, bc ; get OAM record. first byte is y value
|
|
sub a, [hl] ; vCurrentScanline - yvalue
|
|
jp c, .irrelevant ; if it carries, then the sprite is strrictly greater
|
|
; than scanline. not relevant.
|
|
cp a, 8
|
|
jp nc, .irrelevant ; if it doesn't carry, then a-[hl] is greater than or
|
|
; equal to 8. not relevant.
|
|
.relevant
|
|
; if it doesn't satisfy either of those circumstances, then it's relevant.
|
|
pop af
|
|
scf ; set carry
|
|
ret
|
|
.irrelevant
|
|
pop af
|
|
scf
|
|
ccf ; clear carry = set carry + complement carry
|
|
ret
|
|
|
|
AddThisSpriteToDE:
|
|
inc a ; increment a to signal we've added a sprite to the relevant sprites
|
|
push af
|
|
ld a, c ; bc holds hte offset iinto OAM, which always sstarts with $00
|
|
ld [de], a
|
|
inc de
|
|
pop af
|
|
ret
|
|
|
|
AddSpritesToLine:
|
|
; operates on sscanline [vCurrentScanline] and buffer BUFFER_ONE
|
|
push af
|
|
push bc
|
|
|
|
call BuildRelevantSpritesList
|
|
|
|
ld a, 16 ; account for border
|
|
ld [vCurrentDotX], a
|
|
.loopOverX
|
|
call GetCurrentBackgroundPixelValueFromBuffer
|
|
|
|
ld hl, vCurrentLineOAMOffsets
|
|
.loopOverSprites
|
|
ld b, 0
|
|
ld c, [hl]
|
|
bit 0, c
|
|
jp nz, .doneLoopingOverSprites ; if we find an offset with the first bit set
|
|
; then it has to be an endd-of-list flag so we're done looping over sprites.
|
|
; otherrwise we have a valid sprite offset in bc
|
|
|
|
push hl ; push hl (position in vCurrentLineOAMOffsees) to save for later
|
|
; this is popped in .nextSprite
|
|
|
|
ld hl, MY_OAM
|
|
add hl, bc ; index into MY_OAM
|
|
inc hl ; we're already certain it's in the range for y, so look at x
|
|
ld a, [vCurrentDotX] ; current x value
|
|
sub a, [hl] ; dx = x - sx -> if it carries, we skip
|
|
jp c, .nextSprite
|
|
cp a, 8 ; dx - 8 -> if it doesn't carry, we skip
|
|
jp nc, .nextSprite
|
|
|
|
dec hl ; look at whole oam record
|
|
;now we've ensured that 0 <= dx < 8
|
|
;get pixel A from sprite in oam
|
|
|
|
; a holds dx
|
|
; hl holds an OAM record
|
|
call GetPixelFromOAM
|
|
; a now holds a color id. if thatt color id is zero, go to the next sprite
|
|
; hl points to the OAM record
|
|
cp a, 0
|
|
jp z, .nextSprite
|
|
push af ; hold on to color id.
|
|
inc hl ; point to x value
|
|
inc hl ; point tto tile id
|
|
inc hl ; point to attributes
|
|
; palette is bit 4 [hl]
|
|
; priority is bit 7 [hl]
|
|
|
|
bit OAMB_PRI, [hl] ; if priority is zero, continue writing sprite color (skip this block)
|
|
jp z, :+
|
|
ld a, [vCurrentPixelColor] ; else priority iis 1
|
|
cp a, 0
|
|
jp z, :+ ; if priority is 1 and background is zero, continue writing sprite color
|
|
pop af ; gotta get that off the stack so it's clean
|
|
jp .doneLoopingOverSprites ; if priiority is 1 AND backgruond is nonzero,
|
|
; we're done with this pixel forever. this does not properly deal with priority
|
|
; but it should be good enough for thiis program.
|
|
:
|
|
pop af
|
|
cp a, 0
|
|
jp z, .nextSprite ; if the color index of the sprite is zero, then we can skip
|
|
push af
|
|
|
|
; get color from palette
|
|
ld a, [rOBP0]
|
|
bit OAMB_PAL1, [hl]
|
|
jp z, :+
|
|
ld a, [rOBP1]
|
|
:
|
|
ld b, a ; put the palette into b
|
|
pop af
|
|
; right shift the palette to get the specific color
|
|
; index (a) guaranteed to not be zero bc we checked for that above
|
|
:
|
|
srl b
|
|
srl b
|
|
dec a ; shift right twice per color index
|
|
jp nz, :-
|
|
ld a, b
|
|
and a, $3 ; now holds just the color itself
|
|
|
|
|
|
call WritePixelToBuffer
|
|
|
|
.nextSprite
|
|
pop hl
|
|
inc hl
|
|
jp .loopOverSprites
|
|
.doneLoopingOverSprites
|
|
|
|
ld hl, vCurrentDotX
|
|
inc [hl]
|
|
ld a, 80
|
|
cp a, [hl]
|
|
jp nc, .loopOverX
|
|
|
|
pop bc
|
|
pop af
|
|
ret
|
|
|
|
GetPixelFromOAM:
|
|
; hl takes an oam record
|
|
; a has an x offset
|
|
; bit 5, [hl+3] = x flip
|
|
; de takes the yx offsets
|
|
push hl
|
|
push de
|
|
ld e, a ; hold on to x offset
|
|
ld a, [vCurrentScanline] ; y position
|
|
sub a, [hl] ; currentScanline - y position
|
|
ld d, a ; hold on to y offset
|
|
inc hl ; look at x coord
|
|
inc hl ; look at tile id
|
|
|
|
ld a, [hl]
|
|
call FindCardSpriteTiles ; puts card sprite tiles in hl
|
|
call FindTileData ; uses a + hl to get tile data
|
|
|
|
ld a, d ; y offset is number of pairs of bytes to skip
|
|
cp a, 0
|
|
jp z, .doneFindingYLine
|
|
.loopFindYLine
|
|
inc hl
|
|
inc hl
|
|
dec a
|
|
jp nz, .loopFindYLine
|
|
.doneFindingYLine
|
|
|
|
;now hl points to two bytes which correspond to the correct tile data.
|
|
; abcd_efghi jklm_nopq
|
|
ld b, [hl] ; first bitplane
|
|
inc hl
|
|
ld c, [hl] ; second bitplane
|
|
|
|
ld a, 7
|
|
sub a, e ; number of times to shift right to put the bit we want in positoin 0
|
|
cp a, 0
|
|
jp z, .doneShiftingBC
|
|
.shiftbc
|
|
srl b
|
|
srl c
|
|
dec a
|
|
jp nz, .shiftbc
|
|
.doneShiftingBC
|
|
ld a, b
|
|
and a, $1
|
|
ld b, a
|
|
|
|
sla c
|
|
ld a, c
|
|
and a, $2
|
|
or a, b ; now a holds the color id!!
|
|
|
|
pop de
|
|
pop hl
|
|
ret
|
|
|
|
GetCurrentBackgroundPixelValueFromBuffer:
|
|
; takes arguments from vCurrentScanline and vCurrentDotX, gets the two-bit pixel
|
|
; value from the tile data llinearly packed at BUFFER_ONE
|
|
call FindCurrentBufferBytes
|
|
; sets hl and bc. b = msb tile, c = lsb tile
|
|
|
|
ld a, [vCurrentDotX]
|
|
and a, $7
|
|
ld e, a ; e = x % 8 = xoff
|
|
|
|
; now extract the specific pixel
|
|
ld a, 7
|
|
sub a, e ; 7-xoff = number of times to shift to the right
|
|
cp a, 0
|
|
jp z, .doneBitShifting
|
|
.bitShiftLoop
|
|
srl b
|
|
srl c
|
|
dec a
|
|
jp nz, .bitShiftLoop
|
|
.doneBitShifting
|
|
ld a, b
|
|
and a, $1
|
|
sla a
|
|
ld b, a
|
|
ld a, c
|
|
and a, $1
|
|
or a, b
|
|
|
|
ld [vCurrentPixelColor], a
|
|
ret
|
|
|
|
WritePixelToBuffer:
|
|
; takes 2-bit color as a, yx offsets as de.
|
|
; overwrites the pixel in the buffer with the color passed in.
|
|
ld b, a ; hold on to the color we're trying to write
|
|
and a, $1 ; LSB first
|
|
ld c, a
|
|
ld a, b
|
|
sra a ; MSB next
|
|
ld b, a ; now b and c hold msb and lsb
|
|
|
|
ld a, 7
|
|
sub a, e ; get x offset from right side (7-xoff)
|
|
|
|
jp z, :++
|
|
:
|
|
sla b
|
|
sla c
|
|
dec a
|
|
jp nz, :-
|
|
:
|
|
; now b and c have been shifted left according to their values.
|
|
push bc
|
|
call FindCurrentBufferBytes
|
|
call WipeTargetBit
|
|
pop bc
|
|
ld a, c
|
|
or a, [hl]
|
|
ld [hl], a ; lsb first
|
|
|
|
inc hl
|
|
|
|
ld a, b
|
|
or a, [hl]
|
|
ld [hl], a
|
|
|
|
ret
|
|
|
|
|
|
WipeTargetBit:
|
|
; hl points to a row, e holds an xoff
|
|
; sets the xoff bit of [hl] and [hl+1] to zero
|
|
; gonna make a mask that has 1s everywhere except for a zero at bit xoff
|
|
push de
|
|
ld d, $7F
|
|
|
|
; shift right by e bits
|
|
ld a, 0
|
|
cp a, e
|
|
ld a, d
|
|
jp z, :++
|
|
:
|
|
srl a
|
|
or a, $80
|
|
dec e
|
|
jp nz, :-
|
|
:
|
|
|
|
; apply the mask witth AND to [hl] and [hl+1]
|
|
ld d, a
|
|
|
|
;ld a, d
|
|
and a, [hl]
|
|
ld [hl], a
|
|
|
|
inc hl
|
|
|
|
ld a, d
|
|
and a, [hl]
|
|
ld [hl], a
|
|
|
|
dec hl
|
|
|
|
pop de
|
|
|
|
ret
|
|
|
|
|
|
|
|
FindCurrentBufferBytes:
|
|
; points hl at the bytes of BUFFER_TWO where the current scanline/dot live
|
|
ld a, [vCurrentScanline]
|
|
sub a, 16 ; subtract off the overscan
|
|
and a, $7 ; scanline mod 8, so we can step through the buffer
|
|
ld d, a ; store y offset within this row of tiles
|
|
ld a, [vCurrentDotX]
|
|
sub a, 8 ; subtract off the overscan
|
|
and a, $7 ; current dot mod 8, for an offste
|
|
ld e, a
|
|
ld a, [vCurrentDotX]
|
|
sub a, 8 ; subtract off the border
|
|
sra a
|
|
sra a
|
|
sra a ; divide a by 8 to geet numbre of tiles we want to step past
|
|
|
|
; now we want to get hl to point to the two bytes which define the pixel we want.
|
|
ld h, 0
|
|
ld l, a ; numbeer of tiles we want to step past. 16 bytes per this
|
|
add hl, hl ; number of tiles times 2
|
|
add hl, hl ; times 4
|
|
add hl, hl ; times 8
|
|
add hl, hl ; tmies 16 si the number of bytes to step forward
|
|
|
|
ld bc, BUFFER_TWO
|
|
add hl, bc ; this is pointing at the start of a tile.
|
|
|
|
; now step down by 2*d bytes to get the row we want
|
|
ld b, 0
|
|
ld c, d ; this is the y offset
|
|
; add twice y offset to hl to get the row we want.
|
|
add hl, bc
|
|
add hl, bc ; now we're pointing at the two bytes we want to extract a pixel from.
|
|
ld c, [hl] ; LSB fiirst
|
|
inc hl
|
|
ld b, [hl] ; MSB second
|
|
dec hl
|
|
|
|
ret
|
|
|