/*
* ppui/sdl/DisplayDeviceFB_SDL.cpp
*
* Copyright 2009 Peter Barth, Christopher O'Neill, Dale Whinham
*
* This file is part of Milkytracker.
*
* Milkytracker 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.
*
* Milkytracker 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 Milkytracker. If not, see .
*
* 12/5/14 - Dale Whinham
* - Port to SDL2
* - Resizable window which renders to a scaled texture
* - Experimental, buggy Retina support (potential problems with mouse coordinates if letterboxing happens)
*
* TODO: - Test under Linux (only tested under OSX)
* - Test/fix/remove scale factor and orientation code
* - Look at the OpenGL stuff
*/
#include "DisplayDeviceFB_SDL.h"
#include "Graphics.h"
PPDisplayDeviceFB::PPDisplayDeviceFB(pp_int32 width,
pp_int32 height,
pp_int32 scaleFactor,
pp_int32 bpp,
bool fullScreen,
Orientations theOrientation/* = ORIENTATION_NORMAL*/,
bool swapRedBlue/* = false*/) :
PPDisplayDevice(width, height, scaleFactor, bpp, fullScreen, theOrientation),
needsTemporaryBuffer((orientation != ORIENTATION_NORMAL) || (scaleFactor != 1)),
temporaryBuffer(NULL)
{
// Create an SDL window and surface
theWindow = CreateWindow(realWidth, realHeight, bpp,
#ifdef HIDPI_SUPPORT
SDL_WINDOW_ALLOW_HIGHDPI | // Support for 'Retina'/Hi-DPI displays
#endif
SDL_WINDOW_RESIZABLE | // MilkyTracker's window is resizable
(bFullScreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); // Use 'fake fullscreen' because we can scale
if (theWindow == NULL)
{
fprintf(stderr, "SDL: Could not create window.\n");
exit(EXIT_FAILURE);
}
// Create renderer for the window
theRenderer = SDL_CreateRenderer(theWindow, drv_index, 0);
if (theRenderer == NULL)
{
fprintf(stderr, "SDL: SDL_CreateRenderer failed: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
#ifdef HIDPI_SUPPORT
// Feed SDL_RenderSetLogicalSize() with output size, not GUI surface size, otherwise mouse coordinates will be wrong for Hi-DPI
int rendererW, rendererH;
SDL_GetRendererOutputSize(theRenderer, &rendererW, &rendererH);
#endif
// Log renderer capabilities
SDL_RendererInfo theRendererInfo;
if (!SDL_GetRendererInfo(theRenderer, &theRendererInfo))
{
if (theRendererInfo.flags & SDL_RENDERER_SOFTWARE) printf("SDL: Using software renderer.\n");
if (theRendererInfo.flags & SDL_RENDERER_ACCELERATED) printf("SDL: Using accelerated renderer.\n");
if (theRendererInfo.flags & SDL_RENDERER_PRESENTVSYNC) printf("SDL: Vsync enabled.\n");
if (theRendererInfo.flags & SDL_RENDERER_TARGETTEXTURE) printf("SDL: Renderer supports rendering to texture.\n");
}
// Lock aspect ratio and scale the UI up to fit the window
#ifdef HIDPI_SUPPORT
SDL_RenderSetLogicalSize(theRenderer, rendererW, rendererH);
#else
SDL_RenderSetLogicalSize(theRenderer, realWidth, realHeight);
#endif
// Use linear filtering for the scaling (make this optional eventually)
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
// Create surface for rendering graphics
theSurface = SDL_CreateRGBSurface(0, realWidth, realHeight, bpp == -1 ? 32 : bpp, 0, 0, 0, 0);
if (theSurface == NULL)
{
fprintf(stderr, "SDL: SDL_CreateSurface failed: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
// Streaming texture for rendering the UI
theTexture = SDL_CreateTexture(theRenderer, theSurface->format->format, SDL_TEXTUREACCESS_STREAMING, realWidth, realHeight);
if (theTexture == NULL)
{
fprintf(stderr, "SDL: SDL_CreateTexture failed: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
// We got a surface: update bpp value
bpp = theSurface->format->BitsPerPixel;
// Create a PPGraphics context based on bpp
switch (bpp)
{
case 16:
currentGraphics = new PPGraphics_16BIT(width, height, 0, NULL);
break;
case 24:
{
PPGraphics_24bpp_generic* g = new PPGraphics_24bpp_generic(width, height, 0, NULL);
if (swapRedBlue)
{
g->setComponentBitpositions(theSurface->format->Bshift,
theSurface->format->Gshift,
theSurface->format->Rshift);
}
else
{
g->setComponentBitpositions(theSurface->format->Rshift,
theSurface->format->Gshift,
theSurface->format->Bshift);
}
currentGraphics = static_cast(g);
break;
}
case 32:
{
PPGraphics_32bpp_generic* g = new PPGraphics_32bpp_generic(width, height, 0, NULL);
if (swapRedBlue)
{
g->setComponentBitpositions(theSurface->format->Bshift,
theSurface->format->Gshift,
theSurface->format->Rshift);
}
else
{
g->setComponentBitpositions(theSurface->format->Rshift,
theSurface->format->Gshift,
theSurface->format->Bshift);
}
currentGraphics = static_cast(g);
break;
}
default:
fprintf(stderr, "SDL: Unsupported color depth (%i), try either 16, 24 or 32", bpp);
exit(EXIT_FAILURE);
}
if (needsTemporaryBuffer)
{
temporaryBufferPitch = (width*bpp)/8;
temporaryBufferBPP = bpp;
temporaryBuffer = new pp_uint8[getSize().width*getSize().height*(bpp/8)];
}
currentGraphics->lock = true;
}
PPDisplayDeviceFB::~PPDisplayDeviceFB()
{
SDL_FreeSurface(theSurface);
SDL_DestroyRenderer(theRenderer);
SDL_DestroyWindow(theWindow);
delete[] temporaryBuffer;
// base class is responsible for deleting currentGraphics
}
PPGraphicsAbstract* PPDisplayDeviceFB::open()
{
if (!isEnabled())
return NULL;
if (currentGraphics->lock)
{
if (SDL_LockSurface(theSurface) < 0)
return NULL;
currentGraphics->lock = false;
if (needsTemporaryBuffer)
static_cast(currentGraphics)->setBufferProperties(temporaryBufferPitch, (pp_uint8*)temporaryBuffer);
else
static_cast(currentGraphics)->setBufferProperties(theSurface->pitch, (pp_uint8*)theSurface->pixels);
return currentGraphics;
}
return NULL;
}
void PPDisplayDeviceFB::close()
{
SDL_UnlockSurface(theSurface);
currentGraphics->lock = true;
}
void PPDisplayDeviceFB::update()
{
if (!isUpdateAllowed() || !isEnabled())
return;
if (theSurface->locked)
{
return;
}
PPRect r(0, 0, getSize().width, getSize().height);
swap(r);
// Update entire texture and copy to renderer
SDL_UpdateTexture(theTexture, NULL, theSurface->pixels, theSurface->pitch);
SDL_RenderClear(theRenderer);
SDL_RenderCopy(theRenderer, theTexture, NULL, NULL);
SDL_RenderPresent(theRenderer);
}
void PPDisplayDeviceFB::update(const PPRect& r)
{
if (!isUpdateAllowed() || !isEnabled())
return;
if (theSurface->locked)
{
return;
}
swap(r);
PPRect r2(r);
r2.scale(scaleFactor);
transformInverse(r2);
SDL_Rect r3 = { r2.x1, r2.y1, r2.width(), r2.height() };
// Calculate destination pixel data offset based on row pitch and x coordinate
void* surfaceOffset = (char*) theSurface->pixels + r2.y1 * theSurface->pitch + r2.x1 * theSurface->format->BytesPerPixel;
// Update dirty area of texture and copy to renderer
SDL_UpdateTexture(theTexture, &r3, surfaceOffset, theSurface->pitch);
SDL_RenderClear(theRenderer);
SDL_RenderCopy(theRenderer, theTexture, NULL, NULL);
SDL_RenderPresent(theRenderer);
}
void PPDisplayDeviceFB::swap(const PPRect& r2)
{
PPRect r(r2);
pp_int32 h;
if (r.x2 < r.x1)
{
h = r.x1; r.x1 = r.x2; r.x2 = h;
}
if (r.y2 < r.y1)
{
h = r.y1; r.y1 = r.y2; r.y2 = h;
}
switch (orientation)
{
case ORIENTATION_NORMAL:
{
if (!needsTemporaryBuffer)
return;
if (SDL_LockSurface(theSurface) < 0)
return;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
switch (temporaryBufferBPP)
{
case 16:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint16* dstPtr = (pp_uint16*)(dst + y*dstPitch + destRect.x1*dstBPP);
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*dstPtr++ = *(pp_uint16*)(srcPtr + (u>>16) * srcBPP);
u += stepU;
}
v += stepV;
}
break;
}
case 24:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint8* dstPtr = (pp_uint8*)(dst + y*dstPitch + destRect.x1*dstBPP);
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*dstPtr = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP);
*(dstPtr+1) = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP + 1);
*(dstPtr+2) = *(pp_uint8*)(srcPtr + (u>>16) * srcBPP + 2);
dstPtr+=3;
u += stepU;
}
v += stepV;
}
break;
}
case 32:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstPitch + destRect.x1*dstBPP);
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*dstPtr++ = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
u += stepU;
}
v += stepV;
}
break;
}
default:
fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
exit(2);
}
SDL_UnlockSurface(theSurface);
break;
}
case ORIENTATION_ROTATE90CCW:
{
if (SDL_LockSurface(theSurface) < 0)
return;
switch (temporaryBufferBPP)
{
case 16:
{
pp_uint32 srcPitch = temporaryBufferPitch >> 1;
pp_uint32 dstPitch = theSurface->pitch >> 1;
pp_uint16* src = (pp_uint16*)temporaryBuffer;
pp_uint16* dst = (pp_uint16*)theSurface->pixels;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint16* srcPtr = src + (v>>16)*srcPitch;
pp_uint16* dstPtr = dst + y + (realHeight-destRect.x1)*dstPitch;
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*(dstPtr-=dstPitch) = *(srcPtr+(u>>16));
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint16* srcPtr = src + y*srcPitch + r.x1;
pp_uint16* dstPtr = dst + y + (realHeight-r.x1)*dstPitch;
for (pp_uint32 x = r.x1; x < r.x2; x++)
*(dstPtr-=dstPitch) = *srcPtr++;
}
}
break;
}
case 24:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
pp_uint8* dstPtr = dst + y*dstBPP + dstPitch*(realHeight-1-destRect.x1);
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
dstPtr[0] = *(srcPtr+(u>>16) * srcBPP);
dstPtr[1] = *(srcPtr+(u>>16) * srcBPP + 1);
dstPtr[2] = *(srcPtr+(u>>16) * srcBPP + 2);
dstPtr-=dstPitch;
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint8* srcPtr = src + y*srcPitch + r.x1*srcBPP;
pp_uint8* dstPtr = dst + y*dstBPP + dstPitch*(realHeight-1-r.x1);
for (pp_uint32 x = r.x1; x < r.x2; x++)
{
dstPtr[0] = srcPtr[0];
dstPtr[1] = srcPtr[1];
dstPtr[2] = srcPtr[2];
srcPtr+=srcBPP;
dstPtr-=dstPitch;
}
}
}
break;
}
case 32:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstBPP + dstPitch*(realHeight-1-destRect.x1));
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*(dstPtr-=(dstPitch>>2)) = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint32* srcPtr = (pp_uint32*)(src + y*srcPitch + r.x1*srcBPP);
pp_uint32* dstPtr = (pp_uint32*)(dst + y*dstBPP + dstPitch*(realHeight-1-r.x1));
for (pp_uint32 x = r.x1; x < r.x2; x++)
*(dstPtr-=(dstPitch>>2)) = *srcPtr++;
}
}
break;
}
default:
fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
exit(2);
}
SDL_UnlockSurface(theSurface);
break;
}
case ORIENTATION_ROTATE90CW:
{
if (SDL_LockSurface(theSurface) < 0)
return;
switch (temporaryBufferBPP)
{
case 16:
{
pp_uint32 srcPitch = temporaryBufferPitch >> 1;
pp_uint32 dstPitch = theSurface->pitch >> 1;
pp_uint16* src = (pp_uint16*)temporaryBuffer;
pp_uint16* dst = (pp_uint16*)theSurface->pixels;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint16* srcPtr = src + (v>>16)*srcPitch;
pp_uint16* dstPtr = dst + (realWidth-1-y) + (dstPitch*(destRect.x1));
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*(dstPtr+=dstPitch) = *(srcPtr+(u>>16));
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint16* srcPtr = src + y*srcPitch + r.x1;
pp_uint16* dstPtr = dst + (realWidth-1-y) + (dstPitch*r.x1);
for (pp_uint32 x = r.x1; x < r.x2; x++)
*(dstPtr+=dstPitch) = *srcPtr++;
}
}
break;
}
case 24:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
pp_uint8* dstPtr = dst + (realWidth-1-y)*dstBPP + (dstPitch*(destRect.x1));
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
dstPtr[0] = *(srcPtr+(u>>16) * srcBPP);
dstPtr[1] = *(srcPtr+(u>>16) * srcBPP + 1);
dstPtr[2] = *(srcPtr+(u>>16) * srcBPP + 2);
dstPtr+=dstPitch;
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint8* srcPtr = src + y*srcPitch + r.x1*srcBPP;
pp_uint8* dstPtr = dst + (realWidth-1-y)*dstBPP + (dstPitch*r.x1);
for (pp_uint32 x = r.x1; x < r.x2; x++)
{
dstPtr[0] = srcPtr[0];
dstPtr[1] = srcPtr[1];
dstPtr[2] = srcPtr[2];
srcPtr+=srcBPP;
dstPtr+=dstPitch;
}
}
}
break;
}
case 32:
{
pp_uint32 srcPitch = temporaryBufferPitch;
pp_uint32 dstPitch = theSurface->pitch;
pp_uint8* src = (pp_uint8*)temporaryBuffer;
pp_uint8* dst = (pp_uint8*)theSurface->pixels;
const pp_uint32 srcBPP = temporaryBufferBPP/8;
const pp_uint32 dstBPP = theSurface->format->BytesPerPixel;
if (scaleFactor != 1)
{
PPRect destRect(r);
destRect.scale(scaleFactor);
const pp_uint32 stepU = (r.x2 - r.x1) * 65536 / (destRect.x2 - destRect.x1);
const pp_uint32 stepV = (r.y2 - r.y1) * 65536 / (destRect.y2 - destRect.y1);
pp_uint32 v = r.y1 * 65536;
for (pp_uint32 y = destRect.y1; y < destRect.y2; y++)
{
pp_uint32 u = r.x1 * 65536;
pp_uint8* srcPtr = src + (v>>16)*srcPitch;
pp_uint32* dstPtr = (pp_uint32*)(dst + (realWidth-1-y)*dstBPP + (dstPitch*(destRect.x1)));
for (pp_uint32 x = destRect.x1; x < destRect.x2; x++)
{
*(dstPtr+=(dstPitch>>2)) = *(pp_uint32*)(srcPtr + (u>>16) * srcBPP);
u += stepU;
}
v += stepV;
}
}
else
{
for (pp_uint32 y = r.y1; y < r.y2; y++)
{
pp_uint32* srcPtr = (pp_uint32*)(src + y*srcPitch + r.x1*srcBPP);
pp_uint32* dstPtr = (pp_uint32*)(dst + (realWidth-1-y)*dstBPP + (dstPitch*r.x1));
for (pp_uint32 x = r.x1; x < r.x2; x++)
*(dstPtr+=(dstPitch>>2)) = *srcPtr++;
}
}
break;
}
default:
fprintf(stderr, "SDL: Unsupported color depth for requested orientation");
exit(EXIT_FAILURE);
}
SDL_UnlockSurface(theSurface);
break;
}
}
}
// This is unused at the moment, could be useful if we manage to get the GUI resizable in the future.
void PPDisplayDeviceFB::setSize(const PPSize& size)
{
this->size = size;
theSurface = SDL_CreateRGBSurface(0, size.width, size.height, theSurface->format->BitsPerPixel, 0, 0, 0, 0);
theTexture = SDL_CreateTextureFromSurface(theRenderer, theSurface);
theRenderer = SDL_GetRenderer(theWindow);
}