[TI-ASM] Sprite Clipping Routine

Got questions? Got answers? Go here for both.

Moderator: MaxCoderz Staff

Post Reply
User avatar
crzyrbl
Calc Wizard
Posts: 518
Joined: Wed 06 Jul, 2005 4:56 pm
Location: 3rd rock....

[TI-ASM] Sprite Clipping Routine

Post by crzyrbl »

This is my first time posting a routine, so, whooO! It was quite a bit a trouble for a newcomer, and I probably should have worked on it last, but I was just too bugged about not being able to move off-screen. Also, I think it's ridiculous that ion, supposidly made for n00bs like me did not come with a sprite routine with clipping! I used the original non-clipping routine as a base, since its optimized and I'll end up giving credit to ion anyways. My routine is compatible with ionPutSprite so there is no need to change massive amounts of code, just the call xxxx. Right now I'm just looking for a few optimizations. Once I learn self-modifying code, I plan to re-write this a different way. Without futher ado....

Code: Select all

horizClip:
	sub 8
	jr nc, horizClip2	;if part of the ship is on the right of the screen
	ld d, c		;don't jump, use the mask to disable E
Eloop:
	sla e		;push a 0 into the rightmost part of the mask
	dec d		;eliminating that part of the sprite cuz its off-screen
	jr nz, Eloop
	jr retmask

horizClip2:
	sub 151
	jr nc, horizClip3	;if its not in any part of the screen, dont
	ret		;bother showing anything, return!
horizClip3:
	ld a, 8	;ship must be on the left, use the mask to disable D
	sub c
Dloop:
	srl e	;push a 0 into the leftmost part of the mask to clip the sprite
	dec a
	jr nz, Dloop
	ld a, l
	sub 32		;subtract 32 to move sprite from the right to the left
	ld l, a
	jr nc, retmask
	dec h		;dont forget to CARRY the one!
	jr retmask

putSpritePlus:
	ld h, a

vertClip:
	ld a, l		;load y co. into a
	cp 100
	jr c, vertClip2	;while the spite is too high
	inc ix		;go to the next part of the pic since
	inc l		;this one wont be used and go down one
	djnz vertClip	;also subtract one from the height
	ret		;if new height is 0, nothing to print, return

vertClip2:
	add a, b		;y co. + height is the bottom of the sprite
	sub 64
	jr c, vertExit	;while the sprite is too low
	ld a, l		
	djnz vertClip2	;subtract 1 from the height
	ret		;if new height is 0, nothing to print, return

vertExit:
	ld a, h
	push hl		;save the x, y co.'s
	ld    e,l
	ld    h,$00	;now we must go to the correct spot in memory
	ld    d,h		;aka, gbuf to output the sprite
	add    hl,de	;gbuf + (int)(x/8) + y * 12 = answer
	add    hl,de	
	add    hl,hl
	add    hl,hl	;put Y co. * 12 into hl
	ld    e,a
	and    $07	;mod 8 to find the bit offset
	ld    c,a
	srl    e
	srl    e
	srl    e		; equals (int)( x co./ 8 )
	add    hl,de	;adds the x displacement to the y displacement
	ld    de,gbuf
	add    hl,de	;finally add the gbuf to get the correct index!
	pop de		;restore x co. to d, now to make the mask for horiz clipping
	ld e, %11111111	;start with a blank mask (we will and it later on)
	ld a, d
	sub 89
	jr nc, horizClip	;if the sprite is not on the screen, clip it horizontally (using mask)
retmask:	ld a, e
	ld (mask), a	;store the mask

putSpriteLoop1:
	ld a, (mask)
	ld d, a
	ld    a,(ix)		;load part of image into a
	and d		;mask image!
	ld d, a

	ld    e,$00	;de together are the 8-bit image
	ld    a,c
	or    a
	jr    z,putSpriteSkip1
putSpriteLoop2:
	srl    d		;move a bit from d to e
	rr    e
	dec    a		;based on the bit offset (c) times
	jr    nz,putSpriteLoop2
putSpriteSkip1:
	ld    a,(hl)
	xor    d		;xor d part of image & save
	ld    (hl),a
	inc    hl
	ld    a,(hl)
	xor    e		;xor e part of image & save
	ld    (hl),a
	ld    de,$0B
	add    hl,de	;move pointer to the next line
	inc    ix
	djnz    putSpriteLoop1 
	ret
