From 113961fd2a2203434b03766d722a0f8c0854bfd0 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Thu, 19 Jul 2012 19:29:15 +0200 Subject: WINTERMUTE: Change all folder-names to lowercase. --- engines/wintermute/base/gfx/base_image.cpp | 269 ++++++++ engines/wintermute/base/gfx/base_image.h | 74 +++ engines/wintermute/base/gfx/base_renderer.cpp | 257 ++++++++ engines/wintermute/base/gfx/base_renderer.h | 128 ++++ engines/wintermute/base/gfx/base_surface.cpp | 152 +++++ engines/wintermute/base/gfx/base_surface.h | 99 +++ .../base/gfx/osystem/base_render_osystem.cpp | 701 +++++++++++++++++++++ .../base/gfx/osystem/base_render_osystem.h | 129 ++++ .../base/gfx/osystem/base_surface_osystem.cpp | 532 ++++++++++++++++ .../base/gfx/osystem/base_surface_osystem.h | 101 +++ 10 files changed, 2442 insertions(+) create mode 100644 engines/wintermute/base/gfx/base_image.cpp create mode 100644 engines/wintermute/base/gfx/base_image.h create mode 100644 engines/wintermute/base/gfx/base_renderer.cpp create mode 100644 engines/wintermute/base/gfx/base_renderer.h create mode 100644 engines/wintermute/base/gfx/base_surface.cpp create mode 100644 engines/wintermute/base/gfx/base_surface.h create mode 100644 engines/wintermute/base/gfx/osystem/base_render_osystem.cpp create mode 100644 engines/wintermute/base/gfx/osystem/base_render_osystem.h create mode 100644 engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp create mode 100644 engines/wintermute/base/gfx/osystem/base_surface_osystem.h (limited to 'engines/wintermute/base/gfx') diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp new file mode 100644 index 0000000000..f1e27c9622 --- /dev/null +++ b/engines/wintermute/base/gfx/base_image.cpp @@ -0,0 +1,269 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/base/gfx/base_image.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/base/BFileManager.h" +#include "engines/wintermute/graphics/transparentSurface.h" +#include "engines/wintermute/utils/StringUtil.h" +#include "graphics/decoders/png.h" +#include "graphics/decoders/jpeg.h" +#include "graphics/decoders/bmp.h" +#include "graphics/surface.h" +#include "engines/wintermute/graphics/tga.h" +#include "common/textconsole.h" +#include "common/stream.h" +#include "common/system.h" + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////// +CBImage::CBImage(CBGame *inGame, FIBITMAP *bitmap): CBBase(inGame) { +#if 0 + _bitmap = bitmap; +#endif + _bitmap = NULL; + _palette = NULL; + _surface = NULL; + _decoder = NULL; + _deletableSurface = NULL; +} + + +////////////////////////////////////////////////////////////////////// +CBImage::~CBImage() { + /* delete _bitmap; */ + delete _decoder; + if (_deletableSurface) { + _deletableSurface->free(); + } + delete _deletableSurface; +#if 0 + if (_bitmap) FreeImage_Unload(_bitmap); +#endif +} + +bool CBImage::loadFile(const Common::String &filename) { + _filename = filename; + _filename.toLowercase(); + if (StringUtil::startsWith(filename, "savegame:", true)) { + _decoder = new Graphics::BitmapDecoder(); + } else if (_filename.hasSuffix(".png")) { + _decoder = new Graphics::PNGDecoder(); + } else if (_filename.hasSuffix(".bmp")) { + _decoder = new Graphics::BitmapDecoder(); + } else if (_filename.hasSuffix(".tga")) { + _decoder = new WinterMute::TGA(); + } else if (_filename.hasSuffix(".jpg")) { + _decoder = new Graphics::JPEGDecoder(); + } else { + error("CBImage::loadFile : Unsupported fileformat %s", filename.c_str()); + } + _filename = filename; + Common::SeekableReadStream *file = _gameRef->_fileManager->openFile(filename.c_str()); + if (!file) return STATUS_FAILED; + + _decoder->loadStream(*file); + _surface = _decoder->getSurface(); + _palette = _decoder->getPalette(); + _gameRef->_fileManager->closeFile(file); + + return STATUS_OK; +} + +byte CBImage::getAlphaAt(int x, int y) { + if (!_surface) return 0xFF; + uint32 color = *(uint32 *)_surface->getBasePtr(x, y); + byte r, g, b, a; + _surface->format.colorToARGB(color, a, r, g, b); + return a; +} + +void CBImage::copyFrom(Graphics::Surface *surface) { + _surface = _deletableSurface = new Graphics::Surface(); + _deletableSurface->copyFrom(*surface); +} + +////////////////////////////////////////////////////////////////////////// +bool CBImage::saveBMPFile(const char *filename) { +#if 0 + if (!_bitmap) return STATUS_FAILED; + + if (FreeImage_Save(FIF_BMP, _bitmap, filename)) return STATUS_OK; + else return STATUS_FAILED; +#endif + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBImage::resize(int newWidth, int newHeight) { +#if 0 + if (!_bitmap) return STATUS_FAILED; + + if (newWidth == 0) NewWidth = FreeImage_GetWidth(_bitmap); + if (newHeight == 0) NewHeight = FreeImage_GetHeight(_bitmap); + + + FIBITMAP *newImg = FreeImage_Rescale(_bitmap, NewWidth, NewHeight, FILTER_BILINEAR); + if (newImg) { + FreeImage_Unload(_bitmap); + _bitmap = newImg; + return STATUS_OK; + } else return STATUS_FAILED; +#endif + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBImage::writeBMPToStream(Common::WriteStream *stream) { + if (!_surface) return false; + + /* The following is just copied over and inverted to write-ops from the BMP-decoder */ + stream->writeByte('B'); + stream->writeByte('M'); + + /* Since we don't care during reads, we don't care during writes: */ + /* uint32 fileSize = */ + stream->writeUint32LE(54 + _surface->h * _surface->pitch); + /* uint16 res1 = */ + stream->writeUint16LE(0); + /* uint16 res2 = */ + stream->writeUint16LE(0); + const uint32 imageOffset = 54; + stream->writeUint32LE(imageOffset); + + const uint32 infoSize = 40; /* Windows v3 BMP */ + stream->writeUint32LE(infoSize); + + uint32 width = _surface->w; + int32 height = _surface->h; + stream->writeUint32LE(width); + stream->writeUint32LE((uint32)height); + + if (width == 0 || height == 0) + return false; + + if (height < 0) { + warning("Right-side up bitmaps not supported"); + return false; + } + + /* uint16 planes = */ stream->writeUint16LE(1); + const uint16 bitsPerPixel = 24; + stream->writeUint16LE(bitsPerPixel); + + const uint32 compression = 0; + stream->writeUint32LE(compression); + + /* uint32 imageSize = */ + stream->writeUint32LE(_surface->h * _surface->pitch); + /* uint32 pixelsPerMeterX = */ + stream->writeUint32LE(0); + /* uint32 pixelsPerMeterY = */ + stream->writeUint32LE(0); + const uint32 paletteColorCount = 0; + stream->writeUint32LE(paletteColorCount); + /* uint32 colorsImportant = */ + stream->writeUint32LE(0); + + // Start us at the beginning of the image (54 bytes in) + Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); + + // BGRA for 24bpp + if (bitsPerPixel == 24) + format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); + + Graphics::Surface *surface = _surface->convertTo(format); + + int srcPitch = width * (bitsPerPixel >> 3); + const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; + + for (int32 i = height - 1; i >= 0; i--) { + for (uint32 j = 0; j < width; j++) { + byte b, g, r; + uint32 color = *(uint32 *)surface->getBasePtr(j, i); + surface->format.colorToRGB(color, r, g, b); + stream->writeByte(b); + stream->writeByte(g); + stream->writeByte(r); + } + + for (int k = 0; k < extraDataLength; k++) { + stream->writeByte(0); + } + } + surface->free(); + delete surface; + return true; + + //*BufferSize = 0; +#if 0 + FIMEMORY *fiMem = FreeImage_OpenMemory(); + FreeImage_SaveToMemory(FIF_PNG, _bitmap, fiMem); + uint32 size; + byte *data; + FreeImage_AcquireMemory(fiMem, &data, &size); + + + byte *Buffer = new byte[size]; + memcpy(Buffer, data, size); + + FreeImage_CloseMemory(fiMem); + + if (BufferSize) *BufferSize = size; + + return Buffer; +#endif + return false; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBImage::copyFrom(CBImage *origImage, int newWidth, int newHeight) { +#if 0 + if (_bitmap) FreeImage_Unload(_bitmap); + + if (NewWidth == 0) NewWidth = FreeImage_GetWidth(OrigImage->GetBitmap()); + if (NewHeight == 0) NewHeight = FreeImage_GetHeight(OrigImage->GetBitmap()); + + _bitmap = FreeImage_Rescale(OrigImage->GetBitmap(), NewWidth, NewHeight, FILTER_BILINEAR); +#endif + TransparentSurface temp(*origImage->_surface, false); + if (_deletableSurface) { + _deletableSurface->free(); + delete _deletableSurface; + _deletableSurface = NULL; + } + _surface = _deletableSurface = temp.scale(newWidth, newHeight); + return STATUS_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/gfx/base_image.h b/engines/wintermute/base/gfx/base_image.h new file mode 100644 index 0000000000..646a9ddd2d --- /dev/null +++ b/engines/wintermute/base/gfx/base_image.h @@ -0,0 +1,74 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BIMAGE_H +#define WINTERMUTE_BIMAGE_H + +#include "engines/wintermute/base/BBase.h" +#include "graphics/surface.h" +#include "graphics/pixelformat.h" +#include "graphics/decoders/image_decoder.h" +#include "common/endian.h" +#include "common/str.h" +#include "common/stream.h" + +struct FIBITMAP; + +namespace WinterMute { +class CBSurface; +class CBImage: CBBase { + +public: + CBImage(CBGame *inGame, FIBITMAP *bitmap = NULL); + ~CBImage(); + + bool loadFile(const Common::String &filename); + const Graphics::Surface *getSurface() const { + return _surface; + }; + const byte *getPalette() const { + return _palette; + } + byte getAlphaAt(int x, int y); + bool writeBMPToStream(Common::WriteStream *stream); + bool resize(int newWidth, int newHeight); + bool saveBMPFile(const char *filename); + bool copyFrom(CBImage *origImage, int newWidth = 0, int newHeight = 0); + void copyFrom(Graphics::Surface *surface); +private: + Common::String _filename; + Graphics::ImageDecoder *_decoder; + FIBITMAP *_bitmap; + const Graphics::Surface *_surface; + Graphics::Surface *_deletableSurface; + const byte *_palette; +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/base/gfx/base_renderer.cpp b/engines/wintermute/base/gfx/base_renderer.cpp new file mode 100644 index 0000000000..010aca7141 --- /dev/null +++ b/engines/wintermute/base/gfx/base_renderer.cpp @@ -0,0 +1,257 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/base/BActiveRect.h" +#include "engines/wintermute/base/gfx/base_renderer.h" +#include "engines/wintermute/base/gfx/base_surface.h" +#include "engines/wintermute/base/BSubFrame.h" +#include "engines/wintermute/base/BRegion.h" +#include "engines/wintermute/PlatformSDL.h" + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////// +CBRenderer::CBRenderer(CBGame *inGame): CBBase(inGame) { + _window = 0; + _clipperWindow = 0; + _active = false; + _ready = false; + _windowed = true; + _forceAlphaColor = 0x00; + + _width = _height = _bPP = 0; + CBPlatform::setRectEmpty(&_monitorRect); + + _realWidth = _realHeight = 0; + _drawOffsetX = _drawOffsetY = 0; +} + + +////////////////////////////////////////////////////////////////////// +CBRenderer::~CBRenderer() { + deleteRectList(); + unclipCursor(); +} + + +////////////////////////////////////////////////////////////////////// +void CBRenderer::initLoop() { + deleteRectList(); +} + + +////////////////////////////////////////////////////////////////////// +CBObject *CBRenderer::getObjectAt(int x, int y) { + Point32 point; + point.x = x; + point.y = y; + + for (int i = _rectList.getSize() - 1; i >= 0; i--) { + if (CBPlatform::ptInRect(&_rectList[i]->_rect, point)) { + if (_rectList[i]->_precise) { + // frame + if (_rectList[i]->_frame) { + int xx = (int)((_rectList[i]->_frame->_rect.left + x - _rectList[i]->_rect.left + _rectList[i]->_offsetX) / (float)((float)_rectList[i]->_zoomX / (float)100)); + int yy = (int)((_rectList[i]->_frame->_rect.top + y - _rectList[i]->_rect.top + _rectList[i]->_offsetY) / (float)((float)_rectList[i]->_zoomY / (float)100)); + + if (_rectList[i]->_frame->_mirrorX) { + int width = _rectList[i]->_frame->_rect.right - _rectList[i]->_frame->_rect.left; + xx = width - xx; + } + + if (_rectList[i]->_frame->_mirrorY) { + int height = _rectList[i]->_frame->_rect.bottom - _rectList[i]->_frame->_rect.top; + yy = height - yy; + } + + if (!_rectList[i]->_frame->_surface->isTransparentAt(xx, yy)) return _rectList[i]->_owner; + } + // region + else if (_rectList[i]->_region) { + if (_rectList[i]->_region->pointInRegion(x + _rectList[i]->_offsetX, y + _rectList[i]->_offsetY)) return _rectList[i]->_owner; + } + } else return _rectList[i]->_owner; + } + } + + return (CBObject *)NULL; +} + + +////////////////////////////////////////////////////////////////////////// +void CBRenderer::deleteRectList() { + for (int i = 0; i < _rectList.getSize(); i++) { + delete _rectList[i]; + } + _rectList.removeAll(); +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +bool CBRenderer::switchFullscreen() { + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////// +bool CBRenderer::flip() { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////// +bool CBRenderer::initRenderer(int width, int height, bool windowed) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////// +void CBRenderer::onWindowChange() { +} + + +////////////////////////////////////////////////////////////////////// +bool CBRenderer::fill(byte r, byte g, byte b, Common::Rect *rect) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::windowedBlt() { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::setup2D(bool Force) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::setupLines() { + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::drawLine(int x1, int y1, int x2, int y2, uint32 color) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::drawRect(int x1, int y1, int x2, int y2, uint32 color, int width) { + for (int i = 0; i < width; i++) { + drawLine(x1 + i, y1 + i, x2 - i, y1 + i, color); // up + drawLine(x1 + i, y2 - i, x2 - i + 1, y2 - i, color); // down + + drawLine(x1 + i, y1 + i, x1 + i, y2 - i, color); // left + drawLine(x2 - i, y1 + i, x2 - i, y2 - i + 1, color); // right + } + return STATUS_OK; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::fade(uint16 alpha) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::fadeToColor(uint32 color, Common::Rect *rect) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::setViewport(int left, int top, int right, int bottom) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::setScreenViewport() { + return setViewport(_drawOffsetX, _drawOffsetY, _width + _drawOffsetX, _height + _drawOffsetY); +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::setViewport(Rect32 *rect) { + return setViewport(rect->left + _drawOffsetX, + rect->top + _drawOffsetY, + rect->right + _drawOffsetX, + rect->bottom + _drawOffsetY); +} + + +////////////////////////////////////////////////////////////////////////// +CBImage *CBRenderer::takeScreenshot() { + return NULL; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::clipCursor() { + /* + if (!_windowed) { + Rect32 rc; + GetWindowRect(_window, &rc); + + // if "maintain aspect ratio" is in effect, lock mouse to visible area + rc.left = _drawOffsetX; + rc.top = _drawOffsetY; + rc.right = rc.left + _width; + rc.bottom = rc.top + _height; + + ::ClipCursor(&rc); + } + */ + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::unclipCursor() { + /* + if (!_windowed) ::ClipCursor(NULL); + */ + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderer::pointInViewport(Point32 *p) { + if (p->x < _drawOffsetX) return false; + if (p->y < _drawOffsetY) return false; + if (p->x > _drawOffsetX + _width) return false; + if (p->y > _drawOffsetY + _height) return false; + + return true; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h new file mode 100644 index 0000000000..81c13f8b39 --- /dev/null +++ b/engines/wintermute/base/gfx/base_renderer.h @@ -0,0 +1,128 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BRENDERER_H +#define WINTERMUTE_BRENDERER_H + + +#include "engines/wintermute/coll_templ.h" +#include "engines/wintermute/base/BBase.h" +#include "common/rect.h" + +namespace WinterMute { + +class CBImage; +class CBActiveRect; +class CBObject; +class CBSurface; +class CBRenderer: public CBBase { +public: + int _realWidth; + int _realHeight; + int _drawOffsetX; + int _drawOffsetY; + + virtual void dumpData(const char *filename) {}; + virtual CBImage *takeScreenshot(); + virtual bool setViewport(int left, int top, int right, int bottom); + virtual bool setViewport(Rect32 *Rect); + virtual bool setScreenViewport(); + virtual bool fade(uint16 Alpha); + virtual bool fadeToColor(uint32 Color, Common::Rect *rect = NULL); + virtual bool drawLine(int x1, int y1, int x2, int y2, uint32 color); + virtual bool drawRect(int x1, int y1, int x2, int y2, uint32 color, int width = 1); + CBRenderer(CBGame *inGame = NULL); + virtual ~CBRenderer(); + virtual bool setProjection() { + return STATUS_OK; + }; + + virtual bool windowedBlt(); + virtual bool fill(byte r, byte g, byte b, Common::Rect *rect = NULL); + virtual void onWindowChange(); + virtual bool initRenderer(int width, int height, bool windowed); + virtual bool flip(); + virtual void initLoop(); + virtual bool switchFullscreen(); + virtual bool setup2D(bool force = false); + virtual bool setupLines(); + + virtual const char *getName() { + return ""; + }; + virtual bool displayDebugInfo() { + return STATUS_FAILED; + }; + virtual bool drawShaderQuad() { + return STATUS_FAILED; + } + + virtual float getScaleRatioX() const { + return 1.0f; + } + virtual float getScaleRatioY() const { + return 1.0f; + } + + virtual CBSurface *createSurface() = 0; + + bool clipCursor(); + bool unclipCursor(); + + CBObject *getObjectAt(int x, int y); + void deleteRectList(); + + virtual bool startSpriteBatch() { + return STATUS_OK; + }; + virtual bool endSpriteBatch() { + return STATUS_OK; + }; + bool pointInViewport(Point32 *P); + uint32 _forceAlphaColor; + uint32 _window; + uint32 _clipperWindow; + bool _active; + bool _ready; + bool _windowed; + Rect32 _windowRect; + Rect32 _viewportRect; + Rect32 _screenRect; + Rect32 _monitorRect; + int _bPP; + int _height; + int _width; + + CBArray _rectList; +}; + +CBRenderer *makeOSystemRenderer(CBGame *inGame); // Implemented in BRenderSDL.cpp + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp new file mode 100644 index 0000000000..6c0ca40765 --- /dev/null +++ b/engines/wintermute/base/gfx/base_surface.cpp @@ -0,0 +1,152 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/wintypes.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/base/gfx/base_surface.h" + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////// +CBSurface::CBSurface(CBGame *inGame): CBBase(inGame) { + _referenceCount = 0; + + _width = _height = 0; + + _filename = ""; + + _pixelOpReady = false; + + _ckDefault = true; + _ckRed = _ckGreen = _ckBlue = 0; + _lifeTime = 0; + _keepLoaded = false; + + _lastUsedTime = 0; + _valid = false; +} + + +////////////////////////////////////////////////////////////////////// +CBSurface::~CBSurface() { + if (_pixelOpReady) endPixelOp(); +} + + +////////////////////////////////////////////////////////////////////// +bool CBSurface::create(const char *filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////// +bool CBSurface::restore() { + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////// +bool CBSurface::isTransparentAt(int x, int y) { + return false; +} + +////////////////////////////////////////////////////////////////////// +bool CBSurface::displayHalfTrans(int x, int y, Rect32 rect) { + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return displayTransZoom(x, y, rect, zoomX, zoomY, alpha, blendMode, mirrorX, mirrorY); +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::create(int Width, int Height) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::startPixelOp() { + return STATUS_FAILED; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::endPixelOp() { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::putPixel(int x, int y, byte r, byte g, byte b, int a) { + return STATUS_FAILED; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::comparePixel(int x, int y, byte r, byte g, byte b, int a) { + return false; +} + + +////////////////////////////////////////////////////////////////////// +bool CBSurface::isTransparentAtLite(int x, int y) { + return false; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::invalidate() { + return STATUS_FAILED; +} + + + +////////////////////////////////////////////////////////////////////////// +bool CBSurface::prepareToDraw() { + _lastUsedTime = _gameRef->_liveTimer; + + if (!_valid) { + //_gameRef->LOG(0, "Reviving: %s", _filename); + return create(_filename.c_str(), _ckDefault, _ckRed, _ckGreen, _ckBlue, _lifeTime, _keepLoaded); + } else return STATUS_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CBSurface::setSize(int width, int height) { + _width = width; + _height = height; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h new file mode 100644 index 0000000000..f5fbd495aa --- /dev/null +++ b/engines/wintermute/base/gfx/base_surface.h @@ -0,0 +1,99 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BSURFACE_H +#define WINTERMUTE_BSURFACE_H + +#include "engines/wintermute/base/BBase.h" +#include "engines/wintermute/math/Rect32.h" +#include "graphics/surface.h" + +namespace WinterMute { + +class CBSurface: public CBBase { +public: + virtual bool invalidate(); + virtual bool prepareToDraw(); + bool _ckDefault; + byte _ckRed; + byte _ckGreen; + byte _ckBlue; + + uint32 _lastUsedTime; + bool _valid; + int _lifeTime; + bool _keepLoaded; + + bool _pixelOpReady; + CBSurface(CBGame *inGame); + virtual ~CBSurface(); + + virtual bool displayHalfTrans(int x, int y, Rect32 rect); + virtual bool isTransparentAt(int x, int y); + virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0; + virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool MirrorY = false) = 0; + virtual bool displayZoom(int x, int y, Rect32 rect, float ZoomX, float ZoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool restore(); + virtual bool create(const char *filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0; + virtual bool create(int Width, int Height); + virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) { + return STATUS_FAILED; + } + virtual bool putPixel(int x, int y, byte r, byte g, byte b, int a = -1); + virtual bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a = NULL); + virtual bool comparePixel(int x, int y, byte r, byte g, byte b, int a = -1); + virtual bool startPixelOp(); + virtual bool endPixelOp(); + virtual bool isTransparentAtLite(int x, int y); + void setSize(int width, int height); + + int _referenceCount; + + virtual int getWidth() { + return _width; + } + virtual int getHeight() { + return _height; + } + Common::String getFileNameStr() { return _filename; } + const char* getFileName() { return _filename.c_str(); } + //void SetWidth(int Width){ _width = Width; } + //void SetHeight(int Height){ _height = Height; } +protected: + Common::String _filename; + int _height; + int _width; + +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp new file mode 100644 index 0000000000..fc971357bf --- /dev/null +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -0,0 +1,701 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/dcgf.h" +#include "engines/wintermute/base/gfx/osystem/base_render_osystem.h" +#include "engines/wintermute/base/BRegistry.h" +#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" +#include "engines/wintermute/base/BSurfaceStorage.h" +#include "engines/wintermute/base/gfx/base_image.h" +#include "engines/wintermute/math/MathUtil.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/base/BSprite.h" +#include "common/system.h" +#include "engines/wintermute/graphics/transparentSurface.h" +#include "common/queue.h" + +namespace WinterMute { + +RenderTicket::RenderTicket(CBSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY) : _owner(owner), + _srcRect(*srcRect), _dstRect(*dstRect), _drawNum(0), _isValid(true), _wantsDraw(true), _hasAlpha(true) { + _colorMod = 0; + _mirror = TransparentSurface::FLIP_NONE; + if (mirrorX) + _mirror |= TransparentSurface::FLIP_V; + if (mirrorY) + _mirror |= TransparentSurface::FLIP_H; + if (surf) { + _surface = new Graphics::Surface(); + _surface->create((uint16)srcRect->width(), (uint16)srcRect->height(), surf->format); + assert(_surface->format.bytesPerPixel == 4); + // Get a clipped copy of the surface + for (int i = 0; i < _surface->h; i++) { + memcpy(_surface->getBasePtr(0, i), surf->getBasePtr(srcRect->left, srcRect->top + i), srcRect->width() * _surface->format.bytesPerPixel); + } + // Then scale it if necessary + if (dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) { + TransparentSurface src(*_surface, false); + Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height()); + _surface->free(); + delete _surface; + _surface = temp; + } + } else { + _surface = NULL; + } +} + +RenderTicket::~RenderTicket() { + if (_surface) { + _surface->free(); + delete _surface; + } +} + +bool RenderTicket::operator==(RenderTicket &t) { + if ((t._srcRect != _srcRect) || + (t._dstRect != _dstRect) || + (t._mirror != _mirror) || + (t._owner != _owner) || + (t._hasAlpha != _hasAlpha) || + (t._colorMod != _colorMod)) { + return false; + } + return true; +} + +CBRenderer *makeOSystemRenderer(CBGame *inGame) { + return new CBRenderOSystem(inGame); +} + +// TODO: Redo everything here. + +////////////////////////////////////////////////////////////////////////// +CBRenderOSystem::CBRenderOSystem(CBGame *inGame) : CBRenderer(inGame) { + _renderSurface = new Graphics::Surface(); + _drawNum = 1; + _needsFlip = true; + + _borderLeft = _borderRight = _borderTop = _borderBottom = 0; + _ratioX = _ratioY = 1.0f; + setAlphaMod(255); + setColorMod(255, 255, 255); + _dirtyRect = NULL; + _disableDirtyRects = true; +} + +////////////////////////////////////////////////////////////////////////// +CBRenderOSystem::~CBRenderOSystem() { + _renderSurface->free(); + delete _renderSurface; +#if 0 + if (_renderer) SDL_DestroyRenderer(_renderer); + if (_win) SDL_DestroyWindow(_win); + SDL_Quit(); +#endif +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::initRenderer(int width, int height, bool windowed) { + //if (SDL_Init(SDL_INIT_VIDEO) < 0) return STATUS_FAILED; + +#if 0 + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 1); +#endif + _width = width; + _height = height; + _renderRect.setWidth(_width); + _renderRect.setHeight(_height); + + _realWidth = width; + _realHeight = height; + + + // find suitable resolution +/*#ifdef __IPHONEOS__ + _realWidth = 480; + _realHeight = 320; + + int numModes = SDL_GetNumDisplayModes(0); + for (int i = 0; i < numModes; i++) { + SDL_DisplayMode mode; + SDL_GetDisplayMode(0, i, &mode); + + if (mode.w > mode.h) { + _realWidth = mode.w; + _realHeight = mode.h; + break; + } + } +#else*/ + _realWidth = _gameRef->_registry->readInt("Debug", "ForceResWidth", _width); + _realHeight = _gameRef->_registry->readInt("Debug", "ForceResHeight", _height); +//#endif + + /* + _realWidth = 480; + _realHeight = 320; + */ + + + float origAspect = (float)_width / (float)_height; + float realAspect = (float)_realWidth / (float)_realHeight; + + float ratio; + if (origAspect < realAspect) { + // normal to wide + ratio = (float)_realHeight / (float)_height; + } else { + // wide to normal + ratio = (float)_realWidth / (float)_width; + } + + _borderLeft = (int)((_realWidth - (_width * ratio)) / 2); + _borderRight = (int)(_realWidth - (_width * ratio) - _borderLeft); + + _borderTop = (int)((_realHeight - (_height * ratio)) / 2); + _borderBottom = (int)(_realHeight - (_height * ratio) - _borderTop); + + + + _ratioX = (float)(_realWidth - _borderLeft - _borderRight) / (float)_width; + _ratioY = (float)(_realHeight - _borderTop - _borderBottom) / (float)_height; + +#if 0 + Uint32 flags = SDL_WINDOW_SHOWN; +#endif +#ifdef __IPHONEOS__ + //flags |= SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS; +#endif + + //_windowed = _gameRef->_registry->readBool("Video", "Windowed", true); +// if (!windowed) flags |= SDL_WINDOW_FULLSCREEN; + + Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); + g_system->beginGFXTransaction(); + g_system->initSize(_width, _height, &format); + OSystem::TransactionError gfxError = g_system->endGFXTransaction(); + + if (gfxError != OSystem::kTransactionSuccess) { + warning("Couldn't setup GFX-backend for %dx%dx%d", _width, _height, format.bytesPerPixel * 8); + return STATUS_FAILED; + } +#if 0 + _win = SDL_CreateWindow("WME Lite", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + _realWidth, _realHeight, + flags); + + if (!_win) return STATUS_FAILED; +#endif + + g_system->showMouse(false); + +#ifdef __IPHONEOS__ + // SDL defaults to OGL ES2, which doesn't work on old devices + //SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles"); +#else + //SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +#endif +#if 0 + _renderer = SDL_CreateRenderer(_win, -1, 0); + + if (!_renderer) return STATUS_FAILED; +#endif + _renderSurface->create(g_system->getWidth(), g_system->getHeight(), g_system->getScreenFormat()); + _active = true; + + _clearColor = _renderSurface->format.ARGBToColor(255, 0, 0, 0); + + return STATUS_OK; +} + +void CBRenderOSystem::setAlphaMod(byte alpha) { + byte r = RGBCOLGetR(_colorMod); + byte g = RGBCOLGetB(_colorMod); + byte b = RGBCOLGetB(_colorMod); + _colorMod = BS_ARGB(alpha, r, g, b); +} + +void CBRenderOSystem::setColorMod(byte r, byte g, byte b) { + byte alpha = RGBCOLGetA(_colorMod); + _colorMod = BS_ARGB(alpha, r, g, b); +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::flip() { + if (!_disableDirtyRects) { + drawTickets(); + } + if (_needsFlip || _disableDirtyRects) { + if (_disableDirtyRects) { + g_system->copyRectToScreen((byte *)_renderSurface->pixels, _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h); + } + // g_system->copyRectToScreen((byte *)_renderSurface->pixels, _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); + delete _dirtyRect; + _dirtyRect = NULL; + g_system->updateScreen(); + _needsFlip = false; + } + _drawNum = 1; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::fill(byte r, byte g, byte b, Common::Rect *rect) { + //SDL_SetRenderDrawColor(_renderer, r, g, b, 0xFF); + //SDL_RenderClear(_renderer); + _clearColor = _renderSurface->format.ARGBToColor(0xFF, r, g, b); + if (!_disableDirtyRects) + return STATUS_OK; + if (!rect) { + rect = &_renderRect; + } + _renderSurface->fillRect(*rect, _clearColor); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::fade(uint16 Alpha) { + uint32 dwAlpha = 255 - Alpha; + return fadeToColor(dwAlpha << 24); +} + + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::fadeToColor(uint32 Color, Common::Rect *rect) { + // This particular warning is rather messy, as this function is called a ton, + // thus we avoid printing it more than once. + static bool hasWarned = false; + if (!hasWarned) { + warning("CBRenderOSystem::FadeToColor - Breaks when using dirty rects"); + warning("Implement CBRenderOSystem::FadeToColor"); // TODO. + hasWarned = true; + } + + Common::Rect fillRect; + + if (rect) { + fillRect.left = rect->left; + fillRect.top = rect->top; + fillRect.setWidth(rect->width()); + fillRect.setHeight(rect->height()); + } else { + Rect32 rc; + _gameRef->getCurrentViewportRect(&rc); + fillRect.left = (int16)rc.left; + fillRect.top = (int16)rc.top; + fillRect.setWidth((int16)(rc.right - rc.left)); + fillRect.setHeight((int16)(rc.bottom - rc.top)); + } + modTargetRect(&fillRect); + + byte r = RGBCOLGetR(Color); + byte g = RGBCOLGetG(Color); + byte b = RGBCOLGetB(Color); + byte a = RGBCOLGetA(Color); + + //TODO: This is only here until I'm sure about the final pixelformat + uint32 col = _renderSurface->format.ARGBToColor(a, r, g, b); + if (_disableDirtyRects) + _renderSurface->fillRect(fillRect, col); + else { + setAlphaMod(a); + setColorMod(r, g, b); + Graphics::Surface surf; + surf.create((uint16)fillRect.width(), (uint16)fillRect.height(), _renderSurface->format); + Common::Rect sizeRect(fillRect); + sizeRect.translate(-fillRect.top, -fillRect.left); + surf.fillRect(fillRect, col); + drawSurface(NULL, &surf, &sizeRect, &fillRect, false, false); + surf.free(); + _clearColor = col; + } + //SDL_SetRenderDrawColor(_renderer, r, g, b, a); + //SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND); + //SDL_RenderFillRect(_renderer, &fillRect); + + return STATUS_OK; +} + +void CBRenderOSystem::drawSurface(CBSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY) { + if (_disableDirtyRects) { + RenderTicket renderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY); + // HINT: The surface-data contains other info than it should. + // drawFromSurface(renderTicket._surface, srcRect, dstRect, NULL, mirrorX, mirrorY); + drawFromSurface(renderTicket._surface, &renderTicket._srcRect, &renderTicket._dstRect, NULL, renderTicket._mirror); + return; + } + // Skip rects that are completely outside the screen: + if ((dstRect->left < 0 && dstRect->right < 0) || (dstRect->top < 0 && dstRect->bottom < 0)) { + return; + } + + RenderTicket compare(owner, NULL, srcRect, dstRect, mirrorX, mirrorY); + compare._colorMod = _colorMod; + RenderQueueIterator it; + for (it = _renderQueue.begin(); it != _renderQueue.end(); it++) { + if ((*it)->_owner == owner && *(*it) == compare && (*it)->_isValid) { + (*it)->_colorMod = _colorMod; + drawFromTicket(*it); + return; + } + } + RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, mirrorX, mirrorY); + ticket->_colorMod = _colorMod; + drawFromTicket(ticket); +} + +void CBRenderOSystem::invalidateTicket(RenderTicket *renderTicket) { + addDirtyRect(renderTicket->_dstRect); + renderTicket->_isValid = false; +// renderTicket->_canDelete = true; // TODO: Maybe readd this, to avoid even more duplicates. +} + +void CBRenderOSystem::invalidateTicketsFromSurface(CBSurfaceOSystem *surf) { + RenderQueueIterator it; + for (it = _renderQueue.begin(); it != _renderQueue.end(); it++) { + if ((*it)->_owner == surf) { + invalidateTicket(*it); + } + } +} + +void CBRenderOSystem::drawFromTicket(RenderTicket *renderTicket) { + renderTicket->_wantsDraw = true; + // A new item always has _drawNum == 0 + if (renderTicket->_drawNum == 0) { + // In-order + if (_renderQueue.empty() || _drawNum > (_renderQueue.back())->_drawNum) { + renderTicket->_drawNum = _drawNum++; + _renderQueue.push_back(renderTicket); + addDirtyRect(renderTicket->_dstRect); + } else { + // Before something + Common::List::iterator pos; + for (pos = _renderQueue.begin(); pos != _renderQueue.end(); pos++) { + if ((*pos)->_drawNum >= _drawNum) { + break; + } + } + _renderQueue.insert(pos, renderTicket); + Common::List::iterator it; + renderTicket->_drawNum = _drawNum++; + // Increment the following tickets, so they still are in line + for (it = pos; it != _renderQueue.end(); it++) { + (*it)->_drawNum++; + (*it)->_wantsDraw = false; + } + addDirtyRect(renderTicket->_dstRect); + } + } else { + // Was drawn last round, still in the same order + if (_drawNum == renderTicket->_drawNum) { + _drawNum++; + } else { + // Remove the ticket from the list + RenderQueueIterator it = _renderQueue.begin(); + while (it != _renderQueue.end()) { + if ((*it) == renderTicket) { + it = _renderQueue.erase(it); + break; + } else { + it++; + } + } + // Is not in order, so readd it as if it was a new ticket + renderTicket->_drawNum = 0; + drawFromTicket(renderTicket); + } + } +} + +void CBRenderOSystem::addDirtyRect(const Common::Rect &rect) { + if (!_dirtyRect) { + _dirtyRect = new Common::Rect(rect); + } else { + _dirtyRect->extend(rect); + } + _dirtyRect->clip(_renderRect); +// warning("AddDirtyRect: %d %d %d %d", rect.left, rect.top, rect.right, rect.bottom); +} + +void CBRenderOSystem::drawTickets() { + RenderQueueIterator it = _renderQueue.begin(); + // Clean out the old tickets + int decrement = 0; + while (it != _renderQueue.end()) { + if ((*it)->_wantsDraw == false || (*it)->_isValid == false) { + RenderTicket* ticket = *it; + addDirtyRect((*it)->_dstRect); + //warning("Discarding Rect: %d %d %d %d Width: %d Height: %d", (*it)->_dstRect.left, (*it)->_dstRect.top, (*it)->_dstRect.right, (*it)->_dstRect.bottom, (*it)->_dstRect.width() , (*it)->_dstRect.height()); + it = _renderQueue.erase(it); + delete ticket; + decrement++; + } else { + (*it)->_drawNum -= decrement; + it++; + } + } + if (!_dirtyRect || _dirtyRect->width() == 0 || _dirtyRect->height() == 0) + return; + // The color-mods are stored in the RenderTickets on add, since we set that state again during + // draw, we need to keep track of what it was prior to draw. + uint32 oldColorMod = _colorMod; +// warning("DirtyRect: %d %d %d %d Width: %d Height: %d", _dirtyRect->left, _dirtyRect->top, _dirtyRect->right, _dirtyRect->bottom, _dirtyRect->width(), _dirtyRect->height()); + + // Apply the clear-color to the dirty rect. + _renderSurface->fillRect(*_dirtyRect, _clearColor); + for (it = _renderQueue.begin(); it != _renderQueue.end(); it++) { + RenderTicket *ticket = *it; + if (ticket->_isValid && ticket->_dstRect.intersects(*_dirtyRect)) { + // dstClip is the area we want redrawn. + Common::Rect dstClip(ticket->_dstRect); + // reduce it to the dirty rect + dstClip.clip(*_dirtyRect); + // we need to keep track of the position to redraw the dirty rect + Common::Rect pos(dstClip); + int16 offsetX = ticket->_dstRect.left; + int16 offsetY = ticket->_dstRect.top; + // convert from screen-coords to surface-coords. + dstClip.translate(-offsetX, -offsetY); + + _colorMod = ticket->_colorMod; + drawFromSurface(ticket->_surface, &ticket->_srcRect, &pos, &dstClip, ticket->_mirror); + _needsFlip = true; + } + // Some tickets want redraw but don't actually clip the dirty area (typically the ones that shouldnt become clear-color) + ticket->_wantsDraw = false; + } + g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_dirtyRect->left, _dirtyRect->top), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height()); + + // Revert the colorMod-state. + _colorMod = oldColorMod; +} + +// Replacement for SDL2's SDL_RenderCopy +void CBRenderOSystem::drawFromSurface(const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Common::Rect *clipRect, uint32 mirror) { + TransparentSurface src(*surf, false); + bool doDelete = false; + if (!clipRect) { + doDelete = true; + clipRect = new Common::Rect(); + clipRect->setWidth(surf->w); + clipRect->setHeight(surf->h); + } + + src.blit(*_renderSurface, dstRect->left, dstRect->top, mirror, clipRect, _colorMod, clipRect->width(), clipRect->height()); + if (doDelete) + delete clipRect; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::drawLine(int x1, int y1, int x2, int y2, uint32 color) { + static bool hasWarned = false; + if (!hasWarned) { + warning("CBRenderOSystem::DrawLine - not fully ported yet"); + hasWarned = true; + } + byte r = RGBCOLGetR(color); + byte g = RGBCOLGetG(color); + byte b = RGBCOLGetB(color); + byte a = RGBCOLGetA(color); + + //SDL_SetRenderDrawColor(_renderer, r, g, b, a); + //SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND); + + Point32 point1, point2; + point1.x = x1; + point1.y = y1; + pointToScreen(&point1); + + point2.x = x2; + point2.y = y2; + pointToScreen(&point2); + + // TODO: This thing is mostly here until I'm sure about the final color-format. + uint32 colorVal = _renderSurface->format.ARGBToColor(a, r, g, b); + _renderSurface->drawLine(point1.x, point1.y, point2.x, point2.y, colorVal); + //SDL_RenderDrawLine(_renderer, point1.x, point1.y, point2.x, point2.y); + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +CBImage *CBRenderOSystem::takeScreenshot() { +// TODO: Fix this + warning("CBRenderOSystem::TakeScreenshot() - not ported yet"); + CBImage *screenshot = new CBImage(_gameRef); + screenshot->copyFrom(_renderSurface); + return screenshot; +#if 0 + SDL_Rect viewport; + + SDL_RenderGetViewport(_renderer, &viewport); + + SDL_Surface *surface = SDL_CreateRGBSurface(0, viewport.w, viewport.h, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0x00000000); + if (!surface) return NULL; + + if (SDL_RenderReadPixels(_renderer, NULL, surface->format->format, surface->pixels, surface->pitch) < 0) return NULL; + + FIBITMAP *dib = FreeImage_Allocate(viewport.w, viewport.h, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + + int bytespp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib); + + for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { + byte *bits = FreeImage_GetScanLine(dib, y); + byte *src = (byte *)surface->pixels + (viewport.h - y - 1) * surface->pitch; + memcpy(bits, src, bytespp * viewport.w); + } + + return new CBImage(_gameRef, dib); +#endif + return NULL; +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::switchFullscreen() { + /*if (_windowed) SDL_SetWindowFullscreen(_win, SDL_TRUE); + else SDL_SetWindowFullscreen(_win, SDL_FALSE); + + _windowed = !_windowed; + */ + _gameRef->_registry->writeBool("Video", "Windowed", _windowed); + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +const char *CBRenderOSystem::getName() { + if (_name.empty()) { +#if 0 + if (_renderer) { + SDL_RendererInfo info; + SDL_GetRendererInfo(_renderer, &info); + _name = AnsiString(info.name); + } +#endif + } + return _name.c_str(); +} + +////////////////////////////////////////////////////////////////////////// +bool CBRenderOSystem::setViewport(int left, int top, int right, int bottom) { + Common::Rect rect; + // TODO: Hopefully this is the same logic that ScummVM uses. + rect.left = (int16)(left + _borderLeft); + rect.top = (int16)(top + _borderTop); + rect.right = (int16)((right - left) * _ratioX); + rect.bottom = (int16)((bottom - top) * _ratioY); + + // TODO fix this once viewports work correctly in SDL/landscape +#ifndef __IPHONEOS__ + //SDL_RenderSetViewport(GetSdlRenderer(), &rect); +#endif + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +void CBRenderOSystem::modTargetRect(Common::Rect *rect) { +#if 0 + SDL_Rect viewportRect; + SDL_RenderGetViewport(GetSdlRenderer(), &viewportRect); + + rect->x = MathUtil::Round(rect->x * _ratioX + _borderLeft - viewportRect.x); + rect->y = MathUtil::Round(rect->y * _ratioY + _borderTop - viewportRect.y); + rect->w = MathUtil::RoundUp(rect->w * _ratioX); + rect->h = MathUtil::RoundUp(rect->h * _ratioY); +#endif +} + +////////////////////////////////////////////////////////////////////////// +void CBRenderOSystem::pointFromScreen(Point32 *point) { +#if 0 + SDL_Rect viewportRect; + SDL_RenderGetViewport(GetSdlRenderer(), &viewportRect); + + point->x = point->x / _ratioX - _borderLeft / _ratioX + viewportRect.x; + point->y = point->y / _ratioY - _borderTop / _ratioY + viewportRect.y; +#endif +} + + +////////////////////////////////////////////////////////////////////////// +void CBRenderOSystem::pointToScreen(Point32 *point) { +#if 0 + SDL_Rect viewportRect; + SDL_RenderGetViewport(GetSdlRenderer(), &viewportRect); + + point->x = MathUtil::RoundUp(point->x * _ratioX) + _borderLeft - viewportRect.x; + point->y = MathUtil::RoundUp(point->y * _ratioY) + _borderTop - viewportRect.y; +#endif +} + +////////////////////////////////////////////////////////////////////////// +void CBRenderOSystem::dumpData(const char *filename) { + warning("CBRenderOSystem::DumpData(%s) - not reimplemented yet", filename); // TODO +#if 0 + FILE *f = fopen(filename, "wt"); + if (!f) return; + + CBSurfaceStorage *Mgr = _gameRef->_surfaceStorage; + + int TotalKB = 0; + int TotalLoss = 0; + fprintf(f, "Filename;Usage;Size;KBytes\n"); + for (int i = 0; i < Mgr->_surfaces.getSize(); i++) { + CBSurfaceOSystem *Surf = (CBSurfaceOSystem *)Mgr->_surfaces[i]; + if (!Surf->_filename) continue; + if (!Surf->_valid) continue; + + fprintf(f, "%s;%d;", Surf->_filename, Surf->_referenceCount); + fprintf(f, "%dx%d;", Surf->getWidth(), Surf->getHeight()); + + int kb = Surf->getWidth() * Surf->getHeight() * 4 / 1024; + + TotalKB += kb; + fprintf(f, "%d;", kb); + fprintf(f, "\n"); + } + fprintf(f, "Total %d;;;%d\n", Mgr->_surfaces.getSize(), TotalKB); + + + fclose(f); + _gameRef->LOG(0, "Texture Stats Dump completed."); + _gameRef->QuickMessage("Texture Stats Dump completed."); +#endif +} + +CBSurface *CBRenderOSystem::createSurface() { + return new CBSurfaceOSystem(_gameRef); +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h new file mode 100644 index 0000000000..d41d14ef35 --- /dev/null +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -0,0 +1,129 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BRENDERER_SDL_H +#define WINTERMUTE_BRENDERER_SDL_H + +#include "engines/wintermute/base/gfx/base_renderer.h" +#include "common/rect.h" +#include "graphics/surface.h" +#include "common/list.h" + +namespace WinterMute { +class CBSurfaceOSystem; +class RenderTicket { +public: + RenderTicket(CBSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, bool mirrorX = false, bool mirrorY = false); + RenderTicket() : _isValid(true), _wantsDraw(false), _drawNum(0) {} + ~RenderTicket(); + Graphics::Surface *_surface; + Common::Rect _srcRect; + Common::Rect _dstRect; + uint32 _mirror; + bool _hasAlpha; + + bool _isValid; + bool _wantsDraw; + uint32 _drawNum; + uint32 _colorMod; + + CBSurfaceOSystem *_owner; + bool operator==(RenderTicket &a); +}; + +class CBRenderOSystem : public CBRenderer { +public: + CBRenderOSystem(CBGame *inGame); + ~CBRenderOSystem(); + + const char *getName(); + + bool initRenderer(int width, int height, bool windowed); + bool flip(); + bool fill(byte r, byte g, byte b, Common::Rect *rect = NULL); + + bool fade(uint16 alpha); + bool fadeToColor(uint32 color, Common::Rect *rect = NULL); + + bool switchFullscreen(); + + bool drawLine(int x1, int y1, int x2, int y2, uint32 color); + + CBImage *takeScreenshot(); + + void setAlphaMod(byte alpha); + void setColorMod(byte r, byte g, byte b); + void invalidateTicket(RenderTicket *renderTicket); + void invalidateTicketsFromSurface(CBSurfaceOSystem *surf); + void drawFromTicket(RenderTicket *renderTicket); + + bool setViewport(int left, int top, int right, int bottom); + + void modTargetRect(Common::Rect *rect); + void pointFromScreen(Point32 *point); + void pointToScreen(Point32 *point); + + void dumpData(const char *filename); + + float getScaleRatioX() const { + return _ratioX; + } + float getScaleRatioY() const { + return _ratioY; + } + + void drawSurface(CBSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, bool mirrorX, bool mirrorY); + CBSurface *createSurface(); +private: + void addDirtyRect(const Common::Rect &rect); + void drawTickets(); + void drawFromSurface(const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Common::Rect *clipRect, uint32 mirror); + typedef Common::List::iterator RenderQueueIterator; + Common::Rect *_dirtyRect; + Common::List _renderQueue; + bool _needsFlip; + uint32 _drawNum; + Common::Rect _renderRect; + Graphics::Surface *_renderSurface; + AnsiString _name; + + int _borderLeft; + int _borderTop; + int _borderRight; + int _borderBottom; + + bool _disableDirtyRects; + float _ratioX; + float _ratioY; + uint32 _colorMod; + uint32 _clearColor; +}; + +} // end of namespace WinterMute + +#endif // WINTERMUTE_BRENDERER_SDL_H diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp new file mode 100644 index 0000000000..1e4ac9a19e --- /dev/null +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -0,0 +1,532 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#include "engines/wintermute/base/file/BFile.h" +#include "engines/wintermute/base/BFileManager.h" +#include "engines/wintermute/base/BGame.h" +#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" +#include "engines/wintermute/base/gfx/osystem/base_render_osystem.h" +#include "engines/wintermute/base/gfx/base_image.h" +#include "engines/wintermute/PlatformSDL.h" +#include "graphics/decoders/png.h" +#include "graphics/decoders/bmp.h" +#include "graphics/decoders/jpeg.h" +#include "engines/wintermute/graphics/transparentSurface.h" +#include "engines/wintermute/graphics/tga.h" +#include "graphics/pixelformat.h" +#include "graphics/surface.h" +#include "common/stream.h" +#include "common/system.h" + +namespace WinterMute { + +////////////////////////////////////////////////////////////////////////// +CBSurfaceOSystem::CBSurfaceOSystem(CBGame *inGame) : CBSurface(inGame) { + _surface = new Graphics::Surface(); + _alphaMask = NULL; + _hasAlpha = true; + _lockPixels = NULL; + _lockPitch = 0; + _loaded = false; +} + +////////////////////////////////////////////////////////////////////////// +CBSurfaceOSystem::~CBSurfaceOSystem() { + //TODO + if (_surface) { + _surface->free(); + delete _surface; + _surface = NULL; + } + + delete[] _alphaMask; + _alphaMask = NULL; + + _gameRef->addMem(-_width * _height * 4); + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + renderer->invalidateTicketsFromSurface(this); +} + +bool hasTransparency(Graphics::Surface *surf) { + if (surf->format.bytesPerPixel != 4) { + warning("hasTransparency:: non 32 bpp surface passed as argument"); + return false; + } + uint8 r, g, b, a; + for (int i = 0; i < surf->h; i++) { + for (int j = 0; j < surf->w; j++) { + uint32 pix = *(uint32 *)surf->getBasePtr(j, i); + surf->format.colorToARGB(pix, a, r, g, b); + if (a != 255) { + return true; + } + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::create(const char *filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) { + /* CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); */ + _filename = filename; +// const Graphics::Surface *surface = image->getSurface(); + + if (defaultCK) { + ckRed = 255; + ckGreen = 0; + ckBlue = 255; + } + + _ckDefault = defaultCK; + _ckRed = ckRed; + _ckGreen = ckGreen; + _ckBlue = ckBlue; + + if (_lifeTime == 0 || lifeTime == -1 || lifeTime > _lifeTime) + _lifeTime = lifeTime; + + _keepLoaded = keepLoaded; + if (_keepLoaded) _lifeTime = -1; + + return STATUS_OK; +} + +void CBSurfaceOSystem::finishLoad() { + CBImage *image = new CBImage(_gameRef); + image->loadFile(_filename); + + _width = image->getSurface()->w; + _height = image->getSurface()->h; + + bool isSaveGameGrayscale = scumm_strnicmp(_filename.c_str(), "savegame:", 9) == 0 && (_filename.c_str()[_filename.size() - 1] == 'g' || _filename.c_str()[_filename.size() - 1] == 'G'); + if (isSaveGameGrayscale) { + warning("grayscaleConversion not yet implemented"); + /* FIBITMAP *newImg = FreeImage_ConvertToGreyscale(img); + if (newImg) { + FreeImage_Unload(img); + img = newImg; + }*/ + } + + // no alpha, set color key + /* if (surface->format.bytesPerPixel != 4) + SDL_SetColorKey(surf, SDL_TRUE, SDL_MapRGB(surf->format, ck_red, ck_green, ck_blue));*/ + + // convert 32-bit BMPs to 24-bit or they appear totally transparent (does any app actually write alpha in BMP properly?) + // Well, actually, we don't convert via 24-bit as the color-key application overwrites the Alpha-channel anyhow. + delete _surface; + if (_filename.hasSuffix(".bmp") && image->getSurface()->format.bytesPerPixel == 4) { + _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); + TransparentSurface trans(*_surface); + trans.applyColorKey(_ckRed, _ckGreen, _ckBlue); + } else if (image->getSurface()->format.bytesPerPixel == 1 && image->getPalette()) { + _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); + TransparentSurface trans(*_surface); + trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, true); + } else if (image->getSurface()->format.bytesPerPixel == 4 && image->getSurface()->format != g_system->getScreenFormat()) { + _surface = image->getSurface()->convertTo(g_system->getScreenFormat()); + } else { + _surface = new Graphics::Surface(); + _surface->copyFrom(*image->getSurface()); + } + + _hasAlpha = hasTransparency(_surface); + //SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); //TODO + //_texture = SdlUtil::CreateTextureFromSurface(renderer->GetSdlRenderer(), surf); + + // This particular warning is rather messy, as this function is called a ton, + // thus we avoid printing it more than once. + static bool hasWarned = false; + if (!hasWarned) { + warning("Surface-textures not fully ported yet"); + hasWarned = true; + } + //delete imgDecoder; +#if 0 + _texture = SDL_CreateTextureFromSurface(renderer->GetSdlRenderer(), surf); + if (!_texture) { + SDL_FreeSurface(surf); + delete imgDecoder; + return STATUS_FAILED; + } + + GenAlphaMask(surf); + + SDL_FreeSurface(surf); + delete imgDecoder; // TODO: Update this if ImageDecoder doesn't end up owning the surface. +#endif + + _valid = true; + + _gameRef->addMem(_width * _height * 4); + + delete image; + + _loaded = true; +} + +////////////////////////////////////////////////////////////////////////// +void CBSurfaceOSystem::genAlphaMask(Graphics::Surface *surface) { + warning("CBSurfaceOSystem::GenAlphaMask - Not ported yet"); + return; + + delete[] _alphaMask; + _alphaMask = NULL; + if (!surface) return; +#if 0 + SDL_LockSurface(surface); +#endif + bool hasColorKey; + /* uint32 colorKey; */ + uint8 ckRed, ckGreen, ckBlue; + /* if (SDL_GetColorKey(surface, &colorKey) == 0) { + hasColorKey = true; + SDL_GetRGB(colorKey, surface->format, &ckRed, &ckGreen, &ckBlue); + } else hasColorKey = false; + */ //TODO + _alphaMask = new byte[surface->w * surface->h]; + + bool hasTransparency = false; + for (int y = 0; y < surface->h; y++) { + for (int x = 0; x < surface->w; x++) { + uint32 pixel = getPixel(surface, x, y); + + uint8 r, g, b, a; + surface->format.colorToARGB(pixel, a, r, g, b); + //SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); + + if (hasColorKey && r == ckRed && g == ckGreen && b == ckBlue) + a = 0; + + _alphaMask[y * surface->w + x] = a; + if (a < 255) hasTransparency = true; + } + } +#if 0 + SDL_UnlockSurface(surface); +#endif + if (!hasTransparency) { + delete[] _alphaMask; + _alphaMask = NULL; + } +} + +////////////////////////////////////////////////////////////////////////// +uint32 CBSurfaceOSystem::getPixel(Graphics::Surface *surface, int x, int y) { + warning("CBSurfaceOSystem::GetPixel - Not ported yet"); + int bpp = surface->format.bytesPerPixel; + /* Here p is the address to the pixel we want to retrieve */ + uint8 *p = (uint8 *)surface->pixels + y * surface->pitch + x * bpp; + + switch (bpp) { + case 1: + return *p; + break; + + case 2: + return *(uint16 *)p; + break; + + case 3: +#ifdef SCUMM_BIG_ENDIAN + // if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + return p[0] << 16 | p[1] << 8 | p[2]; +#else + //else + return p[0] | p[1] << 8 | p[2] << 16; +#endif + break; + + case 4: + return *(uint32 *)p; + break; + + default: + return 0; /* shouldn't happen, but avoids warnings */ + } + return 0; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::create(int width, int height) { + warning("CBSurfaceOSystem::Create not ported yet"); //TODO +#if 0 + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + _texture = SDL_CreateTexture(renderer->GetSdlRenderer(), SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Width, Height); +#endif + _width = width; + _height = height; + + _gameRef->addMem(_width * _height * 4); + + _valid = true; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::createFromSDLSurface(Graphics::Surface *surface) { + warning("CBSurfaceOSystem::CreateFromSDLSurface not ported yet"); //TODO +#if 0 + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + _texture = SDL_CreateTextureFromSurface(renderer->GetSdlRenderer(), surface); +#endif + if (_surface) { + _surface->free(); + delete _surface; + _surface = NULL; + } + _surface = new Graphics::Surface(); + _surface->copyFrom(*surface); + _width = surface->w; + _height = surface->h; +#if 0 + _gameRef->AddMem(_width * _height * 4); +#endif + _valid = true; + + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::isTransparentAt(int x, int y) { + // This particular warning is rather messy, as this function is called a ton, + // thus we avoid printing it more than once. + static bool hasWarned = false; + if (!hasWarned) { + warning("CBSurfaceOSystem::IsTransparentAt not ported yet"); + hasWarned = true; + } +#if 0 + int access; + int width, height; + //SDL_QueryTexture(_texture, NULL, &access, &width, &height); //TODO + //if (access != SDL_TEXTUREACCESS_STREAMING) return false; + if (X < 0 || X >= width || Y < 0 || Y >= height) return true; + + + StartPixelOp(); + bool ret = isTransparentAtLite(X, Y); + EndPixelOp(); + + return ret; +#endif + return 0; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::isTransparentAtLite(int x, int y) { + //if (!_lockPixels) return false; + + // This particular warning is rather messy, as this function is called a ton, + // thus we avoid printing it more than once. + static bool hasWarned = false; + if (!hasWarned) { + warning("CBSurfaceOSystem::IsTransparentAtLite not ported yet"); + hasWarned = true; + } + if (_surface->format.bytesPerPixel == 4) { + uint32 pixel = *(uint32 *)_surface->getBasePtr(x, y); + uint8 r, g, b, a; + _surface->format.colorToARGB(pixel, a, r, g, b); + if (a <= 128) { + return true; + } else { + return false; + } + } +#if 0 + uint32 format; + int access; + int width, height; + + //SDL_QueryTexture(_texture, &format, &access, &width, &height); + //if (access != SDL_TEXTUREACCESS_STREAMING) return false; + if (X < 0 || X >= width || Y < 0 || Y >= height) return true; + + if (!_alphaMask) return false; + else return _alphaMask[Y * width + X] <= 128; +#endif + return false; + /* + Uint32* dst = (Uint32*)((Uint8*)_lockPixels + Y * _lockPitch); + Uint32 pixel = dst[X]; + + SDL_PixelFormat* pixelFormat = SDL_AllocFormat(format); + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, pixelFormat, &r, &g, &b, &a); + SDL_FreeFormat(pixelFormat); + + return a <= 128; + */ +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::startPixelOp() { + //SDL_LockTexture(_texture, NULL, &_lockPixels, &_lockPitch); + // Any pixel-op makes the caching useless: + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + renderer->invalidateTicketsFromSurface(this); + return STATUS_OK; +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::endPixelOp() { + //SDL_UnlockTexture(_texture); + return STATUS_OK; +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return drawSprite(x, y, &rect, 100, 100, 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY); +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY); +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { + return drawSprite(x, y, &rect, 100, 100, alpha, false, blendMode, mirrorX, mirrorY, offsetX, offsetY); +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool Transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return drawSprite(x, y, &rect, zoomX, zoomY, alpha, !Transparent, blendMode, mirrorX, mirrorY); +} + + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::displayTransform(int x, int y, int hotX, int hotY, Rect32 rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { + return drawSprite(x, y, &rect, zoomX, zoomY, alpha, false, blendMode, mirrorX, mirrorY); +} + +////////////////////////////////////////////////////////////////////////// +bool CBSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + + if (!_loaded) { + finishLoad(); + } + + if (renderer->_forceAlphaColor != 0) + alpha = renderer->_forceAlphaColor; + + // This particular warning is rather messy, as this function is called a ton, + // thus we avoid printing it more than once. + static bool hasWarned = false; + if (!hasWarned) { + warning("CBSurfaceOSystem::DrawSprite not fully ported yet"); // TODO. + hasWarned = true; + } + + byte r = RGBCOLGetR(alpha); + byte g = RGBCOLGetG(alpha); + byte b = RGBCOLGetB(alpha); + byte a = RGBCOLGetA(alpha); + + renderer->setAlphaMod(a); + renderer->setColorMod(r, g, b); +#if 0 + SDL_SetTextureColorMod(_texture, r, g, b); + SDL_SetTextureAlphaMod(_texture, a); + + if (AlphaDisable) + SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE); + else + SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND); +#endif + // TODO: This _might_ miss the intended behaviour by 1 in each direction + // But I think it fits the model used in Wintermute. + Common::Rect srcRect; + srcRect.left = rect->left; + srcRect.top = rect->top; + srcRect.setWidth(rect->right - rect->left); + srcRect.setHeight(rect->bottom - rect->top); + + Common::Rect position; + position.left = x + offsetX; + position.top = y + offsetY; + // TODO: Scaling... + + if (position.left == -1) { + position.left = 0; // TODO: Something is wrong + } + if (position.top == -1) { + position.top = 0; // TODO: Something is wrong + } + + position.setWidth((int16)((float)srcRect.width() * zoomX / 100.f)); + position.setHeight((int16)((float)srcRect.height() * zoomX / 100.f)); + + renderer->modTargetRect(&position); + + /* position.left += offsetX; + position.top += offsetY;*/ + + // TODO: This actually requires us to have the SAME source-offsets every time, + // But no checking is in place for that yet. + + bool hasAlpha; + if (_hasAlpha && !alphaDisable) { + hasAlpha = true; + } else { + hasAlpha = false; + } + if (alphaDisable) { + warning("CBSurfaceOSystem::drawSprite - AlphaDisable ignored"); + } + + renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY); +#if 0 + SDL_RenderCopy(renderer->GetSdlRenderer(), _texture, &srcRect, &position); +#endif + + return STATUS_OK; +} + +bool CBSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAlpha) { + _loaded = true; + _surface->copyFrom(surface); + _hasAlpha = hasAlpha; + CBRenderOSystem *renderer = static_cast(_gameRef->_renderer); + renderer->invalidateTicketsFromSurface(this); + + return STATUS_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h new file mode 100644 index 0000000000..091e8ccba8 --- /dev/null +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -0,0 +1,101 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_BSURFACESDL_H +#define WINTERMUTE_BSURFACESDL_H + +#include "graphics/surface.h" +#include "engines/wintermute/base/gfx/base_surface.h" +#include "common/list.h" + +namespace WinterMute { +struct TransparentSurface; +class CBImage; +class CBSurfaceOSystem : public CBSurface { +public: + CBSurfaceOSystem(CBGame *inGame); + ~CBSurfaceOSystem(); + + bool create(const char *filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false); + bool create(int width, int height); + + bool createFromSDLSurface(Graphics::Surface *surface); //TODO: Rename function + + bool isTransparentAt(int x, int y); + bool isTransparentAtLite(int x, int y); + + bool startPixelOp(); + bool endPixelOp(); + + + bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false); + bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false); + bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0); + bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false); + bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool Transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false); + bool displayTransform(int x, int y, int hotX, int hotY, Rect32 Rect, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false); + virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false); + /* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle); + static int DLL_CALLCONV SeekProc(fi_handle handle, long offset, int origin); + static long DLL_CALLCONV TellProc(fi_handle handle);*/ + virtual int getWidth() { + if (!_loaded) { + finishLoad(); + } + if (_surface) { + return _surface->w; + } + return _width; + } + virtual int getHeight() { + if (!_loaded) { + finishLoad(); + } + if (_surface) { + return _surface->h; + } + return _height; + } + +private: + Graphics::Surface *_surface; + bool _loaded; + void finishLoad(); + bool drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX = 0, int offsetY = 0); + void genAlphaMask(Graphics::Surface *surface); + uint32 getPixel(Graphics::Surface *surface, int x, int y); + + bool _hasAlpha; + void *_lockPixels; + int _lockPitch; + byte *_alphaMask; +}; + +} // end of namespace WinterMute + +#endif // WINTERMUTE_BSURFACESDL_H -- cgit v1.2.3