423 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			10 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
 | 
						|
 | 
						|
CardAdjustTileMap:
 | 
						|
; "fix" the tile map copied into BUFFER_ONE if it needs to be edited for proper 
 | 
						|
; display of a card. so far this should only apply to Wheel of Fortune because 
 | 
						|
; that's the only card that uses custom non-sprite drawing.
 | 
						|
; a holds the row of the tile map we're on.
 | 
						|
 | 
						|
BuildRelevantSpritesList:
 | 
						|
; uses a, bc, de
 | 
						|
  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
 | 
						|
    jr 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
 | 
						|
    jr z, .doneWithOAM
 | 
						|
    ld a, c 
 | 
						|
    add a, 4
 | 
						|
    ld c, a 
 | 
						|
    cp a, $A0
 | 
						|
    jr nc, .doneWithOAM
 | 
						|
    jr .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 bc
 | 
						|
 | 
						|
  call BuildRelevantSpritesList
 | 
						|
  
 | 
						|
  ld a, 16 ; account for border and overscan
 | 
						|
  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
 | 
						|
      
 | 
						|
      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
 | 
						|
        pop hl ; gotta get this off the stack too, bc we're jumpinig to 
 | 
						|
        ; doneloopingoversprites which doesn't normally pop hl
 | 
						|
        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
 | 
						|
  ret
 | 
						|
 | 
						|
GetPixelFromOAM:
 | 
						|
; hl takes an oam record
 | 
						|
; a has an x offset
 | 
						|
; bit 5, [hl+3] = x flip
 | 
						|
; we set de to the yx offsets here, and incorporate flippnig
 | 
						|
  push hl
 | 
						|
  push de
 | 
						|
  inc hl
 | 
						|
  inc hl
 | 
						|
  inc hl 
 | 
						|
  bit 5, [hl]
 | 
						|
  jr z, :+
 | 
						|
    ld e, a 
 | 
						|
    ld a, 7
 | 
						|
    sub a, e
 | 
						|
  :
 | 
						|
  dec hl 
 | 
						|
  dec hl
 | 
						|
  dec hl
 | 
						|
  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 
 | 
						|
  inc hl 
 | 
						|
  inc hl 
 | 
						|
  bit 6, [hl]
 | 
						|
  jr z, :+
 | 
						|
    ld a, 7
 | 
						|
    sub a, d
 | 
						|
    ld d, a 
 | 
						|
  :
 | 
						|
  dec hl
 | 
						|
  
 | 
						|
  ld a, [hl]
 | 
						|
  cp a, $90
 | 
						|
  jr nc, .tileDataFromText
 | 
						|
  .tileDataFromSpriteTiles
 | 
						|
    call FindCardSpriteTiles ; puts card sprite tiles in hl
 | 
						|
    call FindTileData ; uses a + hl to get tile data
 | 
						|
    jr .foundTileData
 | 
						|
  .tileDataFromText
 | 
						|
    sub a, $90
 | 
						|
    ld hl, LetterTiles
 | 
						|
    call FindTileData
 | 
						|
  .foundTileData
 | 
						|
  
 | 
						|
  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
 | 
						|
 |