diff --git a/src/Config.h b/src/Config.h index 864dedd9..918b0606 100644 --- a/src/Config.h +++ b/src/Config.h @@ -121,6 +121,7 @@ struct Config #define hack_ignoreVIHeightChange (1<<9) //Do not reset FBO when VI height is changed. Space Invaders need it. #define hack_VIUpdateOnCIChange (1<<10) //Update frame if color buffer changed. Needed for Quake II underwater. #define hack_skipVIChangeCheck (1<<11) //Don't reset FBO when VI parameters changed. Zelda MM +#define hack_ZeldaCamera (1<<12) //Special hack to detect and process Zelda MM camera. extern Config config; diff --git a/src/FrameBuffer.cpp b/src/FrameBuffer.cpp index 9914519d..73f61d01 100644 --- a/src/FrameBuffer.cpp +++ b/src/FrameBuffer.cpp @@ -357,11 +357,13 @@ FrameBufferList & FrameBufferList::get() void FrameBufferList::init() { m_pCurrent = NULL; + m_pCopy = NULL; } void FrameBufferList::destroy() { m_list.clear(); m_pCurrent = NULL; + m_pCopy = NULL; } void FrameBufferList::setBufferChanged() @@ -1184,7 +1186,15 @@ bool DepthBufferToRDRAM::CopyToRDRAM( u32 _address) { bool FrameBuffer_CopyDepthBuffer( u32 address ) { #ifndef GLES2 - return g_dbToRDRAM.CopyToRDRAM(address); + FrameBuffer * pCopyBuffer = frameBufferList().getCopyBuffer(); + if (pCopyBuffer != NULL) { + // This code is mainly to emulate Zelda MM camera. + g_fbToRDRAM.CopyToRDRAM(pCopyBuffer->m_startAddress); + pCopyBuffer->m_RdramCopy.resize(0); // To disable validity check by RDRAM content. CPU may change content of the buffer for some unknown reason. + frameBufferList().setCopyBuffer(NULL); + return true; + } else + return g_dbToRDRAM.CopyToRDRAM(address); #else return false; #endif diff --git a/src/FrameBuffer.h b/src/FrameBuffer.h index c8574932..e931ed94 100644 --- a/src/FrameBuffer.h +++ b/src/FrameBuffer.h @@ -71,10 +71,13 @@ public: void correctHeight(); void clearBuffersChanged(); + FrameBuffer * getCopyBuffer() const { return m_pCopy; } + void setCopyBuffer(FrameBuffer * _pBuffer) { m_pCopy = _pBuffer; } + static FrameBufferList & get(); private: - FrameBufferList() : m_pCurrent(NULL) {} + FrameBufferList() : m_pCurrent(NULL), m_pCopy(NULL) {} FrameBufferList(const FrameBufferList &); FrameBuffer * _findBuffer(u32 _startAddress, u32 _endAddress, u32 _width); @@ -82,6 +85,7 @@ private: typedef std::list FrameBuffers; FrameBuffers m_list; FrameBuffer * m_pCurrent; + FrameBuffer * m_pCopy; }; struct PBOBinder { diff --git a/src/RSP.cpp b/src/RSP.cpp index a2724fce..46126b62 100644 --- a/src/RSP.cpp +++ b/src/RSP.cpp @@ -338,7 +338,7 @@ void RSP_Init() ) config.generalEmulation.hacks |= hack_VIUpdateOnCIChange; else if (strstr(RSP.romname, (const char *)"MASK") != NULL) // Zelda MM - config.generalEmulation.hacks |= hack_skipVIChangeCheck; + config.generalEmulation.hacks |= hack_skipVIChangeCheck | hack_ZeldaCamera; api().FindPluginPath(RSP.pluginpath); diff --git a/src/gSP.cpp b/src/gSP.cpp index e34c4c03..cf41db5e 100644 --- a/src/gSP.cpp +++ b/src/gSP.cpp @@ -2114,6 +2114,11 @@ void _loadBGImage(const uObjScaleBg * _bgInfo, bool _loadScale) gDP.tiles[0].textureMode = TEXTUREMODE_FRAMEBUFFER_BG; gDP.tiles[0].loadType = LOADTYPE_TILE; gDP.changed |= CHANGED_TMEM; + + if ((config.generalEmulation.hacks & hack_ZeldaCamera) != 0) { + if (gDP.colorImage.address == gDP.depthImageAddress) + frameBufferList().setCopyBuffer(frameBufferList().getCurrent()); + } } } }