SHERLOCK: Implemented more support methods for RT map

This commit is contained in:
Paul Gilbert 2015-06-10 20:54:05 -04:00
parent dd1781a3f2
commit 6780c63e53
5 changed files with 305 additions and 14 deletions

View file

@ -82,7 +82,7 @@ public:
*/ */
int fontHeight() const { return _fontHeight; } int fontHeight() const { return _fontHeight; }
int fontNumber() const { return _fontNumber; }
}; };
} // End of namespace Sherlock } // End of namespace Sherlock

View file

@ -37,6 +37,7 @@ namespace Sherlock {
#define BG_GREYSCALE_RANGE_END 229 #define BG_GREYSCALE_RANGE_END 229
enum { enum {
BLACK = 0,
INFO_BLACK = 1, INFO_BLACK = 1,
INFO_FOREGROUND = 11, INFO_FOREGROUND = 11,
INFO_BACKGROUND = 1, INFO_BACKGROUND = 1,
@ -52,7 +53,8 @@ enum {
BUTTON_BOTTOM = 248, BUTTON_BOTTOM = 248,
TALK_FOREGROUND = 12, TALK_FOREGROUND = 12,
TALK_NULL = 16, TALK_NULL = 16,
PEN_COLOR = 250 PEN_COLOR = 250,
MAP_NAME_COLOR = 131
}; };
class SherlockEngine; class SherlockEngine;
@ -77,11 +79,6 @@ private:
* Returns the union of two dirty area rectangles * Returns the union of two dirty area rectangles
*/ */
bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2); bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
/**
* Draws the given string into the back buffer using the images stored in _font
*/
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
protected: protected:
/** /**
* Adds a rectangle to the list of modified areas of the screen during the * Adds a rectangle to the list of modified areas of the screen during the
@ -244,13 +241,17 @@ public:
*/ */
Common::Rect getDisplayBounds(); Common::Rect getDisplayBounds();
int fontNumber() const { return _fontNumber; }
/** /**
* Synchronize the data for a savegame * Synchronize the data for a savegame
*/ */
void synchronize(Serializer &s); void synchronize(Serializer &s);
/**
* Draws the given string into the back buffer using the images stored in _font
*/
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
// Rose Tattoo specific methods // Rose Tattoo specific methods
void initPaletteFade(int bytesToRead); void initPaletteFade(int bytesToRead);

View file

@ -71,11 +71,6 @@ protected:
Graphics::Surface _surface; Graphics::Surface _surface;
virtual void addDirtyRect(const Common::Rect &r) {} virtual void addDirtyRect(const Common::Rect &r) {}
/**
* Draws the given string into the back buffer using the images stored in _font
*/
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
public: public:
Surface(uint16 width, uint16 height, Common::Platform platform); Surface(uint16 width, uint16 height, Common::Platform platform);
Surface(); Surface();
@ -164,6 +159,11 @@ public:
*/ */
void setPixels(byte *pixels, int width, int height); void setPixels(byte *pixels, int width, int height);
/**
* Draws the given string into the back buffer using the images stored in _font
*/
virtual void writeString(const Common::String &str, const Common::Point &pt, byte overrideColor);
inline uint16 w() const { return _surface.w; } inline uint16 w() const { return _surface.w; }
inline uint16 h() const { return _surface.h; } inline uint16 h() const { return _surface.h; }
inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); } inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); }

View file

