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

View File

@@ -0,0 +1,229 @@
/* 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 "common/textconsole.h"
#include "bagel/mfc/gfx/blitter.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
static inline void copyPixel(const byte *srcP, byte *destP, int mode, const byte &WHITE,
bool isDestMonochrome, uint bgColor, const uint32 *paletteMap) {
byte src = *srcP;
if (paletteMap)
src = paletteMap[src];
switch (mode) {
case SRCCOPY:
*destP = src;
break;
case SRCAND:
*destP &= src;
break;
case SRCINVERT:
*destP ^= src;
break;
case SRCPAINT:
*destP |= src;
break;
case NOTSRCCOPY:
if (isDestMonochrome) {
*destP = src == bgColor ? 0 : 0xff;
return;
}
*destP = ~src;
break;
case DSTINVERT:
*destP = ~*destP;
return;
case BLACKNESS:
*destP = 0;
return;
case WHITENESS:
*destP = WHITE;
return;
default:
error("Unsupported blit mode");
break;
}
if (isDestMonochrome)
*destP = *destP == bgColor ? 0xff : 0;
}
static void blitInner(Gfx::Surface *srcSurface,
Gfx::Surface *destSurface,
const Common::Rect &srcRect, const Common::Point &destPos,
uint bgColor, int mode, const uint32 *paletteMap) {
const bool isDestMonochrome = destSurface->format.bytesPerPixel == 1 &&
destSurface->format.aLoss == 255;
const byte WHITE = 255;
Surface::YIterator ySrc(srcSurface);
Surface::XIterator xSrc(&ySrc);
Surface::YIterator yDest(destSurface);
Surface::XIterator xDest(&yDest);
byte dummy = 0;
byte *srcP, *destP;
for (ySrc = srcRect.top, yDest = destPos.y; ySrc < srcRect.bottom; ++ySrc, ++yDest) {
for (xSrc = srcRect.left, xDest = destPos.x; xSrc < srcRect.right; ++xSrc, ++xDest) {
srcP = xSrc;
destP = xDest;
if (!srcP)
srcP = &dummy;
if (!destP)
destP = &dummy;
copyPixel(srcP, destP, mode, WHITE, isDestMonochrome, bgColor, paletteMap);
}
}
}
static void stretchBlitInner(Gfx::Surface *srcSurface,
Gfx::Surface *destSurface,
const Common::Rect &srcRect, const Common::Rect &dstRect,
uint bgColor, int mode, const uint32 *paletteMap) {
const bool isDestMonochrome = destSurface->format.bytesPerPixel == 1 &&
destSurface->format.aLoss == 255;
const byte WHITE = 255;
const int srcWidth = srcRect.right - srcRect.left;
const int srcHeight = srcRect.bottom - srcRect.top;
const int dstWidth = dstRect.right - dstRect.left;
const int dstHeight = dstRect.bottom - dstRect.top;
Surface::YIterator ySrc(srcSurface);
Surface::XIterator xSrc(&ySrc);
Surface::YIterator yDest(destSurface);
Surface::XIterator xDest(&yDest);
if (srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0)
return; // Invalid rectangles
for (int y = 0; y < dstHeight; ++y) {
// Map destination y to source y using fixed-point arithmetic
int srcY = srcRect.top + (y * srcHeight) / dstHeight;
if (srcY >= srcSurface->h)
continue;
int dstY = dstRect.top + y;
if (dstY >= destSurface->h)
continue;
for (int x = 0; x < dstWidth; ++x) {
int srcX = srcRect.left + (x * srcWidth) / dstWidth;
if (srcX >= srcSurface->w)
continue;
int dstX = dstRect.left + x;
if (dstX >= destSurface->w)
continue;
xSrc = srcX;
ySrc = srcY;
byte *srcP = xSrc;
xDest = dstX;
yDest = dstY;
byte *destP = xDest;
copyPixel(srcP, destP, mode, WHITE, isDestMonochrome, bgColor, paletteMap);
}
}
}
void blit(Gfx::Surface *src, Gfx::Surface *dest,
const Common::Rect &srcRect, const Common::Point &destPos,
uint bgColor, int mode, const uint32 *paletteMap) {
// For normal copying modes, the formats must match.
// Other modes like DSTINVERT don't need a source,
// so in that case the source can remain uninitialized
assert(src->format.bytesPerPixel == dest->format.bytesPerPixel ||
src->format.bytesPerPixel == 0);
assert(dest->format.bytesPerPixel == dest->format.bytesPerPixel ||
dest->format.bytesPerPixel == 0);
blitInner(src, dest, srcRect, destPos, bgColor, mode, paletteMap);
Common::Rect dirtyRect(destPos.x, destPos.y,
destPos.x + srcRect.width(), destPos.y + srcRect.height());
dest->addDirtyRect(dirtyRect);
}
void stretchBlit(Gfx::Surface *src, Gfx::Surface *dest,
const Common::Rect &srcRect, const Common::Rect &destRect,
uint bgColor, int mode, const uint32 *paletteMap) {
assert(src->format.bytesPerPixel == dest->format.bytesPerPixel ||
src->format.bytesPerPixel == 0);
assert(dest->format.bytesPerPixel == dest->format.bytesPerPixel ||
dest->format.bytesPerPixel == 0);
stretchBlitInner(src, dest, srcRect, destRect, bgColor, mode, paletteMap);
}
static inline void rasterPixel(byte *pixel, byte) {
// Currently only R2_NOT
*pixel = ~*pixel;
}
void frameRect(Gfx::Surface *dest,
const Common::Rect &r, byte color, int drawMode) {
assert(dest->format.bytesPerPixel == 1);
if (drawMode == R2_COPYPEN) {
dest->frameRect(r, color);
return;
} else if (drawMode == R2_NOP) {
return;
}
assert(drawMode == R2_NOT);
const int w = r.right - r.left;
const int h = r.bottom - r.top - 2;
byte *pixel;
// Top line
pixel = (byte *)dest->getBasePtr(r.left, r.top);
for (int x = 0; x < w; ++x, ++pixel)
rasterPixel(pixel, color);
// Bottom line
pixel = (byte *)dest->getBasePtr(r.left, r.bottom - 1);
for (int x = 0; x < w; ++x, ++pixel)
rasterPixel(pixel, color);
// Left edge
pixel = (byte *)dest->getBasePtr(r.left, r.top + 1);
for (int y = 0; y < h; ++y, pixel += dest->pitch)
rasterPixel(pixel, color);
// Right edge
pixel = (byte *)dest->getBasePtr(r.right - 1, r.top + 1);
for (int y = 0; y < h; ++y, pixel += dest->pitch)
rasterPixel(pixel, color);
// Mark the rectangle area as dirty
dest->addDirtyRect(r);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,46 @@
/* 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_MFC_GFX_BLITTER_H
#define BAGEL_MFC_GFX_BLITTER_H
#include "bagel/mfc/gfx/surface.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
extern void blit(Gfx::Surface *src, Gfx::Surface *dest,
const Common::Rect &srcRect, const Common::Point &destPos,
uint bgColor, int mode, const uint32 *paletteMap);
extern void stretchBlit(Gfx::Surface *src, Gfx::Surface *dest,
const Common::Rect &srcRect, const Common::Rect &destRect,
uint bgColor, int mode, const uint32 *paletteMap);
extern void frameRect(Gfx::Surface *dest,
const Common::Rect &r, byte color, int drawMode);
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,186 @@
/* 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 "graphics/wincursor.h"
#include "image/bmp.h"
#include "bagel/mfc/gfx/cursor.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
static const byte ARROW_CURSOR[CURSOR_W * CURSOR_H] = {
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0,
1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0,
1, 2, 1, 0, 0, 1, 2, 2, 1, 0, 0, 0,
1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
};
static const byte HOURGLASS_CURSOR[CURSOR_W * CURSOR_H] = {
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
0, 0, 1, 2, 2, 2, 2, 2, 2, 1, 0, 0,
0, 0, 1, 2, 2, 2, 2, 2, 2, 1, 0, 0,
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const byte CURSOR_PALETTE[9] = { 0x80, 0x80, 0x80, 0, 0, 0, 0xff, 0xff, 0xff };
/*--------------------------------------------*/
Cursors::Cursors(Libs::Resources &res) /* : _resources(res) */ {
_cursors[(intptr)IDC_ARROW] = new Cursor(ARROW_CURSOR);
_cursors[(intptr)IDC_WAIT] = new Cursor(HOURGLASS_CURSOR);
_arrowCursor = (HCURSOR)_cursors[(intptr)IDC_ARROW];
_waitCursor = (HCURSOR)_cursors[(intptr)IDC_WAIT];
}
Cursors::~Cursors() {
for (CursorHash::iterator it = _cursors.begin();
it != _cursors.end(); ++it)
delete it->_value;
}
HCURSOR Cursors::loadCursor(intptr cursorId) {
if (!cursorId)
// Null cursor used to hide cursor
return (HCURSOR)nullptr;
if (_cursors.contains(cursorId))
return (HCURSOR)_cursors[cursorId];
Cursor *c = new Cursor(cursorId);
_cursors[cursorId] = c;
return (HCURSOR)c;
}
/*--------------------------------------------*/
Cursor::Cursor(const byte *pixels) : _isBuiltIn(true) {
_surface.create(CURSOR_W, CURSOR_H,
Graphics::PixelFormat::createFormatCLUT8());
byte *dest = (byte *)_surface.getPixels();
Common::copy(pixels, pixels + CURSOR_W * CURSOR_H, dest);
}
Cursor::Cursor(intptr cursorId) : _isBuiltIn(false) {
Image::BitmapDecoder decoder;
const auto &resList = AfxGetApp()->getResources();
intptr id = cursorId;
bool success = false;
Common::SeekableReadStream *bmp = nullptr;
for (const auto &res : resList) {
bmp = res._res->getResource(
Common::kWinBitmap,
(id < 65536) ? Common::WinResourceID(id) :
Common::WinResourceID(cursorId));
if (bmp)
break;
}
if (bmp) {
success = decoder.loadStream(*bmp);
if (success) {
const Graphics::Surface &s = *decoder.getSurface();
_surface.copyFrom(s);
}
}
if (_surface.empty()) {
for (const auto &res : resList) {
_cursorGroup = Graphics::WinCursorGroup::createCursorGroup(res._res, id);
if (_cursorGroup) {
success = true;
break;
}
}
}
if (!success)
error("Could not load cursor resource");
}
Cursor::~Cursor() {
delete _cursorGroup;
}
void Cursor::showCursor() {
Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
CursorMan.disableCursorPalette(!_isBuiltIn);
if (_isBuiltIn)
CursorMan.replaceCursorPalette(CURSOR_PALETTE, 0, ARRAYSIZE(CURSOR_PALETTE) / 3);
if (_cursorGroup) {
const auto &cursor = _cursorGroup->cursors[0].cursor;
CursorMan.replaceCursor(cursor);
} else {
CursorMan.replaceCursor(_surface.getPixels(),
_surface.w, _surface.h, 0, 0, 0, true, &format);
}
CursorMan.showMouse(true);
}
void Cursor::hide() {
CursorMan.showMouse(false);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,108 @@
/* 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_MFC_GFX_CURSOR_H
#define BAGEL_MFC_GFX_CURSOR_H
#include "common/hash-str.h"
#include "common/path.h"
#include "common/formats/winexe_ne.h"
#include "graphics/managed_surface.h"
#include "graphics/wincursor.h"
#include "bagel/mfc/minwindef.h"
#include "bagel/mfc/libs/resources.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
constexpr int CURSOR_W = 12;
constexpr int CURSOR_H = 20;
struct ResourceString_Hash {
uint operator()(const intptr s) const {
return s <= 0xffff ? s : Common::hashit((const char *)s);
}
};
struct ResourceString_EqualTo {
bool operator()(const intptr x, const intptr y) const {
bool xNum = x <= 0xffff;
bool yNum = y <= 0xffff;
return (xNum == yNum) && (
(xNum && x == y) ||
(!xNum && !strcmp((const char *)x, (const char *)y))
);
}
};
class Cursor {
private:
Graphics::ManagedSurface _surface;
Graphics::WinCursorGroup *_cursorGroup = nullptr;
bool _isBuiltIn = false;
public:
static void hide();
public:
/**
* Constructor for predefined cursors
*/
Cursor(const byte *pixels);
/**
* Constructor for cursor resources
*/
Cursor(intptr cursorId);
~Cursor();
/**
* Set the cursor to be active
*/
void showCursor();
};
class Cursors {
private:
//Libs::Resources &_resources;
typedef Common::HashMap<intptr, Cursor *,
ResourceString_Hash, ResourceString_EqualTo> CursorHash;
CursorHash _cursors;
public:
HCURSOR _arrowCursor;
HCURSOR _waitCursor;
public:
Cursors(Libs::Resources &res);
~Cursors();
HCURSOR loadCursor(intptr cursorId);
};
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,276 @@
/* 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 "common/memstream.h"
#include "bagel/mfc/gfx/dialog_template.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
CDialogTemplate::CDialogTemplate(LPCDLGTEMPLATE pTemplate) {
setTemplate(pTemplate);
}
CDialogTemplate::CDialogTemplate(HGLOBAL hGlobal) {
LPDLGTEMPLATE dlgTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
setTemplate(dlgTemplate);
GlobalUnlock(hGlobal);
}
bool CDialogTemplate::setTemplate(LPCDLGTEMPLATE pTemplate) {
Common::MemoryReadStream src((const byte *)pTemplate, 99999);
_header.load(src);
_items.clear();
_items.resize(_header._itemCount);
for (auto &item : _items)
item.load(src);
return true;
}
bool CDialogTemplate::HasFont() const {
return false;
}
bool CDialogTemplate::SetFont(const char *lpFaceName, uint16 nFontSize) {
return false;
}
bool CDialogTemplate::SetSystemFont(uint16 nFontSize) {
return false;
}
bool CDialogTemplate::GetFont(CString &strFaceName, uint16 &nFontSize) const {
return false;
}
void CDialogTemplate::GetSizeInDialogUnits(SIZE *pSize) const {
}
void CDialogTemplate::GetSizeInPixels(SIZE *pSize) const {
}
bool CDialogTemplate::GetFont(LPCDLGTEMPLATE pTemplate,
CString &strFaceName, uint16 &nFontSize) {
return false;
}
/*--------------------------------------------*/
void CDialogTemplate::Header::load(Common::SeekableReadStream &src) {
byte bTerm;
_style = src.readUint32LE();
_itemCount = src.readByte();
_x = src.readSint16LE();
_y = src.readSint16LE();
_w = src.readSint16LE();
_h = src.readSint16LE();
bTerm = src.readByte();
switch (bTerm) {
case 0:
_menuName.clear();
break;
case 0xff:
// Int resource Id
src.skip(2);
break;
default:
src.seek(-1, SEEK_CUR);
_menuName = src.readString();
break;
}
_className = src.readString();
_caption = src.readString();
if (_style & DS_SETFONT) {
_fontInfo._pointSize = src.readUint16LE();
_fontInfo._fontName = src.readString();
} else {
_fontInfo._pointSize = 0;
_fontInfo._fontName.clear();
}
}
/*--------------------------------------------*/
void CDialogTemplate::Item::load(Common::SeekableReadStream &src) {
byte bTerm;
_x = src.readSint16LE();
_y = src.readSint16LE();
_w = src.readSint16LE();
_h = src.readSint16LE();
_id = src.readUint16LE();
_style = src.readUint32LE();
bTerm = src.readByte();
if (bTerm & 0x80) {
switch (bTerm) {
case 0x80: _className = "BUTTON"; break;
case 0x81: _className = "EDIT"; break;
case 0x82: _className = "STATIC"; break;
case 0x83: _className = "LISTBOX"; break;
case 0x84: _className = "SCROLLBAR"; break;
case 0x85: _className = "COMBOBOX"; break;
default:
_className.clear();
break;
}
} else {
src.seek(-1, SEEK_CUR);
_className = src.readString();
}
bTerm = src.readByte();
if (bTerm == 0xff) {
// Integer id, not documented
src.skip(2);
} else {
src.seek(-1, SEEK_CUR);
_title = src.readString();
}
_data.resize(src.readByte());
if (!_data.empty())
src.read(&_data[0], _data.size());
}
LOGFONT CDialogTemplate::ParseFontFromTemplate() {
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
Common::strcpy_s(lf.lfFaceName,
_header._fontInfo._fontName.c_str());
lf.lfHeight = _header._fontInfo._pointSize;
return lf;
}
void CDialogTemplate::getBaseUnits(int &x, int &y) {
// Step 1: Get the font
LOGFONT lf = ParseFontFromTemplate();
HFONT hFont = CreateFontIndirect(&lf);
// Step 2: Create a temporary DC and select the font
HDC hdc = CreateCompatibleDC(nullptr);
HGDIOBJ hOldFont = SelectObject(hdc, hFont);
// Step 3: Get metrics
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
// Calculate DLU conversion
x = tm.tmAveCharWidth;
y = tm.tmHeight;
// Clean up
SelectObject(hdc, hOldFont);
DeleteDC(hdc);
DeleteObject(hFont);
}
void CDialogTemplate::loadTemplate(CDialog *dialog) {
int base_unit_x, base_unit_y;
getBaseUnits(base_unit_x, base_unit_y);
// Set up the overall window
RECT bounds = RectToRECT(
SafeMulDiv(_header._x, base_unit_x, 4),
SafeMulDiv(_header._y, base_unit_y, 8),
SafeMulDiv(_header._x + _header._w, base_unit_x, 4),
SafeMulDiv(_header._y + _header._h, base_unit_y, 8)
);
// WORKAROUND: For Hodj n Podj Boardgame dialog
bounds.right = MIN<long>(bounds.right, 640);
bounds.bottom = MIN<long>(bounds.bottom, 480);
CWnd *wndDialog = static_cast<CWnd *>(dialog);
wndDialog->Create(_header._className.c_str(),
_header._caption.c_str(),
_header._style | WS_POPUP | WS_VISIBLE,
bounds,
dialog->m_pParentWnd,
0
);
// Iterate through the controls
for (const auto &item : _items) {
CWnd *ctl;
if (item._className == "BUTTON")
ctl = new CButton();
else if (item._className == "EDIT")
ctl = new CEdit();
else if (item._className == "STATIC")
ctl = new CStatic();
else if (item._className == "LISTBOX")
ctl = new CListBox();
else if (item._className == "SCROLLBAR")
ctl = new CScrollBar();
else
error("Unhandle dialog item - %s",
item._className.c_str());
// Convert dialog DLU to actual pixels
int x1 = SafeMulDiv(item._x, base_unit_x, 4);
int y1 = SafeMulDiv(item._y, base_unit_y, 8);
int x2 = SafeMulDiv(item._x + item._w, base_unit_x, 4);
int y2 = SafeMulDiv(item._y + item._h, base_unit_y, 8);
// Set up control
bounds = RectToRECT(x1, y1, x2, y2);
ctl->Create(item._className.c_str(),
item._title.c_str(),
item._style | WS_VISIBLE | WS_TABSTOP,
bounds,
dialog,
item._id
);
// Register the control as needing to be
// freed when the dialog is closed
dialog->_ownedControls.push_back(ctl);
if (item._style & BS_DEFPUSHBUTTON)
dialog->_defaultId = item._id;
}
// Apply the font to the window and all child controls
LOGFONT lf = ParseFontFromTemplate();
dialog->_dialogFont.CreateFontIndirect(&lf);
dialog->SendMessageToDescendants(WM_SETFONT,
(WPARAM)dialog->_dialogFont.m_hObject, 0);
// Allow the dialog to set up replacement controls
CDataExchange exchange = { false };
dialog->DoDataExchange(&exchange);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,138 @@
/* 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_MFC_GFX_DIALOG_TEMPLATE_H
#define BAGEL_MFC_GFX_DIALOG_TEMPLATE_H
#include "common/array.h"
#include "common/stream.h"
#include "graphics/managed_surface.h"
#include "bagel/mfc/minwindef.h"
#include "bagel/mfc/afxstr.h"
namespace Bagel {
namespace MFC {
class CDialog;
namespace Gfx {
/*
* Dialog Styles
*/
#define DS_ABSALIGN 0x01L
#define DS_SYSMODAL 0x02L
#define DS_LOCALEDIT 0x20L /* 16-bit: Edit items get Local storage. 32-bit and up: meaningless. */
#define DS_SETFONT 0x40L /* User specified font for Dlg controls */
#define DS_MODALFRAME 0x80L /* Can be combined with WS_CAPTION */
#define DS_NOIDLEMSG 0x100L /* WM_ENTERIDLE message will not be sent */
#define DS_SETFOREGROUND 0x200L /* not in win3.1 */
// Template data pointers. Note that they're
// void *because in ScummVM we do endian-safe
// loading of the data being pointed to
typedef const void *LPCDLGTEMPLATE;
typedef void *LPDLGTEMPLATE;
class CDialogTemplate {
struct FontInfo {
byte _pointSize;
Common::String _fontName;
};
struct Header {
uint16 _style = 0;
byte _itemCount = 0;
int16 _x = 0, _y = 0;
int16 _w = 0, _h = 0;
Common::String _menuName;
Common::String _className;
Common::String _caption;
FontInfo _fontInfo;
void load(Common::SeekableReadStream &src);
};
struct Item {
uint16 _style = 0;
int16 _x = 0;
int16 _y = 0;
int16 _w = 0;
int16 _h = 0;
uint16 _id = 0;
Common::String _className;
uint16 _titleId = 0;
Common::String _title;
Common::Array<byte> _data;
void load(Common::SeekableReadStream &src);
};
private:
Header _header;
Common::Array<Item> _items;
private:
static byte *GetFontSizeField(LPCDLGTEMPLATE pTemplate);
static unsigned int GetTemplateSize(LPCDLGTEMPLATE *pTemplate);
bool setTemplate(LPCDLGTEMPLATE pTemplate);
/**
* Gets the base pixel x/y amounts, used for
* translating DLU units to pixel units
*/
void getBaseUnits(int &x, int &y);
LOGFONT ParseFontFromTemplate();
public:
HGLOBAL m_hTemplate = nullptr;
uint32 m_dwTemplateSize = 0;
bool m_bSystemFont = false;
public:
CDialogTemplate(LPCDLGTEMPLATE pTemplate = NULL);
CDialogTemplate(HGLOBAL hGlobal);
/**
* Sets up window with parsed template data
*/
void loadTemplate(CDialog *dialog);
bool HasFont() const;
bool SetFont(const char *lpFaceName, uint16 nFontSize);
bool SetSystemFont(uint16 nFontSize = 0);
bool GetFont(CString &strFaceName, uint16 &nFontSize) const;
void GetSizeInDialogUnits(SIZE *pSize) const;
void GetSizeInPixels(SIZE *pSize) const;
static bool GetFont(LPCDLGTEMPLATE pTemplate,
CString &strFaceName, uint16 &nFontSize);
};
} // namespace Gfx
using Gfx::LPDLGTEMPLATE;
using Gfx::LPCDLGTEMPLATE;
using Gfx::CDialogTemplate;
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,233 @@
/* 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/winfont.h"
#include "bagel/mfc/gfx/fonts.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
struct FontSizeOverride {
const char *_faceName;
int _height;
int _avgWidth;
int _charHeight;
};
static const FontSizeOverride FONT_SIZE_OVERRIDES[] = {
{ "MS Sans Serif", 8, 7, 13 },
{ "MS Sans Serif", 12, 10, 20 },
{ nullptr, 0, 0, 0 }
};
Fonts::~Fonts() {
_fonts.clear();
}
int Fonts::addFontResource(const char *filename) {
if (!resExists(filename)) {
_fontResources.push_back(filename);
return 1;
}
return 0;
}
bool Fonts::removeFontResource(const char *filename) {
int idx = resIndexOf(filename);
if (idx != -1) {
_fontResources.remove_at(idx);
return true;
} else {
return false;
}
}
HFONT Fonts::createFont(int nHeight, int nWidth, int nEscapement,
int nOrientation, int nWeight, byte bItalic, byte bUnderline,
byte cStrikeOut, byte nCharSet, byte nOutPrecision,
byte nClipPrecision, byte nQuality, byte nPitchAndFamily,
const char *lpszFacename) {
Gfx::Font *font = nullptr;
// for nHeight, -ve means char height (which ScummVM uses),
// whilst +ve means cell height
int charHeight;
if (nHeight < 0) {
charHeight = ABS(nHeight);
} else {
// Cell to char height mappings
// TODO: This needs to be set properly
static const int8 HEIGHTS[][2] = {
{ 8, 8 }, // Default font
{ 10, 10 }, // Boardgame dialog
{ 12, 8 },
{ 14, 9 }, { 16, 10 }, { 18, 24 },
{ 21, 12 }, // The Gesng Gme
{ 0, 0 }
};
charHeight = nHeight * 16 / 24; // Rough default
for (int i = 0; HEIGHTS[i][0]; ++i) {
if (nHeight == HEIGHTS[i][0]) {
charHeight = HEIGHTS[i][1];
break;
}
}
}
// First scan for an existing cached copy of the font
for (auto &it : _fonts) {
if (it._faceName == lpszFacename &&
it._height == nHeight) {
font = it._font;
break;
}
}
if (!font) {
// Create the font
Graphics::WinFont *winFont = new Graphics::WinFont();
for (auto &filename : _fontResources) {
// Note: Windows does some rounding up or down to
// the closest size for a given face name if the
// requested size isn't available
for (int h = charHeight; h >= 2; --h) {
if (winFont->loadFromFON(filename, Graphics::WinFontDirEntry(
lpszFacename, (h >= 6) ? h : charHeight + (6 - h)))) {
// Loaded successfully
font = new Gfx::Font(winFont, lpszFacename, nHeight);
// Add to the font cache
_fonts.push_back(FontEntry());
_fonts.back().set(lpszFacename, nHeight, font);
break;
}
}
if (font)
break;
}
if (!font)
delete winFont;
}
// If we found a found, return a font Impl,
// which can be cast as a HFONT for our MFC classes
if (font) {
CFont::Impl *f = new CFont::Impl(font);
return f;
}
error("Could not locate font %s - size %d",
lpszFacename, nHeight);
return nullptr;
}
int Fonts::resIndexOf(const char *filename) const {
for (uint i = 0; i < _fontResources.size(); ++i) {
if (!strcmp(_fontResources[i], filename))
return i;
}
return -1;
}
HFONT Fonts::getFont(const char *lpszFacename, int nHeight) {
return createFont(nHeight, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, OUT_RASTER_PRECIS, 0, PROOF_QUALITY, FF_ROMAN, lpszFacename);
}
/*--------------------------------------------*/
Fonts::FontEntry::~FontEntry() {
delete _font;
}
/*--------------------------------------------*/
Font::Font(Graphics::Font *font, const Common::String &faceName, int height,
DisposeAfterUse::Flag disposeAfterUse) :
_font(font), _faceName(faceName), _height(height),
_charWidth(0), _charHeight(0),
_disposeAfterUse(disposeAfterUse) {
for (const FontSizeOverride *aw = FONT_SIZE_OVERRIDES; aw->_faceName; ++aw) {
if (faceName == aw->_faceName && height == aw->_height) {
_charWidth = aw->_avgWidth;
_charHeight = aw->_charHeight;
return;
}
}
}
Font::~Font() {
if (_disposeAfterUse == DisposeAfterUse::YES)
delete _font;
}
int Font::getFontHeight() const {
return _font->getFontHeight();
}
int Font::getFontAscent() const {
return _font->getFontAscent();
}
int Font::getFontDescent() const {
return _font->getFontDescent();
}
int Font::getFontLeading() const {
return _font->getFontLeading();
}
int Font::getMaxCharWidth() const {
return _font->getMaxCharWidth() + 1;
}
int Font::getCharWidth(uint32 chr) const {
return _font->getCharWidth(chr) + 1;
}
int Font::getKerningOffset(uint32 left, uint32 right) const {
return _font->getKerningOffset(left, right);
}
void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
_font->drawChar(dst, chr, x, y, color);
_font->drawChar(dst, chr, x + 1, y, color);
}
void Font::drawChar(Graphics::ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const {
const int charW = _font->getCharWidth(chr) + 1;
const int charH = _font->getFontHeight();
if (x >= 0 && y >= 0 && (x + charW) <= dst->w &&
(y + charH) <= dst->h) {
_font->drawChar(dst, chr, x, y, color);
_font->drawChar(dst, chr, x + 1, y, color);
}
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,132 @@
/* 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_MFC_GFX_FONTS_H
#define BAGEL_MFC_GFX_FONTS_H
#include "common/array.h"
#include "common/types.h"
#include "graphics/font.h"
#include "bagel/mfc/minwindef.h"
#include "bagel/mfc/libs/resources.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
/**
* Font derived class that makes the
* original face name and height visible.
* It also bolds the font, which seems to
* more closely match plain text in the
* original Hodj n Podj.
*
* Note: We cache the underlying Graphics::Font
* for the lifetime of the application, but
* Font instances are temporary, and are what
* we cast as HFONT. And as such, will be destroyed.
*/
class Font : public Graphics::Font {
private:
Graphics::Font *_font;
DisposeAfterUse::Flag _disposeAfterUse =
DisposeAfterUse::YES;
Common::String _faceName;
int _height;
int _charWidth;
int _charHeight;
public:
Font(Graphics::Font *font, const Common::String &faceName, int height,
DisposeAfterUse::Flag disposeAfterUse =
DisposeAfterUse::YES);
~Font() override;
int getFontHeight() const override;
int getFontAscent() const override;
int getFontDescent() const override;
int getFontLeading() const override;
int getMaxCharWidth() const override;
int getCharWidth(uint32 chr) const override;
int getKerningOffset(uint32 left, uint32 right) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
void drawChar(Graphics::ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const override;
const Common::String &getFaceName() const {
return _faceName;
}
int getHeight() const {
return _height;
}
int getCharWidth() const {
return _charWidth;
}
int getCharHeight() const {
return _charHeight;
}
};
/**
* Main fonts cache
*/
class Fonts {
struct FontEntry {
Common::String _faceName;
int _height = 0;
Font *_font = nullptr;
void set(const Common::String &faceName,
int height, Font *font) {
_faceName = faceName;
_height = height;
_font = font;
}
~FontEntry();
};
private:
//Libs::Resources &_res;
Common::Array<const char *> _fontResources;
Common::List<FontEntry> _fonts;
int resIndexOf(const char *filename) const;
bool resExists(const char *filename) const {
return resIndexOf(filename) != -1;
}
public:
Fonts(Libs::Resources &res) /*: _res(res) */ {}
~Fonts();
int addFontResource(const char *filename);
bool removeFontResource(const char *filename);
HFONT createFont(int nHeight, int nWidth, int nEscapement,
int nOrientation, int nWeight, byte bItalic, byte bUnderline,
byte cStrikeOut, byte nCharSet, byte nOutPrecision,
byte nClipPrecision, byte nQuality, byte nPitchAndFamily,
const char *lpszFacename);
HFONT getFont(const char *lpszFacename, int nHeight);
};
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,70 @@
/* 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/mfc/gfx/palette_map.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
PaletteMap::PaletteMap(const Graphics::Palette &src,
const Graphics::Palette &dest) : _srcPalCount(src.size()) {
assert(src.size() == 256 && dest.size() == 256);
// Set up lookup map
Graphics::PaletteLookup lookup(dest.data(), dest.size());
_map = lookup.createMap(src.data(), src.size());
// Hack: Index 255 must always remain mapped to 255,
// in order for transparency to work. In cases where the
// palette has multiple White entries, PaletteLookup could
// end up using the first match, not the last (255) one
if (!_map) {
_map = new uint32[256];
for (int i = 0; i < 256; ++i)
_map[i] = i;
}
byte r, g, b;
for (int i = 0; i < 256; ++i) {
src.get(i, r, g, b);
if (r == 0xff && g == 0xff && b == 0xff)
_map[i] = 0xff;
}
}
PaletteMap::~PaletteMap() {
delete[] _map;
}
void PaletteMap::map(const byte *src, byte *dest, size_t len) {
if (_map) {
for (; len > 0; --len, ++src, ++dest)
*dest = _map[*src];
} else {
// Identical palettes, so pixels can just be copied
Common::copy(src, src + len, dest);
}
}
} // namespace Gfx
} // namespace MFC
} // 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_MFC_GFX_PALETTE_MAP_H
#define BAGEL_MFC_GFX_PALETTE_MAP_H
#include "graphics/palette.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
/**
* Simple wrapper over Graphics::PaletteLookup
*/
class PaletteMap {
private:
uint32 *_map;
size_t _srcPalCount;
public:
PaletteMap(const Graphics::Palette &src,
const Graphics::Palette &dest);
~PaletteMap();
void map(const byte *src, byte *dest, size_t len);
};
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,249 @@
/* 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/mfc/gfx/surface.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
Surface::XIterator::XIterator(YIterator *rowIter) :
_rowIter(rowIter), _surface(rowIter->_surface) {
const CPoint org = _surface->getViewportOrg();
_xMin = _surface->_clipRect.left - org.x;
_xMax = _surface->_clipRect.right - org.x;
}
Surface::XIterator &Surface::XIterator::operator=(int x) {
//const CPoint org = _surface->getViewportOrg();
_x = x;
int y = _rowIter->_y;
if (x < _xMin || x >= _xMax ||
y < _rowIter->_yMin || y >= _rowIter->_yMax)
_pixelP = &_dummyPixel;
else
_pixelP = _surface->getBasePtr(_x, _rowIter->_y);
return *this;
}
Surface::XIterator &Surface::XIterator::operator++() {
++_x;
int y = _rowIter->_y;
if (y < _rowIter->_yMin || y >= _rowIter->_yMax)
_pixelP = &_dummyPixel;
else if (_x == _xMin)
_pixelP = _surface->getBasePtr(_x, y);
else if (_x >= _xMax)
_pixelP = &_dummyPixel;
else if (_x >= _xMin)
++_pixelP;
return *this;
}
bool Surface::XIterator::operator<(int xEnd) const {
return _x < xEnd;
}
Surface::XIterator::operator byte *() {
// Keep resetting the dummy pixel, in case
// the pixel pointer is pointing to it
_dummyPixel = 0;
// Return the pixel pointer
return _pixelP;
}
/*--------------------------------------------*/
Surface::YIterator::YIterator(Surface *surface) : _surface(surface) {
assert(surface && surface->format.bytesPerPixel <= 1);
CPoint org = surface->getViewportOrg();
_yMin = surface->_clipRect.top - org.y;
_yMax = surface->_clipRect.bottom - org.y;
}
Surface::YIterator &Surface::YIterator::operator=(int y) {
_y = y;
return *this;
}
Surface::YIterator &Surface::YIterator::operator++() {
++_y;
return *this;
}
bool Surface::YIterator::operator<(int yEnd) const {
return _y < yEnd;
}
/*--------------------------------------------*/
void Surface::create(int16 width, int16 height) {
_surface.create(width, height);
_viewportOrg = CPoint(0, 0);
resetClip();
}
void Surface::create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) {
_surface.create(width, height, pixelFormat);
_viewportOrg = CPoint(0, 0);
resetClip();
}
void Surface::create(Graphics::ManagedSurface &surf, const Common::Rect &bounds) {
_surface.create(surf, bounds);
_viewportOrg = CPoint(0, 0);
resetClip();
}
void Surface::setClipRect(const Common::Rect &r) {
_clipRect = r;
}
Common::Rect Surface::getClipRect() const {
return _clipRect;
}
void Surface::resetClip() {
setClipRect(Common::Rect(0, 0, _surface.w, _surface.h));
}
int Surface::intersectClipRect(const Common::Rect &r) {
setClipRect(_clipRect.findIntersectingRect(r));
return _clipRect.isEmpty() ? NULLREGION : SIMPLEREGION;
}
int Surface::offsetClipRect(int x, int y) {
if (_clipRect.isEmpty()) {
return NULLREGION;
} else {
Common::Rect r = _clipRect;
r.translate(x, y);
setClipRect(r);
return SIMPLEREGION;
}
}
CPoint Surface::getViewportOrg() const {
return _viewportOrg;
}
void Surface::setViewportOrg(const CPoint &pt) {
_viewportOrg = pt;
}
void Surface::offsetViewportOrg(int x, int y) {
_viewportOrg.x += x;
_viewportOrg.y += y;
}
byte *Surface::getBasePtr(int x, int y) {
assert(format.bytesPerPixel == 1);
x += _viewportOrg.x;
y += _viewportOrg.y;
assert(x >= 0 && y >= 0 && x < this->w && y < this->h);
return (byte *)_surface.getBasePtr(x, y);
}
void Surface::addDirtyRect(const Common::Rect &r) {
Common::Rect tmp = r;
tmp.translate(_viewportOrg.x, _viewportOrg.y);
tmp = tmp.findIntersectingRect(_clipRect);
_surface.addDirtyRect(tmp);
}
void Surface::fillRect(const Common::Rect &r, uint color) {
Common::Rect tmp = r;
tmp.translate(_viewportOrg.x, _viewportOrg.y);
tmp = tmp.findIntersectingRect(_clipRect);
if (!tmp.isEmpty())
_surface.fillRect(tmp, color);
}
void Surface::frameRect(const Common::Rect &r, uint color) {
Common::Rect tmp = r;
tmp.translate(_viewportOrg.x, _viewportOrg.y);
tmp = tmp.findIntersectingRect(_clipRect);
if (!tmp.isEmpty())
_surface.frameRect(r, color);
}
void Surface::drawEllipse(int x0, int y0, int x1, int y1, uint32 color, bool filled) {
x0 += _viewportOrg.x;
x1 += _viewportOrg.x;
y0 += _viewportOrg.y;
y1 += _viewportOrg.y;
assert(x0 >= 0 && y0 >= 0 && x1 <= _surface.w && y1 <= _surface.h);
_surface.drawEllipse(x0, y0, x1, y1, color, filled);
}
void Surface::drawLine(int x0, int y0, int x1, int y1, uint32 color) {
x0 += _viewportOrg.x;
x1 += _viewportOrg.x;
y0 += _viewportOrg.y;
y1 += _viewportOrg.y;
assert(x0 >= 0 && y0 >= 0 && x1 <= _surface.w && y1 <= _surface.h);
_surface.drawLine(x0, y0, x1, y1, color);
}
void Surface::hLine(int x0, int y, int x1, uint32 color) {
x0 += _viewportOrg.x;
x1 += _viewportOrg.x;
y += _viewportOrg.y;
assert(x0 >= 0 && y >= 0 && x1 <= _surface.w && y <= _surface.h);
_surface.hLine(x0, y, x1, color);
}
uint32 Surface::getPixel(int x, int y) {
x += _viewportOrg.x;
y += _viewportOrg.y;
assert(x >= 0 && y >= 0 && x <= _surface.w && y <= _surface.h);
assert(format.bytesPerPixel == 1);
return *(byte *)getBasePtr(x, y);
}
Graphics::ManagedSurface Surface::getSubArea(const Common::Rect &r) {
Common::Rect tmp = r;
tmp.translate(_viewportOrg.x, _viewportOrg.y);
assert(tmp.left >= 0 && tmp.top >= 0 &&
tmp.right <= _surface.w && tmp.bottom <= _surface.h);
return Graphics::ManagedSurface(_surface, tmp);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,130 @@
/* 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_MFC_GFX_SURFACE_H
#define BAGEL_MFC_GFX_SURFACE_H
#include "graphics/managed_surface.h"
#include "bagel/mfc/atltypes.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
class Surface;
/**
* Surface class
*/
class Surface {
public:
class YIterator;
/**
* Column iterator
*/
class XIterator {
private:
Surface *_surface;
YIterator *_rowIter;
int _x = 0;
int _xMin, _xMax;
byte *_pixelP = nullptr;
byte _dummyPixel = 0;
public:
XIterator(YIterator *rowIter);
XIterator &operator=(int x);
XIterator &operator++();
bool operator<(int xEnd) const;
operator byte *();
};
/**
* Row iterator
*/
class YIterator {
friend class XIterator;
private:
Surface *_surface;
int _y = 0;
int _yMin, _yMax;
public:
YIterator(Surface *surface);
YIterator &operator=(int y);
YIterator &operator++();
bool operator<(int yMax) const;
};
private:
Graphics::ManagedSurface _surface;
Common::Rect _clipRect;
CPoint _viewportOrg;
public:
Graphics::PixelFormat &format = _surface.format;
int16 &w = _surface.w;
int16 &h = _surface.h;
int32 &pitch = _surface.pitch;
public:
void create(int16 width, int16 height);
void create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat);
void create(Graphics::ManagedSurface &surf, const Common::Rect &bounds);
void setClipRect(const Common::Rect &r);
Common::Rect getClipRect() const;
void resetClip();
int intersectClipRect(const Common::Rect &r);
int offsetClipRect(int x, int y);
CPoint getViewportOrg() const;
void setViewportOrg(const CPoint &pt);
void offsetViewportOrg(int x, int y);
byte *getBasePtr(int x, int y);
void *getPixels() {
return _surface.getPixels();
}
const void *getPixels() const {
return _surface.getPixels();
}
void addDirtyRect(const Common::Rect &r);
void setPalette(const byte *colors, int start, int num) {
_surface.setPalette(colors, start, num);
}
void fillRect(const Common::Rect &r, uint color);
void frameRect(const Common::Rect &r, uint color);
void drawEllipse(int x0, int y0, int x1, int y1, uint32 color, bool filled);
void drawLine(int x0, int y0, int x1, int y1, uint32 color);
void hLine(int x0, int y, int x1, uint32 color);
uint32 getPixel(int x, int y);
Graphics::ManagedSurface getSubArea(const Common::Rect &r);
};
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif

View File

@@ -0,0 +1,161 @@
/* 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/mfc/gfx/text_render.h"
#include "bagel/mfc/wingdi.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
CSize TextRender::renderText(const Common::String &str,
Gfx::Surface *dest, Graphics::Font *font,
uint textCol, LPCRECT lpRect, unsigned int nFormat,
const Common::Array<int> &tabStops,
int nTabOrigin, uint bkColor, int bkMode,
uint textColor, uint textAlign) {
const int maxWidth = lpRect->right - lpRect->left;
Common::Rect textRect = *lpRect;
Common::StringArray lines;
CSize size;
// FIXME: Currently doing a hack to replace
// all tabs with spaces, rather than honoring
// the tab stops array
Common::String text = str;
uint p;
while ((p = text.findFirstOf('\t')) != Common::String::npos) {
text.deleteChar(p);
text.insertString(" ", p);
}
if (nFormat & DT_SINGLELINE) {
lines.push_back(text);
} else {
// Hotkeys aren't supported on multi-line text
assert((nFormat & DT_NOPREFIX) || !str.contains('&'));
// Perform word wrapping of the text as necessary
wordWrapText(font, text, tabStops, maxWidth, lines);
}
// Handle vertical alignment
const int linesHeight = lines.size() * font->getFontHeight();
if (nFormat & DT_BOTTOM) {
textRect.moveTo(textRect.left,
MAX<int16>(lpRect->top, textRect.bottom - linesHeight));
}
if (nFormat & DT_VCENTER) {
textRect.moveTo(textRect.left, MAX<int16>(lpRect->top,
lpRect->top + ((lpRect->bottom - lpRect->top) -
linesHeight) / 2));
}
// Iterate through the lines
for (const Common::String &line : lines) {
// Constrain within passed rect
if (textRect.top >= lpRect->bottom)
break;
const int lineWidth = getStringWidth(font, line);
size.cx = MAX(size.cx, lineWidth);
// Form sub-rect for the single line
Common::Rect lineRect(textRect.left, textRect.top,
textRect.right, textRect.top + font->getFontHeight());
// Handle horizontal alignment
if (nFormat & DT_RIGHT) {
lineRect.moveTo(MAX<int16>(lineRect.left,
lineRect.right - lineWidth),
lineRect.top);
}
if (nFormat & DT_CENTER) {
lineRect.moveTo(MAX<int16>(lineRect.left,
lineRect.left + (lineRect.width() - lineWidth) / 2),
lineRect.top);
}
lineRect.left = MAX<int16>(lineRect.left, 0);
lineRect.right = MIN<int16>(lineRect.right, dest->w);
// If the background is opaque, clear it
if (bkMode == OPAQUE)
dest->fillRect(lineRect, bkColor);
// Write the actual text. This is slightly
// complicated to detect '&' characters when
// DT_NOPREFIX isn't set
Common::String fragment;
Common::String tempLine = line;
while (!tempLine.empty()) {
if (!(nFormat & DT_NOPREFIX) && tempLine.firstChar() == '&') {
tempLine.deleteChar(0);
// Draw an underline
const int x1 = lineRect.left;
const int x2 = x1 + font->getCharWidth(tempLine.firstChar()) - 1;
const int y = lineRect.top + font->getFontAscent() + 1;
dest->hLine(x1, y, x2, textCol);
}
uint idx = (nFormat & DT_NOPREFIX) ? Common::String::npos :
tempLine.findFirstOf('&');
if (idx == Common::String::npos) {
fragment = tempLine;
tempLine.clear();
} else {
fragment = Common::String(tempLine.c_str(), tempLine.c_str() + idx);
tempLine = Common::String(tempLine.c_str() + fragment.size());
}
Graphics::ManagedSurface area = dest->getSubArea(lineRect);
font->drawString(&area, fragment, 0, 0, area.w, textCol);
lineRect.left += getStringWidth(font, fragment);
}
// Move to next line
textRect.top += font->getFontHeight();
}
return size;
}
int TextRender::getStringWidth(Graphics::Font *font, const Common::String &str) {
Common::String tempLine = str;
uint idx;
while ((idx = tempLine.findFirstOf('&')) != Common::String::npos)
tempLine.deleteChar(idx);
return font->getStringWidth(tempLine);
}
void TextRender::wordWrapText(Graphics::Font *font, const Common::String &str,
const Common::Array<int> tabStops, int maxWidth,
Common::StringArray &lines) {
font->wordWrapText(str, maxWidth, lines);
}
} // namespace Gfx
} // namespace MFC
} // namespace Bagel

View File

@@ -0,0 +1,55 @@
/* 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_MFC_GFX_TEXT_RENDER_H
#define BAGEL_MFC_GFX_TEXT_RENDER_H
#include "common/str-array.h"
#include "graphics/font.h"
#include "bagel/mfc/gfx/surface.h"
#include "bagel/mfc/minwindef.h"
#include "bagel/mfc/atltypes.h"
#include "bagel/mfc/wingdi.h"
namespace Bagel {
namespace MFC {
namespace Gfx {
class TextRender {
protected:
CSize renderText(const Common::String &str,
Gfx::Surface *dest, Graphics::Font *font,
uint textCol, LPCRECT lpRect, unsigned int nFormat,
const Common::Array<int> &tabStops,
int nTabOrigin, uint bkColor, int bkMode,
uint textColor, uint textAlign);
void wordWrapText(Graphics::Font *font, const Common::String &str,
const Common::Array<int> tabStops,
int maxWidth, Common::StringArray &lines);
int getStringWidth(Graphics::Font *font, const Common::String &str);
};
} // namespace Gfx
} // namespace MFC
} // namespace Bagel
#endif