diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-01-26 10:13:40 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-01-26 10:13:40 +0100 |
commit | eb2e62609992ab8b47f8805f2bc2cafce271b66f (patch) | |
tree | 58d6c387f910e3a3348a6528127f4216b524ec57 /src/graphics.cpp | |
parent | 05dc1666dc794ed6aa7f6568b768c652f8922c4e (diff) | |
parent | 8d06606835e3d01f537ebe96de8b216e64a1f969 (diff) | |
download | mana-eb2e62609992ab8b47f8805f2bc2cafce271b66f.tar.gz mana-eb2e62609992ab8b47f8805f2bc2cafce271b66f.tar.bz2 mana-eb2e62609992ab8b47f8805f2bc2cafce271b66f.tar.xz mana-eb2e62609992ab8b47f8805f2bc2cafce271b66f.zip |
Merge branch 'master' into lpc2012lpc2012
Diffstat (limited to 'src/graphics.cpp')
-rw-r--r-- | src/graphics.cpp | 451 |
1 files changed, 253 insertions, 198 deletions
diff --git a/src/graphics.cpp b/src/graphics.cpp index 08b1b298..d5c1e1a0 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,122 +26,96 @@ #include "utils/gettext.h" -#include <SDL_gfxBlitFunc.h> -#include <SDL/SDL_rotozoom.h> - -Graphics::Graphics(): - mWidth(0), - mHeight(0), - mScale(1), - mBpp(0), - mFullscreen(false), - mHWAccel(false), - mBlitMode(BLIT_NORMAL), - mScreenSurface(0) +#include <guichan/exception.hpp> + +Graphics::~Graphics() { - mTarget = 0; + _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 - SDL_FreeSurface(mTarget); - mTarget = 0; + SDL_Window *window = nullptr; + SDL_Renderer *renderer = nullptr; + SDL_CreateWindowAndRenderer(w, h, windowFlags, &window, &renderer); - // Calculate scaling factor - mScale = std::max(w / 640, h / 360); + if (!window) + return false; - mScreenSurface = SDL_SetVideoMode(w, h, bpp, displayFlags); - const SDL_PixelFormat& fmt = *(mScreenSurface->format); - setTarget(SDL_CreateRGBSurface(SDL_SWSURFACE, - w / mScale, h / mScale, - fmt.BitsPerPixel, - fmt.Rmask, fmt.Gmask, fmt.Bmask, 0)); + SDL_SetWindowMinimumSize(window, 640, 360); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - if (!mTarget) - return false; + setTarget(window); - mWidth = mTarget->w; - mHeight = mTarget->h; - mBpp = bpp; + mRenderer = renderer; + videoResized(w, h); 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 (mScreenSurface && mScreenSurface->w == w && - mScreenSurface->h == h && - mBpp == bpp && - mFullscreen == fs && - mHWAccel == hwaccel) + if (mWidth == w && + mHeight == h && + 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 fallback resolution. If that doesn't + // 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(640, 360, mBpp, mFullscreen, mHWAccel)) - { + if (!success) { + if (!setVideoMode(mWidth, mHeight, mFullscreen)) { logger->error(_("Failed to change video mode and couldn't " - "switch back to the fallback mode!")); + "switch back to the previous mode!")); } } @@ -152,12 +124,36 @@ bool Graphics::changeVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) return success; } +void Graphics::videoResized(int w, int h) +{ + const int prevWidth = mWidth; + const int prevHeight = mHeight; + + mScale = getScale(w, h); + mWidth = w / mScale; + mHeight = h / mScale; + + if (mWidth != prevWidth || mHeight != prevHeight) { + if (mScreenTexture) { + SDL_DestroyTexture(mScreenTexture); + mScreenTexture = nullptr; + } + + if (mScale > 1) { + auto pixelFormat = SDL_GetWindowPixelFormat(mTarget); + mScreenTexture = SDL_CreateTexture(mRenderer, pixelFormat, SDL_TEXTUREACCESS_TARGET, mWidth, mHeight); + } + + SDL_SetRenderTarget(mRenderer, mScreenTexture); + } +} + 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, @@ -167,15 +163,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; @@ -188,78 +176,37 @@ bool Graphics::drawRescaledImage(Image *image, int srcX, int srcY, SDL_Rect srcRect; dstRect.x = dstX; dstRect.y = dstY; srcRect.x = srcX; srcRect.y = srcY; - srcRect.w = tmpImage->getWidth(); - srcRect.h = tmpImage->getHeight(); - - returnValue = !(SDL_BlitSurface(tmpImage->mSDLSurface, &srcRect, - mTarget, &dstRect) < 0); - - tmpImage->decRef(Resource::DeleteImmediately); + srcRect.w = width; + srcRect.h = height; + dstRect.w = desiredWidth; + dstRect.h = desiredHeight; - 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, @@ -268,50 +215,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, @@ -368,27 +299,16 @@ void Graphics::drawImageRect(int x, int y, int w, int h, void Graphics::updateScreen() { - // Center viewport - SDL_Rect dstRect; - dstRect.x = (mScreenSurface->w-getWidth() * mScale) / 2; - dstRect.y = (mScreenSurface->h-getHeight() * mScale) / 2; - - // Zoom in if necessary - if (mScale > 1) - { - SDL_Surface *tmp = zoomSurface(mTarget, mScale, mScale, 0); - - // Copy temporary surface to screen - SDL_BlitSurface(tmp, NULL, mScreenSurface, &dstRect); - SDL_FreeSurface(tmp); + if (!mScreenTexture) { + // Simple case when we're rendering directly to the window + SDL_RenderPresent(mRenderer); + } else { + // Otherwise, we now render the screen surface to the window + SDL_SetRenderTarget(mRenderer, NULL); + SDL_RenderCopy(mRenderer, mScreenTexture, NULL, NULL); + SDL_RenderPresent(mRenderer); + SDL_SetRenderTarget(mRenderer, mScreenTexture); } - else - { - // Copy mTarget directly to screen - SDL_BlitSurface(mTarget, NULL, mScreenSurface, &dstRect); - } - - SDL_Flip(mScreenSurface); } SDL_Surface *Graphics::getScreenshot() @@ -404,10 +324,145 @@ 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); +} + +int Graphics::getScale(int w, int h) +{ + return std::max(w / 640, h / 360); +} + +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); +} |