void RDP_SetCImg( u32 w0, u32 w1 ) { gDPSetColorImage( _SHIFTR( w0, 21, 3 ), // fmt _SHIFTR( w0, 19, 2 ), // siz _SHIFTR( w0, 0, 12 ) + 1, // width w1 ); // img }
/*---------------------------------------------------------------------------- gfxClearCfb Clear frame buffer/Z buffer ----------------------------------------------------------------------------*/ void gfxClearCfb(void) { /* clear Z buffer*/ gDPSetDepthImage(glist_ptr++, OS_K0_TO_PHYSICAL(zbuffer)); gDPPipeSync(glist_ptr++); gDPSetCycleType(glist_ptr++, G_CYC_FILL); gDPSetColorImage(glist_ptr++, G_IM_FMT_RGBA, G_IM_SIZ_16b,SCREEN_WD, OS_K0_TO_PHYSICAL(zbuffer)); gDPSetFillColor(glist_ptr++,(GPACK_ZDZ(G_MAXFBZ,0) << 16 | GPACK_ZDZ(G_MAXFBZ,0))); gDPFillRectangle(glist_ptr++, 0, 0, SCREEN_WD-1, SCREEN_HT-1); gDPPipeSync(glist_ptr++); /* clear frame buffer */ gDPSetColorImage(glist_ptr++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, osVirtualToPhysical(cfb[gfx_cfbdrawbuffer])); gDPSetFillColor(glist_ptr++, (GPACK_RGBA5551(0, 0, 0, 1) << 16 | GPACK_RGBA5551(0, 0, 0, 1))); gDPFillRectangle(glist_ptr++, 0, 0, SCREEN_WD-1, SCREEN_HT-1); gDPPipeSync(glist_ptr++); }
/* * gameloop -- main loop of game * Called by gameproc; runs in gameThread. * Parameter: rsp_static_addr, the R4300 address where the * rsp_static segment was loaded */ static void gameloop(char *rsp_static_addr) { int oddframe = 0; /* Odd or even rendered frame? Start with even. */ int firstframe = 1; /* First frame? */ dynamic_stuff *generate; /* Dynamic info we're generating now */ Gfx *glistp0; /* Start of this frame's dynamic display list */ Gfx *glistp; /* Current position in dynamic display list */ OSTask *gentask; /* Task we're generating */ float t; /* Weight of 1st set of morph verticies */ int dir; /* Direction in which we're morphing */ int pausecnt; /* Countdown for "stickiness" at morph extremes */ t = 0.0; dir = 1; pausecnt = 0; while (1) { /* Start task on RSP, built in previous iteration of loop. */ if (!firstframe) osSpTaskStart(gentask); /* * Set up pointers to dynamic stuff. We're always generating one set * of dynamic data and drawing another. */ generate = &(dynamic[(oddframe ? 0 : 1)]); /* glist portion of generated dynamic data */ glistp0 = &(generate->glist[0]); glistp = glistp0; /* This one will be incremented as list is built */ /* * Tell RSP where each segment is */ gSPSegment(glistp++, 0, 0x0); /* Physical address segment */ /* Static segment (mapping never changes) */ gSPSegment(glistp++, STATIC_SEG, OS_K0_TO_PHYSICAL(rsp_static_addr)); /* Dynamic segment (mapping changes every frame) */ gSPSegment(glistp++, DYNAMIC_SEG, OS_K0_TO_PHYSICAL(generate)); /* RSP and RDP setup, and screen clear */ gSPDisplayList(glistp++, rspinit_dl); gSPDisplayList(glistp++, rdpinit_dl); #ifdef FB32BIT gDPSetColorImage(glistp++, G_IM_FMT_RGBA, G_IM_SIZ_32b, SCREEN_WD, OS_K0_TO_PHYSICAL(oddframe ? cfb_A : cfb_B)); #else gDPSetColorImage(glistp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, OS_K0_TO_PHYSICAL(oddframe ? cfb_A : cfb_B)); #endif gSPDisplayList(glistp++, scrnclr_dl); /* Must set color image again after zbuffer clear */ #ifdef FB32BIT gDPSetColorImage(glistp++, G_IM_FMT_RGBA, G_IM_SIZ_32b, SCREEN_WD, OS_K0_TO_PHYSICAL(oddframe ? cfb_A : cfb_B)); #else gDPSetColorImage(glistp++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, OS_K0_TO_PHYSICAL(oddframe ? cfb_A : cfb_B)); #endif /* Set Z-buffer */ gDPSetDepthImage(glistp++, OS_K0_TO_PHYSICAL(zbuffer)); /* * Matrix setup, and call display list that does real work */ drawframe(generate, &glistp, t); /* * Put an END on the top-level display list, and check that we * haven't overflowed the buffer. */ gDPFullSync(glistp++); /* Only need this if you want 'accurate' SP done? */ gSPEndDisplayList(glistp++); #ifdef DEBUG if ((int)(glistp - glistp0) > GLIST_SIZE) { /* does this check work?? */ osSyncPrintf("*** GLIST OVERFLOW ***\n"); /* Could quit here or something */ } #endif /* Update morph parameter t */ if (pausecnt == 0) { t += dir*(1.0/60.0); /* A full 60 frames to do the morph */ if (t < 0.0) {t = 0.0; dir = 1; pausecnt = 60;} if (t > 1.0) {t = 1.0; dir = -1; pausecnt = 60;} } else { pausecnt--; } /* * Build graphics task * Note that all addresses are KSEG0, even if used by the RSP. * Conversion is done by the task routines. */ gentask = &(task[oddframe ? 0 : 1]); gentask->t.type = M_GFXTASK; gentask->t.flags = 0x0; gentask->t.ucode_boot = (u64*) rspbootTextStart; gentask->t.ucode_boot_size = ((int)rspbootTextEnd - (int)rspbootTextStart); gentask->t.ucode = (u64*) gspF3DEX2_xbusTextStart; /* use XBUS */ gentask->t.ucode_data = (u64*) gspF3DEX2_xbusDataStart; gentask->t.ucode_size = 4096; gentask->t.ucode_data_size = 2048; gentask->t.dram_stack = (u64*) dram_stack; gentask->t.dram_stack_size = SP_DRAM_STACK_SIZE64; gentask->t.output_buff = (u64*) NULL; gentask->t.output_buff_size= (u64*) NULL; gentask->t.yield_data_ptr = (u64*) NULL; /* Graphics only - no yielding */ gentask->t.yield_data_size = 0x0; gentask->t.data_ptr = (u64*) glistp0; gentask->t.data_size = ((int) glistp - (int) glistp0); /* * Flush the whole cache. Should just do parts of it. */ osWritebackDCacheAll(); if (!firstframe) { /* Wait for task completion (message from RDP) */ osRecvMesg(&RDPDoneMessageQ, NULL, OS_MESG_BLOCK); /* * Specify frame buffer to be displayed starting at next retrace. * We display the one that we've just finished rendering. */ osViSwapBuffer(oddframe ? cfb_B : cfb_A); } /* * Wait for the retrace before rendering next frame * (otherwise we might overwrite the frame which is being displayed). * But first, make sure that the retrace queue is empty in case we * took too long to render the last frame. */ if (MQ_IS_FULL(&RetraceMessageQ)) osRecvMesg(&RetraceMessageQ, NULL, OS_MESG_NOBLOCK); osRecvMesg(&RetraceMessageQ, NULL, OS_MESG_BLOCK); /* Switch to our other set of variables */ oddframe ^= 1; /* No longer the first frame */ firstframe = 0; } /* while(1) */ } /* gameloop */
/*---------------------------------------------------------------------------* * M A I N *---------------------------------------------------------------------------*/ void Main(void *arg) { u8 draw_frame = 0; u32 objRM; Gfx *gp, *gtop; OSTime rspstart; u32 rsptime, rdptime; bg16seg = (u32)_codeSegmentEnd + (u32)_staticSegmentEnd - (u32)_staticSegmentStart; bg8seg = bg16seg + + (u32)_bg_rgbaSegmentRomEnd - (u32)_bg_rgbaSegmentRomStart; loadSegment(bg16seg, bg8seg); menuInit(); actionInit(); rsptime = rdptime = 0; while(1){ /*------ Start to read the controller. ------*/ osContStartReadData(&siMessageQ); /*------ Wait for the retrace. ------*/ osRecvMesg(&retraceMessageQ, NULL, OS_MESG_BLOCK); /*------ Setting the Bg structure. ------*/ setBg(); /*------ Setting the Object structure. ------*/ setObject(); /*------ Create the Gfx list. ------*/ gtop = gp = glist[draw_frame]; /*------ RSP initialization setting. ------*/ gSPSegment(gp ++, 0, 0x0); gSPSegment(gp ++, STATIC_SEGMENT, _codeSegmentEnd); if (aMenu[MENU_BG_TX_FORMAT]){ gSPSegment(gp ++, BG_SEGMENT, bg8seg); } gDPSetColorImage(gp ++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, system_cfb[draw_frame]); gSPDisplayList(gp ++, rdpInit_dl); gSPDisplayList(gp ++, clearCfb_dl); gSPDisplayList(gp ++, spriteInit_dl); /*------ Bg output. ------*/ if (aMenu[MENU_BG_TX_FORMAT]){ gDPSetTextureLUT(gp ++, G_TT_RGBA16); gSPObjLoadTxtr(gp ++, &objBgTLUT); } if (aMenu[MENU_BG_SCALABLE] == 0){ /* Unscalable BG plane */ gDPSetRenderMode(gp ++, G_RM_NOOP, G_RM_NOOP2); gDPSetCycleType(gp ++, G_CYC_COPY); gSPBgRectCopy(gp ++, &objBg); } else { /* Scalable BG plane */ gDPSetRenderMode(gp ++, G_RM_SPRITE, G_RM_SPRITE2); gDPSetCycleType(gp ++, G_CYC_1CYCLE); gDPSetTextureFilter(gp ++, RMmodeTable[aMenu[MENU_RENDERMODE]].txtrFilter); if (aMenu[MENU_BG_SCALABLE] == 1){ /* Emulated by CPU */ guS2DEmuSetScissor(0, 0, SCREEN_WD, SCREEN_HT, (RMmodeTable[aMenu[MENU_RENDERMODE]].txtrFilter == G_TF_BILERP)); guS2DEmuBgRect1Cyc(&gp, &objBg); } else { /* GBI command */ gSPObjRenderMode(gp ++, RMmodeTable[aMenu[MENU_RENDERMODE]].objRMode); gSPBgRect1Cyc(gp ++, &objBg); } } gDPPipeSync(gp ++); /*------ Setting the Render Mode. ------*/ objRM = RMmodeTable[aMenu[MENU_RENDERMODE]].objRMode; if (RMmodeTable[aMenu[MENU_RENDERMODE]].cycleType != G_CYC_COPY){ if (!aMenu[MENU_RENDERMODE_2]){ /* Opaque */ if (RMmodeTable[aMenu[MENU_RENDERMODE]].antiAlias){ gDPSetRenderMode(gp ++, G_RM_AA_SPRITE, G_RM_AA_SPRITE2); } else { gDPSetRenderMode(gp ++, G_RM_SPRITE, G_RM_SPRITE2); } } else { /* Translucent */ if (RMmodeTable[aMenu[MENU_RENDERMODE]].antiAlias){ gDPSetRenderMode(gp ++, G_RM_AA_XLU_SPRITE, G_RM_AA_XLU_SPRITE2); } else { gDPSetRenderMode(gp ++, G_RM_XLU_SPRITE, G_RM_XLU_SPRITE2); } gDPSetCombineMode(gp ++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); gDPSetPrimColor(gp ++, 0, 0, 255, 255, 255, 128); } } /*------ Setting the Texture Filter and CycleType. ------*/ gDPSetTextureFilter(gp ++, RMmodeTable[aMenu[MENU_RENDERMODE]].txtrFilter); gDPSetCycleType (gp ++, RMmodeTable[aMenu[MENU_RENDERMODE]].cycleType ); /*------ Setting the Texture Window. ------*/ if (aMenu[MENU_OBJ_TX_WINDOW]) objRM |= G_OBJRM_NOTXCLAMP; /*------ Setting the Shrink. ------*/ objRM |= ShrinkTable[aMenu[MENU_OBJ_SHRINK]]; /*------ Setting the Object Render Mode. ------*/ gSPObjRenderMode(gp ++, objRM); /*------ Load setting of the Texture. -----*/ if (!aMenu[MENU_OBJ_TX_TYPE]){ gDPSetTextureLUT(gp ++, G_TT_NONE); gSPObjLoadTxtr(gp ++, (aMenu[MENU_OBJ_TX_LOAD_BY] ? &objTxtrTile_RGBA16 : &objTxtrBlock_RGBA16)); } else { gDPSetTextureLUT(gp ++, G_TT_RGBA16); gSPObjLoadTxtr(gp ++, (aMenu[MENU_OBJ_TX_LOAD_BY] ? &objTxtrTile_CI4 : &objTxtrBlock_CI4)); gSPObjLoadTxtr(gp ++, &objTLUT_CI4); } /*------ Output of Object:Rectangle1. ------*/ gSPObjRectangle(gp ++, &(objRect[0])); if (RMmodeTable[aMenu[MENU_RENDERMODE]].cycleType != G_CYC_COPY){ /*------ Output of Object:Rectangle2. ------*/ gSPObjMatrix(gp ++, &(objMtx[0])); gSPObjSprite(gp ++, &(objRect[1])); /*------ Output of Object:Ball. ------*/ /* Ball is displayed by combining two sprite pieces. Because of this, you need to change the processing method by setting the Texture Filter. If the Texture Filter is PointSample, you don't have to specify SHRINKSIZE; but, If it is Bilerp, it must be SHRINKSIZE_1. When you specify SHRINKSIZE_1, the circumference of Sprite for 0.5 texel is clamped. The area excepted by this clamp becomes a part that the Bilerp process gives no effect. Because you need to load the part of adjoining of Sprite twice in Bilerp, Ball draws only for 64x63 texels. It is important to understand the differences between objBall[1] and objBall[2] well. */ if (!aMenu[MENU_RENDERMODE_2]){ /* Draw one size larger to hide the joining part. (Only opaque.) It became unnecessary after S2DEX 1.05. */ /* objRM |= G_OBJRM_WIDEN; */ } gDPPipeSync(gp ++); gDPSetTextureLUT(gp ++, G_TT_RGBA16); gSPObjLoadTxtr(gp ++, &objBallTLUT); if (RMmodeTable[aMenu[MENU_RENDERMODE]].txtrFilter == G_TF_POINT){ gSPObjRenderMode(gp ++, objRM); gSPObjMatrix(gp ++, &(objMtx[2])); gSPObjLoadTxRectR(gp ++, &(objBall[0])); gSPObjLoadTxRectR(gp ++, &(objBall[1])); gSPObjMatrix(gp ++, &(objMtx[1])); gSPObjLoadTxSprite(gp ++, &(objBall[0])); gSPObjLoadTxSprite(gp ++, &(objBall[1])); } else { gSPObjRenderMode(gp ++, objRM|G_OBJRM_SHRINKSIZE_1); gSPObjMatrix(gp ++, &(objMtx[2])); gSPObjLoadTxRectR(gp ++, &(objBall[0])); gSPObjLoadTxRectR(gp ++, &(objBall[2])); gSPObjMatrix(gp ++, &(objMtx[1])); gSPObjLoadTxSprite(gp ++, &(objBall[0])); gSPObjLoadTxSprite(gp ++, &(objBall[2])); } } /*------ Output the processing meter. ------*/ if (rsptime){ gDPPipeSync(gp ++); gDPSetCycleType(gp ++, G_CYC_FILL); gDPSetRenderMode(gp ++, G_RM_OPA_SURF, G_RM_OPA_SURF2); gDPSetFillColor(gp ++, (GPACK_RGBA5551(128,128,255,1) << 16 | GPACK_RGBA5551(128,128,255,1))); gDPFillRectangle(gp ++, 30, 201, 30+rsptime/100, 202); gDPFillRectangle(gp ++, 30, 205, 30+rdptime/100, 206); gDPSetFillColor(gp ++, (GPACK_RGBA5551(255,255,255,1) << 16 | GPACK_RGBA5551(255,255,255,1))); gDPFillRectangle(gp ++, 30, 200, 30, 207); gDPFillRectangle(gp ++, 30+166, 200, 30+166, 207); } gDPFullSync(gp ++); gSPEndDisplayList(gp ++); /*------ Execute the Gfx task. ------*/ tlist.t.data_ptr = (u64 *)gtop; osWritebackDCache(gtop, ((u32)gp)-((u32)gtop)); rspstart = osGetTime(); osSpTaskStart(&tlist); /*------ Wait for the end. ------*/ osRecvMesg(&rspMessageQ, NULL, OS_MESG_BLOCK); rsptime = OS_CYCLES_TO_NSEC(osGetTime() - rspstart) / 1000; #ifdef RSP_DEBUG /*------ The ASSERT process of the micro-code. ------*/ if (ucCheckAssert()){ ucDebugGfxLogPrint(&tlist); /* Output the process log of RSP, Gfx and DL. */ // ucDebugRdpFifoPrint(&tlist); /* Output the RDP and fifo buffers. */ // ucDebugIMEMPrint(); /* Output IMEM. */ // ucDebugDMEMPrint(); /* Output DMEM. */ ucDebugAssertPrint(); /* Output Assert stop location, etc. */ ucDebugInfoPrint(); /* Output the work area for Debugging. */ while(1); } #endif #if 0 /*------ Output the DEBUG information. ------*/ if (Ac.pad[0].push & Z_TRIG){ ucDebugRdpFifoPrint(&tlist); /* Output the RDP and fifo buffers. */ ucDebugInfoPrint(); /* Output the work area for Debugging. */ } #endif osRecvMesg(&rdpMessageQ, NULL, OS_MESG_BLOCK); rdptime = OS_CYCLES_TO_NSEC(osGetTime() - rspstart) / 1000; /* Switching the Frame. */ osViSwapBuffer(system_cfb[draw_frame]); draw_frame ^= 1; /* Accept the controller data. */ osRecvMesg(&siMessageQ, NULL, OS_MESG_BLOCK); osContGetReadData(contPad); /* The input process. */ actionUpdate(); } }