2002-12-25 13:04:01 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
2003-03-06 21:46:56 +00:00
|
|
|
* Copyright (C) 2002-2003 The ScummVM project
|
2002-12-25 13:04:01 +00:00
|
|
|
*
|
|
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
2002-12-25 20:07:09 +00:00
|
|
|
#include "scumm.h"
|
2002-12-25 13:04:01 +00:00
|
|
|
#include "nut_renderer.h"
|
|
|
|
|
2002-12-25 20:07:09 +00:00
|
|
|
NutRenderer::NutRenderer(Scumm *vm) {
|
|
|
|
_vm = vm;
|
2002-12-25 13:04:01 +00:00
|
|
|
_initialized = false;
|
|
|
|
_loaded = false;
|
|
|
|
_dataSrc = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
NutRenderer::~NutRenderer() {
|
2003-03-03 23:57:10 +00:00
|
|
|
if (_dataSrc != NULL) {
|
2002-12-25 13:04:01 +00:00
|
|
|
free(_dataSrc);
|
2003-03-03 23:57:10 +00:00
|
|
|
_dataSrc = NULL;
|
|
|
|
}
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NutRenderer::decodeCodec44(byte *dst, byte *src, uint32 length) {
|
|
|
|
byte val;
|
2003-01-19 11:00:21 +00:00
|
|
|
uint16 size_line, num;
|
2002-12-25 13:04:01 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
size_line = READ_LE_UINT16(src);
|
|
|
|
src += 2;
|
|
|
|
length -= 2;
|
|
|
|
|
2002-12-31 20:17:46 +00:00
|
|
|
while (size_line != 0) {
|
2002-12-25 13:04:01 +00:00
|
|
|
num = *src++;
|
|
|
|
val = *src++;
|
|
|
|
memset(dst, val, num);
|
|
|
|
dst += num;
|
|
|
|
length -= 2;
|
|
|
|
size_line -= 2;
|
2003-01-19 11:00:21 +00:00
|
|
|
if (size_line != 0) {
|
|
|
|
num = READ_LE_UINT16(src) + 1;
|
|
|
|
src += 2;
|
|
|
|
memcpy(dst, src, num);
|
|
|
|
dst += num;
|
|
|
|
src += num;
|
|
|
|
length -= num + 2;
|
|
|
|
size_line -= num + 2;
|
|
|
|
}
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
|
|
|
dst--;
|
|
|
|
|
|
|
|
} while (length > 1);
|
|
|
|
}
|
|
|
|
|
2002-12-25 20:07:09 +00:00
|
|
|
bool NutRenderer::loadFont(const char *filename, const char *dir) {
|
2002-12-25 13:04:01 +00:00
|
|
|
debug(2, "NutRenderer::loadFont() called");
|
|
|
|
if (_loaded == true) {
|
|
|
|
debug(2, "NutRenderer::loadFont() Font already loaded, ok, loading...");
|
|
|
|
}
|
|
|
|
|
|
|
|
File file;
|
|
|
|
file.open(filename, dir);
|
|
|
|
if (file.isOpen() == false) {
|
2003-03-03 23:39:48 +00:00
|
|
|
warning("NutRenderer::loadFont() Can't open font file: %s/%s", dir, filename);
|
2002-12-25 13:04:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 tag = file.readUint32BE();
|
|
|
|
if (tag != 'ANIM') {
|
|
|
|
debug(2, "NutRenderer::loadFont() there is no ANIM chunk in font header");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-03-03 23:57:10 +00:00
|
|
|
if (_dataSrc != NULL) {
|
2002-12-25 14:46:14 +00:00
|
|
|
free(_dataSrc);
|
2003-03-03 23:57:10 +00:00
|
|
|
_dataSrc = NULL;
|
|
|
|
}
|
2002-12-25 14:46:14 +00:00
|
|
|
|
2002-12-25 13:04:01 +00:00
|
|
|
uint32 length = file.readUint32BE();
|
|
|
|
_dataSrc = (byte *)malloc(length);
|
|
|
|
file.read(_dataSrc, length);
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
if (READ_BE_UINT32(_dataSrc) != 'AHDR') {
|
|
|
|
debug(2, "NutRenderer::loadFont() there is no AHDR chunk in font header");
|
|
|
|
free(_dataSrc);
|
2003-03-03 23:57:10 +00:00
|
|
|
_dataSrc = NULL;
|
2002-12-25 13:04:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 l;
|
|
|
|
uint32 offset = READ_BE_UINT32(_dataSrc + 4) + 8;
|
2003-03-04 02:45:50 +00:00
|
|
|
memset(_offsets, 0, 256 * sizeof(int32));
|
2002-12-25 13:04:01 +00:00
|
|
|
for (l = 0; l < 256; l++) {
|
|
|
|
if (READ_BE_UINT32(_dataSrc + offset) == 'FRME') {
|
|
|
|
offset += 8;
|
|
|
|
if (READ_BE_UINT32(_dataSrc + offset) == 'FOBJ') {
|
|
|
|
_offsets[l] = offset + 8;
|
|
|
|
offset += READ_BE_UINT32(_dataSrc + offset + 4) + 8;
|
2003-03-04 02:45:50 +00:00
|
|
|
} else {
|
|
|
|
debug(2, "NutRenderer::loadFont(%s, %s) there is no FOBJ chunk in FRME chunk %d (offset %x)", filename, dir, l, offset);
|
|
|
|
break;
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
2003-03-04 02:45:50 +00:00
|
|
|
} else {
|
|
|
|
debug(2, "NutRenderer::loadFont(%s, %s) there is no FRME chunk %d (offset %x)", filename, dir, l, offset);
|
|
|
|
break;
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_loaded = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-01-30 16:02:20 +00:00
|
|
|
int32 NutRenderer::getCharWidth(byte c) {
|
2002-12-25 13:04:01 +00:00
|
|
|
debug(2, "NutRenderer::getCharWidth() called");
|
|
|
|
if (_loaded == false) {
|
|
|
|
debug(2, "NutRenderer::getCharWidth() Font is not loaded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return READ_LE_UINT16(_dataSrc + _offsets[c] + 6);
|
|
|
|
}
|
|
|
|
|
2003-01-30 16:02:20 +00:00
|
|
|
int32 NutRenderer::getCharHeight(byte c) {
|
2002-12-25 13:04:01 +00:00
|
|
|
debug(2, "NutRenderer::getCharHeight() called");
|
|
|
|
if (_loaded == false) {
|
|
|
|
debug(2, "NutRenderer::getCharHeight() Font is not loaded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return READ_LE_UINT16(_dataSrc + _offsets[c] + 8);
|
|
|
|
}
|
|
|
|
|
2003-01-30 16:02:20 +00:00
|
|
|
int32 NutRenderer::getStringWidth(byte *string) {
|
2002-12-25 13:04:01 +00:00
|
|
|
debug(2, "NutRenderer::getStringWidth() called");
|
|
|
|
if (_loaded == false) {
|
|
|
|
debug(2, "NutRenderer::getStringWidth() Font is not loaded");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int32 length = 0;
|
|
|
|
int32 l = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
length += getCharWidth(string[l]);
|
|
|
|
l++;
|
|
|
|
} while (string[l] != 0);
|
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
2003-01-30 16:02:20 +00:00
|
|
|
void NutRenderer::drawChar(byte c, int32 x, int32 y, byte color, bool useMask) {
|
2003-01-15 03:10:28 +00:00
|
|
|
debug(2, "NutRenderer::drawChar('%c', %d, %d, %d, %d) called", c, x, y, (int)color, useMask);
|
2002-12-25 13:04:01 +00:00
|
|
|
if (_loaded == false) {
|
2002-12-25 20:07:09 +00:00
|
|
|
debug(2, "NutRenderer::drawChar() Font is not loaded");
|
2002-12-25 13:04:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-12-31 21:15:46 +00:00
|
|
|
const uint32 length = READ_BE_UINT32(_dataSrc + _offsets[c] - 4) - 14;
|
|
|
|
const int32 width = READ_LE_UINT16(_dataSrc + _offsets[c] + 6);
|
|
|
|
const int32 height = READ_LE_UINT16(_dataSrc + _offsets[c] + 8);
|
2002-12-25 13:04:01 +00:00
|
|
|
|
2002-12-31 21:15:46 +00:00
|
|
|
byte *src = (byte*)(_dataSrc + _offsets[c] + 14);
|
2002-12-25 13:04:01 +00:00
|
|
|
decodeCodec44(_tmpCodecBuffer, src, length);
|
2002-12-31 20:52:11 +00:00
|
|
|
|
2002-12-31 21:15:46 +00:00
|
|
|
// HACK: we draw the character a total of 7 times: 6 times shifted
|
|
|
|
// and in black for the shadow, and once in the right color and position.
|
|
|
|
// This way we achieve the exact look as the original CMI had. However,
|
|
|
|
// the question remains whether they did it this way, too, or if there is
|
|
|
|
// some "font shadow" resource we don't know yet.
|
|
|
|
// One problem remains: the fonts on the save/load screen don't have a
|
|
|
|
// shadow. So how do we know whether to draw text with or without shadow?
|
|
|
|
|
|
|
|
int offsetX[7] = { -1, 0, 1, 0, 1, 2, 0 };
|
|
|
|
int offsetY[7] = { 0, -1, 0, 1, 2, 1, 0 };
|
|
|
|
int cTable[7] = { 0, 0, 0, 0, 0, 0, color };
|
2003-01-15 03:10:28 +00:00
|
|
|
|
|
|
|
byte *dst, *mask = NULL;
|
|
|
|
byte maskmask;
|
|
|
|
int maskpos;
|
2002-12-31 21:15:46 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
|
|
x += offsetX[i];
|
|
|
|
y += offsetY[i];
|
|
|
|
color = cTable[i];
|
|
|
|
|
2003-01-15 03:10:28 +00:00
|
|
|
dst = _vm->virtscr[0].screenPtr + y * _vm->_realWidth + x + _vm->virtscr[0].xstart;
|
|
|
|
mask = _vm->getResourceAddress(rtBuffer, 9)
|
2002-12-31 21:15:46 +00:00
|
|
|
+ (y * _vm->_realWidth + x) / 8 + _vm->_screenStartStrip;
|
|
|
|
|
|
|
|
src = _tmpCodecBuffer;
|
|
|
|
|
|
|
|
for (int32 ty = 0; ty < height; ty++) {
|
|
|
|
maskmask = revBitMask[x & 7];
|
|
|
|
maskpos = 0;
|
|
|
|
for (int32 tx = 0; tx < width; tx++) {
|
|
|
|
byte pixel = *src++;
|
2003-04-01 15:32:17 +00:00
|
|
|
if (x + tx < 0 || x + tx >= _vm->_realWidth || y + ty < 0 || y + ty >= _vm->_realHeight)
|
2003-03-08 13:26:20 +00:00
|
|
|
continue;
|
2002-12-31 20:17:46 +00:00
|
|
|
#if 1
|
2002-12-31 21:15:46 +00:00
|
|
|
if (pixel != 0) {
|
|
|
|
dst[tx] = color;
|
2003-01-15 03:10:28 +00:00
|
|
|
if (useMask)
|
|
|
|
mask[maskpos] |= maskmask;
|
2002-12-31 21:15:46 +00:00
|
|
|
}
|
2002-12-31 20:17:46 +00:00
|
|
|
#else
|
2002-12-31 21:15:46 +00:00
|
|
|
if (pixel != 0) {
|
|
|
|
if (pixel == 0x01)
|
|
|
|
pixel = (color == 0) ? 0xf : color;
|
|
|
|
if (pixel == 0xff)
|
|
|
|
pixel = 0x0;
|
|
|
|
dst[tx] = pixel;
|
2003-01-15 03:10:28 +00:00
|
|
|
if (useMask)
|
|
|
|
mask[maskpos] |= maskmask;
|
2002-12-31 21:15:46 +00:00
|
|
|
}
|
2002-12-31 20:17:46 +00:00
|
|
|
#endif
|
2002-12-31 21:15:46 +00:00
|
|
|
maskmask >>= 1;
|
|
|
|
if (maskmask == 0) {
|
|
|
|
maskmask = 0x80;
|
|
|
|
maskpos++;
|
|
|
|
}
|
2002-12-31 20:52:11 +00:00
|
|
|
}
|
2002-12-31 21:15:46 +00:00
|
|
|
dst += _vm->_realWidth;
|
|
|
|
mask += _vm->gdi._numStrips;
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
2002-12-31 21:15:46 +00:00
|
|
|
|
|
|
|
x -= offsetX[i];
|
|
|
|
y -= offsetY[i];
|
2002-12-25 13:04:01 +00:00
|
|
|
}
|
|
|
|
}
|