gb-tarot/RecreatingCards.inc
2025-04-25 20:24:12 -04:00

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