Initial commit
This commit is contained in:
229
engines/bagel/mfc/gfx/blitter.cpp
Normal file
229
engines/bagel/mfc/gfx/blitter.cpp
Normal 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
|
||||
46
engines/bagel/mfc/gfx/blitter.h
Normal file
46
engines/bagel/mfc/gfx/blitter.h
Normal 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
|
||||
186
engines/bagel/mfc/gfx/cursor.cpp
Normal file
186
engines/bagel/mfc/gfx/cursor.cpp
Normal 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
|
||||
108
engines/bagel/mfc/gfx/cursor.h
Normal file
108
engines/bagel/mfc/gfx/cursor.h
Normal 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
|
||||
276
engines/bagel/mfc/gfx/dialog_template.cpp
Normal file
276
engines/bagel/mfc/gfx/dialog_template.cpp
Normal 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
|
||||
138
engines/bagel/mfc/gfx/dialog_template.h
Normal file
138
engines/bagel/mfc/gfx/dialog_template.h
Normal 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
|
||||
233
engines/bagel/mfc/gfx/fonts.cpp
Normal file
233
engines/bagel/mfc/gfx/fonts.cpp
Normal 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
|
||||
132
engines/bagel/mfc/gfx/fonts.h
Normal file
132
engines/bagel/mfc/gfx/fonts.h
Normal 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
|
||||
70
engines/bagel/mfc/gfx/palette_map.cpp
Normal file
70
engines/bagel/mfc/gfx/palette_map.cpp
Normal 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
|
||||
51
engines/bagel/mfc/gfx/palette_map.h
Normal file
51
engines/bagel/mfc/gfx/palette_map.h
Normal 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
|
||||
249
engines/bagel/mfc/gfx/surface.cpp
Normal file
249
engines/bagel/mfc/gfx/surface.cpp
Normal 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
|
||||
130
engines/bagel/mfc/gfx/surface.h
Normal file
130
engines/bagel/mfc/gfx/surface.h
Normal 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
|
||||
161
engines/bagel/mfc/gfx/text_render.cpp
Normal file
161
engines/bagel/mfc/gfx/text_render.cpp
Normal 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
|
||||
55
engines/bagel/mfc/gfx/text_render.h
Normal file
55
engines/bagel/mfc/gfx/text_render.h
Normal 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
|
||||
Reference in New Issue
Block a user