diff options
Diffstat (limited to 'engines/toltecs/screen.cpp')
-rw-r--r-- | engines/toltecs/screen.cpp | 971 |
1 files changed, 971 insertions, 0 deletions
diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp new file mode 100644 index 0000000000..69d2966ef6 --- /dev/null +++ b/engines/toltecs/screen.cpp @@ -0,0 +1,971 @@ +/* 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. + * + * + */ + +#include "common/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "graphics/cursorman.h" + +#include "sound/mixer.h" + +#include "toltecs/toltecs.h" +#include "toltecs/palette.h" +#include "toltecs/resource.h" +#include "toltecs/screen.h" +#include "toltecs/script.h" +#include "toltecs/segmap.h" + +namespace Toltecs { + +Screen::Screen(ToltecsEngine *vm) : _vm(vm) { + + _frontScreen = new byte[268800]; + _backScreen = new byte[870400]; + + memset(_fontResIndexArray, 0, sizeof(_fontResIndexArray)); + _fontColor1 = 0; + _fontColor2 = 0; + + // Screen shaking + _shakeActive = false; + _shakeCounterInit = 0; + _shakeCounter = 0; + _shakePos = 0; + + // Verb line + _verbLineNum = 0; + memset(_verbLineItems, 0, sizeof(_verbLineItems)); + _verbLineX = 160; + _verbLineY = 2; + _verbLineWidth = 20; + _verbLineCount = 0; + + // Talk text + _talkTextItemNum = 0; + memset(_talkTextItems, 0, sizeof(_talkTextItems)); + _talkTextX = 0;//TODO correct init values + _talkTextY = 0; + _talkTextFontColor = 0; + _talkTextMaxWidth = 520; + +} + +Screen::~Screen() { + + delete[] _frontScreen; + delete[] _backScreen; + +} + +void Screen::unpackRle(byte *source, byte *dest, uint16 width, uint16 height) { + int32 size = width * height; + while (size > 0) { + byte a = *source++; + byte b = *source++; + if (a == 0) { + dest += b; + size -= b; + } else { + b = ((b << 4) & 0xF0) | ((b >> 4) & 0x0F); + memset(dest, b, a); + dest += a; + size -= a; + } + } +} + +void Screen::loadMouseCursor(uint resIndex) { + byte mouseCursor[16 * 16], *mouseCursorP = mouseCursor; + byte *cursorData = _vm->_res->load(resIndex); + for (int i = 0; i < 32; i++) { + byte pixel; + byte mask1 = *cursorData++; + byte mask2 = *cursorData++; + for (int j = 0; j < 8; j++) { + pixel = 0xE5; + if ((mask2 & 0x80) == 0) + pixel = 0xE0; + mask2 <<= 1; + if ((mask1 & 0x80) == 0) + pixel = 0; + mask1 <<= 1; + *mouseCursorP++ = pixel; + } + } + //CursorMan.replaceCursor((const byte*)mouseCursor, 16, 16, 0, 0, 0); + // FIXME: Where's the cursor hotspot? Using 8, 8 seems good enough for now. + CursorMan.replaceCursor((const byte*)mouseCursor, 16, 16, 8, 8, 0); +} + +void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) { + + byte *imageData = _vm->_res->load(resIndex); + int16 headerSize = READ_LE_UINT16(imageData); + int16 width = imageData[2]; + int16 height = imageData[3]; + int16 workWidth = width, workHeight = height; + imageData += headerSize; + + byte *dest = _frontScreen + x + (y + _vm->_cameraHeight) * 640; + + debug(0, "Screen::drawGuiImage() x = %d; y = %d; w = %d; h = %d; resIndex = %d", x, y, width, height, resIndex); + + //_vm->_arc->dump(resIndex, "gui"); + + while (workHeight > 0) { + int count = 1; + byte pixel = *imageData++; + if (pixel & 0x80) { + pixel &= 0x7F; + count = *imageData++; + count += 2; + } + pixel = pixel + 0xE0; + while (count-- && workHeight > 0) { + *dest++ = pixel; + workWidth--; + if (workWidth == 0) { + workHeight--; + dest += 640 - width; + workWidth = width; + } + } + } + +} + +void Screen::startShakeScreen(int16 shakeCounter) { + _shakeActive = true; + _shakeCounterInit = shakeCounter; + _shakeCounter = shakeCounter; + _shakePos = 0; +} + +void Screen::stopShakeScreen() { + _shakeActive = false; + _vm->_system->setShakePos(0); +} + +void Screen::updateShakeScreen() { + if (_shakeActive) { + _shakeCounter--; + if (_shakeCounter == 0) { + _shakeCounter = _shakeCounterInit; + _shakePos ^= 8; + _vm->_system->setShakePos(_shakePos); + } + } +} + +void Screen::addStaticSprite(byte *spriteItem) { + + DrawRequest drawRequest; + memset(&drawRequest, 0, sizeof(drawRequest)); + + drawRequest.y = READ_LE_UINT16(spriteItem + 0); + drawRequest.x = READ_LE_UINT16(spriteItem + 2); + int16 fragmentId = READ_LE_UINT16(spriteItem + 4); + drawRequest.baseColor = _vm->_palette->findFragment(fragmentId) & 0xFF; + drawRequest.resIndex = READ_LE_UINT16(spriteItem + 6); + drawRequest.flags = READ_LE_UINT16(spriteItem + 8); + drawRequest.scaling = 0; + + debug(0, "Screen::addStaticSprite() x = %d; y = %d; baseColor = %d; resIndex = %d; flags = %04X", drawRequest.x, drawRequest.y, drawRequest.baseColor, drawRequest.resIndex, drawRequest.flags); + + addDrawRequest(drawRequest); + +} + +void Screen::addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, int16 *spriteArray, bool loop, int mode) { + + debug(0, "Screen::addAnimatedSprite(%d, %d, %d)", x, y, fragmentId); + + DrawRequest drawRequest; + memset(&drawRequest, 0, sizeof(drawRequest)); + + drawRequest.x = x; + drawRequest.y = y; + drawRequest.baseColor = _vm->_palette->findFragment(fragmentId) & 0xFF; + + if (mode == 1) { + drawRequest.scaling = _vm->_segmap->getScalingAtPoint(drawRequest.x, drawRequest.y); + } else if (mode == 2) { + drawRequest.scaling = 0; + } + + int16 count = spriteArray[0]; + + debug(0, "count = %d", count); + + for (int16 index = 1; index <= count; index++) { + + byte *spriteItem = data + spriteArray[index]; + + uint16 loopNum = READ_LE_UINT16(spriteItem + 0) & 0x7FFF; + uint16 loopCount = READ_LE_UINT16(spriteItem + 2); + uint16 frameNum = READ_LE_UINT16(spriteItem + 4); + uint16 frameCount = READ_LE_UINT16(spriteItem + 6); + drawRequest.resIndex = READ_LE_UINT16(spriteItem + 8); + drawRequest.flags = READ_LE_UINT16(spriteItem + 10 + loopNum * 2); + + debug(0, "Screen::addAnimatedSprite(%d of %d) loopNum = %d; loopCount = %d; frameNum = %d; frameCount = %d; resIndex = %d; flags = %04X, mode = %d", + index, count, loopNum, loopCount, frameNum, frameCount, drawRequest.resIndex, drawRequest.flags, mode); + + addDrawRequest(drawRequest); + + frameNum++; + if (frameNum == frameCount) { + frameNum = 0; + loopNum++; + if (loopNum == loopCount) { + if (loop) { + loopNum = 0; + } else { + loopNum--; + } + } + } else { + loopNum |= 0x8000; + } + + WRITE_LE_UINT16(spriteItem + 0, loopNum); + WRITE_LE_UINT16(spriteItem + 4, frameNum); + + } + +} + +void Screen::clearSprites() { + + _spriteDrawList.clear(); + // TODO + +} + +void Screen::addDrawRequest(const DrawRequest &drawRequest) { + + int16 scaleValueX, scaleValueY; + int16 spriteDraw_X, spriteDraw_Y; + byte *spriteData; + int16 frameNum; + + SpriteDrawItem sprite; + memset(&sprite, 0, sizeof(SpriteDrawItem)); + + if (drawRequest.flags == 0xFFFF) + return; + + sprite.flags = 0; + sprite.baseColor = drawRequest.baseColor; + sprite.x = drawRequest.x; + sprite.y = drawRequest.y; + sprite.ybottom = drawRequest.y; + sprite.resIndex = drawRequest.resIndex; + + spriteData = _vm->_res->load(drawRequest.resIndex); + + if (drawRequest.flags & 0x2000) { + sprite.flags |= 0x10; + } + + if (drawRequest.flags & 0x4000) { + sprite.flags |= 0x40; + } + + frameNum = drawRequest.flags & 0x0FFF; + + // First initialize the sprite item with the values from the sprite resource + + SpriteFrameEntry spriteFrameEntry(spriteData + frameNum * 12); + + if (spriteFrameEntry.w == 0 || spriteFrameEntry.h == 0) + return; + + sprite.offset = spriteFrameEntry.offset; + + sprite.width = spriteFrameEntry.w; + sprite.height = spriteFrameEntry.h; + + sprite.origWidth = spriteFrameEntry.w; + sprite.origHeight = spriteFrameEntry.h; + + if (drawRequest.flags & 0x1000) { + spriteDraw_X = spriteFrameEntry.w - spriteFrameEntry.x; + } else { + spriteDraw_X = spriteFrameEntry.x; + } + + spriteDraw_Y = spriteFrameEntry.y; + + // If the sprite should be scaled we need to initialize some values now + + if (drawRequest.scaling != 0) { + + byte scaleValue = ABS(drawRequest.scaling); + + scaleValueX = scaleValue * sprite.origWidth; + sprite.xdelta = (10000 * sprite.origWidth) / scaleValueX; + scaleValueX /= 100; + + scaleValueY = scaleValue * sprite.origHeight; + sprite.ydelta = (10000 * sprite.origHeight) / scaleValueY; + scaleValueY /= 100; + + if (drawRequest.scaling > 0) { + sprite.flags |= 2; + sprite.width = sprite.origWidth + scaleValueX; + sprite.height = sprite.origHeight + scaleValueY; + spriteDraw_X += (spriteDraw_X * scaleValue) / 100; + spriteDraw_Y += (spriteDraw_Y * scaleValue) / 100; + } else { + sprite.flags |= 1; + sprite.width = sprite.origWidth - scaleValueX; + sprite.height = sprite.origHeight - 1 - scaleValueY; + if (sprite.width <= 0 || sprite.height <= 0) + return; + spriteDraw_X -= (spriteDraw_X * scaleValue) / 100; + spriteDraw_Y -= (spriteDraw_Y * scaleValue) / 100; + } + + } + + sprite.x -= spriteDraw_X; + sprite.y -= spriteDraw_Y; + + sprite.yerror = sprite.ydelta; + + // Now we check if the sprite needs to be clipped + + // Clip Y + if (sprite.y - _vm->_cameraY < 0) { + + int16 clipHeight = ABS(sprite.y - _vm->_cameraY); + int16 chopHeight, skipHeight, lineWidth; + byte *spriteFrameData; + + sprite.height -= clipHeight; + if (sprite.height <= 0) + return; + + sprite.y = _vm->_cameraY; + + // If the sprite is scaled + if (sprite.flags & 3) { + chopHeight = sprite.ydelta; + skipHeight = clipHeight; + if ((sprite.flags & 2) == 0) { + do { + chopHeight -= 100; + if (chopHeight <= 0) { + skipHeight++; + chopHeight += sprite.ydelta; + } else { + clipHeight--; + } + } while (clipHeight > 0); + } else { + do { + chopHeight -= 100; + if (chopHeight < 0) { + skipHeight--; + chopHeight += sprite.ydelta + 100; + } + clipHeight--; + } while (clipHeight > 0); + } + sprite.yerror = chopHeight; + } + + spriteFrameData = spriteData + sprite.offset; + + // Now the sprite's offset is adjusted to point to the starting line + if ((sprite.flags & 0x10) == 0) { + while (clipHeight--) { + lineWidth = 0; + while (lineWidth </*CHECKME was != */ sprite.origWidth) { + sprite.offset++; + lineWidth += (*spriteFrameData++) & 0x0F; + } + } + } else { + lineWidth = 0; + while (clipHeight--) { + while (lineWidth < sprite.origWidth) { + sprite.offset += 2; + spriteFrameData++; + lineWidth += *spriteFrameData++; + } + } + } + + } + + if (sprite.y + sprite.height - _vm->_cameraY - _vm->_cameraHeight > 0) + sprite.height -= sprite.y + sprite.height - _vm->_cameraY - _vm->_cameraHeight; + if (sprite.height <= 0) + return; + + sprite.value1 = 0; + + if (drawRequest.flags & 0x1000) { + // Left border + sprite.flags |= 4; + if (sprite.x - _vm->_cameraX < 0) { + sprite.width -= ABS(sprite.x - _vm->_cameraX); + if (sprite.width <= 0) + return; + sprite.x = _vm->_cameraX; + } + // Right border + if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) { + sprite.flags |= 8; + sprite.width -= sprite.x + sprite.width - _vm->_cameraX - 640; + if (sprite.width <= 0) + return; + sprite.value1 = sprite.x + sprite.width - _vm->_cameraX - 640; + } + } else { + // Left border + if (sprite.x - _vm->_cameraX < 0) { + sprite.flags |= 8; + sprite.width -= ABS(sprite.x - _vm->_cameraX); + if (sprite.width <= 0) + return; + sprite.value1 = ABS(sprite.x - _vm->_cameraX); + sprite.x = _vm->_cameraX; + } + // Right border + if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) { + sprite.flags |= 8; + sprite.width -= sprite.x + sprite.width - _vm->_cameraX - 640; + if (sprite.width <= 0) + return; + } + } + + // Add sprite sorted by priority + Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin(); + while (iter != _spriteDrawList.end() && (*iter).ybottom <= sprite.ybottom) { + iter++; + } + _spriteDrawList.insert(iter, sprite); + +} + +void Screen::drawSprite(SpriteDrawItem *sprite) { + + debug(0, "Screen::drawSprite() x = %d; y = %d; flags = %04X; resIndex = %d; offset = %08X; drawX = %d; drawY = %d", + sprite->x, sprite->y, sprite->flags, sprite->resIndex, sprite->offset, + sprite->x - _vm->_cameraX, sprite->y - _vm->_cameraY); + debug(0, "Screen::drawSprite() width = %d; height = %d; origWidth = %d; origHeight = %d", + sprite->width, sprite->height, sprite->origWidth, sprite->origHeight); + + byte *source = _vm->_res->load(sprite->resIndex) + sprite->offset; + byte *dest = _frontScreen + (sprite->x - _vm->_cameraX) + (sprite->y - _vm->_cameraY) * 640; + + // FIXME: Temporary hack until proper clipping is implemented + /* + int16 dx = sprite->x - _vm->_cameraX, dy = sprite->y - _vm->_cameraY; + if (dx < 0 || dy < 0 || dx + sprite->width >= 640 || dy + sprite->height >= 400) + return; + */ + + SpriteReader spriteReader(source, sprite); + + if (sprite->flags & 0x40) { + // TODO: Shadow sprites + } else if (sprite->flags & 0x10) { + // 256 color sprite + drawSpriteCore(dest, spriteReader, sprite); + } else { + // 16 color sprite + if (sprite->flags & 1) { + SpriteFilterScaleDown spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else if (sprite->flags & 2) { + SpriteFilterScaleUp spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else { + drawSpriteCore(dest, spriteReader, sprite); + } + } + + debug(0, "Screen::drawSprite() ok"); + +} + +void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite) { + + int16 destInc; + + /* + if ((sprite->flags & 8)) + return; + */ + + if (sprite->flags & 4) { + destInc = -1; + dest += sprite->width; + } else { + destInc = 1; + } + + SpriteReaderStatus status; + PixelPacket packet; + + byte *destp = dest; + int16 skipX = sprite->value1; + + do { + status = reader.readPacket(packet); + + if (skipX > 0) { + while (skipX > 0) { + skipX -= packet.count; + if (skipX < 0) { + packet.count = ABS(skipX); + break; + } + status = reader.readPacket(packet); + } + } + + if (((sprite->flags & 0x10) && (packet.pixel != 0xFF)) || !(sprite->flags & 0x10) && (packet.pixel != 0)) { + if (sprite->flags & 0x40) { + } else if (sprite->flags & 0x10) { + packet.pixel = ((packet.pixel << 4) & 0xF0) | ((packet.pixel >> 4) & 0x0F); + } else { + packet.pixel += sprite->baseColor - 1; + } + while (packet.count--) { + *dest = packet.pixel; + dest += destInc; + } + } else { + dest += packet.count * destInc; + } + + if (status == kSrsEndOfLine) { + dest = destp + 640; + destp = dest; + skipX = sprite->value1; + } + + } while (status != kSrsEndOfSprite); + +} + +void Screen::drawSprites() { + for (Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin(); iter != _spriteDrawList.end(); iter++) { + SpriteDrawItem *sprite = &(*iter); + drawSprite(sprite); + _vm->_segmap->restoreMasksBySprite(sprite); + } +} + +void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) { + + debug(0, "Screen::updateVerbLine() _verbLineNum = %d; _verbLineX = %d; _verbLineY = %d; _verbLineWidth = %d; _verbLineCount = %d", + _verbLineNum, _verbLineX, _verbLineY, _verbLineWidth, _verbLineCount); + + Font font(_vm->_res->load(_fontResIndexArray[0])); + + _verbLineItems[_verbLineNum].slotIndex = slotIndex; + _verbLineItems[_verbLineNum].slotOffset = slotOffset; + + // First clear the line + int16 y = _verbLineY; + for (int16 i = 0; i < _verbLineCount; i++) { + byte *dest = _frontScreen + _verbLineX - _verbLineWidth / 2 + (y - 1 + _vm->_cameraHeight) * 640; + for (int16 j = 0; j < 20; j++) { + memset(dest, 0xE0, _verbLineWidth); + dest += 640; + } + y += 18; + } + + int width = 0; + byte *sourceString; + byte *destString; + byte len; + + _tempStringLen1 = 0; + destString = _tempString; + y = _verbLineY; + + memset(_tempString, 0, sizeof(_tempString)); + + for (int16 i = 0; i <= _verbLineNum; i++) { + sourceString = _vm->_script->getSlotData(_verbLineItems[i].slotIndex) + _verbLineItems[i].slotOffset; + preprocessText(_fontResIndexArray[0], _verbLineWidth, width, sourceString, destString, len); + _tempStringLen1 += len; + } + + if (_verbLineCount != 1) { + int16 charWidth; + if (*sourceString < 0xF0) { + while (*sourceString > 0x20 && *sourceString < 0xF0 && len > 0/*CHECKME, len check added*/) { + byte ch = *sourceString--; + _tempStringLen1--; + len--; + charWidth = font.getCharWidth(ch) + font.getSpacing() - 1; + width -= charWidth; + } + width += charWidth; + sourceString++; + _tempStringLen1 -= len; + _tempStringLen2 = len + 1; + + drawString(_verbLineX - 1 - (width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0]); + + destString = _tempString; + width = 0; + preprocessText(_fontResIndexArray[0], _verbLineWidth, width, sourceString, destString, len); + + _tempStringLen1 += len; + y += 9; + } + y += 9; + } + + _tempStringLen1 -= len; + _tempStringLen2 = len; + + drawString(_verbLineX - 1 - (width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0]); + +} + +void Screen::updateTalkText(int16 slotIndex, int16 slotOffset) { + + int16 x, y, maxWidth, width, length; + byte durationModifier = 1; + byte *textData = _vm->_script->getSlotData(slotIndex) + slotOffset; + + TalkTextItem *item = &_talkTextItems[_talkTextItemNum]; + + item->fontNum = 0; + item->color = _talkTextFontColor; + + //debug(0, "## _talkTextMaxWidth = %d", _talkTextMaxWidth); + + x = CLIP<int16>(_talkTextX - _vm->_cameraX, 120, _talkTextMaxWidth); + y = CLIP<int16>(_talkTextY - _vm->_cameraY, 4, _vm->_cameraHeight - 16); + + maxWidth = 624 - ABS(x - 320) * 2; + + while (1) { + if (*textData == 0x0A) { + x = CLIP<int16>(textData[3], 120, _talkTextMaxWidth); + y = CLIP<int16>(READ_LE_UINT16(&textData[1]), 4, _vm->_cameraHeight - 16); + maxWidth = 624 - ABS(x - 320) * 2; + textData += 4; + } else if (*textData == 0x14) { + item->color = textData[1]; + textData += 2; + } else if (*textData == 0x19) { + durationModifier = textData[1]; + textData += 2; + } else if (*textData < 0x0A) { + item->fontNum = textData[1]; + textData += 2; + } else + break; + } + + item->slotIndex = slotIndex; + item->slotOffset = textData - _vm->_script->getSlotData(slotIndex); + + width = 0; + length = 0; + + item->rectCount = 0; + + Font font(_vm->_res->load(_fontResIndexArray[item->fontNum])); + int16 wordLength, wordWidth; + + while (*textData < 0xF0) { + if (*textData == 0x1E) { + textData++; + addTalkTextRect(font, x, y, length, width, item); + // CHECKME? + width = 0; + length = 0; + } else { + wordLength = 0; + wordWidth = 0; + while (*textData >= 0x20 && *textData < 0xF0) { + byte ch = *textData++; + wordLength++; + if (ch == 0x20) { + wordWidth += font.getWidth(); + break; + } else { + wordWidth += font.getCharWidth(ch) + font.getSpacing() - 1; + } + } + + debug(0, "## width = %d; wordWidth = %d; width + wordWidth = %d; maxWidth + font.getWidth() = %d", + width, wordWidth, width + wordWidth, maxWidth + font.getWidth()); + + if (width + wordWidth > maxWidth + font.getWidth()) { + addTalkTextRect(font, x, y, length, width, item); + width = wordWidth; + length = wordLength; + } else { + width += wordWidth; + length += wordLength; + } + } + } + + addTalkTextRect(font, x, y, length, width, item); + + debug(0, "## item->rectCount = %d", item->rectCount); + + int16 textDurationMultiplier = item->duration + 8; + // TODO: Check sound/text flags + if (*textData == 0xFE) { + //textDurationMultiplier += 100; + } + item->duration = 4 * textDurationMultiplier * durationModifier; + +} + +void Screen::addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item) { + + if (width > 0) { + TextRect *textRect = &item->rects[item->rectCount]; + width = width + 1 - font.getSpacing(); + textRect->width = width; + item->duration += length; + textRect->length = length; + textRect->y = y; + textRect->x = CLIP<int16>(x - width / 2, 0, 640); + item->rectCount++; + } + + y += font.getHeight() - 1; + +} + +void Screen::drawTalkTextItems() { + + //debug(0, "## _talkTextItemNum = %d", _talkTextItemNum); + + for (int16 i = 0; i <= _talkTextItemNum; i++) { + TalkTextItem *item = &_talkTextItems[i]; + byte *text = _vm->_script->getSlotData(item->slotIndex) + item->slotOffset; + + if (item->fontNum == -1 || item->duration == 0) + continue; + + item->duration -= _vm->_counter01; + if (item->duration < 0) + item->duration = 0; + + Font font(_vm->_res->load(_fontResIndexArray[item->fontNum])); + for (byte j = 0; j < item->rectCount; j++) { + int16 x = item->rects[j].x; + for (byte pos = 0; pos < item->rects[j].length; pos++) { + byte ch = *text++; + if (ch < 0x20) + continue; + if (ch == 0x20) { + x += font.getWidth(); + } else { + drawChar2(font, _frontScreen, x, item->rects[j].y, ch, item->color); + x += font.getCharWidth(ch) + font.getSpacing() - 1; + } + } + } + } + +} + +int16 Screen::getTalkTextDuration() { + return _talkTextItems[_talkTextItemNum].duration; +} + +void Screen::registerFont(uint fontIndex, uint resIndex) { + _fontResIndexArray[fontIndex] = resIndex; +} + +void Screen::printText(byte *textData) { + + int16 x = 0, y = 0; + + // Really strange stuff. + for (int i = 30; i >= 0; i--) { + if (textData[i] >= 0xF0) + break; + if (i == 0) + return; + } + + do { + + if (*textData == 0x0A) { + // Set text position + y = textData[1]; + x = READ_LE_UINT32(textData + 2); + textData += 4; + } else if (*textData == 0x0B) { + // Inc text position + y += textData[1]; // CHECKME: Maybe these are signed? + x += textData[2]; + textData += 3; + } else { + byte *destString = _tempString; + int width = 0; + _tempStringLen1 = 0; + preprocessText(_fontResIndexArray[1], 640, width, textData, destString, _tempStringLen2); + drawString(x - width / 2, y, _fontColor1, _fontColor2, _fontResIndexArray[1]); + } + + } while (*textData != 0xFF); + +} + +void Screen::preprocessText(uint fontResIndex, int maxWidth, int &width, byte *&sourceString, byte *&destString, byte &len) { + + Font font(_vm->_res->load(fontResIndex)); + + len = 0; + while (*sourceString >= 0x20 && *sourceString < 0xF0) { + byte ch = *sourceString; + byte charWidth; + if (ch <= 0x20) + charWidth = font.getWidth(); + else + charWidth = font.getCharWidth(ch) + font.getSpacing() - 1; + if (width + charWidth >= maxWidth) + break; + len++; + width += charWidth; + *destString++ = *sourceString++; + } +} + +void Screen::drawString(int16 x, int16 y, byte fontColor1, byte fontColor2, uint fontResIndex) { + + debug(0, "Screen::drawString(%d, %d, %d, %d, %d) _tempStringLen1 = %d; _tempStringLen2 = %d", x, y, fontColor1, fontColor2, fontResIndex, _tempStringLen1, _tempStringLen2); + + Font font(_vm->_res->load(fontResIndex)); + + byte color = fontColor1; + byte *text = _tempString; + byte len = _tempStringLen1 + _tempStringLen2; + int16 yadd = 1; + + for (byte pos = 0; pos < len; pos++) { + if (pos == _tempStringLen1) { + color = fontColor2; + } + byte ch = *text++; + if (ch <= 0x20) { + x += font.getWidth(); + } else { + drawChar(font, _frontScreen, x + 1, y + _vm->_cameraHeight - yadd, ch, color); + x += font.getCharWidth(ch) + font.getSpacing() - 1; + yadd = -yadd; + } + } + +} + +// TODO: Merge drawChar and drawChar2 + +void Screen::drawChar(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color) { + + int16 charWidth, charHeight; + byte *charData; + + dest += x + (y * 640); + + charWidth = font.getCharWidth(ch); + charHeight = font.getHeight() - 2; + charData = font.getCharData(ch); + + while (charHeight--) { + byte lineWidth = charWidth; + while (lineWidth > 0) { + byte count = charData[0] & 0x0F; + byte flags = charData[0] & 0xF0; + charData++; + lineWidth -= count; + if (!(flags & 0x80) && (flags & 0x10)) { + memset(dest, color, count); + } + dest += count; + } + dest += 640 - charWidth; + } + +} + +void Screen::drawChar2(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color) { + + int16 charWidth, charHeight; + byte *charData; + + dest += x + (y * 640); + + charWidth = font.getCharWidth(ch); + charHeight = font.getHeight() - 2; + charData = font.getCharData(ch); + + while (charHeight--) { + byte lineWidth = charWidth; + while (lineWidth > 0) { + byte count = charData[0] & 0x0F; + byte flags = charData[0] & 0xF0; + charData++; + lineWidth -= count; + + if ((flags & 0x80) == 0) { + if ((flags & 0x10) == 0) { + memset(dest, 0, count); + } else { + memset(dest, color, count); + } + } + + dest += count; + } + dest += 640 - charWidth; + } + +} + +/* +void Screen::update() { +} +*/ + +} // End of namespace Toltecs |