Author Topic: 16x12 sprite routine  (Read 4580 times)

0 Members and 1 Guest are viewing this topic.

Offline squidgetx

  • Food.
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1881
  • Rating: +503/-17
  • rawr.
    • View Profile
16x12 sprite routine
« on: October 21, 2012, 05:43:39 pm »
As the title says, I'm having trouble converting Chickendude's 16x16 (really 16xN) sprite routine so I can use it with Axe.
This is the basic code. First however, you'll need to calculate where to draw the sprite on screen and put that into hl, +2 bytes (since it draws from right to left, we start with the right side of the sprite and draw leftward). I'm not really sure how Axe handles inputs to routines, so if i got a little more information i could add that in for you too. The first line loads the x offset, that is, how many pixels away from 0 we are. If you are drawing at an aligned position (a multiple of 8) b will equal 0. If you are drawing at X=1, b = 1. If X=19, b=19%8=3. C should be how many rows you want to draw. Here it's 16 (10h). If you want 12, you would change 10h to 0Ch. And the address of the sprite should be in ix. I also wrote a quick small aligned 16x16 tilemapper, i'm not sure how you draw your tilemaps. None of this uses grayscale, however, so i don't know how useful it is to you. I'd be happy to help write something for you, though. So:
b = x offset (how many pixels away from being aligned the sprite is)
c = number of rows to draw, this could be changed easily to a variable height sprite routine.
ix = address of first byte in sprite
Code: [Select]
47 -  -  -  ld b,a
 0E 10 -  -  ld c,16
 -  -  -  - 
 -  -  -  -  drawPlayerLoop:
 C5 -  -  -  push bc
 DD 56 00 -  ld d,(ix)      ;sprite
 DD 5E 01 -  ld e,(ix+1)
 AF -  -  -  xor a
 B8 -  -  -  cp b
 CA 71 A0 -  jp z,skipSpriteClip
 CB 3A CB 1B F9 srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
 -  -  -  -  skipSpriteClip:
 B6 -  -  -  or (hl)
 77 -  -  -  ld (hl),a
 2B -  -  -  dec hl
 7E -  -  -  ld a,(hl)
 B3 -  -  -  or e
 77 -  -  -  ld (hl),a
 2B -  -  -  dec hl
 7E -  -  -  ld a,(hl)
 B2 -  -  -  or d
 77 -  -  -  ld (hl),a
 DD 23 -  -  inc ix
 DD 23 -  -  inc ix
 11 0E 00 -  ld de,14
 19 -  -  -  add hl,de
 C1 -  -  -  pop bc
 0D -  -  -  dec c
 C2 5E A0 -  jp nz, drawPlayerLoop
 C9 -  -  -  ret

EDIT: This routine will also slow down a little the further away from being aligned you go. We could unroll the shifting loops which, although taking up more space, would be slightly faster and have a more even runtime, or something like a 12x12 version of what i posted over here:
http://ourl.ca/15050 :)

I modified it slightly to draw 12 rows, and changed the jumps to relative jumps. Then I added a couple lines at the beginning so it could read in values passed to it in the r variables ($83A5).
Code: [Select]
.Axe code
DrawT(0,0,L6,Pic1)
...
Lbl DrawT
r2*12+r1+r3+2->r3
r1^8->r2
r3->r1
r4
Asm(stuff)
Code: [Select]
.Assembly stuff
 E5 DD E1 -   push hl / pop ix
 2A A7 83 -   ld hl, ($83A7)
 44 -  -  -   ld b, h
 2A A5 83 -   ld hl, ($83A5)
 0E 0C -  -   ld c,12
 -  -  -  - 
 -  -  -  -  drawPlayerLoop:
 C5 -  -  -   push bc
 DD 56 00 -   ld d,(ix)      ;sprite
 DD 5E 01 -   ld e,(ix+1)
 AF -  -  -   xor a
 B8 -  -  -   cp b
 28 03 -  -   jr z,$+7 (skipspriteclip)
 CB 3A CB 1B F9 srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
 -  -  -  -  skipSpriteClip:
 B6 -  -  -   or (hl)
 77 -  -  -   ld (hl),a
 2B -  -  -   dec hl
 7E -  -  -   ld a,(hl)
 B3 -  -  -   or e
 77 -  -  -   ld (hl),a
 2B -  -  -   dec hl
 7E -  -  -   ld a,(hl)
 B2 -  -  -   or d
 77 -  -  -   ld (hl),a
 DD 23 -  -   inc ix
 DD 23 -  -   inc ix
 11 0E 00 -   ld de,14
 19 -  -  -   add hl,de
 C1 -  -  -   pop bc
 0D -  -  -   dec c
 20 E7 -  -  jp nz, $-23 (drawPlayerLoop)
 C9 -  -  -   ret

