diff options
Diffstat (limited to 'src/graphics.cpp')
-rw-r--r-- | src/graphics.cpp | 367 |
1 files changed, 214 insertions, 153 deletions
diff --git a/src/graphics.cpp b/src/graphics.cpp index ac3735f5..b4c65b0a 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -19,8 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <cassert> - #include "graphics.h" #include "log.h" @@ -28,103 +26,95 @@ #include "utils/gettext.h" -#include <SDL_gfxBlitFunc.h> +#include <guichan/exception.hpp> -Graphics::Graphics(): - mWidth(0), - mHeight(0), - mBpp(0), - mFullscreen(false), - mHWAccel(false), - mBlitMode(BLIT_NORMAL) +Graphics::~Graphics() { + _endDraw(); } -Graphics::~Graphics() +void Graphics::setTarget(SDL_Window *target) { _endDraw(); + + mTarget = target; + + if (mTarget) + _beginDraw(); } -bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) +bool Graphics::setVideoMode(int w, int h, bool fs) { logger->log("Setting video mode %dx%d %s", w, h, fs ? "fullscreen" : "windowed"); - logger->log("Bits per pixel: %d", bpp); - - int displayFlags = SDL_ANYFORMAT; + int windowFlags = SDL_WINDOW_ALLOW_HIGHDPI; if (fs) - displayFlags |= SDL_FULLSCREEN; + windowFlags |= SDL_WINDOW_FULLSCREEN; else - displayFlags |= SDL_RESIZABLE; + windowFlags |= SDL_WINDOW_RESIZABLE; - if (hwaccel) - displayFlags |= SDL_HWSURFACE | SDL_DOUBLEBUF; - else - displayFlags |= SDL_SWSURFACE; + // TODO_SDL2: Support SDL_WINDOW_FULLSCREEN_DESKTOP - setTarget(SDL_SetVideoMode(w, h, bpp, displayFlags)); + SDL_Window *window = nullptr; + SDL_Renderer *renderer = nullptr; + SDL_CreateWindowAndRenderer(w, h, windowFlags, &window, &renderer); - if (!mTarget) + if (!window) return false; + SDL_SetWindowMinimumSize(window, 640, 480); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + + setTarget(window); + + mRenderer = renderer; mWidth = w; mHeight = h; - mBpp = bpp; mFullscreen = fs; - mHWAccel = hwaccel; - char videoDriverName[64]; - - if (SDL_VideoDriverName(videoDriverName, 64)) - logger->log("Using video driver: %s", videoDriverName); + if (const char *driver = SDL_GetCurrentVideoDriver()) + logger->log("Using video driver: %s", driver); else - logger->log("Using video driver: unknown"); - - const SDL_VideoInfo *vi = SDL_GetVideoInfo(); - - logger->log("Possible to create hardware surfaces: %s", - vi->hw_available ? "yes" : "no"); - logger->log("Window manager available: %s", - vi->wm_available ? "yes" : "no"); - logger->log("Accelerated hardware to hardware blits: %s", - vi->blit_hw ? "yes" : "no"); - logger->log("Accelerated hardware to hardware colorkey blits: %s", - vi->blit_hw_CC ? "yes" : "no"); - logger->log("Accelerated hardware to hardware alpha blits: %s", - vi->blit_hw_A ? "yes" : "no"); - logger->log("Accelerated software to hardware blits: %s", - vi->blit_sw ? "yes" : "no"); - logger->log("Accelerated software to hardware colorkey blits: %s", - vi->blit_sw_CC ? "yes" : "no"); - logger->log("Accelerated software to hardware alpha blits: %s", - vi->blit_sw_A ? "yes" : "no"); - logger->log("Accelerated color fills: %s", - vi->blit_fill ? "yes" : "no"); - logger->log("Available video memory: %d", vi->video_mem); + logger->log("Using video driver: not initialized"); + + SDL_RendererInfo info; + + if (SDL_GetRendererInfo(mRenderer, &info) == 0) { + logger->log("Using renderer: %s", info.name); + + logger->log("The renderer is a software fallback: %s", + (info.flags & SDL_RENDERER_SOFTWARE) ? "yes" : "no"); + logger->log("The renderer is hardware accelerated: %s", + (info.flags & SDL_RENDERER_ACCELERATED) ? "yes" : "no"); + logger->log("Vsync: %s", + (info.flags & SDL_RENDERER_PRESENTVSYNC) ? "on" : "off"); + logger->log("Renderer supports rendering to texture: %s", + (info.flags & SDL_RENDERER_TARGETTEXTURE) ? "yes" : "no"); + logger->log("Max texture size: %dx%d", + info.max_texture_width, info.max_texture_height); + } return true; } -bool Graphics::changeVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) +bool Graphics::changeVideoMode(int w, int h, bool fs) { // Just return success if we're already in this mode if (mWidth == w && mHeight == h && - mBpp == bpp && - mFullscreen == fs && - mHWAccel == hwaccel) + mFullscreen == fs) return true; _endDraw(); - bool success = setVideoMode(w, h, bpp, fs, hwaccel); + bool success = setVideoMode(w, h, fs); // If it didn't work, try to restore the previous mode. If that doesn't // work either, we're in big trouble and bail out. if (!success) { - if (!setVideoMode(mWidth, mHeight, mBpp, mFullscreen, mHWAccel)) { + if (!setVideoMode(mWidth, mHeight, mFullscreen)) { logger->error(_("Failed to change video mode and couldn't " "switch back to the previous mode!")); } @@ -135,6 +125,12 @@ bool Graphics::changeVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) return success; } +void Graphics::videoResized(int w, int h) +{ + mWidth = w; + mHeight = h; +} + int Graphics::getWidth() const { return mWidth; @@ -147,10 +143,10 @@ int Graphics::getHeight() const bool Graphics::drawImage(Image *image, int x, int y) { - if (image) - return drawImage(image, 0, 0, x, y, image->mBounds.w, image->mBounds.h); - else + if (!image) return false; + + return drawImage(image, 0, 0, x, y, image->mBounds.w, image->mBounds.h); } bool Graphics::drawRescaledImage(Image *image, int srcX, int srcY, @@ -160,15 +156,7 @@ bool Graphics::drawRescaledImage(Image *image, int srcX, int srcY, bool useColor) { // Check that preconditions for blitting are met. - if (!mTarget || !image) - return false; - if (!image->mSDLSurface) - return false; - - Image *tmpImage = image->SDLgetScaledImage(desiredWidth, desiredHeight); - bool returnValue = false; - - if (!tmpImage) + if (!mTarget || !image || !image->mTexture) return false; dstX += mClipStack.top().xOffset; @@ -183,76 +171,35 @@ bool Graphics::drawRescaledImage(Image *image, int srcX, int srcY, srcRect.x = srcX; srcRect.y = srcY; srcRect.w = width; srcRect.h = height; + dstRect.w = desiredWidth; + dstRect.h = desiredHeight; - returnValue = !(SDL_BlitSurface(tmpImage->mSDLSurface, &srcRect, - mTarget, &dstRect) < 0); - - tmpImage->decRef(Resource::DeleteImmediately); - - return returnValue; + return !(SDL_RenderCopy(mRenderer, image->mTexture, &srcRect, &dstRect) < 0); } bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY, - int width, int height, bool) + int width, int height, bool useColor) { - // Check that preconditions for blitting are met. - if (!mTarget || !image || !image->mSDLSurface) + if (!image) return false; - dstX += mClipStack.top().xOffset; - dstY += mClipStack.top().yOffset; - - srcX += image->mBounds.x; - srcY += image->mBounds.y; - - SDL_Rect dstRect; - SDL_Rect srcRect; - dstRect.x = dstX; dstRect.y = dstY; - srcRect.x = srcX; srcRect.y = srcY; - srcRect.w = width; - srcRect.h = height; - - if (mBlitMode == BLIT_NORMAL) - return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0); - else - return !(SDL_gfxBlitRGBA(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0); + return drawRescaledImage(image, + srcX, srcY, + dstX, dstY, + width, height, + width, height, useColor); } void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h) { // Check that preconditions for blitting are met. - if (!mTarget || !image) - return; - if (!image->mSDLSurface) + if (!image) return; const int iw = image->getWidth(); const int ih = image->getHeight(); - if (iw == 0 || ih == 0) - return; - - for (int py = 0; py < h; py += ih) // Y position on pattern plane - { - int dh = (py + ih >= h) ? h - py : ih; - int srcY = image->mBounds.y; - int dstY = y + py + mClipStack.top().yOffset; - - for (int px = 0; px < w; px += iw) // X position on pattern plane - { - int dw = (px + iw >= w) ? w - px : iw; - int srcX = image->mBounds.x; - int dstX = x + px + mClipStack.top().xOffset; - - SDL_Rect dstRect; - SDL_Rect srcRect; - dstRect.x = dstX; dstRect.y = dstY; - srcRect.x = srcX; srcRect.y = srcY; - srcRect.w = dw; srcRect.h = dh; - - SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect); - } - } + drawRescaledImagePattern(image, x, y, w, h, iw, ih); } void Graphics::drawRescaledImagePattern(Image *image, @@ -261,50 +208,34 @@ void Graphics::drawRescaledImagePattern(Image *image, int scaledWidth, int scaledHeight) { // Check that preconditions for blitting are met. - if (!mTarget || !image) - return; - if (!image->mSDLSurface) + if (!mTarget || !image || !image->mTexture) return; if (scaledHeight == 0 || scaledWidth == 0) return; - Image *tmpImage = image->SDLgetScaledImage(scaledWidth, scaledHeight); - if (!tmpImage) - return; - - const int iw = tmpImage->getWidth(); - const int ih = tmpImage->getHeight(); - - if (iw == 0 || ih == 0) - { - tmpImage->decRef(Resource::DeleteImmediately); - return; - } - - for (int py = 0; py < h; py += ih) // Y position on pattern plane + for (int py = 0; py < h; py += scaledHeight) // Y position on pattern plane { - int dh = (py + ih >= h) ? h - py : ih; - int srcY = tmpImage->mBounds.y; + int dh = (py + scaledHeight >= h) ? h - py : scaledHeight; + int srcY = image->mBounds.y; int dstY = y + py + mClipStack.top().yOffset; - for (int px = 0; px < w; px += iw) // X position on pattern plane + for (int px = 0; px < w; px += scaledWidth) // X position on pattern plane { - int dw = (px + iw >= w) ? w - px : iw; - int srcX = tmpImage->mBounds.x; + int dw = (px + scaledWidth >= w) ? w - px : scaledWidth; + int srcX = image->mBounds.x; int dstX = x + px + mClipStack.top().xOffset; SDL_Rect dstRect; SDL_Rect srcRect; dstRect.x = dstX; dstRect.y = dstY; + dstRect.w = dw; dstRect.h = dh; srcRect.x = srcX; srcRect.y = srcY; srcRect.w = dw; srcRect.h = dh; - SDL_BlitSurface(tmpImage->mSDLSurface, &srcRect, mTarget, &dstRect); + SDL_RenderCopy(mRenderer, image->mTexture, &srcRect, &dstRect); } } - - tmpImage->decRef(Resource::DeleteImmediately); } void Graphics::drawImageRect(int x, int y, int w, int h, @@ -361,7 +292,7 @@ void Graphics::drawImageRect(int x, int y, int w, int h, void Graphics::updateScreen() { - SDL_Flip(mTarget); + SDL_RenderPresent(mRenderer); } SDL_Surface *Graphics::getScreenshot() @@ -377,10 +308,140 @@ SDL_Surface *Graphics::getScreenshot() #endif int amask = 0x00000000; - SDL_Surface *screenshot = SDL_CreateRGBSurface(SDL_SWSURFACE, mTarget->w, - mTarget->h, 24, rmask, gmask, bmask, amask); - - SDL_BlitSurface(mTarget, NULL, screenshot, NULL); + SDL_Surface *screenshot = SDL_CreateRGBSurface(0, mWidth, + mHeight, 24, rmask, gmask, bmask, amask); + SDL_RenderReadPixels(mRenderer, NULL, SDL_PIXELFORMAT_RGB888, screenshot->pixels, screenshot->pitch); return screenshot; } + +bool Graphics::pushClipArea(gcn::Rectangle area) +{ + bool result = gcn::Graphics::pushClipArea(area); + updateSDLClipRect(); + return result; +} + +void Graphics::popClipArea() +{ + gcn::Graphics::popClipArea(); + updateSDLClipRect(); +} + +void Graphics::updateSDLClipRect() +{ + if (mClipStack.empty()) + { + SDL_RenderSetClipRect(mRenderer, NULL); + return; + } + + const gcn::ClipRectangle &carea = mClipStack.top(); + SDL_Rect rect; + rect.x = carea.x; + rect.y = carea.y; + rect.w = carea.width; + rect.h = carea.height; + + SDL_RenderSetClipRect(mRenderer, &rect); +} + +void Graphics::drawPoint(int x, int y) +{ + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); + } + + const gcn::ClipRectangle &top = mClipStack.top(); + + x += top.xOffset; + y += top.yOffset; + + if (!top.isPointInRect(x, y)) + return; + + SDL_SetRenderDrawColor(mRenderer, + (Uint8)(mColor.r), + (Uint8)(mColor.g), + (Uint8)(mColor.b), + (Uint8)(mColor.a)); + SDL_RenderDrawPoint(mRenderer, x, y); +} + +void Graphics::drawLine(int x1, int y1, int x2, int y2) +{ + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); + } + + const gcn::ClipRectangle &top = mClipStack.top(); + + x1 += top.xOffset; + y1 += top.yOffset; + x2 += top.xOffset; + y2 += top.yOffset; + + SDL_SetRenderDrawColor(mRenderer, + (Uint8)(mColor.r), + (Uint8)(mColor.g), + (Uint8)(mColor.b), + (Uint8)(mColor.a)); + SDL_RenderDrawLine(mRenderer, x1, y1, x2, y2); +} + +void Graphics::drawRectangle(const gcn::Rectangle &rectangle) +{ + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); + } + + const gcn::ClipRectangle &top = mClipStack.top(); + + SDL_Rect rect; + rect.x = rectangle.x + top.xOffset; + rect.y = rectangle.y + top.yOffset; + rect.w = rectangle.width; + rect.h = rectangle.height; + + SDL_SetRenderDrawColor(mRenderer, + (Uint8)(mColor.r), + (Uint8)(mColor.g), + (Uint8)(mColor.b), + (Uint8)(mColor.a)); + SDL_RenderDrawRect(mRenderer, &rect); +} + +void Graphics::fillRectangle(const gcn::Rectangle &rectangle) +{ + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); + } + + const gcn::ClipRectangle &top = mClipStack.top(); + + gcn::Rectangle area = rectangle; + area.x += top.xOffset; + area.y += top.yOffset; + + if(!area.isIntersecting(top)) + { + return; + } + + SDL_Rect rect; + rect.x = area.x; + rect.y = area.y; + rect.w = area.width; + rect.h = area.height; + + SDL_SetRenderDrawColor(mRenderer, + (Uint8)(mColor.r), + (Uint8)(mColor.g), + (Uint8)(mColor.b), + (Uint8)(mColor.a)); + SDL_RenderFillRect(mRenderer, &rect); +} |