F3DEX3
Modern microcode for N64 romhacks. Will make you want to finally ditch HLE.
Features
Most important
- 56 verts can fit into DMEM at once, up from 32 verts in F3DEX2, and only 13% below the 64 verts of reject microcodes. This reduces DRAM traffic and RSP time as fewer verts have to be reloaded and re-transformed, and also makes display lists shorter.
New visual features
- New geometry mode bit enables simultaneous vertex colors and normals/lighting on the same object. There is no loss of color precision, and only a fraction of a bit of loss of normals precision in each model space axis. (The competing implementation loses no normals precision, but loses 3 bits of each color channel.)
- New geometry mode bit enables ambient/directional occlusion for opaque materials (vertex alpha multiplies light intensity). Separate factors for how much this affects ambient light and how much it affects all directional lights. Point lights are never affected by ambient occlusion.
- New geometry mode bit moves light intensity to shade alpha (then shade color = vertex color). Useful for cel shading (with alpha compare), bump mapping, or unusual CC effects (e.g. vertex color multiplies texture, lighting applied after).
- New geometry mode bit enables Fresnel. The dot product between a vertex normal and the vector from the vertex to the camera is computed. A settable scale and offset converts this to a shade alpha value. This is useful for making surfaces fade between transparent when viewed straight-on and opaque when viewed at a large angle, or for applying a fake "outline" around the border of meshes.
- New geometry mode bits enable attribute offsets (applied after scale) for Z and ST. For Z, this fixes decal mode. For ST, this enables UV scrolling without CPU intervention.
Improved existing features
- Point lighting redesigned. Improved appearance when light is close to object. Fixed 2*Z bug. Quadratic point light attenuation factor is now an E3M5 floating-point number. The performance penalty for enabling point lighting, and for each additional point light, has been reduced.
- Maximum number of directional / point lights raised from 7 to 9. Minimum
number of directional / point lights lowered from 1 to 0 (F3DEX2 required at
least one). Also supports loading all lights in one DMA transfer
(
SPSetLights), rather than one per light. - Clipped triangles are drawn by minimal overlapping scanlines algorithm; this slightly improves RDP draw time for large tris.
New GBI features
- New
SPTriangleStripandSPTriangleFancommands pack up to 5 tris into one 64-bit GBI command (up from 2 tris in F3DEX2). In any given object, most tris can be drawn with these commands, with only a few at the end drawn withSP2TrianglesorSP1Triangle, so this cuts the triangle portion of display lists roughly in half. - New
SPAlphaCompareCullcommand enables culling of triangles whose computed shade alpha values are all below or above a settable threshold. This substantially reduces the performance penalty of cel shading--only tris which "straddle" the cel threshold are drawn twice, the others are only drawn once. - New
SPLightToRDPfamily of commands (e.g.SPLightToPrimColor) writes a selectable RDP command (e.g.DPSetPrimColor) with the RGB color of a selectable light (any including ambient). The alpha channel and any other parameters are encoded in the command. With some limitations, this allows the tint colors of cel shading to match scene lighting with no code intervention. Possibly useful for other lighting-dependent effects. - New cull flags system replaces
SPBranchZandSPCullDL(these are still supported, but are slower). This system uses a 24 bit flags value kept in DMEM.SPFlagsVerts: Loads up to 32 vertex positions, encoded as XYZ0 shorts (no ST / RGBA). These do not overwrite or affect the vertex buffer. Sets "bit 1" if at least one vert is closer to the camera than the threshold in world coords (i.e. object is close, should use higher LoD). Sets "bit 0" if "bit 1" is set AND if at least one vert is on the screen side of each clip plane (i.e. object is close enough and not culled due to offscreen). The shift of "bit 0" / "bit 1" within the flags word is selected by a field in the command.SPFlags1Vert: Same asSPFlagsVerts, but for one vertex only, which is encoded in the command instead of taking a DMA transfer.SPFlagsDist: Sets the distance threshold in the RDP generic word (G_RDPHALF_1). The only other commands which overwrite this areSPBranchLessZ*,SPLoadUcode*,SP*TextureRectangle*,DPWord, andSPPerspNormalize.SPFlagsLoad/SPFlagsSet/SPFlagsClear/SPFlagsModify: All the same underlying instructionSPFlagsMasks. Instruction contains a 24 bit mask which is ANDed with the flags word, and then a 24 bit mask which is ORed with the flags word.SPFlagsLoadclears all flags then sets selected flags.SPFlagsSetjust sets the selected flags andSPFlagsClearjust clears the selected flags.SPFlagsModifysets flags within a selectable group.SPFlagsDram: Loads 64 bits from the given segmented address, and then applies it to the flags as an AND and OR mask like the previous instruction.SPCullFlagsNone,SPCullFlagsSome,SPCullFlagsAll,SPCullFlagsNotAll: 24 bit mask. Cull (SPEndDisplayList) if none, some (at least one), all, or not all (at least one clear) of the flags within the mask are set.SPBranchFlagsNone,SPBranchFlagsSome,SPBranchFlagsAll,SPBranchFlagsNotAll: same but branch (jump) to segmented address.SPCallFlagsNone,SPCallFlagsSome,SPCallFlagsAll,SPCallFlagsNotAll: same but call segmented address.
Usage
C GBI Backwards Compatibility with F3DEX2
F3DEX3 is backwards compatible with F3DEX2 at the C GBI level for all commands except:
G_LINE3D(andGfx.line) has been removed. This command did not actually work in F3DEX2 (it behaved as a no-op).G_MW_CLIPhas been removed, andg*SPClipRatiohas been converted into a no-op. Clipping is handled differently in F3DEX3 and cannot be changed from 2.G_MV_MATRIXandG_MW_FORCEMTXhave been removed, andg*SPForceMatrixhas been converted into a no-op. This is because there is no MVP matrix in F3DEX3.G_MVO_LOOKATXandG_MVO_LOOKATYhave been removed, andg*SPLookAtXandg*SPLookAtYare deprecated.g*SPLookAtXhas been changed to set both directions andg*SPLookAtYhas been converted to a no-op. To set the lookat directions, useg*SPLookAt. The lookat directions are now in one 8-byte DMA word, so they must always be set at the same time as each other. Most of the non-functional fields (e.g. color) ofLookAtand its sub-types have been removed, so code which accesses these fields needs to change. Code which only accesses lookat directions should be compatible with no changes.- TODO update:
g*SPLightcannot be used to load an ambient light into light 7 (LIGHT_8). It can be used to load directional, point, or ambient lights into lights 0-6 (LIGHT_1throughLIGHT_7). To load an ambient light into light 7 (LIGHT_8) (or to load an ambient light into any slot), useg*SPAmbient. Note that you can now load all your lights with one command,g*SPSetLights; there is no need to set them one-at-a-time withg*SPLight(though you can). G_MV_POINThas been removed. This was not used in any command; it would have likely been used for debugging to copy vertices from DMEM to examine them. This does not affectg*SPModifyVertex, which is still supported.
ucode_disas.c and lookathil.c in OoT need relatively minor fixes due to
using removed things. The rest of the OoT codebase does not need code changes.
Binary Display List Backwards Compatibility with F3DEX2
F3DEX3 is generally binary backwards compatible with OoT-style display lists for
objects, scenes, etc. It is not compatible at the binary level with SM64-style
display lists which encode object colors as light colors, as all the command
encodings related to lighting have changed. Of course, if you recompile these
display lists with the new gbi.h, it can run them.
The deprecated commands mentioned above in the C GBI section have had their encodings changed (the original encodings will do bad things / crash). In addition, the following other commands have had their encodings changed, making them binary incompatible:
- All lighting-related commands, e.g.
gdSPDefLights*,g*SPNumLights,g*SPLight,g*SPLightColor,g*SPSetLights*,g*SPLookAt. The basic lighting data structuresLight_t,PosLight_t, andAmbient_thave not changed, butLookAt_tand all the larger data structures such asLightsn,Lights*, andPosLights*have changed. g*SPPerspNormalizebinary encoding has changed.