diff options
Diffstat (limited to 'src/render/graphics.cpp')
-rw-r--r-- | src/render/graphics.cpp | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/src/render/graphics.cpp b/src/render/graphics.cpp new file mode 100644 index 000000000..42de3429d --- /dev/null +++ b/src/render/graphics.cpp @@ -0,0 +1,586 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2013 The ManaPlus Developers + * + * This file is part of The ManaPlus 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 "render/graphics.h" + +#include "main.h" + +#include "configuration.h" +#include "graphicsmanager.h" +#include "graphicsvertexes.h" +#include "logger.h" + +#include "resources/imagehelper.h" +#include "resources/openglimagehelper.h" + +#include <guichan/sdl/sdlpixel.hpp> + +#ifdef USE_OPENGL +#ifdef __APPLE__ +#include <OpenGL/OpenGL.h> +#endif +#endif + +#include "debug.h" + +#ifdef USE_OPENGL +#ifndef GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX +#define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#endif +#endif + +Graphics::Graphics() : + gcn::Graphics(), + mWidth(0), + mHeight(0), + mWindow(nullptr), +#ifdef USE_SDL2 + mRenderer(nullptr), +#ifdef USE_OPENGL + mGLContext(nullptr), +#endif +#endif + mBpp(0), + mAlpha(false), + mFullscreen(false), + mHWAccel(false), + mRedraw(false), + mDoubleBuffer(false), + mRect(), + mSecure(false), + mOpenGL(0), + mEnableResize(false), + mNoFrame(false), + mName("Software"), + mStartFreeMem(0), + mSync(false), + mColor(), + mColor2() +{ + mRect.x = 0; + mRect.y = 0; + mRect.w = 0; + mRect.h = 0; +} + +Graphics::~Graphics() +{ + _endDraw(); +#ifdef USE_SDL2 + if (mRenderer) + { + SDL_DestroyRenderer(mRenderer); + mRenderer = nullptr; + } +#ifdef USE_OPENGL + if (mGLContext) + { + SDL_GL_DeleteContext(mGLContext); + mGLContext = 0; + } +#endif +#endif +} + +void Graphics::setSync(const bool sync) +{ + mSync = sync; +} + +void Graphics::setMainFlags(const int w, const int h, const int bpp, + const bool fs, const bool hwaccel, + const bool resize, const bool noFrame) +{ + logger->log("graphics backend: %s", getName().c_str()); + logger->log("Setting video mode %dx%d %s", + w, h, fs ? "fullscreen" : "windowed"); + + mWidth = w; + mHeight = h; + mBpp = bpp; + mFullscreen = fs; + mHWAccel = hwaccel; + mEnableResize = resize; + mNoFrame = noFrame; +} + +int Graphics::getOpenGLFlags() const +{ +#ifdef USE_OPENGL + +#ifdef USE_SDL2 + int displayFlags = SDL_WINDOW_OPENGL; + if (mFullscreen) + displayFlags |= SDL_WINDOW_FULLSCREEN; +#else + int displayFlags = SDL_ANYFORMAT | SDL_OPENGL; +#endif // USE_SDL2 + + if (mFullscreen) + { + displayFlags |= SDL_FULLSCREEN; + } + else + { + // Resizing currently not supported on Windows, where it would require + // reuploading all textures. +#if !defined(_WIN32) + if (mEnableResize) + displayFlags |= SDL_RESIZABLE; +#endif + } + + if (mNoFrame) + displayFlags |= SDL_NOFRAME; + + return displayFlags; +#else + return 0; +#endif // USE_OPENGL +} + +bool Graphics::setOpenGLMode() +{ +#ifdef USE_OPENGL + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + if (!(mWindow = graphicsManager.createWindow(mWidth, mHeight, + mBpp, getOpenGLFlags()))) + { + mRect.w = 0; + mRect.h = 0; + return false; + } + +#ifdef USE_SDL2 + int w1 = 0; + int h1 = 0; + SDL_GetWindowSize(mWindow, &w1, &h1); + mRect.w = w1; + mRect.h = h1; + + mGLContext = SDL_GL_CreateContext(mWindow); + +#else // USE_SDL2 + + mRect.w = static_cast<uint16_t>(mWindow->w); + mRect.h = static_cast<uint16_t>(mWindow->h); +#endif // USE_SDL2 + +#ifdef __APPLE__ + if (mSync) + { + const GLint VBL = 1; + CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); + } +#endif + + graphicsManager.setGLVersion(); + graphicsManager.logVersion(); + + // Setup OpenGL + glViewport(0, 0, mWidth, mHeight); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + int gotDoubleBuffer = 0; + SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gotDoubleBuffer); + logger->log("Using OpenGL %s double buffering.", + (gotDoubleBuffer ? "with" : "without")); + + graphicsManager.initOpenGL(); + initArrays(); + graphicsManager.updateTextureFormat(); + updateMemoryInfo(); + + GLint texSize; + bool rectTex = graphicsManager.supportExtension( + "GL_ARB_texture_rectangle"); + if (rectTex && OpenGLImageHelper::getInternalTextureType() == 4 + && getOpenGL() != 3 && config.getBoolValue("rectangulartextures") + && !graphicsManager.isUseTextureSampler()) + { + logger->log1("using GL_ARB_texture_rectangle"); + OpenGLImageHelper::mTextureType = GL_TEXTURE_RECTANGLE_ARB; + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &texSize); + OpenGLImageHelper::mTextureSize = texSize; + logger->log("OpenGL texture size: %d pixels (rectangle textures)", + OpenGLImageHelper::mTextureSize); + } + else + { + OpenGLImageHelper::mTextureType = GL_TEXTURE_2D; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); + OpenGLImageHelper::mTextureSize = texSize; + logger->log("OpenGL texture size: %d pixels", + OpenGLImageHelper::mTextureSize); + } + return videoInfo(); +#else // USE_OPENGL + + return false; +#endif // USE_OPENGL +} + +int Graphics::getSoftwareFlags() const +{ +#ifdef USE_SDL2 + int displayFlags = SDL_WINDOW_SHOWN; +#else + int displayFlags = SDL_ANYFORMAT; + + if (mHWAccel) + displayFlags |= SDL_HWSURFACE | SDL_DOUBLEBUF; + else + displayFlags |= SDL_SWSURFACE; +#endif + + if (mFullscreen) + displayFlags |= SDL_FULLSCREEN; + else if (mEnableResize) + displayFlags |= SDL_RESIZABLE; + + if (mNoFrame) + displayFlags |= SDL_NOFRAME; + return displayFlags; +} + + +void Graphics::updateMemoryInfo() +{ +#ifdef USE_OPENGL + if (mStartFreeMem) + return; + + if (graphicsManager.supportExtension("GL_NVX_gpu_memory_info")) + { + glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, + &mStartFreeMem); + logger->log("free video memory: %d", mStartFreeMem); + } +#endif +} + +int Graphics::getMemoryUsage() const +{ +#ifdef USE_OPENGL + if (!mStartFreeMem) + return 0; + + if (graphicsManager.supportExtension("GL_NVX_gpu_memory_info")) + { + GLint val; + glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, + &val); + return mStartFreeMem - val; + } +#endif + return 0; +} + +#ifdef USE_SDL2 +void Graphics::dumpRendererInfo(const char *const str, + const SDL_RendererInfo &info) +{ + logger->log(str, info.name); + logger->log("flags:"); + if (info.flags & SDL_RENDERER_SOFTWARE) + logger->log(" software"); + if (info.flags & SDL_RENDERER_ACCELERATED) + logger->log(" accelerated"); + if (info.flags & SDL_RENDERER_PRESENTVSYNC) + logger->log(" vsync"); + if (info.flags & SDL_RENDERER_TARGETTEXTURE) + logger->log(" texture target"); +} +#endif + +bool Graphics::videoInfo() +{ + logger->log("SDL video info"); +#ifdef USE_SDL2 + logger->log("Using video driver: %s", SDL_GetCurrentVideoDriver()); + + if (mRenderer) + { + SDL_RendererInfo info; + SDL_GetRendererInfo(mRenderer, &info); + dumpRendererInfo("Current SDL renderer name: %s", info); + + const int num = SDL_GetNumRenderDrivers(); + logger->log("Known renderers"); + for (int f = 0; f < num; f ++) + { + if (!SDL_GetRenderDriverInfo(f, &info)) + dumpRendererInfo("renderer name: %s", info); + } + } +#else + char videoDriverName[65]; + if (SDL_VideoDriverName(videoDriverName, 64)) + logger->log("Using video driver: %s", videoDriverName); + else + logger->log1("Using video driver: unknown"); + mDoubleBuffer = ((mWindow->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF); + logger->log("Double buffer mode: %s", mDoubleBuffer ? "yes" : "no"); + + imageHelper->dumpSurfaceFormat(mWindow); + + const SDL_VideoInfo *const vi = SDL_GetVideoInfo(); + if (!vi) + return false; + + 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")); +#endif + + return true; +} + +bool Graphics::setFullscreen(const bool fs) +{ + if (mFullscreen == fs) + return true; + + return setVideoMode(mWidth, mHeight, mBpp, fs, mHWAccel, + mEnableResize, mNoFrame); +} + +bool Graphics::resizeScreen(const int width, const int height) +{ + if (mWidth == width && mHeight == height) + return true; + +#ifdef USE_SDL2 + _endDraw(); + + mRect.w = width; + mRect.h = height; + mWidth = width; + mHeight = height; + +#ifdef USE_OPENGL + // +++ probably this way will not work in windows/mac + // Setup OpenGL + glViewport(0, 0, mWidth, mHeight); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); +#else + // +++ need impliment resize in soft mode +#endif // USE_OPENGL + + _beginDraw(); + return true; + +#else + const int prevWidth = mWidth; + const int prevHeight = mHeight; + + _endDraw(); + + const bool success = setVideoMode(width, height, mBpp, + mFullscreen, mHWAccel, mEnableResize, mNoFrame); + + // If it didn't work, try to restore the previous size. If that didn't + // work either, bail out (but then we're in deep trouble). + if (!success) + { + if (!setVideoMode(prevWidth, prevHeight, mBpp, + mFullscreen, mHWAccel, mEnableResize, mNoFrame)) + { + return false; + } + } + + _beginDraw(); + + return success; +#endif // USE_SDL2 +} + +int Graphics::getWidth() const +{ + return mWidth; +} + +int Graphics::getHeight() const +{ + return mHeight; +} + +bool Graphics::drawImage(const Image *image, int x, int y) +{ + if (image) + { + return drawImage2(image, 0, 0, x, y, + image->mBounds.w, image->mBounds.h, false); + } + else + { + return false; + } +} + +void Graphics::drawImageRect(const int x, const int y, + const int w, const int h, + const Image *const topLeft, + const Image *const topRight, + const Image *const bottomLeft, + const Image *const bottomRight, + const Image *const top, + const Image *const right, + const Image *const bottom, + const Image *const left, + const Image *const center) +{ + BLOCK_START("Graphics::drawImageRect") + const bool drawMain = center && topLeft && topRight + && bottomLeft && bottomRight; + + // Draw the center area + if (center && drawMain) + { + const int tlw = topLeft->getWidth(); + const int tlh = topLeft->getHeight(); + drawImagePattern(center, tlw + x, tlh + y, + w - tlw - topRight->getWidth(), + h - tlh - bottomLeft->getHeight()); + } + + // Draw the sides + if (top && left && bottom && right) + { + const int lw = left->getWidth(); + const int rw = right->getWidth(); + const int th = top->getHeight(); + const int bh = bottom->getHeight(); + drawImagePattern(top, x + lw, y, w - lw - rw, th); + drawImagePattern(bottom, x + lw, h - bh + y, w - lw - rw, bh); + drawImagePattern(left, x, y + th, lw, h - th - bh); + drawImagePattern(right, x + w - rw, th + y, rw, h - th - bh); + } + // Draw the corners + if (drawMain) + { + drawImage(topLeft, x, y); + drawImage(topRight, x + w - topRight->getWidth(), y); + drawImage(bottomLeft, x, h - bottomLeft->getHeight() + y); + drawImage(bottomRight, + x + w - bottomRight->getWidth(), + y + h - bottomRight->getHeight()); + } + BLOCK_END("Graphics::drawImageRect") +} + +void Graphics::drawImageRect(int x, int y, int w, int h, + const ImageRect &imgRect) +{ + drawImageRect(x, y, w, h, + imgRect.grid[0], imgRect.grid[2], imgRect.grid[6], imgRect.grid[8], + imgRect.grid[1], imgRect.grid[5], imgRect.grid[7], imgRect.grid[3], + imgRect.grid[4]); +} + +bool Graphics::drawNet(const int x1, const int y1, const int x2, const int y2, + const int width, const int height) +{ + for (int y = y1; y < y2; y += height) + drawLine(x1, y, x2, y); + + for (int x = x1; x < x2; x += width) + drawLine(x, y1, x, y2); + + return true; +} + +bool Graphics::calcImageRect(ImageVertexes *const vert, + const int x, const int y, + const int w, const int h, + const Image *const topLeft, + const Image *const topRight, + const Image *const bottomLeft, + const Image *const bottomRight, + const Image *const top, + const Image *const right, + const Image *const bottom, + const Image *const left, + const Image *const center) +{ + if (!vert) + return false; + + BLOCK_START("Graphics::calcImageRect") + const bool drawMain = center && topLeft && topRight + && bottomLeft && bottomRight; + +// pushClipArea(gcn::Rectangle(x, y, w, h)); + + // Draw the center area + if (center && drawMain) + { + const int tlw = topLeft->getWidth(); + const int tlh = topLeft->getHeight(); + calcImagePattern(vert, center, tlw + x, tlh + y, + w - tlw - topRight->getWidth(), + h - tlh - bottomLeft->getHeight()); + } + // Draw the sides + if (top && left && bottom && right) + { + const int lw = left->getWidth(); + const int rw = right->getWidth(); + const int th = top->getHeight(); + const int bh = bottom->getHeight(); + calcImagePattern(vert, top, x + lw, y, w - lw - rw, th); + calcImagePattern(vert, bottom, x + lw, y + h - bh, w - lw - rw, bh); + calcImagePattern(vert, left, x, y + th, lw, h - th - bh); + calcImagePattern(vert, right, x + w - rw, y + th, rw, h - th - bh); + } + + calcTile(vert, topLeft, x, y); + if (topRight) + calcTile(vert, topRight, x + w - topRight->getWidth(), y); + if (bottomLeft) + calcTile(vert, bottomLeft, x, y + h - bottomLeft->getHeight()); + if (bottomRight) + { + calcTile(vert, bottomRight, x + w - bottomRight->getWidth(), + y + h - bottomRight->getHeight()); + } + +// popClipArea(); + BLOCK_END("Graphics::calcImageRect") + return 0; +} |