Emu?
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

273 lines
8.2 KiB

/* SdlWindow.cpp
*
* Implements a SDL2 rendering window.
*/
#include <sstream>
#include "Video/PlipVideoException.h"
#include "SdlWindow.h"
namespace PlipSdl {
SdlWindow::SdlWindow(int gameScale, const std::string &title) {
std::stringstream error;
m_gameScale = gameScale;
SDL_InitSubSystem(SDL_INIT_VIDEO);
// Try to create a window.
m_window = SDL_CreateWindow(title.c_str(),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
m_width * m_gameScale, m_height * m_gameScale, 0);
if(m_window == nullptr) {
error << "Unable to create SDL window: " << SDL_GetError();
throw Plip::PlipVideoException(error.str().c_str());
}
// Try to create a renderer.
m_renderer = SDL_CreateRenderer(m_window, -1, 0);
if(m_renderer == nullptr) {
error << "Unable to create SDL renderer: " << SDL_GetError();
throw Plip::PlipVideoException(error.str().c_str());
}
SDL_RendererInfo rendererInfo;
if(SDL_GetRendererInfo(m_renderer, &rendererInfo)) {
error << "Unable to retrieve SDL renderer info: " << SDL_GetError();
throw Plip::PlipVideoException(error.str().c_str());
}
auto found = false;
for(auto i = 0; i < rendererInfo.num_texture_formats; i++) {
if(SelectFormat(rendererInfo.texture_formats[i])) {
found = true;
break;
}
}
if(!found) {
error << "No supported texture formats!";
throw Plip::PlipVideoException(error.str().c_str());
}
// Try to create a small starting texture. This will be removed and
// recreated later, but we want to ensure that we can make one in the
// first place.
CreateConsoleTexture();
CreateGameTexture();
}
SdlWindow::~SdlWindow() {
if(m_gameTex != nullptr) SDL_DestroyTexture(m_gameTex);
if(m_renderer != nullptr) SDL_DestroyRenderer(m_renderer);
if(m_window != nullptr) SDL_DestroyWindow(m_window);
}
bool SdlWindow::BeginDraw() {
return SDL_LockTexture(m_gameTex, nullptr, &m_texData, &m_pitch) == 0;
}
bool SdlWindow::BeginDrawConsole() {
if(!SDL_RenderTargetSupported(m_renderer)) return false;
SDL_SetRenderTarget(m_renderer, m_conTex);
return true;
}
void SdlWindow::Clear() {
SDL_RenderClear(m_renderer);
}
void SdlWindow::CreateTexture(SDL_Texture **texture, int width, int height,
SDL_BlendMode blendMode, SDL_TextureAccess access) {
if(*texture != nullptr) SDL_DestroyTexture(*texture);
uint32_t pixelFormat = SelectSdlFormat(m_format);
*texture = SDL_CreateTexture(m_renderer,
pixelFormat, access,
width, height);
SDL_SetTextureBlendMode(*texture, blendMode);
if(*texture == nullptr) {
std::stringstream error;
error << "Unable to create SDL texture: " << SDL_GetError();
throw Plip::PlipVideoException(error.str().c_str());
}
}
void SdlWindow::CreateConsoleTexture() {
CreateTexture(&m_conTex, m_width * m_gameScale, m_height * m_gameScale,
SDL_BLENDMODE_BLEND, SDL_TEXTUREACCESS_TARGET);
}
void SdlWindow::CreateGameTexture() {
CreateTexture(&m_gameTex, m_width, m_height);
}
void SdlWindow::Draw(void *data) {
memcpy(m_texData, data, m_pitch * m_height);
}
bool SdlWindow::EndDraw() {
// Overlay the pause icon if it's enabled.
if(m_drawPauseIcon) {
auto sX = m_width - m_pauseOffsetX - m_pauseSizeX;
auto xRun = m_pauseSizeX / 3;
auto maxY = m_height - m_pauseOffsetY;
auto sY = maxY - m_pauseSizeY;
for(auto y = sY; y < maxY; y++) {
auto offset = (y * m_width) + sX;
for(auto x = 0; x < m_pauseSizeX; x++) {
if(x / xRun == 1) continue;
m_fmtInfo.plot(m_texData, offset + x, 255, 0, 0, 255);
}
}
}
SDL_UnlockTexture(m_gameTex);
return true;
}
bool SdlWindow::EndDrawConsole() {
SDL_SetRenderTarget(m_renderer, nullptr);
return true;
}
Plip::PlipVideoFormat SdlWindow::GetFormat() {
return m_format;
}
int SdlWindow::GetGameScale() const {
return m_gameScale;
}
int SdlWindow::GetHeight() {
return m_height;
}
SDL_Renderer *SdlWindow::GetRenderer() const {
return m_renderer;
}
int SdlWindow::GetWidth() {
return m_width;
}
void SdlWindow::Render() {
SDL_RenderCopy(m_renderer, m_gameTex, nullptr, nullptr);
if(m_drawConsole) SDL_RenderCopy(m_renderer, m_conTex, nullptr, nullptr);
SDL_RenderPresent(m_renderer);
}
void SdlWindow::Resize(int width, int height) {
m_width = width;
m_height = height;
// Resize the window.
SDL_SetWindowSize(m_window, m_width * m_gameScale, m_height * m_gameScale);
// Destroy and recreate the texture.
CreateConsoleTexture();
CreateGameTexture();
}
bool SdlWindow::SelectFormat(uint32_t format) {
switch(format) {
case SDL_PIXELFORMAT_RGB24:
m_format = Plip::PlipVideoFormat::RGB888;
break;
case SDL_PIXELFORMAT_BGR24:
m_format = Plip::PlipVideoFormat::BGR888;
break;
case SDL_PIXELFORMAT_RGB888:
m_format = Plip::PlipVideoFormat::XRGB8888;
break;
case SDL_PIXELFORMAT_BGR888:
m_format = Plip::PlipVideoFormat::XBGR8888;
break;
case SDL_PIXELFORMAT_ARGB8888:
m_format = Plip::PlipVideoFormat::ARGB8888;
break;
case SDL_PIXELFORMAT_ABGR8888:
m_format = Plip::PlipVideoFormat::ABGR8888;
break;
case SDL_PIXELFORMAT_RGBX8888:
m_format = Plip::PlipVideoFormat::RGBX8888;
break;
case SDL_PIXELFORMAT_BGRX8888:
m_format = Plip::PlipVideoFormat::BGRX8888;
break;
case SDL_PIXELFORMAT_RGBA8888:
m_format = Plip::PlipVideoFormat::RGBA8888;
break;
case SDL_PIXELFORMAT_BGRA8888:
m_format = Plip::PlipVideoFormat::BGRA8888;
break;
default:
return false;
}
m_fmtInfo = Plip::PlipVideo::GetFormatInfo(m_format);
return true;
}
uint32_t SdlWindow::SelectSdlFormat(Plip::PlipVideoFormat format) {
switch(format) {
case Plip::PlipVideoFormat::RGB888:
return SDL_PIXELFORMAT_RGB24;
case Plip::PlipVideoFormat::BGR888:
return SDL_PIXELFORMAT_BGR24;
case Plip::PlipVideoFormat::XRGB8888:
case Plip::PlipVideoFormat::ARGB8888:
return SDL_PIXELFORMAT_ARGB8888;
case Plip::PlipVideoFormat::XBGR8888:
case Plip::PlipVideoFormat::ABGR8888:
return SDL_PIXELFORMAT_ABGR8888;
case Plip::PlipVideoFormat::RGBX8888:
case Plip::PlipVideoFormat::RGBA8888:
return SDL_PIXELFORMAT_RGBA8888;
case Plip::PlipVideoFormat::BGRX8888:
case Plip::PlipVideoFormat::BGRA8888:
return SDL_PIXELFORMAT_BGRA8888;
default:
throw Plip::PlipVideoException("Unsupported pixel format.");
}
}
void SdlWindow::SetConsoleEnabled(bool enabled) {
m_drawConsole = enabled;
}
void SdlWindow::SetDrawPauseIcon(bool value) {
m_drawPauseIcon = value;
}
void SdlWindow::SetGameScale(int scale) {
m_gameScale = scale;
SDL_SetWindowSize(m_window, m_width * m_gameScale, m_height * m_gameScale);
}
void SdlWindow::SetTitle(std::string title) {
SDL_SetWindowTitle(m_window, title.c_str());
}
}