/* Copyright (C) 2001 StrmnNrmn This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" CGraphicsContext* CGraphicsContext::g_pGraphicsContext = NULL; bool CGraphicsContext::needCleanScene = false; CGraphicsContext * CGraphicsContext::Get(void) { return CGraphicsContext::g_pGraphicsContext; } CGraphicsContext::CGraphicsContext() : m_bReady(false), m_bActive(false), m_bWindowed(true), m_hWnd(NULL), // TODO: Assign window handle somewhere m_hWndFocus(NULL), // TODO: Assign window handle somewhere m_hMenu(NULL), m_dwChosenWidth(640), m_dwChosenHeight(480), m_bShowCursorWhenFullscreen(FALSE), m_supportTextureMirror(false) { } DWORD statusBarHeight = 0; DWORD statusBarHeightToUse = 0; DWORD toolbarHeight = 0; DWORD toolbarHeightToUse = 0; bool CGraphicsContext::Initialize(HWND hWnd, HWND hWndStatus, DWORD dwWidth, DWORD dwHeight, BOOL bWindowed ) { #ifdef _WIN32 m_hWnd = hWnd; m_hWndStatus = hWndStatus; m_hMenu = GetMenu(hWnd); #endif if( windowSetting.bDisplayFullscreen ) { m_dwChosenWidth = windowSetting.uFullScreenDisplayWidth; m_dwChosenHeight= windowSetting.uFullScreenDisplayHeight; } else { m_dwChosenWidth = windowSetting.uWindowDisplayWidth; m_dwChosenHeight= windowSetting.uWindowDisplayHeight; } windowSetting.uCurrentDisplayWidth = (WORD)m_dwChosenWidth; windowSetting.uCurrentDisplayHeight = (WORD)m_dwChosenHeight; #ifdef _WIN32 // The focus window can be a specified to be a different window than the // device window. If not, use the device window as the focus window. if( m_hWndFocus == NULL ) m_hWndFocus = m_hWnd; // Save window properties m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE ); m_dwWindowExStyle = GetWindowLong( m_hWnd, GWL_EXSTYLE ); m_dwStatusWindowStyle = GetWindowLong( m_hWndStatus, GWL_STYLE ); RECT rcScreen, rcStatus; SetRect(&rcScreen, 0,0, m_dwChosenWidth, m_dwChosenHeight); // Calculate window size to give desired window size... AdjustWindowRectEx(&rcScreen, m_dwWindowStyle & (~(WS_THICKFRAME|WS_MAXIMIZEBOX)), TRUE, m_dwWindowExStyle); // Add extra margin for the status bar statusBarHeight = 0; if ( IsWindow( m_hWndStatus ) ) { // Add on enough space for the status bar GetClientRect(m_hWndStatus, &rcStatus); rcScreen.bottom += (rcStatus.bottom - rcStatus.top); statusBarHeight = (rcStatus.bottom - rcStatus.top); } statusBarHeightToUse = statusBarHeight; toolbarHeight = 0; if( windowSetting.bUseEmulatorToolbar ) { if( IsWindow( m_hWndStatus ) ) { toolbarHeight = statusBarHeight; } else { toolbarHeight = 15; // 15 is not correct } } toolbarHeightToUse = toolbarHeight; rcScreen.bottom += toolbarHeight; SetWindowPos(m_hWnd, 0, rcScreen.left, rcScreen.top, rcScreen.right-rcScreen.left+1, rcScreen.bottom-rcScreen.top+1, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); GetWindowRect( m_hWnd, &m_rcWindowBounds ); GetClientRect( m_hWnd, &m_rcWindowClient ); EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &m_DMsaved); if ( IsWindow( m_hWndStatus ) ) { // Remove statusbar area m_rcWindowClient.bottom -= statusBarHeight; } if( windowSetting.bUseEmulatorToolbar ) { m_rcWindowClient.top += toolbarHeight; } m_rcWindowClientSrc.left = 0; m_rcWindowClientSrc.top = 0; m_rcWindowClientSrc.right = m_rcWindowClient.right; m_rcWindowClientSrc.bottom = m_rcWindowClient.bottom - m_rcWindowClient.top; #endif // _WIN32 return true; } void CGraphicsContext::CleanUp() { m_bActive = false; m_bReady = false; #ifdef _WIN32 if ( IsWindow( m_hWnd ) ) { SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle ); } if ( IsWindow(m_hWndStatus) ) { SetWindowLong( m_hWndStatus, GWL_STYLE, m_dwStatusWindowStyle); } #endif } bool FrameBufferInRDRAMCheckCRC(); void ClearFrameBufferToBlack(DWORD left=0, DWORD top=0, DWORD width=0, DWORD height=0); bool ProcessFrameWriteRecord(); extern RECT frameWriteByCPURect; void CGraphicsContext::UpdateFrameBufferBeforeUpdateFrame() { if( (currentRomOptions.N64FrameBufferEmuType == FRM_WITH_EMULATOR && status.frameWriteByCPU ) || (currentRomOptions.N64FrameBufferEmuType == FRM_COPY_AND_BACK && !FrameBufferInRDRAMCheckCRC() ) ) // Checks if frame buffer has been modified by CPU // Only happens to Dr. Mario { if( currentRomOptions.N64FrameBufferEmuType == FRM_WITH_EMULATOR ) { if( ProcessFrameWriteRecord() ) { CDaedalusRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top); ClearFrameBufferToBlack(frameWriteByCPURect.left, frameWriteByCPURect.top, frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top); } status.frameWriteByCPU = FALSE; } else { extern RecentCIInfo *g_uRecentCIInfoPtrs[3]; RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]); CDaedalusRender::GetRender()->DrawFrameBuffer(false, 0,0,p.dwWidth,p.dwHeight); ClearFrameBufferToBlack(); } } } /* * Swap chain management */ extern int g_DlistCount; void CGraphicsContext::SetFrontBuffer(DWORD viorg) // Change front buffer to the viorg addr { u32 i; //UpdateFrame(); if( !m_bFrontBuffersReady ) { // Doing nothing but initialize the swapchain backbuffers for( i=0; i=1 ) { m_bFrontBuffersReady = true; } } else { // Search a backbuffer by using the viorg, and send this backbuffer // as the current render buffer /* for( i=0; im_SwapChainInfos[i].ciimg_addr && (viorg-m_SwapChainInfos[i].ciimg_addr)<0x400 ) ) { m_SwapChainInfos[i].viorg_addr = viorg; m_currentFrontBufferIdx = i; // Selecting front buffer #i return; } } if( i=1 ) { m_bBackBuffersReady = true; } } else { // Search a backbuffer by using the ciaddr, and send this backbuffer // as the current render buffer for( i=0; iSetFrontBuffer(*g_GraphicsInfo.VI_ORIGIN_REG); } if( m_SwapChainInfos[m_currentFrontBufferIdx].isFrontBuffer ) return; m_SwapChainInfos[lastFrontBuffer].isFrontBuffer = false; m_SwapChainInfos[m_currentBackBufferIdx].beingRendered = false; #ifdef _DEBUG if( pauseAtNext && eventToPause == NEXT_FRAME ) { DebuggerAppendMsg("Update screen, last=%d, cur=%d", lastFrontBuffer, m_currentBackBufferIdx); } #endif while( lastFrontBuffer != m_currentFrontBufferIdx ) { lastFrontBuffer++; lastFrontBuffer %= m_numOfBackBuffers; #ifdef _DEBUG if( pauseAtNext && eventToPause == NEXT_FRAME ) { //UpdateFrame(); UpdateFrame(lastFrontBuffer != m_currentFrontBufferIdx); DebuggerAppendMsg("%s screen %d", lastFrontBuffer != m_currentFrontBufferIdx?"Skip":"Update",lastFrontBuffer ); //ErrorMsg("Continue"); } else { UpdateFrame(lastFrontBuffer != m_currentFrontBufferIdx); } #else UpdateFrame(lastFrontBuffer != m_currentFrontBufferIdx); #endif } m_SwapChainInfos[m_currentFrontBufferIdx].isFrontBuffer = true; m_currentBackBufferIdx = m_currentFrontBufferIdx+1; m_currentBackBufferIdx %= m_numOfBackBuffers; m_SwapChainInfos[m_currentBackBufferIdx].beingRendered = true; return; DWORD nextFrontBuffer = (m_currentFrontBufferIdx+1)%m_numOfBackBuffers; DWORD nextBackBuffer = (nextFrontBuffer+1)%m_numOfBackBuffers; m_SwapChainInfos[m_currentFrontBufferIdx].isFrontBuffer = false; m_SwapChainInfos[nextFrontBuffer].isFrontBuffer = true; m_SwapChainInfos[nextFrontBuffer].beingRendered = false; m_currentFrontBufferIdx = nextFrontBuffer; m_SwapChainInfos[nextBackBuffer].beingRendered = true; m_currentBackBufferIdx = nextBackBuffer; #else UpdateFrame(); #endif } void CGraphicsContext::InitBackBufferInfoArray(DWORD numOfBuf) { m_numOfBackBuffers = numOfBuf+1; for( u32 i=0; i