Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,446 @@
/* 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/>.
*
*/
#ifndef BAGEL_BOFLIB_GFX_BMP_H
#define BAGEL_BOFLIB_GFX_BMP_H
#include "graphics/managed_surface.h"
#include "bagel/boflib/palette.h"
#include "bagel/boflib/cache.h"
#include "bagel/boflib/error.h"
#include "bagel/boflib/object.h"
#include "bagel/boflib/point.h"
#include "bagel/boflib/rect.h"
#include "bagel/boflib/size.h"
#include "bagel/boflib/stdinc.h"
namespace Bagel {
namespace SpaceBar {
// Color constants
//
enum {
NOT_TRANSPARENT = -1,
COLOR_WHITE = 255,
COLOR_BLACK = 0
};
#define CBMP_FADE_SPEED 10
#define CBMP_FADE_SIZE 4
#define CBMP_CURT_SPEED 8 // Must be a power of 2
#define CBMP_LINE_SPEED 32 // Should be a power of 4
// forward declare CBofWindow
class CBofWindow;
class CBofBitmap : public CBofError, public CBofObject, public CCache {
protected:
/**
* Does the actual allocation for this bitmap
* @return true is this bitmap was successfully loaded into the cache
*/
bool alloc() override;
/**
* Frees the data used by this bitmap (removes from cache)
*/
void free() override;
//
// data members
//
static bool _bUseBackdrop;
char _szFileName[MAX_FNAME];
Graphics::ManagedSurface _bitmap;
byte *_pBits = nullptr;
CBofPalette *_pPalette = nullptr;
int _nScanDX = 0;
int _nDX = 0;
int _nDY = 0;
bool _bTopDown = false;
bool _bOwnPalette = false;
bool _bReadOnly = false;
bool _bInitialized = false;
public:
/**
* Default constructor
*/
CBofBitmap();
/**
* Constructs a CBofBitmap
* @param dx Width of new bitmap
* @param dy Height of new bitmap
* @param pPalette Palette to use for this bitmap
* @param bOwnPalette true if destructor should delete palette
* @param pPrivateBuff
*/
CBofBitmap(int dx, int dy, CBofPalette *pPalette, bool bOwnPalette = false, byte *pPrivateBuff = nullptr);
/**
* Constructs a CBofBitmap
* @param pszFileName Path and Filename for Bitmap on disk
* @param pPalette Palette to use for this bitmap
* @param bOwnPalette true if destructor should delete palette
*/
CBofBitmap(const char *pszFileName, CBofPalette *pPalette = nullptr, bool bOwnPalette = false);
/**
* Destructor
*/
virtual ~CBofBitmap();
/**
* Allocates the structures needed for a CBofBitmap
* @param pPalette Palette to be assigned into this bitmap
*/
ErrorCode buildBitmap(CBofPalette *pPalette);
/**
* Loads the specified bitmap from disk
* @param pszFileName Filename
* @param pPalette Palette
* @return Error return code
*/
ErrorCode loadBitmap(const char *pszFileName, CBofPalette *pPalette);
/**
* Frees the data used by this bitmap
*/
void releaseBitmap();
//
// Palette routines
//
/**
* Assigns specified palette to this bitmap
* @param pPalette Pointer to CBofPalette to be assigned
* @param bOwnPalette true if bitmap is to own this palette
*/
void setPalette(CBofPalette *pPalette, bool bOwnPalette = false);
CBofPalette *getPalette() {
return _pPalette;
}
void setIsOwnPalette(bool own) {
_bOwnPalette = own;
}
//
// Misc routines
//
/**
* Returns the bit address of the (x, y) location in this bmp
* @param x Column in _pBits
* @param y Row in _pBits
* @return Address of (x,y) in bitmap surface
*/
byte *getPixelAddress(int x, int y);
byte *getPixelAddress(CBofPoint *pPoint) {
return getPixelAddress(pPoint->x, pPoint->y);
}
CBofSize getSize() {
return CBofSize(_nDX, _nDY);
}
CBofRect getRect() {
return CBofRect(0, 0, _nDX - 1, _nDY - 1);
}
void setReadOnly(bool bReadOnly) {
_bReadOnly = bReadOnly;
}
bool getReadOnly() {
return _bReadOnly;
}
bool isTopDown() {
return _bTopDown;
}
int width() {
return _nDX;
}
int widthBytes() {
return _nScanDX;
}
int height() {
return _nDY;
}
operator Graphics::ManagedSurface &() {
return _bitmap;
}
Graphics::ManagedSurface getSurface();
/**
* Returns current bitmap's filename (if any)
* @return Pointer to bitmap's filename
*/
const char *getFileName();
//
// Drawing routines
//
/**
* Paints some or all of the bitmap directly to the screen
* @param pWnd Destination device for painting
* @param x Destination column
* @param y Destination row
* @param pSrcRect Source rectangle from bitmap
* @param nMaskColor Transparency color
* @return error return code
*/
ErrorCode paint(CBofWindow *pWnd, int x, int y, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
/**
* Paints some or all of the bitmap directly to the screen
* @param pWnd Destination Device to paint to
* @param pDstRect Destination rectangle (for stretching)
* @param pSrcRect Source rectangle from bitmap
* @param nMaskColor transparency color
* @return Error return code
*/
ErrorCode paint(CBofWindow *pWnd, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
/**
* Paints some or all of the bitmap directly to the screen
* @param pWnd Destination Device to paint to
* @param pDstRect Destination rectangle (for stretching)
* @param pSrcRect Source rectangle from bitmap
* @param nMaskColor Transparency color
* @return Error return code
*/
ErrorCode paintMaskBackdrop(CBofWindow *pWnd, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
/**
* Paints some or all of the bitmap directly to the screen
* @param pBmp Destination bitmap to paint to
* @param x Destination column
* @param y Destination row
* @param pSrcRect Source rectangle from bitmap
* @param nMaskColor Transparency color
* @return Error return code
*/
ErrorCode paint(CBofBitmap *pBmp, int x, int y, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
/**
* Paints some or all of the bitmap directly to the screen
* @param pBmp Destination bitmap to paint to
* @param pDstRect Destination rectangle (for stretching)
* @param pSrcRect Source rectangle from bitmap
* @param nMaskColor Transparency color
* @return Error return code.
*/
ErrorCode paint(CBofBitmap *pBmp, CBofRect *pDstRect = nullptr, CBofRect *pSrcRect = nullptr, int nMaskColor = NOT_TRANSPARENT);
//
// Special Paint routines Optimized for specific tasks
//
// Stretches 4 pixel wide
/**
* Stretches 4 pixel wide strips from source to destination
* @brief The Destination rectangle MUST be divisible by 4.
* Both bitmaps must be Bottom-Up. The Source must be smaller than the Destination.
*
* @param pBmp Destination bitmap to paint to
* @param pDstRect Destination rectangle (for stretching)
* @param pSrcRect Source rectangle from bitmap
* @return Error return code
*/
ErrorCode paintStretch4(CBofBitmap *pBmp, CBofRect *pDstRect, CBofRect *pSrcRect);
/**
* Stretches a multiple of 4 pixel wide strips from source to destination
* @param pBmp Destination bitmap to paint to
* @param pDstRect Destination rectangle (for stretching)
* @param pSrcRect Source rectangle from bitmap
* @param nOptSize
* @return Error return code
*/
ErrorCode paintStretchOpt(CBofBitmap *pBmp, CBofRect *pDstRect, CBofRect *pSrcRect, int nOptSize);
/**
* Paints some or all of the bitmap directly to the screen
* @param pBmp Destination bitmap to paint to
* @return Error return code
*/
ErrorCode paint1To1(CBofBitmap *pBmp);
/** Copy specified section of screen (or window) to bitmap.
* @param pWnd Window to capture
* @param pSrcRect Source rectangle in window
* @param pDstRect Destination area to copy image to
* @return Error return code
*/
ErrorCode captureScreen(CBofWindow *pWnd, CBofRect *pSrcRect, CBofRect *pDstRect = nullptr);
/**
* Performs a "Fade" onto the specified window
* @param pWnd Pointer to window to fade into
* @param x Fade upper left X
* @param y Fade upper left Y
* @param nMaskColor Transparency color (if any)
* @param nBlockSize Size of Fade Blocks
* @param nSpeed Speed for fade (not implemented yet)
* @return Error return code
*/
ErrorCode fadeIn(CBofWindow *pWnd, int x = 0, int y = 0, int nMaskColor = NOT_TRANSPARENT, int nBlockSize = CBMP_FADE_SIZE, int nSpeed = CBMP_FADE_SPEED);
ErrorCode curtain(CBofWindow *pWnd, int nSpeed = CBMP_CURT_SPEED, int nMaskColor = NOT_TRANSPARENT);
ErrorCode fadeLines(CBofWindow *pWnd, int nSpeed = CBMP_LINE_SPEED, int nMaskColor = NOT_TRANSPARENT);
/**
* Returns the color at the (x, y) location in this bmp
* @param x X position
* @param y Y position
* @return Color Index of specified (x,y) location in _pBits
*/
byte readPixel(int x, int y);
/**
* Assigns the specified color to the (x, y) location
* @param x X position
* @param y Y position
* @param iColor Pixel value
*/
void writePixel(int x, int y, byte iColor);
/**
* Writes a circle into this bitmap
* @param x X center position
* @param y Y center position
* @param nRadius Radius of circle
* @param iColor Pixel value
*/
void circle(int x, int y, uint16 nRadius, byte iColor);
/**
* Writes a line into this bitmap
* @param nSrcX Endpoint 1 x
* @param nSrcY Endpoint 1 y
* @param nDstX Endpoint 2 x
* @param nDstY Endpoint 2 y
* @param iColor Pixel value
*/
void line(int nSrcX, int nSrcY, int nDstX, int nDstY, byte iColor);
/**
* Writes a line into this bitmap
* @param pSrc Endpoint 1
* @param pDest Endpoint 2
* @param iColor Pixel value
*/
void line(CBofPoint *pSrc, CBofPoint *pDest, byte iColor);
/**
* Writes a Rectangle into this bitmap
* @param cRect Pointer to rectangle Coordinates
* @param iColor Color of rectangle
*/
void drawRect(CBofRect *cRect, byte iColor);
/**
* Writes a filled in Rectangle to this bitmap
* @param cRect Pointer to rectangle Coordinates
* @param iColor Color of rectangle
*/
void fillRect(CBofRect *cRect, byte iColor);
/**
* Scrolls current bitmap horizontally
* @param nPixels Number of pixels to scroll by
* @param pRect Section of bitmap to scroll
* @return Error return code
*/
ErrorCode scrollRight(int nPixels, CBofRect *pRect = nullptr);
ErrorCode scrollLeft(int nPixels, CBofRect *pRect = nullptr) {
return scrollRight(-nPixels, pRect);
}
/**
* Scrolls current bitmap vertically
* @param nPixels Number of pixels to scroll by
* @return Error return code
*/
ErrorCode scrollUp(int nPixels);
static void setUseBackdrop(bool b) {
_bUseBackdrop = b;
}
static bool getUseBackdrop() {
return _bUseBackdrop;
}
};
//////////////////////////////////////////////////////////////////////////////
//
// Misc graphics routines
//
//////////////////////////////////////////////////////////////////////////////
/**
* Loads specified bitmap (and possibly re-maps to palette)
* @param pszFileName Bitmap to open
* @param pPalette Palette for re-mapping
* @param bSharedPal Shared palette flag
* @return Pointer to bitmap
*/
extern CBofBitmap *loadBitmap(const char *pszFileName, CBofPalette *pPalette = nullptr, bool bSharedPal = false);
/**
* Paints specified bitmap to specified window
* @param pWindow Window to paint to
* @param pszFileName Bitmap filename
* @param pDstRect Destination area to paint to
* @param pSrcRect Source area to paint from
* @param pPalette Optional palette to re-map with
* @param nMaskColor Optional transparent color
* @return Error return code
*/
extern ErrorCode paintBitmap(CBofWindow *pWindow, const char *pszFileName, CBofRect *pDstRect = nullptr,
CBofRect *pSrcRect = nullptr, CBofPalette *pPalette = nullptr, int nMaskColor = NOT_TRANSPARENT);
} // namespace SpaceBar
} // namespace Bagel
#endif

View File

@@ -0,0 +1,72 @@
/* 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 "graphics/cursorman.h"
#include "bagel/spacebar/boflib/gfx/cursor.h"
#include "bagel/boflib/stdinc.h"
namespace Bagel {
namespace SpaceBar {
void CBofCursor::initialize() {
show();
}
CBofCursor::~CBofCursor() {
assert(isValidObject(this));
unLoad();
}
ErrorCode CBofCursor::load() {
assert(isValidObject(this));
// kill any previous cursor
unLoad();
return _errCode;
}
ErrorCode CBofCursor::unLoad() {
assert(isValidObject(this));
return _errCode;
}
ErrorCode CBofCursor::set() {
assert(isValidObject(this));
return _errCode;
}
// TODO: This controlled the "Windows cursor" in the original game
// ScummVM doesn't have one, so just show the arrow cursor or
// use CursorMan accordingly
void CBofCursor::hide() {
//CursorMan.showMouse(false);
}
void CBofCursor::show() {
CursorMan.showMouse(true);
}
} // namespace SpaceBar
} // namespace Bagel

View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef BAGEL_BOFLIB_GFX_CURSOR_H
#define BAGEL_BOFLIB_GFX_CURSOR_H
#include "bagel/boflib/error.h"
#include "bagel/boflib/object.h"
namespace Bagel {
namespace SpaceBar {
class CBofCursor : public CBofObject, public CBofError {
public:
CBofCursor() {
}
~CBofCursor();
static void initialize();
ErrorCode load();
ErrorCode unLoad();
ErrorCode set();
static void show();
static void hide();
};
} // namespace SpaceBar
} // namespace Bagel
#endif

View File

@@ -0,0 +1,729 @@
/* 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 "bagel/spacebar/boflib/gfx/sprite.h"
#include "bagel/boflib/misc.h"
namespace Bagel {
namespace SpaceBar {
CBofRect *CBofSprite::_cDirtyRect;
CBofSprite *CBofSprite::_pSpriteChain = nullptr; // Pointer to chain of linked sprites
CBofSprite *CBofSprite::_pTouchedSprite = nullptr; // Pointer to sprite overlapped during painting
CBofBitmap *CBofSprite::_pWorkBmp = nullptr; // Offscreen work area
CBofPalette *CBofSprite::_pSharedPalette = nullptr; // Shared palette for ALL sprites
int CBofSprite::_nWorkDX = 0;
int CBofSprite::_nWorkDY = 0;
void CBofSprite::initialize() {
_cDirtyRect = new CBofRect();
_pSpriteChain = nullptr;
_pTouchedSprite = nullptr;
_pWorkBmp = nullptr;
_pSharedPalette = nullptr;
_nWorkDX = 0;
_nWorkDY = 0;
}
void CBofSprite::shutdown() {
delete _cDirtyRect;
}
void CBofSprite::openLibrary(CBofPalette *pPal) {
// Must have a valid palette to do any sprite related stuff
assert(pPal != nullptr);
clearDirtyRect();
setSharedPalette(pPal);
// Set up a default work area
setupWorkArea(200, 200);
}
void CBofSprite::closeLibrary() {
flushSpriteChain();
tearDownWorkArea();
_pSharedPalette = nullptr;
}
CBofSprite::CBofSprite() {
_pImage = nullptr; // No initial bitmap image for the sprite
_cSize = CBofSize(0, 0); // There is no size to the sprite image
_cRect.setRectEmpty(); // Rectangular bounds not yet defined
_cImageRect = _cRect; // Image rectangle starts same as display bounds
_cPosition = CBofPoint(0, 0); // Default position to upper left corner of display
_bPositioned = false; // Not yet positioned
_bDuplicated = false; // Not sharing resources with other sprites
_nZOrder = SPRITE_TOPMOST; // Default to top most in fore/back ground order
_nCelCount = 1; // Number of frames in animated cel strip
_nCelID = _nCelCount - 1; // Cel identifier not pointing at a cel
_bAnimated = false; // Not initially animated
_bLinked = false; // Not initially linked into the sprite chain
_nMaskColor = NOT_TRANSPARENT; // Default to NO transparency
_bReadOnly = true;
setBlockAdvance(false); // Default always advance next sprite
}
CBofSprite::~CBofSprite() {
assert(isValidObject(this));
unlinkSprite();
clearImage(); // Clear the sprite image bitmap and context
}
void CBofSprite::linkSprite() {
assert(isValidObject(this));
if (!_bLinked) {
// Set for linked into chain
_bLinked = true;
if (_pSpriteChain != nullptr) {
switch (_nZOrder) {
case SPRITE_TOPMOST:
_pSpriteChain->addToTail(this);
break;
case SPRITE_HINDMOST:
_pSpriteChain->addToHead(this);
_pSpriteChain = this;
break;
default: {
CBofSprite *pSprite;
CBofSprite *pLastSprite = pSprite = _pSpriteChain;
while (pSprite != nullptr && pSprite->_nZOrder > _nZOrder) {
pLastSprite = pSprite;
pSprite = (CBofSprite *)pSprite->_pNext;
}
pLastSprite->Insert(this);
break;
}
}
} else {
_pSpriteChain = this;
}
// _pSpriteChain must always point to the head of the linked list
assert(_pSpriteChain == (CBofSprite *)_pSpriteChain->getHead());
}
}
void CBofSprite::unlinkSprite() {
assert(isValidObject(this));
if (_bLinked) {
// Set for not linked into chain
_bLinked = false;
if (_pSpriteChain == this)
_pSpriteChain = (CBofSprite *)_pNext;
Delete();
}
}
void CBofSprite::flushSpriteChain() {
CBofSprite *pSprite = getSpriteChain();
// Cycle getting head of chain, un-linking it and then deleting it
while (pSprite != nullptr) {
pSprite->unlinkSprite();
delete pSprite;
pSprite = getSpriteChain();
}
}
void CBofSprite::setupWorkArea(int dx, int dy) {
// Do we already have a work area?
if (_pWorkBmp != nullptr) {
// Yes, so lets tear it down before we start a new one
tearDownWorkArea();
}
// Create an offscreen bitmap where we do all the work;
_pWorkBmp = new CBofBitmap(dx, dy, _pSharedPalette);
_nWorkDX = dx;
_nWorkDY = dy;
}
void CBofSprite::tearDownWorkArea() {
delete _pWorkBmp;
_pWorkBmp = nullptr;
}
CBofSprite *CBofSprite::duplicateSprite() {
assert(isValidObject(this));
// Create an object for the sprite
CBofSprite *pSprite = new CBofSprite;
duplicateSprite(pSprite);
return pSprite;
}
void CBofSprite::duplicateSprite(CBofSprite *pSprite) {
if (!isValidObject(this) || (pSprite == nullptr))
error("duplicateSprite - Invalid source or destination sprite");
pSprite->_pImage = _pImage;
pSprite->_cRect = _cRect;
pSprite->_cImageRect = _cImageRect;
pSprite->_cSize = _cSize;
pSprite->_cPosition = _cPosition;
pSprite->_nZOrder = _nZOrder;
pSprite->_nCelID = _nCelID;
pSprite->_nCelCount = _nCelCount;
pSprite->_bAnimated = _bAnimated;
pSprite->_nMaskColor = _nMaskColor;
pSprite->_bDuplicated = true; // Mark it as a sprite with shared resources
}
bool CBofSprite::loadSprite(const char *pszPathName, int nCels) {
assert(isValidObject(this));
assert(pszPathName != nullptr);
assert(nCels >= 1);
// Create an object for the sprite's image
CBofBitmap *pBitmap = new CBofBitmap(pszPathName, _pSharedPalette);
return loadSprite(pBitmap, nCels);
}
bool CBofSprite::loadSprite(CBofBitmap *pBitmap, int nCels) {
assert(isValidObject(this));
// Can't load an invalid bitmap
assert(pBitmap != nullptr);
assert(nCels >= 1);
clearImage(); // Clear out any/all existing bitmaps, palettes,
_pImage = pBitmap; // Save pointer to bitmap
pBitmap->setReadOnly(_bReadOnly);
_cSize = pBitmap->getSize();
_cRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1);
_cImageRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1);
_nCelCount = 1;
_nCelID = _nCelCount - 1;
if (nCels != 1) {
setupCels(nCels);
// Assume it's animated
_bAnimated = true;
}
return true; // Return success
}
bool CBofSprite::setupCels(const int nCels) {
assert(isValidObject(this));
assert(nCels > 0);
_nCelCount = nCels; // Set cel count
_nCelID = _nCelCount - 1; // No current cel
int nStripWidth = _cSize.cx; // Temp place toRetain cell strip pixel length
_cSize.cx /= nCels; // Calculate width of a cel
if (_cSize.cx * nCels == nStripWidth) { // Verify we have an even multiple
_cRect.right = _cRect.left + _cSize.cx; // Reset sprite rectangular bounds
_cRect.bottom = _cRect.top + _cSize.cy; // ... based on cel dimensions
_cImageRect.setRect(0, 0, _cSize.cx - 1, _cSize.cy - 1); // Set bounds for first cel in strip
return true;
}
return false;
}
void CBofSprite::nextCel() {
assert(isValidObject(this));
// verify old cel id
assert(_nCelID >= 0 && _nCelID < _nCelCount);
if (getBlockAdvance() == false) {
if (++_nCelID >= _nCelCount)
_nCelID = 0;
setCel(_nCelID);
}
}
void CBofSprite::prevCel() {
assert(isValidObject(this));
// verify old cel id
assert(_nCelID >= 0 && _nCelID < _nCelCount);
if (--_nCelID < 0)
_nCelID = _nCelCount - 1;
setCel(_nCelID);
}
bool CBofSprite::paintSprite(CBofWindow *pWnd, const int x, const int y) {
assert(isValidObject(this));
// Can't paint to a non-existent window
assert(pWnd != nullptr);
// The window MUST have a backdrop
assert(pWnd->getBackdrop() != nullptr);
batchPaint(x, y);
updateDirtyRect(pWnd, this);
return !errorOccurred();
}
bool CBofSprite::paintSprite(CBofBitmap *pBmp, const int x, const int y) {
assert(isValidObject(this));
// Can't paint to a non-existent window
assert(pBmp != nullptr);
batchPaint(x, y);
updateDirtyRect(pBmp, this);
return !errorOccurred();
}
bool CBofSprite::paintCel(CBofWindow *pWnd, int nCelId, const int x, const int y) {
setCel(nCelId - 1);
return paintSprite(pWnd, x, y);
}
bool CBofSprite::paintCel(CBofBitmap *pBmp, int nCelId, const int x, const int y) {
setCel(nCelId - 1);
return paintSprite(pBmp, x, y);
}
void CBofSprite::batchPaint(const int x, const int y) {
assert(isValidObject(this));
CBofRect cDstRect;
// Default to no sprite being overlapped by this painting operation
_pTouchedSprite = nullptr;
// Calculate destination rectangle
cDstRect.setRect(x, y, x + _cSize.cx - 1, y + _cSize.cy - 1);
// Add the destination position to the dirty rectangle list
addToDirtyRect(&cDstRect);
// If the sprite is already on screen, then we must also add it's old
// current location to the dirty rect list so that it is erase properly
if (_bPositioned) {
addToDirtyRect(&_cRect);
}
// Now establish the sprite's new position
setPosition(x, y);
if (_bAnimated && (_nCelCount > 1))
// Advance to the next cel in the strip
nextCel();
}
bool CBofSprite::updateDirtyRect(CBofWindow *pWnd, CBofSprite *pPrimarySprite) {
assert(pWnd != nullptr);
// The window MUST have a backdrop associated with it. If that's not feasible, then
// use CSprites instead of CBofSprites
assert(pWnd->getBackdrop() != nullptr);
//
// Repaint the contents of the specified rectangle
//
CBofBitmap *pBackdrop = pWnd->getBackdrop();
if (pBackdrop != nullptr) {
CBofRect *pRect = _cDirtyRect;
if (pRect->width() != 0 && pRect->height() != 0) {
// Need a work area
CBofBitmap *pWork = _pWorkBmp;
int dx = pRect->width();
int dy = pRect->height();
bool bTempWorkArea = false;
if ((pWork == nullptr) || (dx > _nWorkDX) || (dy > _nWorkDY)) {
bTempWorkArea = true;
pWork = new CBofBitmap(dx, dy, _pSharedPalette);
}
pWork->lock();
// Paint the background into the work area
pBackdrop->paint(pWork, 0, 0, pRect);
// Only need to search the sprite list if current sprite is linked
CBofSprite *pSprite = pPrimarySprite;
if (pPrimarySprite == nullptr || pPrimarySprite->_bLinked) {
pSprite = _pSpriteChain;
}
CBofRect cRect, cSrcRect;
// Run through the sprite list
while (pSprite != nullptr) {
// and paint each partial sprite overlap to the work area
if (pSprite->_bPositioned && cRect.intersectRect(&pSprite->_cRect, pRect)) {
if (pPrimarySprite != pSprite)
_pTouchedSprite = pSprite;
cSrcRect = cRect - pSprite->_cRect.topLeft();
cSrcRect += pSprite->_cImageRect.topLeft();
cRect -= pRect->topLeft();
pSprite->_pImage->paint(pWork, &cRect, &cSrcRect, pSprite->_nMaskColor);
}
pSprite = (CBofSprite *)pSprite->_pNext;
}
// Paint final outcome to the screen
cSrcRect.setRect(0, 0, pRect->width() - 1, pRect->height() - 1);
pWork->paint(pWnd, pRect, &cSrcRect);
pWork->unlock();
if (bTempWorkArea) {
delete pWork;
}
}
}
clearDirtyRect();
return true;
}
bool CBofSprite::updateDirtyRect(CBofBitmap *pBmp, CBofSprite *pPrimarySprite) {
assert(pBmp != nullptr);
//
// Repaint the contents of the specified rectangle
//
CBofRect *pRect = getDirtyRect();
// Only need to search the sprite list if current sprite is linked
CBofSprite *pSprite = pPrimarySprite;
if (pPrimarySprite == nullptr || pPrimarySprite->_bLinked) {
pSprite = _pSpriteChain;
}
CBofRect cRect;
// Run through the sprite list
while (pSprite != nullptr) {
// and paint each partial sprite overlap to the work area
if (pSprite->_bPositioned && cRect.intersectRect(&pSprite->_cRect, pRect)) {
if (pPrimarySprite != pSprite)
_pTouchedSprite = pSprite;
CBofRect cSrcRect = cRect - pSprite->_cRect.topLeft();
cSrcRect += pSprite->_cImageRect.topLeft();
pSprite->_pImage->paint(pBmp, &cRect, &cSrcRect, pSprite->_nMaskColor);
}
pSprite = (CBofSprite *)pSprite->_pNext;
}
clearDirtyRect();
return true;
}
void CBofSprite::addToDirtyRect(CBofRect *pRect) {
assert(pRect != nullptr);
CBofRect cRect;
if (_cDirtyRect->isRectEmpty()) {
cRect = *pRect;
} else {
cRect.unionRect(_cDirtyRect, pRect);
}
*_cDirtyRect = cRect;
}
void CBofSprite::setCel(const int nCelID) {
assert(isValidObject(this));
// All sprites must have at least 1 frame
assert(_nCelCount > 0);
if (_nCelID != nCelID) {
_nCelID = nCelID % _nCelCount;
if ((_nCelID != 0) && (nCelID < 0)) {
_nCelID = _nCelCount + _nCelID;
}
}
// Verify new cel id
assert(_nCelID >= 0 && _nCelID < _nCelCount);
_cImageRect.left = _nCelID * _cSize.cx;
_cImageRect.right = _cImageRect.left + _cSize.cx;
}
bool CBofSprite::eraseSprite(CBofWindow *pWnd) {
assert(isValidObject(this));
assert(pWnd != nullptr);
batchErase();
updateDirtyRect(pWnd);
return !errorOccurred();
}
void CBofSprite::batchErase() {
if (_bPositioned) {
_bPositioned = false;
addToDirtyRect(&_cRect);
}
}
bool CBofSprite::testInterception(CBofSprite *pTestSprite, CBofPoint *pPoint) {
assert(isValidObject(this));
assert(pTestSprite != nullptr);
// Punt if no interception allowed
if (pTestSprite != nullptr) {
// be sure to not test against ourself
if (this != pTestSprite) {
CBofRect overlapRect; // Area of overlap between rectangles
// Use simple rectangle screening first
if (overlapRect.intersectRect(&_cRect, &pTestSprite->_cRect)) {
// ... and if that succeeds, see if we
// ... have image masks that overlap
if ((_nMaskColor == NOT_TRANSPARENT) || (pTestSprite->_nMaskColor == NOT_TRANSPARENT) || spritesOverlap(pTestSprite, pPoint)) {
return true;
}
}
}
}
return false;
}
CBofSprite *CBofSprite::interception(CBofRect *pNewRect, CBofSprite *pTestSprite) {
assert(isValidObject(this));
assert(pNewRect != nullptr);
// Get first sprite to be tested
CBofSprite *pSprite = pTestSprite;
// Thumb through the sprite chain
while (pSprite != nullptr) {
// be sure to not test against ourself
// ... and only test against overlapping sprites
if (this != pSprite) {
CBofRect overlapRect; // Area of overlap between rectangles
// Sprites touch if their rectangles intersect.
// does our sprite overlap another?
if (overlapRect.intersectRect(pNewRect, &pSprite->_cRect))
// ... if so return a pointer to it
return pSprite;
}
// Fetch next sprite in chain for testing
pSprite = (CBofSprite *)pSprite->_pNext;
}
return nullptr;
}
CBofSprite *CBofSprite::interception(CBofSprite *pTestSprite) {
assert(isValidObject(this));
CBofSprite *pSprite = pTestSprite; // Get first sprite to be tested
while (pSprite != nullptr) { // Thumb through the entire sprite collection
if (testInterception(pSprite, nullptr)) // ... testing against each sprite in turn
return pSprite; // found an interception
pSprite = (CBofSprite *)pSprite->_pNext; // fetch next sprite in chain for testing
}
return nullptr;
}
bool CBofSprite::spritesOverlap(CBofSprite *pSprite, CBofPoint *pPoint) {
assert(isValidObject(this));
assert(pSprite != nullptr);
// Assume no overlap
bool bHit = false;
// If the sprite's rectangles overlap
CBofRect overlapRect;
if (overlapRect.intersectRect(&_cRect, &pSprite->_cRect)) {
int32 dx = overlapRect.width();
int32 dy = overlapRect.height();
int32 x1 = overlapRect.left - _cRect.left + _cImageRect.left;
int32 y1 = overlapRect.top - _cRect.top + _cImageRect.top;
int32 x2 = overlapRect.left - pSprite->_cRect.left + pSprite->_cImageRect.left;
int32 y2 = overlapRect.top - pSprite->_cRect.top + pSprite->_cImageRect.top;
int32 dx1 = _pImage->widthBytes();
int32 dx2 = pSprite->_pImage->widthBytes();
byte m1 = (byte)_nMaskColor;
byte m2 = (byte)pSprite->_nMaskColor;
// Lock down these bitmaps
_pImage->lock();
pSprite->_pImage->lock();
byte *pDib1 = (byte *)_pImage->getPixelAddress((int)x1, (int)y1);
byte *pDib2 = (byte *)pSprite->_pImage->getPixelAddress((int)x2, (int)y2);
if (!_pImage->isTopDown()) {
dx1 = -dx1;
}
if (!pSprite->_pImage->isTopDown()) {
dx2 = -dx2;
}
for (int32 y = 0; y < dy; y++) {
byte *pPtr1 = pDib1;
byte *pPtr2 = pDib2;
for (int32 x = 0; x < dx; x++) {
if ((*pPtr1 != m1) && (*pPtr2 != m2)) {
if (pPoint != nullptr) {
pPoint->x = (int)x;
pPoint->y = (int)y;
}
bHit = true;
goto endroutine;
}
pPtr1++;
pPtr2++;
}
pDib1 += dx1;
pDib2 += dx2;
}
}
endroutine:
// Don't need access to these bitmaps any more
pSprite->_pImage->unlock();
_pImage->unlock();
return bHit;
}
void CBofSprite::setPosition(int x, int y) {
assert(isValidObject(this));
// Now have a real location establish the new location of the sprite
// and setup the bitmap's bounding rectangle
_bPositioned = true;
_cPosition.x = x;
_cPosition.y = y;
_cRect.setRect(_cPosition.x, _cPosition.y, _cPosition.x + _cSize.cx - 1, _cPosition.y + _cSize.cy - 1);
}
void CBofSprite::clearImage() {
assert(isValidObject(this));
if (!_bDuplicated && (_pImage != nullptr)) {
delete _pImage;
}
_pImage = nullptr;
}
void CBofSprite::setSharedPalette(CBofPalette *pPal) {
assert(pPal != nullptr);
_pSharedPalette = pPal;
}
void CBofSprite::setZOrder(int nValue) {
assert(isValidObject(this));
assert(nValue >= SPRITE_TOPMOST && nValue <= SPRITE_HINDMOST);
_nZOrder = nValue;
// Relinking this sprite after setting it's new Z-Order will
// add the sprite to the correct Z-Order sorted location (Insertion Sort)
if (_bLinked) {
unlinkSprite();
linkSprite();
}
}
} // namespace SpaceBar
} // namespace Bagel

View File

@@ -0,0 +1,237 @@
/* 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/>.
*
*/
#ifndef BAGEL_BOFLIB_GFX_SPRITE_H
#define BAGEL_BOFLIB_GFX_SPRITE_H
#include "bagel/spacebar/boflib/gfx/bitmap.h"
#include "bagel/boflib/object.h"
#include "bagel/boflib/palette.h"
#include "bagel/spacebar/boflib/gui/window.h"
namespace Bagel {
namespace SpaceBar {
#define SPRITE_TOPMOST 0
#define SPRITE_FOREGROUND 64
#define SPRITE_MIDDLE 128
#define SPRITE_BACKGROUND 192
#define SPRITE_HINDMOST 255
class CBofSprite : public CBofError, public CBofObject, public CLList {
public:
static void initialize();
static void shutdown();
// Constructors
CBofSprite();
// Destructors
virtual ~CBofSprite();
//////////////////////////////////////////
// Implementation
CBofSprite *duplicateSprite();
void duplicateSprite(CBofSprite *pSprite);
bool loadSprite(const char *pszPathName, int nCels = 1);
bool loadSprite(CBofBitmap *pBitmap, int nCels = 1);
bool paintSprite(CBofBitmap *pBmp, int x, int y);
bool paintSprite(CBofBitmap *pBmp, CBofPoint point) {
return paintSprite(pBmp, point.x, point.y);
}
bool paintSprite(CBofWindow *pWnd, int x, int y);
bool paintSprite(CBofWindow *pWnd, CBofPoint point) {
return paintSprite(pWnd, point.x, point.y);
}
bool paintCel(CBofWindow *pWnd, int nCelId, int x, int y);
bool paintCel(CBofBitmap *pBmp, int nCelId, int x, int y);
void batchPaint(int, int y);
void batchErase();
bool setupCels(int nCels);
void setCel(int nCelID);
void nextCel();
void prevCel();
bool refreshSprite(CBofBitmap *pBmp) {
return paintSprite(pBmp, _cPosition.x, _cPosition.y);
}
bool refreshSprite(CBofWindow *pWnd) {
return paintSprite(pWnd, _cPosition.x, _cPosition.y);
}
bool eraseSprite(CBofWindow *pWnd);
// Notice how there is no eraseSprite for a CBofBitmap - that's because
// sprites no longer retain their background, so there would be no way
// to restore the background, and that's all eraseSprite does.
CBofSprite *interception(CBofRect *newRect, CBofSprite *pTestSprite);
CBofSprite *interception(CBofSprite *pTestSprite);
CBofSprite *interception() {
return interception(_pSpriteChain);
}
CBofSprite *interception(CBofRect *newRect) {
return interception(newRect, _pSpriteChain);
}
bool testInterception(CBofSprite *pTestSprite, CBofPoint *pPoint = nullptr);
void setPosition(int x, int y);
CBofPoint getPosition() const {
return _cPosition;
}
CBofSize getSize() const {
return _cSize;
}
CBofRect getRect() const {
return _cRect;
}
int height() const {
return _cRect.height();
}
int width() const {
return _cRect.width();
}
void setMaskColor(int nColor) {
_nMaskColor = nColor;
}
int getMaskColor() const {
return _nMaskColor;
}
byte readPixel(int x, int y) const {
return _pImage->readPixel(x, y);
}
void setZOrder(int nValue);
int getCelCount() const {
return _nCelCount;
}
int getCelIndex() const {
return _nCelID;
}
void setAnimated(bool bAnimated) {
_bAnimated = bAnimated;
}
bool getAnimated() const {
return _bAnimated;
}
void linkSprite();
void unlinkSprite();
const char *getFileName() const {
return _pImage->getFileName();
}
static void openLibrary(CBofPalette *pPal);
static void closeLibrary();
static void setSharedPalette(CBofPalette *pPalette);
static CBofSprite *getSpriteChain() {
return _pSpriteChain;
}
static bool updateDirtyRect(CBofWindow *pWnd, CBofSprite *pPrimarySprite = nullptr);
static bool updateDirtyRect(CBofBitmap *pBmp, CBofSprite *pPrimarySprite = nullptr);
static void addToDirtyRect(CBofRect *pRect);
static void clearDirtyRect() {
_cDirtyRect->setRectEmpty();
}
static CBofRect *getDirtyRect() {
return _cDirtyRect;
}
static void flushSpriteChain();
static void setupWorkArea(int dx, int dy);
static void tearDownWorkArea();
// Add a method for allowing callers of this object to block
// next cell advancement
void setBlockAdvance(bool b = true) {
_bBlockAdvance = b;
}
bool getBlockAdvance() const {
return _bBlockAdvance;
}
private:
void clearImage();
bool spritesOverlap(CBofSprite *pSprite, CBofPoint *pPoint = nullptr);
bool _bBlockAdvance; // Allow block next cell.
public:
CBofBitmap *_pImage; // Bitmap for the sprite
protected:
CBofPoint _cPosition; // Upper left corner of sprite on display
CBofSize _cSize; // dx/dy size of the sprite bitmap
CBofRect _cRect; // Bounding rectangle on display
CBofRect _cImageRect; // Bounding rectangle within image bitmap
int _nMaskColor; // Transparent color index for this sprite
int _nZOrder; // Foreground / background order
int _nCelID; // Index of current cel image
int _nCelCount; // Number of cels in the animation strip
bool _bDuplicated : 1; // Shares bitmaps with some other sprite
bool _bPositioned : 1; // Whether sprite has been positioned yet
bool _bAnimated : 1; // Whether cel advance occurs when painting
bool _bLinked : 1; // Whether sprite is linked into the chain
bool _bReadOnly : 1; // Whether image is read only or not
static CBofRect *_cDirtyRect;
static CBofSprite *_pSpriteChain; // Pointer to linked chain of sprites
static CBofSprite *_pTouchedSprite; // Sprite touched during painting operation
static CBofBitmap *_pWorkBmp; // Offscreen work area
static CBofPalette *_pSharedPalette; // Shared palette for ALL sprites
static int _nWorkDX;
static int _nWorkDY;
};
} // namespace SpaceBar
} // namespace Bagel
#endif

View File

@@ -0,0 +1,476 @@
/* 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 "graphics/fonts/ttf.h"
#include "bagel/spacebar/boflib/app.h"
#include "bagel/spacebar/boflib/gfx/text.h"
namespace Bagel {
namespace SpaceBar {
#define START_SIZE 8
#define MONO_FONT "LiberationMono-Regular.ttf"
#define SERIF_FONT_REGULAR "LiberationSans-Regular.ttf"
#define SERIF_FONT_BOLD "LiberationSans-Bold.ttf"
#define TAB_SIZE 50
int CBofText::_tabStop;
bool CBofText::_initialized;
Graphics::Font *CBofText::_defaultFonts[NUM_POINT_SIZES];
Graphics::Font *CBofText::_fixedFonts[NUM_POINT_SIZES];
ErrorCode CBofText::initialize() {
_initialized = true;
_tabStop = 20; // tabstops every 20 pixels
Common::fill(_defaultFonts, _defaultFonts + NUM_POINT_SIZES,
(Graphics::Font *)nullptr);
Common::fill(_fixedFonts, _fixedFonts + NUM_POINT_SIZES,
(Graphics::Font *)nullptr);
return ERR_NONE;
}
ErrorCode CBofText::shutdown() {
for (int i = 0; i < NUM_POINT_SIZES; i++) {
delete _defaultFonts[i];
delete _fixedFonts[i];
}
_initialized = false;
return ERR_NONE;
}
CBofText::CBofText() {
initializeFields(); // Initialize stuff
}
CBofText::CBofText(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
// Can't access null pointers
assert(pRect != nullptr);
// Initialize stuff
initializeFields();
// Build the work areas
setupText(pRect, nJustify, nFormatFlags);
}
CBofText::~CBofText() {
delete _pWork;
_pWork = nullptr;
delete _pBackground;
_pBackground = nullptr;
}
void CBofText::initializeFields() {
_pBackground = nullptr;
_pWork = nullptr;
_bSaved = false;
_cPosition = CBofPoint(0, 0);
_cSize = CBofSize(0, 0);
_cRect.setRect(0, 0, 0, 0);
_cShadowColor = RGB(0, 0, 0);
_nShadow_DX = 0;
_nShadow_DY = 0;
_nJustify = JUSTIFY_LEFT;
_nFormatFlags = FORMAT_DEFAULT;
_bMultiLine = false;
_nCurSize = 10;
_nCurWeight = TEXT_DONTCARE;
_cTextColor = CTEXT_COLOR;
}
ErrorCode CBofText::setupText(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
// Can't access null pointers
assert(pRect != nullptr);
_nJustify = nJustify;
// Setup the fields for location and size of the text area
_cRect = *pRect;
_cSize.cx = _cRect.width();
_cSize.cy = _cRect.height();
delete _pWork;
_pWork = nullptr;
delete _pBackground;
_pBackground = nullptr;
CBofPalette *pPalette = CBofApp::getApp()->getPalette();
// Create a bitmap to serve as our work area as we output text
_pWork = new CBofBitmap(_cSize.cx, _cSize.cy, pPalette);
// Create a bitmap to hold the background we overwrite
_pBackground = new CBofBitmap(_cSize.cx, _cSize.cy, pPalette);
return _errCode;
}
ErrorCode CBofText::setupTextOpt(const CBofRect *pRect, int nJustify, uint32 nFormatFlags) {
// Can't access null pointers
assert(pRect != nullptr);
_nJustify = nJustify;
_nFormatFlags = nFormatFlags;
// Setup the fields for location and size of the text area
_cRect = *pRect;
_cSize.cx = _cRect.width();
_cSize.cy = _cRect.height();
return _errCode;
}
ErrorCode CBofText::erase(CBofWindow *pWnd) {
// Can't access null pointers
assert(pWnd != nullptr);
if (_pBackground != nullptr && _bSaved) {
// Simply splat the background art back where it came from
_errCode = _pBackground->paint(pWnd, &_cRect);
}
return _errCode;
}
ErrorCode CBofText::erase(CBofBitmap *pBmp) {
// Can't access null pointers
assert(pBmp != nullptr);
if (_pBackground != nullptr && _bSaved) {
// Simply splat the background art back where it came from
_errCode = _pBackground->paint(pBmp, &_cRect);
}
return _errCode;
}
ErrorCode CBofText::display(CBofWindow *pWnd, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, int nFont) {
assert(isValidObject(this));
// Can't access null pointers
assert(pWnd != nullptr);
_cTextColor = cColor;
return displayText(pWnd, pszText, &_cRect, nSize, nWeight, false, nFont);
}
ErrorCode CBofText::display(CBofWindow *pWnd) {
assert(isValidObject(this));
assert(pWnd != nullptr);
return display(pWnd, _cCurString, _nCurSize, _nCurWeight, _cTextColor);
}
ErrorCode CBofText::display(CBofBitmap *pBmp) {
assert(isValidObject(this));
assert(pBmp != nullptr);
return display(pBmp, _cCurString, _nCurSize, _nCurWeight, _cTextColor);
}
ErrorCode CBofText::display(CBofBitmap *pBmp, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, int nFont) {
// Can't access null pointers
assert(pBmp != nullptr);
_cTextColor = cColor;
return displayText(pBmp, pszText, &_cRect, nSize, nWeight, false, nFont);
}
ErrorCode CBofText::displayShadowed(CBofWindow *pWnd, const char *pszText, const int nSize, const int nWeight, const COLORREF cColor, const COLORREF cShadow, const int nDX, const int nDY, int nFont) {
// Can't access null pointers
assert(pWnd != nullptr);
_cTextColor = cColor;
_cShadowColor = cShadow;
_nShadow_DX = nDX;
_nShadow_DY = nDY;
return displayText(pWnd, pszText, &_cRect, nSize, nWeight, true, nFont);
}
ErrorCode CBofText::displayText(CBofWindow *pWnd, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
assert(isValidObject(this));
assert(pWnd != nullptr);
assert(pszText != nullptr);
assert(pRect != nullptr);
CBofRect cRect(0, 0, pRect->width() - 1, pRect->height() - 1);
assert(_pBackground != nullptr);
assert(_pWork != nullptr);
if (!_bSaved) {
CBofBitmap::setUseBackdrop(true);
_pBackground->captureScreen(pWnd, pRect);
CBofBitmap::setUseBackdrop(false);
_bSaved = true;
}
_pBackground->paint(_pWork, 0, 0);
displayTextEx(_pWork, pszText, &cRect, nSize, nWeight, bShadowed, nFont);
_pWork->paint(pWnd, pRect);
return _errCode;
}
ErrorCode CBofText::displayText(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
assert(isValidObject(this));
assert(pBmp != nullptr);
assert(pszText != nullptr);
assert(pRect != nullptr);
CBofRect cRect(0, 0, pRect->width() - 1, pRect->height() - 1);
assert(_pWork != nullptr);
assert(_pBackground != nullptr);
if (!_bSaved) {
CBofRect r = _pBackground->getRect();
pBmp->paint(_pBackground, &r, pRect);
_bSaved = true;
}
_pBackground->paint(_pWork, 0, 0);
displayTextEx(_pWork, pszText, &cRect, nSize, nWeight, bShadowed, nFont);
_pWork->paint(pBmp, pRect);
return _errCode;
}
Graphics::Font *CBofText::getFont(int nFont, int nSize, int nWeight) {
Graphics::Font *font;
// Attempt to use one of the fonts that we pre-allocated
if (nFont != FONT_MONO) {
font = _defaultFonts[nSize - START_SIZE];
} else {
font = _fixedFonts[nSize - START_SIZE];
}
// Last resort - create the font now
if (font == nullptr) {
if (nFont != FONT_MONO) {
font = Graphics::loadTTFFontFromArchive(SERIF_FONT_REGULAR, nSize, Graphics::kTTFSizeModeCell);
_defaultFonts[nSize - START_SIZE] = font;
} else {
font = Graphics::loadTTFFontFromArchive(MONO_FONT, nSize, Graphics::kTTFSizeModeCell);
_fixedFonts[nSize - START_SIZE] = font;
}
}
return font;
}
ErrorCode CBofText::displayTextEx(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, const int nSize, const int nWeight, const bool bShadowed, int nFont) {
assert(isValidObject(this));
// can't access null pointers
assert(pBmp != nullptr);
assert(pszText != nullptr);
assert(pRect != nullptr);
Graphics::ManagedSurface surface = pBmp->getSurface();
Graphics::Font *font = getFont(nFont, nSize, nWeight);
int color;
// Split lines
Common::U32StringArray lines;
font->wordWrapText(Common::U32String(pszText, Common::kWindows1252), pRect->width(), lines);
// Iterate the lines to get the maximum width
int maxWidth = 0;
for (uint i = 0; i < lines.size(); ++i)
maxWidth = MAX(maxWidth, font->getStringWidth(lines[i]));
Common::Point textInfo(maxWidth, (int)lines.size() * font->getFontHeight());
_cPosition.y = (_cSize.cy - textInfo.y) >> 1;
Graphics::TextAlign align = Graphics::kTextAlignLeft;
switch (_nJustify) {
case JUSTIFY_CENTER:
_cPosition.x = (_cSize.cx - textInfo.x) >> 1;
align = Graphics::kTextAlignCenter;
break;
case JUSTIFY_LEFT:
// align left
_cPosition.x = 0;
break;
case JUSTIFY_RIGHT:
_cPosition.x = _cSize.cx - textInfo.x;
align = Graphics::kTextAlignRight;
break;
case JUSTIFY_WRAP:
// Align left
_bMultiLine = true;
break;
default:
break;
}
// text starts relative to area for painting
_cPosition += pRect->topLeft();
// Note: Under ScummVM, even single line drawing uses the multiLine code
Common::Rect newRect = *pRect;
if ((_nFormatFlags & FORMAT_TOP_CENTER) == FORMAT_TOP_CENTER) {
int h = lines.size() * font->getFontHeight();
newRect.top = (newRect.top + newRect.bottom) / 2 - h / 2;
newRect.bottom = newRect.top + h;
}
Common::Rect shadowRect = newRect;
shadowRect.translate(_nShadow_DX, _nShadow_DY);
for (uint i = 0; i < lines.size(); ++i) {
const Common::U32String &line = lines[i];
if (bShadowed) {
color = CBofApp::getApp()->getPalette()->getNearestIndex(_cShadowColor);
displayLine(font, surface, line, shadowRect.left, shadowRect.top,
shadowRect.width(), color, align);
}
color = CBofApp::getApp()->getPalette()->getNearestIndex(_cTextColor);
displayLine(font, surface, line, newRect.left, newRect.top,
newRect.width(), color, align);
newRect.top += font->getFontHeight();
shadowRect.top += font->getFontHeight();
}
return _errCode;
}
void CBofText::displayLine(Graphics::Font *font, Graphics::ManagedSurface &surface,
const Common::U32String &line, int left, int top, int width, int color, Graphics::TextAlign align) {
if (!line.contains('\t')) {
font->drawString(&surface, line, left, top, width, color, align);
} else {
// Special rendering of tabbed text
Common::U32String str = line;
while (!str.empty()) {
if (str[0] == '\t') {
// Move to next tab stop
left = (left + TAB_SIZE) / TAB_SIZE * TAB_SIZE;
str.deleteChar(0);
} else {
Common::U32String fragment;
size_t tab = str.findFirstOf('\t');
if (tab == Common::U32String::npos) {
fragment = str;
str.clear();
} else {
fragment = Common::U32String(str.c_str(), str.c_str() + tab);
str = Common::U32String(str.c_str() + tab);
}
int fragmentWidth = font->getStringWidth(fragment);
font->drawString(&surface, fragment, left, top, width, color, align);
left += fragmentWidth;
width -= fragmentWidth;
}
}
}
}
ErrorCode paintText(CBofWindow *pWnd, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
assert(pWnd != nullptr);
assert(pRect != nullptr);
CBofText cText(pRect, nJustify, nFormatFlags);
return cText.display(pWnd, pszString, nSize, nWeight, cColor, nFont);
}
ErrorCode paintText(CBofBitmap *pBmp, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
assert(pBmp != nullptr);
assert(pRect != nullptr);
CBofText cText;
cText.setupTextOpt(pRect, nJustify, nFormatFlags);
cText.setColor(cColor);
return cText.displayTextEx(pBmp, pszString, pRect, nSize, nWeight, false, nFont);
}
ErrorCode paintShadowedText(CBofBitmap *pBmp, CBofRect *pRect, const char *pszString, const int nSize, const int nWeight, const COLORREF cColor, int nJustify, uint32 nFormatFlags, int nFont) {
assert(pBmp != nullptr);
assert(pRect != nullptr);
CBofText cText;
cText.setupTextOpt(pRect, nJustify, nFormatFlags);
cText.setColor(cColor);
cText.setShadowColor(CTEXT_SHADOW_COLOR);
cText.setShadowSize(CTEXT_SHADOW_DX, CTEXT_SHADOW_DY);
return cText.displayTextEx(pBmp, pszString, pRect, nSize, nWeight, true, nFont);
}
CBofRect calculateTextRect(CBofWindow *pWnd, const CBofString *pStr, int nSize, int nFont) {
return calculateTextRect(pWnd->getRect(), pStr, nSize, nFont);
}
CBofRect calculateTextRect(CBofRect rect, const CBofString *pStr, int nSize, int nFont) {
// Get the font to use
Graphics::Font *font = CBofText::getFont(nFont, nSize, TEXT_NORMAL);
// Wrap the text as necessary
Common::U32StringArray lines;
font->wordWrapText(Common::U32String(pStr->getBuffer(), Common::kWindows1252), rect.width(), lines);
// Iterate the lines to get the maximum width
int maxWidth = 0;
for (uint i = 0; i < lines.size(); ++i)
maxWidth = MAX(maxWidth, font->getStringWidth(lines[i]));
return CBofRect(0, 0, maxWidth, (int)lines.size() * font->getFontHeight());
}
} // namespace SpaceBar
} // namespace Bagel

View File

@@ -0,0 +1,340 @@
/* 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/>.
*
*/
#ifndef BAGEL_BOFLIB_GFX_TEXT_H
#define BAGEL_BOFLIB_GFX_TEXT_H
#include "graphics/font.h"
#include "bagel/boflib/object.h"
#include "bagel/spacebar/boflib/gfx/bitmap.h"
#include "bagel/boflib/error.h"
#include "bagel/boflib/string.h"
namespace Bagel {
namespace SpaceBar {
#define NUM_POINT_SIZES 32
// Text color and offset definitions
#define CTEXT_COLOR RGB(0,0,0)
#define CTEXT_SHADOW_COLOR RGB(0,0,0)
#define CTEXT_YELLOW RGB(255, 255, 0)
#define CTEXT_WHITE RGB(255, 255, 255)
#define CTEXT_SHADOW_DX 2
#define CTEXT_SHADOW_DY 2
// Text justification definitions
enum {
JUSTIFY_CENTER = 0,
JUSTIFY_LEFT = 1,
JUSTIFY_RIGHT = 2,
JUSTIFY_WRAP = 3
};
// Text weight definitions
//
/*
* DrawText Format Flags
*/
#define DT_TOP 0x00000000
#define DT_LEFT 0x00000000
#define DT_CENTER 0x00000001
#define DT_RIGHT 0x00000002
#define DT_VCENTER 0x00000004
#define DT_BOTTOM 0x00000008
#define DT_WORDBREAK 0x00000010
#define DT_SINGLELINE 0x00000020
#define DT_EXPANDTABS 0x00000040
#define DT_TABSTOP 0x00000080
#define DT_NOCLIP 0x00000100
#define DT_EXTERNALLEADING 0x00000200
#define DT_CALCRECT 0x00000400
#define DT_NOPREFIX 0x00000800
#define DT_intERNAL 0x00001000
enum {
FW_NORMAL,
FW_BOLD,
FW_MEDIUM,
};
#define FONT_DEFAULT 0
#define FONT_MONO 1
#define TEXT_DONTCARE 0
#define TEXT_THIN FW_THIN
#define TEXT_EXTRALIGHT FW_EXTRALIGHT
#define TEXT_ULTRALIGHT FW_ULTRALIGHT
#define TEXT_LIGHT FW_LIGHT
#define TEXT_NORMAL FW_NORMAL
#define TEXT_REGULAR FW_REGULAR
#define TEXT_MEDIUM FW_MEDIUM
#define TEXT_SEMIBOLD FW_SEMIBOLD
#define TEXT_DEMIBOLD FW_DEMIBOLD
#define TEXT_BOLD FW_BOLD
#define TEXT_EXTRABOLD FW_EXTRABOLD
#define TEXT_ULTRABOLD FW_ULTRABOLD
#define TEXT_BLACK FW_BLACK
#define TEXT_HEAVY FW_HEAVY
#define FORMAT_TOP_LEFT ( DT_TOP | DT_LEFT )
#define FORMAT_TOP_RIGHT ( DT_TOP | DT_RIGHT )
#define FORMAT_TOP_CENTER ( DT_TOP | DT_CENTER )
#define FORMAT_BOT_LEFT ( DT_BOTTOM | DT_LEFT )
#define FORMAT_BOT_RIGHT ( DT_BOTTOM | DT_RIGHT )
#define FORMAT_BOT_CENTER ( DT_BOTTOM | DT_CENTER )
#define FORMAT_CENTER_LEFT ( DT_VCENTER | DT_LEFT )
#define FORMAT_CENTER_RIGHT ( DT_VCENTER | DT_RIGHT )
#define FORMAT_CENTER_CENTER ( DT_VCENTER | DT_CENTER )
#define FORMAT_SINGLE_LINE DT_SINGLELINE
#define FORMAT_MULTI_LINE DT_WORDBREAK
#define FORMAT_DEFAULT ( FORMAT_TOP_LEFT | FORMAT_MULTI_LINE )
#define FONT_DEFAULT_SIZE (-14)
#define FONT_8POINT 8
#define FONT_10POINT 10
#define FONT_12POINT 12
#define FONT_14POINT 14
#define FONT_15POINT 15
#define FONT_18POINT 18
#define FONT_20POINT 20
#define TEXT_DEFAULT_FACE TEXT_BOLD
class CBofText : public CBofObject, public CBofError {
public:
// Constructors
CBofText();
CBofText(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
virtual ~CBofText();
// Implementation
//
/**
* Build primary data objects and work areas; text will be displayed
* centered within the defined rectangular area, hence it is up to
* the caller to ensure that the text fits (excess is cropped).
* @param pRect Rectangular area encompassed by the text object
* @param nJustify Alignment of text in the rectangle
* @param nFormatFlags Format flag
*/
ErrorCode setupText(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
ErrorCode setupTextOpt(const CBofRect *pRect, int nJustify = JUSTIFY_CENTER, uint32 nFormatFlags = FORMAT_DEFAULT);
void setText(const CBofString &cString) {
_cCurString = cString;
}
void setColor(const COLORREF cColor) {
_cTextColor = cColor;
}
void SetSize(const int nSize) {
_nCurSize = nSize;
}
void setWeight(const int nWeight) {
_nCurWeight = nWeight;
}
void setShadowColor(const COLORREF cColor) {
_cShadowColor = cColor;
}
void setShadowSize(int nDX, int nDY) {
_nShadow_DX = nDX;
_nShadow_DY = nDY;
}
CBofString getText() const {
return _cCurString;
}
COLORREF getColor() const {
return _cTextColor;
}
int getSize() const {
return _nCurSize;
}
int getWeight() const {
return _nCurWeight;
}
/**
* Restores the background behind current text on screen
* @param pWnd Window to erase text from
* @return Error return Code
*/
ErrorCode erase(CBofWindow *pWnd);
/**
* Restores the background behind current text offscreen
* @param pBmp Offscreen bitmap to erase text from
* @return Error return Code
*/
ErrorCode erase(CBofBitmap *pBmp);
/**
* Re-displays current text, formatted with current attribs
* @param pWnd Window to paint into
* @return Error return Code
*/
ErrorCode display(CBofWindow *pWnd);
/**
* Re-displays current text, formatted with current attribs
* @param pBmp Bitmap to paint into
* @return Error return Code
*/
ErrorCode display(CBofBitmap *pBmp);
/**
* Display a text string, formatted in the current text area
* @param pWnd Window to paint into
* @param pszText Point to text string to be displayed
* @param nSize Point size of the text to be used
* @param nWeight Weighting of the font (FW_ identifier)
* @param cColor Color that the text will be
* @param nFont Font used (default or mono)
* @return Error return Code
*/
ErrorCode display(CBofWindow *pWnd, const char *pszText, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nFont = FONT_DEFAULT);
/**
* Display a text string, formatted in the current text area
* @param pBmp Bitmap to paint into
* @param pszText Point to text string to be displayed
* @param nSize Point size of the text to be used
* @param nWeight Weighting of the font (FW_ identifier)
* @param cColor Color that the text will be
* @param nFont Font used (default or mono)
* @return Error return Code
*/
ErrorCode display(CBofBitmap *pBmp, const char *pszText, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nFont = FONT_DEFAULT);
/**
* Display a shadowed text string into the current text area
* @param pWnd Window to paint into
* @param pszText Point to text string to be displayed
* @param nSize Point size of the text to be used
* @param nWeight Weighting of the font (FW_ identifier)
* @param cColor Color that the text will be
* @param cShadow Color that the text's shadow will be
* @param nDX Shadow DX
* @param nDY Shadow DY
* @param nFont Font used (default or mono)
* @return Error return Code
*/
ErrorCode displayShadowed(CBofWindow *pWnd, const char *pszText, int nSize,
int nWeight, COLORREF cColor, COLORREF cShadow = CTEXT_SHADOW_COLOR,
int nDX = CTEXT_SHADOW_DX, int nDY = CTEXT_SHADOW_DY, int nFont = FONT_DEFAULT);
void flushBackground() {
_bSaved = false;
}
static ErrorCode initialize();
static ErrorCode shutdown();
/**
* Displays specified text onto specified bitmap
* @param pBmp Bitmap to paint text onto
* @param pszText Pointer to text string to be displayed
* @param pRect Area to paint text to
* @param nSize Point size of the text to be used
* @param nWeight Weighting of the font (FW_ identifier)
* @param bShadowed Whether the text is shadowed
* @param nFont Font used (default or mono)
* @return Error return Code
*/
ErrorCode displayTextEx(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
static Graphics::Font *getFont(int nFont, int nSize, int nWeight);
private:
/**
* Initializes key fields to zero or nullptr states.
*/
void initializeFields();
/**
* Displays specified text onto specified bitmap
* @param pWnd Window to paint text onto
* @param pszText Pointer to text string to be displayed
* @param pRect Area to paint text to
* @param nSize Point size of the text to be used
* @param nWeight Weighting of the font (FW_ identifier)
* @param bShadowed Whether the text is shadowed
* @param nFont Font used (default or mono)
* @return Error return Code
*/
ErrorCode displayText(CBofWindow *pWnd, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
ErrorCode displayText(CBofBitmap *pBmp, const char *pszText, CBofRect *pRect, int nSize, int nWeight, bool bShadowed, int nFont = FONT_DEFAULT);
void displayLine(Graphics::Font *font, Graphics::ManagedSurface &surface, const Common::U32String &line,
int left, int top, int width, int color, Graphics::TextAlign align);
protected:
CBofString _cCurString; // text to be displayed
CBofRect _cRect; // bounding rectangle of text area
CBofPoint _cPosition; // upper left corner of text displayed
CBofSize _cSize; // dx/dy size of the text bitmap
COLORREF _cTextColor; // color to use for the text itself
COLORREF _cShadowColor; // color to use for the text's shadow
CBofBitmap *_pBackground; // bitmap for the text's background
CBofBitmap *_pWork; // bitmap for the work area
int _nCurSize; // point size of current text
int _nCurWeight; // style of current text
int _nJustify; // positioning within the rectangle
int _nShadow_DX; // horizontal offset for shadow
int _nShadow_DY; // vertical offset for shadow
uint32 _nFormatFlags; // multi line formatting flags
bool _bMultiLine; // multi vs single line formatting
bool _bSaved;
static Graphics::Font *_defaultFonts[NUM_POINT_SIZES];
static Graphics::Font *_fixedFonts[NUM_POINT_SIZES];
static bool _initialized;
static int _tabStop; // tabstop table
};
// Global text functions
//
ErrorCode paintText(CBofWindow *pWnd, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 nFormat = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
ErrorCode paintText(CBofBitmap *pBmp, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 nFormat = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
ErrorCode paintShadowedText(CBofBitmap *, CBofRect *pRect, const char *, int nSize, int nWeight, COLORREF cColor = CTEXT_COLOR, int nJustify = JUSTIFY_CENTER, uint32 n = FORMAT_DEFAULT, int nFont = FONT_DEFAULT);
/**
* Utility routine that will calculate the rectangle that a text string
* will fit in, given point size and font.
*/
CBofRect calculateTextRect(CBofWindow *pWnd, const CBofString *pStr, int nSize, int nFont);
CBofRect calculateTextRect(CBofRect rect, const CBofString *pStr, int nSize, int nFont);
} // namespace SpaceBar
} // namespace Bagel
#endif