F3DEX3
Loading...
Searching...
No Matches
gbi.h File Reference

Modded GBI for use with F3DEX3 custom microcode. More...

#include "ultra64/mbi.h"
Include dependency graph for gbi.h:

Go to the source code of this file.

Data Structures

struct  Vtx_t
 
struct  Vtx_tn
 
union  Vtx
 
struct  Tri
 
struct  Vp_t
 
struct  Light_t
 
struct  PointLight_t
 
struct  Ambient_t
 
struct  Gdma
 
struct  Gdma2
 
struct  Gmovewd
 
struct  Gmovemem
 
struct  Gtri
 
struct  Gsetimg
 
struct  TexRect
 
struct  Gwords
 
union  Gfx
 

Macros

#define G_MTX_MODELVIEW   0x00 /* matrix types */
 specifies whether the matrix operation will be performed on the projection or the model view matrix.
 
#define G_MTX_PROJECTION   0x04
 specifies whether the matrix operation will be performed on the projection or the model view matrix.
 
#define G_MTX_MUL   0x00 /* concat or load */
 concatenates the matrix (m) with the top of the matrix stack.
 
#define G_MTX_LOAD   0x02
 loads the matrix (m) onto the top of the matrix stack.
 
#define G_MTX_NOPUSH   0x00 /* push or not */
 specifies do not push the matrix stack prior to matrix operations
 
#define G_MTX_PUSH   0x01
 specifies push the matrix stack prior to matrix operations
 
#define G_MWO_POINT_RGBA   0x10
 changes the color of the vertex. The val parameter is interpreted as 4 bytes: red (high byte), green, blue, and alpha (low byte).
 
#define G_MWO_POINT_ST   0x14
 changes the S and T values (texture coordinates of the vertex). The high 16 bits of val specify the S coordinate, and the low 16 bits specify the T coordinate. Each coordinate is an S10.5 number.
 
#define G_MWO_POINT_XYSCREEN   0x18
 change the screen coordinates of the vertex. The high 16 bits of val specify the X coordinate and the low 16 bits specify the Y coordinate. Both coordinates are S13.2 numbers with 0,0 being the upper-left of the screen, positive X going right, and positive Y going down.
 
#define G_MWO_POINT_ZSCREEN   0x1C
 changes the screen Z coordinate of the vertex. The entire 32-bit val is taken as the new screen Z value. It is a 16.16 number in the range 0x00000000 to 0x03ff0000.
 
#define gSPMatrix(pkt, m, p)    gDma2p((pkt),G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0)
 macro which inserts a matrix operation at the end display list.
 
#define gsSPMatrix(m, p)    gsDma2p( G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0)
 macro which inserts a matrix operation in a static display list.
 
#define gSPPopMatrixN(pkt, n, num)   gDma2p((pkt), G_POPMTX, (num) * 64, 64, 2, 0)
 macro which pops one of the matrix stacks at the end display list.
 
#define gsSPPopMatrixN(n, num)   gsDma2p( G_POPMTX, (num) * 64, 64, 2, 0)
 macro which pops one of the matrix stacks in a static display list.
 
#define gSPPopMatrix(pkt, n)   gSPPopMatrixN((pkt), (n), 1)
 macro which pops one of the matrix stacks at the end display list.
 
#define gsSPPopMatrix(n)   gsSPPopMatrixN( (n), 1)
 macro which pops one of the matrix stacks in a static display list.
 
#define gSPVertex(pkt, v, n, v0)
 macro which loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons at the end display list.
 
#define gsSPVertex(v, n, v0)
 macro which loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons in a static display list.
 
#define gSPDisplayListHint(pkt, dl, count)   _gSPDisplayListRaw(pkt, dl, _DLHINTVALUE(count))
 
#define gsSPDisplayListHint( dl, count)   _gsSPDisplayListRaw( dl, _DLHINTVALUE(count))
 
#define gSPBranchListHint(pkt, dl, count)   _gSPBranchListRaw( pkt, dl, _DLHINTVALUE(count))
 
#define gsSPBranchListHint( dl, count)   _gsSPBranchListRaw( dl, _DLHINTVALUE(count))
 
#define gSPEndDisplayListHint(pkt, count)   _gSPEndDisplayListRaw( pkt, _DLHINTVALUE(count))
 
#define gsSPEndDisplayListHint( count)   _gsSPEndDisplayListRaw( _DLHINTVALUE(count))
 
#define gSPDisplayList(pkt, dl)   _gSPDisplayListRaw(pkt, dl, 0)
 
#define gsSPDisplayList( dl)   _gsSPDisplayListRaw( dl, 0)
 
#define gSPBranchList(pkt, dl)   _gSPBranchListRaw( pkt, dl, 0)
 
#define gsSPBranchList( dl)   _gsSPBranchListRaw( dl, 0)
 
#define gSPEndDisplayList(pkt)   _gSPEndDisplayListRaw( pkt, 0)
 
#define gsSPEndDisplayList()   _gsSPEndDisplayListRaw( 0)
 
#define gSPLoadUcodeEx(pkt, uc_start, uc_dstart, uc_dsize)
 
#define gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize)
 
#define gSPDma_io(pkt, flag, dmem, dram, size)
 
#define gsSPDma_io(flag, dmem, dram, size)
 
#define gSPMemset(pkt, dram, value, size)
 
#define gsSPMemset(pkt, dram, value, size)
 
#define gImmp0(pkt, c)
 
#define gsImmp0(c)
 
#define gSP1Triangle(pkt, v0, v1, v2, flag)
 
#define gsSP1Triangle(v0, v1, v2, flag)
 
#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag)
 
#define gsSP1Quadrangle(v0, v1, v2, v3, flag)
 
#define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1)
 
#define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1)
 
#define gSPTriStrip(pkt, v1, v2, v3, v4, v5, v6, v7)    _gSP5Triangles(pkt, G_TRISTRIP, v1, v2, v3, v4, v5, v6, v7)
 
#define gsSPTriStrip(v1, v2, v3, v4, v5, v6, v7)    _gsSP5Triangles(G_TRISTRIP, v1, v2, v3, v4, v5, v6, v7)
 
#define gSPTriFan(pkt, v1, v2, v3, v4, v5, v6, v7)    _gSP5Triangles(pkt, G_TRIFAN, v1, v2, v3, v4, v5, v6, v7)
 
#define gsSPTriFan(v1, v2, v3, v4, v5, v6, v7)    _gsSP5Triangles(G_TRIFAN, v1, v2, v3, v4, v5, v6, v7)
 
#define gSPClipRatio(pkt, r)   gSPNoOp(pkt)
 Clipping Macros.
 
#define gsSPClipRatio(r)   gsSPNoOp()
 Clipping Macros.
 
#define gSPForceMatrix(pkt, mptr)   gSPNoOp(pkt)
 Load new MVP matrix directly.
 
#define gsSPForceMatrix(mptr)   gsSPNoOp()
 Load new MVP matrix directly.
 
#define gSPAmbOcclusionAmb(pkt, amb)   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_AMBIENT, amb)
 
#define gsSPAmbOcclusionAmb(amb)   gsMoveHalfwd( G_MW_FX, G_MWO_AO_AMBIENT, amb)
 
#define gSPAmbOcclusionDir(pkt, dir)   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_DIRECTIONAL, dir)
 
#define gsSPAmbOcclusionDir(dir)   gsMoveHalfwd( G_MW_FX, G_MWO_AO_DIRECTIONAL, dir)
 
#define gSPAmbOcclusionPoint(pkt, point)   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_POINT, point)
 
#define gsSPAmbOcclusionPoint(point)   gsMoveHalfwd( G_MW_FX, G_MWO_AO_POINT, point)
 
#define gSPFresnelScale(pkt, scale)    gMoveHalfwd(pkt, G_MW_FX, G_MWO_FRESNEL_SCALE, scale)
 
#define gsSPFresnelScale(scale)    gsMoveHalfwd(G_MW_FX, G_MWO_FRESNEL_SCALE, scale)
 
#define gSPFresnelOffset(pkt, offset)    gMoveHalfwd(pkt, G_MW_FX, G_MWO_FRESNEL_OFFSET, offset)
 
#define gsSPFresnelOffset(offset)    gsMoveHalfwd(G_MW_FX, G_MWO_FRESNEL_OFFSET, offset)
 
#define gSPFresnel(pkt, scale, offset)
 
#define gsSPFresnel(scale, offset)
 
#define gSPAttrOffsetST(pkt, s, t)
 
#define gsSPAttrOffsetST(s, t)
 
#define gSPAttrOffsetZ(pkt, z)    gMoveHalfwd(pkt, G_MW_FX, G_MWO_ATTR_OFFSET_Z, z)
 
#define gsSPAttrOffsetZ(z)    gsMoveHalfwd(G_MW_FX, G_MWO_ATTR_OFFSET_Z, z)
 
#define gSPAlphaCompareCull(pkt, mode, thresh)
 
#define gsSPAlphaCompareCull(mode, thresh)
 
#define gSPNormalsMode(pkt, mode)    gMoveHalfwd(pkt, G_MW_FX, G_MWO_NORMALS_MODE, (mode) & 0xFF)
 
#define gsSPNormalsMode(mode)    gsMoveHalfwd(G_MW_FX, G_MWO_NORMALS_MODE, (mode) & 0xFF)
 
#define gSPDontSkipTexLoadsAcross(pkt)    gMoveWd(pkt, G_MW_FX, G_MWO_LAST_MAT_DL_ADDR, 0xFFFFFFFF)
 
#define gsSPDontSkipTexLoadsAcross()    gsMoveWd(G_MW_FX, G_MWO_LAST_MAT_DL_ADDR, 0xFFFFFFFF)
 
#define gSPMITMatrix(pkt, mit)    gDma2p((pkt), G_MOVEMEM, (mit), sizeof(MITMtx), G_MV_MMTX, 0x80)
 
#define gsSPMITMatrix(mtx)    gsDma2p( G_MOVEMEM, (mit), sizeof(MITMtx), G_MV_MMTX, 0x80)
 
#define gSPModifyVertex(pkt, vtx, where, val)
 You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro).
 
#define gsSPModifyVertex(vtx, where, val)
 You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro).
 
#define gSPCullDisplayList(pkt, vstart, vend)
 
#define gsSPCullDisplayList(vstart, vend)
 
#define gSPBranchLessZraw(pkt, dl, vtx, zval)
 
#define gsSPBranchLessZraw(dl, vtx, zval)
 
#define gSPNumLights(pkt, n)    gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))
 
#define gsSPNumLights(n)    gsMoveWd( G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))
 
#define gSPLight(pkt, l, n)    gDma2p((pkt), G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))
 
#define gsSPLight(l, n)    gsDma2p( G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))
 
#define gSPAmbient(pkt, l, n)    gDma2p((pkt), G_MOVEMEM, (l), sizeof(Ambient), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))
 
#define gsSPAmbient(l, n)    gsDma2p( G_MOVEMEM, (l), sizeof(Ambient), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))
 
#define gSPLightColor(pkt, n, col)
 
#define gsSPLightColor(n, col)
 
#define gSPSetLights(pkt, n, name)
 
#define gsSPSetLights(n, name)
 
#define gSPCameraWorld(pkt, cam)    gDma2p((pkt), G_MOVEMEM, (cam), sizeof(PlainVtx), G_MV_LIGHT, 0)
 
#define gsSPCameraWorld(cam)    gsDma2p( G_MOVEMEM, (cam), sizeof(PlainVtx), G_MV_LIGHT, 0)
 
#define gSPLookAt(pkt, la)    gDma2p((pkt), G_MOVEMEM, (la), sizeof(LookAt), G_MV_LIGHT, 8)
 
#define gsSPLookAt(la)    gsDma2p( G_MOVEMEM, (la), sizeof(LookAt), G_MV_LIGHT, 8)
 
#define gSPLookAtX(pkt, l)   gSPLookAt(pkt, l)
 
#define gsSPLookAtX(l)   gsSPLookAt(l)
 
#define gSPLookAtY(pkt, l)   gSPNoOp(pkt)
 
#define gsSPLookAtY(l)   gsSPNoOp()
 
#define gSPOcclusionPlane(pkt, o)
 
#define gsSPOcclusionPlane(o)
 
#define gSPFogFactor(pkt, fm, fo)
 
#define gsSPFogFactor(fm, fo)
 
#define gSPTexture(pkt, s, t, level, tile, on)
 
#define gsSPTexture(s, t, level, tile, on)
 
#define gSPTextureL(pkt, s, t, level, bowtie, tile, on)    gSPTexture(pkt, s, t, level, tile, on)
 
#define gsSPTextureL(s, t, level, bowtie, tile, on)    gsSPTexture(s, t, level, tile, on)
 
