News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

[SM] Reading level data and game graphics

Started by Sunbeam, January 01, 2012, 11:03:26 AM

Previous topic - Next topic

Sunbeam

Hi all!
I'm currently working on something I'd like to present here soon. But before that I have to figure out how to do some things. I hope some of you can help me with this :^_^: I got all of my knowledge from Kejardons documents (esp. the RAM map) and Scyzers addition to that.

1) I managed to read the Super Metroid level data from the game RAM while it's running in an emulator. However I have not been able to find out where things like mirroring of certain tiles is saved. The tilemap in RAM seems to only contain the type of a given block (bomb, crumble, air...) and what graphic it should use. Nothing about if the graphic should be mirrored or not. Can I only find this information in VRAM, not normal RAM? And where can I find this information/data?

2) I want to read the graphic data of the currently loaded room. Would it be better to read the data from RAM or from VRAM? I'm specifically interested in the rooms tile graphics. I also need what I think is called the CRE graphics (which don't change while the game is running if I'm correct). So I guess I would have to only read them once when the game starts. Is this correct? The RAM/VRAM question also applies to these graphics.

3) After I have read out the game graphics, what steps would be necessary to convert these graphics into a more recent format (something in 32 bits for example)? From what I read the SM graphics are 4bit. Also I'm programming in C++ if that's of any interest.
The most important question for converting these graphics is how they are arranged in RAM/VRAM so I can understand how to change them to a more recent format. I also need to know how palettes work with this.

Thanks for your interest!

Qactis

You are correct that a lot of graphics such as enemy item pickups and other graphics are loaded to VRAM via a DMA transfer, I believe the DMA transfer routines are in bank $80, though I never actually was able to locate what I was looking for. CRE is compressed and is probably decompressed during the game load and loaded to VRAM. That is where you need to look for your graphics.

P.JBoy

Mirror data is stored in the RAM
The level data tiledata follows the format:

ffffvhtt tttttttt
t = 16x16 number
h = horizontal flip
v = vertical flip
f = simple block properties

Sunbeam

Thanks for your answers!
@P.JBoy
That did the trick. I assumed that the 16x16 number consisted of 12 bits. I guess I would never have figured this out on my own.  ;)

About the graphics: I currently don't know enough about assembly to do anything with the SM code. Instead I just ended up reading the graphics out of the emulators VRAM. The only problem was SMs (or SNES in general) 4bit graphics format, which is easily one of the strangest and confusing graphics formats that I ever came across. It was a total pain in the neck reading it from memory. :)

P.JBoy

Pardon the tone of voice, I'm copying a previous post of mine.


Super Metroid, Fusion and Zero Mission all do this the same way with minor differences.  The consoles' memory to display the map is called the VRAM, there are two sections of the VRAM, one's called the characters, and the other's called the map.  The characters are 8x8 pixel blocks, which take up 32 bytes each (4-bits per pixel), each pixel is a reference to the colour in a palette it's supposed to use (colour 0..15); the map is what puts the characters in order displayed and says which palette for each block to use, as well as which way to flip them (taking 2 bytes per tile).  I'll try to demonstrate visually:


Here's the characters.  We can see that they don't know what palette they're meant to use, only which colours in palette belong to which pixel.  In the bottom left, you can see the 64 individual pixels; I selected the palette that they actually do belong to (palette 5) so you can see that colour both here and in the palette:


Here's the same colour as in the character image; you can see that it is in the 5th row, and it's the 15th colour in that row; in fact, the above block's data is fairly easy to determine without even looking at the VRAM.  Since each pixel is a nybble (a single hex digit),  It'll be 0FFFFFFF for the first row, F6666666 for the second row, etc.

Here's the map:


