2016-05-02 20:58:55 +02:00
|
|
|
#include "gfx.h"
|
|
|
|
#include "engines/util.h"
|
|
|
|
#include "common/system.h"
|
|
|
|
#include "common/file.h"
|
|
|
|
#include "graphics/palette.h"
|
|
|
|
#include "common/endian.h"
|
2016-05-07 23:27:16 +02:00
|
|
|
#include "dm/dungeonman.h"
|
2016-05-02 20:58:55 +02:00
|
|
|
|
2016-05-05 18:11:11 +02:00
|
|
|
|
|
|
|
namespace DM {
|
2016-05-02 20:58:55 +02:00
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
// TODO: this is ONLY for the Amiga version, name will have to be refactored
|
2016-05-04 12:50:06 +02:00
|
|
|
uint16 dmPalettes[10][16] = {
|
|
|
|
{0x000, 0xFFF, 0xFFF, 0xFFF, 0xFFF, 0xFFF, 0xFFF, 0xFFF, 0x000, 0xFFF, 0xAAA, 0xFFF, 0xAAA, 0x444, 0xFF0, 0xFF0},
|
|
|
|
{0x000, 0x666, 0x888, 0x620, 0x0CC, 0x840, 0x080, 0x0C0, 0xF00, 0xFA0, 0xC86, 0xFF0, 0x000, 0xAAA, 0x00F, 0xFFF},
|
|
|
|
{0x006, 0x0AA, 0xFF6, 0x840, 0xFF8, 0x000, 0x080, 0xA00, 0xC84, 0xFFA, 0xF84, 0xFC0, 0xFA0, 0x000, 0x620, 0xFFC},
|
|
|
|
{0x000, 0x666, 0x888, 0x840, 0xCA8, 0x0C0, 0x080, 0x0A0, 0x864, 0xF00, 0xA86, 0x642, 0x444, 0xAAA, 0x620, 0xFFF},
|
|
|
|
{0x000, 0x666, 0x888, 0x620, 0x0CC, 0x840, 0x080, 0x0C0, 0xF00, 0xFA0, 0xC86, 0xFF0, 0x444, 0xAAA, 0x00F, 0xFFF},
|
|
|
|
{0x000, 0x444, 0x666, 0x620, 0x0CC, 0x820, 0x060, 0x0A0, 0xC00, 0x000, 0x000, 0xFC0, 0x222, 0x888, 0x00C, 0xCCC},
|
|
|
|
{0x000, 0x222, 0x444, 0x420, 0x0CC, 0x620, 0x040, 0x080, 0xA00, 0x000, 0x000, 0xFA0, 0x000, 0x666, 0x00A, 0xAAA},
|
|
|
|
{0x000, 0x000, 0x222, 0x200, 0x0CC, 0x420, 0x020, 0x060, 0x800, 0x000, 0x000, 0xC80, 0x000, 0x444, 0x008, 0x888},
|
|
|
|
{0x000, 0x000, 0x000, 0x000, 0x0CC, 0x200, 0x000, 0x040, 0x600, 0x000, 0x000, 0xA60, 0x000, 0x222, 0x006, 0x666},
|
|
|
|
{0x000, 0x000, 0x000, 0x000, 0x0CC, 0x000, 0x000, 0x020, 0x400, 0x000, 0x000, 0x640, 0x000, 0x000, 0x004, 0x444}
|
|
|
|
};
|
|
|
|
|
2016-05-05 18:36:02 +02:00
|
|
|
|
2016-05-05 18:11:11 +02:00
|
|
|
enum GraphicIndice {
|
2016-05-06 18:20:30 +02:00
|
|
|
gFloorIndice = 75,
|
|
|
|
gCeilingIndice = 76
|
2016-05-05 18:11:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Frame {
|
2016-05-06 18:13:23 +02:00
|
|
|
// FIXME: these bundaries are inclusive, workaround by adding +1 in the drawFrame methods
|
|
|
|
uint16 destFromX, destToX, destFromY, destToY;
|
2016-05-05 18:11:11 +02:00
|
|
|
// srcWidth and srcHeight (present in the original sources) is redundant here, can be deduced from gaphicsIndice
|
2016-05-06 18:13:23 +02:00
|
|
|
uint16 srcX, srcY;
|
2016-05-05 18:11:11 +02:00
|
|
|
};
|
|
|
|
|
2016-05-06 18:20:30 +02:00
|
|
|
Frame gCeilingFrame = {0, 223, 0, 28, 0, 0};
|
|
|
|
Frame gFloorFrame = {0, 223, 66, 135, 0, 0};
|
2016-05-07 23:27:16 +02:00
|
|
|
Frame gWallFrameD3L2 = {0, 15, 25, 73, 0, 0}; // @ FRAME G0711_s_Graphic558_Frame_Wall_D3L2
|
|
|
|
Frame gWallFrameD3R2 = {208, 223, 25, 73, 0, 0}; // @ G0712_s_Graphic558_Frame_Wall_D3R2
|
2016-05-05 18:11:11 +02:00
|
|
|
|
2016-05-06 18:55:09 +02:00
|
|
|
extern Viewport gDefultViewPort = {0, 0};
|
2016-05-07 20:53:35 +02:00
|
|
|
extern Viewport gDungeonViewport = {0, 64}; // TODO: I guessed the numbers
|
2016-05-06 18:55:09 +02:00
|
|
|
|
2016-05-05 18:11:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
using namespace DM;
|
2016-05-04 12:50:06 +02:00
|
|
|
|
2016-05-02 20:58:55 +02:00
|
|
|
DisplayMan::DisplayMan(DMEngine *dmEngine) :
|
2016-05-06 18:20:30 +02:00
|
|
|
_vm(dmEngine), _currPalette(kPalSwoosh), _screenWidth(0), _screenHeight(0),
|
2016-05-05 18:11:11 +02:00
|
|
|
_vgaBuffer(NULL), _itemCount(0), _packedItemPos(NULL), _packedBitmaps(NULL),
|
2016-05-06 18:13:23 +02:00
|
|
|
_bitmaps(NULL) {}
|
2016-05-02 20:58:55 +02:00
|
|
|
|
|
|
|
DisplayMan::~DisplayMan() {
|
2016-05-05 18:11:11 +02:00
|
|
|
delete[] _packedBitmaps;
|
|
|
|
delete[] _packedItemPos;
|
2016-05-04 11:16:41 +02:00
|
|
|
delete[] _vgaBuffer;
|
2016-05-06 18:13:23 +02:00
|
|
|
delete[] _bitmaps;
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::setUpScreens(uint16 width, uint16 height) {
|
|
|
|
_screenWidth = width;
|
|
|
|
_screenHeight = height;
|
2016-05-06 18:20:30 +02:00
|
|
|
loadPalette(kPalSwoosh);
|
2016-05-02 20:58:55 +02:00
|
|
|
_vgaBuffer = new byte[_screenWidth * _screenHeight];
|
2016-05-06 18:20:30 +02:00
|
|
|
clearScreen(kColorBlack);
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::loadGraphics() {
|
|
|
|
Common::File f;
|
|
|
|
f.open("graphics.dat");
|
|
|
|
|
|
|
|
_itemCount = f.readUint16BE();
|
2016-05-05 18:11:11 +02:00
|
|
|
_packedItemPos = new uint32[_itemCount + 1];
|
|
|
|
_packedItemPos[0] = 0;
|
2016-05-02 20:58:55 +02:00
|
|
|
for (uint16 i = 1; i < _itemCount + 1; ++i)
|
2016-05-05 18:11:11 +02:00
|
|
|
_packedItemPos[i] = f.readUint16BE() + _packedItemPos[i - 1];
|
2016-05-02 20:58:55 +02:00
|
|
|
|
2016-05-05 18:11:11 +02:00
|
|
|
_packedBitmaps = new uint8[_packedItemPos[_itemCount]];
|
2016-05-02 20:58:55 +02:00
|
|
|
|
|
|
|
f.seek(2 + _itemCount * 4);
|
2016-05-05 18:11:11 +02:00
|
|
|
for (uint32 i = 0; i < _packedItemPos[_itemCount]; ++i)
|
|
|
|
_packedBitmaps[i] = f.readByte();
|
2016-05-02 20:58:55 +02:00
|
|
|
|
|
|
|
f.close();
|
2016-05-05 18:11:11 +02:00
|
|
|
|
|
|
|
unpackGraphics();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::unpackGraphics() {
|
|
|
|
uint32 unpackedBitmapsSize = 0;
|
|
|
|
for (uint16 i = 0; i <= 20; ++i)
|
2016-05-06 18:13:23 +02:00
|
|
|
unpackedBitmapsSize += width(i) * height(i);
|
2016-05-05 18:11:11 +02:00
|
|
|
for (uint16 i = 22; i <= 532; ++i)
|
2016-05-06 18:13:23 +02:00
|
|
|
unpackedBitmapsSize += width(i) * height(i);
|
2016-05-05 18:11:11 +02:00
|
|
|
// graphics items go from 0-20 and 22-532 inclusive, _unpackedItemPos 21 and 22 are there for indexing convenience
|
2016-05-06 18:13:23 +02:00
|
|
|
_bitmaps = new byte*[533];
|
|
|
|
_bitmaps[0] = new byte[unpackedBitmapsSize];
|
|
|
|
loadIntoBitmap(0, _bitmaps[0]);
|
2016-05-05 18:11:11 +02:00
|
|
|
for (uint16 i = 1; i <= 20; ++i) {
|
2016-05-06 18:13:23 +02:00
|
|
|
_bitmaps[i] = _bitmaps[i - 1] + width(i - 1) * height(i - 1);
|
|
|
|
loadIntoBitmap(i, _bitmaps[i]);
|
2016-05-05 18:11:11 +02:00
|
|
|
}
|
2016-05-06 18:13:23 +02:00
|
|
|
_bitmaps[22] = _bitmaps[20] + width(20) * height(20);
|
2016-05-05 18:11:11 +02:00
|
|
|
for (uint16 i = 23; i < 533; ++i) {
|
2016-05-06 18:13:23 +02:00
|
|
|
_bitmaps[i] = _bitmaps[i - 1] + width(i - 1) * height(i - 1);
|
|
|
|
loadIntoBitmap(i, _bitmaps[i]);
|
2016-05-05 18:11:11 +02:00
|
|
|
}
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
2016-05-04 12:50:06 +02:00
|
|
|
void DisplayMan::loadPalette(dmPaletteEnum palette) {
|
2016-05-05 18:11:11 +02:00
|
|
|
if (_currPalette == palette)
|
|
|
|
return;
|
|
|
|
|
2016-05-04 12:50:06 +02:00
|
|
|
byte colorPalette[16 * 3];
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
colorPalette[i * 3] = (dmPalettes[palette][i] >> 8) * (256 / 16);
|
|
|
|
colorPalette[i * 3 + 1] = (dmPalettes[palette][i] >> 4) * (256 / 16);
|
|
|
|
colorPalette[i * 3 + 2] = dmPalettes[palette][i] * (256 / 16);
|
|
|
|
}
|
|
|
|
_vm->_system->getPaletteManager()->setPalette(colorPalette, 0, 16);
|
2016-05-05 18:11:11 +02:00
|
|
|
_currPalette = palette;
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DisplayMan::loadIntoBitmap(uint16 index, byte *destBitmap) {
|
2016-05-05 18:11:11 +02:00
|
|
|
uint8 *data = _packedBitmaps + _packedItemPos[index];
|
2016-05-06 18:25:23 +02:00
|
|
|
uint16 width = READ_BE_UINT16(data);
|
|
|
|
uint16 height = READ_BE_UINT16(data + 2);
|
2016-05-02 20:58:55 +02:00
|
|
|
uint16 nextByteIndex = 4;
|
|
|
|
for (uint16 k = 0; k < width * height;) {
|
|
|
|
uint8 nextByte = data[nextByteIndex++];
|
|
|
|
uint8 nibble1 = (nextByte & 0xF0) >> 4;
|
|
|
|
uint8 nibble2 = (nextByte & 0x0F);
|
|
|
|
if (nibble1 <= 7) {
|
|
|
|
for (int j = 0; j < nibble1 + 1; ++j)
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
} else if (nibble1 == 0x8) {
|
|
|
|
uint8 byte1 = data[nextByteIndex++];
|
|
|
|
for (int j = 0; j < byte1 + 1; ++j)
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
} else if (nibble1 == 0xC) {
|
2016-05-06 18:25:23 +02:00
|
|
|
uint16 word1 = READ_BE_UINT16(data + nextByteIndex);
|
2016-05-02 20:58:55 +02:00
|
|
|
nextByteIndex += 2;
|
|
|
|
for (int j = 0; j < word1 + 1; ++j)
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
} else if (nibble1 == 0xB) {
|
|
|
|
uint8 byte1 = data[nextByteIndex++];
|
|
|
|
for (int j = 0; j < byte1 + 1; ++j, ++k)
|
|
|
|
destBitmap[k] = destBitmap[k - width];
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
} else if (nibble1 == 0xF) {
|
2016-05-06 18:25:23 +02:00
|
|
|
uint16 word1 = READ_BE_UINT16(data + nextByteIndex);
|
2016-05-02 20:58:55 +02:00
|
|
|
nextByteIndex += 2;
|
|
|
|
for (int j = 0; j < word1 + 1; ++j, ++k)
|
|
|
|
destBitmap[k] = destBitmap[k - width];
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
} else if (nibble1 == 9) {
|
|
|
|
uint8 byte1 = data[nextByteIndex++];
|
|
|
|
if (byte1 % 2)
|
|
|
|
byte1++;
|
|
|
|
else
|
|
|
|
destBitmap[k++] = nibble2;
|
|
|
|
|
|
|
|
for (int j = 0; j < byte1 / 2; ++j) {
|
|
|
|
uint8 byte2 = data[nextByteIndex++];
|
|
|
|
destBitmap[k++] = byte2 & 0x0F;
|
|
|
|
destBitmap[k++] = (byte2 & 0xF0) >> 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::blitToBitmap(byte *srcBitmap, uint16 srcWidth, uint16 srcX, uint16 srcY,
|
|
|
|
byte *destBitmap, uint16 destWidth,
|
|
|
|
uint16 destFromX, uint16 destToX, uint16 destFromY, uint16 destToY,
|
2016-05-06 18:55:09 +02:00
|
|
|
Color transparent, Viewport &destViewport) {
|
2016-05-06 18:13:23 +02:00
|
|
|
for (uint16 y = 0; y < destToY - destFromY; ++y)
|
|
|
|
for (uint16 x = 0; x < destToX - destFromX; ++x) {
|
|
|
|
byte srcPixel = srcBitmap[srcWidth * (y + srcY) + srcX + x];
|
2016-05-05 18:36:02 +02:00
|
|
|
if (srcPixel != transparent)
|
2016-05-06 18:55:09 +02:00
|
|
|
destBitmap[destWidth * (y + destFromY + destViewport.posY) + destFromX + x + destViewport.posX] = srcPixel;
|
2016-05-05 18:36:02 +02:00
|
|
|
}
|
2016-05-05 18:11:11 +02:00
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::blitToScreen(byte *srcBitmap, uint16 srcWidth, uint16 srcX, uint16 srcY,
|
|
|
|
uint16 destFromX, uint16 destToX, uint16 destFromY, uint16 destToY,
|
2016-05-06 18:55:09 +02:00
|
|
|
Color transparent, Viewport &viewport) {
|
2016-05-06 18:13:23 +02:00
|
|
|
blitToBitmap(srcBitmap, srcWidth, srcX, srcY,
|
2016-05-06 18:55:09 +02:00
|
|
|
getCurrentVgaBuffer(), _screenWidth, destFromX, destToX, destFromY, destToY, transparent, viewport);
|
2016-05-06 18:13:23 +02:00
|
|
|
}
|
2016-05-05 22:18:51 +02:00
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::blitToBitmap(byte *srcBitmap, uint16 srcWidth, uint16 srcHeight, byte *destBitmap, uint16 destWidth, uint16 destX, uint16 destY) {
|
|
|
|
for (uint16 y = 0; y < srcHeight; ++y)
|
|
|
|
memcpy(destBitmap + destWidth*(y + destY) + destX, srcBitmap + y * srcWidth, sizeof(byte)* srcWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::flipBitmapHorizontal(byte *bitmap, uint16 width, uint16 height) {
|
|
|
|
for (uint16 y = 0; y < height; ++y)
|
|
|
|
for (uint16 x = 0; x < width / 2; ++x) {
|
2016-05-05 22:18:51 +02:00
|
|
|
byte tmp;
|
|
|
|
tmp = bitmap[y*width + x];
|
|
|
|
bitmap[y*width + x] = bitmap[y*width + width - 1 - x];
|
|
|
|
bitmap[y*width + width - 1 - x] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::flipBitmapVertical(byte *bitmap, uint16 width, uint16 height) {
|
2016-05-05 22:18:51 +02:00
|
|
|
byte *tmp = new byte[width];
|
|
|
|
|
|
|
|
for (uint16 y = 0; y < height / 2; ++y) {
|
2016-05-06 18:13:23 +02:00
|
|
|
memcpy(tmp, bitmap + y * width, width);
|
|
|
|
memcpy(bitmap + y * width, bitmap + (height - 1 - y) * width, width);
|
|
|
|
memcpy(bitmap + (height - 1 - y) * width, tmp, width);
|
2016-05-05 22:18:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
delete[] tmp;
|
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
|
2016-05-02 20:58:55 +02:00
|
|
|
|
|
|
|
void DisplayMan::updateScreen() {
|
|
|
|
_vm->_system->copyRectToScreen(_vgaBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight);
|
|
|
|
_vm->_system->updateScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
byte *DisplayMan::getCurrentVgaBuffer() {
|
|
|
|
return _vgaBuffer;
|
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
uint16 DisplayMan::width(uint16 index) {
|
2016-05-05 18:11:11 +02:00
|
|
|
byte *data = _packedBitmaps + _packedItemPos[index];
|
2016-05-06 18:25:23 +02:00
|
|
|
return READ_BE_UINT16(data);
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
uint16 DisplayMan::height(uint16 index) {
|
2016-05-05 18:11:11 +02:00
|
|
|
uint8 *data = _packedBitmaps + _packedItemPos[index];
|
2016-05-06 18:25:23 +02:00
|
|
|
return READ_BE_UINT16(data + 2);
|
2016-05-02 20:58:55 +02:00
|
|
|
}
|
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::drawWallSetBitmap(byte *bitmap, Frame &f, uint16 srcWidth) {
|
2016-05-06 18:55:09 +02:00
|
|
|
blitToScreen(bitmap, srcWidth, f.srcX, f.srcY, f.destFromX, f.destToX + 1, f.destFromY, f.destToY + 1, kColorFlesh, gDungeonViewport);
|
2016-05-05 19:49:26 +02:00
|
|
|
}
|
|
|
|
|
2016-05-05 18:11:11 +02:00
|
|
|
|
2016-05-05 22:18:51 +02:00
|
|
|
|
2016-05-06 18:13:23 +02:00
|
|
|
void DisplayMan::drawDungeon(direction dir, uint16 posX, uint16 posY) {
|
2016-05-06 18:20:30 +02:00
|
|
|
loadPalette(kPalDungeonView0);
|
2016-05-06 18:13:23 +02:00
|
|
|
// TODO: this is a global variable, set from here
|
|
|
|
bool flippedWallAndFootprints = (posX + posY + dir) & 1;
|
|
|
|
|
|
|
|
// NOTE: this can hold every bitmap, width and height is "flexible"
|
|
|
|
byte *tmpBitmap = new byte[305 * 111];
|
2016-05-06 18:20:30 +02:00
|
|
|
clearBitmap(tmpBitmap, 305, 111, kColorBlack);
|
2016-05-06 18:13:23 +02:00
|
|
|
|
|
|
|
if (flippedWallAndFootprints) {
|
2016-05-06 18:20:30 +02:00
|
|
|
blitToBitmap(_bitmaps[gFloorIndice], width(gFloorIndice), height(gFloorIndice), tmpBitmap, width(gFloorIndice));
|
|
|
|
flipBitmapHorizontal(tmpBitmap, width(gFloorIndice), height(gFloorIndice));
|
|
|
|
drawWallSetBitmap(tmpBitmap, gFloorFrame, width(gFloorIndice));
|
|
|
|
drawWallSetBitmap(_bitmaps[gCeilingIndice], gCeilingFrame, width(gCeilingIndice));
|
2016-05-06 18:13:23 +02:00
|
|
|
} else {
|
2016-05-06 18:20:30 +02:00
|
|
|
blitToBitmap(_bitmaps[gCeilingIndice], width(gCeilingIndice), height(gCeilingIndice), tmpBitmap, width(gCeilingIndice));
|
|
|
|
flipBitmapHorizontal(tmpBitmap, width(gCeilingIndice), height(gCeilingIndice));
|
|
|
|
drawWallSetBitmap(tmpBitmap, gCeilingFrame, width(gCeilingIndice));
|
|
|
|
drawWallSetBitmap(_bitmaps[gFloorIndice], gFloorFrame, width(gFloorIndice));
|
2016-05-06 18:13:23 +02:00
|
|
|
}
|
2016-05-05 22:18:51 +02:00
|
|
|
|
2016-05-07 23:27:16 +02:00
|
|
|
// TODO: CRUDE TEST CODE AT BEST
|
|
|
|
if (_vm->_dungeonMan->getRelSquareType(dir, 3, -2, posX, posY) == kWallSquareType)
|
|
|
|
drawWallSetBitmap(_bitmaps[77 + 12], gWallFrameD3L2, width(77 + 12));
|
|
|
|
// TODO CRUDE TEST CODE AT BEST
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-05 22:18:51 +02:00
|
|
|
|
|
|
|
delete[] tmpBitmap;
|
2016-05-05 19:49:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::clearScreen(Color color) {
|
|
|
|
memset(getCurrentVgaBuffer(), color, sizeof(byte) * _screenWidth * _screenHeight);
|
2016-05-05 22:18:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayMan::clearBitmap(byte *bitmap, uint16 width, uint16 height, Color color) {
|
|
|
|
memset(bitmap, color, sizeof(byte) * width * height);
|
2016-05-05 18:11:11 +02:00
|
|
|
}
|