#define gSPGeometryMode(pkt, c, s)
 
#define gsSPGeometryMode(c, s)
 
#define gDPPipelineMode(pkt, mode)    gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
 
#define gsDPPipelineMode(mode)    gsSPSetOtherMode( G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)
 
#define gDPSetBlendMask(pkt, mask)   gSPNoOp(pkt)
 
#define gsDPSetBlendMask(mask)   gsSPNoOp()
 
#define gDPSetCombineMode(pkt, a, b)   gDPSetCombineLERP(pkt, a, b)
 
#define gsDPSetCombineMode(a, b)   gsDPSetCombineLERP( a, b)
 
#define gSPLightToRDP(pkt, light, alpha, word0)
 
#define gsSPLightToRDP(light, alpha, word0)
 
#define gDPSetOtherMode(pkt, mode0, mode1)
 
#define gsDPSetOtherMode(mode0, mode1)
 
#define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadMultiTile(pkt, timg, tmem, rtile, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiTile(timg, tmem, rtile, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadMultiTile_4b(pkt, timg, tmem, rtile, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gsDPLoadMultiTile_4b(timg, tmem, rtile, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt)
 
#define gDPLoadTLUT_pal16(pkt, pal, dram)
 
#define gsDPLoadTLUT_pal16(pal, dram)
 
#define gDPLoadTLUT_pal256(pkt, dram)
 
#define gsDPLoadTLUT_pal256(dram)
 
#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy)
 
#define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy)
 

Typedefs

typedef long int Mtx_t[4][4]
 

Detailed Description

Modded GBI for use with F3DEX3 custom microcode.

Macro Definition Documentation

◆ G_MWO_POINT_XYSCREEN

#define G_MWO_POINT_XYSCREEN   0x18

change the screen coordinates of the vertex. The high 16 bits of val specify the X coordinate and the low 16 bits specify the Y coordinate. Both coordinates are S13.2 numbers with 0,0 being the upper-left of the screen, positive X going right, and positive Y going down.

Deprecated
to use, won't work if the tri gets clipped.

◆ G_MWO_POINT_ZSCREEN

#define G_MWO_POINT_ZSCREEN   0x1C

changes the screen Z coordinate of the vertex. The entire 32-bit val is taken as the new screen Z value. It is a 16.16 number in the range 0x00000000 to 0x03ff0000.

Deprecated
to use, won't work if the tri gets clipped.

◆ gDPLoadMultiBlock

#define gDPLoadMultiBlock ( pkt,
timg,
tmem,
rtile,
fmt,
siz,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadBlock(pkt, _G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \
CALC_DXT(width, siz##_BYTES)); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, siz, \
(((width) * siz##_LINE_BYTES) + 7) >> 3, tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts); \
gDPSetTileSize(pkt, rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC); \
})

allows tmem address and render tile to be specified

◆ gDPLoadMultiBlock_4b

#define gDPLoadMultiBlock_4b ( pkt,
timg,
tmem,
rtile,
fmt,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadBlock(pkt, _G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + 3) >> 2) - 1, \
CALC_DXT_4b(width)); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \
((((width) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts); \
gDPSetTileSize(pkt, rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC); \
})

4-bit load block. Useful when loading multiple tiles

◆ gDPLoadMultiBlock_4bS

#define gDPLoadMultiBlock_4bS ( pkt,
timg,
tmem,
rtile,
fmt,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \
gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadBlock(pkt, _G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + 3) >> 2) - 1, \
0); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \
((((width) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts); \
gDPSetTileSize(pkt, rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC); \
})

4-bit load block. Allows tmem and render tile to be specified. Useful when loading multiple tiles. The S means odd lines are already word swapped.

◆ gDPLoadMultiBlockS

#define gDPLoadMultiBlockS ( pkt,
timg,
tmem,
rtile,
fmt,
siz,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \
gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadBlock(pkt, _G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1,0); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, siz, \
(((width) * siz##_LINE_BYTES) + 7) >> 3, tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, \
shifts); \
gDPSetTileSize(pkt, rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC); \
})

Allow tmem address and render tile to be specified. The S at the end means odd lines are already word Swapped

◆ gDPLoadMultiTile

#define gDPLoadMultiTile ( pkt,
timg,
tmem,
rtile,
fmt,
siz,
width,
height,
uls,
ult,
lrs,
lrt,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, siz, width, timg); \
gDPSetTile(pkt, fmt, siz, \
(((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), tmem, \
_G_TEXLOADTILE(rtile), 0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadTile(pkt, _G_TEXLOADTILE(rtile), \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, siz, \
(((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts); \
gDPSetTileSize(pkt, rtile, \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC); \
})

Load texture tile. Allows tmem address and render tile to be specified. Useful for loading multiple tiles.

◆ gDPLoadMultiTile_4b

#define gDPLoadMultiTile_4b ( pkt,
timg,
tmem,
rtile,
fmt,
width,
height,
uls,
ult,
lrs,
lrt,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
_DW({ \
gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width) >> 1), timg); \
gDPSetTile(pkt, fmt, G_IM_SIZ_8b, \
(((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, \
_G_TEXLOADTILE(rtile), 0, cmt, maskt, shiftt, cms, masks, shifts); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadTile(pkt, _G_TEXLOADTILE(rtile), \
(uls) << (G_TEXTURE_IMAGE_FRAC - 1), \
(ult) << (G_TEXTURE_IMAGE_FRAC), \
(lrs) << (G_TEXTURE_IMAGE_FRAC - 1), \
(lrt) << (G_TEXTURE_IMAGE_FRAC)); \
gDPPipeSyncInTexLoad(pkt); \
gDPSetTile(pkt, fmt, G_IM_SIZ_4b, \
(((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts); \
gDPSetTileSize(pkt, rtile, \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC); \
})

Load texture tile. Allows tmem address and render tile to be specified. Useful for loading multiple tiles.

◆ gDPLoadTLUT_pal16

#define gDPLoadTLUT_pal16 ( pkt,
pal,
dram )
Value:
_DW({ \
gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
gDPTileSyncInTexLoad(pkt); \
gDPSetTile(pkt, 0, 0, 0, (256 + (((pal) & 0xF) * 16)), \
_G_PALLOADTILE((pal) & 1), 0, 0, 0, 0, 0, 0, 0); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadTLUTCmd(pkt, _G_PALLOADTILE((pal) & 1), 15); \
gDPPipeSyncInTexLoad(pkt); \
})

Load a 16-entry palette (for 4-bit CI textures) Assumes a 16 entry tlut is being loaded, palette # is 0-15 With NO_SYNCS_IN_TEXTURE_LOADS: assumes that palette 0 is for multitexture texture 0 and palette 1 is for texture 1 (uses load tiles 5 and 4)

◆ gDPLoadTLUT_pal256

#define gDPLoadTLUT_pal256 ( pkt,
dram )
Value:
_DW({ \
gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \
gDPTileSyncInTexLoad(pkt); \
gDPSetTile(pkt, 0, 0, 0, 256, \
_G_PALLOADTILE(0), 0, 0, 0, 0, 0, 0, 0); \
gDPLoadSyncInTexLoad(pkt); \
gDPLoadTLUTCmd(pkt, _G_PALLOADTILE(0), 255); \
gDPPipeSyncInTexLoad(pkt); \
})

Load a 256-entry palette (for 8-bit CI textures) Assumes a 256 entry tlut is being loaded, palette # is not used

◆ gDPPipelineMode

#define gDPPipelineMode ( pkt,
mode )    gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)

RDP setothermode register commands - register shadowed in RSP

◆ gDPSetBlendMask

#define gDPSetBlendMask ( pkt,
mask )   gSPNoOp(pkt)

'blendmask' is not supported anymore. The bits are reserved for future use. Fri May 26 13:45:55 PDT 1995

Deprecated

◆ gDPSetCombineMode

#define gDPSetCombineMode ( pkt,
a,
b )   gDPSetCombineLERP(pkt, a, b)

SetCombineMode macros are NOT redunant. It allow the C preprocessor to substitute single parameter which includes commas in the token and rescan for higher parameter count macro substitution.

eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0)

◆ gDPSetOtherMode

#define gDPSetOtherMode ( pkt,
mode0,
mode1 )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_RDPSETOTHERMODE, 24, 8) | \
_SHIFTL(mode0, 0, 24)); \
_g->words.w1 = (unsigned int)(mode1); \
})
Definition gbi.h:2001

gDPSetOtherMode (This is for expert user.)

This command makes all othermode parameters set. Do not use this command in the same DL with another g*SPSetOtherMode DLs.

[Usage] gDPSetOtherMode(pkt, modeA, modeB)

'modeA' is described all parameters of GroupA GBI command.
'modeB' is also described all parameters of GroupB GBI command.

GroupA: gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp, gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT, gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey, gDPSetColorDither, gDPSetAlphaDither

GroupB: gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode

Use 'OR' operation to get modeA and modeB.

modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_* G_TC_* | G_CK_* | G_CD_* | G_AD_*;

modeB = G_AC_* | G_ZS_* | G_RM_* | G_RM_*2;

◆ gDPTextureRectangle

#define gDPTextureRectangle ( pkt,
xl,
yl,
xh,
yh,
tile,
s,
t,
dsdx,
dtdy )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
if (pkt); \
_g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | \
_SHIFTL(xh, 12, 12) | \
_SHIFTL(yh, 0, 12)); \
_g->words.w1 = (_SHIFTL(tile, 24, 3) | \
_SHIFTL(xl, 12, 12) | \
_SHIFTL(yl, 0, 12)); \
_g ++; \
_g->words.w0 = (_SHIFTL(s, 16, 16) | \
_SHIFTL(t, 0, 16)); \
_g->words.w1 = (_SHIFTL(dsdx, 16, 16) | \
_SHIFTL(dtdy, 0, 16)); \
})

Notice that textured rectangles are 128-bit commands, therefore gsDPTextureRectangle() should not be used in display lists under normal circumstances (use gsSPTextureRectangle()). That is also why there is no gDPTextureRectangle() macros.

◆ gImmp0

#define gImmp0 ( pkt,
c )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL((c), 24, 8); \
})

RSP short command (no DMA required) macros

◆ gsDPLoadMultiBlock

