Connor Olding
be6a0f8261
unfortunately i seem to have broken console compatibility along the way; it dies after a few frames. i will have to fix this later. for now, i just really need to commit something.
619 lines
24 KiB
C++
619 lines
24 KiB
C++
|
|
// gMatrix: params argument
|
|
// NOTE: the 0 flags are to declare intent. they have no effect.
|
|
constant G_MTX_MODELVIEW(0)
|
|
constant G_MTX_PROJECTION(4)
|
|
constant G_MTX_MUL(0)
|
|
constant G_MTX_LOAD(2)
|
|
constant G_MTX_NOPUSH(0)
|
|
constant G_MTX_PUSH(1)
|
|
|
|
// gMoveWord: index argument
|
|
constant G_MW_MATRIX(0x0)
|
|
constant G_MW_NUMLIGHT(0x2)
|
|
constant G_MW_CLIP(0x4)
|
|
constant G_MW_SEGMENT(0x6)
|
|
constant G_MW_FOG(0x8)
|
|
constant G_MW_LIGHTCOL(0xA)
|
|
constant G_MW_FORCEMTX(0xC)
|
|
constant G_MW_PERSPNORM(0xE)
|
|
|
|
// gMoveWord: offset argument
|
|
constant G_MWO_CLIP_RNX(0x04)
|
|
constant G_MWO_CLIP_RNY(0x0C)
|
|
constant G_MWO_CLIP_RPX(0x14)
|
|
constant G_MWO_CLIP_RPY(0x1C)
|
|
|
|
// gMoveMemory: index argument
|
|
constant G_MV_MMTX(2)
|
|
constant G_MV_PMTX(6)
|
|
constant G_MV_VIEWPORT(8)
|
|
constant G_MV_LIGHT(10)
|
|
constant G_MV_POINT(12)
|
|
constant G_MV_MATRIX(14)
|
|
|
|
// gSetTImage, gSetCImage: fmt argument
|
|
constant G_IM_FMT_RGBA(0)
|
|
constant G_IM_FMT_YUV(1)
|
|
constant G_IM_FMT_CI(2)
|
|
constant G_IM_FMT_IA(3)
|
|
constant G_IM_FMT_I(4)
|
|
|
|
// gSetTImage, gSetCImage: size argument
|
|
constant G_IM_SIZE_4(0)
|
|
constant G_IM_SIZE_8(1)
|
|
constant G_IM_SIZE_16(2)
|
|
constant G_IM_SIZE_32(3)
|
|
constant G_IM_SIZE_DD(5)
|
|
|
|
// gGeometryMode: clearbits, setbits arguments
|
|
constant G_ZBUFFER(1 << 0)
|
|
constant G_SHADE(1 << 2)
|
|
constant G_CULL_FRONT(1 << 9)
|
|
constant G_CULL_BACK(1 << 10)
|
|
constant G_FOG(1 << 16)
|
|
constant G_LIGHTING(1 << 17)
|
|
constant G_TEXTURE_GEN(1 << 18)
|
|
constant G_TEXTURE_GEN_LINEAR(1 << 19)
|
|
constant G_SHADING_SMOOTH(1 << 21)
|
|
constant G_CLIPPING(1 << 23)
|
|
|
|
macro gNoOp() {
|
|
// stalls the RDP (and not the RSP?)
|
|
_g(0x00, 0, 0)
|
|
}
|
|
|
|
macro gVertex(variable vaddr, variable numv, variable vbidx) {
|
|
// TODO: document
|
|
if numv < 1 || numv > 32 {; error "numv out of range"; }
|
|
if vbidx < 0 || vbidx > 31 {; error "vbidx out of range"; }
|
|
_g(0x01, (numv << 12) | (((vbidx + numv) & 0x7F) << 1), vaddr)
|
|
}
|
|
|
|
macro gModifyVertex(variable vbidx, variable where, variable val) {
|
|
// TODO: document
|
|
if where != 0x10 && where != 0x14 && where != 0x18 && where != 0x1C {; error "invalid enum for where"; }
|
|
if vbidx < 0 || vbidx > 0x7FFF {; error "vbidx out of range"; }
|
|
_g(0x02, (where << 16) | (vbidx << 1), val)
|
|
}
|
|
|
|
macro gCullList(variable vfirst, variable vlast) {
|
|
// TODO: document
|
|
if vfirst < 0 || vfirst > 0x7FFF {; error "vfirst out of range"; }
|
|
if vlast < 0 || vlast > 0x7FFF {; error "vlast out of range"; }
|
|
_g(0x03, vfirst << 1, vlast << 1)
|
|
}
|
|
|
|
macro gBranchLessZ(variable newdl, variable vbidx, variable zval) {
|
|
// TODO: check ranges, document
|
|
gRdpHalf1(newdl)
|
|
_g(0x04, ((vbidx * 5) << 12) | (vbidx * 2), zval)
|
|
}
|
|
|
|
macro gTri1(variable v0, variable v1, variable v2) {
|
|
// draws two triangles given vertex indices relative to those loaded by gVertex.
|
|
// for G_CULL_FRONT, the vertices should be given in a clockwise order.
|
|
// for G_CULL_BACK, the vertices should be given in a counter-clockwise order.
|
|
if v0 < 0 || v0 > 31 {; error "v0 out of range"; }
|
|
if v1 < 0 || v1 > 31 {; error "v1 out of range"; }
|
|
if v2 < 0 || v2 > 31 {; error "v2 out of range"; }
|
|
_g(0x05, (v0 << 17) | (v1 << 9) | (v2 << 1), 0)
|
|
}
|
|
|
|
macro gTri2(variable a0, variable a1, variable a2, variable b0, variable b1, variable b2) {
|
|
// draws two triangles given vertex indices relative to those loaded by gVertex.
|
|
// some microcodes run this faster than the equivalent two gTri1 calls.
|
|
// for G_CULL_FRONT, the vertices should be given in a clockwise order.
|
|
// for G_CULL_BACK, the vertices should be given in a counter-clockwise order.
|
|
if a0 < 0 || a0 > 31 {; error "a0 out of range"; }
|
|
if a1 < 0 || a1 > 31 {; error "a1 out of range"; }
|
|
if a2 < 0 || a2 > 31 {; error "a2 out of range"; }
|
|
if b0 < 0 || b0 > 31 {; error "b0 out of range"; }
|
|
if b1 < 0 || b1 > 31 {; error "b1 out of range"; }
|
|
if b2 < 0 || b2 > 31 {; error "b2 out of range"; }
|
|
_g(0x06, (a0 << 17) | (a1 << 9) | (a2 << 1), (b0 << 17) | (b1 << 9) | (b2 << 1))
|
|
}
|
|
|
|
macro gQuad(variable v0, variable v1, variable v2, variable v3) {
|
|
// you really should be using gTri2 instead.
|
|
// some microcodes don't support this.
|
|
_g(0x07, (v0 << 17) | (v1 << 9) | (v2 << 1), (v0 << 17) | (v2 << 9) | (v3 << 1))
|
|
}
|
|
|
|
macro gLine3D(variable a, variable b) {
|
|
// TODO: document, implement
|
|
_g(0x08, a, b)
|
|
}
|
|
|
|
// these triangle commands are never used directly,
|
|
// instead, they are generated by the RSP
|
|
// by OR-ing the lowest byte of the current GeometryMode with 0xC8.
|
|
|
|
macro gTriFill(variable a, variable b) {
|
|
// (internal use) fill triangle
|
|
_g(0xC8, a, b)
|
|
}
|
|
|
|
macro gTriFillZ(variable a, variable b) {
|
|
// (internal use) fill triangle utilizing z-buffer
|
|
_g(0xC9, a, b)
|
|
}
|
|
|
|
macro gTriTexture(variable a, variable b) {
|
|
// (internal use) texture triangle
|
|
_g(0xCA, a, b)
|
|
}
|
|
|
|
macro gTriTextureZ(variable a, variable b) {
|
|
// (internal use) texture triangle utilizing z-buffer
|
|
_g(0xCB, a, b)
|
|
}
|
|
|
|
macro gTriShade(variable a, variable b) {
|
|
// (internal use) shade triangle
|
|
_g(0xCC, a, b)
|
|
}
|
|
|
|
macro gTriShadeZ(variable a, variable b) {
|
|
// (internal use) shade triangle utilizing z-buffer
|
|
_g(0xCD, a, b)
|
|
}
|
|
|
|
macro gTriShadeTexture(variable a, variable b) {
|
|
// (internal use) shade and texture triangle
|
|
_g(0xCE, a, b)
|
|
}
|
|
|
|
macro gTriShadeTextureZ(variable a, variable b) {
|
|
// (internal use) shade and texture triangle utilizing z-buffer
|
|
_g(0xCF, a, b)
|
|
}
|
|
|
|
macro gSpecial3(variable a, variable b) {
|
|
// TODO: see if this actually does something
|
|
_g(0xD3, a, b)
|
|
}
|
|
|
|
macro gSpecial2(variable a, variable b) {
|
|
// TODO: see if this actually does something
|
|
_g(0xD4, a, b)
|
|
}
|
|
|
|
macro gSpecial1(variable a, variable b) {
|
|
// TODO: see if this actually does something
|
|
_g(0xD5, a, b)
|
|
}
|
|
|
|
macro gDmaIo(variable flag, variable dmem, variable dram, variable size) {
|
|
if flag != 0 && flag != 1 {; error "invalid enum for flag"; }
|
|
// TODO: check more ranges
|
|
_g(0xD6, (flag << 23) | (((dmem / 8) & 0x3FF) << 12) | (size - 1), dram)
|
|
}
|
|
|
|
macro gTexture(variable scaleS, variable scaleT, variable level, variable tile, variable on) {
|
|
// TODO: document
|
|
// scaleS and scaleT are fractional values; e.g. 0x8000 is 0.5.
|
|
// level + 1: number of mipmaps
|
|
if level < 0 || level > 7 {; error "level out of range"; }
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
if on != 0 && on != 1 {; error "invalid enum for on"; }
|
|
if scaleS < 0 || scaleS > 0xFFFF {; error "scaleS out of range"; }
|
|
if scaleT < 0 || scaleT > 0xFFFF {; error "scaleT out of range"; }
|
|
_g(0xD7, (level << 11) | (tile << 8) | on, (scaleS << 16) | scaleT)
|
|
}
|
|
|
|
macro gPopMatrix(variable num) {
|
|
// TODO: document, better range?
|
|
if num < 0 || num > 0x3FFFFFF {; error "num out of range"; }
|
|
_g(0xD8, 0x380002, num << 6)
|
|
}
|
|
|
|
macro gGeometryMode(variable clearbits, variable setbits) {
|
|
// TODO: document, add convenience macros
|
|
_g(0xD9, clearbits, setbits)
|
|
}
|
|
|
|
macro gMatrix(variable mtxaddr, variable params) {
|
|
// TODO: document, add convenience macros
|
|
if params < 0 || params > 7 {; error "invalid enum for params"; }
|
|
_g(0xDA, 0x380000 | params ^ G_MTX_PUSH, mtxaddr)
|
|
}
|
|
|
|
macro gMoveWord(variable index, variable offset, variable data) {
|
|
// TODO: document, add (more) convenience macros
|
|
if (index & 1) != 0 || index < 0 || index > 0xE {; error "invalid enum for index"; }
|
|
if offset < 0 || offset > 0xFFFF {; error "offset out of range"; }
|
|
if (offset & 3) != 0 {; error "offset unaligned"; }
|
|
_g(0xDB, (index << 16) | offset, data)
|
|
}
|
|
|
|
macro gMoveMemory(variable size, variable index, variable offset, variable addr) {
|
|
// TODO: document
|
|
if size < 1 || size > 0x100 {; error "size out of range"; }
|
|
if (index & 1) != 0 || index < 0 || index > 14 {; "invalid enum for index"; }
|
|
if offset < 0 || offset > 0x7F8 {; error "offset out of range"; }
|
|
if (offset & 7) != 0 {; error "offset unaligned"; }
|
|
variable written_size(((size - 1) / 8) & 0x1F)
|
|
_g(0xDC, (written_size << 19) | (offset << 5) | index, addr)
|
|
}
|
|
|
|
macro gLoadMicrocode(variable tstart, variable dstart, variable dsize) {
|
|
// TODO: document
|
|
if dsize < 0 || dsize > 0x1000 {; error "dsize out of range"; }
|
|
gRdpHalf1(dstart)
|
|
_g(0xDD, dsize, tstart)
|
|
}
|
|
|
|
macro gDisplayList(variable dl) {
|
|
// "calls" another display list,
|
|
// resuming execution from this point after "returning" with gEndList.
|
|
_g(0xDE, 0, dl)
|
|
}
|
|
|
|
macro gBranchList(variable dl) {
|
|
// jumps to another display list.
|
|
_g(0xDE, 1 << 16, dl)
|
|
}
|
|
|
|
macro gEndList() {
|
|
// ends a display list.
|
|
// this either "returns" to the last gBranchList,
|
|
// or in the absence of that, sets signal 2 and breaks.
|
|
_g(0xDF, 0, 0)
|
|
}
|
|
|
|
macro gSpNoOp() {
|
|
// stalls the RSP (and not the RDP?)
|
|
_g(0xE0, 0, 0)
|
|
}
|
|
|
|
macro gRdpHalf1(variable wordhi) {
|
|
// this command is used in other commands to carry additional information.
|
|
_g(0xE1, 0, wordhi)
|
|
}
|
|
|
|
macro gSetOtherModeL(variable shift, variable length, variable data) {
|
|
// TODO: document, add convenience macros.
|
|
// starts clearing bits starting from shift
|
|
// and upwards (towards the MSB) until length is met.
|
|
// TODO: is a length of 0 valid?
|
|
if shift < 0 || shift > 31 {; error "shift out of range"; }
|
|
if length < 1 || length > 32 {; error "length out of range"; }
|
|
if shift + length > 32 {; error "length exceeds word size for given shift"; }
|
|
_g(0xE2, ((32 - shift - length) << 16) | (length - 1), data)
|
|
}
|
|
|
|
macro gSetOtherModeH(variable shift, variable length, variable data) {
|
|
// TODO: document, add convenience macros.
|
|
// starts clearing bits starting from shift
|
|
// and upwards (towards the MSB) until length is met.
|
|
// TODO: is a length of 0 valid?
|
|
if shift < 0 || shift > 31 {; error "shift out of range"; }
|
|
if length < 1 || length > 32 {; error "length out of range"; }
|
|
if shift + length > 32 {; error "length exceeds word size for given shift"; }
|
|
_g(0xE3, ((32 - shift - length) << 16) | (length - 1), data)
|
|
}
|
|
|
|
macro gTextureRect(variable ulx, variable uly, variable lrx, variable lry, variable tile, variable uls, variable ult, variable dsdx, variable dtdy) {
|
|
// arguments: upper-left x, upper-left y, lower-right x, lower-right y,
|
|
// tile descriptor, texture S coord, texture T coord,
|
|
// change in S over X, change in T over Y.
|
|
// TODO: document, check uls/ult ranges
|
|
if ulx < 0 || ulx > 1024 * 4 {; error "ulx out of range"; }
|
|
if uly < 0 || uly > 1024 * 4 {; error "uly out of range"; }
|
|
if lrx < 0 || lrx > 1024 * 4 {; error "lrx out of range"; }
|
|
if lry < 0 || lry > 1024 * 4 {; error "lry out of range"; }
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xE4, (lrx << 12) | lry, (tile << 24) | (ulx << 12) | uly)
|
|
gRdpHalf1((uls << 16) | ult)
|
|
gRdpHalf2((dsdx << 16) | dtdy)
|
|
}
|
|
|
|
macro gTextureRect(variable ulx, variable uly, variable lrx, variable lry, variable tile, variable uls, variable ult, variable dtdx, variable dsdy) {
|
|
// same as gTextureRect except flipped along the diagonal:
|
|
// S is instead based on Y, and T is instead based on X.
|
|
// the last two arguments have accordingly different names.
|
|
// TODO: check uls/ult ranges
|
|
if ulx < 0 || ulx > 1024 * 4 {; error "ulx out of range"; }
|
|
if uly < 0 || uly > 1024 * 4 {; error "uly out of range"; }
|
|
if lrx < 0 || lrx > 1024 * 4 {; error "lrx out of range"; }
|
|
if lry < 0 || lry > 1024 * 4 {; error "lry out of range"; }
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xE4, (lrx << 12) | lry, (tile << 24) | (ulx << 12) | uly)
|
|
gRdpHalf1((uls << 16) | ult)
|
|
gRdpHalf2((dtdx << 16) | dsdy)
|
|
}
|
|
|
|
macro gRdpLoadSync() {
|
|
// wait for a texture to load.
|
|
_g(0xE6, 0, 0)
|
|
}
|
|
|
|
macro gRdpPipeSync() {
|
|
// wait for the last primitive to finish rendering.
|
|
_g(0xE7, 0, 0)
|
|
}
|
|
|
|
macro gRdpTileSync() {
|
|
// wait for rendering to finish before changing tile attributes.
|
|
// TODO: better document.
|
|
_g(0xE8, 0, 0)
|
|
}
|
|
|
|
macro gRdpFullSync() {
|
|
// finish rendering. usually followed by a final gEndList command.
|
|
_g(0xE9, 0, 0)
|
|
}
|
|
|
|
macro gSetKeyGB() {
|
|
// TODO
|
|
_g(0xEA, 0, 0)
|
|
}
|
|
|
|
macro gSetKeyR() {
|
|
// TODO
|
|
_g(0xEB, 0, 0)
|
|
}
|
|
|
|
macro gSetConvert() {
|
|
// TODO
|
|
_g(0xEC, 0, 0)
|
|
}
|
|
|
|
macro gSetScissor(variable mode, variable ulx, variable uly, variable lrx, variable lry) {
|
|
// constrains rendering to a rectangle.
|
|
// arguments: mode, upper-left x, upper-left y, lower-right x, lower-right y.
|
|
// the lower-right coordinates are exclusive? whereas gFillRect is inclusive.
|
|
if mode != 0 && mode != 2 && mode != 3 {; error "invalid enum for mode"; }
|
|
if ulx < 0 || ulx > 1024 {; error "ulx out of range"; }
|
|
if uly < 0 || uly > 1024 {; error "uly out of range"; }
|
|
if lrx < 0 || lrx > 1024 {; error "lrx out of range"; }
|
|
if lry < 0 || lry > 1024 {; error "lry out of range"; }
|
|
// setting lrx < ulx or lry < uly is probably allowed,
|
|
// though i don't know what it would do.
|
|
_g(0xED, (ulx << 14) | (uly << 2), (lrx << 14) | (lry << 2))
|
|
}
|
|
|
|
macro gSetPrimDepth(variable z, variable dz) {
|
|
// fixes the Z value to a constant for the following primitives.
|
|
// useful for 2.5D effects, maybe?
|
|
// TODO: what are the ranges?
|
|
_g(0xEE, 0, (z << 16) | d)
|
|
}
|
|
|
|
macro gRdpSetOtherMode(variable omodeH, variable omodeL) {
|
|
// like gSetOtherModeL and gSetOtherModeR combined,
|
|
// but always overwriting existing values.
|
|
// TODO: check enums
|
|
_g(0xEF, omodeH, omodeL)
|
|
}
|
|
|
|
macro gLoadTLUT(variable tile, variable count) { // TODO: rename?
|
|
// used for loading color palettes.
|
|
// TODO: document properly, check ranges.
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xF0, 0, (tile << 24) | ((count & 0x3FF) << 14))
|
|
}
|
|
|
|
macro gRdpHalf2(variable wordlo) {
|
|
// this command is used in other commands to carry additional information.
|
|
_g(0xF1, 0, wordlo)
|
|
}
|
|
|
|
macro gSetTileSize(variable tile, variable uls, variable ult, variable lrs, variable lrt) {
|
|
// TODO: document, check ranges
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xF2, (uls << 12) | ult, (tile << 24) | (lrs << 12) | lrt)
|
|
}
|
|
|
|
macro gLoadBlock(variable tile, variable uls, variable ult, variable texels, variable dxt) {
|
|
// TODO: document, check ranges
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xF3, (uls << 12) | ult, (tile << 24) | (texels << 12) | dxt)
|
|
}
|
|
|
|
macro gLoadTile(variable tile, variable uls, variable ult, variable lrs, variable lrt) {
|
|
// TODO: document, check ranges
|
|
if tile < 0 || tile > 7 {; error "tile out of range"; }
|
|
_g(0xF4, (uls << 12) | ult, (tile << 24) | (lrs << 12) | lrt)
|
|
}
|
|
|
|
macro gSetTile() {
|
|
// TODO
|
|
_g(0xF5, 0, 0)
|
|
}
|
|
|
|
macro gFillRect(variable ulx, variable uly, variable lrx, variable lry) {
|
|
// TODO: describe.
|
|
// NOTE: coordinates are inclusive.
|
|
if ulx < 0 || ulx > 1024 {; error "ulx out of range"; }
|
|
if uly < 0 || uly > 1024 {; error "uly out of range"; }
|
|
if lrx < 0 || lrx > 1024 {; error "lrx out of range"; }
|
|
if lry < 0 || lry > 1024 {; error "lry out of range"; }
|
|
_g(0xF6, (lrx << 14) | (lry << 2), (ulx << 14) | (uly << 2))
|
|
}
|
|
|
|
macro gSetFillColor(variable color) {
|
|
// TODO: describe.
|
|
_g(0xF7, 0, color)
|
|
}
|
|
|
|
macro gSetFogColor(variable r, variable g, variable b, variable a) {
|
|
// sets fog color. also used as a general-purpose color register for blending.
|
|
// always given as 8-bit values regardless of any color formats being used.
|
|
if r < 0 || r > 0xFF {; error "red out of range"; }
|
|
if g < 0 || g > 0xFF {; error "green out of range"; }
|
|
if b < 0 || b > 0xFF {; error "blue out of range"; }
|
|
if a < 0 || a > 0xFF {; error "alpha out of range"; }
|
|
_g(0xF8, 0, (r << 24) | (g << 16) | (b << 8) | a)
|
|
}
|
|
|
|
macro gSetBlendColor(variable r, variable g, variable b, variable a) {
|
|
// sets a general-purpose color register for blending.
|
|
// always given as 8-bit values regardless of any color formats being used.
|
|
if r < 0 || r > 0xFF {; error "red out of range"; }
|
|
if g < 0 || g > 0xFF {; error "green out of range"; }
|
|
if b < 0 || b > 0xFF {; error "blue out of range"; }
|
|
if a < 0 || a > 0xFF {; error "alpha out of range"; }
|
|
_g(0xF9, 0, (r << 24) | (g << 16) | (b << 8) | a)
|
|
}
|
|
|
|
macro gSetPrimColor(variable minlevel, variable lodfrac, variable r, variable g, variable b, variable a) {
|
|
// TODO: describe.
|
|
// always given as 8-bit values regardless of any color formats being used.
|
|
if minlevel < 0 || minlevel > 0xFF {; error "minlevel out of range"; }
|
|
if lodfrac < 0 || lodfrac > 0xFF {; error "minlevel out of range"; }
|
|
if r < 0 || r > 0xFF {; error "red out of range"; }
|
|
if g < 0 || g > 0xFF {; error "green out of range"; }
|
|
if b < 0 || b > 0xFF {; error "blue out of range"; }
|
|
if a < 0 || a > 0xFF {; error "alpha out of range"; }
|
|
_g(0xFA, (minlevel << 8) | lodfrac, (r << 24) | (g << 16) | (b << 8) | a)
|
|
}
|
|
|
|
macro gSetEnvColor(variable r, variable g, variable b, variable a) {
|
|
// sets environment color. also used as a general-purpose color register for blending.
|
|
if r < 0 || r > 0xFF {; error "red out of range"; }
|
|
if g < 0 || g > 0xFF {; error "green out of range"; }
|
|
if b < 0 || b > 0xFF {; error "blue out of range"; }
|
|
if a < 0 || a > 0xFF {; error "alpha out of range"; }
|
|
_g(0xFB, 0, (r << 24) | (g << 16) | (b << 8) | a)
|
|
}
|
|
|
|
macro gSetCombine(variable a0, variable b0, variable c0, variable d0, variable Aa0, variable Ab0, variable Ac0, variable Ad0, variable a1, variable b1, variable c1, variable d1, variable Aa1, variable Ab1, variable Ac1, variable Ad1) {
|
|
// TODO: describe.
|
|
if a0 != (a0 & 0xF) {; error "a0 out of range"; }
|
|
if c0 != (c0 & 0x1F) {; error "c0 out of range"; }
|
|
if Aa0 != (Aa0 & 0x7) {; error "Aa0 out of range"; }
|
|
if Ac0 != (Ac0 & 0x7) {; error "Ac0 out of range"; }
|
|
if a1 != (a1 & 0xF) {; error "a1 out of range"; }
|
|
if c1 != (c1 & 0x1F) {; error "c1 out of range"; }
|
|
if b0 != (b0 & 0xF) {; error "b0 out of range"; }
|
|
if b1 != (b1 & 0xF) {; error "b1 out of range"; }
|
|
if Aa1 != (Aa1 & 0x7) {; error "Aa1 out of range"; }
|
|
if Ac1 != (Ac1 & 0x7) {; error "Ac1 out of range"; }
|
|
if d0 != (d0 & 0x7) {; error "d0 out of range"; }
|
|
if Ab0 != (Ab0 & 0x7) {; error "Ab0 out of range"; }
|
|
if Ad0 != (Ad0 & 0x7) {; error "Ad0 out of range"; }
|
|
if d1 != (d1 & 0x7) {; error "d1 out of range"; }
|
|
if Ab1 != (Ab1 & 0x7) {; error "Ab1 out of range"; }
|
|
if Ad1 != (Ad1 & 0x7) {; error "Ad1 out of range"; }
|
|
variable upper((a0 << 20) | (c0 << 15) | (Aa0 << 12) | (Ac0 << 9) | (a1 << 5) | c1)
|
|
variable lower((b0 << 28) | (b1 << 24) | (Aa1 << 21) | (Ac1 << 18) | (d0 << 15) | (Ab0 << 12) | (Ad0 << 9) | (d1 << 6) | (Ab1 << 3) | Ad1)
|
|
_g(0xFC, upper, lower)
|
|
}
|
|
|
|
macro gSetTImage(variable fmt, variable size, variable width, variable imgaddr) {
|
|
// sets the location in RDRAM for storing a texture image.
|
|
// only required for the relevant copy operations.
|
|
//if imgaddr & 0x1FFFFFFF > 0x800000 {; error "address out of range"; }
|
|
if fmt < 0 || fmt > 4 {; error "invalid enum for fmt"; }
|
|
if size < 0 || size > 5 || size == 4 {; error "invalid enum for size"; }
|
|
if width < 1 || width > 1024 {; error "width out of range"; }
|
|
_g(0xFD, (fmt << 21) | (size << 19) | (width - 1), imgaddr)
|
|
}
|
|
|
|
macro gSetZImage(variable imgaddr) {
|
|
// sets the location in RDRAM for storing the Z-buffer.
|
|
// only one is needed, and the format is fixed: (14 + 2) bits per pixel.
|
|
//if imgaddr & 0x1FFFFFFF > 0x800000 {; error "address out of range"; }
|
|
_g(0xFE, 0, imgaddr)
|
|
}
|
|
|
|
macro gSetCImage(variable fmt, variable size, variable width, variable imgaddr) {
|
|
// sets the location in RDRAM for storing the color buffer.
|
|
// sometimes refered to as a framebuffer?
|
|
// do not set this to the same address as the VI color buffer
|
|
// or else you will run into issues and wonder why nothing is blitting.
|
|
// instead, allocate space for two color buffers and swap between them.
|
|
if fmt < 0 || fmt > 4 {; error "invalid enum for fmt"; }
|
|
if size < 0 || size > 5 || size == 4 {; error "invalid enum for size"; }
|
|
if width < 1 || width > 1024 {; error "width out of range"; }
|
|
_g(0xFF, (fmt << 21) | (size << 19) | (width - 1), imgaddr)
|
|
}
|
|
|
|
// from here-on it's just convenience.
|
|
|
|
macro gLoadSync() {; gRdpLoadSync(); }
|
|
macro gPipeSync() {; gRdpPipeSync(); }
|
|
macro gTileSync() {; gRdpTileSync(); }
|
|
macro gFullSync() {; gRdpFullSync(); }
|
|
macro gSetOtherMode(variable omodeH, variable omodeL) {; gRdpSetOtherMode(omodeH, omodeL); }
|
|
|
|
macro gVtx(variable vaddr, variable numv, variable vbidx) {; gVertex(vaddr, numv, vbidx); }
|
|
macro gModifyVtx(variable vbidx, variable where, variable val) {; gModifyVertex(vbidx, where, val); }
|
|
|
|
// TODO: just how useful is this really?
|
|
macro gTextureOff() {; gTexture(0xFFFF, 0xFFFF, 0, 0, 0); }
|
|
|
|
// possible idea for the future: keeping track of segment addresses in bass defines?
|
|
macro gSetSegment0(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x0 * 4, vaddr); }
|
|
macro gSetSegment1(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x1 * 4, vaddr); }
|
|
macro gSetSegment2(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x2 * 4, vaddr); }
|
|
macro gSetSegment3(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x3 * 4, vaddr); }
|
|
macro gSetSegment4(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x4 * 4, vaddr); }
|
|
macro gSetSegment5(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x5 * 4, vaddr); }
|
|
macro gSetSegment6(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x6 * 4, vaddr); }
|
|
macro gSetSegment7(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x7 * 4, vaddr); }
|
|
macro gSetSegment8(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x8 * 4, vaddr); }
|
|
macro gSetSegment9(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0x9 * 4, vaddr); }
|
|
macro gSetSegmentA(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xA * 4, vaddr); }
|
|
macro gSetSegmentB(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xB * 4, vaddr); }
|
|
macro gSetSegmentC(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xC * 4, vaddr); }
|
|
macro gSetSegmentD(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xD * 4, vaddr); }
|
|
macro gSetSegmentE(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xE * 4, vaddr); }
|
|
macro gSetSegmentF(variable vaddr) {; gMoveWord(G_MW_SEGMENT, 0xF * 4, vaddr); }
|
|
|
|
// TODO
|
|
macro gInit() {; }
|
|
|
|
macro gQuadTri(variable v0, variable v1, variable v2, variable v3) {
|
|
gTri2(v0, v1, v2, v2, v3, v0)
|
|
}
|
|
|
|
macro gClipRatio(variable n) {
|
|
// specifies the ratio between the clipping and scissoring boxes.
|
|
// Frustrum Ratio?
|
|
if n < 1 || n > 6 {; error "n out of range"; }
|
|
gMoveWord(G_MW_CLIP, G_MWO_CLIP_RNX, n)
|
|
gMoveWord(G_MW_CLIP, G_MWO_CLIP_RNY, n)
|
|
gMoveWord(G_MW_CLIP, G_MWO_CLIP_RPX, 0x10000 - n)
|
|
gMoveWord(G_MW_CLIP, G_MWO_CLIP_RPY, 0x10000 - n)
|
|
}
|
|
|
|
macro gClearZImage(variable width, variable height, variable imgaddr) {
|
|
gSetCImage(G_IM_FMT_RGBA, G_IM_SIZE_16, width, imgaddr)
|
|
gSetOtherModeH(20, 2, 0x00300000) // TODO: use enums
|
|
gSetOtherModeL(3, 1, 0x00000000) // TODO: use enums
|
|
gSetFillColor(0xFFFCFFFC)
|
|
gFillRect(0, 0, width - 1, height - 1)
|
|
}
|
|
|
|
macro gViewport(variable viewport) {
|
|
gMoveMemory(16, G_MV_VIEWPORT, 0, viewport)
|
|
}
|
|
|
|
macro gPerspNorm(variable norm) {
|
|
gMoveWord(G_MW_PERSPNORM, 0, norm)
|
|
}
|
|
|
|
// a tool to figure out just what the heck raw gSetCombine commands are doing.
|
|
macro gDisasmCombine(variable upper, variable lower) {
|
|
if (upper >> 24) != 0xFC {; error "that's not a gSetCombine command!"; }
|
|
variable a0((upper >> 20) & 0xF)
|
|
variable c0((upper >> 15) & 0x1F)
|
|
variable Aa0((upper >> 12) & 0x7)
|
|
variable Ac0((upper >> 9) & 0x7)
|
|
variable a1((upper >> 5) & 0xF)
|
|
variable c1(upper & 0x1F)
|
|
variable b0((lower >> 28) & 0xF)
|
|
variable b1((lower >> 24) & 0xF)
|
|
variable Aa1((lower >> 21) & 0x7)
|
|
variable Ac1((lower >> 18) & 0x7)
|
|
variable d0((lower >> 15) & 0x7)
|
|
variable Ab0((lower >> 12) & 0x7)
|
|
variable Ad0((lower >> 9) & 0x7)
|
|
variable d1((lower >> 6) & 0x7)
|
|
variable Ab1((lower >> 3) & 0x7)
|
|
variable Ad1((lower >> 3) & 0x7)
|
|
print "gSetCombine(",a0,",",b0,",",c0,",",d0,",",Aa0,",",Ab0,",",Ac0,",",Ad0,", ",a1,",",b1,",",c1,",",d1,",",Aa1,",",Ab1,",",Ac1,",",Ad1,")\n"
|
|
}
|