Graphics and Display Lists
You can’t realistically have a game without graphics on it, so knowing how to make graphics work is essential to any N64 development project. Graphics are created by things called Display Lists (DLs) which are arrays that contain a list of commands for the graphics processor to execute.
NuSystem graphics pipeline
[tbd]N64 Graphics functions
Display lists can contain a wide variety of functions, but they can be boiled down two call types for two processors:
- gSP functions refer to the Signal Processor with a reference to a display list. These deal mostly with things like vertex processing and light calculations.
- gsSP functions refer to the signal processor from within the display list, so they contain no reference to it.
- gDP functions refer to the Display processor with a reference to a display list. These functions work with managing settings, the rendering of textures and even working with the frame buffer and z-buffer.
- gsDP functions refer to the signal processor from within the display list, so they contain no reference to it.
We’ll go through a few examples for display lists below.
Initialising the RCP
Now, in order to get graphics to work, there needs to be some sort of standard settings in order to get things rolling. You can see this in various demos within functions called things like setup_rdpstate
or rdpinit_dl
. The contents of these initialisation DLs depend on the needs of each project you’re working on, but there are some things you might want to keep in there as a standard.
RSP initialisation
Since the RSP deals with most of the graphics processing in 3D environments, there are some functions that are included more than others.
Most demos have a list of functions in a display list to initialise the RSP, with the exception of a few that are exclusively sprite-base like nuhighreso which just displays a bitmap. The typical initialise funtion looks something like this (function parameters removed for simplicity):
Gfx rsp_dl[] = { gsSPViewport(), gsSPClearGeometryMode(), gsSPSetGeometryMode(), gsSPTexture(), gsSPEndDisplayList(), };
There might be a few more functions added on to these, but these 5 seem to be the core of what we’re looking for. Let’s go through what each function is:
gSPViewport
defines the viewport area. This is the area that behaves as your monitor’s ‘screen’ though which you view the scene.
gSPClearGeometryMode
in combination with gsSPSetGeometryMode()
clears and sets the geometry pipeline to make sure that only the required modes are running.
gsSPTexture()
sets the scaling factors for the textures used in the program.
gSPEndDisplayList()
does what it says on the tin; it completes the display list and ends the graphics process.
RDP initialisation
This one is a bit more complicated. The problem tends to be that it depends a lot more on the project itself than the RSP initialisation does. Here is a sample of a typical RDP initialisation display list (function parameters again removed for simplicity):
Gfx rdp_dl[] = { gsDPSetCycleType(), gsDPPipelineMode(), gsDPSetScissor(), gsDPSetRenderMode(), // there are then a bunch of texture-related commands that include (but are not limited to) the following: gsDPSetTextureLOD(), gsDPSetTextureLUT(), gsDPSetTextureDetail(), // and finally a few to finish off the DL: gsDPPipeSync(), gsSPEndDisplayList(), };
Again, this is a very simplified list, but I’ll go through some of the more common ones:
gDPSetCycleType()
sets the general cycle type for the RDP, ie the number of pixels drawn per cycle.
gDPPipelineMode()
determines the span buffer coherency.
gDPSetScissor()
sets the scissor screen mode and size.
The texture settings are to long to enumerate here, will be done on another page.
gDPPipeSync()
tells the RDP to synchronise by waiting for rendering to finish before starting the next command.
gSPEndDisplayList()
tells the RSP to finish the DL and mark it for deletion from the stack.
Other Display Lists
There are many other different kinds of display lists, probably as many as there are ideas for how to display things on screen. The above examples are just some sample functions that you might want to use to set the settings for your program. Play around with the different gSP and gDP functions to see what you can come up with.
Executing a display list
Once you have a DL witten and all set, you need to execute it or else it will just sit there occupying memory and not doing anything. There are a few ways to execute a display list once it has been written. First and foremost is the easiest way: by using nuSystem of course. This is done by using the following function:
void nuGfxTaskStart(Gfx *gfxList_ptr, u32 gfxListSize, u32 ucode, u32 flag)