ADL: Implement hires2 PIC drawing

This commit is contained in:
Walter van Niftrik 2016-03-11 23:46:41 +01:00 committed by Walter van Niftrik
parent 641d87f752
commit 930bdcfa91
6 changed files with 393 additions and 2 deletions

View File

@ -219,9 +219,24 @@ void Display::loadFrameBuffer(Common::ReadStream &stream) {
error("Failed to read frame buffer");
}
void Display::putPixelRaw(const Common::Point &p, byte color) {
byte *b = _frameBuf + p.y * DISPLAY_PITCH + (p.x / 7);
color ^= *b;
color &= 0x80 | (1 << (p.x % 7));
*b ^= color;
}
void Display::putPixel(const Common::Point &p, byte color) {
byte offset = p.x / 7;
byte mask = 0x80 | (1 << (p.x % 7));
// Since white and black are in both palettes, we leave
// the palette bit alone
if ((color & 0x7f) == 0x7f || (color & 0x7f) == 0)
mask &= 0x7f;
// Adjust colors starting with bits '01' or '10' for
// odd offsets
if (offset & 1) {
byte c = color << 1;
if (c >= 0x40 && c < 0xc0)
@ -230,10 +245,15 @@ void Display::putPixel(const Common::Point &p, byte color) {
byte *b = _frameBuf + p.y * DISPLAY_PITCH + offset;
color ^= *b;
color &= 1 << (p.x % 7);
color &= mask;
*b ^= color;
}
bool Display::getPixelBit(const Common::Point &p) const {
byte *b = _frameBuf + p.y * DISPLAY_PITCH + (p.x / 7);
return *b & (1 << (p.x % 7));
}
void Display::clear(byte color) {
byte val = 0;

View File

@ -61,7 +61,9 @@ public:
// Graphics
void loadFrameBuffer(Common::ReadStream &stream);
void putPixelRaw(const Common::Point &p, byte color);
void putPixel(const Common::Point &p, byte color);
bool getPixelBit(const Common::Point &p) const;
void clear(byte color);
// Text

View File

@ -28,6 +28,7 @@
#include "adl/hires2.h"
#include "adl/display.h"
#include "adl/picture.h"
namespace Adl {
@ -121,9 +122,22 @@ void HiRes2Engine::restartGame() {
}
void HiRes2Engine::drawPic(byte pic, Common::Point pos) const {
// Temp hack
PictureD test(*_display);
Common::File f;
if (!f.open(IDS_HR2_DISK_IMAGE))
error("Failed to open file '" IDS_HR2_DISK_IMAGE "'");
f.seek(0x1000);
test.draw(f);
}
void HiRes2Engine::showRoom() const {
drawPic(0, Common::Point());
_display->updateHiResScreen();
}
Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd) {

View File

@ -5,7 +5,8 @@ MODULE_OBJS := \
detection.o \
display.o \
hires1.o \
hires2.o
hires2.o \
picture.o
MODULE_DIRS += \
engines/adl

298
engines/adl/picture.cpp Normal file
View File

@ -0,0 +1,298 @@
/* 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.
*
*/
#include "common/stream.h"
#include "common/rect.h"
#include "common/textconsole.h"
#include "adl/display.h"
#include "adl/picture.h"
#define MIN_COMMAND 0xe0
namespace Adl {
#define NUM_PATTERNS 22
#define PATTERN_LEN 4
static const byte fillPatterns[NUM_PATTERNS][PATTERN_LEN] = {
{ 0x00, 0x00, 0x00, 0x00 },
{ 0x80, 0x80, 0x80, 0x80 },
{ 0xff, 0xff, 0xff, 0xff },
{ 0x7f, 0x7f, 0x7f, 0x7f },
{ 0x2a, 0x55, 0x2a, 0x55 },
{ 0xaa, 0xd5, 0xaa, 0xd5 },
{ 0x55, 0x2a, 0x55, 0x2a },
{ 0xd5, 0xaa, 0xd5, 0xaa },
{ 0x33, 0x66, 0x4c, 0x19 },
{ 0xb3, 0xe6, 0xcc, 0x99 },
{ 0x22, 0x44, 0x08, 0x11 },
{ 0xa2, 0xc4, 0x88, 0x91 },
{ 0x11, 0x22, 0x44, 0x08 },
{ 0x91, 0xa2, 0xc4, 0x88 },
{ 0x6e, 0x5d, 0x3b, 0x77 },
{ 0xee, 0xdd, 0xbb, 0xf7 },
{ 0x5d, 0x3b, 0x77, 0x6e },
{ 0xdd, 0xbb, 0xf7, 0xee },
{ 0x66, 0x4c, 0x19, 0x33 },
{ 0xe6, 0xcc, 0x99, 0xb3 },
{ 0x33, 0x66, 0x4c, 0x19 },
{ 0xb3, 0xe6, 0xcc, 0x99 }
};
#define CHECK_COMMAND(X) \
do { \
if ((X) >= MIN_COMMAND) { \
pic.seek(-1, SEEK_CUR); \
return; \
} \
} while (0)
#define READ_BYTE(b) \
do { \
b = pic.readByte(); \
if (pic.eos() || pic.err()) \
return; \
CHECK_COMMAND(b); \
} while (0)
#define READ_POINT(p) \
do { \
READ_BYTE(p.x); \
p.x <<= 1; \
READ_BYTE(p.y); \
} while (0)
// Draws a four-connected line
void PictureD::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const {
int16 deltaX = p2.x - p1.x;
int8 xStep = 1;
if (deltaX < 0) {
deltaX = -deltaX;
xStep = -1;
}
int16 deltaY = p2.y - p1.y;
int8 yStep = -1;
if (deltaY > 0) {
deltaY = -deltaY;
yStep = 1;
}
Common::Point p(p1);
int16 steps = deltaX - deltaY + 1;
int16 err = deltaX + deltaY;
while (true) {
_display.putPixel(p, color);
if (--steps == 0)
return;
if (err < 0) {
p.y += yStep;
err += deltaX;
} else {
p.x += xStep;
err += deltaY;
}
}
}
void PictureD::clear() {
_display.clear(0xff);
_color = 0;
}
void PictureD::drawCorners(Common::SeekableReadStream &pic, bool yFirst) {
Common::Point p;
READ_POINT(p);
if (yFirst)
goto doYStep;
while (true) {
int16 n;
READ_BYTE(n);
_display.putPixel(p, _color);
n <<= 1;
drawLine(p, Common::Point(n, p.y), _color);
p.x = n;
doYStep:
READ_BYTE(n);
_display.putPixel(p, _color);
drawLine(p, Common::Point(p.x, n), _color);
_display.putPixel(Common::Point(p.x + 1, p.y), _color);
drawLine(Common::Point(p.x + 1, p.y), Common::Point(p.x + 1, n), _color);
p.y = n;
}
}
void PictureD::drawRelativeLines(Common::SeekableReadStream &pic) {
Common::Point p1;
READ_POINT(p1);
_display.putPixel(p1, _color);
while (true) {
Common::Point p2(p1);
byte n;
READ_BYTE(n);
byte h = (n & 0x70) >> 4;
byte l = n & 7;
if (n & 0x80)
p2.x -= (h << 1);
else
p2.x += (h << 1);
if (n & 8)
p2.y -= l;
else
p2.y += l;
drawLine(p1, p2, _color);
p1 = p2;
}
}
void PictureD::drawAbsoluteLines(Common::SeekableReadStream &pic) {
Common::Point p1;
READ_POINT(p1);
_display.putPixel(p1, _color);
while (true) {
Common::Point p2;
READ_POINT(p2);
drawLine(p1, p2, _color);
p1 = p2;
}
}
static byte getPatternColor(const Common::Point &p, byte pattern) {
if (pattern >= NUM_PATTERNS)
error("Invalid fill pattern %i encountered", pattern);
byte offset = (p.y & 1) << 1;
offset += (p.x / 7) & 3;
return fillPatterns[pattern][offset % PATTERN_LEN];
}
void PictureD::fillRow(const Common::Point &p, bool stopBit, byte pattern) {
const byte color = getPatternColor(p, pattern);
_display.putPixelRaw(p, color);
Common::Point q(p);
byte c = color;
while (++q.x < DISPLAY_WIDTH && _display.getPixelBit(q) != stopBit) {
if ((q.x % 7) == 0)
c = getPatternColor(q, pattern);
_display.putPixelRaw(q, c);
}
q = p;
c = color;
while (--q.x >= 0 && _display.getPixelBit(q) != stopBit) {
if ((q.x % 7) == 6)
c = getPatternColor(q, pattern);
_display.putPixelRaw(q, c);
}
}
// Basic flood fill
void PictureD::fill(Common::SeekableReadStream &pic) {
byte pattern;
READ_BYTE(pattern);
while (true) {
Common::Point p;
READ_POINT(p);
bool stopBit = !_display.getPixelBit(p);
while (--p.y >= 0) {
if (_display.getPixelBit(p) == stopBit)
break;
if (_display.getPixelBit(Common::Point(p.x + 1, p.y)) == stopBit)
break;
}
while (++p.y < DISPLAY_HEIGHT) {
if (_display.getPixelBit(p) == stopBit)
break;
if (_display.getPixelBit(Common::Point(p.x + 1, p.y)) == stopBit)
break;
fillRow(p, stopBit, pattern);
}
}
}
void PictureD::draw(Common::SeekableReadStream &pic) {
while (true) {
byte opcode = pic.readByte();
if (pic.eos() || pic.err())
error("Error reading picture");
switch (opcode) {
case 0xe0:
drawCorners(pic, false);
break;
case 0xe1:
drawCorners(pic, true);
break;
case 0xe2:
drawRelativeLines(pic);
break;
case 0xe3:
drawAbsoluteLines(pic);
break;
case 0xe4:
fill(pic);
break;
case 0xe5:
clear();
break;
case 0xff:
return;
default:
error("Invalid pic opcode %02x", opcode);
}
}
}
} // End of namespace Adl

56
engines/adl/picture.h Normal file
View File

@ -0,0 +1,56 @@
/* 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.
*
*/
#ifndef ADL_PICTURE_H
#define ADL_PICTURE_H
namespace Common{
class SeekableReadStream;
class Point;
}
namespace Adl {
class Display;
class PictureD {
public:
PictureD(Display &display) : _display(display) { }
void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const;
void draw(Common::SeekableReadStream &pic);
private:
void clear();
void drawCorners(Common::SeekableReadStream &pic, bool yFirst);
void drawRelativeLines(Common::SeekableReadStream &pic);
void drawAbsoluteLines(Common::SeekableReadStream &pic);
void fillRow(const Common::Point &p, bool fillBit, byte pattern);
void fill(Common::SeekableReadStream &pic);
Display &_display;
byte _color;
};
} // End of namespace Adl
#endif