Rotating BIG sprites

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Rotating BIG sprites
by on (#165652)
My current sprite rotation engine fills up the RAM with rotation steps. Obviously this limits the size of the rotating sprites, so I'm thinking of an alternative for larger sprites.

My idea is to pre-rotate the sprite to only 16 angles (which doubles to 32 angles when flipped) and smoothing the rotation by doing something similar to offset-per-tile mode, only being applied to sprites, and being done through software. First it will shift columns of 8x8 cells vertically, then it will shift lines of pixels horizontally.
Re: Rotating BIG sprites
by on (#165656)
psycopathicteen wrote:
My idea is to pre-rotate the sprite to only 16 angles (which doubles to 32 angles when flipped) and smoothing the rotation by doing something similar to offset-per-tile mode, only being applied to sprites, and being done through software. First it will shift columns of 8x8 cells vertically, then it will shift lines of pixels horizontally.

So something like this sprite shearing technique?
Re: Rotating BIG sprites
by on (#165659)
tepples wrote:
psycopathicteen wrote:
My idea is to pre-rotate the sprite to only 16 angles (which doubles to 32 angles when flipped) and smoothing the rotation by doing something similar to offset-per-tile mode, only being applied to sprites, and being done through software. First it will shift columns of 8x8 cells vertically, then it will shift lines of pixels horizontally.

So something like this sprite shearing technique?


Pretty much, except the shearing would be done through software.

One thing I'd need to change about my engine is something I think Khan mentioned in a thread about animation. He once mentioned about using a bit to signal when an animation needs to be updated, as opposed to comparing numbers. Instead of having to compare 2 metasprite data address registers, 2 graphics address registers, and now a flag to mark if the graphics at that particular address happened to change, it makes sense to just have a flag that declares if the metasprite was changed in general.
Re: Rotating BIG sprites
by on (#169544)
I think I'll arrange the "unshifted" version of the sprites in a slightly different format. All 4 planar bytes would be stored together, and the 8x1 slivers would be stored from left to right, top to bottom. The sprites would be padded 4 lines of pixels on top and bottom with blank pixels in order to not have boundary crossing problems. So here is some code to copy a column of pixels.

Code:
-;
lda $0000,x
sta $0000,y
lda $0002,x
sta $0010,y

lda $0020,x
sta $0002,y
lda $0022,x
sta $0012,y

lda $0040,x
sta $0004,y
lda $0042,x
sta $0014,y

lda $0060,x
sta $0006,y
lda $0062,x
sta $0016,y

lda $0080,x
sta $0008,y
lda $0082,x
sta $0018,y

lda $00a0,x
sta $000a,y
lda $00a2,x
sta $001a,y

lda $00c0,x
sta $000c,y
lda $00c2,x
sta $001c,y

lda $00e0,x
sta $000e,y
lda $00e2,x
sta $001e,y

txa
clc
adc #$0100
tax
tya
clc
adc #$0100
tay
dec {temp}
bne -
Re: Rotating BIG sprites
by on (#169609)
Okay, now I have working code for tilting a 64x64 sprite.

Code:
big_sprite_rotation:
phb
lda #$7e7e
pha
plb
plb

ldy #$0000
sty {temp4}
sty {temp3}

lda #$0008
clc
adc {shift_factor}   //shift factor is between -8 and 7
asl #2
sta {temp2}


-;
and #$0038
asl #2
clc
adc {temp3}
tax
jsr copy_collumn
lda {temp4}
clc
adc #$0020
sta {temp4}
tay
lda {temp3}
clc
adc #$0004
sta {temp3}
cmp #$0020
beq +

lda {temp2}
sec
sbc {shift_factor}
sta {temp2}
bra -
+;



ldx #$0000
lda {shift_factor}
asl #5
sta {temp}
-;
lda {temp}
lsr #6
sep #$20
cmp #$00
beq ++
bpl +
jsr shift_pixels_left
bra ++
+;
jsr shift_pixels_right
+;
rep #$20
lda {temp}
sec
sbc {shift_factor}
sta {temp}
inx
inx
txa
and #$001f
cmp #$0010
bne -
txa
clc
adc #$00f0
tax
cpx #$0800
beq +
jmp -
+;

plb
rts







copy_collumn:
lda #$0008
sta {temp}
-;
lda {rotating_sprite}+$0000,x
sta {rotating_sprite_buffer}+$0000,y
lda {rotating_sprite}+$0002,x
sta {rotating_sprite_buffer}+$0010,y

lda {rotating_sprite}+$0020,x
sta {rotating_sprite_buffer}+$0002,y
lda {rotating_sprite}+$0022,x
sta {rotating_sprite_buffer}+$0012,y

lda {rotating_sprite}+$0040,x
sta {rotating_sprite_buffer}+$0004,y
lda {rotating_sprite}+$0042,x
sta {rotating_sprite_buffer}+$0014,y

lda {rotating_sprite}+$0060,x
sta {rotating_sprite_buffer}+$0006,y
lda {rotating_sprite}+$0062,x
sta {rotating_sprite_buffer}+$0016,y

lda {rotating_sprite}+$0080,x
sta {rotating_sprite_buffer}+$0008,y
lda {rotating_sprite}+$0082,x
sta {rotating_sprite_buffer}+$0018,y

lda {rotating_sprite}+$00a0,x
sta {rotating_sprite_buffer}+$000a,y
lda {rotating_sprite}+$00a2,x
sta {rotating_sprite_buffer}+$001a,y

lda {rotating_sprite}+$00c0,x
sta {rotating_sprite_buffer}+$000c,y
lda {rotating_sprite}+$00c2,x
sta {rotating_sprite_buffer}+$001c,y

lda {rotating_sprite}+$00e0,x
sta {rotating_sprite_buffer}+$000e,y
lda {rotating_sprite}+$00e2,x
sta {rotating_sprite_buffer}+$001e,y

txa
clc
adc #$0100
tax
tya
clc
adc #$0100
tay
dec {temp}
beq +
jmp -
+;
rts


shift_pixels_right:
-;
pha
lsr {rotating_sprite_buffer}+$0000,x
ror {rotating_sprite_buffer}+$0020,x
ror {rotating_sprite_buffer}+$0040,x
ror {rotating_sprite_buffer}+$0060,x
ror {rotating_sprite_buffer}+$0080,x
ror {rotating_sprite_buffer}+$00a0,x
ror {rotating_sprite_buffer}+$00c0,x
ror {rotating_sprite_buffer}+$00e0,x

lsr {rotating_sprite_buffer}+$0001,x
ror {rotating_sprite_buffer}+$0021,x
ror {rotating_sprite_buffer}+$0041,x
ror {rotating_sprite_buffer}+$0061,x
ror {rotating_sprite_buffer}+$0081,x
ror {rotating_sprite_buffer}+$00a1,x
ror {rotating_sprite_buffer}+$00c1,x
ror {rotating_sprite_buffer}+$00e1,x

lsr {rotating_sprite_buffer}+$0010,x
ror {rotating_sprite_buffer}+$0030,x
ror {rotating_sprite_buffer}+$0050,x
ror {rotating_sprite_buffer}+$0070,x
ror {rotating_sprite_buffer}+$0090,x
ror {rotating_sprite_buffer}+$00b0,x
ror {rotating_sprite_buffer}+$00d0,x
ror {rotating_sprite_buffer}+$00f0,x

lsr {rotating_sprite_buffer}+$0011,x
ror {rotating_sprite_buffer}+$0031,x
ror {rotating_sprite_buffer}+$0051,x
ror {rotating_sprite_buffer}+$0071,x
ror {rotating_sprite_buffer}+$0091,x
ror {rotating_sprite_buffer}+$00b1,x
ror {rotating_sprite_buffer}+$00d1,x
ror {rotating_sprite_buffer}+$00f1,x
pla
dec
beq +
jmp -
+;

rts


shift_pixels_left:
-;
pha

asl {rotating_sprite_buffer}+$00e0,x
rol {rotating_sprite_buffer}+$00c0,x
rol {rotating_sprite_buffer}+$00a0,x
rol {rotating_sprite_buffer}+$0080,x
rol {rotating_sprite_buffer}+$0060,x
rol {rotating_sprite_buffer}+$0040,x
rol {rotating_sprite_buffer}+$0020,x
rol {rotating_sprite_buffer}+$0000,x

asl {rotating_sprite_buffer}+$00e1,x
rol {rotating_sprite_buffer}+$00c1,x
rol {rotating_sprite_buffer}+$00a1,x
rol {rotating_sprite_buffer}+$0081,x
rol {rotating_sprite_buffer}+$0061,x
rol {rotating_sprite_buffer}+$0041,x
rol {rotating_sprite_buffer}+$0021,x
rol {rotating_sprite_buffer}+$0001,x

asl {rotating_sprite_buffer}+$00f0,x
rol {rotating_sprite_buffer}+$00d0,x
rol {rotating_sprite_buffer}+$00b0,x
rol {rotating_sprite_buffer}+$0090,x
rol {rotating_sprite_buffer}+$0070,x
rol {rotating_sprite_buffer}+$0050,x
rol {rotating_sprite_buffer}+$0030,x
rol {rotating_sprite_buffer}+$0010,x

asl {rotating_sprite_buffer}+$00f1,x
rol {rotating_sprite_buffer}+$00d1,x
rol {rotating_sprite_buffer}+$00b1,x
rol {rotating_sprite_buffer}+$0091,x
rol {rotating_sprite_buffer}+$0071,x
rol {rotating_sprite_buffer}+$0051,x
rol {rotating_sprite_buffer}+$0031,x
rol {rotating_sprite_buffer}+$0011,x

pla
inc
beq +
jmp -
+;

rts
Re: Rotating BIG sprites
by on (#169617)
Can you post a rom ? I'm curious about the result ... and the perfs ...
Re: Rotating BIG sprites
by on (#169714)
At 60fps it causes slowdown, but I can fix it by having it run outside the main routine. It's okay if it runs 30fps or 20fps, because even the non-realtime rotation sprites have variable framerates because of DMA limitations.
Re: Rotating BIG sprites
by on (#169917)
Really impressive psycopathicteen :)
Re: Rotating BIG sprites
by on (#194217)
I've been thinking today about this and I realized that if I scroll every 5 pixels instead of 8, I would only need 8 distinct rotation frames (16 including x/y flip) to make a full circle because arctan(1/5) = ~11.25 degrees.
Re: Rotating BIG sprites
by on (#194545)
I got a 64x64 sprite rotating 360 degrees, but it looks kind've crappy because I was in a rush.
Re: Rotating BIG sprites
by on (#194573)
Looking good.

EDIT: The rotations look a lot nicer on my CRT TV then on a SNES emulator. I can barely see the tearing on my PAL SNES+CRT TV.
Re: Rotating BIG sprites
by on (#194579)
UnDisbeliever wrote:
The rotations look a lot nicer on my CRT TV then on a SNES emulator.

EVERYTHING looks better on a CRT television than on an emulator. :wink:
Re: Rotating BIG sprites
by on (#194585)
I didn't think about this, but it would look better on a PAL TV set than an NTSC TV set, because you have 20% more CPU time.

Here is an improved version, that would look good even on NTSC.
Re: Rotating BIG sprites
by on (#194593)
UnDisbeliever wrote:
I can barely see the tearing on my PAL SNES+CRT TV.

"It looks a lot better after it's been blurred out." :lol:
Re: Rotating BIG sprites
by on (#194625)
It looks quite good, and I really like the green pumpkin spider. Very Wolfteam-like.

Music is strident, but slowly getting less abrasive....
Re: Rotating BIG sprites
by on (#194723)
Espozo wrote:
UnDisbeliever wrote:
I can barely see the tearing on my PAL SNES+CRT TV.

"It looks a lot better after it's been blurred out." :lol:


Three words: R, G and B.
Re: Rotating BIG sprites
by on (#194736)
RGB from SNES is kinda blurry, due to what seems like the DACs only being able to source current (transitions toward 5V are straight lines but towards GND they're gradual). 1chips apparently fix that. Still way less blurry than composhit, and no dot crawl artifacts lol
Re: Rotating BIG sprites
by on (#194807)
Today I wasted time trying to make a double buffering system that start the next rotation frame directly after it gets done with the previous frame if it takes more than a frame to draw.

My big mistake was using a double buffer instead of a triple buffer.
:roll:
Re: Rotating BIG sprites
by on (#195504)
Now that I got it running at practically 60 fps, I think I'll add scaling into the mix, but I have to rearrange the format again just to apply it.
Re: Rotating BIG sprites
by on (#196856)
Do you have a ROM demo of this ? :)
Re: Rotating BIG sprites
by on (#196865)
Yeah
Re: Rotating BIG sprites
by on (#196875)
Thanks, just tested :) Definitely impressive, i wonder if you will be able to get a full game from it at some point :)
Re: Rotating BIG sprites
by on (#196876)
Looks great on bsnes, but black screen on hardware (3 attempts) and ZSNES.
Re: Rotating BIG sprites
by on (#196878)
impressive, i think there is some hardware init problems, it works fine on snes9x, but the music works only after a reset .
If you let some foes coming to the most left side and kill them, there is no slow down even with sprite rotation.

@psycopathicteen: Do you rotate the entire sprite or only the alf and use mirroring for the other half ??
Re: Rotating BIG sprites
by on (#196883)
I rotate the entire sprite.

I do notice some framerate drop with the rotating sprite when I let enemies follow me back.