Source

gb_emulator / gb_emulator / src / gb_video_sdl.cpp

/*  Copyright © 2011 Chris Spencer <spencercw@gmail.com>

    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 3 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, see <http://www.gnu.org/licenses/>.  */

#include <gb_emulator/gb_video_sdl.h>

#include <stdexcept>
#include <string>

#ifdef _MSC_VER
#pragma warning(push, 0)
#endif

#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <hqx.h>

using std::logic_error;
using std::runtime_error;
using std::string;

class SdlVideoLock
{
public:
	SdlVideoLock(SDL_Surface *surface):
	surface_(surface)
	{
		if (SDL_MUSTLOCK(surface_))
		{
			if (!SDL_LockSurface(surface_))
			{
				throw runtime_error(string("failed to lock video surface: ") + SDL_GetError());
			}
			locked_ = true;
		}
		else
		{
			locked_ = false;
		}
	}

	~SdlVideoLock()
	{
		if (locked_)
		{
			SDL_UnlockSurface(surface_);
		}
	}

private:
	SDL_Surface *surface_;
	bool locked_;
};

GbVideoSdl::GbVideoSdl(Gb &gb, GbConfig::Renderer renderer):
GbVideo(gb),
unscaledPixelBuffer_(new uint32_t[WIDTH * HEIGHT]),
scaledPixelBuffer_(new uint32_t[SCALED_WIDTH * SCALED_HEIGHT])
{
	// Check the rendering method
	if (renderer != GbConfig::RENDER_DEFAULT && renderer != GbConfig::RENDER_SOFTWARE)
	{
		throw logic_error("unsupported rendering method");
	}

	// Create the display
	if (!SDL_WasInit(SDL_INIT_VIDEO))
	{
		SDL_InitSubSystem(SDL_INIT_VIDEO);
	}

	surface_ = SDL_SetVideoMode(SCALED_WIDTH, SCALED_HEIGHT, 32, SDL_SWSURFACE);
	if (!surface_)
	{
		throw runtime_error(string("failed to create video surface: ") + SDL_GetError());
	}
}

#ifdef _WIN32
HWND GbVideoSdl::window() const
{
	SDL_SysWMinfo info;
	SDL_VERSION(&info.version);
	if (SDL_GetWMInfo(&info) != 1)
	{
		throw runtime_error("failed to get window information");
	}
	return info.window;
}
#endif

void GbVideoSdl::draw(uint16_t *pixelBuffer, bool gbc)
{
	// Perform colour correction and image scaling in software
	postProcess(pixelBuffer, gbc, unscaledPixelBuffer_.get(), scaledPixelBuffer_.get());

	// Update the display
	SdlVideoLock lock(surface_);
	memcpy(surface_->pixels, scaledPixelBuffer_.get(),
		SCALED_WIDTH * SCALED_HEIGHT * sizeof(uint32_t));
	SDL_UpdateRect(surface_, 0, 0, 0, 0);
}