So, while perusing code snippets and old forum posts, in relation to FH2-GC, I came across an issue Im sure others have solved, but whose answer remains elusive to me.

In the game, I am likely going to simply draw the map to the screen, and then handle the sprites - but, XORing sprites on top of a different image will make things look weird, right? How would I draw the sprite without either making the sprite look weird, and without erasing the 16x24 area of the sprite that isn't actually needed for drawing?
You might try ORing the sprites to the screen... I am a little unsure of what is being drawn on what. Smile
You could use OR logic to draw a sprite, however any solid pixels in your background will be shown through the sprite as well.

I think perhaps you're looking for a 'sprite masking' routine?

The concept is that you have a sprite and also black and white mask that goes with it. You first apply the mask to your background (typically using AND logic) where the mask is used to only erase the portion of the background that the necessary parts of the sprite will overwrite, and preserve the rest. Basically you can use this technique to specify which pixels in your sprite will be transparent, or opaque.

For example, take the rough background, sprite and sprite mask below:


Note that the sprite is a circle, so you dont want the 'square corners' of the sprite drawn. You can see that the sprite mask has the 'corners' filled in so when the mask is AND'd with the background, the corners will be preserved and the white section, which is the circular sprite will be cleared as shown:


Then you can simply OR/XOR the sprite to the background to combine them:


Sorry thats a bit of a rough explanation and there are plenty of sprite routines around that are an 'all-in-one' options. Sadly I lost all my routines but I'm sure this forum has some somewhere.
What exactly does the XOR command do? And how would one use it to draw sprites?

EDIT: Answer to the first question: http://tibasicdev.wikidot.com/xor
That is not actually the right XOR command Smile Basically, in usually non-basic programs, an xor routine can be used to draw the sprite, and if drawn again in the same spot it will display what was originally there. You can use this primarily in order to not have to reset the screen every time. You could use the XOR command for some encryption routines though Wink
Ah I see Smile non-basic? Like using something like Grammar?
Kind of, but this is more typical of assembly. There are many sprite routines out there; this is just an example of one method.
You can read up on bitwise operations here: http://en.wikipedia.org/wiki/Bitwise_operation
I've written several masked sprite routines which you're welcome to use if you'd like. The basic concept is that you'll need to rotate both your sprite and your mask. Then, instead of:

Code:
xor (hl)   ;hl = position in gbuf, a = rotated sprite byte
ld (hl),a  ;save xor'd byte to gbuf
..you do:

Code:
and (hl)    ;a = rotated mask, hl = gbuf byte
or d       ;d = rotated sprite byte
ld (hl),a   ;save masked byte into gbuf


Here's a sample 16x16 masked sprite routine:

Code:
;ix = player sprite
;ix+32 = player sprite mask
;b = x
;e = y
;c = sprite height
dibSprite:
; y * 12
   ld l,e         ;hl=de
   add   hl, hl      ; 2
   add   hl, de      ; 3
   add   hl, hl      ; 6
   add   hl, hl      ;x12

; x / 8
   ld a,b
   srl b
   srl b
   srl b
   ld e,b
   add   hl, de      ; A present on a le décalage dans hl
   ld de,gbuf+2      ; Prendre le début du graphbuffer
   add   hl, de      ; Puis ajouter le décalage
   and $07
   ld b,a
;b=xoff
drawPlayerSprite:
drawPlayerSpriteLoop:
   push bc
drawPlayerRow:
   ld d,(ix+32)   ;sprite mask
   ld e,(ix+33)
   ld a,$ff
   dec b \ inc b \ jr z,skipMaskClip   ;si b=0
   scf \ rr d \ rr e \ rra \ djnz $-6   ;rotate mask
skipMaskClip:
   and (hl)
   ld (hl),a
   dec hl
   ld a,(hl)
   and e
   ld (hl),a
   dec hl
   ld a,(hl)
   and d
   ld (hl),a
   pop bc
   inc hl
   inc hl
   push bc
   ld d,(ix)      ;sprite
   ld e,(ix+1)
   xor a
   cp b
   jp z,skipSpriteClip
   srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
skipSpriteClip:
   or (hl)
   ld (hl),a
   dec hl
   ld a,(hl)
   or e
   ld (hl),a
   dec hl
   ld a,(hl)
   or d
   ld (hl),a
   inc ix
   inc ix
   ld de,16
   add hl,de
   pop bc
   dec c
   jp nz, drawPlayerSpriteLoop
   ret


What we do is:
1. Find the location in the gbuf to draw the sprite.
2. Load the sprite mask into de and set a to $FF (a will hold the overflow)
3. Rotate the mask (de) to the right 0-7 times, depending on the location of the sprite. Rotate the carry into a.
4. AND the rotated mask with the gbuf, and save.
5. Repeat 2-4 with the sprite, only this time ORing (you could also XOR, it doesn't make a difference) it with the gbuf
6. Repeat for all 16 rows (or whatever number is in c).

EDIT: You'll also need to clear what you've drawn on the screen afterwards, you can do this a couple of ways. You can either save what's under the sprite you draw before you draw over it or have your tilemap routine update the whole gbuf every frame. I personally tend to do the second one (have my tilemap update the whole screen), as i think overall it's much easier than copying what's in the gbuf and restoring it. For the CSE i don't think you've really got much choice, though.
APotato wrote:
Ah I see Smile non-basic? Like using something like Grammar? Cool

Grammer does support XOR sprites.
tr1p1ea, Your explanation was perfectly what I was looking for! and, what I figured I would likely do, except I wasn't sure how I would do it.

Also, thanks to chickendude for the code - are those French comments in there? in regards to your EDIT, I likely would have to redraw the gbuf anyways, since the maps mostly will be plenty larger than the screen. however, what framerate can we achieve by redrawing the screen each and every time? and, that routine, what would have to change to draw my oddly sized sprites (32x32 AND 24x16 ones)?
Height would be simply altering C, but I couldn't find what controls sprite width.
Changing height is simple, you just do more repetitions with c, but adding support for wider sprites is more complicated. The part you'll want to look at is this:

Code:
   ld d,(ix+32)   ;sprite mask
   ld e,(ix+33)
   ld a,$ff
   dec b \ inc b \ jr z,skipMaskClip   ;si b=0
   scf \ rr d \ rr e \ rra \ djnz $-6   ;rotate mask
...and the similar section for the sprite (this is the mask part). The problem is, you're already low on variables, doing 24-width sprites isn't so bad (you can use c: ld c,(ix+(24*3)+2) then an "rr c" between the rr e and rra), but with 4-byte sprites you're really running out of registers. I'd suggest maybe using the shadows.

Depending on how efficient your tilemap routine is, you can get pretty decent framerate redrawing every frame. For example, the tilemapper i use in one of my projects takes up a lot of processor time (there are several layers to draw) but i think the framerate is still alright, even redrawing every frame:


(i'm in China and for some reason mirar.fr is blocked now, so i'm not sure if those are the right pictures, the project thread is here: http://www.yaronet.com/posts.php?sl=0&s=141295)

And yeah, sorry about the French comments, i tend to jump around between French/Spanish/English.

EDIT: If you want to have one routine to handle everything, similar to the ionLargeSprite routine, you could just base it off of the ion routine, but it's going to be much slower. I usually have a separate routine for every sprite width that i need.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement