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
 | |
| 
 |