From b718d86a6ffa25c7cdbe7959c07bbcb17817b9fd Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Sun, 19 Jun 2016 07:35:45 +0200 Subject: [PATCH] OPENGL: Add TiledSurface to be used for drawing large 2D surfaces --- graphics/module.mk | 1 + graphics/opengl/tiledsurface.cpp | 125 +++++++++++++++++++++++++++++++ graphics/opengl/tiledsurface.h | 118 +++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 graphics/opengl/tiledsurface.cpp create mode 100644 graphics/opengl/tiledsurface.h diff --git a/graphics/module.mk b/graphics/module.mk index d101eea1bad..ebd1c0dec0f 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS := \ opengl/context.o \ opengl/framebuffer.o \ opengl/texture.o \ + opengl/tiledsurface.o \ opengl/shader.o \ opengl/surfacerenderer.o \ opengl/box_shaders.o \ diff --git a/graphics/opengl/tiledsurface.cpp b/graphics/opengl/tiledsurface.cpp new file mode 100644 index 00000000000..4591160470a --- /dev/null +++ b/graphics/opengl/tiledsurface.cpp @@ -0,0 +1,125 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 (at your option) 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/textconsole.h" + +#if defined(USE_OPENGL) + +#include "graphics/opengl/tiledsurface.h" + +#include "graphics/opengl/surfacerenderer.h" +#include "graphics/opengl/texture.h" + +namespace OpenGL { + +TiledSurface::TiledSurface(uint width, uint height, const Graphics::PixelFormat &pixelFormat) { + _backingSurface.create(width, height, pixelFormat); + + for (uint y = 0; y < height; y += maxTextureSize) { + for (uint x = 0; x < width; x += maxTextureSize) { + uint textureWidth = (x + maxTextureSize >= width) ? (width - x) : maxTextureSize; + uint textureHeight = (y + maxTextureSize >= height) ? (height - y) : maxTextureSize; + + _tiles.push_back(Tile()); + + Tile &tile = _tiles.back(); + tile.rect = Common::Rect(textureWidth, textureHeight); + tile.rect.translate(x, y); + tile.texture = nullptr; + tile.dirty = true; + } + } +} + +TiledSurface::~TiledSurface() { + for (uint i = 0; i < _tiles.size(); i++) { + delete _tiles[i].texture; + } + _backingSurface.free(); +} + +void TiledSurface::copyRectToSurface(const void *src, int srcPitch, int x, int y, int w, int h) { + _backingSurface.copyRectToSurface(src, srcPitch, x, y, w, h); + + Common::Rect destRect = Common::Rect(w, h); + destRect.translate(x, y); + + for (uint i = 0; i < _tiles.size(); i++) { + if (_tiles[i].rect.intersects(destRect) || _tiles[i].rect.contains(destRect)) { + _tiles[i].dirty = true; + } + } +} + +void TiledSurface::update() { + for (uint i = 0; i < _tiles.size(); i++) { + Tile &tile = _tiles[i]; + if (tile.dirty) { + Graphics::Surface subSurface = _backingSurface.getSubArea(tile.rect); + + delete tile.texture; + tile.texture = new Texture(subSurface); + + tile.dirty = false; + } + } +} + +void TiledSurface::draw(SurfaceRenderer *surfaceRenderer) const { + for (uint i = 0; i < _tiles.size(); i++) { + const Tile &tile = _tiles[i]; + + assert(tile.texture); + assert(!tile.dirty); + + Math::Vector2d topLeft = Math::Vector2d(tile.rect.left / (float)_backingSurface.w, tile.rect.top / (float)_backingSurface.h); + Math::Vector2d bottomRight = Math::Vector2d(tile.rect.right / (float)_backingSurface.w, tile.rect.bottom / (float)_backingSurface.h); + + surfaceRenderer->render(tile.texture, Math::Rect2d(topLeft, bottomRight)); + } +} + +void TiledSurface::fill(uint32 color) { + Common::Rect rect = Common::Rect(_backingSurface.w, _backingSurface.h); + _backingSurface.fillRect(rect, color); + + invalidateAllTiles(); +} + +void TiledSurface::invalidateAllTiles() { + for (uint i = 0; i < _tiles.size(); i++) { + _tiles[i].dirty = true; + } +} + +Graphics::Surface *TiledSurface::getBackingSurface() { + invalidateAllTiles(); + return &_backingSurface; +} + +const Graphics::Surface *TiledSurface::getBackingSurface() const { + return &_backingSurface; +} + +} // End of namespace OpenGL + +#endif diff --git a/graphics/opengl/tiledsurface.h b/graphics/opengl/tiledsurface.h new file mode 100644 index 00000000000..107d27243bd --- /dev/null +++ b/graphics/opengl/tiledsurface.h @@ -0,0 +1,118 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 (at your option) 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GRAPHICS_OPENGL_TILED_SURFACE_H +#define GRAPHICS_OPENGL_TILED_SURFACE_H + +#include "graphics/opengl/system_headers.h" + +#include "common/array.h" +#include "common/rect.h" + +#include "graphics/surface.h" + +namespace OpenGL { + +class Texture; +class SurfaceRenderer; + +/** + * Surface implementation using OpenGL texture tiles + */ +class TiledSurface { +public: + TiledSurface(uint width, uint height, const Graphics::PixelFormat &pixelFormat); + ~TiledSurface(); + + /** + * Copy image data to the surface. + * + * The format of the input data needs to match the format returned by + * getFormat. + * This does not immediatly updates the textures. + * + * @param x X coordinate of upper left corner to copy data to. + * @param y Y coordinate of upper left corner to copy data to. + * @param w Width of the image data to copy. + * @param h Height of the image data to copy. + * @param src Pointer to image data. + * @param srcPitch The number of bytes in a row of the image data. + */ + void copyRectToSurface(const void *src, int srcPitch, int x, int y, int w, int h); + + /** + * Update the OpenGL textures from the backing surface + */ + void update(); + + /** + * Draw as a 2D surface + * + * The destination rect is as follow : + * x: left [0.0, 1.0] right + * y: top [0.0, 1.0] bottom + * + * @param surfaceRenderer + */ + void draw(SurfaceRenderer *surfaceRenderer) const; + + /** + * Fill the surface with a fixed color. + * + * @param color Color value in format returned by getFormat. + */ + void fill(uint32 color); + + /** + * Get the backing surface + * + * This can be used to update the image data, but causes a full update. + * Using copyRectToSurface is preferred + */ + Graphics::Surface *getBackingSurface(); + + /** + * Get the backing surface + * + * This const version can be used to read image data without causing + * a full texture invalidation. + */ + const Graphics::Surface *getBackingSurface() const; + +private: + static const uint maxTextureSize = 256; + + struct Tile { + Texture *texture; + Common::Rect rect; + bool dirty; + }; + + Graphics::Surface _backingSurface; + Common::Array _tiles; + + void invalidateAllTiles(); +}; + +} // End of namespace OpenGL + +#endif