#define gsDPLoadMultiBlock ( timg,
tmem,
rtile,
fmt,
siz,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadBlock(_G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \
CALC_DXT(width, siz##_BYTES)), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, siz, \
((((width) * siz##_LINE_BYTES) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC)

Allow tmem address and render_tile to be specified, useful when loading mutilple tiles at a time.

◆ gsDPLoadMultiBlock_4b

#define gsDPLoadMultiBlock_4b ( timg,
tmem,
rtile,
fmt,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadBlock(_G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + 3) >> 2) - 1, \
CALC_DXT_4b(width)), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, G_IM_SIZ_4b, \
((((width) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, 0, 0, \
((width)-1) << G_TEXTURE_IMAGE_FRAC, \
((height)-1) << G_TEXTURE_IMAGE_FRAC)

4-bit load block. Allows tmem address and render tile to be specified. Useful when loading multiple tiles.

◆ gsDPLoadMultiBlock_4bS

#define gsDPLoadMultiBlock_4bS ( timg,
tmem,
rtile,
fmt,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \
gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadBlock(_G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + 3) >> 2) - 1, \
0), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, G_IM_SIZ_4b, \
((((width) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC)

4-bit load block. Allows tmem address and render tile to be specified. Useful when loading multiple tiles. S means odd lines are already swapped.

◆ gsDPLoadMultiBlockS

#define gsDPLoadMultiBlockS ( timg,
tmem,
rtile,
fmt,
siz,
width,
height,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \
gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, _G_TEXLOADTILE(rtile), \
0, cmt, maskt,shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadBlock(_G_TEXLOADTILE(rtile), 0, 0, \
(((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, siz, \
((((width) * siz##_LINE_BYTES) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, 0, 0, \
((width) - 1) << G_TEXTURE_IMAGE_FRAC, \
((height) - 1) << G_TEXTURE_IMAGE_FRAC)

Allows tmem and render tile to be specified. Useful when loading several tiles at a time.

Here is the static form of the pre-swapped texture block loading See gDPLoadTextureBlockS() for reference. Basically, just don't calculate DxT, use 0

◆ gsDPLoadMultiTile

#define gsDPLoadMultiTile ( timg,
tmem,
rtile,
fmt,
siz,
width,
height,
uls,
ult,
lrs,
lrt,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
gsDPSetTextureImage(fmt, siz, width, timg), \
gsDPSetTile(fmt, siz, \
(((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), tmem, \
_G_TEXLOADTILE(rtile), 0, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadTile(_G_TEXLOADTILE(rtile), \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, siz, \
(((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), \
tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC)

Load texture tile. Allows tmem address and render tile to be specified. Useful for loading multiple tiles.

◆ gsDPLoadMultiTile_4b

#define gsDPLoadMultiTile_4b ( timg,
tmem,
rtile,
fmt,
width,
height,
uls,
ult,
lrs,
lrt,
pal,
cms,
cmt,
masks,
maskt,
shifts,
shiftt )
Value:
\
gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width) >> 1), timg), \
gsDPSetTile(fmt, G_IM_SIZ_8b, \
(((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, \
_G_TEXLOADTILE(rtile), 0, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPLoadSyncInTexLoad \
gsDPLoadTile(_G_TEXLOADTILE(rtile), \
(uls) << (G_TEXTURE_IMAGE_FRAC - 1), \
(ult) << (G_TEXTURE_IMAGE_FRAC), \
(lrs) << (G_TEXTURE_IMAGE_FRAC - 1), \
(lrt) << (G_TEXTURE_IMAGE_FRAC)), \
gsDPPipeSyncInTexLoad \
gsDPSetTile(fmt, G_IM_SIZ_4b, \
(((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, \
rtile, pal, cmt, maskt, shiftt, cms, masks, shifts), \
gsDPSetTileSize(rtile, \
(uls) << G_TEXTURE_IMAGE_FRAC, \
(ult) << G_TEXTURE_IMAGE_FRAC, \
(lrs) << G_TEXTURE_IMAGE_FRAC, \
(lrt) << G_TEXTURE_IMAGE_FRAC)

Load texture tile. Allows tmem address and render tile to be specified. Useful for loading multiple tiles.

◆ gsDPLoadTLUT_pal16

#define gsDPLoadTLUT_pal16 ( pal,
dram )
Value:
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
gsDPTileSyncInTexLoad \
gsDPSetTile(0, 0, 0, (256 + (((pal) & 0xF) * 16)), \
_G_PALLOADTILE((pal) & 1), 0, 0, 0, 0, 0, 0, 0), \
gsDPLoadSyncInTexLoad \
gsDPLoadTLUTCmd(_G_PALLOADTILE((pal) & 1), 15) \
gsDPPipeSyncEndOfTexLoad

Load a 16-entry palette (for 4-bit CI textures) Assumes a 16 entry tlut is being loaded, palette # is 0-15 With NO_SYNCS_IN_TEXTURE_LOADS: assumes that palette 0 is for multitexture texture 0 and palette 1 is for texture 1 (uses load tiles 5 and 4)

◆ gsDPLoadTLUT_pal256

#define gsDPLoadTLUT_pal256 ( dram)
Value:
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), \
gsDPTileSyncInTexLoad \
gsDPSetTile(0, 0, 0, 256, \
_G_PALLOADTILE(0), 0, 0, 0, 0, 0, 0, 0), \
gsDPLoadSyncInTexLoad \
gsDPLoadTLUTCmd(_G_PALLOADTILE(0), 255) \
gsDPPipeSyncEndOfTexLoad

Load a 256-entry palette (for 8-bit CI textures) Assumes a 256 entry tlut is being loaded, palette # is not used

◆ gsDPPipelineMode

#define gsDPPipelineMode ( mode)     gsSPSetOtherMode( G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode)

RDP setothermode register commands - register shadowed in RSP

◆ gsDPSetBlendMask

#define gsDPSetBlendMask ( mask)    gsSPNoOp()

'blendmask' is not supported anymore. The bits are reserved for future use. Fri May 26 13:45:55 PDT 1995

Deprecated

◆ gsDPSetCombineMode

#define gsDPSetCombineMode ( a,
b )   gsDPSetCombineLERP( a, b)

SetCombineMode macros are NOT redunant. It allow the C preprocessor to substitute single parameter which includes commas in the token and rescan for higher parameter count macro substitution.

eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0)

◆ gsDPSetOtherMode

#define gsDPSetOtherMode ( mode0,
mode1 )
Value:
{ \
(_SHIFTL(G_RDPSETOTHERMODE, 24, 8) | \
_SHIFTL(mode0, 0, 24)), \
(unsigned int)(mode1) \
}

gDPSetOtherMode (This is for expert user.)

This command makes all othermode parameters set. Do not use this command in the same DL with another g*SPSetOtherMode DLs.

[Usage] gDPSetOtherMode(pkt, modeA, modeB)

'modeA' is described all parameters of GroupA GBI command.
'modeB' is also described all parameters of GroupB GBI command.

GroupA: gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp, gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT, gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey, gDPSetColorDither, gDPSetAlphaDither

GroupB: gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode

Use 'OR' operation to get modeA and modeB.

modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_* G_TC_* | G_CK_* | G_CD_* | G_AD_*;

modeB = G_AC_* | G_ZS_* | G_RM_* | G_RM_*2;

◆ gsDPTextureRectangle

#define gsDPTextureRectangle ( xl,
yl,
xh,
yh,
tile,
s,
t,
dsdx,
dtdy )
Value:
{ \
(_SHIFTL(G_TEXRECT, 24, 8) | \
_SHIFTL(xh, 12, 12) | \
_SHIFTL(yh, 0, 12)), \
(_SHIFTL(tile, 24, 3) | \
_SHIFTL(xl, 12, 12) | \
_SHIFTL(yl, 0, 12)), \
}, \
{ \
(_SHIFTL(s, 16, 16) | \
_SHIFTL(t, 0, 16)), \
(_SHIFTL(dsdx, 16, 16) | \
_SHIFTL(dtdy, 0, 16)) \
}

Notice that textured rectangles are 128-bit commands, therefore gsDPTextureRectangle() should not be used in display lists under normal circumstances (use gsSPTextureRectangle()). That is also why there is no gDPTextureRectangle() macros.

◆ gsImmp0

#define gsImmp0 ( c)
Value:
{ \
_SHIFTL((c), 24, 8) \
}

RSP short command (no DMA required) macros

◆ gSP1Quadrangle

#define gSP1Quadrangle ( pkt,
v0,
v1,
v2,
v3,
flag )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL(G_QUAD, 24, 8) | \
__gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \
_g->words.w1 = (__gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag)); \
})

1 Quadrangle

◆ gSP1Triangle

#define gSP1Triangle ( pkt,
v0,
v1,
v2,
flag )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL(G_TRI1, 24, 8) | \
__gsSP1Triangle_w1f(v0, v1, v2, flag)); \
_g->words.w1 = 0; \
})

1 Triangle

◆ gSP2Triangles

#define gSP2Triangles ( pkt,
v00,
v01,
v02,
flag0,
v10,
v11,
v12,
flag1 )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL(G_TRI2, 24, 8) | \
__gsSP1Triangle_w1f(v00, v01, v02, flag0)); \
_g->words.w1 = __gsSP1Triangle_w1f(v10, v11, v12, flag1); \
})

2 Triangles

◆ gSPAlphaCompareCull

#define gSPAlphaCompareCull ( pkt,
mode,
thresh )
Value:
gMoveHalfwd(pkt, G_MW_FX, G_MWO_ALPHA_COMPARE_CULL, \
(_SHIFTL((mode), 8, 8) | _SHIFTL((thresh), 0, 8)))

Alpha compare culling. Optimization for cel shading, could also be used for other scenarios where lots of tris are being drawn with alpha compare.

If mode == G_ALPHA_COMPARE_CULL_DISABLE, tris are drawn normally.

Otherwise:

  • "vertex alpha" means the post-transform alpha value at each vertex being sent to the RDP. This may be the original model vertex alpha, fog, light level (for cel shading), or Fresnel.
  • Assuming a cel shading context: you have a threshold value thresh, you draw tris once and want to write all pixels where shade alpha >= thresh. Then you change color settings and draw tris again, and want to write all other pixels, i.e. where shade alpha < thresh.

For the light pass:

  • Set blend color alpha to thresh
  • Set CC alpha cycle 1 (or only cycle) to (shade alpha - 0) * tex alpha + 0
  • The RDP will draw pixels whenever shade alpha >= thresh (with binary alpha from the texture)
  • Set mode = G_ALPHA_COMPARE_CULL_BELOW in SPAlphaCompareCull, and thresh
  • The RSP will cull any tris where all three vertex alpha values (i.e. light level) are < thresh

For the dark pass:

  • Set blend color alpha to 0x100 - thresh (yes, not 0xFF - thresh).
  • Set CC alpha cycle 1 (or only cycle) to (1 - shade alpha) * tex alpha + 0
  • The RDP will draw pixels whenever shade alpha < thresh (with binary alpha from the texture)
  • Set mode = G_ALPHA_COMPARE_CULL_ABOVE in SPAlphaCompareCull, and thresh
  • The RSP will cull any tris where all three vertex alpha values (i.e. light level) are >= thresh

The idea is to cull tris early on the RSP which won't have any of their fragments drawn on the RDP, to save RDP time and memory bandwidth.

◆ gSPAmbient

#define gSPAmbient ( pkt,
l,
n )    gDma2p((pkt), G_MOVEMEM, (l), sizeof(Ambient), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))

l should point to an Ambient struct. n should be an integer 1-10 to load lights 0-9.

◆ gSPAmbOcclusionAmb

#define gSPAmbOcclusionAmb ( pkt,
amb )   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_AMBIENT, amb)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gSPAmbOcclusionDir

#define gSPAmbOcclusionDir ( pkt,
dir )   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_DIRECTIONAL, dir)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gSPAmbOcclusionPoint

#define gSPAmbOcclusionPoint ( pkt,
point )   gMoveHalfwd(pkt, G_MW_FX, G_MWO_AO_POINT, point)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gSPAttrOffsetST

#define gSPAttrOffsetST ( pkt,
s,
t )
Value:
gMoveWd(pkt, G_MW_FX, G_MWO_ATTR_OFFSET_S, \
(_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)))

Attribute offsets These are added to ST or Z values after vertices are loaded and transformed. They are all s16s. For ST, the addition is after the multiplication for ST scale in SPTexture. For Z, this simply adds to the Z offset from the viewport. Whether each feature is enabled or disabled at a given time is determined by the G_ATTROFFSET_ST_ENABLE and G_ATTROFFSET_Z_ENABLE bits respectively in the geometry mode. Normally you would use ST offsets for UV scrolling, and you would use a Z offset of -2 (which it is set to by default) to fix decal mode. For the latter, enable the Z offset and set the Z mode to opaque.

◆ gSPAttrOffsetZ

#define gSPAttrOffsetZ ( pkt,
z )    gMoveHalfwd(pkt, G_MW_FX, G_MWO_ATTR_OFFSET_Z, z)

Attribute offsets These are added to ST or Z values after vertices are loaded and transformed. They are all s16s. For ST, the addition is after the multiplication for ST scale in SPTexture. For Z, this simply adds to the Z offset from the viewport. Whether each feature is enabled or disabled at a given time is determined by the G_ATTROFFSET_ST_ENABLE and G_ATTROFFSET_Z_ENABLE bits respectively in the geometry mode. Normally you would use ST offsets for UV scrolling, and you would use a Z offset of -2 (which it is set to by default) to fix decal mode. For the latter, enable the Z offset and set the Z mode to opaque.

◆ gSPBranchLessZraw

#define gSPBranchLessZraw ( pkt,
dl,
vtx,
zval )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \
_g->words.w1 = (unsigned int)(dl); \
\
_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_BRANCH_Z, 24, 8) | \
_SHIFTL((vtx) * 5, 12, 12) | \
_SHIFTL((vtx) * 2, 0, 12)); \
_g->words.w1 = (unsigned int)(zval); \
})

gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval).

dl = DL branch to vtx = Vertex zval = Raw value of screen depth

◆ gSPBranchList

#define gSPBranchList ( pkt,
dl )   _gSPBranchListRaw( pkt, dl, 0)

Normal control flow commands; same as gSPBranchListHint but with hint of 0

◆ gSPBranchListHint

#define gSPBranchListHint ( pkt,
dl,
count )   _gSPBranchListRaw( pkt, dl, _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gSPCameraWorld

#define gSPCameraWorld ( pkt,
cam )    gDma2p((pkt), G_MOVEMEM, (cam), sizeof(PlainVtx), G_MV_LIGHT, 0)

Camera world position for Fresnel and specular lighting. Set this whenever you set the VP matrix, viewport, etc. cam is the address of a PlainVtx struct.

◆ gSPClipRatio

#define gSPClipRatio ( pkt,
r )   gSPNoOp(pkt)

Clipping Macros.

Deprecated
encodes SP no-ops it is not possible to change the clip ratio from 2 in F3DEX3.

◆ gSPCullDisplayList

#define gSPCullDisplayList ( pkt,
vstart,
vend )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_CULLDL, 24, 8) | \
_SHIFTL((vstart) * 2, 0, 16)); \
_g->words.w1 = _SHIFTL((vend) * 2, 0, 16); \
})