@ -35,6 +35,10 @@ void MapEntry::clear() {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
TattooMap::TattooMap(SherlockEngine *vm) : Map(vm) { TattooMap::TattooMap(SherlockEngine *vm) : Map(vm) {
_iconImages = nullptr;
_bgFound = _oldBgFound = 0;
_textBuffer = nullptr;
loadData(); loadData();
} }
@ -104,6 +108,264 @@ void TattooMap::loadData() {
} while (stream->pos() < stream->size()); } while (stream->pos() < stream->size());
} }
void TattooMap::drwaMapIcons() {
Screen &screen = *_vm->_screen;
for (uint idx = 0; idx < _data.size(); ++idx) {
if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
MapEntry &mapEntry = _data[idx];
ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
screen._backBuffer1.transBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2,
mapEntry.y - img._height / 2));
}
}
}
void TattooMap::checkMapNames(bool slamIt) {
Events &events = *_vm->_events;
Screen &screen = *_vm->_screen;
Common::Point mousePos = events.mousePos();
int dif = 10000;
// See if the mouse is pointing at any of the map locations
_bgFound = -1;
for (uint idx = 0; idx < _data.size(); ++idx) {
if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
MapEntry &mapEntry = _data[idx];
ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
Common::Rect r(mapEntry.x - img._width / 2, mapEntry.y - img._height / 2,
mapEntry.x + img._width / 2, mapEntry.y + img._height / 2);
if (r.contains(mousePos)) {
_bgFound = idx;
break;
}
}
}
// Store the previous bounds that were drawn
_oldTextBounds = _textBounds;
// See if thay are pointing at a different location and we need to change the display
if (_bgFound != _oldBgFound || (_bgFound != -1 && _textBuffer == nullptr)) {
// See if there is a new image to be displayed
if (_bgFound != -1 && (_bgFound != _oldBgFound || _textBuffer == nullptr)) {
const Common::String &desc = _data[_bgFound]._description;
const char *space = nullptr;
int width = screen.stringWidth(desc) + 2;
int height = 0;
// See if we need to split it into two lines
if (width > 150) {
const char *s = desc.c_str();
for (;;) {
// Move to end of next word
s = strchr(s, ' ');
if (s == nullptr) {
// Reached end of description
if (space == nullptr) {
height = screen.stringHeight(desc) + 2;
} else {
Common::String line1(desc.c_str(), space);
Common::String line2(space + 1);
height = screen.stringHeight(line1) + screen.stringHeight(line2);
}
break;
} else {
// Reached space separating words within the description
// Get width before and after word
int width1 = screen.stringWidth(Common::String(desc.c_str(), s));
int width2 = screen.stringWidth(Common::String(s + 1));
if (ABS(width1 - width2) < dif) {
space = s;
dif = ABS(width1 - width2);
width = MAX(width1, width) + 2;
}
++s;
}
}
} else {
height = screen.stringHeight(desc) + 2;
}
// Delete any previous saved area
delete _textBuffer;
// Allocate a new surface
_textBuffer = new Surface(width, height, _vm->getPlatform());
_textBuffer->fillRect(Common::Rect(0, 0, width, height), 255);
if (space == nullptr) {
// The whole text can be drawn on a single line
_textBuffer->writeString(desc, Common::Point(0, 0), BLACK);
_textBuffer->writeString(desc, Common::Point(1, 0), BLACK);
_textBuffer->writeString(desc, Common::Point(2, 0), BLACK);
_textBuffer->writeString(desc, Common::Point(0, 1), BLACK);
_textBuffer->writeString(desc, Common::Point(2, 1), BLACK);
_textBuffer->writeString(desc, Common::Point(0, 2), BLACK);
_textBuffer->writeString(desc, Common::Point(1, 2), BLACK);
_textBuffer->writeString(desc, Common::Point(2, 2), BLACK);
_textBuffer->writeString(desc, Common::Point(1, 1), MAP_NAME_COLOR);
} else {
// The text needs to be split up over two lines
Common::String line1(desc.c_str(), space);
Common::String line2(space + 1);
int xp, yp;
// Draw the first line
xp = (width - screen.stringWidth(desc)) / 2;
_textBuffer->writeString(line1, Common::Point(xp + 0, 0), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 1, 0), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 2, 0), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 0, 1), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 2, 1), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 0, 2), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 1, 2), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 2, 2), BLACK);
_textBuffer->writeString(line1, Common::Point(xp + 1, 1), MAP_NAME_COLOR);
yp = screen.stringHeight(line2);
xp = (width - screen.stringWidth(line2)) / 2;
_textBuffer->writeString(line2, Common::Point(xp + 0, 0), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 1, 0), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 2, 0), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 0, 1), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 2, 1), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 0, 2), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 1, 2), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 2, 2), BLACK);
_textBuffer->writeString(line2, Common::Point(xp + 1, 1), MAP_NAME_COLOR);
}
// Set the position of the Text Tag
// TODO: take current scroll into account
int xp = (mousePos.x - width / 2);
int yp = (mousePos.y - height / 2);
_textBounds = Common::Rect(xp, yp, xp + width, yp + height);
} else if (_bgFound == -1 && _oldBgFound != -1) {
// We need to clear a currently displayed name
delete _textBuffer;
}
_oldBgFound = _bgFound;
} else {
// Set the new text position
// TODO: take current scroll into account
int xp = (mousePos.x - _textBounds.width() / 2);
int yp = (mousePos.y - _textBounds.height() / 2);
_textBounds.moveTo(xp, yp);
}
// If the text tag was displayed, restore the graphics underneath it
if (_oldTextBounds.width() > 0)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTextBounds.left, _oldTextBounds.top), _oldTextBounds);
// See if we need to draw a Text Tag floating with the cursor
if (_textBuffer != nullptr)
screen.transBlitFrom(*_textBuffer, Common::Point(_textBounds.left, _textBounds.top));
// See if we need to flush the areas associated with the text
if (_oldTextBounds.width() > 0) {
if (slamIt)
// TODO: Take into account scroll
screen.slamRect(_oldTextBounds);
// If there's no text to display, reset the tag and old tag bounds
if (_textBuffer == nullptr) {
_textBounds.left = _textBounds.top = _textBounds.right = _textBounds.bottom = 0;
_oldTextBounds.left = _oldTextBounds.top = _oldTextBounds.right = _oldTextBounds.bottom = 0;
}
}
// If there's a text to display, then copy the drawn area to the screen
if (_textBuffer != nullptr && slamIt)
// TODO: Handle scroll
screen.slamRect(_textBounds);
}
void TattooMap::restoreArea(const Common::Rect &bounds) {
Screen &screen = *_vm->_screen;
Common::Rect r = bounds;
r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h()));
if (!r.isEmpty())
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r);
}
void TattooMap::showCloseUp(int closeUpNum) {
Screen &screen = *_vm->_screen;
// Get the closeup images
Common::String fname = Common::String::format("res%02d.vgs", closeUpNum + 1);
ImageFile pic(fname);
Common::Point closeUp(_data[closeUpNum].x * 100, _data[closeUpNum].y * 100);
Common::Point delta((SHERLOCK_SCREEN_WIDTH / 2 - closeUp.x / 100) * 100 / CLOSEUP_STEPS,
(SHERLOCK_SCREEN_HEIGHT / 2 - closeUp.y / 100) * 100 / CLOSEUP_STEPS);
Common::Rect oldBounds(closeUp.x / 100, closeUp.y / 100, closeUp.x / 100 + 1, closeUp.y / 100 + 1);
int size = 64;
int n = 256;
int deltaVal = 512;
bool minimize = false;
int scaleVal, newSize;
do
{
scaleVal = n;
newSize = pic[0].sDrawXSize(n);
if (newSize > size) {
if (minimize)
deltaVal /= 2;
n += deltaVal;
} else {
minimize = true;
deltaVal /= 2;
n -= deltaVal;
if (n < 1)
n = 1;
}
} while (deltaVal && size != newSize);
int deltaScale = (SCALE_THRESHOLD - scaleVal) / CLOSEUP_STEPS;
for (int step = 0; step < CLOSEUP_STEPS; ++step) {
Common::Point picSize(pic[0].sDrawXSize(scaleVal), pic[0].sDrawYSize(scaleVal));
Common::Point pt(closeUp.x / 100 - picSize.x, closeUp.y / 100 - picSize.y);
restoreArea(oldBounds);
screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal);
// TODO: handle scrolling
screen.slamRect(_oldTextBounds);
screen.slamArea(pt.x, pt.y, picSize.x, picSize.y);
oldBounds = Common::Rect(pt.x, pt.y, pt.x + picSize.x + 1, pt.y + picSize.y + 1);
closeUp += delta;
scaleVal += deltaScale;
}
// Handle final drawing of closeup
// TODO: Handle scrolling
Common::Rect r(SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2, SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2,
SHERLOCK_SCREEN_WIDTH / 2 + pic[0]._width / 2 + pic[0]._width,
SHERLOCK_SCREEN_HEIGHT / 2 + pic[0]._height / 2 + pic[0]._height);
restoreArea(oldBounds);
screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top));
screen.slamRect(oldBounds);
screen.slamRect(r);
}
} // End of namespace Tattoo } // End of namespace Tattoo
} // End of namespace Sherlock } // End of namespace Sherlock

