### Author Topic: 16x12 sprite routine  (Read 4287 times)

0 Members and 1 Guest are viewing this topic.

#### squidgetx

• Food.
• CoT Emeritus
• LV10 31337 u53r (Next: 2000)
• Posts: 1881
• Rating: +503/-17
• rawr.
##### 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 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 codeDrawT(0,0,L6,Pic1)...Lbl DrawTr2*12+r1+r3+2->r3r1^8->r2r3->r1r4Asm(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 *Edited to make the bottom two code boxes show up* « Last Edit: October 23, 2012, 12:22:32 pm by squidgetx » #### chickendude • LV8 Addict (Next: 1000) • Posts: 817 • Rating: +90/-1 • Pro-Riot Squad ##### 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 at83A8 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) #### squidgetx • Food. • CoT Emeritus • LV10 31337 u53r (Next: 2000) • Posts: 1881 • Rating: +503/-17 • rawr. ##### 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 » #### calc84maniac • eZ80 Guru • Coder Of Tomorrow • LV11 Super Veteran (Next: 3000) • Posts: 2912 • Rating: +471/-17 ##### 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 #### squidgetx • Food. • CoT Emeritus • LV10 31337 u53r (Next: 2000) • Posts: 1881 • Rating: +503/-17 • rawr. ##### 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]->Pic1DrawT(0,0,L6,Pic1)DispGraphRepeat getKeyEndReturnLbl DrawT... #### calc84maniac • eZ80 Guru • Coder Of Tomorrow • LV11 Super Veteran (Next: 3000) • Posts: 2912 • Rating: +471/-17 ##### 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

#### chickendude

• LV8 Addict (Next: 1000)
• Posts: 817
• Rating: +90/-1
##### 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.

#### squidgetx

• Food.
• CoT Emeritus
• LV10 31337 u53r (Next: 2000)
• Posts: 1881
• Rating: +503/-17
• rawr.
##### 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 -> r3r1^8->r2r4Asm( 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 » #### calc84maniac • eZ80 Guru • Coder Of Tomorrow • LV11 Super Veteran (Next: 3000) • Posts: 2912 • Rating: +471/-17 ##### 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 #### chickendude • LV8 Addict (Next: 1000) • Posts: 817 • Rating: +90/-1 • Pro-Riot Squad ##### 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,0bossX = $+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égatifclipLeft =$+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 noWorkToDoxNotNegative: 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,aclipRight =$+1 jr $ld (spriteByte2),a ;SMC: change the ld (hl),a to a nop (HEX$00) ld (spriteByte3),a ; ld (spriteByte4),a ; pop afnoWorkToDo: 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_HdesBossBoucle: 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 spritespriteAligne: or (hl) ;HL = endroit dans gbufspriteByte4 =$ ld (hl),a ;charger a dec hl ld a,(hl) or cspriteByte3 = $ld (hl),a ;charger c dec hl ld a,(hl) or espriteByte2 =$ ld (hl),a ;charger e dec hl ld a,(hl) or dspriteByte1 = $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 retLDHLA =$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 subMapHLsubMapXHL: 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,hlendSubMap: pop de retThe 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 »

#### squidgetx

• Food.
• CoT Emeritus
• LV10 31337 u53r (Next: 2000)
• Posts: 1881
• Rating: +503/-17
• rawr.
##### 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