summaryrefslogtreecommitdiff
path: root/src/sdlgraphics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sdlgraphics.cpp')
-rw-r--r--src/sdlgraphics.cpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/src/sdlgraphics.cpp b/src/sdlgraphics.cpp
new file mode 100644
index 00000000..b7f80fd2
--- /dev/null
+++ b/src/sdlgraphics.cpp
@@ -0,0 +1,304 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2012 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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 2 of the License, or
+ * 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 "sdlgraphics.h"
+
+#include "log.h"
+#include "resources/image.h"
+
+#include <guichan/exception.hpp>
+
+SDLGraphics::SDLGraphics(SDL_Window *window, SDL_Renderer *renderer)
+ : mWindow(window)
+ , mRenderer(renderer)
+{
+ Image::setRenderer(mRenderer);
+
+ SDL_GetRendererOutputSize(mRenderer, &mWidth, &mHeight);
+
+ SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
+
+ if (const char *driver = SDL_GetCurrentVideoDriver())
+ logger->log("Using video driver: %s", driver);
+ else
+ logger->log("Using video driver: not initialized");
+
+ SDL_RendererInfo info;
+
+ if (SDL_GetRendererInfo(renderer, &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);
+ }
+}
+
+SDLGraphics::~SDLGraphics()
+{
+ SDL_DestroyRenderer(mRenderer);
+}
+
+void SDLGraphics::setVSync(bool sync)
+{
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ SDL_RenderSetVSync(mRenderer, sync ? SDL_TRUE : SDL_FALSE);
+#endif
+}
+
+void SDLGraphics::videoResized(int w, int h)
+{
+ SDL_GetRendererOutputSize(mRenderer, &mWidth, &mHeight);
+}
+
+bool SDLGraphics::drawRescaledImage(Image *image,
+ int srcX, int srcY,
+ int dstX, int dstY,
+ int width, int height,
+ int desiredWidth, int desiredHeight,
+ bool useColor)
+{
+ // Check that preconditions for blitting are met.
+ if (!image || !image->mTexture)
+ 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;
+ dstRect.w = desiredWidth;
+ dstRect.h = desiredHeight;
+
+ return !(SDL_RenderCopy(mRenderer, image->mTexture, &srcRect, &dstRect) < 0);
+}
+
+void SDLGraphics::drawRescaledImagePattern(Image *image,
+ int x, int y,
+ int w, int h,
+ int scaledWidth,
+ int scaledHeight)
+{
+ // Check that preconditions for blitting are met.
+ if (!image || !image->mTexture)
+ return;
+
+ if (scaledHeight <= 0 || scaledWidth <= 0)
+ return;
+
+ for (int py = 0; py < h; py += scaledHeight) // Y position on pattern plane
+ {
+ 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 += scaledWidth) // X position on pattern plane
+ {
+ 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;
+
+ if (SDL_RenderCopy(mRenderer, image->mTexture, &srcRect, &dstRect))
+ return;
+ }
+ }
+}
+
+void SDLGraphics::updateScreen()
+{
+ SDL_RenderPresent(mRenderer);
+}
+
+SDL_Surface *SDLGraphics::getScreenshot()
+{
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ int rmask = 0xff000000;
+ int gmask = 0x00ff0000;
+ int bmask = 0x0000ff00;
+#else
+ int rmask = 0x000000ff;
+ int gmask = 0x0000ff00;
+ int bmask = 0x00ff0000;
+#endif
+ int amask = 0x00000000;
+
+ SDL_Surface *screenshot = SDL_CreateRGBSurface(0, mWidth,
+ mHeight, 24, rmask, gmask, bmask, amask);
+
+ SDL_RenderReadPixels(mRenderer, nullptr,
+ screenshot->format->format,
+ screenshot->pixels,
+ screenshot->pitch);
+
+ return screenshot;
+}
+
+bool SDLGraphics::pushClipArea(gcn::Rectangle area)
+{
+ bool result = Graphics::pushClipArea(area);
+ updateSDLClipRect();
+ return result;
+}
+
+void SDLGraphics::popClipArea()
+{
+ Graphics::popClipArea();
+ updateSDLClipRect();
+}
+
+void SDLGraphics::updateSDLClipRect()
+{
+ if (mClipStack.empty())
+ {
+ SDL_RenderSetClipRect(mRenderer, nullptr);
+ 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 SDLGraphics::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 SDLGraphics::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 SDLGraphics::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 SDLGraphics::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);
+}