Yes, I know there are more comments than grains of sand, I'm showing this to a friend later so I needed them.
(\__/)
(='.'=)This is Bunny. Copy and paste bunny into your
(")_(")signature to help him gain world domination.

Image
User avatar
crzyrbl
Calc Wizard
Posts: 518
Joined: Wed 06 Jul, 2005 4:56 pm
Location: 3rd rock....

Post by crzyrbl »

uh, so are there any obvious optimizations?
(\__/)
(='.'=)This is Bunny. Copy and paste bunny into your
(")_(")signature to help him gain world domination.

Image
Tyler
New Member
Posts: 7
Joined: Wed 13 Jun, 2007 11:22 pm

Post by Tyler »

I'm rather new to assembly, and I can't spot much. What I have learned is that the best way to optimize something is to completely rewrite it, in most cases...

At the very end of your code, since you're loading 11 ($000B) into DE to advance a row for each line of sprite, you know that D has to be zero when the loop comes around again. So instead of loading $00 into E the next loop around, perform a (ld e, d) operation before you start messing around with D. You might also have to load D to zero before the whole loop begins, just for the first time around. Saves only three clocks or so per loop, which totals to about twenty some-odd clocks altogether... it's not much, but it's something.
User avatar
crzyrbl
Calc Wizard
Posts: 518
Joined: Wed 06 Jul, 2005 4:56 pm
Location: 3rd rock....

Post by crzyrbl »

wait, so is (ld e, d) 3 clocks less than (ld e, $00) ??
wow, that's so weird.
and that part is straight from ionPutSprite!

