aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorbjörn Andersson2007-01-21 17:14:53 +0000
committerTorbjörn Andersson2007-01-21 17:14:53 +0000
commit01a5faa6a0ba89b7f774efe33839a077eeaa5f9d (patch)
tree64ebe05de9e2d099e85f2053b591b8cbdafe80e0
parent44cbf4996b7a26832e566bfada4d186643056234 (diff)
downloadscummvm-rg350-01a5faa6a0ba89b7f774efe33839a077eeaa5f9d.tar.gz
scummvm-rg350-01a5faa6a0ba89b7f774efe33839a077eeaa5f9d.tar.bz2
scummvm-rg350-01a5faa6a0ba89b7f774efe33839a077eeaa5f9d.zip
Applied my own patch #1635584 (after discussing with Fingolfin) to reduce the
memory usage and number of allocations made by the NUT font renderer. svn-id: r25155
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/insane/insane.cpp8
-rw-r--r--engines/scumm/nut_renderer.cpp192
-rw-r--r--engines/scumm/nut_renderer.h13
-rw-r--r--engines/scumm/smush/smush_player.cpp12
5 files changed, 180 insertions, 47 deletions
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 261d00a0cb..a15f2b6d76 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -1609,7 +1609,7 @@ CharsetRendererNut::CharsetRendererNut(ScummEngine *vm)
break;
sprintf(fontname, "font%d.nut", i);
_fr[i] = new NutRenderer(_vm);
- if (!(_fr[i]->loadFont(fontname))) {
+ if (!(_fr[i]->loadFont(fontname, true))) {
delete _fr[i];
_fr[i] = NULL;
}
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index de5b5f04d3..505ade1453 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -66,15 +66,15 @@ Insane::Insane(ScummEngine_v7 *scumm) {
readFileToMem("minedriv.flu", &_smush_minedrivFlu);
readFileToMem("minefite.flu", &_smush_minefiteFlu);
_smush_bensgoggNut = new NutRenderer(_vm);
- _smush_bensgoggNut->loadFont("bensgogg.nut");
+ _smush_bensgoggNut->loadFont("bensgogg.nut", false);
_smush_bencutNut = new NutRenderer(_vm);
- _smush_bencutNut->loadFont("bencut.nut");
+ _smush_bencutNut->loadFont("bencut.nut", false);
}
_smush_iconsNut = new NutRenderer(_vm);
- _smush_iconsNut->loadFont("icons.nut");
+ _smush_iconsNut->loadFont("icons.nut", false);
_smush_icons2Nut = new NutRenderer(_vm);
- _smush_icons2Nut->loadFont("icons2.nut");
+ _smush_icons2Nut->loadFont("icons2.nut", false);
}
Insane::~Insane(void) {
diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp
index af52242f81..cc0b632a89 100644
--- a/engines/scumm/nut_renderer.cpp
+++ b/engines/scumm/nut_renderer.cpp
@@ -30,26 +30,92 @@ namespace Scumm {
NutRenderer::NutRenderer(ScummEngine *vm) :
_vm(vm),
_loaded(false),
- _numChars(0) {
+ _numChars(0),
+ _decodedData(0) {
memset(_chars, 0, sizeof(_chars));
}
NutRenderer::~NutRenderer() {
- for (int i = 0; i < _numChars; i++) {
- delete []_chars[i].src;
- }
+ delete [] _decodedData;
}
-void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
+void NutRenderer::codec1(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch) {
+ byte val, code;
+ int32 length;
+ int h = height, size_line;
+
+ for (h = 0; h < height; h++) {
+ size_line = READ_LE_UINT16(src);
+ src += 2;
+ byte bit = 0x80;
+ byte *dstPtrNext = dst + pitch;
+ while (size_line > 0) {
+ code = *src++;
+ size_line--;
+ length = (code >> 1) + 1;
+ if (code & 1) {
+ val = *src++;
+ size_line--;
+ if (bitmap) {
+ for (int i = 0; i < length; i++) {
+ if (val)
+ *dst |= bit;
+ bit >>= 1;
+ if (!bit) {
+ bit = 0x80;
+ dst++;
+ }
+ }
+ } else {
+ if (val)
+ memset(dst, val, length);
+ dst += length;
+ }
+ } else {
+ size_line -= length;
+ while (length--) {
+ val = *src++;
+ if (bitmap) {
+ if (val)
+ *dst |= bit;
+ bit >>= 1;
+ if (!bit) {
+ bit = 0x80;
+ dst++;
+ }
+ } else {
+ if (val)
+ *dst = val;
+ dst++;
+ }
+ }
+ }
+ }
+ dst = dstPtrNext;
+ }
+}
-static void smush_decode_codec21(byte *dst, const byte *src, int width, int height, int pitch) {
+void NutRenderer::codec21(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch) {
while (height--) {
- uint8 *dstPtrNext = dst + pitch;
- const uint8 *srcPtrNext = src + 2 + READ_LE_UINT16(src); src += 2;
+ byte *dstPtrNext = dst + pitch;
+ const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src);
+ src += 2;
int len = width;
+ byte bit = 0x80;
do {
+ int i;
int offs = READ_LE_UINT16(src); src += 2;
- dst += offs;
+ if (bitmap) {
+ for (i = 0; i < offs; i++) {
+ bit >>= 1;
+ if (!bit) {
+ bit = 0x80;
+ dst++;
+ }
+ }
+ } else {
+ dst += offs;
+ }
len -= offs;
if (len <= 0) {
break;
@@ -63,18 +129,34 @@ static void smush_decode_codec21(byte *dst, const byte *src, int width, int heig
// src bytes equal to 255 are replaced by 0 in dst
// src bytes equal to 1 are replaced by a color passed as an argument in the original function
// other src bytes values are copied as-is
- memcpy(dst, src, w); dst += w; src += w;
+ if (bitmap) {
+ for (i = 0; i < w; i++) {
+ if (src[i])
+ *dst |= bit;
+ bit >>= 1;
+ if (!bit) {
+ bit = 0x80;
+ dst++;
+ }
+ }
+ } else {
+ memcpy(dst, src, w);
+ dst += w;
+ }
+ src += w;
} while (len > 0);
dst = dstPtrNext;
src = srcPtrNext;
}
}
-bool NutRenderer::loadFont(const char *filename) {
+bool NutRenderer::loadFont(const char *filename, bool bitmap) {
if (_loaded) {
debug(0, "NutRenderer::loadFont() Font already loaded, ok, loading...");
}
+ _bitmapFont = bitmap;
+
ScummFile file;
_vm->openFile(file, filename);
if (!file.isOpen()) {
@@ -89,7 +171,7 @@ bool NutRenderer::loadFont(const char *filename) {
}
uint32 length = file.readUint32BE();
- byte *dataSrc = (byte *)malloc(length);
+ byte *dataSrc = new byte[length];
file.read(dataSrc, length);
file.close();
@@ -99,9 +181,36 @@ bool NutRenderer::loadFont(const char *filename) {
return false;
}
+ // We pre-decode the font, which may seem wasteful at first. Actually,
+ // the memory needed for just the decoded glyphs is smaller than the
+ // whole of the undecoded font file.
+
_numChars = READ_LE_UINT16(dataSrc + 10);
assert(_numChars <= ARRAYSIZE(_chars));
+
uint32 offset = 0;
+ uint32 decodedLength = 0;
+ for (int l = 0; l < _numChars; l++) {
+ offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
+ int width = READ_LE_UINT16(dataSrc + offset + 14);
+ int height = READ_LE_UINT16(dataSrc + offset + 16);
+ if (_bitmapFont) {
+ decodedLength += (((width + 7) / 8) * height);
+ } else {
+ decodedLength += (width * height);
+ }
+ }
+
+ // If characters have transparency, then bytes just get skipped and
+ // so there may appear some garbage. That's why we have to fill it
+ // with zeroes first.
+
+ _decodedData = new byte[decodedLength];
+ memset(_decodedData, 0, decodedLength);
+
+ byte *decodedPtr = _decodedData;
+
+ offset = 0;
for (int l = 0; l < _numChars; l++) {
offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
if (READ_BE_UINT32(dataSrc + offset) != 'FRME') {
@@ -114,32 +223,37 @@ bool NutRenderer::loadFont(const char *filename) {
break;
}
int codec = READ_LE_UINT16(dataSrc + offset + 8);
- _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
- _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
+ // _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
+ // _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
_chars[l].width = READ_LE_UINT16(dataSrc + offset + 14);
_chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
- const int srcSize = _chars[l].width * _chars[l].height;
- _chars[l].src = new byte[srcSize];
- // If characters have transparency, then bytes just get skipped and
- // so there may appear some garbage. That's why we have to fill it
- // with zeroes first.
- memset(_chars[l].src, 0, srcSize);
+ _chars[l].src = decodedPtr;
+
+ int pitch;
+
+ if (_bitmapFont) {
+ pitch = (_chars[l].width + 7) / 8;
+ } else {
+ pitch = _chars[l].width;
+ }
+
+ decodedPtr += (pitch * _chars[l].height);
const uint8 *fobjptr = dataSrc + offset + 22;
switch (codec) {
case 1:
- smush_decode_codec1(_chars[l].src, fobjptr, 0, 0, _chars[l].width, _chars[l].height, _chars[l].width);
+ codec1(_bitmapFont, _chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
break;
case 21:
case 44:
- smush_decode_codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
+ codec21(_bitmapFont, _chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
break;
default:
error("NutRenderer::loadFont: unknown codec: %d", codec);
}
}
- free(dataSrc);
+ delete [] dataSrc;
_loaded = true;
return true;
}
@@ -210,8 +324,10 @@ void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y
}
void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
- const int width = MIN(_chars[c].width, _vm->_screenWidth - x);
- const int height = MIN(_chars[c].height, _vm->_screenHeight - y);
+ assert(!_bitmapFont);
+
+ const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x);
+ const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y);
const byte *src = _chars[c].src;
const int srcPitch = _chars[c].width;
byte bits = 0;
@@ -243,10 +359,16 @@ void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color) {
byte *dst = (byte *)s.pixels + y * s.pitch + x;
- const int width = MIN(_chars[c].width, s.w - x);
- const int height = MIN(_chars[c].height, s.h - y);
+ const int width = MIN((int)_chars[c].width, s.w - x);
+ const int height = MIN((int)_chars[c].height, s.h - y);
const byte *src = _chars[c].src;
- const int srcPitch = _chars[c].width;
+ int srcPitch;
+
+ if (_bitmapFont) {
+ srcPitch = (_chars[c].width + 7) / 8;
+ } else {
+ srcPitch = _chars[c].width;
+ }
const int minX = x < 0 ? -x : 0;
const int minY = y < 0 ? -y : 0;
@@ -261,9 +383,17 @@ void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byt
}
for (int ty = minY; ty < height; ty++) {
- for (int tx = minX; tx < width; tx++) {
- if (src[tx] != 0) {
- dst[tx] = color;
+ int tx;
+
+ for (tx = minX; tx < width; tx++) {
+ if (_bitmapFont) {
+ if (src[tx / 8] & (0x80 >> (tx % 8))) {
+ dst[tx] = color;
+ }
+ } else {
+ if (src[tx] != 0) {
+ dst[tx] = color;
+ }
}
}
src += srcPitch;
diff --git a/engines/scumm/nut_renderer.h b/engines/scumm/nut_renderer.h
index 8972fef949..c3bc68477a 100644
--- a/engines/scumm/nut_renderer.h
+++ b/engines/scumm/nut_renderer.h
@@ -33,15 +33,18 @@ class NutRenderer {
protected:
ScummEngine *_vm;
bool _loaded;
+ bool _bitmapFont;
int _numChars;
+ byte *_decodedData;
struct {
- int xoffs;
- int yoffs;
- int width;
- int height;
+ uint16 width;
+ uint16 height;
byte *src;
} _chars[256];
+ static void codec1(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch);
+ static void codec21(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch);
+
void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
@@ -50,7 +53,7 @@ public:
virtual ~NutRenderer();
int getNumChars() const { return _numChars; }
- bool loadFont(const char *filename);
+ bool loadFont(const char *filename, bool bitmap);
void drawFrame(byte *dst, int c, int x, int y);
void drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow);
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index dbcde31597..747e89a980 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -1042,17 +1042,17 @@ void SmushPlayer::setupAnim(const char *file) {
_sf[1] = new SmushFont(_vm, true, false);
_sf[2] = new SmushFont(_vm, true, false);
_sf[3] = new SmushFont(_vm, true, false);
- _sf[0]->loadFont("scummfnt.nut");
- _sf[1]->loadFont("techfnt.nut");
- _sf[2]->loadFont("titlfnt.nut");
- _sf[3]->loadFont("specfnt.nut");
+ _sf[0]->loadFont("scummfnt.nut", false);
+ _sf[1]->loadFont("techfnt.nut", false);
+ _sf[2]->loadFont("titlfnt.nut", false);
+ _sf[3]->loadFont("specfnt.nut", false);
}
} else if (_vm->_game.id == GID_DIG) {
if (!(_vm->_game.features & GF_DEMO)) {
for (i = 0; i < 4; i++) {
sprintf(file_font, "font%d.nut", i);
_sf[i] = new SmushFont(_vm, i != 0, false);
- _sf[i]->loadFont(file_font);
+ _sf[i]->loadFont(file_font, false);
}
}
} else if (_vm->_game.id == GID_CMI) {
@@ -1061,7 +1061,7 @@ void SmushPlayer::setupAnim(const char *file) {
break;
sprintf(file_font, "font%d.nut", i);
_sf[i] = new SmushFont(_vm, false, true);
- _sf[i]->loadFont(file_font);
+ _sf[i]->loadFont(file_font, false);
}
} else {
error("SmushPlayer::setupAnim() Unknown font setup for game");