News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Understanding Sprite Assembly, Decoding C++  (Read 1248 times)

pianohombre

  • Sr. Member
  • ****
  • Posts: 301
    • View Profile
    • My personal website of short stories and comics
Understanding Sprite Assembly, Decoding C++
« on: August 11, 2020, 07:07:39 am »
Hi,
The only project I've pretty much worked on ever is one that was written in Assembly and C++, then later the project was made open source. Unfortunately, the programmers who understand the code and how to finish it, have pretty much abandoned the project and complain the engine needs to be re-written, and they are difficult to get a hold of. The source code is not commented well (I've added a lot of comments to what I have been able to decipher). I was very active a couple years ago on a project called Megaman X Editor (and unfortunately the forum thread where most of the work understanding the project has been locked).

Basically what I've been trying to do is get the enemy sprites to display in the editor. The editor lets you edit levels, enemies, items, checkpoints, etc. in the program, but it's a WIP. There's a couple bugs but most are pretty minor. I've added a lot of features, but there's still much to do to get the editor to be as powerful as something like SMILE or Lunar Magic. The program can edit 4 games- MMX1-3 and Rockman & Forte, but basically the editor works pretty good without any glitches for MMX1-3 and was unfinished for RNF. The biggest problem is that the graphics for the enemy sprites don't display! The editor is still functional, but who wants to guess what enemy they are moving around by looking at an empty square? I can add enemy names to the editor so they can pull up what the actual enemy is in a separate window, but I'm trying to make the thing as user friendly as possible.

The problem is trying to find what values control what. I'm not even sure which variable controls the starting point for the graphics table in the editor (you need an address obviously which is like searching for a needle in a haystack.) But that's not all that's required. Several variables control graphics disassembly and assembly. It may use the same compression algorithm as MMX1-3, but I'm not sure. So I may have to use like an exception clause for RNF to run a separate function/class that handles this game's compression, assembly, etc. I have the addresses for the graphics pointer table I was able to find by a disassembly program, but I think there's like an offset value or something (another unknown that has be included in the function).
"Programming in itself is beauty,
whether or not the operating system actually functions." - Linus Torvalds

slidelljohn

  • Sr. Member
  • ****
  • Posts: 326
    • View Profile
Re: Understanding Sprite Assembly, Decoding C++
« Reply #1 on: August 17, 2020, 05:14:18 pm »
I would like to help you accomplish your goals with this editor or a new mmx editor from scratch. I’m not sure when I will be able to put the information together for you to understand how the graphics for the sprites work but I will get that to you as soon as I’m able to.
« Last Edit: September 06, 2020, 08:35:30 pm by slidelljohn »

bosn

  • Jr. Member
  • **
  • Posts: 24
    • View Profile
Re: Understanding Sprite Assembly, Decoding C++
« Reply #2 on: August 17, 2020, 06:36:56 pm »
Dunno if I can help but I would like to take a look, can you share it?

slidelljohn

  • Sr. Member
  • ****
  • Posts: 326
    • View Profile
Re: Understanding Sprite Assembly, Decoding C++
« Reply #3 on: August 28, 2020, 09:15:08 pm »
@bosn
I'm not sure if you were talking to me or pianohombre but I have found most of my notes
for the mmx v1.1 data structure for the sprites that I will hopefully have posted within
a few days so everyone will have access to it.


The problem is trying to find what values control what. I'm not even sure which variable controls the starting point for the graphics table in the editor (you need an address obviously which is like searching for a needle in a haystack.) But that's not all that's required. Several variables control graphics disassembly and assembly. It may use the same compression algorithm as MMX1-3, but I'm not sure. So I may have to use like an exception clause for RNF to run a separate function/class that handles this game's compression, assembly, etc. I have the addresses for the graphics pointer table I was able to find by a disassembly program, but I think there's like an offset value or something (another unknown that has be included in the function).

I found the majority of my notes for how the data works which I will post soon but from what
you have said it seems like your biggest problem is understanding how the snes hardware works.
If you understand the hardware you should(or seems like you should) be able to find out how
the data works. I would like to show you how to figure out how the data works instead of just
showing you how the data works.

To be able to figure out and understand the sprite data own your own you really need to know how the snes:

1: cgram registers work
2: oamram registers work
3: vram registers work
4: 65c816 assembly language works

Knowing how these snes registers work will give you the ability to trace the assembly code
backwards to the location of the data. If you know these 4 things the data wont be like
"searching for a needle in a haystack" it would be more like hunting your prey. ;D

If there is any of the 4 things listed above that you don't fully understand just let me know which ones
and I'll walk you through each one in search of the mmx data that you need to understand to accomplish your
goals with the mmx editor.