(I'm new at asm as well :D )
(\__/)
(='.'=)This is Bunny. Copy and paste bunny into your
(")_(")signature to help him gain world domination.

Image
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

LD E,D is a register load, it only has to read itself (the instruction) from RAM, LD E,$00 is a constant-load, which is from RAM (the byte after the instruction) so that adds 3 cc's ram-fetch. Yes it is pretty crazy that a RAM-fetch takes 3/4 or more of the total execution time.. That's probably due to the lack of parallelism (and caching) in this very old processor.
Liazon
Calc Guru
Posts: 962
Joined: Thu 27 Oct, 2005 8:28 pm

Post by Liazon »

you mean a ram fetch takes less time in an x86?

sorry i can't type much, but i should probably point out that you don't need to pre-mask you're sprite (at least that's what i think you're doing). i saw a good clipping one once, and it simply changes the height and start pt of the sprite for vertical clip and simply ignores the left or right putsprite byte depending on which side of the screen it's on.

maybe king harold can explain cuz i can't type XP
Image Image Image
User avatar
Jim e
Calc King
Posts: 2457
Joined: Sun 26 Dec, 2004 5:27 am
Location: SXIOPO = Infinite lives for both players
Contact:

Post by Jim e »

Liazon wrote:you mean a ram fetch takes less time in an x86?
Less time kinda depends on a lot of things. But bascially the quickiest instruction on the z80 takes 4 tstates, the quickest on the x86 takes 1 tstates. Most modern CPUs perform better in that sense.

For the z80 you can typically count tstates by the type of read and write. Opcode Reads take 4 tstates, non-opcode reads take 3 tstates, and writes take 3 tstates.

Theres also added tstates for certain types of work. Like relative adds to 16bit addresses take 5 tstates. All the instructions timings make a lot of sense when you stare at them long enough.
Image
User avatar
crzyrbl
Calc Wizard
Posts: 518
Joined: Wed 06 Jul, 2005 4:56 pm
Location: 3rd rock....

Post by crzyrbl »

@Liazon: That is what I'm doing for the vertical clipping. I planned to do the horizontal clipping like that once I learn self-modifying code.
(\__/)
(='.'=)This is Bunny. Copy and paste bunny into your
(")_(")signature to help him gain world domination.

Image
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

You do not need SMC for it, and I would stay far away from SMC unless you're absolutely confident about your asm skills.. It's very hard to trace bugs in SMC when it gets complicated. I know all those asm masters out there use it all the time, but as soon as you use it for something else than changing not-so-constant bytes (say, the offset at an index register operation) it can get quite nasty. Well not if it works, but if it doesn't you'll most likely need quite some debugging to find out why.

You only need to skip the blitting of the byte that would be part of the sprite but fell off the edge to the next or previous row anyway. So after the shifting, how about a compare of sorts to find out whether all parts of the sprite are still on the same line? When they're not, it is either because the sprite fell off left, or it fell off the right.
User avatar
driesguldolf
Extreme Poster
Posts: 395
Joined: Thu 17 May, 2007 4:49 pm
Location: $4080
Contact:

Post by driesguldolf »

Dunno if this could help, but sigma has written beautiful clipping sprite routines (non masked and masked), I think the masked one ROCKS, the way he uses the stackpointer... amazing :worship:
http://www.ticalc.org/archives/files/fi ... 27484.html
These are actually beautiful, and im blessed by understading them (gonna base my ultra fast tilemapping on them)

debug hint: try stepping trough all the instructions with an emu, its slow but if there is an error you'll always find it (even with smc).
User avatar
driesguldolf
Extreme Poster
Posts: 395
Joined: Thu 17 May, 2007 4:49 pm
Location: $4080
Contact:

Post by driesguldolf »

about some optimizations:

Code: Select all

horizClip2:
   sub 151
   jr nc, horizClip3   ;if its not in any part of the screen, dont
   ret      ;bother showing anything, return!
horizClip3:
How about this:

Code: Select all

horizClip2:
   sub 151
   ret c
horizClip3:
Last edited by driesguldolf on Wed 20 Jun, 2007 10:37 pm, edited 1 time in total.
User avatar
crzyrbl
Calc Wizard
Posts: 518
Joined: Wed 06 Jul, 2005 4:56 pm
Location: 3rd rock....

Post by crzyrbl »

gah, I shoulda got that one! nice catch
(\__/)
(='.'=)This is Bunny. Copy and paste bunny into your
(")_(")signature to help him gain world domination.

Image
User avatar
driesguldolf
Extreme Poster
Posts: 395
Joined: Thu 17 May, 2007 4:49 pm
Location: $4080
Contact:

Post by driesguldolf »

No problemo, but the rest is just a little bit too complicated (for a first look)
Dont know if you're doing this but...:

Code: Select all

sdr_noclip:
 get_address:
  addr = gbuf + ypos * 12 + xpos / 8
 draw:
  do nr_of_rows times:
   s = get next byte from image
   l = s >> ((8 - xpos) % 8)
   r = s << (xpos % 8)
   write left and right parts in the buffer
   addr = addr + 11
for clipping just preprocess the inputs

Code: Select all

sdr_clip:
 if ypos >= -7 and ypos < 0 then
  img_ptr = img_ptr - ypos     ;remeber the ypos is negative
  nr_of_rows = 8 + ypos
 if ypos < 64 and ypos >= 64 - nr_of_rows
  nr_of_rows = 64 - ypos

 if xpos >= -7 and xpos < 0
  erase the part where the left part is written to the buffer
 if xpos < 96 and xpos >= 96 - 8
  erase the part where the right part is written to the buffer

 get_address:
  addr = gbuf + ypos * 12 + xpos / 8
 draw:
  do nr_of_rows times:
  s = get next byte from image
  l = s >> ((8 - xpos) % 8)
  r = s << (xpos % 8)
  write left and right parts in the buffer
  addr = addr + 11
It's pretty much the way sigma does this, and ok it should be very easy to add full offscreen clipping

I hope this can help, plz don't kill me if you already do this or something, just trying to help

EDIT: % means modulo
ANOTHER EDIT: don't forget to rewrite the instructions in case of clipping
Liazon
Calc Guru
Posts: 962
Joined: Thu 27 Oct, 2005 8:28 pm

Post by Liazon »

King Harold wrote:You only need to skip the blitting of the byte that would be part of the sprite but fell off the edge to the next or previous row anyway. So after the shifting, how about a compare of sorts to find out whether all parts of the sprite are still on the same line? When they're not, it is either because the sprite fell off left, or it fell off the right.
like he said.

basically, iirc, putsprite was designed to split the sprite into two sprites through rotations and write two aligned sprites to the screen. just find a way to tell it to skip the writing of one side or another because the clip part you see is only one of the two aligned sprites.
Image Image Image
Post Reply