Cull the display list based on screen clip flags of range of loaded verts. Executes SPEndDisplayList if the convex hull formed by the specified range of already-loaded vertices is offscreen.

◆ gSPDisplayList

#define gSPDisplayList ( pkt,
dl )   _gSPDisplayListRaw(pkt, dl, 0)

Normal control flow commands; same as gSPDisplayListHint but with hint of 0

◆ gSPDisplayListHint

#define gSPDisplayListHint ( pkt,
dl,
count )   _gSPDisplayListRaw(pkt, dl, _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gSPDma_io

#define gSPDma_io ( pkt,
flag,
dmem,
dram,
size )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_DMA_IO, 24, 8) | \
_SHIFTL((flag), 23, 1) | \
_SHIFTL((dmem) / 8, 13, 10) | \
_SHIFTL((size) - 1, 0, 12)); \
_g->words.w1 = (unsigned int)(dram); \
})

gSPDma_io DMA to/from DMEM/IMEM for DEBUG.

◆ gSPDontSkipTexLoadsAcross

#define gSPDontSkipTexLoadsAcross ( pkt)     gMoveWd(pkt, G_MW_FX, G_MWO_LAST_MAT_DL_ADDR, 0xFFFFFFFF)

F3DEX3 has a basic auto-batched rendering system. At a high level, if a material display list being run is the same as the last material, the texture loads are automatically skipped the second time as they should already be in TMEM.

This design generally works, but can break if you call a display list twice but in between change a segment mapping so that a referenced image inside is actually different the two times. In these cases, run the below command between the two calls (e.g. when you change the segment) and the microcode will not skip the second texture loads.

Internally, a material is defined to start with any set image command, and end on any of the following: call, branch, return, vertex, all tri commands, tex/fill rectangles, and successes on cull or branch w/z (which are usually preceded by vertex loads anyway). The physical address of the display list –not the address of the image–is stored when a material is started. If a material starts and its physical address is the same as the stored last start address, i.e. we're executing the same material display list as the last material, material cull mode is set. In this mode, load block, load tile, and load TLUT all are skipped. This mode is cleared when the material ends.

This design has the benefit that it works correctly even with complex materials, e.g. with two CI4 textures (four loads), whereas it would be difficult to implement tracking all these loads separately. Furthermore, a design based on tracking the image addresses could break if you loaded different tile sections of the same image in consecutive materials.

◆ gSPEndDisplayList

#define gSPEndDisplayList ( pkt)    _gSPEndDisplayListRaw( pkt, 0)

Normal control flow commands; same as gSPEndDisplayListHint but with hint of 0

◆ gSPEndDisplayListHint

#define gSPEndDisplayListHint ( pkt,
count )   _gSPEndDisplayListRaw( pkt, _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gSPFogFactor

#define gSPFogFactor ( pkt,
fm,
fo )
Value:
gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \
(_SHIFTL(fm, 16, 16) | _SHIFTL(fo, 0, 16)))

FOG macros fm = z multiplier fo = z offset FOG FORMULA: alpha(fog) = (eyespace z) * fm + fo CLAMPED 0 to 255 note: (eyespace z) ranges -1 to 1

Alternate method of setting fog: min, max: range 0 to 1000: 0=nearplane, 1000=farplane min is where fog begins (usually less than max and often 0) max is where fog is thickest (usually 1000)

◆ gSPForceMatrix

#define gSPForceMatrix ( pkt,
mptr )   gSPNoOp(pkt)

Load new MVP matrix directly.

This is no longer supported as there is no MVP matrix in F3DEX3.

Deprecated

◆ gSPFresnel

#define gSPFresnel ( pkt,
scale,
offset )
Value:
gMoveWd(pkt, G_MW_FX, G_MWO_FRESNEL_SCALE, \
(_SHIFTL((scale), 16, 16) | _SHIFTL((offset), 0, 16)))

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gSPFresnelOffset

#define gSPFresnelOffset ( pkt,
offset )    gMoveHalfwd(pkt, G_MW_FX, G_MWO_FRESNEL_OFFSET, offset)

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gSPFresnelScale

#define gSPFresnelScale ( pkt,
scale )    gMoveHalfwd(pkt, G_MW_FX, G_MWO_FRESNEL_SCALE, scale)

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gSPGeometryMode

#define gSPGeometryMode ( pkt,
c,
s )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_GEOMETRYMODE, 24, 8) | \
_SHIFTL(~(u32)(c), 0, 24)); \
_g->words.w1 = (u32)(s); \
})

One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs.

gSPClearGeometryMode(pkt,c)
gSPSetGeometryMode(pkt,s)

gSPLoadGeometryMode(pkt, word) sets GeometryMode directly.

◆ gSPLight

#define gSPLight ( pkt,
l,
n )    gDma2p((pkt), G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))

l should point to a Light struct. n should be an integer 1-9 to load lights 0-8. Can also load Ambient lights to lights 0-8 with this. However, if you have 9 directional / point lights, you must use SPAmbient to load light 9 (LIGHT_10) with an ambient light. (That is, the memory for light 9 (LIGHT_10) is only sizeof(Ambient), so if you load this with SPLight, it will overwrite other DMEM and corrupt unrelated things.) New code should not generally use SPLight, and instead use SPSetLights to set all lights in one memory transaction.

◆ gSPLightColor

#define gSPLightColor ( pkt,
n,
col )
Value:
_DW({ \
gMoveWd(pkt, G_MW_LIGHTCOL, ((((n) - 1) * 0x10) + 0), ((col) & 0xFFFFFF00)); \
gMoveWd(pkt, G_MW_LIGHTCOL, ((((n) - 1) * 0x10) + 4), ((col) & 0xFFFFFF00)); \
})

gSPLightColor changes the color of a directional light without an additional DMA transfer. col is a 32 bit word where (col >> 24) & 0xFF is red, (col >> 16) & 0xFF is green, and (col >> 8) & 0xFF is blue. (col & 0xFF) is ignored and masked to zero. n should be an integer 1-10 to apply to light 0-9.

◆ gSPLightToRDP

#define gSPLightToRDP ( pkt,
light,
alpha,
word0 )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL(G_LIGHTTORDP, 24, 8) | \
_SHIFTL(light * 0x10, 8, 8) | \
_SHIFTL(alpha, 0, 8)); \
_g->words.w1 = (word0); \
})

Send the color of the specified light to one of the RDP's color registers. light is the index of a light in the RSP counting from the end, i.e. 0 is the ambient light, 1 is the last directional / point light, etc. The RGB color of the selected light is combined with the alpha specified in this command as word 1 of a RDP command, and word 0 is specified in this command. Specialized versions are provided below for prim color and fog color, because these are the two versions needed for cel shading, but any RDP color command could be specified this way.

◆ gSPLoadUcodeEx

#define gSPLoadUcodeEx ( pkt,
uc_start,
uc_dstart,
uc_dsize )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \
_g->words.w1 = (unsigned int)(uc_dstart); \
\
_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_LOAD_UCODE, 24, 8) | \
_SHIFTL((int)(uc_dsize) - 1, 0, 16)); \
_g->words.w1 = (unsigned int)(uc_start); \
})

gSPLoadUcode RSP loads specified ucode.

uc_start = ucode text section start uc_dstart = ucode data section start

◆ gSPLookAt

#define gSPLookAt ( pkt,
la )    gDma2p((pkt), G_MOVEMEM, (la), sizeof(LookAt), G_MV_LIGHT, 8)

Reflection/Hiliting Macros. la is the address of a LookAt struct.

◆ gSPLookAtX

#define gSPLookAtX ( pkt,
l )   gSPLookAt(pkt, l)

These versions are deprecated, please use g*SPLookAt. The two directions cannot be set independently anymore as they both fit within one memory word. (They could be set with moveword, but then the values would have to be within the command itself, not at a memory address.) This deprecated version has the X command set both (assuming l is the name / address of a LookAt struct) and has the Y command as a SP no-op.

Deprecated

◆ gSPLookAtY

#define gSPLookAtY ( pkt,
l )   gSPNoOp(pkt)

These versions are deprecated, please use g*SPLookAt. The two directions cannot be set independently anymore as they both fit within one memory word. (They could be set with moveword, but then the values would have to be within the command itself, not at a memory address.) This deprecated version has the X command set both (assuming l is the name / address of a LookAt struct) and has the Y command as a SP no-op.

Deprecated

◆ gSPMatrix

#define gSPMatrix ( pkt,
m,
p )    gDma2p((pkt),G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0)

macro which inserts a matrix operation at the end display list.

It inserts a matrix operation in the display list. The parameters allow you to select which matrix stack to use (projection or model view), where to load or concatenate, and whether or not to push the matrix stack. The following parameters are bit OR'ed together:

  • G_MTX_PROJECTION G_MTX_MODELVIEW - specifies whether the matrix operation will be performed on the projection or the model view matrix.
  • G_MTX_MUL - concatenates the matrix (m) with the top of the matrix stack.
  • G_MTX_LOAD - loads the matrix (m) onto the top of the matrix stack.
  • G_MTX_NOPUSH - specifies do not push the matrix stack prior to matrix operations
  • G_MTX_PUSH - specifies push the matrix stack prior to matrix operations

Matrix Format

The format of the fixed-point matrices may seem a little awkward to the application programmer because it is optimized for the RSP geometry engine. This unusual format is hidden in the graphics utility libraries and not usually exposed to the application programmer, but in some cases (static matrix declarations or direct element manipulation) it is necessary to understand the format.

The integer and fractional components of the matrix elements are separated. The first 8 words (16 shorts) hold the 16-bit integer elements, the second 8 words (16 shorts) hold the 16-bit fractional elements. The fact that the Mtx type is declared as a long [4][4] array is slightly misleading. For example, to declare a static identity matrix, use code similar to this:

#include "gbi.h"
static Mtx ident =
{
// integer portion:
0x00010000, 0x00000000,
0x00000001, 0x00000000,
0x00000000, 0x00010000,
0x00000000, 0x00000001,
// fractional portion:
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
};
Modded GBI for use with F3DEX3 custom microcode.

To force the translation elements of a matrix to be (10.5, 20.5, 30.5), use code similar to this:

#include "gbi.h"
mat.m[1][2] =
(10 << 16) | (20);
mat.m[1][3] =
(30 << 16) | (1);
mat.m[3][2] =
(0x8000 << 16) | (0x8000);
mat.m[3][3] =
(0x8000 << 16) | (0);
Note
Matrix concatenation in the RSP geometry engine is done using 32-bit integer arithmetic. A 32 x 32 bit multiply results in a 64-bit number. Only the middle 32 bits of this 64-bit result are kept for the new matrix. Therefore, when concatenating matrices, remember about the resulting fixed-point numerical error.

For example, to retain maximum precision, the number ranges must be similar. Large-scale and translate parameters can decrease the transformation precision. Because rotation and projection matrices require quite a bit of fractional accuracy, these fractions may get tossed out if multiplied against large integer numbers.

Each concatenation results in the rounding of the LSB of each matrix term. This means that each concatenation injects 1/2 LSB of error into the matrix. To keep full precision, concatenate matrices in floating-point on the processor and just load the result into the RSP.

Performance

Each G_MTX_MODELVIEW matrix operation has an implicit matrix multiplication even if you specify G_MTX_LOAD. This is the combined model view (M) and projection (P) matrix that is necessary for the vertex transformation to use a single matrix during transformation.

You can optimize this by concatenating modeling matrices on the CPU and then putting the viewing (V) and projection matrices on the projection stack. By doing this, you only incur the single MxVP matrix concatenation each time you load a modeling matrix. Furthermore, the application has more information on how to do a cheap hack for modeling matrix concatenation. For example, if you want to combine a single axis rotation with a translation, just place the coefficients in the correct entries of the resulting matrix.

Parameters
mis the pointer to the 4x4 fixed-point matrix (see note below about format)
pare the bit OR'd parameters to the matrix macro (G_MTX_PROJECTION, G_MTX_MODELVIEW, G_MTX_MUL, G_MTX_LOAD, G_MTX_NOPUSH)

◆ gSPMemset

#define gSPMemset ( pkt,
dram,
value,
size )
Value:
_DW({ \
gImmp1(pkt, G_RDPHALF_1, ((value) & 0xFFFF)); \
gDma0p(pkt, G_MEMSET, (dram), ((size) & 0xFFFFF0)); \
})

Use RSP DMAs to set a region of memory to a repeated 16-bit value. This can clear the color framebuffer or Z-buffer faster than the RDP can in fill mode. SPMemset overwrites the DMEM vertex buffer, so vertices loaded before this command cannot be used after it (though this would not normally be done).