View file

@ -25,6 +25,8 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#include "sherlock/map.h" #include "sherlock/map.h"
#include "sherlock/resources.h"
#include "sherlock/surface.h"
namespace Sherlock { namespace Sherlock {
@ -32,6 +34,8 @@ class SherlockEngine;
namespace Tattoo { namespace Tattoo {
#define CLOSEUP_STEPS 30
struct MapEntry : Common::Point { struct MapEntry : Common::Point {
int _iconNum; int _iconNum;
Common::String _description; Common::String _description;
@ -44,11 +48,35 @@ struct MapEntry : Common::Point {
class TattooMap : public Map { class TattooMap : public Map {
private: private:
Common::Array<MapEntry> _data; Common::Array<MapEntry> _data;
ImageFile *_iconImages;
int _bgFound, _oldBgFound;
Surface *_textBuffer;
Common::Rect _textBounds, _oldTextBounds;
/** /**
* Load data needed for the map * Load data needed for the map
*/ */
void loadData(); void loadData();
/**
* Draws all available location icons onto the back buffer
*/
void drwaMapIcons();
/**
* Draws the location names of whatever the mouse moves over on the map
*/
void checkMapNames(bool slamIt);
/**
* Restores an area of the map background
*/
void restoreArea(const Common::Rect &bounds);
/**
* This will load a specified close up and zoom it up to the middle of the screen
*/
void showCloseUp(int closeUpNum);
public: public:
TattooMap(SherlockEngine *vm); TattooMap(SherlockEngine *vm);
virtual ~TattooMap() {} virtual ~TattooMap() {}