mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 12:39:56 +00:00
191 lines
4.8 KiB
C++
191 lines
4.8 KiB
C++
/* 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.
|
|
*
|
|
*/
|
|
|
|
// Conversion routines for planar graphics in Amiga versions
|
|
|
|
|
|
#include "agos/agos.h"
|
|
#include "agos/intern.h"
|
|
|
|
#include "common/endian.h"
|
|
|
|
namespace AGOS {
|
|
|
|
enum {
|
|
kMaxColorDepth = 5
|
|
};
|
|
|
|
static void uncompressPlane(const byte *plane, byte *outptr, int length) {
|
|
while (length != 0) {
|
|
int wordlen;
|
|
signed char x = *plane++;
|
|
if (x >= 0) {
|
|
wordlen = MIN<int>(x + 1, length);
|
|
uint16 w = READ_UINT16(plane); plane += 2;
|
|
for (int i = 0; i < wordlen; ++i) {
|
|
WRITE_UINT16(outptr, w); outptr += 2;
|
|
}
|
|
} else {
|
|
wordlen = MIN<int>(-x, length);
|
|
memcpy(outptr, plane, wordlen * 2);
|
|
outptr += wordlen * 2;
|
|
plane += wordlen * 2;
|
|
}
|
|
length -= wordlen;
|
|
}
|
|
}
|
|
|
|
static void bitplaneToChunky(uint16 *w, uint8 colorDepth, uint8 *&dst) {
|
|
for (int j = 0; j < 8; j++) {
|
|
byte color1 = 0;
|
|
byte color2 = 0;
|
|
for (int p = 0; p < colorDepth; ++p) {
|
|
if (w[p] & 0x8000) {
|
|
color1 |= 1 << p;
|
|
}
|
|
if (w[p] & 0x4000) {
|
|
color2 |= 1 << p;
|
|
}
|
|
w[p] <<= 2;
|
|
}
|
|
if (colorDepth > 4) {
|
|
*dst++ = color1;
|
|
*dst++ = color2;
|
|
} else {
|
|
*dst++ = (color1 << 4) | color2;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void bitplaneToChunkyText(uint16 *w, uint8 colorDepth, uint8 *&dst) {
|
|
for (int j = 0; j < 16; j++) {
|
|
byte color = 0;
|
|
for (int p = 0; p < colorDepth; ++p) {
|
|
if (w[p] & 0x8000) {
|
|
color |= 1 << p;
|
|
}
|
|
w[p] <<= 1;
|
|
}
|
|
if (color)
|
|
color |= 0xC0;
|
|
*dst++ = color;
|
|
}
|
|
}
|
|
|
|
static void convertCompressedImage(const byte *src, byte *dst, uint8 colorDepth, int height, int width, bool horizontal = true) {
|
|
const byte *plane[kMaxColorDepth];
|
|
byte *uncptr[kMaxColorDepth];
|
|
int length, i, j;
|
|
|
|
byte *uncbfrout = (byte *)malloc(width * height);
|
|
|
|
length = (width + 15) / 16 * height;
|
|
|
|
for (i = 0; i < colorDepth; ++i) {
|
|
plane[i] = src + READ_BE_UINT16(src + i * 4) + READ_BE_UINT16(src + i * 4 + 2);
|
|
uncptr[i] = (uint8 *)malloc(length * 2);
|
|
uncompressPlane(plane[i], uncptr[i], length);
|
|
plane[i] = uncptr[i];
|
|
}
|
|
|
|
byte *uncbfroutptr = uncbfrout;
|
|
for (i = 0; i < length; ++i) {
|
|
uint16 w[kMaxColorDepth];
|
|
for (j = 0; j < colorDepth; ++j) {
|
|
w[j] = READ_BE_UINT16(plane[j]); plane[j] += 2;
|
|
}
|
|
bitplaneToChunky(w, colorDepth, uncbfroutptr);
|
|
}
|
|
|
|
uncbfroutptr = uncbfrout;
|
|
const int chunkSize = colorDepth > 4 ? 16 : 8;
|
|
if (horizontal) {
|
|
for (j = 0; j < height; ++j) {
|
|
for (i = 0; i < width / 16; ++i) {
|
|
memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
|
|
uncbfroutptr += chunkSize;
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < width / 16; ++i) {
|
|
for (j = 0; j < height; ++j) {
|
|
memcpy(dst + width * chunkSize / 16 * j + chunkSize * i, uncbfroutptr, chunkSize);
|
|
uncbfroutptr += chunkSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(uncbfrout);
|
|
for (i = 0; i < colorDepth; ++i) {
|
|
free(uncptr[i]);
|
|
}
|
|
}
|
|
|
|
byte *AGOSEngine::convertImage(VC10_state *state, bool compressed) {
|
|
int length, i, j;
|
|
|
|
uint8 colorDepth = 4;
|
|
if (getGameType() == GType_SIMON1) {
|
|
if (((_videoLockOut & 0x20) && !state->palette) || ((getFeatures() & GF_32COLOR) &&
|
|
state->palette != 0xC0)) {
|
|
colorDepth = 5;
|
|
}
|
|
}
|
|
|
|
const byte *src = state->srcPtr;
|
|
int width = state->width * 16;
|
|
int height = state->height;
|
|
|
|
free(_planarBuf);
|
|
_planarBuf = (byte *)malloc(width * height);
|
|
byte *dst = _planarBuf;
|
|
|
|
if (compressed) {
|
|
convertCompressedImage(src, dst, colorDepth, height, width, (getGameType() == GType_PN));
|
|
} else {
|
|
length = (width + 15) / 16 * height;
|
|
for (i = 0; i < length; i++) {
|
|
uint16 w[kMaxColorDepth];
|
|
if (getGameType() == GType_SIMON1 && colorDepth == 4) {
|
|
for (j = 0; j < colorDepth; ++j) {
|
|
w[j] = READ_BE_UINT16(src + j * length * 2);
|
|
}
|
|
if (state->palette == 0xC0) {
|
|
bitplaneToChunkyText(w, colorDepth, dst);
|
|
} else {
|
|
bitplaneToChunky(w, colorDepth, dst);
|
|
}
|
|
src += 2;
|
|
} else {
|
|
for (j = 0; j < colorDepth; ++j) {
|
|
w[j] = READ_BE_UINT16(src); src += 2;
|
|
}
|
|
bitplaneToChunky(w, colorDepth, dst);
|
|
}
|
|
}
|
|
}
|
|
|
|
return _planarBuf;
|
|
}
|
|
|
|
} // End of namespace AGOS
|