Sorry for yet another dumb question, but I was wondering if it were possible to scale sprites without the need of an expansion chip. I know that the Super FX chip was only a cpu and not a graphics processor, but was able to pull of impressive sprite scaling techniques in games such as in Yoshi's Island. Because of this, It seems possible to use the same sprite scaling algorithm used in the Super FX chip and use it on the SNES, even if it would take a huge chunk of processing time.
With memory being cheap as it is, I would consider pre-rendering the sprites whenever possible. Though if you need both scaling and rotation at the same time, you could probably pre-render the rotation and do the scaling in in real-time (or some similar combination), if that helps.
Thank you, and as you said, I would like to be able to have sprites that would be rotated and scaled. Do you know what equation the Super FX chip uses for sprite scaling? Sorry for all these questions, it is just that I really don't know much about programing.
Rotation and scaling are an affine transformation. Do a web search for linear algebra, affine transformation, and texture mapping.
In the case of an SNES without expansion chips, wouldn't it make more sense to use a set o look-up tables than to perform the actual calculations in real-time?
What would be interesting to see attempted is it to be done on the PIC and then pixels written to the output. It's basically how the SFX chip works, but shove a 40Mhz PIC in there, and have it do it just off of the data base and sprites/object inside the PIC.
I've always thought it would be possible to do scaling as a series of shifting, with a different routine for each step.
Wolfenstein 3D exists. Therefore yes.
Yeah, look-up tables would be better than calculating. There's plenty of memory for it. If I'm thinking right, a 32x32 tile with 64 angle LUT would be 128kB (if byte-aligned). 32 * 32 * 64 * 2 (x/y position). That's not big at all.
3gengames wrote:
What would be interesting to see attempted is it to be done on the PIC and then pixels written to the output. It's basically how the SFX chip works, but shove a 40Mhz PIC in there, and have it do it just off of the data base and sprites/object inside the PIC.
That would be interesting. That's one of the things I had wanted to try on NES with the PIC18 on the old Squeedo board, stuff like matrix multiplication, but the big limitation was the latency - NES had to wait between port accesses, or use interrupts and have overhead for every single byte transferred. More modern ones like PIC24 and PIC32 have a 4-byte FIFO, but even better - a DMA channel. I had wondered about that recently too, if the PIC parallel port with DMA is fast enough for the SNES to DMA transfer from it. Maybe. Even just loading out with LDA would be really practical though.
If you're just talking about scaling (not rotation) then it's pretty basic.
Lets say we have one horizontal line of an object of 8 pixel coordinates... 01234567
well, what would doubling twice as wide look like? 0011223344556677
what would half as wide look like? 0246
what would 1.5x as wide look like (cheaply)? 001223445667
Either it's new or not to you, but you can treat binary numbers as having a decimal point wherever you feel like.
It's called fixed-point math.
Let's say I just pick two bytes, one byte "A" represents the whole number (0..1.. up to 255) and the other byte "B" represents the fraction (0/256th, 1/256th up to 255/256th). A is 8 bits, B is 8 bits, therefore A.B is an 8.8 fixed point number.
if I set "A" to 1, and "B" to 0, I have the value 1.
if I set "A" to 0, and "B" to 64, I have the value 0 + (64/256), or just simply .25 decimal
if I set "A" to 1, and "B" to 128, I have the value 1.5 (1 + 128/256)
So when I step across horizontally starting at 0, I can just keep doing one addition, then use the whole number portion to look up what pixel number to copy over, and either terminate the loop when the whole number reaches the width of the source, or I did the multiplication ahead of time and know how many times to step... either way.
The scale factor, and this step amount are inverse (1/x), as in if the step amount is .25, it's going to be 4x wide under this scheme.
Using the example from above, adding the "0.25" every time... (0 whole + 64 / 256th)
[0 + 0/256] = pixel coordinate 0
[0 + 64/256] = pixel coordinate 0
[0 + 128/256] = pixel coordinate 0
[0 + 192/256] = pixel coordinate 0
[1 + 0/256] = pixel coordinate 1, (192+64 = 256 = generated a carry, which was added to the while number portion)
[1 + 64/256] = pixel coordinate 1
[1 + 128/256] = pixel coordinate 1
[1 + 192/256] = pixel coordinate 1
[2 + 0/256] = pixel coordinate 2
...
etc.
Now if you treat this the same in the vertical direction (work left to right each row from top to bottom), now you have a coordinate pair that points to the x and y of the source bitmap.
Further,
If you don't like scaling to start at the top-left corner, and want to make it look like it expands from the middle, count from negative to positive like this: (-4, -3, -2, -1, 0, 1, 2, 3). Scaling always expands outward from the origin (0,0)
Further,
2D Rotation around the origin (0,0) is a matrix operation, simplified:
rotated X := x * cos(A) - y * sin(A)
rotated Y := x * sin(A) + y * cos(A)
For speed, this again could be decomposed into fixed point arithmetic, this time adding both an X and a Y step amount every time, as you work from left to right each row, top to bottom.
tepples wrote:
Wolfenstein 3D exists. Therefore yes.
psycopathicteen wrote:
Toy Story exists.
As long as we're playing this game: Jurassic Park exists.
Although I feel like saying that the math behind raycasters is somewhat different from typical sprite scaling and rotation. Scaling might be similar, but the only kind of rotation found in these raycasters is that of the level map, and that's almost nothing like plotting rotated pixels.
This is reminding me of the Neo-Geo's table of sprite shrinking lines. It stores which lines to drop out of an image, which could be done on the SNES / Genesis as a raster effect.
Can Super NES OAM even be written during hblank? I know it can on GBA, but GBA has its sprite scaling and rotation in hardware.
tepples wrote:
Can Super NES OAM even be written during hblank? I know it can on GBA, but GBA has its sprite scaling and rotation in hardware.
Probably -- and could probably be combined with HDMA to do tweaky effects on sprites on a per-scanline basis (e.g. make a sprite wobbly/wavy in a sinus-like manner).
Since the SNES uses planar mode, you can use the bytes that make up the sprite pattern as indexes to a LUT.
koitsu wrote:
tepples wrote:
Can Super NES OAM even be written during hblank? I know it can on GBA, but GBA has its sprite scaling and rotation in hardware.
Probably -- and could probably be combined with HDMA to do tweaky effects on sprites on a per-scanline basis (e.g. make a sprite wobbly/wavy in a sinus-like manner).
I really doubt there's enough time to write a significant amount of sprites during hblank.
And even then, isn't it very likely that during hblank the SPPU is way too busy fetching sprite data in order to later render it in that scanline? Which would mean that OAM is completely out of reach during hblank as well (as you'd interfere with that process).
http://problemkaputt.de/fullsnes.htm#sn ... ryaccessesIt seems no one is sure. A few years ago
psycopathicteen had this idea, figuring that you could clone sprites by rewriting their locations during HBlank and get up to 900 of them on screen. All we found out was that the Mega Drive could
kinda do it...
Part of the problem is that the OAM address is scrambled during active display and doesn't reset until VBlank or FBlank. Uniracers writes to OAM during HBlank, but as far as I know no one knows exactly what it accomplishes thereby; once the caching for the next scanline is done, the address ends up in the high OAM region and you can't rewrite it (I'm not sure if it ignores writes or if they have unexpected behaviour).
I was considering trying this for my bullet hell port, but there were too many issues, even assuming it was going to work at all...
...
Is it fair to assume that you can't try writing during a scanline, using timed code to target a specific access by the PPU and sneaking in a write to the last-read location before the next read? I don't know if the OAM is wired to allow that, but people seem to be assuming it's not... but if it's not, how was the PPU access timing determined?
Well yeah, the Mega Drive can do it perfectly actually, the only issue is that bandwidth is heavily limited during active scan, there's barely enough to overwrite two sprites per scanline (and one sprite alone will fill up the FIFO, so the CPU will get frozen), unless you start exploiting quirks about how the sprite cache works and such. (to be fair, 528 sprites on screen doesn't sound bad...)
However, take into account that the only reason it works on the Mega Drive at all in the first place is because the VDP explicitly allows you to keep writing to video memory during active scan (albeit in limited capacity). The SPPU in the SNES doesn't, and that basically makes this idea pretty much impossible to implement.
Or to put it in the terms of the console wars of the day:
♪ Genesis does ♪
Over two hundred moving objects
♪ You can't do this on Nintendo ♫
I'd like to see a demo that does this.
Sik wrote:
Well yeah, the Mega Drive can do it perfectly actually
I was going by TmEE's description, which involved the adjective "jiggly" (though I'm not clear on why this would be). I haven't seen it done myself.
Quote:
However, take into account that the only reason it works on the Mega Drive at all in the first place is because the VDP explicitly allows you to keep writing to video memory during active scan (albeit in limited capacity). The SPPU in the SNES doesn't, and that basically makes this idea pretty much impossible to implement.
Sprite attribute tables on the MD are in VRAM, right? VRAM and OAM are separate on the SNES, meaning the limits on VRAM access (which according to fullsnes may not be as absolute as is generally thought) do not directly prove anything about OAM access. CGRAM, which is analogous to OAM in some respects, is known to be writable during HBlank under at least some circumstances; I've done it myself.
We do know that it is technically possible to edit a certain part of the OAM between scanlines, because Uniracers does it. What is not yet clear, so far as I am aware, is whether it is possible to do anything more interesting/generally applicable, like freely repositioning a sprite after (or while) drawing it. I admit it looks dubious...
Maybe I should try fiddling with this once I have a practical grasp of the sprite system...
...
@psycopathicteen: did you ever get anywhere with this idea?
No. I don't have a Neo Myth Cart or PowerPak, so I have no way of testing it out on real hardware.
I have SNES PowerPak and can run a test ROM for you. Or are you talking about needing to test ten different builds in a day?
I didn't even start programming the OAM thing.
psycopathicteen wrote:
Since the SNES uses planar mode, you can use the bytes that make up the sprite pattern as indexes to a LUT.
Very interesting trick. I'll have to try it in a demo. And you can even use the same table for the left and right half of a 16x16 by using the multiply ports to shift the right half left by a power of 2.
If you're talking about the multiplication trick I've mentioned in the SA-1 thread, I realized something wrong with it. The left-most pixel is bit-7. Maybe it could work, by working right to left, instead of left to right. Another important factor is what format your storing sprites in.
A horizontal sprite squashing method for 1bpp or planar platforms (CV, NES, GB, SMS, TG16, SNES) would be roughly comparable to sprite squashing in the Neo Geo. It would use four lookup tables, totaling 1024 bytes: scale8to7, scale8to6, scale8to5, and scale8to4. Each would be flush right, padded on the left with zeroes.
Pixels:
11223344
(This corresponds to the bitplanes 11001100 00111100 00000011 00000000)
Each plane through right-aligned scale8to6 lookup table:
00112334
(This corresponds to the bitplanes 00110110 00001110 00000001 00000000)
Multiply each plane by four:
11233400
(This corresponds to the bitplanes 11011000 00111000 00000100 00000000)
I know the TG16 is stuck at 16x16 sprites. Does it have any sort of barrel shifter or hardware multiplier, or would it need to use a second set of left-aligned tables?
tepples wrote:
Wolfenstein 3D exists. Therefore yes.
psycopathicteen wrote:
Toy Story exists.
tokumaru wrote:
As long as we're playing this game: Jurassic Park exists.
I don't know if this is relevant anymore, but the racing minigame of Chrono Trigger exists.
Tales of Phantasia exists.
Star Ocean exists.
Bregalad wrote:
I don't know if this is relevant anymore, but the racing minigame of Chrono Trigger exists.
This one definitely is relevant because it's actual normal sprites being scaled. There are like only two though, and it's possible they're just prerendered since they don't scale that much.
No idea about the other games.
Sik wrote:
Bregalad wrote:
I don't know if this is relevant anymore, but the racing minigame of Chrono Trigger exists.
This one definitely is relevant because it's actual normal sprites being scaled. There are like only two though, and it's possible they're just prerendered since they don't scale that much.
No idea about the other games.
You can rotate the camera.