Right now, it just crashes on run. I'd be super grateful if anyone could help ;D

*Edited to make the bottom two code boxes show up*
« Last Edit: October 23, 2012, 12:22:32 pm by squidgetx »

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: 16x12 sprite routine
« Reply #1 on: October 22, 2012, 09:43:21 am »
I'm not sure how you are using that routine, that routine requires the position in the gbuf to be set already. The other routine i posted will calculate the x/y position in the gbuf for you. In that routine, b isn't the x coordinate on screen, it's the x offset, essentially how many pixels from 8 (being byte-aligned) it is. So if X = 32, 32 AND 7: b=0. If X = 35, 35 AND 7: b=3.

I'm not sure what you're trying to put into b, but if you are putting 'h' into 'b', you're putting the byte at $83A8 into b. 'l' holds the byte at $83A7. But anyway, i think you're passing the wrong parameter. The other code i posted should calculate the position in the gbuf for you with an X/Y coordinate (in pixels) :)

Offline squidgetx

  • Food.
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1881
  • Rating: +503/-17
  • rawr.
    • View Profile
Re: 16x12 sprite routine
« Reply #2 on: October 22, 2012, 12:41:29 pm »
Well I guess I should explain what the code is (supposed) to do (btw, changing it to ld b,l makes it crash anyway).

I calculate the position in the gbuf with the first axe line: r2*12+r1+r3+2, where r2 is the Y value, r1 is the X value, and r3 is the buffer to be drawn to. I store this value to r3. Then I take r1 mod 8 (the offset) and store that into r2 ($83A7). Then I take r3 (the gbuf) and put it into r1 ($83A5). Finally, I call r4 (the sprite pointer) and put it into hl.

That's the axe "prep." So I have all the pieces the routine needs; the position to draw to (in $83A5), the offset (in $83A7), and the sprite pointer (in hl). I just need to move them to hl, b, and ix respectively.
So what follows is 5 lines of asm before the original routie, push hl / pop ix to get the sprite pointer to ix, ld hl ($83A7) / ld b, l to get the offset into b, and ld hl ($83A5) to get the draw position into hl
« Last Edit: October 22, 2012, 12:42:29 pm by squidgetx »

Offline calc84maniac

  • eZ80 Guru
  • Coder Of Tomorrow
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2912
  • Rating: +471/-17
    • View Profile
    • TI-Boy CE
Re: 16x12 sprite routine
« Reply #3 on: October 22, 2012, 01:07:57 pm »
The calculation for the position in the buffer needs to be r2*12+(r1/2/2/2)+r3+2, because the X offset in the buffer increases for every 8 pixels, not every pixel.
"Most people ask, 'What does a thing do?' Hackers ask, 'What can I make it do?'" - Pablos Holman

Offline squidgetx

  • Food.
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1881
  • Rating: +503/-17
  • rawr.
    • View Profile
Re: 16x12 sprite routine
« Reply #4 on: October 22, 2012, 01:18:26 pm »
Thanks, MGOS also pointed this out to me. I'm testing with coordinates 0,0 though, and it still doesn't work =/

Code: [Select]
.TEST
[hex]->Pic1
DrawT(0,0,L6,Pic1)
DispGraph
Repeat getKey
End
Return
Lbl DrawT
...

Offline calc84maniac

  • eZ80 Guru
  • Coder Of Tomorrow
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2912
  • Rating: +471/-17
    • View Profile
    • TI-Boy CE
Re: 16x12 sprite routine
« Reply #5 on: October 22, 2012, 02:53:01 pm »
Code: [Select]
28 03 -  -   jr z,$+7 (skipspriteclip)
 CB 3A CB 1B F9 srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
 -  -  -  -  skipSpriteClip:
I think that 28 03 should be 28 07 if you really want to skip 7 bytes. (Also technically the code should be jr z,$+9)

Edit:
And that second line should be CB 3A CB 1B 1F 10 F9
« Last Edit: October 22, 2012, 02:54:10 pm by calc84maniac »
"Most people ask, 'What does a thing do?' Hackers ask, 'What can I make it do?'" - Pablos Holman

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: 16x12 sprite routine
« Reply #6 on: October 23, 2012, 05:35:13 am »
Or just use "jr z,skipSpriteClip", but yeah if you're typing it out by hand it should be 28 07 (28 00 jumps to the next instruction). And about the missing $1F and $10, i must've accidentally cut them off when copying/pasting it, sorry about that. The hex codes spanned two lines and i moved them all onto one line.

