diff options
Diffstat (limited to 'engines/cge/talk.cpp')
-rw-r--r-- | engines/cge/talk.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/engines/cge/talk.cpp b/engines/cge/talk.cpp new file mode 100644 index 0000000000..812fa1d9dc --- /dev/null +++ b/engines/cge/talk.cpp @@ -0,0 +1,304 @@ +/* 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. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/talk.h" +#include "cge/vol.h" +#include "cge/game.h" +#include "cge/events.h" + +namespace CGE { + +Font::Font(const char *name) { + _map = (uint8 *)malloc(kMapSize); + _pos = (uint16 *)malloc(kPosSize * sizeof(uint16)); + _wid = (uint8 *)malloc(kWidSize); + + assert((_map != NULL) && (_pos != NULL) && (_wid != NULL)); + mergeExt(_path, name, kFontExt); + load(); +} + +Font::~Font() { + free(_map); + free(_pos); + free(_wid); +} + +void Font::load() { + INI_FILE f(_path); + if (f._error) + return; + + f.read(_wid, kWidSize); + if (f._error) + return; + + uint16 p = 0; + for (uint16 i = 0; i < kPosSize; i++) { + _pos[i] = p; + p += _wid[i]; + } + f.read(_map, p); +} + +uint16 Font::width(const char *text) { + uint16 w = 0; + if (!text) + return 0; + while (*text) + w += _wid[(unsigned char)*(text++)]; + return w; +} + +Talk::Talk(CGEEngine *vm, const char *text, TextBoxStyle mode) + : Sprite(vm, NULL), _mode(mode), _vm(vm) { + _ts = NULL; + _flags._syst = true; + update(text); +} + + +Talk::Talk(CGEEngine *vm) + : Sprite(vm, NULL), _mode(kTBPure), _vm(vm) { + _ts = NULL; + _flags._syst = true; +} + +Font *Talk::_font; + +void Talk::init() { + _font = new Font(progName()); +} + +void Talk::deinit() { + delete _font; +} + +void Talk::update(const char *text) { + const uint16 vmarg = (_mode) ? kTextVMargin : 0; + const uint16 hmarg = (_mode) ? kTextHMargin : 0; + uint16 mw = 0; + uint16 ln = vmarg; + uint8 *m; + + if (!_ts) { + uint16 k = 2 * hmarg; + uint16 mh = 2 * vmarg + kFontHigh; + for (const char *p = text; *p; p++) { + if (*p == '|' || *p == '\n') { + mh += kFontHigh + kTextLineSpace; + if (k > mw) + mw = k; + k = 2 * hmarg; + } else + k += _font->_wid[(unsigned char)*p]; + } + if (k > mw) + mw = k; + + _ts = new BitmapPtr[2]; + _ts[0] = box(mw, mh); + _ts[1] = NULL; + } + + m = _ts[0]->_m + ln * mw + hmarg; + + while (*text) { + if (*text == '|' || *text == '\n') { + m = _ts[0]->_m + (ln += kFontHigh + kTextLineSpace) * mw + hmarg; + } else { + int cw = _font->_wid[(unsigned char)*text]; + uint8 *f = _font->_map + _font->_pos[(unsigned char)*text]; + for (int i = 0; i < cw; i++) { + uint8 *pp = m; + uint16 n; + uint16 b = *(f++); + for (n = 0; n < kFontHigh; n++) { + if (b & 1) + *pp = kTextColFG; + b >>= 1; + pp += mw; + } + m++; + } + } + text++; + } + _ts[0]->code(); + setShapeList(_ts); +} + +Bitmap *Talk::box(uint16 w, uint16 h) { + if (w < 8) + w = 8; + if (h < 8) + h = 8; + uint16 n = w * h; + uint8 *b = (uint8 *)malloc(n); + assert(b != NULL); + memset(b, kTextColBG, n); + + if (_mode) { + uint8 *p = b; + uint8 *q = b + n - w; + memset(p, kVgaColLightGray, w); + memset(q, kVgaColDarkGray, w); + while (p < q) { + p += w; + *(p - 1) = kVgaColDarkGray; + *p = kVgaColLightGray; + } + p = b; + const uint16 r = (_mode == kTBRound) ? kTextRoundCorner : 0; + for (int i = 0; i < r; i++) { + int j; + for (j = 0; j < r - i; j++) { + p[j] = kPixelTransp; + p[w - j - 1] = kPixelTransp; + q[j] = kPixelTransp; + q[w - j - 1] = kPixelTransp; + } + p[j] = kVgaColLightGray; + p[w - j - 1] = kVgaColDarkGray; + q[j] = kVgaColLightGray; + q[w - j - 1] = kVgaColDarkGray; + p += w; + q -= w; + } + } + return new Bitmap(w, h, b); +} + +void Talk::putLine(int line, const char *text) { + // Note: (_ts[0]._w % 4) must be 0 + uint16 w = _ts[0]->_w; + uint16 h = _ts[0]->_h; + uint8 *v = _ts[0]->_v; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gap, but + plane trailer + uint16 size = 4 * psiz; // whole map size + uint16 rsiz = kFontHigh * lsiz; // length of whole text row map + + // set desired line pointer + v += (kTextVMargin + (kFontHigh + kTextLineSpace) * line) * lsiz; + uint8 *p = v; // assume blanked line above text + + // clear whole rectangle + assert((rsiz % lsiz) == 0); + for (int planeCtr = 0; planeCtr < 4; planeCtr++, p += psiz) { + for (byte *pDest = p; pDest < (p + (rsiz - lsiz)); pDest += lsiz) + Common::copy(p - lsiz, p, pDest); + } + + // paint text line + if (!text) + return; + p = v + 2 + (kTextHMargin / 4) + (kTextHMargin % 4) * psiz; + uint8 *q = v + size; + + while (*text) { + uint16 cw = _font->_wid[(unsigned char)*text], i; + uint8 *fp = _font->_map + _font->_pos[(unsigned char)*text]; + + for (i = 0; i < cw; i++) { + uint16 b = fp[i]; + uint16 n; + for (n = 0; n < kFontHigh; n++) { + if (b & 1) + *p = kTextColFG; + b >>= 1; + p += lsiz; + } + p = p - rsiz + psiz; + if (p >= q) + p = p - size + 1; + } + text++; + } +} + +InfoLine::InfoLine(CGEEngine *vm, uint16 w) : Talk(vm), _oldText(NULL), _vm(vm) { + if (!_ts) { + _ts = new BitmapPtr[2]; + _ts[1] = NULL; + } + + _ts[0] = new Bitmap(w, kFontHigh, kTextColBG); + setShapeList(_ts); +} + +void InfoLine::update(const char *text) { + if (text == _oldText) + return; + + uint16 w = _ts[0]->_w; + uint16 h = _ts[0]->_h; + uint8 *v = (uint8 *)_ts[0]->_v; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gape, but + plane trailer + uint16 size = 4 * psiz; // whole map size + + // clear whole rectangle + memset(v + 2, kTextColBG, dsiz); // data bytes + for (byte *pDest = v + lsiz; pDest < (v + psiz); pDest += lsiz) { + Common::copy(v, v + lsiz, pDest); + } + *(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16 + for (byte *pDest = v + psiz; pDest < (v + 4 * psiz); pDest += psiz) { + Common::copy(v, v + psiz, pDest); + } + + // paint text line + if (text) { + uint8 *p = v + 2, * q = p + size; + + while (*text) { + uint16 cw = _font->_wid[(unsigned char)*text]; + uint8 *fp = _font->_map + _font->_pos[(unsigned char)*text]; + + for (uint16 i = 0; i < cw; i++) { + uint16 b = fp[i]; + for (uint16 n = 0; n < kFontHigh; n++) { + if (b & 1) + *p = kTextColFG; + b >>= 1; + p += lsiz; + } + if (p >= q) + p = p - size + 1; + } + text++; + } + } + + _oldText = text; +} + +} // End of namespace CGE |