The CPU goes through each block of the VRAM, checking the map; the map will say something like: block 1 block 1 block 1 block 1 block 2 block 2 block 2 block 40 block 23 etc. referring to the characters.  The map also says which palette to use (there's 15 in the palette RAM, sometimes called the CGRAM), and if it's horizontally flipped or vertically flipped.  That garbage data on the right half is the remaining map from the previous room, which used a different character set; the fact that VRAM keeps a lot more map information than is displayed is very important for how these games handle scrolling; but that's a pretty advanced subject.

There is in fact, more than one layer.  In Super Metroid, there's the level layer (the blocks Samus interacts with), the background layer (the scenery), and the foreground layer (the HUD and rain/fog/water effects).  In Fusion and Zero Mission, there's another layer, and it's just used for very specific things, as to not need to include them in the tileset (I guess).

Furthermore, the consoles use 8x8 blocks, however, the games are designed with 16x16 blocks.  Though all the blocks in the above map picture are 8x8's, in the VRAM they're actually 16x16's, the VRAM contains four tiles for every one tile used when designing the games' rooms (the four quarters).  So it goes: game's tileset -> the four blocks it's made of -> VRAM char, game's map -> the four blocks in VRAM it represents (somewhere in the ROM) -> VRAM map.

Sunbeam

Thanks for your in-depth information :) But I think I should have been more clear in my previous post. I already managed to read the graphics data from VRAM by trial and error. Actually one of the most obscure things in that is that each pixel of a character is not saved as a half-byte (which would make two pixels per byte) but instead each pixel is scattered over four different bytes. As I said it's possibly the weirdest graphics format I've ever come across. Maybe it's easier if you read the data directly from ROM and not VRAM.
Anyway, thanks for your help! :)
I only have to work a bit more on my project before I'll post it here.

Qactis

Man if you can find where these graphics are transfered to VRAM/RAM from the ROM that would be amazing. I couldn't find where the enemy missile/sm drops were after searching for a week

Sunbeam

I think I have to disappoint you there. As I stated above I have nearly no knowledge of ASM coding and debugging. The "only" thing I did was reading the data directly out of VRAM of the running game. This was no problem using the RAM map, the only difficult part was finding out how to interpret the graphical data. At the moment I have the CRE graphics and the scenery graphics. Basically I now get the same image as SMILE has for its tiles. That also means I have no enemy or pickup graphics. I do however receive item (PLM) graphics, as these get written into the character graphics after the room was loaded (at least I assume that). If I just copy the graphics after that I also have said item graphics. (That were a lot of "graphics" ;) )

P.JBoy

Writing graphics to the VRAM is done using the table at 7E:00D0; that table is read during the NMI and is the graphics are updated then.  Enemy drops are enemy/room projectiles, if that helps

Crashtour99

Well, there are other methods that Super Metroid uses to transfer graphics as well.  As an example, here's a bit of coding from the HUD routine run during game loading that uses the registers for a DMA transfer to VRAM.

the following lines set up a DMA transfer of graphics for the HUD
$80/9A7F A9 00 58    LDA #$5800              ;VRAM target address
$80/9A82 8D 16 21    STA $2116  [$88:2116]   ;VRAM target address
$80/9A85 A9 80 00    LDA #$0080              ;Normal increment by 1, no remapping, increment after writing $2119/reading $213a
$80/9A88 8D 15 21    STA $2115  [$88:2115]   ;VMAIN - Video Port Control
$80/9A8B 22 A9 91 80 JSL $8091A9[$80:91A9]   A:0010 X:0012 Y:00A8 P:envmxdizC
;values used by previous JSL
01 01 18
8B 98 80   
40 00   

$80/9A97 E2 20       SEP #$20                A:0010 X:0012 Y:00A8 P:envmxdizC
$80/9A99 A9 02       LDA #$02                ;DMA channel 2
$80/9A9B 8D 0B 42    STA $420B  [$88:420B]   ;enables DMA channel transfers (runs immediately)
$80/9A9E C2 20       REP #$20                end DMA transfer

following section writes HUD tilemap to it's location in RAM
$80/9AA0 A2 00 00    LDX #$0000             
$80/9AA3 BD CB 98    LDA $98CB,x[$88:98DD]   location of initial HUD tilemap
$80/9AA6 9F 08 C6 7E STA $7EC608,x[$7E:C61A] A:0010 X:0012 Y:00A8 P:envmxdizC
$80/9AAA E8          INX                     A:0010 X:0012 Y:00A8 P:envmxdizC
$80/9AAB E8          INX                     A:0010 X:0012 Y:00A8 P:envmxdizC
$80/9AAC E0 C0 00    CPX #$00C0              A:0010 X:0012 Y:00A8 P:envmxdizC
$80/9AAF D0 F2       BNE $F2    [$9AA3]      A:0010 X:0012 Y:00A8 P:envmxdizC