dram: Segmented or physical start address. Must be aligned to 16 bytes. value: 16-bit value to fill the memory with. e.g. 0 for color, 0xFFFC for Z. size: Size in bytes to fill, must be nonzero and a multiple of 16 bytes.

◆ gSPMITMatrix

#define gSPMITMatrix ( pkt,
mit )    gDma2p((pkt), G_MOVEMEM, (mit), sizeof(MITMtx), G_MV_MMTX, 0x80)

See SPNormalsMode. mtx is the address of a MITMtx (M inverse transpose).

The matrix values must be scaled down so that the matrix norm is <= 1, i.e. multiplying this matrix by any vector length <= 1 must produce a vector with length <= 1. Normally, M scales things down substantially, so M inverse transpose natively would scale them up substantially; you need to apply a constant scale to counteract this. One easy way to do this is compute M inverse transpose normally, then scale it so until the maximum absolute value of any element is 0.5. Because of this scaling, you can also skip the part of the inverse computation where you compute the determinant and divide by it, cause you're going to rescale it arbitrarily anyway.

◆ gSPModifyVertex

#define gSPModifyVertex ( pkt,
vtx,
where,
val )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_MODIFYVTX, 24, 8) | \
_SHIFTL((where), 16, 8) | \
_SHIFTL((vtx) * 2, 0, 16)); \
_g->words.w1 = (unsigned int)(val); \
})

You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro).

This is an advanced macro. You need a good understanding of how vertices work in the RSP microcode before you use this macro (refer to gSPVertex).

You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro). This is useful for vertices that are shared between two or more triangles that must have different properties when associated with one triangle versus the other triangle.

For example, you might have two adjacent triangles that both need smooth-shaded color, but one is smooth-shaded red-to-yellow and the other is smooth-shaded green-to-cyan. In this case, the vertex that is shared by both triangles is sent with red/yellow color by using the gSPVertex macro. The first triangle is drawn. Then, the gSPModifyVertex macro is used to change the color to green/cyan, and the second triangle is drawn.

The primary use of the gSPModifyVertex macro is to modify the texture coordinate of a vertex so that a vertex that is shared by two triangles with different textures and different texture coordinate spaces can contain the texture coordinate for the first texture and then be modified to contain the texture coordinate for the second texture.

It is faster to use the gSPModifyVertex macro than to send a new vertex macro with a different but similar vertex because no transformations or lighting are done to the vertex when you use the gSPModifyVertex macro.

The where argument specifies which part of the vertex is to be modified. It can hold one of the following values:

  • G_MWO_POINT_RGBA - changes the color of the vertex. The val parameter is interpreted as 4 bytes: red (high byte), green, blue, and alpha (low byte).
  • G_MWO_POINT_ST - changes the S and T values (texture coordinates of the vertex). The high 16 bits of val specify the S coordinate, and the low 16 bits specify the T coordinate. Each coordinate is an S10.5 number.
  • G_MWO_POINT_XYSCREEN - change the screen coordinates of the vertex. The high 16 bits of val specify the X coordinate and the low 16 bits specify the Y coordinate. Both coordinates are S13.2 numbers with 0,0 being the upper-left of the screen, positive X going right, and positive Y going down.
  • G_MWO_POINT_ZSCREEN - changes the screen Z coordinate of the vertex. The entire 32-bit val is taken as the new screen Z value. It is a 16.16 number in the range 0x00000000 to 0x03ff0000.
Note
Lighting is not performed after a gSPModifyVertex macro, so modifying the color of the vertex with G_MWO_POINT_RGBA is just that - modifying the actual color that will be output. It is not a modification of normal values. This means it cannot be used to update vertex normals for lighting.

The S and T coordinates supplied in the gSPModifyVertex macro are never multiplied by the texture scale (from the gSPTexture macro), so you must pre-scale them before sending them. For example, if you want a texture scale of 1/2 (0x8000), make the S and T values sent with the gSPModifyVertex macro half the value of the equivalent values used with the gSPVertex macro.

Example

To share a vertex between two triangles with different textures and texture coordinates, use this code:

// load vertex by gSPVertex
gSPVertex(...);
// load texture of triangle 1
gDPLoadTextureBlock(...);
// draw triangle 1 using vertex #3
gSP1Triangle(glistp++, 1,2,3,0);
// change a value of vertex 3 to S=3.0 and T=2.5
gSPModifyVertex(glistp++, 3, G_MWO_POINT_ST, 0x00600050);
// load texture of triangle 2
gDPLoadTextureBlock(...);
// draw triangle 2 using vertex #3
gSP1Triangle(glistp++, 1,2,3,0);
#define gSPVertex(pkt, v, n, v0)
macro which loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macr...
Definition gbi.h:2228
#define gSPModifyVertex(pkt, vtx, where, val)
You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by t...
Definition gbi.h:3112
#define G_MWO_POINT_ST
changes the S and T values (texture coordinates of the vertex). The high 16 bits of val specify the S...
Definition gbi.h:296
#define gSP1Triangle(pkt, v0, v1, v2, flag)
Definition gbi.h:2567
Parameters
vtxspecifies which of the RSP's vertices (0-55) to modify
wherespecifies which part of the vertex to modify (G_MWO_POINT_RGBA, G_MWO_POINT_ST, G_MWO_POINT_XYSCREEN or G_MWO_POINT_ZSCREEN)
valis the new value for the part of the vertex to be modified (a 32 bit integer number)

◆ gSPNormalsMode

#define gSPNormalsMode ( pkt,
mode )    gMoveHalfwd(pkt, G_MW_FX, G_MWO_NORMALS_MODE, (mode) & 0xFF)

Normals mode: How to handle transformation of vertex normals from model to world space for lighting.

If mode = G_NORMALS_MODE_FAST, transforms normals from model space to world space with the M matrix. This is correct if the object's transformation matrix stack only included translations, rotations, and uniform scale (i.e. same scale in X, Y, and Z); otherwise, if the transformation matrix has nonuniform scale or shear, the lighting on the object will be somewhat distorted.

If mode = G_NORMALS_MODE_AUTO, transforms normals from model space to world space with M inverse transpose, which renders lighting correctly for the object regardless of its transformation matrix (nonuniform scale or shear is okay). Whenever vertices are drawn with lighting enabled after M has been changed, computes M inverse transpose from M. This requires swapping to overlay 4 for M inverse transpose and then back to overlay 2 for lighting, which produces roughly 3.5 us of extra DRAM traffic. This performance penalty happens effectively once per matrix, which is once per normal object or separated limb or about twice per flex skeleton limb. So in a scene with lots of complex skeletons, this may have a noticeable performance impact.

If mode = G_NORMALS_MODE_MANUAL, uses M inverse transpose for correct results like G_NORMALS_MODE_AUTO, but it never internally computes M inverse transpose. You have to upload M inverse transpose to the RSP using SPMITMatrix every time you change the M matrix. The DRAM traffic for the extra matrix uploads is much smaller than the overlay swaps, so if you can efficiently compute M inverse transpose on the CPU, this may be faster than G_NORMALS_MODE_AUTO.

Recommended to leave this set to G_NORMALS_MODE_FAST generally, and only set it to G_NORMALS_MODE_AUTO for specific objects at times when they actually have a nonuniform scale. For example, G_NORMALS_MODE_FAST for Mario generally, but G_NORMALS_MODE_AUTO temporarily while he is squashed.

◆ gSPNumLights

#define gSPNumLights ( pkt,
n )    gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))

Number of directional / point lights, in the range 0-9. There is also always one ambient light not counted in this number.

◆ gSPOcclusionPlane

#define gSPOcclusionPlane ( pkt,
o )
Value:
gDma2p((pkt), G_MOVEMEM, (o), sizeof(OcclusionPlane), G_MV_LIGHT, \
(G_MAX_LIGHTS * 0x10) + 0x18)

Set the occlusion plane. This is a quadrilateral in 3D space where all geometry behind it is culled. You should create occlusion plane candidates just behind walls and other large objects, and have your game engine pick the most optimal one every frame to send to the RSP.

Computing the coefficients for the occlusion plane is far too complicated to explain here. The reference implementation guOcclusionPlane is provided separately.

o is the address of an OcclusionPlane struct

◆ gSPPopMatrix

#define gSPPopMatrix ( pkt,
n )   gSPPopMatrixN((pkt), (n), 1)

macro which pops one of the matrix stacks at the end display list.

It pops one of the matrix stacks. The model view stack can be up to 10 matrices deep. The projection stack is 1 matrix deep, so it cannot be popped.

Note
If the stack is empty, the macro is ignored.
Parameters
nis the flag field that identifies which matrix stack to pop:

◆ gSPPopMatrixN

#define gSPPopMatrixN ( pkt,
n,
num )   gDma2p((pkt), G_POPMTX, (num) * 64, 64, 2, 0)

macro which pops one of the matrix stacks at the end display list.

It pops num of the matrix stacks. The model view stack can be up to 10 matrices deep. The projection stack is 1 matrix deep, so it cannot be popped.

Note
If the stack is empty, the macro is ignored.
Parameters
nis the flag field that identifies which matrix stack to pop:
numis the number of matrices to pop

◆ gSPSetLights

#define gSPSetLights ( pkt,
n,
name )
Value:
_DW({ \
gSPNumLights(pkt, n); \
gDma2p((pkt), G_MOVEMEM, &(name), (n) * 0x10 + 8, G_MV_LIGHT, 0x10); \
})

Set all your scene's lights (directional/point + ambient) with one memory transaction. n is the number of directional / point lights, from 0 to 9. There is also always an ambient light. name should be the NAME of a Lights struct (NOT A POINTER) filled in with all the lighting data. You can use the gdSPDef* macros to fill in the struct or just do it manually. Example: Lights2 myLights; // 2 dir/pos + 1 ambient gSPSetLights(POLY_OPA_DISP++, 2, myLights);

If you need to use a pointer, e.g. if the number of lights is variable at runtime: Light *lights = memory_allocate((numLights + 1) * sizeof(Light)); lights[0].p.pos = ...; lights[1].l.dir = ...; ... lights[numLights].l.col = ambient_color(); gSPSetLights(POLY_OPA_DISP++, numLights, *lights); // <- NOTE DEREFERENCE

If you're wondering why this macro takes a name / dereference instead of a pointer, it's for backwards compatibility.

◆ gSPTexture

#define gSPTexture ( pkt,
s,
t,
level,
tile,
on )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_TEXTURE, 24, 8) | \
_SHIFTL((level), 11, 3) | \
_SHIFTL((tile), 8, 3) | \
_SHIFTL((on), 1, 7)); \
_g->words.w1 = (_SHIFTL((s), 16, 16) | \
_SHIFTL((t), 0, 16)); \
})

Macros to turn texture on/off

◆ gSPTextureL

#define gSPTextureL ( pkt,
s,
t,
level,
bowtie,
tile,
on )    gSPTexture(pkt, s, t, level, tile, on)

The bowtie value is a workaround for a bug in HW V1, and is not supported by F3DEX2, let alone F3DEX3.

◆ gSPTriFan

#define gSPTriFan ( pkt,
v1,
v2,
v3,
v4,
v5,
v6,
v7 )    _gSP5Triangles(pkt, G_TRIFAN, v1, v2, v3, v4, v5, v6, v7)

5 Triangles in fan arrangement. Draws the following tris: v1-v2-v3, v1-v3-v4, v1-v4-v5, v1-v5-v6, v1-v6-v7 Otherwise works the same as SPTriStrip, see above.

◆ gSPTriStrip

#define gSPTriStrip ( pkt,
v1,
v2,
v3,
v4,
v5,
v6,
v7 )    _gSP5Triangles(pkt, G_TRISTRIP, v1, v2, v3, v4, v5, v6, v7)

5 Triangles in strip arrangement. Draws the following tris: v1-v2-v3, v3-v2-v4, v3-v4-v5, v5-v4-v6, v5-v6-v7 If you want to draw fewer tris, set indices to -1 from the right. e.g. to draw 4 tris, set v7 to -1; to draw 3 tris, set v6 to -1 Note that any set of 3 adjacent tris can be drawn with either SPTriStrip or SPTriFan. For arbitrary sets of 4 adjacent tris, four out of five of them can be drawn with one of SPTriStrip or SPTriFan. The 4-triangle formation which can't be drawn with either command looks like the Triforce.

◆ gSPVertex

#define gSPVertex ( pkt,
v,
n,
v0 )
Value:
_DW({ \
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = (_SHIFTL(G_VTX, 24, 8) | \
_SHIFTL((n), 12, 8) | \
_SHIFTL((v0) + (n), 1, 7)); \
_g->words.w1 = (unsigned int)(v); \
})

macro which loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons at the end display list.

It loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons. This vertex cache can hold up to 56 vertices, and the vertex loading can begin at any entry (index) within the cache. The vertex coordinates (x,y,z) are encoded in signed 2's complement, 16-bit integers. The texture coordinates (s,t) are encoded in S10.5 format. A vertex either has a color or a normal (for shading). These values are 8-bit values. The colors and alphas are treated as 8-bit unsigned values (0-255), but the normals are treated as 8-bit signed values (-128 to 127). Therefore, the appropriate member of the union to use (.v. or .n.) depends on whether you are using colors or normals.

Normal coordinates range from -1.0 to 1.0. A value of -1.0 is represented as -128, and a value of 1.0 is represented as 128, but because the maximum positive value of a signed byte is 127, a value of 1.0 can't really be represented. Therefore, 0.992 is the maximum representable positive value, which is good enough for this purpose.

The flag value is used for the packed normals feature to store normals with octahedral encoding.

The coordinates (x,y,z) are transformed using the current 4x4 projection and model view matrices, and (s,t) are transformed using the scale defined by gSPTexture.

Example

To load vertex cache entry 2,3,4, use this code:

gSPVertex(glistp++, v, 3, 2);
Note
Because the RSP geometry transformation engine uses a vertex list with triangle list architecture, it is quite powerful. A simple one-triangle macro retains least performance compared to gSP2Triangles or the new 5 tris commands in EX3 (gSPTriStrip, gSPTriFan).
Parameters
vis the pointer to the vertex list (segment address)
nis the number of vertices
v0is the load vertex by index vo(0~55) in vertex buffer

◆ gsSP1Quadrangle

#define gsSP1Quadrangle ( v0,
v1,
v2,
v3,
flag )
Value:
{ \
(_SHIFTL(G_QUAD, 24, 8) | \
__gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \
__gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \
}

1 Quadrangle

◆ gsSP1Triangle

#define gsSP1Triangle ( v0,
v1,
v2,
flag )
Value:
{ \
(_SHIFTL(G_TRI1, 24, 8) | \
__gsSP1Triangle_w1f(v0, v1, v2, flag)), \
0 \
}

1 Triangle

◆ gsSP2Triangles

#define gsSP2Triangles ( v00,
v01,
v02,
flag0,
v10,
v11,
v12,
flag1 )
Value:
{ \
(_SHIFTL(G_TRI2, 24, 8) | \
__gsSP1Triangle_w1f(v00, v01, v02, flag0)), \
__gsSP1Triangle_w1f(v10, v11, v12, flag1) \
}

2 Triangles

◆ gsSPAlphaCompareCull

#define gsSPAlphaCompareCull ( mode,
thresh )
Value:
gsMoveHalfwd(G_MW_FX, G_MWO_ALPHA_COMPARE_CULL, \
(_SHIFTL((mode), 8, 8) | _SHIFTL((thresh), 0, 8)))

Alpha compare culling. Optimization for cel shading, could also be used for other scenarios where lots of tris are being drawn with alpha compare.

If mode == G_ALPHA_COMPARE_CULL_DISABLE, tris are drawn normally.

Otherwise:

  • "vertex alpha" means the post-transform alpha value at each vertex being sent to the RDP. This may be the original model vertex alpha, fog, light level (for cel shading), or Fresnel.
  • Assuming a cel shading context: you have a threshold value thresh, you draw tris once and want to write all pixels where shade alpha >= thresh. Then you change color settings and draw tris again, and want to write all other pixels, i.e. where shade alpha < thresh.

For the light pass:

  • Set blend color alpha to thresh
  • Set CC alpha cycle 1 (or only cycle) to (shade alpha - 0) * tex alpha + 0
  • The RDP will draw pixels whenever shade alpha >= thresh (with binary alpha from the texture)
  • Set mode = G_ALPHA_COMPARE_CULL_BELOW in SPAlphaCompareCull, and thresh
  • The RSP will cull any tris where all three vertex alpha values (i.e. light level) are < thresh

For the dark pass:

  • Set blend color alpha to 0x100 - thresh (yes, not 0xFF - thresh).
  • Set CC alpha cycle 1 (or only cycle) to (1 - shade alpha) * tex alpha + 0
  • The RDP will draw pixels whenever shade alpha < thresh (with binary alpha from the texture)
  • Set mode = G_ALPHA_COMPARE_CULL_ABOVE in SPAlphaCompareCull, and thresh
  • The RSP will cull any tris where all three vertex alpha values (i.e. light level) are >= thresh

The idea is to cull tris early on the RSP which won't have any of their fragments drawn on the RDP, to save RDP time and memory bandwidth.

◆ gsSPAmbient

#define gsSPAmbient ( l,
n )    gsDma2p( G_MOVEMEM, (l), sizeof(Ambient), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))

l should point to an Ambient struct. n should be an integer 1-10 to load lights 0-9.

◆ gsSPAmbOcclusionAmb

#define gsSPAmbOcclusionAmb ( amb)    gsMoveHalfwd( G_MW_FX, G_MWO_AO_AMBIENT, amb)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gsSPAmbOcclusionDir

#define gsSPAmbOcclusionDir ( dir)    gsMoveHalfwd( G_MW_FX, G_MWO_AO_DIRECTIONAL, dir)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gsSPAmbOcclusionPoint

#define gsSPAmbOcclusionPoint ( point)    gsMoveHalfwd( G_MW_FX, G_MWO_AO_POINT, point)

Ambient occlusion Enabled with the G_AMBOCCLUSION bit in geometry mode. Each of these factors sets how much ambient occlusion affects lights of the given type (ambient, directional, point). They are u16s. You can set each independently or two adjacent values with one moveword. A two-command macro is also provided to set all three values.

When building the model, you must encode the amount of ambient occlusion at each vertex–effectively the shadow map for the model–in vertex alpha, where 00 means darkest and FF means lightest. Then, the factors set with the SPAmbOcclusion command determine how much the vertex alpha values affect the light intensity. For example, if the ambient factor is set to 0x8000, this means that in the darkest parts of the model, the ambient light intensity will be reduced by 50%, and in the lightest parts of the model, the ambient light intensity won't be reduced at all.

The default is: amb = 0xFFFF (ambient light fully affected by vertex alpha) dir = 0xA000 (directional lights 62% affected by vertex alpha) point = 0 (point lights not at all affected by vertex alpha)

Two reasons to use ambient occlusion rather than darkening the vertex colors:

  • With ambient occlusion, the geometry can be fully lit up with point and/or directional lights, depending on your settings here.
  • Ambient occlusion can be used with cel shading to create areas which are "darker" for the cel shading thresholds, but still have bright / white vertex colors.

Two reasons to use these factors to modify ambient occlusion rather than just manually scaling and offsetting all the vertex alpha values:

  • To allow the behavior to differ between ambient, directional, and point lights
  • To allow the lighting to be adjusted at the scene level on-the-fly

◆ gsSPAttrOffsetST

#define gsSPAttrOffsetST ( s,
t )
Value:
gsMoveWd(G_MW_FX, G_MWO_ATTR_OFFSET_S, \
(_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)))

Attribute offsets These are added to ST or Z values after vertices are loaded and transformed. They are all s16s. For ST, the addition is after the multiplication for ST scale in SPTexture. For Z, this simply adds to the Z offset from the viewport. Whether each feature is enabled or disabled at a given time is determined by the G_ATTROFFSET_ST_ENABLE and G_ATTROFFSET_Z_ENABLE bits respectively in the geometry mode. Normally you would use ST offsets for UV scrolling, and you would use a Z offset of -2 (which it is set to by default) to fix decal mode. For the latter, enable the Z offset and set the Z mode to opaque.

◆ gsSPAttrOffsetZ

#define gsSPAttrOffsetZ ( z)     gsMoveHalfwd(G_MW_FX, G_MWO_ATTR_OFFSET_Z, z)

Attribute offsets These are added to ST or Z values after vertices are loaded and transformed. They are all s16s. For ST, the addition is after the multiplication for ST scale in SPTexture. For Z, this simply adds to the Z offset from the viewport. Whether each feature is enabled or disabled at a given time is determined by the G_ATTROFFSET_ST_ENABLE and G_ATTROFFSET_Z_ENABLE bits respectively in the geometry mode. Normally you would use ST offsets for UV scrolling, and you would use a Z offset of -2 (which it is set to by default) to fix decal mode. For the latter, enable the Z offset and set the Z mode to opaque.

◆ gsSPBranchLessZraw

#define gsSPBranchLessZraw ( dl,
vtx,
zval )
Value:
{ \
_SHIFTL(G_RDPHALF_1, 24, 8), \
(unsigned int)(dl), \
}, \
{ \
(_SHIFTL(G_BRANCH_Z, 24, 8) | \
_SHIFTL((vtx) * 5, 12, 12) | \
_SHIFTL((vtx) * 2, 0, 12)), \
(unsigned int)(zval), \
}

gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval).

dl = DL branch to vtx = Vertex zval = Raw value of screen depth

◆ gsSPBranchList

#define gsSPBranchList ( dl)    _gsSPBranchListRaw( dl, 0)

Normal control flow commands; same as gsSPBranchListHint but with hint of 0

◆ gsSPBranchListHint

#define gsSPBranchListHint ( dl,
count )   _gsSPBranchListRaw( dl, _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gsSPCameraWorld

#define gsSPCameraWorld ( cam)     gsDma2p( G_MOVEMEM, (cam), sizeof(PlainVtx), G_MV_LIGHT, 0)

Camera world position for Fresnel and specular lighting. Set this whenever you set the VP matrix, viewport, etc. cam is the address of a PlainVtx struct.

◆ gsSPClipRatio

#define gsSPClipRatio ( r)    gsSPNoOp()

Clipping Macros.

Deprecated
Deprecated
encodes SP no-ops it is not possible to change the clip ratio from 2 in F3DEX3.

◆ gsSPCullDisplayList

#define gsSPCullDisplayList ( vstart,
vend )
Value:
{ \
(_SHIFTL(G_CULLDL, 24, 8) | \
_SHIFTL((vstart) * 2, 0, 16)), \
_SHIFTL((vend) * 2, 0, 16) \
}

Cull the display list based on screen clip flags of range of loaded verts. Executes SPEndDisplayList if the convex hull formed by the specified range of already-loaded vertices is offscreen.

◆ gsSPDisplayList

#define gsSPDisplayList ( dl)    _gsSPDisplayListRaw( dl, 0)

Normal control flow commands; same as gsSPDisplayListHint but with hint of 0

◆ gsSPDisplayListHint

#define gsSPDisplayListHint ( dl,
count )   _gsSPDisplayListRaw( dl, _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gsSPDma_io

#define gsSPDma_io ( flag,
dmem,
dram,
size )
Value:
{ \
(_SHIFTL(G_DMA_IO, 24, 8) | \
_SHIFTL((flag), 23, 1) | \
_SHIFTL((dmem) / 8, 13, 10) | \
_SHIFTL((size) - 1, 0, 12)), \
(unsigned int)(dram) \
}

gSPDma_io DMA to/from DMEM/IMEM for DEBUG.

◆ gsSPDontSkipTexLoadsAcross

#define gsSPDontSkipTexLoadsAcross ( )     gsMoveWd(G_MW_FX, G_MWO_LAST_MAT_DL_ADDR, 0xFFFFFFFF)

F3DEX3 has a basic auto-batched rendering system. At a high level, if a material display list being run is the same as the last material, the texture loads are automatically skipped the second time as they should already be in TMEM.

This design generally works, but can break if you call a display list twice but in between change a segment mapping so that a referenced image inside is actually different the two times. In these cases, run the below command between the two calls (e.g. when you change the segment) and the microcode will not skip the second texture loads.

Internally, a material is defined to start with any set image command, and end on any of the following: call, branch, return, vertex, all tri commands, tex/fill rectangles, and successes on cull or branch w/z (which are usually preceded by vertex loads anyway). The physical address of the display list –not the address of the image–is stored when a material is started. If a material starts and its physical address is the same as the stored last start address, i.e. we're executing the same material display list as the last material, material cull mode is set. In this mode, load block, load tile, and load TLUT all are skipped. This mode is cleared when the material ends.

This design has the benefit that it works correctly even with complex materials, e.g. with two CI4 textures (four loads), whereas it would be difficult to implement tracking all these loads separately. Furthermore, a design based on tracking the image addresses could break if you loaded different tile sections of the same image in consecutive materials.

◆ gsSPEndDisplayList

#define gsSPEndDisplayList ( )    _gsSPEndDisplayListRaw( 0)

Normal control flow commands; same as gsSPEndDisplayListHint but with hint of 0

◆ gsSPEndDisplayListHint

#define gsSPEndDisplayListHint ( count)    _gsSPEndDisplayListRaw( _DLHINTVALUE(count))

