2008-01-28 12:31:14 +00:00
|
|
|
/* 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 2
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2008-01-28 12:20:53 +00:00
|
|
|
#include "graphics.h"
|
|
|
|
#include "disk.h"
|
|
|
|
|
2008-01-28 22:05:23 +00:00
|
|
|
#include "common/algorithm.h"
|
2008-02-03 10:48:07 +00:00
|
|
|
#include "parallaction/parallaction.h"
|
2008-01-28 22:05:23 +00:00
|
|
|
|
2008-01-28 12:20:53 +00:00
|
|
|
namespace Parallaction {
|
|
|
|
|
2008-01-28 16:52:41 +00:00
|
|
|
GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(0), _keep(true) {
|
2008-01-28 12:20:53 +00:00
|
|
|
if (name) {
|
|
|
|
_name = strdup(name);
|
|
|
|
} else {
|
|
|
|
_name = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GfxObj::~GfxObj() {
|
|
|
|
delete _frames;
|
|
|
|
free(_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GfxObj::release() {
|
|
|
|
// _keep = false;
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *GfxObj::getName() const {
|
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint GfxObj::getNum() {
|
|
|
|
return _frames->getNum();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-28 15:20:47 +00:00
|
|
|
void GfxObj::getRect(uint f, Common::Rect &r) {
|
|
|
|
_frames->getRect(f, r);
|
2008-01-28 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-28 15:20:47 +00:00
|
|
|
byte *GfxObj::getData(uint f) {
|
|
|
|
return _frames->getData(f);
|
2008-01-28 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
2008-02-03 10:48:07 +00:00
|
|
|
uint GfxObj::getRawSize(uint f) {
|
|
|
|
return _frames->getRawSize(f);
|
|
|
|
}
|
|
|
|
uint GfxObj::getSize(uint f) {
|
|
|
|
return _frames->getSize(f);
|
|
|
|
}
|
|
|
|
|
2008-01-28 12:20:53 +00:00
|
|
|
|
2008-01-30 23:12:51 +00:00
|
|
|
void GfxObj::setFlags(uint32 flags) {
|
2008-01-28 12:20:53 +00:00
|
|
|
_flags |= flags;
|
|
|
|
}
|
|
|
|
|
2008-01-30 23:12:51 +00:00
|
|
|
void GfxObj::clearFlags(uint32 flags) {
|
2008-01-28 12:20:53 +00:00
|
|
|
_flags &= ~flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
GfxObj* Gfx::loadAnim(const char *name) {
|
2008-07-03 10:31:25 +00:00
|
|
|
Frames* frames = _disk->loadFrames(name);
|
|
|
|
assert(frames);
|
|
|
|
|
|
|
|
GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name);
|
2008-01-28 12:20:53 +00:00
|
|
|
assert(obj);
|
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
// animation Z is not set here, but controlled by game scripts and user interaction.
|
|
|
|
// it is always >=0 and <screen height
|
2008-07-02 01:41:08 +00:00
|
|
|
obj->transparentKey = 0;
|
2008-06-30 01:36:50 +00:00
|
|
|
_gfxobjList.push_back(obj);
|
2008-01-28 12:20:53 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GfxObj* Gfx::loadGet(const char *name) {
|
2008-06-29 09:30:32 +00:00
|
|
|
GfxObj *obj = _disk->loadStatic(name);
|
2008-01-28 12:20:53 +00:00
|
|
|
assert(obj);
|
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations
|
2008-06-29 09:30:32 +00:00
|
|
|
obj->type = kGfxObjTypeGet;
|
2008-07-02 01:41:08 +00:00
|
|
|
obj->transparentKey = 0;
|
2008-06-30 01:36:50 +00:00
|
|
|
_gfxobjList.push_back(obj);
|
2008-01-28 12:20:53 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
GfxObj* Gfx::loadDoor(const char *name) {
|
2008-07-03 10:31:25 +00:00
|
|
|
Frames *frames = _disk->loadFrames(name);
|
|
|
|
assert(frames);
|
|
|
|
|
|
|
|
GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name);
|
2008-01-28 12:20:53 +00:00
|
|
|
assert(obj);
|
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first
|
2008-07-02 01:41:08 +00:00
|
|
|
obj->transparentKey = 0;
|
2008-06-30 01:36:50 +00:00
|
|
|
_gfxobjList.push_back(obj);
|
2008-01-28 12:20:53 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::clearGfxObjects() {
|
2008-06-29 09:56:44 +00:00
|
|
|
_gfxobjList.clear();
|
2008-01-28 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::showGfxObj(GfxObj* obj, bool visible) {
|
2008-06-30 01:36:50 +00:00
|
|
|
// if (!obj || obj->isVisible() == visible) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
assert(obj);
|
2008-01-28 12:20:53 +00:00
|
|
|
|
|
|
|
if (visible) {
|
|
|
|
obj->setFlags(kGfxObjVisible);
|
|
|
|
} else {
|
|
|
|
obj->clearFlags(kGfxObjVisible);
|
2008-06-30 01:36:50 +00:00
|
|
|
// _gfxobjList.remove(obj);
|
2008-01-28 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-01-28 16:52:41 +00:00
|
|
|
|
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
bool compareZ(const GfxObj* a1, const GfxObj* a2) {
|
2008-01-28 22:05:23 +00:00
|
|
|
return a1->z < a2->z;
|
2008-01-28 16:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::sortAnimations() {
|
2008-06-29 09:56:44 +00:00
|
|
|
GfxObjList::iterator first = _gfxobjList.begin();
|
|
|
|
GfxObjList::iterator last = _gfxobjList.end();
|
2008-01-28 16:52:41 +00:00
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
Common::sort(first, last, compareZ);
|
2008-01-28 16:52:41 +00:00
|
|
|
}
|
|
|
|
|
2008-07-02 01:41:08 +00:00
|
|
|
|
|
|
|
void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) {
|
|
|
|
if (!obj->isVisible()) {
|
|
|
|
return;
|
|
|
|
}
|
2008-01-28 12:20:53 +00:00
|
|
|
|
|
|
|
Common::Rect rect;
|
|
|
|
byte *data;
|
|
|
|
|
2008-07-02 01:41:08 +00:00
|
|
|
uint scrollX = (scene) ? -_varScrollX : 0;
|
|
|
|
|
|
|
|
obj->getRect(obj->frame, rect);
|
|
|
|
rect.translate(obj->x + scrollX, obj->y);
|
|
|
|
data = obj->getData(obj->frame);
|
|
|
|
|
|
|
|
if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) {
|
|
|
|
blt(rect, data, &surf, obj->layer, obj->transparentKey);
|
|
|
|
} else {
|
|
|
|
unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Gfx::drawGfxObjects(Graphics::Surface &surf) {
|
|
|
|
|
2008-01-28 16:52:41 +00:00
|
|
|
sortAnimations();
|
2008-01-28 12:20:53 +00:00
|
|
|
// TODO: some zones don't appear because of wrong masking (3 or 0?)
|
|
|
|
// TODO: Dr.Ki is not visible inside the club
|
|
|
|
|
2008-01-28 13:10:49 +00:00
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
GfxObjList::iterator b = _gfxobjList.begin();
|
|
|
|
GfxObjList::iterator e = _gfxobjList.end();
|
2008-01-28 12:20:53 +00:00
|
|
|
|
2008-06-29 09:56:44 +00:00
|
|
|
for (; b != e; b++) {
|
2008-07-02 01:41:08 +00:00
|
|
|
drawGfxObject(*b, surf, true);
|
2008-01-28 12:20:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-30 01:36:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) {
|
|
|
|
byte *dst = (byte*)surf->getBasePtr(x, y);
|
|
|
|
font->setColor(color);
|
|
|
|
font->drawString(dst, surf->w, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
|
|
|
|
|
|
|
|
uint16 lines = 0;
|
|
|
|
uint16 linewidth = 0;
|
|
|
|
|
|
|
|
uint16 rx = 10;
|
|
|
|
uint16 ry = 4;
|
|
|
|
|
|
|
|
uint16 blankWidth = font->getStringWidth(" ");
|
|
|
|
uint16 tokenWidth = 0;
|
|
|
|
|
|
|
|
char token[MAX_TOKEN_LEN];
|
|
|
|
|
|
|
|
if (wrapwidth == -1)
|
|
|
|
wrapwidth = _vm->_screenWidth;
|
|
|
|
|
|
|
|
while (strlen(text) > 0) {
|
|
|
|
|
|
|
|
text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
|
|
|
|
|
|
|
|
if (!scumm_stricmp(token, "%p")) {
|
|
|
|
lines++;
|
|
|
|
rx = 10;
|
|
|
|
ry = 4 + lines*10; // y
|
|
|
|
|
|
|
|
strcpy(token, "> .......");
|
|
|
|
strncpy(token+2, _password, strlen(_password));
|
|
|
|
tokenWidth = font->getStringWidth(token);
|
|
|
|
} else {
|
|
|
|
tokenWidth = font->getStringWidth(token);
|
|
|
|
|
|
|
|
linewidth += tokenWidth;
|
|
|
|
|
|
|
|
if (linewidth > wrapwidth) {
|
|
|
|
// wrap line
|
|
|
|
lines++;
|
|
|
|
rx = 10; // x
|
|
|
|
ry = 4 + lines*10; // y
|
|
|
|
linewidth = tokenWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!scumm_stricmp(token, "%s")) {
|
|
|
|
sprintf(token, "%d", _score);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
drawText(font, surf, rx, ry, token, color);
|
|
|
|
|
|
|
|
rx += tokenWidth + blankWidth;
|
|
|
|
linewidth += blankWidth;
|
|
|
|
|
|
|
|
text = Common::ltrim(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this is the maximum size of an unpacked frame in BRA
|
|
|
|
byte _unpackedBitmap[640*401];
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
|
|
|
|
|
|
|
|
byte *d = _unpackedBitmap;
|
|
|
|
|
|
|
|
while (size > 0) {
|
|
|
|
|
|
|
|
uint8 p = *data++;
|
|
|
|
size--;
|
|
|
|
uint8 color = p & 0xF;
|
|
|
|
uint8 repeat = (p & 0xF0) >> 4;
|
|
|
|
if (repeat == 0) {
|
|
|
|
repeat = *data++;
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(d, color, repeat);
|
|
|
|
d += repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
blt(r, _unpackedBitmap, surf, z, transparentColor);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
|
|
|
|
|
|
|
|
byte *d = _unpackedBitmap;
|
|
|
|
uint pixelsLeftInLine = r.width();
|
|
|
|
|
|
|
|
while (size > 0) {
|
|
|
|
uint8 p = *data++;
|
|
|
|
size--;
|
|
|
|
uint8 color = p & 0xF;
|
|
|
|
uint8 repeat = (p & 0xF0) >> 4;
|
|
|
|
if (repeat == 0) {
|
|
|
|
repeat = *data++;
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
if (repeat == 0) {
|
|
|
|
// end of line
|
|
|
|
repeat = pixelsLeftInLine;
|
|
|
|
pixelsLeftInLine = r.width();
|
|
|
|
} else {
|
|
|
|
pixelsLeftInLine -= repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(d, color, repeat);
|
|
|
|
d += repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
blt(r, _unpackedBitmap, surf, z, transparentColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) {
|
|
|
|
|
|
|
|
Common::Point dp;
|
|
|
|
Common::Rect q(r);
|
|
|
|
|
|
|
|
Common::Rect clipper(surf->w, surf->h);
|
|
|
|
|
|
|
|
q.clip(clipper);
|
|
|
|
if (!q.isValidRect()) return;
|
|
|
|
|
|
|
|
dp.x = q.left;
|
|
|
|
dp.y = q.top;
|
|
|
|
|
|
|
|
q.translate(-r.left, -r.top);
|
|
|
|
|
|
|
|
byte *s = data + q.left + q.top * r.width();
|
|
|
|
byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
|
|
|
|
|
|
|
|
uint sPitch = r.width() - q.width();
|
|
|
|
uint dPitch = surf->w - q.width();
|
|
|
|
|
|
|
|
|
|
|
|
if (_varRenderMode == 2) {
|
|
|
|
|
|
|
|
for (uint16 i = 0; i < q.height(); i++) {
|
|
|
|
|
|
|
|
for (uint16 j = 0; j < q.width(); j++) {
|
|
|
|
if (*s != transparentColor) {
|
|
|
|
if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
|
|
|
|
byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
|
|
|
|
if (z >= v) *d = 5;
|
|
|
|
} else {
|
|
|
|
*d = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += sPitch;
|
|
|
|
d += dPitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
|
|
|
|
|
|
|
|
for (uint16 i = 0; i < q.height(); i++) {
|
|
|
|
|
|
|
|
for (uint16 j = 0; j < q.width(); j++) {
|
|
|
|
if (*s != transparentColor) {
|
|
|
|
byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
|
|
|
|
if (z >= v) *d = *s;
|
|
|
|
}
|
|
|
|
|
|
|
|
s++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += sPitch;
|
|
|
|
d += dPitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
for (uint16 i = q.top; i < q.bottom; i++) {
|
|
|
|
for (uint16 j = q.left; j < q.right; j++) {
|
|
|
|
if (*s != transparentColor)
|
|
|
|
*d = *s;
|
|
|
|
|
|
|
|
s++;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s += sPitch;
|
|
|
|
d += dPitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-28 12:20:53 +00:00
|
|
|
} // namespace Parallaction
|