// Yoshi's Story uses this - 0x03 void RSP_S2DEX_OBJ_RECTANGLE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *ptr = (uObjSprite*)(g_pRDRAMu8+dwAddr); uObjTxSprite objtx; memcpy(&objtx.sprite,ptr,sizeof(uObjSprite)); if( g_TxtLoadBy == CMD_LOAD_OBJ_TXTR ) { memcpy(&(objtx.txtr.block),&(gObjTxtr->block),sizeof(uObjTxtr)); CRender::g_pRender->LoadObjSprite(objtx, true); } else { PrepareTextures(); } CRender::g_pRender->DrawSprite(objtx, false); #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { if( debuggerPauseCount > 0 ) debuggerPauseCount--; if( debuggerPauseCount == 0 ) { eventToPause = false; debuggerPause = true; TRACE3("Paused at RSP_S2DEX_OBJ_RECTANGLE\nptr=%08X, img=%08X, TMEM=%08X", dwAddr,objtx.txtr.block.image, ptr->imageAdrs); CGraphicsContext::g_pGraphicsContext->UpdateFrame(false); } } #endif }
// Yoshi's Story uses this - 0x04 void RSP_S2DEX_OBJ_SPRITE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; status.bAllowLoadFromTMEM = false; // Because we need to use TLUT loaded by ObjTlut cmd PrepareTextures(); status.bAllowLoadFromTMEM = true; uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); /* static BOOL bWarned = FALSE; //if (!bWarned) { RSP_RDP_NOIMPL("RDP: RSP_S2DEX_OBJ_SPRITE (0x%08x 0x%08x)", (gfx->words.w0), (gfx->words.w1)); bWarned = TRUE; } */ #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { eventToPause = false; debuggerPause = true; TRACE0("Paused at RSP_S2DEX_OBJ_SPRITE"); CGraphicsContext::Get()->UpdateFrame(); } #endif }
// Yoshi's Story uses this - 0x02 void RSP_S2DEX_BG_COPY(Gfx *gfx) { SP_Timing(DP_Minimal16); DP_Timing(DP_Minimal16); uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjBg *sbgPtr = (uObjBg*)(g_pRDRAMu8+dwAddr); CRender::g_pRender->LoadObjBGCopy(*sbgPtr); CRender::g_pRender->DrawObjBGCopy(*sbgPtr); }
// Yoshi's Story uses this - 0x04 void RSP_S2DEX_OBJ_SPRITE(Gfx *gfx) { uint32 dwAddr = RSPSegmentAddr((gfx->words.w1)); uObjSprite *info = (uObjSprite*)(g_pRDRAMu8+dwAddr); uint32 dwTile = gRSP.curTile; status.bAllowLoadFromTMEM = false; // Because we need to use TLUT loaded by the ObjTlut command PrepareTextures(); status.bAllowLoadFromTMEM = true; uObjTxSprite drawinfo; memcpy( &(drawinfo.sprite), info, sizeof(uObjSprite)); CRender::g_pRender->DrawSpriteR(drawinfo, false, dwTile, 0, 0, drawinfo.sprite.imageW/32, drawinfo.sprite.imageH/32); #ifdef DEBUGGER if( (pauseAtNext && (eventToPause == NEXT_OBJ_TXT_CMD||eventToPause == NEXT_FLUSH_TRI)) || logTextures ) { eventToPause = false; debuggerPause = true; TRACE0("Paused at RSP_S2DEX_OBJ_SPRITE"); CGraphicsContext::g_pGraphicsContext->UpdateFrame(false); } #endif }
//#define SUPPORT_ZBUFFER_IMG //Doesn't work good enough, still need lockable zbuffer //#define SUPPORT_LOCKABLE_ZBUFFER void D3DRender::DrawObjBGCopy(uObjBg &info) { if( IsUsedAsDI(g_CI.dwAddr) ) { #ifndef SUPPORT_LOCKABLE_ZBUFFER #ifndef SUPPORT_ZBUFFER_IMG g_pD3DDev->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0, 0); //Check me LOG_UCODE(" Clearing ZBuffer by using ZeldaBG"); #else if( g_CI.dwWidth == 0x200 && info.imageFmt == g_CI.dwFormat && info.imageSiz == g_CI.dwSize && info.frameW == 0x800 ) { InitCombinerBlenderForSimpleTextureDraw(); ZBufferEnable( TRUE ); gD3DDevWrapper.SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TFACTOR ); gD3DDevWrapper.SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR ); SetTextureFactor(0); //SetTextureFactor(0x80808080); //gD3DDevWrapper.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR); //gD3DDevWrapper.SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); // Resident Evil2 uint32 width = *g_GraphicsInfo.VI_WIDTH_REG & 0xFFF; uint32 height = (info.frameW/4*info.frameH/4)/width; uint32 pitch = width; //LoadObjBGCopy(info); // We don't support lockable Zbuffer, but we can simular it by splitting the image // to small pieces and render the piece with depth from the depth image uint16 *Base = (uint16*)(g_pu8RamBase+RSPSegmentAddr(info.imagePtr)); float depth; const uint32 inc=10; for( uint32 i=0; i<height; i+=inc ) { uint16 *pSrc = Base + i * pitch; depth = (*pSrc + 1.0f ) / 0x10000; for( uint32 j=0; j<width; j+=inc) { DrawSimpleRect(j, i, j+inc, i+inc, gRDP.primitiveColor, depth, 1/depth); #ifdef _DEBUG if( pauseAtNext && eventToPause == NEXT_TRIANGLE ) { debuggerPause = true; TRACE0("Pause after drawing a rect for Z buffer"); DebuggerPause(); } #endif } } } #endif #else if( g_pLockableBackBuffer == NULL && status.bHandleN64RenderTexture == false ) { if( IsResultGood(g_pD3DDev->CreateDepthStencilSurface(windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, D3DFMT_D16_LOCKABLE, D3DMULTISAMPLE_NONE, &g_pLockableBackBuffer)) && g_pLockableBackBuffer ) { g_pD3DDev->SetRenderTarget(NULL, g_pLockableBackBuffer); TRACE0("Created and use lockable depth buffer"); } else { if( g_pLockableBackBuffer ) { g_pLockableBackBuffer->Release(); g_pLockableBackBuffer = NULL; } TRACE0("Can not create lockable depth buffer"); } } DEBUGGER_IF_DUMP((pauseAtNext&& (eventToPause==NEXT_OBJ_TXT_CMD||eventToPause==NEXT_OBJ_BG)), {TRACE0("Using BG to update Z buffer has not been implemented yet");});