As far as the c++ I'm probably not going to be much help with that part but I can do a little bit.
I mostly use QT for my c++ and I do have some stuff written for mmx to view the levels and sprite
data but nothing I have available yet to edit the levels and data. It will probable be awhile before
I'll be ready to finish my QT c++ programs for mmx but it is something that I would like to finish
eventually.

justin3009

  • Hero Member
  • *****
  • Posts: 1648
  • Welp
    • View Profile
Re: Understanding Sprite Assembly, Decoding C++
« Reply #4 on: August 29, 2020, 03:45:55 pm »
I know how X and Zero are setup all the way around for sprites, mostly anyway. It's a bit hard to explain and sort of convoluted since my notes are pretty scattered. Most of this SHOULD hold true for X1/X2 as they share the exact same system. Just the offsets will obviously be different.

Sprite Assembly, Animation Data (Though some bits here are confusing) and their VRAM data. It's pretty straight forward for the most part.

The "VRAM" data is a 24-bit ROM pointer to the graphics. Generally it's three transfers to VRAM. THIS is where the sprite assembly kicks in though for reading specific chunks. The sprite assembly uses the sprites organized in VRAM to set things up overall and the animation data is just which sprite frame to use.


Pointer to Animation Data
Code: [Select]
3F8000 - X with no armor (Sprite set #1. Does NOT include Z-Saber sprites, Ride Armor sprites, etc.. just the basic ones)
3F8048 - X with armor (Sprite set #1. Does NOT include Z-Saber sprites, Ride Armor sprites, etc.. just the basic ones)
3F809C - X ??? (Don't have this noted properly) (This includes Z-Saber sprites, vertical dash, charged Gravity Well/Ray Splasher, etc..)

3F80DE - Zero (Sprite set #1. Does not include Z-Saber)
3F80E1 - Zero (Sprite set #2. Z-Saber)



Animation data setup for X/Zero. (This SHOULD be the same setup for enemies and objects. These notes are incredibly old.)
Code: [Select]
3F8000 --> 3FCB64 - Base start for X.  Example: (3FCC04 = 59 03 = Idle.  Reverse to get 359.  Add 359 to 3FCB64 and you get 3FCEBD)

Idle animation
3FCEBD - Wait time until 1st frame
3FCEBE - ???
3FCEBF - Frame 1 graphic
3FCEC0 - Wait time until 2nd frame
3FCEC1 - ???
3FCEC2 - Frame 2 graphic
3FCEC3 - Wait time until 3rd frame
3FCEC4 - ???
3FCEC5 - Frame 3 graphic
3FCEC6 - Wait time until 4th frame
3FCEC7 - ???
3FCEC8 - Frame 4 graphic
3FCEC9 - Wait time until 5th frame
3FCECA - ???
3FCECB - Frame 5 graphic
3FCECC - Wait time until 6th frame
3FCECD - ???
3FCECE - Frame 6 graphic
3FCECF - Wait time until 7th frame
3FCED0 - ???
3FCED1 - Frame 7 graphic
3FCED2 - Wait time until 8th frame
3FCED3 - ???
3FCED4 - Frame 8 graphic
3FCED5 - Wait time until 9th frame
3FCED6 - ???
3FCED7 - Frame 9 graphic
3FCED8 - Wait time until 10th frame
3FCED9 - ???
3FCEDA - Frame 10 graphic
3FCEDB - Wait time until 11th frame
3FCEDC - ???
3FCEDD - Frame 11 graphic
3FCEDE - Wait time until 12th frame
3FCEDF - ???
3FCEE0 - Frame 12 graphic
3FCEE1 - ??? - Something to do with restarting animation
3FCEE2 - ??? - Something to do with restarting animation

Sprite Assembly for X/Zero
Code: [Select]
$03/8FB1 BF 00 80 0D LDA $0D8000,x[$0D:8000] A:0000 X:0000 Y:0010 P:envmxdIZc ;Sprite assembly pointers
$03/8FB5 85 1C       STA $1C    [$00:001C]   A:8231 X:0000 Y:0010 P:eNvmxdIzc
$03/8FB7 BF 02 80 0D LDA $0D8002,x[$0D:8002] A:8231 X:0000 Y:0010 P:eNvmxdIzc
$03/8FBB 85 1E       STA $1E    [$00:001E]   A:5D0D X:0000 Y:0010 P:envmxdIzc

$03/8FCB B7 1C       LDA [$1C],y[$0D:8231]   A:0000 X:09D8 Y:0000 P:envmxdIZc ;X idle graphics - Sprite Frame 1 Setup
$03/8FCD 85 18       STA $18    [$00:0018]   A:B92A X:09D8 Y:0000 P:eNvmxdIzc
$03/8FCF C8          INY                     A:B92A X:09D8 Y:0000 P:eNvmxdIzc
$03/8FD0 B7 1C       LDA [$1C],y[$0D:8232]   A:B92A X:09D8 Y:0001 P:envmxdIzc ;X idle graphics - Sprite Frame 1 Setup
$03/8FD2 85 19       STA $19    [$00:0019]   A:0DB9 X:09D8 Y:0001 P:envmxdIzc


X - Stance Frame 1 [DB92A]
************************************
xDB92A - How many chunks there are.  (4 bytes each)

Sprite #1 = Top of helmet
---------------------------
xDB92B - Chunks/Direction of chunks 
--> 00 = 1 chunk, normal.
--> 20 = 4 chunks (Top two, bottom two) normal. 
--> 40 = 1 chunk flipped left/right. 
--> 60 = 4 chunks (Top two, bottom two) flipped left/right
--> 80 = 1 chunk flipped upside down
--> A0 = 4 chunks (Top two, bottom two) flipped upside down.
xDB92C - X coordinates of piece 1
xDB92D - Y coordinates of piece 1
xDB92E - Sprite #1 graphic


Sprite #2
---------------------------
xDB92F - Direction/Chunks
xDB930 - X coordinate of piece 2
xDB931 - Y coordinate of piece 2
xDB932 - Sprite 2 graphic

Sprite #3
---------------------------
xDB933 - Direction/Chunks
xDB934 - X coordinate of piece 3
xDB935 - Y coordinate of piece 3
xDB936 - Sprite #3 graphic

Sprite #4
--------------------------
xDB937 - Direction/Chunks
xDB938 - X coordinate of piece 3
xDB939 - Y coordinate of piece 3
xDB93A - Sprite #4 graphic
etc..

There is no end byte to sprite assembly, it's all calculated by how many pieces to load at the very first byte.

VRAM
Code: [Select]
$04/BCCF B1 31       LDA ($31),y[$05:CE45]   A:00A2 X:01FE Y:0000 P:envmxdIzc ;Pointer to ROM graphic and how many bytes to send to VRAM. (Generally loops three times based on a specific byte at the end of each chunk?)
$04/BCD1 65 31       ADC $31    [$00:0A09]   A:0411 X:01FE Y:00A2 P:envmxdIzc


05CF0E (Idle X)
$20 ;How many tiles to load? (Forgot how this calculation works)
$2D8000 ;Pointer to ROM graphics
$6000 ;VRAM location (Double to get proper value. #$8000+ is used to end the total transfers. Subtract #$8000 for anything above to get proper VRAM location.)

$20 ;How many tiles to load? (Forgot how this calculation works)
$2D8200 ;Pointer to ROM graphics
$6100 ;VRAM location (Double to get proper value. #$8000+ is used to end the total transfers. Subtract #$8000 for anything above to get proper VRAM location.)

$02 ;How many tiles to load? (Forgot how this calculation works)
$2D8400 ;Pointer to ROM graphics
$E200 ;VRAM location (Double to get proper value. #$8000+ is used to end the total transfers. Subtract #$8000 for anything above to get proper VRAM location.)

I'm not so sure how it all works on enemies per se because their data is compressed. All I know is it gets decompressed into RAM then it all gets sent straight into VRAM so they probably lack proper 'VRAM' data like X/Zero overall unless there's a byte signifying that difference. However, sprite assembly and animation data should be extremely similar if not the same for both.
« Last Edit: August 30, 2020, 08:05:22 am by justin3009 »
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

pianohombre

  • Sr. Member
  • ****
  • Posts: 301
    • View Profile
    • My personal website of short stories and comics
Re: Understanding Sprite Assembly, Decoding C++
« Reply #5 on: August 31, 2020, 07:43:34 pm »
To be able to figure out and understand the sprite data own your own you really need to know how the snes:

1: cgram registers work
2: oamram registers work
3: vram registers work
4: 65c816 assembly language works

Hi, first off thanks so much for any help. I just ask that you try and be patient with me, since I've only done very light hacking in snes assembly so I will probably run into a lot of problems. Is there any documentation on this site that goes into detail with the 4 above?

Also, thank you justin3009 (all praise his contributions and programming glory). This info will help me determine if assembly is different between Rockman&Forte and MMX1-3.
"Programming in itself is beauty,
whether or not the operating system actually functions." - Linus Torvalds

slidelljohn

  • Sr. Member
  • ****
  • Posts: 326
    • View Profile
Re: Understanding Sprite Assembly, Decoding C++
« Reply #6 on: September 02, 2020, 11:38:40 pm »
This link is useful for snes registers
https://wiki.superfamicom.org/registers

This link is useful for snes assembly but I mostly learned
from looking at and editing code to see how it works.
https://wiki.superfamicom.org/65816-reference

I’ll try to have something posted by tomorrow showing how
I found the data and how it works. I’ll also upload a tool to unpack some of the mmx v1.1 files.