Optimization for reduced memory traffic. In count, put the estimated number of DL commands in the target DL (the DL being called / jumped to, or the DL being returned to, starting from the next command to be executed) up to and including the next call / jump / return. Normally, for SPDisplayList, this is just the total number of commands in the target DL. The actual on-screen result will not change regardless of the value of count, but the performance will be best if count is correct, and potentially worse than not specifying count if it is wrong. Feature suggested by Kaze Emanuar

◆ gsSPFogFactor

#define gsSPFogFactor ( fm,
fo )
Value:
gsMoveWd(G_MW_FOG, G_MWO_FOG, \
(_SHIFTL(fm, 16, 16) | _SHIFTL(fo, 0, 16)))

FOG macros fm = z multiplier fo = z offset FOG FORMULA: alpha(fog) = (eyespace z) * fm + fo CLAMPED 0 to 255 note: (eyespace z) ranges -1 to 1

Alternate method of setting fog: min, max: range 0 to 1000: 0=nearplane, 1000=farplane min is where fog begins (usually less than max and often 0) max is where fog is thickest (usually 1000)

◆ gsSPForceMatrix

#define gsSPForceMatrix ( mptr)    gsSPNoOp()

Load new MVP matrix directly.

This is no longer supported as there is no MVP matrix in F3DEX3.

Deprecated

◆ gsSPFresnel

#define gsSPFresnel ( scale,
offset )
Value:
gsMoveWd(G_MW_FX, G_MWO_FRESNEL_SCALE, \
(_SHIFTL((scale), 16, 16) | _SHIFTL((offset), 0, 16)))

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gsSPFresnelOffset

#define gsSPFresnelOffset ( offset)     gsMoveHalfwd(G_MW_FX, G_MWO_FRESNEL_OFFSET, offset)

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gsSPFresnelScale

#define gsSPFresnelScale ( scale)     gsMoveHalfwd(G_MW_FX, G_MWO_FRESNEL_SCALE, scale)

Fresnel - Feature suggested by thecozies Enabled with the G_FRESNEL bit in geometry mode. The dot product between a vertex normal and the vector from the vertex to the camera is computed. The offset and scale here convert 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.

If using Fresnel, you need to set the camera world position whenever you set the VP matrix, viewport, etc. See SPCameraWorld.

The RSP does: s16 dotProduct = dot(vertex normal, camera pos - vertex pos); dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away s32 factor = ((scale * dotProduct) >> 15) + offset; s16 result = clamp(factor << 8, 0, 7FFF); color_or_alpha = result >> 7;

At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F At dotMin, color_or_alpha = 00, result = 0, factor = 0 7F = ((scale * dotMax) >> 15) + offset 00 = ((scale * dotMin) >> 15) + offset Subtract: 7F = (scale * (dotMax - dotMin)) >> 15 3F8000 = scale * (dotMax - dotMin) scale = 3F8000 / (dotMax - dotMin) <– offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15) offset = -((7F * dotMin) / (dotMax - dotMin)) <–

To convert in the opposite direction: ((7F - offset) << 15) / scale = dotMax ((00 - offset) << 15) / scale = dotMin

◆ gsSPGeometryMode

#define gsSPGeometryMode ( c,
s )
Value:
{ \
(_SHIFTL(G_GEOMETRYMODE, 24, 8) | \
_SHIFTL(~(u32)(c), 0, 24)), \
(u32)(s) \
}

One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs.

gSPClearGeometryMode(pkt,c)
gSPSetGeometryMode(pkt,s)

gSPLoadGeometryMode(pkt, word) sets GeometryMode directly.

◆ gsSPLight

#define gsSPLight ( l,
n )    gsDma2p( G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, _LIGHT_TO_OFFSET(n))

l should point to a Light struct. n should be an integer 1-9 to load lights 0-8. Can also load Ambient lights to lights 0-8 with this. However, if you have 9 directional / point lights, you must use SPAmbient to load light 9 (LIGHT_10) with an ambient light. (That is, the memory for light 9 (LIGHT_10) is only sizeof(Ambient), so if you load this with SPLight, it will overwrite other DMEM and corrupt unrelated things.) New code should not generally use SPLight, and instead use SPSetLights to set all lights in one memory transaction.

◆ gsSPLightColor

#define gsSPLightColor ( n,
col )
Value:
gsMoveWd(G_MW_LIGHTCOL, ((((n) - 1) * 0x10) + 0), ((col) & 0xFFFFFF00)), \
gsMoveWd(G_MW_LIGHTCOL, ((((n) - 1) * 0x10) + 4), ((col) & 0xFFFFFF00))

gSPLightColor changes the color of a directional light without an additional DMA transfer. col is a 32 bit word where (col >> 24) & 0xFF is red, (col >> 16) & 0xFF is green, and (col >> 8) & 0xFF is blue. (col & 0xFF) is ignored and masked to zero. n should be an integer 1-10 to apply to light 0-9.

◆ gsSPLightToRDP

#define gsSPLightToRDP ( light,
alpha,
word0 )
Value:
{ \
(_SHIFTL(G_LIGHTTORDP, 24, 8) | \
_SHIFTL(light * 0x10, 8, 8) | \
_SHIFTL(alpha, 0, 8)), \
(word0) \
}

Send the color of the specified light to one of the RDP's color registers. light is the index of a light in the RSP counting from the end, i.e. 0 is the ambient light, 1 is the last directional / point light, etc. The RGB color of the selected light is combined with the alpha specified in this command as word 1 of a RDP command, and word 0 is specified in this command. Specialized versions are provided below for prim color and fog color, because these are the two versions needed for cel shading, but any RDP color command could be specified this way.

◆ gsSPLoadUcodeEx

#define gsSPLoadUcodeEx ( uc_start,
uc_dstart,
uc_dsize )
Value:
{ \
_SHIFTL(G_RDPHALF_1, 24, 8), \
(unsigned int)(uc_dstart), \
}, \
{ \
(_SHIFTL(G_LOAD_UCODE, 24, 8) | \
_SHIFTL((int)(uc_dsize) - 1, 0, 16)), \
(unsigned int)(uc_start), \
}

gSPLoadUcode RSP loads specified ucode.

uc_start = ucode text section start uc_dstart = ucode data section start

◆ gsSPLookAt

#define gsSPLookAt ( la)     gsDma2p( G_MOVEMEM, (la), sizeof(LookAt), G_MV_LIGHT, 8)

Reflection/Hiliting Macros. la is the address of a LookAt struct.

◆ gsSPLookAtX

#define gsSPLookAtX ( l)    gsSPLookAt(l)

These versions are deprecated, please use g*SPLookAt. The two directions cannot be set independently anymore as they both fit within one memory word. (They could be set with moveword, but then the values would have to be within the command itself, not at a memory address.) This deprecated version has the X command set both (assuming l is the name / address of a LookAt struct) and has the Y command as a SP no-op.

Deprecated

◆ gsSPLookAtY

#define gsSPLookAtY ( l)    gsSPNoOp()

These versions are deprecated, please use g*SPLookAt. The two directions cannot be set independently anymore as they both fit within one memory word. (They could be set with moveword, but then the values would have to be within the command itself, not at a memory address.) This deprecated version has the X command set both (assuming l is the name / address of a LookAt struct) and has the Y command as a SP no-op.

Deprecated

◆ gsSPMatrix

#define gsSPMatrix ( m,
p )    gsDma2p( G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0)

macro which inserts a matrix operation in a static display list.

It inserts a matrix operation in the display list. The parameters allow you to select which matrix stack to use (projection or model view), where to load or concatenate, and whether or not to push the matrix stack. The following parameters are bit OR'ed together:

  • G_MTX_PROJECTION G_MTX_MODELVIEW - specifies whether the matrix operation will be performed on the projection or the model view matrix.
  • G_MTX_MUL - concatenates the matrix (m) with the top of the matrix stack.
  • G_MTX_LOAD - loads the matrix (m) onto the top of the matrix stack.
  • G_MTX_NOPUSH - specifies do not push the matrix stack prior to matrix operations
  • G_MTX_PUSH - specifies push the matrix stack prior to matrix operations

Matrix Format

The format of the fixed-point matrices may seem a little awkward to the application programmer because it is optimized for the RSP geometry engine. This unusual format is hidden in the graphics utility libraries and not usually exposed to the application programmer, but in some cases (static matrix declarations or direct element manipulation) it is necessary to understand the format.

The integer and fractional components of the matrix elements are separated. The first 8 words (16 shorts) hold the 16-bit integer elements, the second 8 words (16 shorts) hold the 16-bit fractional elements. The fact that the Mtx type is declared as a long [4][4] array is slightly misleading. For example, to declare a static identity matrix, use code similar to this:

#include "gbi.h"
static Mtx ident =
{
// integer portion:
0x00010000, 0x00000000,
0x00000001, 0x00000000,
0x00000000, 0x00010000,
0x00000000, 0x00000001,
// fractional portion:
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
};

To force the translation elements of a matrix to be (10.5, 20.5, 30.5), use code similar to this:

#include "gbi.h"
mat.m[1][2] =
(10 << 16) | (20);
mat.m[1][3] =
(30 << 16) | (1);
mat.m[3][2] =
(0x8000 << 16) | (0x8000);
mat.m[3][3] =
(0x8000 << 16) | (0);
Note
Matrix concatenation in the RSP geometry engine is done using 32-bit integer arithmetic. A 32 x 32 bit multiply results in a 64-bit number. Only the middle 32 bits of this 64-bit result are kept for the new matrix. Therefore, when concatenating matrices, remember about the resulting fixed-point numerical error.

For example, to retain maximum precision, the number ranges must be similar. Large-scale and translate parameters can decrease the transformation precision. Because rotation and projection matrices require quite a bit of fractional accuracy, these fractions may get tossed out if multiplied against large integer numbers.

Each concatenation results in the rounding of the LSB of each matrix term. This means that each concatenation injects 1/2 LSB of error into the matrix. To keep full precision, concatenate matrices in floating-point on the processor and just load the result into the RSP.

Performance

Each G_MTX_MODELVIEW matrix operation has an implicit matrix multiplication even if you specify G_MTX_LOAD. This is the combined model view (M) and projection (P) matrix that is necessary for the vertex transformation to use a single matrix during transformation.

You can optimize this by concatenating modeling matrices on the CPU and then putting the viewing (V) and projection matrices on the projection stack. By doing this, you only incur the single MxVP matrix concatenation each time you load a modeling matrix. Furthermore, the application has more information on how to do a cheap hack for modeling matrix concatenation. For example, if you want to combine a single axis rotation with a translation, just place the coefficients in the correct entries of the resulting matrix.

Parameters
mis the pointer to the 4x4 fixed-point matrix (see note below about format)
pare the bit OR'd parameters to the matrix macro (G_MTX_PROJECTION, G_MTX_MODELVIEW, G_MTX_MUL, G_MTX_LOAD, G_MTX_NOPUSH)

◆ gsSPMemset

#define gsSPMemset ( pkt,
dram,
value,
size )
Value:
gsImmp1(G_RDPHALF_1, ((value) & 0xFFFF)), \
gsDma0p(G_MEMSET, (dram), ((size) & 0xFFFFF0))

Use RSP DMAs to set a region of memory to a repeated 16-bit value. This can clear the color framebuffer or Z-buffer faster than the RDP can in fill mode. SPMemset overwrites the DMEM vertex buffer, so vertices loaded before this command cannot be used after it (though this would not normally be done).

dram: Segmented or physical start address. Must be aligned to 16 bytes. value: 16-bit value to fill the memory with. e.g. 0 for color, 0xFFFC for Z. size: Size in bytes to fill, must be nonzero and a multiple of 16 bytes.

◆ gsSPMITMatrix

#define gsSPMITMatrix ( mtx)     gsDma2p( G_MOVEMEM, (mit), sizeof(MITMtx), G_MV_MMTX, 0x80)

See SPNormalsMode. mtx is the address of a MITMtx (M inverse transpose).

The matrix values must be scaled down so that the matrix norm is <= 1, i.e. multiplying this matrix by any vector length <= 1 must produce a vector with length <= 1. Normally, M scales things down substantially, so M inverse transpose natively would scale them up substantially; you need to apply a constant scale to counteract this. One easy way to do this is compute M inverse transpose normally, then scale it so until the maximum absolute value of any element is 0.5. Because of this scaling, you can also skip the part of the inverse computation where you compute the determinant and divide by it, cause you're going to rescale it arbitrarily anyway.

◆ gsSPModifyVertex

#define gsSPModifyVertex ( vtx,
where,
val )
Value:
{ \
(_SHIFTL(G_MODIFYVTX, 24, 8) | \
_SHIFTL((where), 16, 8) | \
_SHIFTL((vtx) * 2, 0, 16)), \
(unsigned int)(val) \
}

