include "inc/F3DEX2.inc" include "inc/CC.inc" include "inc/dlist.inc" constant FOV90(0) macro _g(variable c, variable a, variable b) { WriteDL((c << 24) | a, b) } framecount: dw 0 SmoothStep16: // a0: s15.16? // v0: s15.16 // v1: lower 16 bits // t9 = abs(a0) bgez a0,+ addu t9, r0, a0 subu t9, r0, a0 + // t9 = triangle_wave(t9) // note that every minimum and maximum value is repeated once li t0, 0x1FFFF // period of 2 and t9, t0 lli t0, 0xFFFF subu t9, t0, t9 bgez t9,+ subiu t1, r0, 1 subu t9, t1, t9 + subu t9, t0, t9 // t8 = t9 * t9 multu t9, t9 mflo t8 srl t8, 16 // t7 = 3 - 2 * t9 sll t7, t9, 1 // times two subu t7, r0, t7 // negate li t0, 3 << 16 addu t7, t0 // t6 = t8 * t7 // instead do a u0.15 * u2.15 multiply to avoid overflow: srl t8, 1 srl t7, 1 multu t8, t7 mflo t6 srl v0, t6, 14 sll v1, t6, 1 jr ra nop WriteDList: // a0: pointer to receive F3DZEX instructions // a1: use alt color buffer (boolean) subiu sp, 0x20 sw ra, 0x10(sp) sw s0, 0x14(sp) sw s1, 0x18(sp) sw s2, 0x1C(sp) bnez a1,+ nop la a1, VIDEO_C_IMAGE j ++ nop + la a1, VIDEO_C_IMAGE_ALT + or s0, a0, r0 or s1, a1, r0 // move the object around based on framecount la t8, framecount lw t9, 0(t8) sll a0, t9, 16 + 7 srl a0, 15 jal SmoothStep16 nop or s2, v0, r0 la t8, framecount lw t9, 0(t8) sll a0, t9, 16 + 7 srl a0, 15 jal SmoothStep16 subiu a0, 0x7FFF subu s2, r0, s2 addiu s2, 0x7FFF sll s2, 1 subu v0, r0, v0 addiu v0, 0x7FFF sll v0, 1 // s2: cos-like // v0: sin-like la t8, view_mat1 sh s2, MAT_XX_FRAC(t8) sra t9, s2, 16 sh t9, MAT_XX(t8) subu v0, r0, v0 sh v0, MAT_XZ_FRAC(t8) sra t9, v0, 16 sh t9, MAT_XZ(t8) subu v0, r0, v0 sh v0, MAT_ZX_FRAC(t8) sra t9, v0, 16 sh t9, MAT_ZX(t8) sh s2, MAT_ZZ_FRAC(t8) sra t9, s2, 16 sh t9, MAT_ZZ(t8) or a0, s0, r0 // init gSetSegment0(0) // set to 0 so that 00-prefixed addresses are absolute (physical). gReset() gSetScissor(0, 0, 0, WIDTH, HEIGHT) // TODO: use mode enum gSetBlendColor(0,0,0,0) gClipRatio(2) gSetZImage(VIDEO_Z_IMAGE) // this overwrites our color image address so we must do it first: gClearZImage(WIDTH, HEIGHT, VIDEO_Z_IMAGE) gPipeSync() WriteCB(G_SETCIMB_UPPER_WORD | (WIDTH - 1), s1) if HICOLOR { gSetFillColor(0x444444FF) // dark gray } else { gSetFillColor(0x42114211) // dark gray } gFillRect(0, 0, WIDTH - 1, HEIGHT - 1) gPipeSync() if HICOLOR { gSetFillColor(0xFFFFFFFF) // white } else { gSetFillColor(0xFFFFFFFF) // white } gPipeSync() // note that all the coordinates are inclusive! if HIRES { gFillRect(WIDTH/2-8, HEIGHT/2-8, WIDTH/2+7, HEIGHT/2+7) } else { gFillRect(WIDTH/2-4, HEIGHT/2-4, WIDTH/2+3, HEIGHT/2+3) } gPipeSync() gViewport(viewport) gPerspNorm(PERSPECTIVE_NORMALIZATION) gMatrix(view_mat0, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION) gMatrix(view_mat1, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION) if 0 { // colorful gPipeSync() gSetCombine(0,0,0,4,0,0,0,4, 0,0,0,4,0,0,0,4) variable clk1(G_BL_CLR_IN << 12 | G_BL_A_IN << 8 | G_BL_CLR_MEM << 4 | G_BL_A_MEM) variable clk2(G_BL_CLR_IN << 12 | G_BL_A_IN << 8 | G_BL_CLR_MEM << 4 | G_BL_A_MEM) variable upper(G_PM_NPRIMITIVE | G_CYC_1CYCLE | G_TP_NONE | G_TD_CLAMP | G_TL_TILE | G_TT_NONE | G_TF_AVERAGE | G_TC_FILT | G_CK_NONE | G_CD_MAGICSQ | G_AD_PATTERN) variable lower(AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | clk1 << 18 | clk2 << 16) gSetOtherMode(upper, lower) gGeometryMode(0, G_ZBUFFER | G_SHADE | G_CULL_FRONT | G_SHADING_SMOOTH) } else { gReset() // sane upper other mode: no lod constant SANE(G_PM_NPRIMITIVE | G_TP_PERSP | G_TD_CLAMP | G_TL_TILE | G_TC_FILT | G_CK_NONE | G_CD_MAGICSQ | G_AD_PATTERN) // sane lower other mode: high quality constant AAZB(AA_EN | Z_CMP | Z_UPD | IM_RD) gPipeSync() if 1 { //gLoadTex(texture + 0x200, G_IM_FMT_CI, G_IM_SIZE_8, 64, 64) gLoadTex(texture + 0x200, G_IM_FMT_CI, G_IM_SIZE_8, 32, 32) gLoadPal256(texture) variable G_TT(G_TT_RGBA16) } else { gLoadTex(texture, G_IM_FMT_RGBA, G_IM_SIZE_16, 32, 64) variable G_TT(G_TT_NONE) } CC.Cycle1Color(CC.COLOR_TEXEL_0, CC.CONST_0, CC.COLOR_SHADE, CC.CONST_0) CC.Cycle1Alpha(CC.CONST_0, CC.CONST_0, CC.CONST_0, CC.CONST_1) CC.Cycle2Color(CC.CONST_0, CC.CONST_0, CC.CONST_0, CC.COLOR_OUT) CC.Cycle2Alpha(CC.CONST_0, CC.CONST_0, CC.CONST_0, CC.ALPHA_OUT) CC.Commit() variable clk1(G_BL_CLR_IN << 12 | G_BL_A_IN << 8 | G_BL_CLR_IN << 4 | G_BL_1MA) variable clk2(G_BL_CLR_IN << 12 | G_BL_A_IN << 8 | G_BL_CLR_MEM << 4 | G_BL_A_MEM) variable upper(SANE | G_CYC_2CYCLE | G_TF_BILERP | G_TT) variable lower(AAZB | ZMODE_OPA | ALPHA_CVG_SEL | clk1 << 18 | clk2 << 16) gSetOtherMode(upper, lower) gGeometryMode(0xFFFFFF, G_CULL_BACK) gSetPrimColor(0, 0, 0xFF,0xFF,0xFF,0xFF) gTexture(0x8000, 0x8000, 0, 0, 2) } gSetSegment6(model) gMatrix(model_mat, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW) gDisplayList((6 << 24) | MODEL_START) if 0 { // debug: display coverage values onscreen. gPipeSync() gSetOtherMode(G_CYC_1CYCLE, G_ZS_PRIM | IM_RD | FORCE_BL | G_BL_CLR_IN << 30 | G_BL_0 << 26 | G_BL_CLR_BL << 22 | G_BL_A_MEM << 18) gSetBlendColor(0xFF,0xFF,0xFF,0xFF) gSetPrimDepth(0xFFFF, 0xFFFF) gFillRect(0, 0, WIDTH - 1, HEIGHT - 1) } // finish. gFullSync() gEndList() la t8, framecount lw t9, 0(t8) addiu t9, 1 sw t9, 0(t8) lw ra, 0x10(sp) lw s0, 0x14(sp) lw s1, 0x18(sp) lw s2, 0x1C(sp) jr ra addiu sp, 0x20 print {dpos} / 8, "\n" align(8) viewport: // note that the third parameters here affect the range of Z-buffering. dh WIDTH/2*4, HEIGHT/2*4, 0x1FF, 0 // scale dh WIDTH/2*4, HEIGHT/2*4, 0x1FF, 0 // translation view_mat0: if FOV90 { Mat.X($0000'C000, $0000'0000, $0000'0000, $0000'0000) Mat.Y($0000'0000, $0001'0000, $0000'0000, $0000'0000) } else { Mat.X($0001'4C8D, $0000'0000, $0000'0000, $0000'0000) Mat.Y($0000'0000, $0001'BB67, $0000'0000, $0000'0000) } Mat.Z($0000'0000, $0000'0000, $FFFE'FF9A, $FFFF'0000) Mat.W($0000'0000, $0000'0000, $FFEB'FC00, $0000'0000) Mat.rix() constant PERSPECTIVE_NORMALIZATION($000A) view_mat1: Mat.X($0001'0000, $0000'0000, $0000'0000, $0000'0000) Mat.Y($0000'0000, $0001'0000, $0000'0000, $0000'0000) Mat.Z($0000'0000, $0000'0000, $0001'0000, $0000'0000) if FOV90 { Mat.W($0000'0000, $FFD4'0000, $FF80'0000, $0001'0000) } else { Mat.W($0000'0000, $FFD4'0000, $FF40'0000, $0001'0000) } Mat.rix() model_mat: MatObject(0,0,0, 0x0800) identity: MatEye() macro _g(variable c, variable a, variable b) { dw (c << 24) | a, b } if 1 { model: // a colorful cube constant S(0x400) variable lo(0 << 5) variable hi(63 << 5) // assuming texture is HALF the width/height here // TODO: write a macro for this struct dh -S, -S, -S, 0, lo, lo, 0x0000, 0x00FF // left bot back dh -S, -S, +S, 0, lo, hi, 0x0000, 0xFFFF // left bot front dh -S, +S, -S, 0, hi, lo, 0x00FF, 0x00FF // left top back dh -S, +S, +S, 0, hi, hi, 0x00FF, 0xFFFF // left top front dh +S, -S, -S, 0, lo, hi, 0xFF00, 0x00FF // right bot back dh +S, -S, +S, 0, lo, lo, 0xFF00, 0xFFFF // right bot front dh +S, +S, -S, 0, hi, hi, 0xFFFF, 0x00FF // right top back dh +S, +S, +S, 0, hi, lo, 0xFFFF, 0xFFFF // right top font constant MODEL_START(pc() - model) gPipeSync() gVertex(0x06000000, 8, 0) gQuadTri(0, 1, 3, 2) gQuadTri(1, 5, 7, 3) gQuadTri(5, 4, 6, 7) gQuadTri(4, 0, 2, 6) gQuadTri(4, 5, 1, 0) gQuadTri(2, 3, 7, 6) gEndList() } else { constant MODEL_START(0) insert model, "res/teapot.F3D" } align(16) insert texture, "res/blah.ci8" // 0x200 pal followed by 0x800 image