Offline squidgetx

  • Food.
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1881
  • Rating: +503/-17
  • rawr.
    • View Profile
Re: 16x12 sprite routine
« Reply #7 on: October 23, 2012, 12:25:13 pm »
Ergh, still not working... Does anyone know a good utility to convert whole asm programs to hex, or should I just grab a hex editor or something?

I changed that missing-2-byte line and adjusted the two relative jumps accordingly:

EDIT: Just realized a pretty major bug, that register a is never intialized properly
EDIT2: Runer just pointed out that this routine doesn't clip...uh oh :(

 
Code: [Select]
Sprite(X,Y,Buff,Pointer)

r2*12+(r1/8)+r3+2 -> r3
r1^8->r2
r4

Asm(

 E5 DD E1 -   push hl \ pop ix
 2A A7 83 -   ld hl, ($83A7)
 45 -  -  -   ld b, l
 2A A9 83 -   ld hl, ($83A9)
 0E 0C -  -   ld c,12
 -  -  -  - 
 -  -  -  -  drawPlayerLoop:
 C5 -  -  -   push bc
 DD 56 00 -   ld d,(ix)      ;sprite
 DD 5E 01 -   ld e,(ix+1)
 AF -  -  -   xor a
 B8 -  -  -   cp b
 28 07 -  -   jr z,$+9 (skipspriteclip)
 CB 3A CB 1B
 1F 10 F9 -   srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
 -  -  -  -  skipSpriteClip:
 B6 -  -  -   or (hl)
 77 -  -  -   ld (hl),a
 2B -  -  -   dec hl
 7E -  -  -   ld a,(hl)
 B3 -  -  -   or e
 77 -  -  -   ld (hl),a
 2B -  -  -   dec hl
 7E -  -  -   ld a,(hl)
 B2 -  -  -   or d
 77 -  -  -   ld (hl),a
 DD 23 -  -   inc ix
 DD 23 -  -   inc ix
 11 0E 00 -   ld de,14
 19 -  -  -   add hl,de
 C1 -  -  -   pop bc
 0D -  -  -   dec c
 20 E4 -  -   jr nz, $-26 38d (drawPlayerLoop)
 C9 -  -  -   ret
« Last Edit: October 23, 2012, 12:35:13 pm by squidgetx »

Offline calc84maniac

  • eZ80 Guru
  • Coder Of Tomorrow
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2912
  • Rating: +471/-17
    • View Profile
    • TI-Boy CE
Re: 16x12 sprite routine
« Reply #8 on: October 23, 2012, 12:36:06 pm »
I recounted the bytes in the main drawing loop and I think the final jr nz should be 20 D8.
"Most people ask, 'What does a thing do?' Hackers ask, 'What can I make it do?'" - Pablos Holman

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: 16x12 sprite routine
« Reply #9 on: October 23, 2012, 02:57:03 pm »
Do you need it to clip? I can post the clipped sprite routine i've got though it's much more dependent on SMC (and much larger). It's also probably not very optimized.
To give you an idea, this is what it looks like (this is for a 24x24 sprite):
Code: [Select]
bossY = $+1
ld hl,TERRE_Y*256 ;la coordonnée y du boss
call subMapYHL ;hl (bossY) - map Y
ret c ;si le carry est armé, le boss est hors de l'écran
ld a,h
cp 64 ;plus de 8 et le boss est hors d'écran
ret nc
ld e,a ;sauver coordonnée Y
ld b,0
bossX = $+1
ld hl,$0400
ld a,l
rlca
rlca
rlca
and $7 ;a = xOff
ld c,a ;sauver xOff dans c
ld a,h
ld hl,xCoord
sub (hl) ;bossX-mapX
jr nc,xNotNegative
;pour une explication, voir dessous
ld d,a ;sauver a dans d. a = combien d'octets (pas de pixels!) on est de le bout gauche de l'écran
add a,BOSS_W
ret m ; ... le sprite est hors d'écran
ld b,a ;
add a,a ;*2
add a,b ;*3 (parce que chaque ld (xxx),a occupe trois octets)
ld (clipLeft),a ;SMC: changer où va sauter le jr
xor a ;valeur qui va remplacer spriteByteX
ld b,$FF ;plus tard nous chargeons b dans d. $FF est parce que c'est un numéro (16bit) négatif
clipLeft = $+1
jr $ ;avec du SMC on va sauter
ld (spriteByte3),a ;SMC: change the ld (hl),a to a nop (HEX $00)
ld (spriteByte2),a ;
ld (spriteByte1),a ;
ld a,d
ld d,0
jr noWorkToDo
xNotNegative:
cp 13 ;s'il est complètement hors d'écran, quitter
ret nc
cp 10 ;s'il est partiellement hors d'écran, clipper
jr c,noWorkToDo
push af
;###########################
;# je vais expliquer cette partie-ci parce qu'elle m'a vraiment frustré
;#  cette partie s'occupe du "clippage" des sprites hors d'écran
;#  si le sprite va s'afficher dans la 11ème colonne (ou la 10ème commençant de zéro)
;#  une partie va être hors d'écran. il faut la clipper.
;# si le sprite s'affiche dans la 10ème colonne, il y a un octet qui ne s'affichera pas
;#  la 11ème, il y'en aura 2, et la 12ème, 3.
;# regarder la liste au-dessous du "jr $". si nous voulons effacer le dernier octet du sprite
;#  il nous faut sauter "ld (spriteByte2),a" et "ld (spriteByte3),a". donc, on nécessite savoir 12-a
;#  puis, nous multiplions ça par 3 (chaque instruction occupe 3 octets) et changer où "jr" va sauter.
ld b,a
ld a,12
sub b ;essentiellement, a=12-a
ld b,a
add a,a
add a,b ;a*3 (parce que chaque ld (xxx),a occupe trois octets)
ld (clipRight),a ;SMC: changer le jr
xor a ;valeur qui va remplacer spriteByteX
ld b,a
clipRight = $+1
jr $
ld (spriteByte2),a ;SMC: change the ld (hl),a to a nop (HEX $00)
ld (spriteByte3),a ;
ld (spriteByte4),a ;
pop af
noWorkToDo:
ld d,0
ld l,e
ld h,d
add hl,hl ;y*2
add hl,de ;y*3
add hl,hl ;y*6
add hl,hl ;y*12
add hl,de ;y*13
ld de,megaGbuf+BOSS_W ;86EC+2 (nous dessinons de droite à gauche, les sprites des boss occupent 2 octets, 16 pixels)
add hl,de
ld e,a
ld d,b
add hl,de
ld a,c
ld b,a
ld c,BOSS_H
desBossBoucle:
push bc
ld d,(ix)      ;sprite
ld e,(ix+1)
ld c,(ix+2)
xor a
cp b ;si b = 0
jp z,spriteAligne
srl d \ rr e \ rr c \ rra \ djnz $-7   ;rotate sprite
spriteAligne:
or (hl) ;HL = endroit dans gbuf
spriteByte4 = $
ld (hl),a ;charger a
dec hl
ld a,(hl)
or c
spriteByte3 = $
ld (hl),a ;charger c
dec hl
ld a,(hl)
or e
spriteByte2 = $
ld (hl),a ;charger e
dec hl
ld a,(hl)
or d
spriteByte1 = $
ld (hl),a ;charger d
inc ix
inc ix
inc ix
ld de,13+BOSS_W
add hl,de
pop bc
dec c
jp nz,desBossBoucle
ld a,LDHLA
ld (spriteByte4),a
ld (spriteByte3),a
ld (spriteByte2),a
ld (spriteByte1),a
ret

LDHLA = $77 ;$77 est le "opcode" de "ld (hl),a"
And this is subMapYHL/XHL, which is used all over the place:
Code: [Select]
subMapYHL:
ld a,(yCoord)
jr subMapHL
subMapXHL:
ld a,(xCoord)
subMapHL:
push de
ld d,a
ld e,0
or a
sbc hl,de
jr c,endSubMap
add hl,hl
add hl,hl
add hl,hl
endSubMap:
pop de
ret
The comments are all in (really bad) French, sorry. It'd be slightly smaller but that's what you'd be dealing with for a clipped routine (at least from me ;)). It might be easier just to give you my entire tilemapper.
« Last Edit: October 23, 2012, 03:00:26 pm by chickendude »

Offline squidgetx

  • Food.
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1881
  • Rating: +503/-17
  • rawr.
    • View Profile
Re: 16x12 sprite routine
« Reply #10 on: October 23, 2012, 04:34:33 pm »
Hm, I'll start off with a pure Axe approach of using 4 8x8 routines, and see whether I need the speed bump. Thanks for offering, though :)