You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro).

This is an advanced macro. You need a good understanding of how vertices work in the RSP microcode before you use this macro (refer to gSPVertex).

You can use this macro to modify certain sections of a vertex after it has been sent to the RSP (by the gSPVertex macro). This is useful for vertices that are shared between two or more triangles that must have different properties when associated with one triangle versus the other triangle.

For example, you might have two adjacent triangles that both need smooth-shaded color, but one is smooth-shaded red-to-yellow and the other is smooth-shaded green-to-cyan. In this case, the vertex that is shared by both triangles is sent with red/yellow color by using the gSPVertex macro. The first triangle is drawn. Then, the gSPModifyVertex macro is used to change the color to green/cyan, and the second triangle is drawn.

The primary use of the gSPModifyVertex macro is to modify the texture coordinate of a vertex so that a vertex that is shared by two triangles with different textures and different texture coordinate spaces can contain the texture coordinate for the first texture and then be modified to contain the texture coordinate for the second texture.

It is faster to use the gSPModifyVertex macro than to send a new vertex macro with a different but similar vertex because no transformations or lighting are done to the vertex when you use the gSPModifyVertex macro.

The where argument specifies which part of the vertex is to be modified. It can hold one of the following values:

  • G_MWO_POINT_RGBA - changes the color of the vertex. The val parameter is interpreted as 4 bytes: red (high byte), green, blue, and alpha (low byte).
  • G_MWO_POINT_ST - changes the S and T values (texture coordinates of the vertex). The high 16 bits of val specify the S coordinate, and the low 16 bits specify the T coordinate. Each coordinate is an S10.5 number.
  • G_MWO_POINT_XYSCREEN - change the screen coordinates of the vertex. The high 16 bits of val specify the X coordinate and the low 16 bits specify the Y coordinate. Both coordinates are S13.2 numbers with 0,0 being the upper-left of the screen, positive X going right, and positive Y going down.
  • G_MWO_POINT_ZSCREEN - changes the screen Z coordinate of the vertex. The entire 32-bit val is taken as the new screen Z value. It is a 16.16 number in the range 0x00000000 to 0x03ff0000.
Note
Lighting is not performed after a gSPModifyVertex macro, so modifying the color of the vertex with G_MWO_POINT_RGBA is just that - modifying the actual color that will be output. It is not a modification of normal values. This means it cannot be used to update vertex normals for lighting.

The S and T coordinates supplied in the gSPModifyVertex macro are never multiplied by the texture scale (from the gSPTexture macro), so you must pre-scale them before sending them. For example, if you want a texture scale of 1/2 (0x8000), make the S and T values sent with the gSPModifyVertex macro half the value of the equivalent values used with the gSPVertex macro.

Example

To share a vertex between two triangles with different textures and texture coordinates, use this code:

// load vertex by gSPVertex
gSPVertex(...);
// load texture of triangle 1
gDPLoadTextureBlock(...);
// draw triangle 1 using vertex #3
gSP1Triangle(glistp++, 1,2,3,0);
// change a value of vertex 3 to S=3.0 and T=2.5
gSPModifyVertex(glistp++, 3, G_MWO_POINT_ST, 0x00600050);
// load texture of triangle 2
gDPLoadTextureBlock(...);
// draw triangle 2 using vertex #3
gSP1Triangle(glistp++, 1,2,3,0);
Parameters
vtxspecifies which of the RSP's vertices (0-55) to modify
wherespecifies which part of the vertex to modify (G_MWO_POINT_RGBA, G_MWO_POINT_ST, G_MWO_POINT_XYSCREEN or G_MWO_POINT_ZSCREEN)
valis the new value for the part of the vertex to be modified (a 32 bit integer number)

◆ gsSPNormalsMode

#define gsSPNormalsMode ( mode)     gsMoveHalfwd(G_MW_FX, G_MWO_NORMALS_MODE, (mode) & 0xFF)

Normals mode: How to handle transformation of vertex normals from model to world space for lighting.

If mode = G_NORMALS_MODE_FAST, transforms normals from model space to world space with the M matrix. This is correct if the object's transformation matrix stack only included translations, rotations, and uniform scale (i.e. same scale in X, Y, and Z); otherwise, if the transformation matrix has nonuniform scale or shear, the lighting on the object will be somewhat distorted.

If mode = G_NORMALS_MODE_AUTO, transforms normals from model space to world space with M inverse transpose, which renders lighting correctly for the object regardless of its transformation matrix (nonuniform scale or shear is okay). Whenever vertices are drawn with lighting enabled after M has been changed, computes M inverse transpose from M. This requires swapping to overlay 4 for M inverse transpose and then back to overlay 2 for lighting, which produces roughly 3.5 us of extra DRAM traffic. This performance penalty happens effectively once per matrix, which is once per normal object or separated limb or about twice per flex skeleton limb. So in a scene with lots of complex skeletons, this may have a noticeable performance impact.

If mode = G_NORMALS_MODE_MANUAL, uses M inverse transpose for correct results like G_NORMALS_MODE_AUTO, but it never internally computes M inverse transpose. You have to upload M inverse transpose to the RSP using SPMITMatrix every time you change the M matrix. The DRAM traffic for the extra matrix uploads is much smaller than the overlay swaps, so if you can efficiently compute M inverse transpose on the CPU, this may be faster than G_NORMALS_MODE_AUTO.

Recommended to leave this set to G_NORMALS_MODE_FAST generally, and only set it to G_NORMALS_MODE_AUTO for specific objects at times when they actually have a nonuniform scale. For example, G_NORMALS_MODE_FAST for Mario generally, but G_NORMALS_MODE_AUTO temporarily while he is squashed.

◆ gsSPNumLights

#define gsSPNumLights ( n)     gsMoveWd( G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n))

Number of directional / point lights, in the range 0-9. There is also always one ambient light not counted in this number.

◆ gsSPOcclusionPlane

#define gsSPOcclusionPlane ( o)
Value:
gsDma2p( G_MOVEMEM, (o), sizeof(OcclusionPlane), G_MV_LIGHT, \
(G_MAX_LIGHTS * 0x10) + 0x18)

Set the occlusion plane. This is a quadrilateral in 3D space where all geometry behind it is culled. You should create occlusion plane candidates just behind walls and other large objects, and have your game engine pick the most optimal one every frame to send to the RSP.

Computing the coefficients for the occlusion plane is far too complicated to explain here. The reference implementation guOcclusionPlane is provided separately.

o is the address of an OcclusionPlane struct

◆ gsSPPopMatrix

#define gsSPPopMatrix ( n)    gsSPPopMatrixN( (n), 1)

macro which pops one of the matrix stacks in a static display list.

It pops one of the matrix stacks. The model view stack can be up to 10 matrices deep. The projection stack is 1 matrix deep, so it cannot be popped.

Note
If the stack is empty, the macro is ignored.
Parameters
nis the flag field that identifies which matrix stack to pop:

◆ gsSPPopMatrixN

#define gsSPPopMatrixN ( n,
num )   gsDma2p( G_POPMTX, (num) * 64, 64, 2, 0)

macro which pops one of the matrix stacks in a static display list.

It pops num of the matrix stacks. The model view stack can be up to 10 matrices deep. The projection stack is 1 matrix deep, so it cannot be popped.

Note
If the stack is empty, the macro is ignored.
Parameters
nis the flag field that identifies which matrix stack to pop:
numis the number of matrices to pop

◆ gsSPSetLights

#define gsSPSetLights ( n,
name )
Value:
gsDma2p(G_MOVEMEM, &(name), (n) * 0x10 + 8, G_MV_LIGHT, 0x10)
#define gsSPNumLights(n)
Definition gbi.h:3292

Set all your scene's lights (directional/point + ambient) with one memory transaction. n is the number of directional / point lights, from 0 to 9. There is also always an ambient light. name should be the NAME of a Lights struct (NOT A POINTER) filled in with all the lighting data. You can use the gdSPDef* macros to fill in the struct or just do it manually. Example: Lights2 myLights; // 2 dir/pos + 1 ambient gSPSetLights(POLY_OPA_DISP++, 2, myLights);

If you need to use a pointer, e.g. if the number of lights is variable at runtime: Light *lights = memory_allocate((numLights + 1) * sizeof(Light)); lights[0].p.pos = ...; lights[1].l.dir = ...; ... lights[numLights].l.col = ambient_color(); gSPSetLights(POLY_OPA_DISP++, numLights, *lights); // <- NOTE DEREFERENCE

If you're wondering why this macro takes a name / dereference instead of a pointer, it's for backwards compatibility.

◆ gsSPTexture

#define gsSPTexture ( s,
t,
level,
tile,
on )
Value:
{ \
(_SHIFTL(G_TEXTURE, 24, 8) | \
_SHIFTL((level), 11, 3) | \
_SHIFTL((tile), 8, 3) | \
_SHIFTL((on), 1, 7)), \
(_SHIFTL((s), 16, 16) | \
_SHIFTL((t), 0, 16)) \
}

Macros to turn texture on/off

◆ gsSPTextureL

#define gsSPTextureL ( s,
t,
level,
bowtie,
tile,
on )    gsSPTexture(s, t, level, tile, on)

The bowtie value is a workaround for a bug in HW V1, and is not supported by F3DEX2, let alone F3DEX3.

◆ gsSPTriFan

#define gsSPTriFan ( v1,
v2,
v3,
v4,
v5,
v6,
v7 )    _gsSP5Triangles(G_TRIFAN, v1, v2, v3, v4, v5, v6, v7)

5 Triangles in fan arrangement. Draws the following tris: v1-v2-v3, v1-v3-v4, v1-v4-v5, v1-v5-v6, v1-v6-v7 Otherwise works the same as SPTriStrip, see above.

◆ gsSPTriStrip

#define gsSPTriStrip ( v1,
v2,
v3,
v4,
v5,
v6,
v7 )    _gsSP5Triangles(G_TRISTRIP, v1, v2, v3, v4, v5, v6, v7)

5 Triangles in strip arrangement. Draws the following tris: v1-v2-v3, v3-v2-v4, v3-v4-v5, v5-v4-v6, v5-v6-v7 If you want to draw fewer tris, set indices to -1 from the right. e.g. to draw 4 tris, set v7 to -1; to draw 3 tris, set v6 to -1 Note that any set of 3 adjacent tris can be drawn with either SPTriStrip or SPTriFan. For arbitrary sets of 4 adjacent tris, four out of five of them can be drawn with one of SPTriStrip or SPTriFan. The 4-triangle formation which can't be drawn with either command looks like the Triforce.

◆ gsSPVertex

#define gsSPVertex ( v,
n,
v0 )
Value:
{ \
(_SHIFTL(G_VTX, 24, 8) | \
_SHIFTL((n), 12, 8) | \
_SHIFTL((v0) + (n), 1, 7)), \
(unsigned int)(v) \
}

macro which loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons in a static display list.

It loads an internal vertex buffer in the RSP with points that are used by gSP1Triangle macros to generate polygons. This vertex cache can hold up to 56 vertices, and the vertex loading can begin at any entry (index) within the cache. The vertex coordinates (x,y,z) are encoded in signed 2's complement, 16-bit integers. The texture coordinates (s,t) are encoded in S10.5 format. A vertex either has a color or a normal (for shading). These values are 8-bit values. The colors and alphas are treated as 8-bit unsigned values (0-255), but the normals are treated as 8-bit signed values (-128 to 127). Therefore, the appropriate member of the union to use (.v. or .n.) depends on whether you are using colors or normals.

Normal coordinates range from -1.0 to 1.0. A value of -1.0 is represented as -128, and a value of 1.0 is represented as 128, but because the maximum positive value of a signed byte is 127, a value of 1.0 can't really be represented. Therefore, 0.992 is the maximum representable positive value, which is good enough for this purpose.

The flag value is used for the packed normals feature to store normals with octahedral encoding.

The coordinates (x,y,z) are transformed using the current 4x4 projection and model view matrices, and (s,t) are transformed using the scale defined by gSPTexture.

Example

To load vertex cache entry 2,3,4, use this code:

gSPVertex(glistp++, v, 3, 2);
Note
Because the RSP geometry transformation engine uses a vertex list with triangle list architecture, it is quite powerful. A simple one-triangle macro retains least performance compared to gSP2Triangles or the new 5 tris commands in EX3 (gSPTriStrip, gSPTriFan).
Parameters
vis the pointer to the vertex list (segment address)
nis the number of vertices
v0is the load vertex by index vo(0~55) in vertex buffer

Typedef Documentation

◆ Mtx_t

typedef long int Mtx_t[4][4]

4x4 matrix, fixed point s15.16 format. First 8 words are integer portion of the 4x4 matrix Last 8 words are the fraction portion of the 4x4 matrix