aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2014-12-31 16:14:45 -1000
committerPaul Gilbert2014-12-31 16:14:45 -1000
commitd21c47e019434797217b1b44708c8f1810a003b3 (patch)
treefc48b2e3a0495d8bca552953577e440a6202f6f6 /engines
parent5c88d2cc42d9b6124f552464b9c02e800f3956df (diff)
downloadscummvm-rg350-d21c47e019434797217b1b44708c8f1810a003b3.tar.gz
scummvm-rg350-d21c47e019434797217b1b44708c8f1810a003b3.tar.bz2
scummvm-rg350-d21c47e019434797217b1b44708c8f1810a003b3.zip
XEEN: Lot of font code implemented
Diffstat (limited to 'engines')
-rw-r--r--engines/xeen/resdata.cpp43
-rw-r--r--engines/xeen/resdata.h2
-rw-r--r--engines/xeen/screen.cpp33
-rw-r--r--engines/xeen/screen.h7
-rw-r--r--engines/xeen/xsurface.cpp248
-rw-r--r--engines/xeen/xsurface.h29
6 files changed, 345 insertions, 17 deletions
diff --git a/engines/xeen/resdata.cpp b/engines/xeen/resdata.cpp
index 44002c62f2..1cdd3ac0fb 100644
--- a/engines/xeen/resdata.cpp
+++ b/engines/xeen/resdata.cpp
@@ -148,4 +148,47 @@ const byte SYMBOLS[20][64] = {
}
};
+const byte TEXT_COLORS[40][4] = {
+ { 0x00, 0x19, 0x19, 0x19 },
+ { 0x00, 0x08, 0x08, 0x08 },
+ { 0x00, 0x0F, 0x0F, 0x0F },
+ { 0x00, 0x15, 0x15, 0x15 },
+ { 0x00, 0x01, 0x01, 0x01 },
+ { 0x00, 0x21, 0x21, 0x21 },
+ { 0x00, 0x26, 0x26, 0x26 },
+ { 0x00, 0x2B, 0x2B, 0x2B },
+ { 0x00, 0x31, 0x31, 0x31 },
+ { 0x00, 0x36, 0x36, 0x36 },
+ { 0x00, 0x3D, 0x3D, 0x3D },
+ { 0x00, 0x41, 0x41, 0x41 },
+ { 0x00, 0x46, 0x46, 0x46 },
+ { 0x00, 0x4C, 0x4C, 0x4C },
+ { 0x00, 0x50, 0x50, 0x50 },
+ { 0x00, 0x55, 0x55, 0x55 },
+ { 0x00, 0x5D, 0x5D, 0x5D },
+ { 0x00, 0x60, 0x60, 0x60 },
+ { 0x00, 0x65, 0x65, 0x65 },
+ { 0x00, 0x6C, 0x6C, 0x6C },
+ { 0x00, 0x70, 0x70, 0x70 },
+ { 0x00, 0x75, 0x75, 0x75 },
+ { 0x00, 0x7B, 0x7B, 0x7B },
+ { 0x00, 0x80, 0x80, 0x80 },
+ { 0x00, 0x85, 0x85, 0x85 },
+ { 0x00, 0x8D, 0x8D, 0x8D },
+ { 0x00, 0x90, 0x90, 0x90 },
+ { 0x00, 0x97, 0x97, 0x97 },
+ { 0x00, 0x9D, 0x9D, 0x9D },
+ { 0x00, 0xA4, 0xA4, 0xA4 },
+ { 0x00, 0xAB, 0xAB, 0xAB },
+ { 0x00, 0xB0, 0xB0, 0xB0 },
+ { 0x00, 0xB6, 0xB6, 0xB6 },
+ { 0x00, 0xBD, 0xBD, 0xBD },
+ { 0x00, 0xC0, 0xC0, 0xC0 },
+ { 0x00, 0xC6, 0xC6, 0xC6 },
+ { 0x00, 0xCD, 0xCD, 0xCD },
+ { 0x00, 0xD0, 0xD0, 0xD0 },
+ { 0x00, 0xD6, 0xD6, 0xD6 },
+ { 0x00, 0xDB, 0xDB, 0xDB },
+};
+
} // End of namespace Xeen
diff --git a/engines/xeen/resdata.h b/engines/xeen/resdata.h
index ce355e71cb..deb6e589be 100644
--- a/engines/xeen/resdata.h
+++ b/engines/xeen/resdata.h
@@ -30,6 +30,8 @@ namespace Xeen {
extern const byte SYMBOLS[20][64];
+extern const byte TEXT_COLORS[40][4];
+
} // End of namespace Xeen
#endif /* XEEN_RESDATA_H */
diff --git a/engines/xeen/screen.cpp b/engines/xeen/screen.cpp
index 4563e37498..2da2412866 100644
--- a/engines/xeen/screen.cpp
+++ b/engines/xeen/screen.cpp
@@ -66,8 +66,8 @@ void Window::open2() {
void Window::frame() {
Screen &screen = *_vm->_screen;
- int xCount = (_bounds.width() - 9) / SYMBOL_WIDTH;
- int yCount = (_bounds.height() - 9) / SYMBOL_HEIGHT;
+ int xCount = (_bounds.width() - 9) / FONT_WIDTH;
+ int yCount = (_bounds.height() - 9) / FONT_HEIGHT;
// Write the top line
screen._writePos = Common::Point(_bounds.left, _bounds.top);
@@ -82,7 +82,7 @@ void Window::frame() {
}
}
- screen._writePos.x = _bounds.right - SYMBOL_WIDTH;
+ screen._writePos.x = _bounds.right - FONT_WIDTH;
screen.writeSymbol(5);
// Write the vertical edges
@@ -94,7 +94,7 @@ void Window::frame() {
screen._writePos.x = _bounds.left;
screen.writeSymbol(symbolId);
- screen._writePos.x = _bounds.right - SYMBOL_WIDTH;
+ screen._writePos.x = _bounds.right - FONT_WIDTH;
screen.writeSymbol(symbolId + 4);
if (++symbolId == 10)
@@ -103,7 +103,7 @@ void Window::frame() {
}
// Write the bottom line
- screen._writePos = Common::Point(_bounds.left, _bounds.bottom - SYMBOL_HEIGHT);
+ screen._writePos = Common::Point(_bounds.left, _bounds.bottom - FONT_HEIGHT);
screen.writeSymbol(14);
if (xCount > 0) {
@@ -115,7 +115,7 @@ void Window::frame() {
}
}
- screen._writePos.x = _bounds.right - SYMBOL_WIDTH;
+ screen._writePos.x = _bounds.right - FONT_WIDTH;
screen.writeSymbol(19);
}
@@ -154,6 +154,17 @@ void Window::addDirtyRect(const Common::Rect &r) {
_dirtyRects.push(r);
}
+/**
+ * Fill the content area of a window with the current background color
+ */
+void Window::fill() {
+ fillRect(_innerBounds, _bgColor);
+}
+
+void Window::writeString(const Common::String &s) {
+ _vm->_screen->writeString(s, _innerBounds);
+}
+
/*------------------------------------------------------------------------*/
/**
@@ -163,6 +174,16 @@ Screen::Screen(XeenEngine *vm) : _vm(vm) {
_fadeIn = false;
create(SCREEN_WIDTH, SCREEN_HEIGHT);
setupWindows();
+
+ // Load font data for the screen
+ File f("fnt");
+ byte *data = new byte[f.size()];
+ f.read(data, f.size());
+ _fontData = data;
+}
+
+Screen::~Screen() {
+ delete[] _fontData;
}
void Screen::setupWindows() {
diff --git a/engines/xeen/screen.h b/engines/xeen/screen.h
index cbf57670b3..907409dbfb 100644
--- a/engines/xeen/screen.h
+++ b/engines/xeen/screen.h
@@ -70,7 +70,10 @@ public:
void update();
void frame();
-};
+
+ void fill();
+
+ void writeString(const Common::String &s);};
class Screen: public XSurface {
private:
@@ -104,6 +107,8 @@ public:
public:
Screen(XeenEngine *vm);
+ virtual ~Screen();
+
void closeWindows();
void update();
diff --git a/engines/xeen/xsurface.cpp b/engines/xeen/xsurface.cpp
index d3c547861b..5e7d831380 100644
--- a/engines/xeen/xsurface.cpp
+++ b/engines/xeen/xsurface.cpp
@@ -21,16 +21,29 @@
*/
#include "common/algorithm.h"
+#include "common/util.h"
#include "xeen/xsurface.h"
#include "xeen/resdata.h"
namespace Xeen {
-XSurface::XSurface(): Graphics::Surface() {
+const byte *XSurface::_fontData;
+
+XSurface::XSurface() : Graphics::Surface(), _bgColor(DEFAULT_BG_COLOR), _fontReduced(false),
+ _fontJustify(JUSTIFY_NONE), _msgWraps(false) {
+ _textColors[0] = 0;
+ _textColors[1] = 0x40;
+ _textColors[2] = 0x30;
+ _textColors[3] = 0x20;
}
-XSurface::XSurface(int w, int h) : Graphics::Surface() {
+XSurface::XSurface(int w, int h) : Graphics::Surface(), _bgColor(DEFAULT_BG_COLOR),
+ _fontReduced(false), _fontJustify(JUSTIFY_NONE), _msgWraps(false) {
create(w, h);
+ _textColors[0] = 0;
+ _textColors[1] = 0x40;
+ _textColors[2] = 0x30;
+ _textColors[3] = 0x20;
}
XSurface::~XSurface() {
@@ -87,10 +100,10 @@ void XSurface::blitTo(XSurface &dest, const Common::Point &destPos) const {
void XSurface::writeSymbol(int symbolId) {
const byte *srcP = &SYMBOLS[symbolId][0];
- for (int yp = 0; yp < SYMBOL_HEIGHT; ++yp) {
+ for (int yp = 0; yp < FONT_HEIGHT; ++yp) {
byte *destP = (byte *)getBasePtr(_writePos.x, _writePos.y + yp);
- for (int xp = 0; xp < SYMBOL_WIDTH; ++xp, ++destP) {
+ for (int xp = 0; xp < FONT_WIDTH; ++xp, ++destP) {
byte b = *srcP++;
if (b)
*destP = b;
@@ -102,9 +115,158 @@ void XSurface::writeSymbol(int symbolId) {
/**
* Write a string to the surface
+ * @param s String to display
+ * @param bounds Window bounds to display string within
+ * @returns Any string remainder that couldn't be displayed
+ * @remarks Note that bounds is just used for wrapping purposes. Unless
+ * justification is set, the message will be written at _writePos
*/
-void XSurface::writeString(const Common::String &s) {
- error("TODO");
+Common::String XSurface::writeString(const Common::String &s, const Common::Rect &bounds) {
+ _displayString = s.c_str();
+
+ for (;;) {
+ _msgWraps = false;
+
+ // Get the size of the string that can be displayed on the likne
+ int xp = _fontJustify ? bounds.left : _writePos.x;
+ while (!getNextCharWidth(xp)) {
+ if (xp >= bounds.right) {
+ --_displayString;
+ _msgWraps = true;
+ }
+ }
+
+ // Get the end point of the text that can be displayed
+ const char *displayEnd = _displayString;
+ _displayString = s.c_str();
+
+ if (*displayEnd && _fontJustify != JUSTIFY_RIGHT && xp >= bounds.right) {
+ // Need to handle justification of text
+ // First, move backwards to find the end of the previous word
+ // for a convenient point to break the line at
+ const char *endP = displayEnd;
+ while (endP > _displayString && (*endP & 0x7f) != ' ')
+ --endP;
+
+ if (endP == _displayString) {
+ // There was no word breaks at all in the string
+ --displayEnd;
+ if (_fontJustify == JUSTIFY_NONE && _writePos.x != bounds.left) {
+ // Move to the next line
+ if (!newLine(bounds))
+ continue;
+ // Ran out of space to display string
+ break;
+ }
+ } else {
+ // Found word break, find end of previous word
+ while (displayEnd > _displayString && (*displayEnd & 0x7f) == ' ')
+ --displayEnd;
+ }
+ }
+
+ // Main character display loop
+ while (_displayString <= displayEnd) {
+ char c = getNextChar();
+
+ if (c == ' ') {
+ _writePos.x += _fontReduced ? 3 : 4;
+ } else if (c == '\r') {
+ fillRect(bounds, _bgColor);
+ _writePos = Common::Point(bounds.left, bounds.top);
+ } else if (c == 1) {
+ // Turn off reduced font mode
+ _fontReduced = false;
+ } else if (c == 2) {
+ // Turn on reduced font mode
+ _fontReduced = true;
+ } else if (c == 3) {
+ // Justify text
+ c = getNextChar();
+ if (c == 'r')
+ _fontJustify = JUSTIFY_RIGHT;
+ else if (c == 'c')
+ _fontJustify = JUSTIFY_CENTER;
+ else
+ _fontJustify = JUSTIFY_NONE;
+ } else if (c == 4) {
+ // Draw an empty box of a given width
+ int w = fontAtoi();
+ Common::Point pt = _writePos;
+ if (_fontJustify == JUSTIFY_RIGHT)
+ pt.x -= w;
+ fillRect(Common::Rect(pt.x, pt.y, pt.x + w, pt.y + (_fontReduced ? 9 : 10)),
+ _bgColor);
+ } else if (c == 5) {
+ continue;
+ } else if (c == 6) {
+ // Non-breakable space
+ writeChar(' ');
+ } else if (c == 7) {
+ // Set text background color
+ int c = fontAtoi();
+ _bgColor = (c < 0 || c > 255) ? DEFAULT_BG_COLOR : c;
+ } else if (c == 8) {
+ // Draw a character outline
+ c = getNextChar();
+ if (c == ' ') {
+ c = '\0';
+ _writePos.x -= 3;
+ } else {
+ if (c == 6)
+ c = ' ';
+ byte charSize = _fontData[0x1000 + (int)c + (_fontReduced ? 0x80 : 0)];
+ _writePos.x -= charSize;
+ }
+
+ if (_writePos.x < bounds.left)
+ _writePos.x = bounds.left;
+
+ if (c) {
+ int oldX = _writePos.x;
+ byte oldColor[4];
+ Common::copy(&_textColors[0], &_textColors[4], &oldColor[0]);
+
+ _textColors[1] = _textColors[2] = _textColors[3] = _bgColor;
+ writeChar(c);
+
+ Common::copy(&oldColor[0], &oldColor[4], &_textColors[0]);
+ _writePos.x = oldX;
+ }
+ } else if (c == 9) {
+ // Skip x position
+ int xp = fontAtoi();
+ _writePos.x = MIN(bounds.left + xp, (int)bounds.right);
+ } else if (c == 10) {
+ // Newline
+ if (newLine(bounds))
+ break;
+ } else if (c == 11) {
+ // Skip y position
+ int yp = fontAtoi( );
+ _writePos.y = MIN(bounds.top + yp, (int)bounds.bottom);
+ } else if (c == 12) {
+ // Set text colors
+ int idx = fontAtoi();
+ if (idx < 0)
+ idx = 0;
+ setTextColor(idx);
+ } else if (c < ' ') {
+ // Invalid command
+ displayEnd = nullptr;
+ break;
+ } else {
+ // Standard character - write it out
+ writeChar(c);
+ }
+ }
+
+ if (_displayString > displayEnd && _fontJustify != JUSTIFY_RIGHT && _msgWraps
+ && newLine(bounds))
+ break;
+ }
+
+ return Common::String(_displayString);
}
/**
@@ -114,5 +276,79 @@ void XSurface::writeChar(char c) {
error("TODO");
}
+/**
+ * Return the next pending character to display
+ */
+char XSurface::getNextChar() {
+ return *_displayString++ & 0x7f;
+}
+
+/**
+* Return the width of a given character
+*/
+bool XSurface::getNextCharWidth(int &total) {
+ char c = getNextChar();
+
+ if (c > ' ') {
+ total += _fontData[0x1000 + (int)c + (_fontReduced ? 0x80 : 0)];
+ return false;
+ } else if (c == ' ') {
+ total += 4;
+ return false;
+ } else if (c == 8) {
+ c = getNextChar();
+ if (c == ' ') {
+ total -= 2;
+ return false;
+ } else {
+ _displayString -= 2;
+ return true;
+ }
+ } else if (c == 12) {
+ c = getNextChar();
+ if (c != 'd')
+ getNextChar();
+ return false;
+ } else {
+ --_displayString;
+ return true;
+ }
+}
+
+bool XSurface::newLine(const Common::Rect &bounds) {
+ // Move past any spaces currently being pointed to
+ while ((*_displayString & 0x7f) == ' ')
+ ++_displayString;
+
+ _msgWraps = false;
+ _writePos.x = bounds.left;
+
+ int h = _fontReduced ? 9 : 10;
+ _writePos.y += h;
+
+ return ((_writePos.y + h - 1) > bounds.bottom);
+}
+
+int XSurface::fontAtoi(int len) {
+ int total = 0;
+ for (int i = 0; i < len; ++i) {
+ char c = getNextChar();
+ if (c == ' ')
+ c = '0';
+
+ int digit = c - '0';
+ if (digit < 0 || digit > 9)
+ return -1;
+
+ total = total * 10 + digit;
+ }
+
+ return total;
+}
+
+void XSurface::setTextColor(int idx) {
+ const byte *colP = &TEXT_COLORS[idx][0];
+ Common::copy(colP, colP + 4, &_textColors[0]);
+}
} // End of namespace Xeen
diff --git a/engines/xeen/xsurface.h b/engines/xeen/xsurface.h
index 6688285361..6e88ae9f97 100644
--- a/engines/xeen/xsurface.h
+++ b/engines/xeen/xsurface.h
@@ -30,18 +30,39 @@
namespace Xeen {
-#define SYMBOL_WIDTH 8
-#define SYMBOL_HEIGHT 8
+#define FONT_WIDTH 8
+#define FONT_HEIGHT 8
+#define DEFAULT_BG_COLOR 0x99
+
+enum Justify { JUSTIFY_NONE = 0, JUSTIFY_CENTER = 1, JUSTIFY_RIGHT = 2 };
class XSurface: public Graphics::Surface {
+private:
+ const char *_displayString;
+ bool _msgWraps;
+
+ char getNextChar();
+
+ bool getNextCharWidth(int &total);
+
+ bool newLine(const Common::Rect &bounds);
+
+ int fontAtoi(int len = 3);
+
+ void setTextColor(int idx);
public:
+ static const byte *_fontData;
Common::Point _writePos;
+ byte _textColors[4];
+ byte _bgColor;
+ bool _fontReduced;
+ Justify _fontJustify;
public:
virtual void addDirtyRect(const Common::Rect &r) {}
public:
XSurface();
XSurface(int w, int h);
- ~XSurface();
+ virtual ~XSurface();
void create(uint16 w, uint16 h);
@@ -57,7 +78,7 @@ public:
void writeSymbol(int symbolId);
- void writeString(const Common::String &s);
+ Common::String writeString(const Common::String &s, const Common::Rect &bounds);
void writeChar(char c);
};