mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-15 21:20:19 +00:00
357 lines
10 KiB
C++
357 lines
10 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "titanic/support/screen_manager.h"
|
|
#include "titanic/support/video_surface.h"
|
|
#include "titanic/titanic.h"
|
|
#include "graphics/screen.h"
|
|
|
|
namespace Titanic {
|
|
|
|
CScreenManager *CScreenManager::_screenManagerPtr;
|
|
CScreenManager *CScreenManager::_currentScreenManagerPtr;
|
|
|
|
CScreenManager::CScreenManager(TitanicEngine *vm): _vm(vm) {
|
|
_screenManagerPtr = nullptr;
|
|
_currentScreenManagerPtr = nullptr;
|
|
|
|
_frontRenderSurface = nullptr;
|
|
_mouseCursor = nullptr;
|
|
_textCursor = nullptr;
|
|
_inputHandler = nullptr;
|
|
_fontNumber = 0;
|
|
|
|
_screenManagerPtr = this;
|
|
}
|
|
|
|
CScreenManager::~CScreenManager() {
|
|
_screenManagerPtr = nullptr;
|
|
}
|
|
|
|
void CScreenManager::setWindowHandle(int v) {
|
|
// Not needed
|
|
}
|
|
|
|
bool CScreenManager::resetWindowHandle(int v) {
|
|
hideCursor();
|
|
return true;
|
|
}
|
|
|
|
CScreenManager *CScreenManager::setCurrent() {
|
|
if (!_currentScreenManagerPtr)
|
|
_currentScreenManagerPtr = _screenManagerPtr;
|
|
|
|
return _currentScreenManagerPtr;
|
|
}
|
|
|
|
void CScreenManager::setSurfaceBounds(SurfaceNum surfaceNum, const Rect &r) {
|
|
if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size())
|
|
_backSurfaces[surfaceNum]._bounds = r;
|
|
else if (surfaceNum == SURFACE_PRIMARY)
|
|
_frontSurfaceBounds = r;
|
|
}
|
|
|
|
int CScreenManager::setFontNumber(int fontNumber) {
|
|
int oldFontNumber = _fontNumber;
|
|
_fontNumber = fontNumber;
|
|
return oldFontNumber;
|
|
}
|
|
|
|
void CScreenManager::preLoad() {
|
|
if (_textCursor)
|
|
_textCursor->hide();
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
OSScreenManager::OSScreenManager(TitanicEngine *vm): CScreenManager(vm),
|
|
_directDrawManager(vm, false) {
|
|
_field48 = 0;
|
|
_field4C = 0;
|
|
_field50 = 0;
|
|
_field54 = 0;
|
|
}
|
|
|
|
OSScreenManager::~OSScreenManager() {
|
|
destroyFrontAndBackBuffers();
|
|
delete _mouseCursor;
|
|
delete _textCursor;
|
|
}
|
|
|
|
void OSScreenManager::setMode(int width, int height, int bpp, uint numBackSurfaces, bool flag2) {
|
|
assert(bpp == 16);
|
|
destroyFrontAndBackBuffers();
|
|
_directDrawManager.initVideo(width, height, bpp, numBackSurfaces);
|
|
|
|
_vm->_screen->create(width, height, g_system->getScreenFormat());
|
|
_frontRenderSurface = new OSVideoSurface(this, nullptr);
|
|
_frontRenderSurface->setSurface(this, _directDrawManager._mainSurface);
|
|
|
|
_backSurfaces.resize(numBackSurfaces);
|
|
for (uint idx = 0; idx < numBackSurfaces; ++idx) {
|
|
_backSurfaces[idx]._surface = new OSVideoSurface(this, nullptr);
|
|
_backSurfaces[idx]._surface->setSurface(this, _directDrawManager._backSurfaces[idx]);
|
|
}
|
|
|
|
// Load fonts
|
|
_fonts[0].load(149);
|
|
_fonts[1].load(151);
|
|
_fonts[2].load(152);
|
|
_fonts[3].load(153);
|
|
|
|
// Load the cursors
|
|
loadCursors();
|
|
}
|
|
|
|
void OSScreenManager::drawCursors() {
|
|
// The original did both text and mouse cursor drawing here.
|
|
// For ScummVM, we only need to worry about the text cursor
|
|
_textCursor->draw();
|
|
}
|
|
|
|
DirectDrawSurface *OSScreenManager::getDDSurface(SurfaceNum surfaceNum) {
|
|
if (surfaceNum == SURFACE_PRIMARY)
|
|
return _directDrawManager._mainSurface;
|
|
else if (surfaceNum < (int)_backSurfaces.size())
|
|
return _directDrawManager._backSurfaces[surfaceNum];
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
CVideoSurface *OSScreenManager::lockSurface(SurfaceNum surfaceNum) {
|
|
CVideoSurface *surface = getSurface(surfaceNum);
|
|
surface->lock();
|
|
return surface;
|
|
}
|
|
|
|
void OSScreenManager::unlockSurface(CVideoSurface *surface) {
|
|
surface->unlock();
|
|
}
|
|
|
|
CVideoSurface *OSScreenManager::getSurface(SurfaceNum surfaceNum) const {
|
|
if (surfaceNum == SURFACE_PRIMARY)
|
|
return _frontRenderSurface;
|
|
else if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size())
|
|
return _backSurfaces[surfaceNum]._surface;
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
void OSScreenManager::fillRect(SurfaceNum surfaceNum, Rect *rect, byte r, byte g, byte b) {
|
|
DirectDrawSurface *surface = getDDSurface(surfaceNum);
|
|
if (!surface)
|
|
return;
|
|
|
|
// If bounds are provided, clip and use them. Otherwise, use entire surface area
|
|
Rect surfaceRect(0, 0, surface->getWidth(), surface->getHeight());
|
|
Rect tempRect;
|
|
|
|
if (rect) {
|
|
tempRect = *rect;
|
|
tempRect.clip(surfaceRect);
|
|
} else {
|
|
tempRect = surfaceRect;
|
|
}
|
|
|
|
// Constrain the fill area to the set modification area of the surface
|
|
Rect surfaceBounds = (surfaceNum == SURFACE_PRIMARY) ? _frontSurfaceBounds :
|
|
_backSurfaces[surfaceNum]._bounds;
|
|
if (!surfaceBounds.isEmpty())
|
|
tempRect.constrain(surfaceBounds);
|
|
|
|
// If there is any area defined, clear it
|
|
if (tempRect.isValidRect())
|
|
surface->fillRect(&tempRect, r, g, b);
|
|
}
|
|
|
|
void OSScreenManager::blitFrom(SurfaceNum surfaceNum, CVideoSurface *src,
|
|
const Point *destPos, const Rect *srcRect) {
|
|
// Get the dest surface
|
|
CVideoSurface *destSurface = _frontRenderSurface;
|
|
if (surfaceNum < -1)
|
|
return;
|
|
if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size())
|
|
destSurface = _backSurfaces[surfaceNum]._surface;
|
|
if (!destSurface->hasSurface())
|
|
return;
|
|
|
|
Point destPoint = destPos ? *destPos : Point(0, 0);
|
|
Rect srcBounds = srcRect ? *srcRect : Rect(0, 0, src->getWidth(), src->getHeight());
|
|
Rect *bounds = &srcBounds;
|
|
Rect rect2;
|
|
|
|
Rect surfaceBounds = (surfaceNum == SURFACE_PRIMARY) ? _frontSurfaceBounds :
|
|
_backSurfaces[surfaceNum]._bounds;
|
|
|
|
if (!surfaceBounds.isEmpty()) {
|
|
// Perform clipping to the bounds of the back surface
|
|
rect2 = srcBounds;
|
|
rect2.translate(-srcBounds.left, -srcBounds.top);
|
|
rect2.translate(destPoint.x, destPoint.y);
|
|
rect2.constrain(surfaceBounds);
|
|
|
|
rect2.translate(-destPoint.x, -destPoint.y);
|
|
rect2.translate(srcBounds.left, srcBounds.top);
|
|
|
|
if (rect2.isEmpty())
|
|
return;
|
|
|
|
destPoint.x += rect2.left - srcBounds.left;
|
|
destPoint.y += rect2.top - srcBounds.top;
|
|
bounds = &rect2;
|
|
}
|
|
|
|
if (!bounds->isEmpty())
|
|
destSurface->blitFrom(destPoint, src, bounds);
|
|
}
|
|
|
|
void OSScreenManager::blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSurface *src, int v) {
|
|
// Get the dest surface
|
|
CVideoSurface *destSurface = _frontRenderSurface;
|
|
if (surfaceNum < -1)
|
|
return;
|
|
if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size())
|
|
destSurface = _backSurfaces[surfaceNum]._surface;
|
|
if (!destSurface->hasSurface())
|
|
return;
|
|
|
|
if (!rect->isEmpty())
|
|
destSurface->blitFrom(Point(rect->left, rect->top), src, rect);
|
|
}
|
|
|
|
int OSScreenManager::writeString(int surfaceNum, const Rect &destRect,
|
|
int yOffset, const CString &str, CTextCursor *textCursor) {
|
|
CVideoSurface *surface;
|
|
Rect bounds;
|
|
|
|
if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) {
|
|
surface = _backSurfaces[surfaceNum]._surface;
|
|
bounds = _backSurfaces[surfaceNum]._bounds;
|
|
} else if (surfaceNum == SURFACE_PRIMARY) {
|
|
surface = _frontRenderSurface;
|
|
bounds = _frontSurfaceBounds;
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
return _fonts[_fontNumber].writeString(surface, destRect, bounds,
|
|
yOffset, str, textCursor);
|
|
}
|
|
|
|
void OSScreenManager::writeString(int surfaceNum, const Point &destPos,
|
|
const Rect &clipRect, const CString &str, int lineWidth) {
|
|
CVideoSurface *surface;
|
|
Rect bounds;
|
|
|
|
if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) {
|
|
surface = _backSurfaces[surfaceNum]._surface;
|
|
bounds = _backSurfaces[surfaceNum]._bounds;
|
|
} else if (surfaceNum == -1) {
|
|
surface = _frontRenderSurface;
|
|
bounds = Rect(0, 0, surface->getWidth(), surface->getHeight());
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
Rect destRect = clipRect;
|
|
destRect.constrain(bounds);
|
|
|
|
_fonts[_fontNumber].writeString(surface, destPos, destRect, str, lineWidth);
|
|
}
|
|
|
|
void OSScreenManager::setFontColor(byte r, byte g, byte b) {
|
|
_fonts[_fontNumber].setColor(r, g, b);
|
|
}
|
|
|
|
int OSScreenManager::getTextBounds(const CString &str, int maxWidth, Point *sizeOut) const {
|
|
return _fonts[_fontNumber].getTextBounds(str, maxWidth, sizeOut);
|
|
}
|
|
|
|
int OSScreenManager::getFontHeight() const {
|
|
return _fonts[_fontNumber]._fontHeight;
|
|
}
|
|
|
|
int OSScreenManager::stringWidth(const CString &str) {
|
|
return _fonts[_fontNumber].stringWidth(str);
|
|
}
|
|
|
|
void OSScreenManager::frameRect(SurfaceNum surfaceNum, const Rect &rect, byte r, byte g, byte b) {
|
|
Rect top(rect.left, rect.top, rect.right, rect.top + 1);
|
|
fillRect(surfaceNum, &top, r, g, b);
|
|
Rect bottom(rect.left, rect.bottom - 1, rect.right, rect.bottom);
|
|
fillRect(surfaceNum, &bottom, r, g, b);
|
|
Rect left(rect.left, rect.top, rect.left + 1, rect.bottom);
|
|
fillRect(surfaceNum, &left, r, g, b);
|
|
Rect right(rect.right - 1, rect.top, rect.right, rect.bottom);
|
|
}
|
|
|
|
void OSScreenManager::clearSurface(SurfaceNum surfaceNum, Rect *bounds) {
|
|
if (surfaceNum == SURFACE_PRIMARY)
|
|
_directDrawManager._mainSurface->fill(bounds, 0);
|
|
else if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size())
|
|
_directDrawManager._backSurfaces[surfaceNum]->fill(bounds, 0);
|
|
}
|
|
|
|
void OSScreenManager::resizeSurface(CVideoSurface *surface, int width, int height, int bpp) {
|
|
DirectDrawSurface *ddSurface = _directDrawManager.createSurface(width, height, bpp, 0);
|
|
surface->setSurface(this, ddSurface);
|
|
}
|
|
|
|
CVideoSurface *OSScreenManager::createSurface(int w, int h, int bpp) {
|
|
DirectDrawSurface *ddSurface = _directDrawManager.createSurface(w, h, bpp, 0);
|
|
return new OSVideoSurface(this, ddSurface);
|
|
}
|
|
|
|
CVideoSurface *OSScreenManager::createSurface(const CResourceKey &key) {
|
|
return new OSVideoSurface(this, key);
|
|
}
|
|
|
|
void OSScreenManager::showCursor() {
|
|
CScreenManager::_screenManagerPtr->_mouseCursor->unsuppressCursor();
|
|
}
|
|
|
|
void OSScreenManager::hideCursor() {
|
|
CScreenManager::_screenManagerPtr->_mouseCursor->suppressCursor();
|
|
}
|
|
|
|
void OSScreenManager::destroyFrontAndBackBuffers() {
|
|
delete _frontRenderSurface;
|
|
_frontRenderSurface = nullptr;
|
|
|
|
for (uint idx = 0; idx < _backSurfaces.size(); ++idx)
|
|
delete _backSurfaces[idx]._surface;
|
|
_backSurfaces.clear();
|
|
}
|
|
|
|
void OSScreenManager::loadCursors() {
|
|
if (_mouseCursor) {
|
|
hideCursor();
|
|
delete _mouseCursor;
|
|
}
|
|
_mouseCursor = new CMouseCursor(this);
|
|
|
|
if (!_textCursor) {
|
|
_textCursor = new CTextCursor(this);
|
|
}
|
|
}
|
|
|
|
} // End of namespace Titanic
|