//---------------------------------------------------------------------------------------------------- void GBEmulator::Update() { const float k_fFrameRate = static_cast<float>( GBCpu::CLOCK_SPEED ) / static_cast<float>( kMaxCyclesPerFrame ); const float k_fFrameTime = 1000.f / static_cast<float>( k_fFrameRate ); if( m_bCartridgeLoaded ) { m_fElapsedTime += static_cast<float>( SDL_GetTicks() ) - m_fElapsedTime; if( m_fElapsedTime >= m_fNextFrame ) { if( !m_bDebugPaused ) { float fDelta = m_fElapsedTime - m_fNextFrame; // Make sure we don't render faster than our framerate fDelta = fDelta > k_fFrameTime ? k_fFrameTime : fDelta; // Determine how much time was spend idle this frame since the end of the last emulation step m_fIdleTime += m_fNextFrame - m_fLastFrame; ++m_u32TotalFrames; // Calculate the idle time over the last second and reset counters if( static_cast<float>( m_u32TotalFrames ) >= k_fFrameRate ) { m_fAvgIdleTime = static_cast<float>( m_fIdleTime / m_u32TotalFrames ); m_fIdleTime = 0; m_u32TotalFrames = 0; } // Set the next frame render time m_fNextFrame = m_fElapsedTime + k_fFrameTime - fDelta; Step(); // Calculate the last frame time after emulation step m_fLastFrame = static_cast<float>( SDL_GetTicks() ); GTimer()->Update(); // If the cart has a battery and something has changed, we need to update our .sav file if( m_pCartridge->HasBattery() && m_pCartridge->IsRamDirty() ) { m_pCartridge->FlushRamToSaveFile( GB_BATTERY_DIRECTORY ); } } } else if( m_fNextFrame - m_fElapsedTime > 1.f ) { // Wait a bit if we can, so we don't hog the cpu SDL_Delay( 1 ); } } }
//---------------------------------------------------------------------------------------------------- void GBEmulator::Initialize() { if( -1 == SDL_Init( SDL_INIT_EVERYTHING ) ) { fprintf( stderr, "Failed to initialize SDL!\n" ); exit( 1 ); } if( -1 == SDL_CreateWindowAndRenderer( GBScreenWidth * kScreenScaleFactor, GBScreenHeight * kScreenScaleFactor, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE, &m_pWindow, &m_pRenderer ) ) { fprintf( stderr, "Failed to initialize window!\n" ); exit( 1 ); } // Load the user preferences UserPrefs()->Load(); SDL_SetWindowTitle( m_pWindow, "Gameboy Emulator" ); // Clear color is white SDL_SetRenderDrawColor( m_pRenderer, 255, 255, 255, 255 ); // Create main display surface m_pTexture = SDL_CreateTexture( m_pRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, GBScreenWidth, GBScreenHeight ); // Make sure our battery directory exists if( 0 != _access( GB_BATTERY_DIRECTORY, 0 ) ) { _mkdir( GB_BATTERY_DIRECTORY ); } m_pMem = new GBMem; m_pTimer = new GBTimer( this, m_pMem ); m_pCpu = new GBCpu( m_pMem, m_pTimer ); m_pGpu = new GBGpu( this, m_pMem ); m_pJoypad = new GBJoypad( this, m_pMem ); m_pCartridge = new GBCartridge( m_pMem ); TTF_Init(); TTF_Font* pFont = TTF_OpenFont( "assets\\Charybdis.ttf", 24 ); if( NULL == pFont ) { char szBuffer[ 1024 ] = { 0 }; GetWindowsDirectory( szBuffer, 1024 ); sprintf_s( szBuffer, 1024, "%s%s", szBuffer, "\\fonts\\arial.ttf" ); pFont = TTF_OpenFont( szBuffer, 14 ); } m_pFpsText = new NFont; m_pFpsText->load( m_pRenderer, pFont, NFont::Color::Color() ); GTimer()->Initialize(); m_bInitialized = true; Reset(); }
//---------------------------------------------------------------------------------------------------- void GBEmulator::Draw() { const uint32* pu32ScreenData = m_pGpu->GetScreenData(); SDL_RenderClear( m_pRenderer ); if( m_bRunning && m_bCartridgeLoaded ) { SDL_UpdateTexture( m_pTexture, NULL, pu32ScreenData, GBScreenWidth * sizeof( uint32 ) ); SDL_RenderCopy( m_pRenderer, m_pTexture, NULL, NULL ); } m_pFpsText->draw( m_pRenderer, 0, GBScreenHeight * kScreenScaleFactor - 20, "%.1f (Idle: %.1f)", GTimer()->GetFPS(), m_fAvgIdleTime ); SDL_RenderPresent( m_pRenderer ); }
GTimer GTimerEvent::getGTimer() const { return GTimer(gtd); }