Clone wiki

z64-tex-ext / Home

About

z64-tex-ext is an extension of the map format used in N64 Zeldas. What it's basic function is to load and execute code specified in the map header's mesh header command. Normally, a mesh header is something like 0A000000 mmmmmmmm where m is the address of the mesh data header. The 24-bits after the 0x0A command are usually ignored - this is where this extension comes in. z64-tex-ext uses those 24 bits as an offset of code to execute, assumed to be the same segment (also known as bank) as the offset of the mesh data header, m. Thus, if a version of the game does not have z64-tex-ext ported to it, the map still runs, as the bits used for the offset of the code are normally ignored by the engine. This extension was created with the intention of making animated textures possible in imported maps, for things such as windows which light up at night, or scrolling water textures. However, it has many other possible uses.

Utilizing the extension

The extension is loaded under the circumstances that:

  • It uses the first entry in the jump table for scene-specific functions (most test maps, and maps with no special properties usually use this)
  • The code is properly pointed to in the mesh header command

It is loaded to unused memory whenever the map's header offset changes, and is executed that time and each frame afterwards. The current implementation loads the data to 0x80600000.

Arguments

Whenever the user's function is called, it is passed one argument - a pointer to the global context, commonly referred to here as z_ctxt. It is used for an argument in many, many functions, including some of the built in ones.

Built in functions

To use these functions, be sure to include help_funcs.h in your source and include extern.ld (produced when z64-tex-ext is built)
CVT_SEG_PTR
CVT_SEG_PTR( uint32_t segmented_address )
While actually a macro and not a function, this is part of the helper functions provided by z64-tex-ext. It takes a segmented address (form bboooooo) and converts it to a RAM pointer (form 80xxxxxx). This is useful when converting something from a map or scene pointer to a specific address to use in a gSPSegment command.
Calls seg_to_ram.

seg_to_ram
void * seg_to_ram( int seg );
Gives the RAM pointer of segment seg

dl_write
void dl_write( void *z_ctxt, uint32_t w0, uint32_t w1);
Writes a display list command to the current display list of z_ctxt, consisting of the 32-bit words w0 and w1

set_segment
void set_segment( void *z_ctxt, int seg, void *ptr );
Sets segment seg to address ptr in the current display list used by z_ctxt.

Porting to other games

You'll probably have to poke around in RAM to get some addresses - try finding the scene table bytes which control which jump table entry is read and break-pointing that data. It should point you in the right direction. As for finding the location of the segment table... Locate the map, scene, or gameplay_keep in RAM and search for their ram offsets & 0xFFFFFF - their high 8 bits are omitted for some reason in the segment table. You'll probably get multiple results; but something that is like this is probably it:
00000000 00000000 ssssssss mmmmmmmm
gggggggg ( ... )
Where s is the scene's offset, m is the map's offset, and g is gameplay_keep's offset. Do keep in mind that the map offset is not necessarily the same one as pointed to by map_ptr_ptr (see global.ld), as that pointer is to the current map header.

And remember, patches would be greatly appreciated if you do indeed port to another game. Feel free to fork it if you want to do it that way.

Updated