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

Author Topic: Exporting N64 Models - Correctly Textured  (Read 7140 times)

Shadow0144

  • Jr. Member
  • **
  • Posts: 5
    • View Profile
Exporting N64 Models - Correctly Textured
« on: September 14, 2015, 12:14:16 pm »
I've been scouring the internet for a way to export models from an N64 rom, and I've found the only two tools anyone ever mentions: Lemmy and TR64, both of which are plugins for emulators. But the problem is that while Lemmy actually successfully exports the models instead of giving me a mostly empty file, its UV mapping is all over the place both in-game and when exported; however, TR64 seems to map the textures mostly fine in-game, but then, for whatever reason, doesn't export the textures with the model. TR64 can export the textures separately, but in both cases, you need to do all the texturing work from scratch. While this would be fine for one or two or maybe even ten models, I plan to use quite a few models, and it seems strange to me that there isn't someway to combine these features and save me a ton of work.

Alternately, if there's someway to figure out how the models are stored in the rom, I could just write my own extractor or something. I don't know, haha. Does anyone know of a guide I could read to learn more about that maybe? Or if I could get the source code for both plugins, maybe I could find a way to combine them...

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #1 on: September 14, 2015, 01:32:44 pm »
I'll try not to make this complicated, but just to warn you this isn't a simple subject.

The reason for this is that N64 geometry is typically written(*) using display lists written with a variety of microcode.  For comparison, these resemble openGL display lists in how they are set up.  (They aren't, but it's a decent way to visualize it)

Geometry microcode is processed by the RSP into RDP display lists.  You load a program into the RSP, and this program interprets the commands fed into it.  The RSP will processes images into a usable format, generate mipmaps when requested, apply transformations to vertices and groups, etc.  Although RDP lists don't differ at all between titles, the microcode used to generate them will vary as well as the code used to run it.  There's a number of different microcodes, all of which require different processing.
The RDP is basically a joint graphics/audio card and the commands fed into it are used to generate an image, and this image is then pushed to the VI which may or may not post-process it, and from there to the screen.

One problem though is that the RDP is a unique and early graphics card and has a few features not typically implemented nowadays.  For instance, clamping duplicates the last line of either the texture UV when you exceed the texture's width/height instead of doubling or mirroring it.  Also, it can switch between using vertex normals for enviromental lighting and what used to be called "precalculated lighting", now known as vertex colors.  To export all aspects of a model might be tricky--especially within the constraints of PC model formats--even before dealing with additional textures for mirrored textures and other such workarounds.
Another problem is that the RSP's program can be fed arguments that are not obvious outside a running program, such as an array of pointers to different banks of data. 

So, in order to properly export models you have one of several choices:
1) Simply "fudge" the nitty-gritty of display lists, omitting clever combiner effects and only really paying attention to vertex, tri/quad, and major texture commands.  Easiest way to get an extract, and most common used.
2) Use geometry dumps generated by an emulated game, either with internal dumps or using an external directX/openGL dumper.  If you go this route, you might want to use an LLE plugin like Angrylion or a low-level emulator like MESS or Cen64 to avoid things still not properly emulated.  There's still a chance of distorted geometry though, and you'll have to basically walk around and "snapshot", then clean up the overlapping stuff.
3) Effectively process the RSP microcode, either indirectly or directly into a different format.

Long story short it isn't an easy process.  In the past I've just written my own extractors, then own importers, and they're still limited by features not easily converted.

* Unless you're dealing with one of the maybe 3% special cases where they generate all geometry microcode from script-like stuff.  Basically, Eurocom titles, certain PC conversions, Mario Kart 64, etc.

Shadow0144

  • Jr. Member
  • **
  • Posts: 5
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #2 on: September 15, 2015, 12:45:23 am »
I knew it wouldn't be an easy process. Can the extractor be a standalone executable or does it need to be tied to an emulator? I guess I'm not 100% sure how model and texture data is stored in a rom.

At least for now, I only have one game in mind, and it looks like there isn't really much going on as far as fancy effects or shaders or anything, so I think writing a custom extractor may be the best way to go if there's nothing better than Lemmy's plugin out yet. Do you know where I could look to start getting an idea how to write such a program?

