2020-05-29 13:11:53 +02:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-16 00:17:43 +02:00
|
|
|
#include "common/algorithm.h"
|
2020-06-02 13:42:48 +02:00
|
|
|
#include "engines/wintermute/base/gfx/base_image.h"
|
2020-05-22 00:49:03 +02:00
|
|
|
#include "graphics/transparent_surface.h"
|
2020-05-19 18:32:27 +02:00
|
|
|
|
2020-10-10 14:12:07 +02:00
|
|
|
#if defined(USE_OPENGL_GAME) && !defined(USE_GLES2)
|
2020-10-06 07:33:01 +02:00
|
|
|
|
|
|
|
#include "engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h"
|
|
|
|
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
namespace Wintermute {
|
|
|
|
|
2020-06-12 15:29:28 +02:00
|
|
|
void applyColorKey(Graphics::Surface &surf, byte ckRed, byte ckGreen, byte ckBlue, bool replaceAlpha) {
|
|
|
|
// this is taken from Graphics::TransparentSurface
|
|
|
|
// only difference is that we set the pixel
|
|
|
|
// color to transparent black, like D3DX,
|
|
|
|
// if it matches the color key
|
|
|
|
for (int y = 0; y < surf.h; y++) {
|
|
|
|
for (int x = 0; x < surf.w; x++) {
|
|
|
|
uint32 pix = ((uint32 *)surf.getPixels())[y * surf.w + x];
|
|
|
|
uint8 r, g, b, a;
|
|
|
|
surf.format.colorToARGB(pix, a, r, g, b);
|
|
|
|
if (r == ckRed && g == ckGreen && b == ckBlue) {
|
|
|
|
a = 0;
|
|
|
|
r = 0;
|
|
|
|
g = 0;
|
|
|
|
b = 0;
|
|
|
|
((uint32 *)surf.getPixels())[y * surf.w + x] = surf.format.ARGBToColor(a, r, g, b);
|
|
|
|
} else if (replaceAlpha) {
|
|
|
|
a = 255;
|
|
|
|
((uint32 *)surf.getPixels())[y * surf.w + x] = surf.format.ARGBToColor(a, r, g, b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-21 04:14:33 +02:00
|
|
|
BaseSurfaceOpenGL3D::BaseSurfaceOpenGL3D(BaseGame *game, BaseRenderer3D *renderer)
|
2020-06-21 20:53:04 +02:00
|
|
|
: BaseSurface(game), _tex(0), _renderer(renderer), _imageData(nullptr), _texWidth(0), _texHeight(0) {
|
2020-06-16 00:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BaseSurfaceOpenGL3D::~BaseSurfaceOpenGL3D() {
|
|
|
|
glDeleteTextures(1, &_tex);
|
2020-06-12 14:25:30 +02:00
|
|
|
delete[] _imageData;
|
2020-05-19 16:23:53 +02:00
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::invalidate() {
|
2020-06-25 23:09:04 +02:00
|
|
|
glDeleteTextures(1, &_tex);
|
|
|
|
delete[] _imageData;
|
|
|
|
_imageData = nullptr;
|
|
|
|
|
|
|
|
_valid = false;
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayHalfTrans(int x, int y, Rect32 rect) {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::displayHalfTrans not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::isTransparentAt(int x, int y) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-12 14:25:30 +02:00
|
|
|
uint8 *imageData = new uint8[4 * _texWidth * _texHeight]();
|
|
|
|
|
|
|
|
// assume 32 bit rgba for now
|
|
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
|
|
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
uint8 alpha = imageData[y * _texWidth * 4 + x * 4 + 3];
|
|
|
|
|
|
|
|
delete[] imageData;
|
|
|
|
return alpha < 128;
|
2020-05-19 16:23:53 +02:00
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-21 20:53:04 +02:00
|
|
|
_renderer->drawSprite(*this, rect, zoomX, zoomY, Vector2(x, y), alpha, false, blendMode, mirrorX, mirrorY);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayTrans(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-21 20:53:04 +02:00
|
|
|
_renderer->drawSprite(*this, rect, 100, 100, Vector2(x, y), alpha, false, blendMode, mirrorX, mirrorY);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-21 20:53:04 +02:00
|
|
|
_renderer->drawSprite(*this, rect, 100, 100, Vector2(x + offsetX, y + offsetY), alpha, false, blendMode, mirrorX, mirrorY);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-21 20:53:04 +02:00
|
|
|
_renderer->drawSprite(*this, rect, 100, 100, Vector2(x, y), 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) {
|
2020-08-18 18:52:57 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
|
|
|
Vector2 position(x, y);
|
|
|
|
Vector2 rotation;
|
|
|
|
rotation.x = x + transform._hotspot.x * (transform._zoom.x / 100.0f);
|
|
|
|
rotation.y = y + transform._hotspot.y * (transform._zoom.y / 100.0f);
|
|
|
|
Vector2 scale(transform._zoom.x / 100.0f, transform._zoom.y / 100.0f);
|
|
|
|
|
|
|
|
_renderer->drawSpriteEx(*this, rect, position, rotation, scale, transform._angle, transform._rgbaMod, transform._alphaDisable, transform._blendMode, transform.getMirrorX(), transform.getMirrorY());
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::displayZoom not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-05-21 19:43:38 +02:00
|
|
|
Vector2 scale(numTimesX, numTimesY);
|
2020-06-21 20:53:04 +02:00
|
|
|
_renderer->drawSpriteEx(*this, rect, Vector2(x, y), Vector2(0, 0), scale, 0, 0xFFFFFFFF, true, Graphics::BLEND_NORMAL, false, false);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::restore() {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::restore not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
|
2020-05-29 13:11:53 +02:00
|
|
|
BaseImage img = BaseImage();
|
2020-05-19 18:32:27 +02:00
|
|
|
if (!img.loadFile(filename)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-28 13:39:23 +02:00
|
|
|
if (img.getSurface()->format.bytesPerPixel == 1 && img.getPalette() == nullptr) {
|
2020-05-19 18:32:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
_filename = filename;
|
|
|
|
|
|
|
|
if (defaultCK) {
|
2020-05-29 13:11:53 +02:00
|
|
|
ckRed = 255;
|
2020-05-19 18:32:27 +02:00
|
|
|
ckGreen = 0;
|
2020-05-29 13:11:53 +02:00
|
|
|
ckBlue = 255;
|
2020-05-19 18:32:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_ckDefault = defaultCK;
|
|
|
|
_ckRed = ckRed;
|
|
|
|
_ckGreen = ckGreen;
|
|
|
|
_ckBlue = ckBlue;
|
|
|
|
|
2020-05-22 00:49:03 +02:00
|
|
|
bool needsColorKey = false;
|
|
|
|
bool replaceAlpha = true;
|
|
|
|
|
2020-09-28 18:37:37 +02:00
|
|
|
Graphics::Surface *surf = img.getSurface()->convertTo(OpenGL::TextureGL::getRGBAPixelFormat(), img.getPalette());
|
2020-05-22 00:49:03 +02:00
|
|
|
|
|
|
|
if (_filename.hasSuffix(".bmp") && img.getSurface()->format.bytesPerPixel == 4) {
|
|
|
|
// 32 bpp BMPs have nothing useful in their alpha-channel -> color-key
|
|
|
|
needsColorKey = true;
|
|
|
|
replaceAlpha = false;
|
|
|
|
} else if (img.getSurface()->format.aBits() == 0) {
|
|
|
|
needsColorKey = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needsColorKey) {
|
2020-06-12 15:29:28 +02:00
|
|
|
applyColorKey(*surf, ckRed, ckGreen, ckBlue, replaceAlpha);
|
2020-05-22 00:49:03 +02:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:31:34 +02:00
|
|
|
putSurface(*surf);
|
2020-06-16 00:17:43 +02:00
|
|
|
|
2020-06-30 19:12:10 +02:00
|
|
|
surf->free();
|
2020-05-22 00:49:03 +02:00
|
|
|
delete surf;
|
|
|
|
|
2020-05-19 18:32:27 +02:00
|
|
|
if (_lifeTime == 0 || lifeTime == -1 || lifeTime > _lifeTime) {
|
|
|
|
_lifeTime = lifeTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
_keepLoaded = keepLoaded;
|
|
|
|
if (_keepLoaded) {
|
|
|
|
_lifeTime = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_valid = true;
|
|
|
|
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::create(int width, int height) {
|
2020-06-16 00:17:43 +02:00
|
|
|
_width = width;
|
|
|
|
_height = height;
|
|
|
|
_texWidth = Common::nextHigher2(width);
|
|
|
|
_texHeight = Common::nextHigher2(height);
|
|
|
|
|
2020-06-25 23:09:04 +02:00
|
|
|
glGenTextures(1, &_tex);
|
2020-06-16 00:17:43 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _texWidth, _texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2020-05-19 18:32:27 +02:00
|
|
|
_valid = true;
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:31:34 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::putSurface(const Graphics::Surface &surface, bool hasAlpha) {
|
|
|
|
_width = surface.w;
|
|
|
|
_height = surface.h;
|
|
|
|
_texWidth = Common::nextHigher2(_width);
|
|
|
|
_texHeight = Common::nextHigher2(_height);
|
|
|
|
|
2020-06-25 23:09:04 +02:00
|
|
|
if (_valid) {
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
glGenTextures(1, &_tex);
|
2020-06-16 01:31:34 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _texWidth, _texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, surface.getPixels());
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2020-06-25 23:09:04 +02:00
|
|
|
_valid = true;
|
2020-06-16 01:31:34 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::putPixel(int x, int y, byte r, byte g, byte b, int a) {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::putPixel not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::getPixel not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::comparePixel(int x, int y, byte r, byte g, byte b, int a) {
|
2020-06-01 12:51:58 +02:00
|
|
|
warning("BaseSurfaceOpenGL3D::comparePixel not yet implemented");
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::startPixelOp() {
|
2020-06-12 14:25:30 +02:00
|
|
|
if (_imageData) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-12 14:25:30 +02:00
|
|
|
_imageData = new uint8[4 * _texWidth * _texHeight]();
|
2020-06-16 00:17:43 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
2020-06-12 14:25:30 +02:00
|
|
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, _imageData);
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::endPixelOp() {
|
2020-05-19 18:32:27 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2020-06-12 14:25:30 +02:00
|
|
|
delete[] _imageData;
|
|
|
|
_imageData = nullptr;
|
2020-05-19 16:23:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-01 12:42:14 +02:00
|
|
|
bool BaseSurfaceOpenGL3D::isTransparentAtLite(int x, int y) {
|
2020-06-16 00:17:43 +02:00
|
|
|
if (x < 0 || y < 0 || x >= _width || y >= _height) {
|
2020-05-19 18:32:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-12 14:25:30 +02:00
|
|
|
if (_imageData == nullptr) {
|
2020-05-19 18:32:27 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-12 14:25:30 +02:00
|
|
|
//TODO: Check for endianness issues
|
|
|
|
uint8 alpha = _imageData[y * _texWidth * 4 + x * 4 + 3];
|
|
|
|
return alpha == 0;
|
2020-05-19 16:23:53 +02:00
|
|
|
}
|
2020-06-01 12:42:14 +02:00
|
|
|
|
2020-06-05 02:55:16 +02:00
|
|
|
void BaseSurfaceOpenGL3D::setTexture() {
|
2020-06-25 23:09:04 +02:00
|
|
|
prepareToDraw();
|
|
|
|
|
2020-06-16 00:17:43 +02:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
2020-06-05 02:55:16 +02:00
|
|
|
}
|
|
|
|
|
2020-10-06 07:33:01 +02:00
|
|
|
} // End of namespace Wintermute
|
|
|
|
|
2020-10-10 14:12:07 +02:00
|
|
|
#endif // defined(USE_OPENGL_GAME) && !defined(USE_GLES2)
|