;----------------------------------------------------------------------------- ; sprite.inc ; Part of manic miner, the zx spectrum game, made for Apple II ; ; Stefan Wessels, 2020 ; This is free and unencumbered software released into the public domain. ;----------------------------------------------------------------------------- 65816 OFF copy src/defs.s SPRITE start using LOWMEM using ROSYSTEM using ROLEVELS using ROSPRITES ;----------------------------------------------------------------------------- ; Copy bytes from srcPtr to dstPtr ; IN: - srcPtr - start of copy ; dstPtr - start of non-overlapping destination ; size - number of bytes to copy ; Clobbers: a,y spriteCopyMemSrcToDst entry ldy #0 hiCopy anop dec sizeH bmi lowCopy scm0 lda (srcPtrL),y sta (dstPtrL),y dey bne scm0 inc srcPtrH inc dstPtrH bne hiCopy lowCopy anop ldy sizeL dey bmi doneScm scm1 lda (srcPtrL),y sta (dstPtrL),y dey bpl scm1 doneScm anop rts ;----------------------------------------------------------------------------- ; Look up the color, and apply those masks to the frames ; IN: x = start frame ; y = num frames ; a = color index ; Clobbers: a,y spriteApplyMaskToFrames entry ;instanceIdx0 equ tmpBot+0 colMaskL0 equ tmpBot+1 colMaskR0 equ tmpBot+2 numFrames equ tmpBot+3 sty numFrames ; save y tay ; put color index in y lda masksLeft,y ; look up the masks for the color sta colMaskL0 lda masksRight,y sta colMaskR0 lda mult64L,x ; build a pointer to the frame sta srcPtrL lda mult64H,x adc #>spriteInstances sta srcPtrH ldy numFrames ; convert frames to bytes lda mult64H,y sta sizeH lda mult64L,y sta sizeL ldy #0 ; do blocks of 256 hiPass anop dec sizeH ; see if there's a hi block to do bmi lowPass ; if none (remain) to do, move on sam0 lda (srcPtrL),y ; do a left hand byte and colMaskL0 sta (srcPtrL),y dey lda (srcPtrL),y ; then a right hand byte and colMaskR0 sta (srcPtrL),y dey bne sam0 ; for 256 bytes inc dstPtrH ; advance the dest ptr Hi bne hiPass ; BRA lowPass anop ldy sizeL ; do bytes remaining lt 256 dey bmi doneSam ; keep going till all done sam1 lda (srcPtrL),y and colMaskL0 sta (srcPtrL),y dey lda (srcPtrL),y and colMaskR0 sta (srcPtrL),y dey bpl sam1 doneSam anop rts ;----------------------------------------------------------------------------- ; Copy one frame to another ; IN: ; originalFrame = tmpBot+4 ; newFrame = tmpBot+5 ; Clobbers: a,x,y spriteCopyFrameToFrame entry originalFrame0 equ tmpBot+4 newFrame0 equ tmpBot+5 clc ldx originalFrame0 ; point srcPtr at the original frame lda mult64L,x sta srcPtrL lda mult64H,x adc #>spriteInstances sta srcPtrH ldx newFrame0 ; point dstPtr at the target frame lda mult64L,x sta dstPtrL lda mult64H,x adc #>spriteInstances sta dstPtrH lda #0 ; 256 or less bytes (no Hi) sta sizeH lda #64 ; just 64 bytes to copy sta sizeL jsr spriteCopyMemSrcToDst ; use copymem to copy a 64 byte frame rts ;----------------------------------------------------------------------------- ; Invert the pixels of a frame ; IN: ; x = frame number spriteInvertFrame entry clc lda mult64L,x ; make srcPtr point at the frame sta srcPtrL lda mult64H,x adc #>spriteInstances sta srcPtrH ldy #SPRITE_BYTES-1 ; do for a whole frame (0 based) sif0 lda (srcPtrL),y ; get the frame byte eor #%01111111 ; invert except for the MSB sta (srcPtrL),y ; and save the byte dey ; one less byte to do bpl sif0 ; do for all bytes rts ;----------------------------------------------------------------------------- ; Clear all the pixels of a frame ; IN: ; x = frame number ; y = number of frames to clear spriteClearFrames entry count0 equ sizeL lda mult64L,y ; turn the number of frames into num bytes sta count0 ; save as a count clc ; and clear carry lda mult64L,x ; make srcPtr point at the sta srcPtrL lda mult64H,x adc #>spriteInstances sta srcPtrH ldy count0 ; how many bytes to clear dey ; make zero based lda #0 ; value to write scf0 sta (srcPtrL),y ; write 0 to frame dey ; previous byte in frame bpl scf0 ; do for all, incl. zero'th byte rts ;----------------------------------------------------------------------------- ; Make an instance of the bitmap (index in a) into the spriteInstance buffer ; while expanding the bitmap from 32 byte 1bpp into 64 byte 2bpp and masking ; the instance for the required color. ; IN: ; a - bitmapIdx ; x - instanceIdx spriteInstanceSpriteFrames entry ; count = tmpBot+0 ; spriteIdx = tmpBot+1 instanceIdx1 equ tmpBot+2 srcIdx equ tmpBot+3 dstIdx equ tmpBot+4 colMaskL1 equ tmpBot+5 colMaskR1 equ tmpBot+6 ldy #0 sty srcPtrH sty dstPtrH ldy #5 ; mult * 32 (shl 5 times) since each src frame is 32 bytes sis0 asl a ; shift the low rol srcPtrH ; and the hi, and move carry into hi if needed dey ; do for all 6 iterations bne sis0 adc #sprite08 adc srcPtrH sta srcPtrH ; src ptr now points at the 1st frame lda spriteFramesIdx,x ; get the sprite dest frame ldy #6 ; mult * 64 (shl 6 times) since each frame is 64 bytes sis1 asl a ; shift the lo rol dstPtrH ; and the hi, and move carry into hi if needed dey ; do for all 6 iterations bne sis1 sta dstPtrL ; save the lo lda dstPtrH ; get the hi adc #>spriteInstances ; and make relative to the buffer sta dstPtrH ; and save the hi lda #1 ; assume 4 frames equ 256 bytes sta sizeH lda spriteClass,x ; get the class bit bit1Mask ; CLASS_FOUR_FRAME is it 4 frames bne sis2 ; yes, all set inc sizeH ; 8 frames = 512 bytes equ 2 Hi sis2 ldy instanceIdx1 ; get the instance lda spriteColor,y ; and get the color for the instance tay ; put the color index in y lda masksLeft,y ; get the color mask sta colMaskL1 lda masksRight,y ; do the same for the right sta colMaskR1 ; SQW - look at comments but save for second (inverse) buffer ldy #0 sty dstIdx ; set the src and dst indices to start at 0 sty srcIdx ; srcIndex moves at 1/2 of dstIndex copyFrames anop ldy srcIdx ; get the source index lda (srcPtrL),y ; get a (left) src byte at the source index pha ; save so the right nibble can be expanded later lsr a ; make the left nibble the low nibble lsr a lsr a lsr a tax ; put the value in x lda binDouble,x ; look up the "pixel doubled" value ora #$80 ; and set the color msb "on" and colMaskL1 ; mask it with appropriate color ldy dstIdx ; get the destination offset sta (dstPtrL),y ; and save to instance destination iny ; move the destination along one pla ; get the source byte and #$0f ; mask so only right nibble tax ; put it in x lda binDouble,x ; and look up the "doubled" pixel values sec ; set carry so a rotate will be equiv to or #$80 ror a ; and rotate, making it a "right" byte and colMaskR1 ; mask it with appropriate color sta (dstPtrL),y ; and save to instance destination iny ; move the dest index along again sty dstIdx ; and save the index bne sis3 ; if the index rolled over inc dstPtrH ; move the hi byte along dec sizeH ; check if moved all required 4 * 32 src byte blocks beq doneSis sis3 inc srcIdx ; move the src index along bne copyFrames ; do max 256 bytes equ 8 * 32 byte src frames doneSis anop rts ;----------------------------------------------------------------------------- ; Copy the door frame, invert the copy, mask both and combine spriteDoorSetup entry originalFrame1 equ tmpBot+4 newFrame1 equ tmpBot+5 ldx numSprites ; numSprites is the door sprite index lda spriteFramesIdx,x tax stx originalFrame1 inx stx newFrame1 jsr spriteCopyFrameToFrame ; make a copy y = instanceIdx, a = srcFrame,x equ dstFrame ldx newFrame1 jsr spriteInvertFrame ; invert the instance frame bits (leave msb alone) ldx currLevel lda door_color1,x beq sds0 ldx originalFrame1 ldy #1 jsr spriteApplyMaskToFrames ldx currLevel lda door_color2,x beq sds0 ldx newFrame1 ldy #1 jmp spriteApplyMaskToFrames sds0 rts ;----------------------------------------------------------------------------- ; Make 4 copies of Eugene frame 0 into frames 1-4 and apply a different ; color mask to the additional frames spriteEugeneSetup entry originalFrame2 equ tmpBot+4 newFrame2 equ tmpBot+5 count1 equ tmpBot+6 ldx numSprites dex ; eugene is sprite before the door lda spriteFramesIdx,x ; get the frame where eugene is tax ; put in x stx originalFrame2 ; and call it the original inx ; and go to the next frame stx newFrame2 ; and call it the new frame ldx #3 ; and set the loop count to 3 stx count1 ses0 jsr spriteCopyFrameToFrame ; make a copy of eugene,x = ori,y equ new lda count1 ; get the count in a (as a color mask index) ldx newFrame2 ; the frame in x ldy #1 ; and the number of frames to process in Y jsr spriteApplyMaskToFrames ; mask the new eugene to the "count" color inc newFrame2 ; go up a frame dec count1 ; and dec the loop counter bne ses0 ; and do for the number of loops (3) rts ; there are now 4 eugenes, White, Green, Orange & Purple end