;*********************************************** ; NASR WARP - by Jingyang Xu * ; (br00416@bingsuns.cc.binghamton.edu) * ; Include this header if you wish to use * ; the subroutines please * ;*********************************************** ****************** *Revision History* ****************** 1.0 - First version - scanned sprite pixel-by-pixel and PTON 1.5 - 70% speed increase - only use FINDPIXEL once 1.9 - 100% speed increase from 1.0 - optimized routines 2.0a - first attempt at byte-shifting, didn't work 2.0b - swapped b and c registers, first working version of byte-shifter - 200% increase of speed over 1.0 2.1 - fixed periodic cutting off of the right side of sprite WARP - fixed extra blank pixels "region of influence" around sprite (I hope I don't get sued by IBM) WARP fix - replaced fake NASR 2.1 with real one. WARP fix 2 - fixed WARP clipping problem, added fixed transparent version of NASR, fixed hellosprite WARP addon 1 - Erasure built into NASRWARP ******* *Usage* ******* Included with this file are NASR (Non-Aligned Sprite Routine) 2.1 and WARP and TRANS. NASR 2.1 and WARP will write a non-transparent sprite to the screen, to erase, a blank sprite of the same size must be defined*. 2.1 is included because it is a bit faster and smaller than WARP, but it will overwrite up to 8 blank pixels to the right and left of each line of the sprite. So if you are using big sprites or don't mind the overwriting, use 2.1 instead of WARP. NASRTRANS is a working transparent version of NASR; Erasure should be done by reading the area that the sprite is drawn over. -------------------------- * this version of NASR allows you to erase using the same sprite, but only with NASR WARP. If you have a sprite that is x wide and y high then: a=smallest integer greater than or equal to x/8 b=a*8-x+1 c=y Define a sprite like this: Sprite: .db a,b,c <- 3 bytes .db %xxxxxxxx,%xxxxxxxx,%xxxxxxxx,... <- first line of sprite .db %xxxxxxxx,%xxxxxxxx,%xxxxxxxx,... <- 2nd line .db .... <- other lines like above Each of the x's is a 1 or a 0, depending on if you want the pixel on or off. If a sprite have a length that's not a multiple of 8, then just leave the unused bits of each line to be 0 (they can be anything you want, just fill them in) Example - the following sprite is a "hello" (the 0's have been changed to a "." to make the sprite stand out) Hello_Sprite: .db 3,6,5 .db %1.1.111., %1...1..., %111..... .db %1.1.1..., %1...1..., %1.1..... .db %111.111., %1...1..., %1.1..... .db %1.1.1..., %1...1..., %1.1..... .db %1.1.111., %111.111., %111..... Input - (x,y) coordinates from bottom left corner of screen are passed in b and c respectively, these define the upper left corner of the sprite. The address of the sprite must be in hl. So if you want to blit the sprite to 2,55 on the screen, you'd do this: ld b,2 ld c,55 ld hl,Hello_Sprite ld de,(PROGRAM_ADDR) add hl,de CALL_(NASRWARP) ******* *Setup* ******* You must define three (four for NASRWARP) variables in Text Memory: TempLine = $80df TempLine is a storage buffer for the each line of the sprite before it is blitted to the screen. The number of bytes you allot to TempLine determines the maximum width of the sprite. In this setup, 8 bytes is allotted to TempLine, therefore the maximum width is 64 bytes. PicCoor = $80e7 Two byte space needed by the program to store on-screen coordinates offset = $80e9 One byte space to store c NASR_Status = $80ea (NASRWARP only, do not use with NASR 2.1 or NASR TRANS) One byte space: load a zero in this prior to calling NASRWARP to have it erase your sprite, load anything else in to have it draw your sprite. ********** *Routines* ********** NASRWARP: push bc ex de,hl ROM_CALL(FIND_PIXEL) ld bc,$fc00 add hl,bc ld (PicCoor),hl ex de,hl ld b,$ff Patch: rla inc b jr nc,Patch ld a,(hl) ld c,a inc hl ld a,(hl) ld (offset),a ld a,b ld e,c cp (hl) jr c,DS1 inc e DS1: inc hl ld a,(hl) ld d,a inc hl YLoop: push bc push de ld b,8 ex de,hl ld hl,TempLine InitTempLineLoop: ld (hl),$ff inc hl djnz InitTempLineLoop ex de,hl ld a,(NASR_Status) cp 0 jr z,NASRErase NASRDraw: ld b,0 ld de,TempLine ldir jr NASRDrawFin NASRErase: ld b,c ld hl,TempLine LoadEmpty: ld (hl),0 inc hl djnz LoadEmpty NASRDrawFin: pop de pop bc push hl push bc push de ld d,b ld a,b cp 0 jr z,skipshift SpriLoop1: ld a,b ld HL,TempLine ld b,e scf SpriLoop2: rr (HL) inc HL djnz SpriLoop2 ld b,a djnz SpriLoop1 ld b,d skipshift: ld a,$ff ;fill accumulator inc b mask1: srl a ;make the mask djnz mask1 ;something like scf ;00001111 -> rl a ld hl,(PicCoor) ;implement the mask or (hl) ;this preserve the 0 bits ld hl,TempLine ;become xxxx1111 and (hl) ;when anded, become ld (hl),a ;xxxxyyyy ld b,d ;retrieve b ld a,(offset) dec a sub b jr nc,skip sub 248 skip: ld b,a inc b ld a,$ff mask2: sla a djnz mask2 scf rr a dec e ld hl,(PicCoor) ld d,0 add hl,de or (hl) ld hl,TempLine add hl,de and (hl) ld (hl),a inc e ld c,e ld hl,(PicCoor) ld de,16 push hl add hl,de ld (PicCoor),hl pop hl ld de,TempLine ex de,hl ld b,0 ldir pop de pop bc pop hl dec d jr nz,YLoop pop bc ret ;**************************************************8 NASR2_1: push bc ex de,hl ROM_CALL(FIND_PIXEL) ld bc,$fc00 add hl,bc ld (PicCoor),hl ex de,hl ld b,$ff Patch: rla inc b jr nc,Patch ld a,(hl) ld c,a inc hl ld a,b ld e,c cp (hl) jr c,DS1 inc e DS1: inc hl ld a,(hl) ld d,a inc hl YLoop: push bc push de ld b,8 ex de,hl ld hl,TempLine InitTempLineLoop: ld (hl),0 inc hl djnz InitTempLineLoop ex de,hl ld b,0 ld de,TempLine ldir pop de pop bc ld a,b cp 0 CALL_NZ(ShiftLine) push bc push hl push de ld c,e ld hl,(PicCoor) ld de,16 push hl add hl,de ld (PicCoor),hl pop hl ld de,TempLine ex de,hl ld b,0 ldir pop de pop hl pop bc dec d jr nz,YLoop pop bc ret ShiftLine: push hl push bc SpriLoop1: ld a,b ld HL,TempLine ld b,e and a SpriLoop2: rr (HL) inc HL djnz SpriLoop2 ld b,a djnz SpriLoop1 pop bc pop hl ret ;********************************************************** NASRTRANS: push bc ex de,hl ROM_CALL(FIND_PIXEL) ld bc,$fc00 add hl,bc ld (PicCoor),hl ex de,hl ld b,$ff Patch: rla inc b jr nc,Patch ld c,(hl) inc hl ld a,b ld e,c cp (hl) jr c,DS1 inc e DS1: inc hl ld a,(hl) ld d,a inc hl YLoop: push bc push de ld b,8 ex de,hl ld hl,TempLine InitTempLineLoop: ld (hl),0 inc hl djnz InitTempLineLoop ex de,hl ld b,0 ld de,TempLine ldir pop de pop bc ld a,b cp 0 CALL_NZ(ShiftLine) push bc push hl push de ld b,e ld hl,(PicCoor) ld de,16 push hl add hl,de ld (PicCoor),hl pop hl ld de,TempLine ex de,hl LoadSpriteLoop: ld a,(hl) ex de,hl or (hl) ld (hl),a ex de,hl inc de inc hl djnz LoadSpriteLoop pop de pop hl pop bc dec d jr nz,YLoop pop bc ret ShiftLine: push hl push bc SpriLoop1: ld a,b ld HL,TempLine ld b,e and a SpriLoop2: rr (HL) inc HL djnz SpriLoop2 ld b,a djnz SpriLoop1 pop bc pop hl ret ;**************************************************************** NASRWARPErase: push bc ex de,hl ROM_CALL(FIND_PIXEL) ld bc,$fc00 add hl,bc ld (PicCoor),hl ex de,hl ld b,$ff Patch: rla inc b jr nc,Patch ld a,(hl) ld c,a inc hl ld a,(hl) ld (offset),a ld a,b ld e,c cp (hl) jr c,DS1 inc e DS1: inc hl ld a,(hl) ld d,a inc hl YLoop: push bc push de ld b,8 ex de,hl ld hl,TempLine InitTempLineLoop: ld (hl),$ff inc hl djnz InitTempLineLoop ex de,hl ld b,c ld hl,TempLine LoadEmpty: ld (hl),0 inc hl inc de djnz LoadEmpty ex de,hl pop de pop bc push hl push bc push de ld d,b ld a,b cp 0 jr z,skipshift SpriLoop1: ld a,b ld HL,TempLine ld b,e scf SpriLoop2: rr (HL) inc HL djnz SpriLoop2 ld b,a djnz SpriLoop1 ld b,d skipshift: ld a,$ff ;fill accumulator inc b mask1: srl a ;make the mask djnz mask1 ;something like scf ;00001111 -> rl a ld hl,(PicCoor) ;implement the mask or (hl) ;this preserve the 0 bits ld hl,TempLine ;become xxxx1111 and (hl) ;when anded, become ld (hl),a ;xxxxyyyy ld b,d ;retrieve b ld a,(offset) dec a sub b jr nc,skip sub 248 skip: ld b,a inc b ld a,$ff mask2: sla a djnz mask2 scf rr a dec e ld hl,(PicCoor) ld d,0 add hl,de or (hl) ld hl,TempLine add hl,de and (hl) ld (hl),a inc e ld c,e ld hl,(PicCoor) ld de,16 push hl add hl,de ld (PicCoor),hl pop hl ld de,TempLine ex de,hl ld b,0 ldir pop de pop bc pop hl dec d jr nz,YLoop pop bc ret ; Enjoy!