Also, Angrylion likes to completely freeze and then crash my computer when it starts :/
A lot of those abbreviations are rather hard to Google, but the only ones I didn't understand were the VI and LLE. Unless LLE is local linear embedding. In which case I'm not sure how that works - wouldn't I just end up with 2D renders? Or am I not understanding it correctly?

Corvo

  • Jr. Member
  • **
  • Posts: 43
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #3 on: September 15, 2015, 12:54:07 am »
VI = Video Interface
LLE = Low-Level Emulation (most N64 video plugins use HLE - High-Level Emulation)

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #4 on: September 15, 2015, 08:40:35 am »
I usually just use standalone scripts.
Without any idea of what you're working on I can't tell you which microcode you'll be working with or if they did something more unique.  This is just going to have to be very general.

Basic vertices will use a structure like: (and yes, there are exceptions)
Code: [Select]
0x0 2 xpos
0x2 2 ypos
0x4 2 zpos
0x6 2 RESERVED
0x8 2 S
0xA 2 T
0xC 4 byte values
in vertex color mode RGBA
in enviromental mode XYZ0, typically converted x/(127+(x<0)
Vertex loading commands load a number of vertices starting at a pointer or offset given into an internal buffer of vertices.  The number it can use at a single time is microcode-specific (in other words the amount of space they dedicated to it), and some also allow you to load them starting at an offset in the buffer.
It's pretty important to also do the same, not just so that your tris reference the correct data but because later F3DEX variants have commands to alter vertices loaded in this buffer.  Usually it's to change the ST values around, so other tris/quads can share the same vertex data even though the image--or a different image--gets mapped to the point differently.

A note about ST.  On an N64 they're actual image positions, not percentages like in most PC formats.  So yes, that means ST are actually texture-dependant.  I'd suggest when writing lists of vertices for tris to also store info about the current texture along with it.  Mirroring and clamping complicate this, and they can do it in only one direction too.  Mirroring will cause a texture to flip when repeated, and clamping duplicates the last line instead of repeating.  Flags for those are found on the SetTile command.

Another thing to worry about is that very few games have images ready to shove into the RDP.  Most get some degree of processing by the RSP (interlacing minimum, but conversion as well), and the RSP may chop them up into smaller images to fit within the constraints of tmem.  ST is an actual position in the working image, not the source.  In the overwhelming number of cases the source is the same size or is being tiled regularly so chances are you'll be okay.  Mostly it's sprite-based games that abuse splitting.

You can probably omit most matrix conversions or fudge a scale modification, though some will use a matrix stack to position different elements in a model. 
You might be able to get away with ignoring most of the combiner.  It selects how--and if--textures, vertex colors, lighting, enviromental colors, etc. are all combined.  You will need to catch the Texture command though to know if a surface is untextured. 

I'd rather not given an example without knowing which microcode you'll be working with.  It can get seriously confusing if it's a related one.  Nothing like all the right commands and all the wrong interpretation ;*)

Shadow0144

  • Jr. Member
  • **
  • Posts: 5
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #5 on: September 16, 2015, 12:16:56 am »
I'm working on Harvest Moon 64 if that's any help. My goal is to rip out the models and just remake the game from scratch as accurately as I can using XNA since the changes I want to make a pretty severe (eg, multiplayer). With the exception of houses, the only real models seem to be the ground; everything else is just flat textures. I don't think a great deal of model magic or fancy footwork is being used, but I guess you never know.
The uCode that Lenny's plugin autoselects (and the only one that works even remotely, though not perfectly) is "4 (Ex Zelda)" if that helps.

How does one go about tracking down model and texture data? Is there some kind of pattern I can see in the rom?

Thanks for all the help!

(What do you think my chances would be if I just emailed Natsume asking if they'd be kind enough to lend me their assets if they even still had them lying around? Haha)
« Last Edit: September 16, 2015, 12:28:15 am by Shadow0144 »

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #6 on: September 16, 2015, 11:06:09 am »
Didn't do the models for it but did do a script and partial sprite dump some time back for somebody else.  Includes a decompression script and some info on some file formats.
http://www.mediafire.com/download/pc9vp88wxjhvh8h/Harvest.7z

A filelist, with some stuff already named:
http://pastebin.com/ziqPHN0U


Microcode looks like F3DEX2.  Have a sub-optimal basic parsing script for some common things for reference here:
http://pastebin.com/ynkH9sft

Note microcode can also be used to get the RSP to do sprite layout so if you see a bunch of "texrect" commands that's probably just sprites or the HUD.  Why lay them out yourself when a co-processor can do it for you?

The basics:
Commands are 8 bytes long.  The first byte is the command type.  Many commands can be ignored (such as the syncs) if you're just interested in basic geometry dumping.  Also, you can probably ignore more complicated things like the combiner since you're just extracting the basic objects for another purpose.

0xDF (endDL) ends a display list.  Any time you read DF000000 00000000 it stops this display list group and returns to whatever called it.  If nothing called it, you're done.
0xDE (DL) jumps and links another display list.  Continue reading that one until you hit the endDL.  It will be in the format DE000000 xxxxxxxx, where the x is a pointer or offset to the other display list.  Pointers start 80xxxxxx and will be an rdram address, offsets will have a different leader byte.

Vertices are loaded using the 0x01 command.  It loads a number of vertices from a given location into an internal buffer, and this buffer is used for the tri commands.  This one is bitpacked:
Code: [Select]
FF000000 00000000 command (01)
00FE0000 00000000 starting offset for putting these in the vtx table.  Usually 0.
0001FC00 00000000 number of vertices to load
000003FF 00000000 number of DWs to load (<< 3 for actual bytesize)
00000000 FFFFFFFF offset or pointer to vertices
A command like 01004008 0A000000 would load 4 vertices (0x40 of data) from offset 0 in bank 10 (wherever that happens to be).

The two basic tri commands are 05 and 06, tri1 and tri 2 respectively.  The vertex indicies are drawn from the internal buffer filled by the 01 command above.  They have the same format:
Code: [Select]
FF000000 00000000 command
00FE0000 00000000 vertex 1
0000FE00 00000000 vertex 2
000000FE 00000000 vertex 3
00000000 00FE0000 vertex 1 (06 only)
00000000 0000FE00 vertex 2 (06 only)
00000000 000000FE vertex 3 (06 only)

07 is a quad type, though you probably won't see it at all.  Pretty sure it goes x1, y1, x2, y2.
Code: [Select]
FF000000 00000000 command (07)
00000000 FE000000 vertex 1
00000000 00FE0000 vertex 2
00000000 0000FE00 vertex 3
00000000 000000FE vertex 4


To throw a monkey-wrench in things, there's a modifyvtx command.  It's command 02, and it changes a word at an offset in the vertex buffer to a new value.  Read the note in that script about this, since it's a tad bit complicated how it changes texture coordinates.  Basically, it changes the vertices after they've already been modified, but it also doesn't affect anything that has already used that vertex.
Code: [Select]
FF000000 00000000 command (02)
00FF0000 00000000 modification; 0x14 for ST
0000FFFE 00000000 vertex number
00000000 FFFFFFFF value

Command 0xD7 is Texture.  It turns textures on and off and can set the ST when a specific tile is used.  The most important flag, and probably only one you need to catch, is 00000001 00000000.  If set, textures are applied to geometry that follows.

Commands FA and FB change the foreground and background color--in other words, white and black.  You probably won't run into this, but if you do the lower word is an RGBA value.  These can also change the color of intensity and ia images.

Texrect is a multiple-command one.  It doesn't use vertices.  There's a normal and reverse version, and it's common to all microcodes.  They're 0xE4 and 0xE5.  They're going to be used almost exclusively for sprites and text though, so probably won't need it.

Then the ones for images.  Thing about images is the RSP will load them initially into memory, unconcerned about the image type, just so it can preprocess them.  Then it loads it again with final settings before pushing to the RDP. 
The other thing is they can be loaded in one of two ways.  First is just as a block of data; and the second row-by-row, aligning each row properly automatically with optional subdivision for referencing subimages.

(I'm going to simplify the image stuff a little bit since you probably won't need to manage a virtual tmem or know how tile layouts or mipmaps work.)

Most import is 0xFD.  It sets a source for image data.  This data is copied into tmem using other commands, which is a buffer for the working images similar to the buffer for vertices.  Fair warning, it's also possible to load palette data this way, and the type cast here isn't necessarily going to be the final image type.
Code: [Select]
FF000000 00000000 command (0xFD)
00E00000 00000000 color type
0 rgb(a)
1 yuv (don't use; requires RSP translation to RGB colorspace!)
2 color-indexed (paletted)
3 intensity+alpha (black+white w/ alpha)
4 intensity (black+white)
00180000 00000000 color depth
0 4bit
1 8bit
2 16bit
3 32bit
00000FFF 00000000 width-1
00000000 FFFFFFFF offset or pointer to image data
Images can be loaded into tmem as either a block (0xF3, the loadblock command) or as one or more tiles (0xF4, loadtile).  The difference is how the data is copied.  A block is just copied as-is and assumes that you padded it properly.  A tile copies each row of an image in, pads it, then continues.  They read the image starting at a given ST and ending at a given ST, but these values are actually a fixed point 6.2 value.  Both have the same format:
Code: [Select]
FF000000 00000000 command
00FFF000 00000000 upper left S
00000FFF 00000000 upper left T
00000000 00FFF000 lower right S
00000000 00000FFF lower right T
When subdividing into tiles, such as with a font, the divisions are assumed to be aligned.  This is done with the F2 command, which outside the tile value is the same format as the two above.  You probably won't encounter it.

Palettes, or texture lookup tables, are always 16bit rgba or ia.  Admittantly you won't come across the ia version much.  It's the same format as the commands above.

Finally, the F5 settile command sets how an image should be interpreted.  It also sets attributes like mirroring, clamping, and shifting.
Code: [Select]
FF000000 00000000 command (0xF5)
00E00000 00000000 format; same as 0xFD type
00180000 00000000 size; same as 0xFD type
0003FE00 00000000 line, used with the tile commands to split image
000001FF 00000000 offset in tmem to load image data to; << 4 for actual
00000000 07000000 tile, which you don't need to mess with
00000000 00F00000 palette, when applicable
00000000 00080000 clamp T if set
00000000 00040000 mirror T if set
00000000 0003C000 mask for T when tiling; ANDs offsets with this, so tile height
00000000 00003C00 shift for T when tiling, like an offset
00000000 00000200 clamp S if set
00000000 00000100 mirror S if set
00000000 000000F0 mask for S when tiling; ANDs offsets with this, so tile width
00000000 0000000F shift for S when tiling, like an offset
« Last Edit: September 16, 2015, 05:20:09 pm by Zoinkity »

Shadow0144

  • Jr. Member
  • **
  • Posts: 5
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #7 on: September 18, 2015, 04:16:52 am »
Wow, this is so much information and help! And you've already gotten and even *named and sorted* all the sprites *and* the dialogue?! You've saved me so much work, thank you so much! I was at a loss for how the text had been encoded. And the Japanese is there too, excellent! The code is even commented! :0! I'm so excited, haha.

This is a lot of information; I'm going to read through the Python scripts and what you've posted and see if I can figure this all out. I'll let you know what happens or if have questions.

You've been a tremendous help; I can't thank you enough!

September 24, 2015, 12:56:43 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
I had a question about your scripts. They seem to run off of already extracted files: .res, .obj, .script; how did you get those files? All the data originally came from the .rom, right?
« Last Edit: September 24, 2015, 12:56:43 pm by Shadow0144 »

Zoinkity

  • Hero Member
  • *****
  • Posts: 565
    • View Profile
Re: Exporting N64 Models - Correctly Textured
« Reply #8 on: September 25, 2015, 09:11:56 am »
Yes, all the files were originally in the ROM.  The "filelist" is written for a buggy extractor I wrote some time back, though in this case basically did all of them by hand while narrowing down locations and lengths.  The extensions are just convenience.  The extractor keeps dropping random entries and I've never quite gotten around to fixing it.

The files themselves aren't compressed.  The text is encoded (which is what the decoder is for), but pretty sure nothing else is compressed.  Reading entries is simple:
Code: [Select]
0xE72780 bin dlg/events/road.script
0xE73070 bin dlg/events/road.idx
First entry is the location in ROM (0xE72780).  If an end isn't specified the file ends at the start of the next file (0xE73070 in this case).  'bin' denotes it's an uncompressed binary file, and the rest is the filename.

Also, you probably noticed that not all the images in the game are extracted already.  Pretty sure there are some sprite sets like the sakura leaves etc. that were skipped.  Really, anything prior to the last entry with a proper name weren't really looked at (since at that point overshot the original project).