Initial commit
This commit is contained in:
312
engines/kyra/graphics/animator_hof.cpp
Normal file
312
engines/kyra/graphics/animator_hof.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/engine/kyra_hof.h"
|
||||
#include "kyra/graphics/wsamovie.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
void KyraEngine_HoF::restorePage3() {
|
||||
screen()->copyBlockToPage(2, 0, 0, 320, 144, _gamePlayBuffer);
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::clearAnimObjects() {
|
||||
_animObjects[0].index = 0;
|
||||
_animObjects[0].type = 0;
|
||||
_animObjects[0].enabled = true;
|
||||
_animObjects[0].flags = 0x800;
|
||||
_animObjects[0].width = 32;
|
||||
_animObjects[0].height = 49;
|
||||
_animObjects[0].width2 = 4;
|
||||
_animObjects[0].height2 = 10;
|
||||
|
||||
for (int i = 1; i < 11; ++i) {
|
||||
_animObjects[i].index = i;
|
||||
_animObjects[i].type = 2;
|
||||
}
|
||||
|
||||
for (int i = 11; i <= 40; ++i) {
|
||||
_animObjects[i].index = i;
|
||||
_animObjects[i].type = 1;
|
||||
_animObjects[i].flags = 0x800;
|
||||
_animObjects[i].width = 16;
|
||||
_animObjects[i].height = 16;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::drawAnimObjects() {
|
||||
for (AnimObj *curObject = _animList; curObject; curObject = curObject->nextObject) {
|
||||
if (!curObject->enabled)
|
||||
continue;
|
||||
|
||||
int x = curObject->xPos2 - (_screen->getScreenDim(2)->sx << 3);
|
||||
int y = curObject->yPos2 - _screen->getScreenDim(2)->sy;
|
||||
int layer = 7;
|
||||
|
||||
if (curObject->flags & 0x800) {
|
||||
if (curObject->animFlags)
|
||||
layer = 0;
|
||||
else
|
||||
layer = getDrawLayer(curObject->xPos1, curObject->yPos1);
|
||||
}
|
||||
curObject->flags |= 0x800;
|
||||
|
||||
if (curObject->index)
|
||||
drawSceneAnimObject(curObject, x, y, layer);
|
||||
else
|
||||
drawCharacterAnimObject(curObject, x, y, layer);
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::refreshAnimObjects(int force) {
|
||||
for (AnimObj *curObject = _animList; curObject; curObject = curObject->nextObject) {
|
||||
if (!curObject->enabled)
|
||||
continue;
|
||||
if (!curObject->needRefresh && !force)
|
||||
continue;
|
||||
|
||||
int x = curObject->xPos2 - curObject->width2;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 320)
|
||||
x = 319;
|
||||
int y = curObject->yPos2 - curObject->height2;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (y >= 143)
|
||||
y = 142;
|
||||
|
||||
int width = curObject->width + curObject->width2 + 8;
|
||||
int height = curObject->height + curObject->height2*2;
|
||||
if (width + x > 320)
|
||||
width -= width + x - 322;
|
||||
if (height + y > 143)
|
||||
height -= height + y - 144;
|
||||
|
||||
_screen->copyRegion(x, y, x, y, width, height, 2, 0, Screen::CR_NO_P_CHECK);
|
||||
|
||||
curObject->needRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::updateItemAnimations() {
|
||||
bool nextFrame = false;
|
||||
|
||||
if (_itemAnimDefinition[0].itemIndex == -1 || _inventorySaved)
|
||||
return;
|
||||
|
||||
const ItemAnimDefinition *s = &_itemAnimDefinition[_nextAnimItem];
|
||||
ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
|
||||
_nextAnimItem = (_nextAnimItem + 1) % _itemAnimDefinitionSize;
|
||||
|
||||
if (_system->getMillis() < a->nextFrameTime)
|
||||
return;
|
||||
|
||||
uint16 shpIdx = s->frames[a->currentFrame].index + 64;
|
||||
if (s->itemIndex == _mouseState && s->itemIndex == _itemInHand && _screen->isMouseVisible()) {
|
||||
nextFrame = true;
|
||||
_screen->setMouseCursor(8, 15, getShapePtr(shpIdx));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (s->itemIndex == _mainCharacter.inventory[i]) {
|
||||
nextFrame = true;
|
||||
_screen->drawShape(2, getShapePtr(240 + i), 304, 184, 0, 0);
|
||||
_screen->drawShape(2, getShapePtr(shpIdx), 304, 184, 0, 0);
|
||||
_screen->copyRegion(304, 184, _inventoryX[i], _inventoryY[i], 16, 16, 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
_screen->updateScreen();
|
||||
|
||||
for (int i = 11; i < 40; i++) {
|
||||
AnimObj *animObject = &_animObjects[i];
|
||||
if (animObject->shapeIndex2 == s->itemIndex + 64) {
|
||||
if (s->itemIndex == 121) {
|
||||
int f = findItem(_mainCharacter.sceneId, 121);
|
||||
int nx = _itemList[f].x - 4;
|
||||
if (nx > 12) {
|
||||
if (lineIsPassable(nx, _itemList[f].y)) {
|
||||
animObject->xPos2 -= 4;
|
||||
_itemList[f].x -= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
animObject->shapePtr = getShapePtr(shpIdx);
|
||||
animObject->shapeIndex1 = shpIdx;
|
||||
animObject->needRefresh = 1;
|
||||
nextFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextFrame) {
|
||||
a->nextFrameTime = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
|
||||
a->currentFrame = (a->currentFrame + 1) % s->numFrames;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::updateCharFacing() {
|
||||
if (_mainCharacter.x1 > _mouseX)
|
||||
_mainCharacter.facing = 5;
|
||||
else
|
||||
_mainCharacter.facing = 3;
|
||||
|
||||
_mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
|
||||
updateCharacterAnim(0);
|
||||
refreshAnimObjectsIfNeed();
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::updateCharacterAnim(int) {
|
||||
Character *c = &_mainCharacter;
|
||||
AnimObj *animState = _animObjects;
|
||||
|
||||
animState->needRefresh = 1;
|
||||
animState->specialRefresh = 1;
|
||||
|
||||
if (c->facing >= 1 && c->facing <= 3)
|
||||
animState->flags |= 1;
|
||||
else if (c->facing >= 5 && c->facing <= 7)
|
||||
animState->flags &= ~1;
|
||||
|
||||
animState->xPos2 = animState->xPos1 = c->x1;
|
||||
animState->yPos2 = animState->yPos1 = c->y1;
|
||||
animState->shapePtr = getShapePtr(c->animFrame);
|
||||
animState->shapeIndex1 = animState->shapeIndex2 = c->animFrame;
|
||||
|
||||
int xAdd = _shapeDescTable[c->animFrame-9].xAdd;
|
||||
int yAdd = _shapeDescTable[c->animFrame-9].yAdd;
|
||||
|
||||
_charScale = getScale(c->x1, c->y1);
|
||||
|
||||
animState->xPos2 += (xAdd * _charScale) >> 8;
|
||||
animState->yPos2 += (yAdd * _charScale) >> 8;
|
||||
animState->width2 = 8;
|
||||
animState->height2 = 10;
|
||||
|
||||
_animList = deleteAnimListEntry(_animList, animState);
|
||||
if (_animList)
|
||||
_animList = addToAnimListSorted(_animList, animState);
|
||||
else
|
||||
_animList = initAnimList(_animList, animState);
|
||||
|
||||
updateCharPal(1);
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::updateSceneAnim(int anim, int newFrame) {
|
||||
AnimObj *animObject = &_animObjects[1+anim];
|
||||
if (!animObject->enabled)
|
||||
return;
|
||||
|
||||
animObject->needRefresh = 1;
|
||||
animObject->specialRefresh = 1;
|
||||
animObject->flags = 0;
|
||||
|
||||
if (_sceneAnims[anim].flags & 2)
|
||||
animObject->flags |= 0x800;
|
||||
else
|
||||
animObject->flags &= ~0x800;
|
||||
|
||||
if (_sceneAnims[anim].flags & 4)
|
||||
animObject->flags |= 1;
|
||||
else
|
||||
animObject->flags &= ~1;
|
||||
|
||||
if (_sceneAnims[anim].flags & 0x20) {
|
||||
animObject->shapePtr = _sceneShapeTable[newFrame];
|
||||
animObject->shapeIndex2 = 0xFFFF;
|
||||
animObject->shapeIndex3 = 0xFFFF;
|
||||
animObject->animNum = 0xFFFF;
|
||||
} else {
|
||||
animObject->shapePtr = nullptr;
|
||||
animObject->shapeIndex3 = newFrame;
|
||||
animObject->animNum = anim;
|
||||
}
|
||||
|
||||
animObject->xPos1 = _sceneAnims[anim].x;
|
||||
animObject->yPos1 = _sceneAnims[anim].y;
|
||||
animObject->xPos2 = _sceneAnims[anim].x2;
|
||||
animObject->yPos2 = _sceneAnims[anim].y2;
|
||||
|
||||
if (_sceneAnims[anim].flags & 2) {
|
||||
_animList = deleteAnimListEntry(_animList, animObject);
|
||||
if (!_animList)
|
||||
_animList = initAnimList(_animList, animObject);
|
||||
else
|
||||
_animList = addToAnimListSorted(_animList, animObject);
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::drawSceneAnimObject(AnimObj *obj, int x, int y, int layer) {
|
||||
if (obj->type == 1) {
|
||||
if (obj->shapeIndex1 == 0xFFFF)
|
||||
return;
|
||||
int scale = getScale(obj->xPos1, obj->yPos1);
|
||||
_screen->drawShape(2, getShapePtr(obj->shapeIndex1), x, y, 2, obj->flags | 4, layer, scale, scale);
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj->shapePtr) {
|
||||
_screen->drawShape(2, obj->shapePtr, x, y, 2, obj->flags, layer);
|
||||
} else {
|
||||
if (obj->shapeIndex3 == 0xFFFF || obj->animNum == 0xFFFF)
|
||||
return;
|
||||
|
||||
int flags = 0x4000;
|
||||
if (obj->flags & 0x800)
|
||||
flags |= 0x8000;
|
||||
|
||||
if (_sceneAnims[obj->animNum].wsaFlag) {
|
||||
x = y = 0;
|
||||
} else {
|
||||
x = obj->xPos2;
|
||||
y = obj->yPos2;
|
||||
}
|
||||
|
||||
_sceneAnimMovie[obj->animNum]->displayFrame(obj->shapeIndex3, 2, x, y, int(flags | layer), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::drawCharacterAnimObject(AnimObj *obj, int x, int y, int layer) {
|
||||
if (_drawNoShapeFlag || obj->shapeIndex1 == 0xFFFF)
|
||||
return;
|
||||
_screen->drawShape(2, getShapePtr(obj->shapeIndex1), x, y, 2, obj->flags | 4, layer, _charScale, _charScale);
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::setCharacterAnimDim(int w, int h) {
|
||||
restorePage3();
|
||||
|
||||
_animObj0Width = _animObjects[0].width;
|
||||
_animObj0Height = _animObjects[0].height;
|
||||
|
||||
_animObjects[0].width = w;
|
||||
_animObjects[0].height = h;
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::resetCharacterAnimDim() {
|
||||
restorePage3();
|
||||
|
||||
_animObjects[0].width = _animObj0Width;
|
||||
_animObjects[0].height = _animObj0Height;
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
646
engines/kyra/graphics/animator_lok.cpp
Normal file
646
engines/kyra/graphics/animator_lok.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/engine/kyra_lok.h"
|
||||
#include "kyra/graphics/screen.h"
|
||||
#include "kyra/graphics/animator_lok.h"
|
||||
#include "kyra/engine/sprites.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Animator_LoK::Animator_LoK(KyraEngine_LoK *vm, OSystem *system) {
|
||||
_vm = vm;
|
||||
_screen = vm->screen();
|
||||
_initOk = false;
|
||||
_system = system;
|
||||
_screenObjects = _actors = _items = _sprites = _objectQueue = nullptr;
|
||||
_noDrawShapesFlag = 0;
|
||||
_brandonDrawFrame = 0;
|
||||
_brandonScaleX = _brandonScaleY = _brandonAnimSeqSizeWidth = _brandonAnimSeqSizeHeight = 0;
|
||||
|
||||
_actorBkgBackUp[0] = new uint8[_screen->getRectSize(8, 69)]();
|
||||
_actorBkgBackUp[1] = new uint8[_screen->getRectSize(8, 69)]();
|
||||
}
|
||||
|
||||
Animator_LoK::~Animator_LoK() {
|
||||
close();
|
||||
delete[] _actorBkgBackUp[0];
|
||||
delete[] _actorBkgBackUp[1];
|
||||
}
|
||||
|
||||
void Animator_LoK::init(int actors_, int items_, int sprites_) {
|
||||
_screenObjects = new AnimObject[actors_ + items_ + sprites_]();
|
||||
assert(_screenObjects);
|
||||
_actors = _screenObjects;
|
||||
_sprites = &_screenObjects[actors_];
|
||||
_items = &_screenObjects[actors_ + items_];
|
||||
_brandonDrawFrame = 113;
|
||||
|
||||
_initOk = true;
|
||||
}
|
||||
|
||||
void Animator_LoK::close() {
|
||||
if (_initOk) {
|
||||
_initOk = false;
|
||||
delete[] _screenObjects;
|
||||
_screenObjects = _actors = _items = _sprites = _objectQueue = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator_LoK::initAnimStateList() {
|
||||
AnimObject *animStates = _screenObjects;
|
||||
animStates[0].index = 0;
|
||||
animStates[0].active = 1;
|
||||
animStates[0].flags = 0x800;
|
||||
animStates[0].background = _actorBkgBackUp[0];
|
||||
animStates[0].rectSize = _screen->getRectSize(4, 48);
|
||||
animStates[0].width = 4;
|
||||
animStates[0].height = 48;
|
||||
animStates[0].width2 = 4;
|
||||
animStates[0].height2 = 3;
|
||||
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
animStates[i].index = i;
|
||||
animStates[i].active = 0;
|
||||
animStates[i].flags = 0x800;
|
||||
animStates[i].background = _actorBkgBackUp[1];
|
||||
animStates[i].rectSize = _screen->getRectSize(4, 64);
|
||||
animStates[i].width = 4;
|
||||
animStates[i].height = 48;
|
||||
animStates[i].width2 = 4;
|
||||
animStates[i].height2 = 3;
|
||||
}
|
||||
|
||||
for (int i = 5; i < 16; ++i) {
|
||||
animStates[i].index = i;
|
||||
animStates[i].active = 0;
|
||||
animStates[i].flags = 0;
|
||||
}
|
||||
|
||||
for (int i = 16; i < 28; ++i) {
|
||||
animStates[i].index = i;
|
||||
animStates[i].flags = 0;
|
||||
animStates[i].background = _vm->_shapes[345 + i];
|
||||
animStates[i].rectSize = _screen->getRectSize(3, 24);
|
||||
animStates[i].width = 3;
|
||||
animStates[i].height = 16;
|
||||
animStates[i].width2 = 0;
|
||||
animStates[i].height2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator_LoK::preserveAllBackgrounds() {
|
||||
uint8 curPage = _screen->_curPage;
|
||||
_screen->_curPage = 2;
|
||||
|
||||
AnimObject *curObject = _objectQueue;
|
||||
while (curObject) {
|
||||
if (curObject->active && !curObject->disable) {
|
||||
preserveOrRestoreBackground(curObject, false);
|
||||
curObject->bkgdChangeFlag = 0;
|
||||
}
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
_screen->_curPage = curPage;
|
||||
}
|
||||
|
||||
void Animator_LoK::flagAllObjectsForBkgdChange() {
|
||||
AnimObject *curObject = _objectQueue;
|
||||
while (curObject) {
|
||||
curObject->bkgdChangeFlag = 1;
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator_LoK::flagAllObjectsForRefresh() {
|
||||
AnimObject *curObject = _objectQueue;
|
||||
while (curObject) {
|
||||
curObject->refreshFlag = 1;
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator_LoK::restoreAllObjectBackgrounds() {
|
||||
AnimObject *curObject = _objectQueue;
|
||||
_screen->_curPage = 2;
|
||||
|
||||
while (curObject) {
|
||||
if (curObject->active && !curObject->disable) {
|
||||
preserveOrRestoreBackground(curObject, true);
|
||||
curObject->x2 = curObject->x1;
|
||||
curObject->y2 = curObject->y1;
|
||||
}
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
|
||||
_screen->_curPage = 0;
|
||||
}
|
||||
|
||||
void Animator_LoK::preserveAnyChangedBackgrounds() {
|
||||
AnimObject *curObject = _objectQueue;
|
||||
_screen->_curPage = 2;
|
||||
|
||||
while (curObject) {
|
||||
if (curObject->active && !curObject->disable && curObject->bkgdChangeFlag) {
|
||||
preserveOrRestoreBackground(curObject, false);
|
||||
curObject->bkgdChangeFlag = 0;
|
||||
}
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
|
||||
_screen->_curPage = 0;
|
||||
}
|
||||
|
||||
void Animator_LoK::preserveOrRestoreBackground(AnimObject *obj, bool restore) {
|
||||
int x = 0, y = 0, width = obj->width, height = obj->height;
|
||||
|
||||
if (restore) {
|
||||
x = obj->x2 >> 3;
|
||||
y = obj->y2;
|
||||
} else {
|
||||
x = obj->x1 >> 3;
|
||||
y = obj->y1;
|
||||
}
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
|
||||
int temp;
|
||||
|
||||
temp = x + width;
|
||||
if (temp >= 39)
|
||||
x = 39 - width;
|
||||
temp = y + height;
|
||||
if (temp >= 136)
|
||||
y = 136 - height;
|
||||
|
||||
if (restore)
|
||||
_screen->copyBlockToPage(_screen->_curPage, x << 3, y, width << 3, height, obj->background);
|
||||
else
|
||||
_screen->copyRegionToBuffer(_screen->_curPage, x << 3, y, width << 3, height, obj->background);
|
||||
}
|
||||
|
||||
void Animator_LoK::prepDrawAllObjects() {
|
||||
AnimObject *curObject = _objectQueue;
|
||||
int drawPage = 2;
|
||||
int invisibilityDrawFlag = 0, blurDrawFlag = 0, fadeDrawFlag = 0;
|
||||
if (_noDrawShapesFlag)
|
||||
return;
|
||||
if (_vm->_brandonStatusBit & 0x20)
|
||||
invisibilityDrawFlag = Screen::kDRAWSHP_PREDATOR;
|
||||
if (_vm->_brandonStatusBit & 0x40)
|
||||
blurDrawFlag = Screen::kDRAWSHP_MORPH;
|
||||
|
||||
while (curObject) {
|
||||
if (curObject->active) {
|
||||
int xpos = curObject->x1;
|
||||
int ypos = curObject->y1;
|
||||
|
||||
int drawLayer = 0;
|
||||
if (!(curObject->flags & Screen::kDRAWSHP_PRIORITY))
|
||||
drawLayer = 7;
|
||||
else if (curObject->disable)
|
||||
drawLayer = 0;
|
||||
else
|
||||
drawLayer = _vm->_sprites->getDrawLayer(curObject->drawY);
|
||||
|
||||
// Talking head functionallity
|
||||
// DOS Floppy, Amiga and Mac work differently than DOS Talkie. PC-98 and FM-Towns are similar to DOS Talkie, but also slightly different.
|
||||
bool fmTownsOrPC98 = (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98);
|
||||
if (_vm->_talkingCharNum != -1 && (fmTownsOrPC98 || (_vm->gameFlags().isTalkie ?
|
||||
(_vm->_currentCharacter->currentAnimFrame != 88 || curObject->index != 0) : (_brandonScaleX == 0x100 || !_vm->_scaleMode)))) {
|
||||
const int16 baseAnimFrameTable1[] = { 0x11, 0x35, 0x59, 0x00, 0x00 };
|
||||
const int16 baseAnimFrameTable2[] = { 0x15, 0x39, 0x5D, 0x00, 0x00 };
|
||||
const int8 xOffsetTable1[] = { 2, 4, 0, 5, 2, };
|
||||
const int8 xOffsetTable2[] = { 6, 4, 8, 3, 6, };
|
||||
const int8 yOffsetTable[] = { 0, 8, 1, 1, 0, };
|
||||
if (curObject->index <= 4) {
|
||||
int shapesIndex = 0;
|
||||
if (curObject->index == _vm->_talkHeadAnimCharNum)
|
||||
shapesIndex = _vm->_currHeadShape + baseAnimFrameTable1[curObject->index];
|
||||
else if (curObject->index != 2 || _vm->_characterList[2].sceneId == 77 || _vm->_characterList[2].sceneId == 86)
|
||||
shapesIndex = baseAnimFrameTable2[curObject->index];
|
||||
else
|
||||
shapesIndex = -1;
|
||||
|
||||
xpos = curObject->x1;
|
||||
ypos = curObject->y1;
|
||||
|
||||
int tempX = 0, tempY = 0;
|
||||
if (curObject->flags & Screen::kDRAWSHP_XFLIP) {
|
||||
tempX = xOffsetTable1[curObject->index];
|
||||
tempY = yOffsetTable[curObject->index];
|
||||
} else {
|
||||
tempX = xOffsetTable2[curObject->index];
|
||||
tempY = yOffsetTable[curObject->index];
|
||||
}
|
||||
|
||||
if (_vm->gameFlags().isTalkie || fmTownsOrPC98) {
|
||||
tempX = (tempX * _brandonScaleX) >> 8;
|
||||
tempY = (tempY * _brandonScaleY) >> 8;
|
||||
if (_vm->_scaleMode && _brandonScaleX != 0x100)
|
||||
++tempX;
|
||||
}
|
||||
|
||||
xpos += tempX;
|
||||
ypos += tempY;
|
||||
|
||||
if (curObject->index == 0 && shapesIndex != -1) {
|
||||
if (!(_vm->_brandonStatusBit & 2)) {
|
||||
fadeDrawFlag = Screen::kDRAWSHP_FADE;
|
||||
if ((invisibilityDrawFlag & Screen::kDRAWSHP_PREDATOR) || (blurDrawFlag & Screen::kDRAWSHP_MORPH))
|
||||
fadeDrawFlag = 0;
|
||||
|
||||
int tempFlags = 0;
|
||||
if (fadeDrawFlag & Screen::kDRAWSHP_FADE) {
|
||||
tempFlags = curObject->flags & Screen::kDRAWSHP_XFLIP;
|
||||
tempFlags |= (Screen::kDRAWSHP_PRIORITY | invisibilityDrawFlag | Screen::kDRAWSHP_FADE);
|
||||
}
|
||||
|
||||
if (!(fadeDrawFlag & Screen::kDRAWSHP_FADE) && (blurDrawFlag & Screen::kDRAWSHP_MORPH)) {
|
||||
tempFlags = curObject->flags & Screen::kDRAWSHP_XFLIP;
|
||||
tempFlags |= (Screen::kDRAWSHP_PRIORITY | Screen::kDRAWSHP_FADE | invisibilityDrawFlag | Screen::kDRAWSHP_MORPH);
|
||||
_screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | Screen::kDRAWSHP_SCALE, _vm->_brandonPoisonFlagsGFX, int(1), int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY);
|
||||
} else {
|
||||
if (!(blurDrawFlag & Screen::kDRAWSHP_MORPH)) {
|
||||
tempFlags = curObject->flags & Screen::kDRAWSHP_XFLIP;
|
||||
tempFlags |= (Screen::kDRAWSHP_PRIORITY | Screen::kDRAWSHP_FADE | invisibilityDrawFlag);
|
||||
}
|
||||
|
||||
_screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | Screen::kDRAWSHP_SCALE, _vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (shapesIndex != -1) {
|
||||
int tempFlags = 0;
|
||||
if (curObject->flags & Screen::kDRAWSHP_XFLIP)
|
||||
tempFlags = Screen::kDRAWSHP_XFLIP;
|
||||
_screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | Screen::kDRAWSHP_PRIORITY, drawLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xpos = curObject->x1;
|
||||
ypos = curObject->y1;
|
||||
|
||||
curObject->flags |= Screen::kDRAWSHP_PRIORITY;
|
||||
if (curObject->index == 0) {
|
||||
fadeDrawFlag = Screen::kDRAWSHP_FADE;
|
||||
|
||||
if (invisibilityDrawFlag & Screen::kDRAWSHP_PREDATOR || blurDrawFlag & Screen::kDRAWSHP_MORPH)
|
||||
fadeDrawFlag = 0;
|
||||
|
||||
if (_vm->_brandonStatusBit & 2)
|
||||
curObject->flags &= ~Screen::kDRAWSHP_XFLIP;
|
||||
|
||||
if (!_vm->_scaleMode) {
|
||||
if (fadeDrawFlag & Screen::kDRAWSHP_FADE)
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag | Screen::kDRAWSHP_FADE, (uint8 *)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer);
|
||||
else if (blurDrawFlag & Screen::kDRAWSHP_MORPH)
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag | Screen::kDRAWSHP_MORPH, int(_vm->_brandonInvFlag), drawLayer);
|
||||
else
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag, drawLayer);
|
||||
} else {
|
||||
if (fadeDrawFlag & Screen::kDRAWSHP_FADE)
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag | Screen::kDRAWSHP_FADE | Screen::kDRAWSHP_SCALE, (uint8 *)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY);
|
||||
else if (blurDrawFlag & Screen::kDRAWSHP_MORPH)
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag | Screen::kDRAWSHP_MORPH | Screen::kDRAWSHP_SCALE, int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY);
|
||||
else
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | invisibilityDrawFlag | Screen::kDRAWSHP_SCALE, drawLayer, _brandonScaleX, _brandonScaleY);
|
||||
}
|
||||
} else {
|
||||
if (curObject->index >= 16 && curObject->index <= 27)
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | Screen::kDRAWSHP_SCALE, drawLayer, (int)_vm->_scaleTable[curObject->drawY], (int)_vm->_scaleTable[curObject->drawY]);
|
||||
else
|
||||
_screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags, drawLayer);
|
||||
}
|
||||
}
|
||||
curObject = curObject->nextAnimObject;
|
||||
}
|
||||
}
|
||||
|
||||
void Animator_LoK::copyChangedObjectsForward(int refreshFlag, bool refreshScreen) {
|
||||
for (AnimObject *curObject = _objectQueue; curObject; curObject = curObject->nextAnimObject) {
|
||||
if (curObject->active) {
|
||||
if (curObject->refreshFlag || refreshFlag) {
|
||||
int xpos = 0, ypos = 0, width = 0, height = 0;
|
||||
xpos = (curObject->x1 >> 3) - (curObject->width2 >> 3) - 1;
|
||||
ypos = curObject->y1 - curObject->height2;
|
||||
width = curObject->width + (curObject->width2 >> 3) + 2;
|
||||
height = curObject->height + curObject->height2 * 2;
|
||||
|
||||
if (xpos < 1)
|
||||
xpos = 1;
|
||||
else if (xpos > 39)
|
||||
continue;
|
||||
|
||||
if (xpos + width > 39)
|
||||
width = 39 - xpos;
|
||||
|
||||
if (ypos < 8)
|
||||
ypos = 8;
|
||||
else if (ypos > 136)
|
||||
continue;
|
||||
|
||||
if (ypos + height > 136)
|
||||
height = 136 - ypos;
|
||||
|
||||
_screen->copyRegion(xpos << 3, ypos, xpos << 3, ypos, width << 3, height, 2, 0);
|
||||
curObject->refreshFlag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshScreen)
|
||||
_screen->updateScreen();
|
||||
}
|
||||
|
||||
void Animator_LoK::updateAllObjectShapes(bool refreshScreen) {
|
||||
restoreAllObjectBackgrounds();
|
||||
preserveAnyChangedBackgrounds();
|
||||
prepDrawAllObjects();
|
||||
copyChangedObjectsForward(0, refreshScreen);
|
||||
}
|
||||
|
||||
void Animator_LoK::animRemoveGameItem(int index) {
|
||||
restoreAllObjectBackgrounds();
|
||||
|
||||
AnimObject *animObj = &_items[index];
|
||||
animObj->sceneAnimPtr = nullptr;
|
||||
animObj->animFrameNumber = -1;
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
updateAllObjectShapes();
|
||||
animObj->active = 0;
|
||||
|
||||
objectRemoveQueue(_objectQueue, animObj);
|
||||
}
|
||||
|
||||
void Animator_LoK::animAddGameItem(int index, uint16 sceneId) {
|
||||
restoreAllObjectBackgrounds();
|
||||
assert(sceneId < _vm->_roomTableSize);
|
||||
Room *currentRoom = &_vm->_roomTable[sceneId];
|
||||
AnimObject *animObj = &_items[index];
|
||||
animObj->active = 1;
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
animObj->drawY = currentRoom->itemsYPos[index];
|
||||
animObj->sceneAnimPtr = _vm->_shapes[216 + currentRoom->itemsTable[index]];
|
||||
animObj->animFrameNumber = -1;
|
||||
animObj->x1 = currentRoom->itemsXPos[index];
|
||||
animObj->y1 = currentRoom->itemsYPos[index];
|
||||
animObj->x1 -= fetchAnimWidth(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]) >> 1;
|
||||
animObj->y1 -= fetchAnimHeight(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]);
|
||||
animObj->x2 = animObj->x1;
|
||||
animObj->y2 = animObj->y1;
|
||||
animObj->width2 = 0;
|
||||
animObj->height2 = 0;
|
||||
_objectQueue = objectQueue(_objectQueue, animObj);
|
||||
preserveAnyChangedBackgrounds();
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
}
|
||||
|
||||
void Animator_LoK::animAddNPC(int character) {
|
||||
restoreAllObjectBackgrounds();
|
||||
AnimObject *animObj = &_actors[character];
|
||||
const Character *ch = &_vm->_characterList[character];
|
||||
|
||||
animObj->active = 1;
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
animObj->drawY = ch->y1;
|
||||
animObj->sceneAnimPtr = _vm->_shapes[ch->currentAnimFrame];
|
||||
animObj->x1 = animObj->x2 = ch->x1 + _vm->_defaultShapeTable[ch->currentAnimFrame - 7].xOffset;
|
||||
animObj->y1 = animObj->y2 = ch->y1 + _vm->_defaultShapeTable[ch->currentAnimFrame - 7].yOffset;
|
||||
|
||||
if (ch->facing >= 1 && ch->facing <= 3)
|
||||
animObj->flags |= 1;
|
||||
else if (ch->facing >= 5 && ch->facing <= 7)
|
||||
animObj->flags &= 0xFFFFFFFE;
|
||||
|
||||
_objectQueue = objectQueue(_objectQueue, animObj);
|
||||
preserveAnyChangedBackgrounds();
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
}
|
||||
|
||||
Animator_LoK::AnimObject *Animator_LoK::objectRemoveQueue(AnimObject *queue, AnimObject *rem) {
|
||||
AnimObject *cur = queue;
|
||||
AnimObject *prev = queue;
|
||||
|
||||
while (cur != rem && cur) {
|
||||
AnimObject *temp = cur->nextAnimObject;
|
||||
if (!temp)
|
||||
break;
|
||||
prev = cur;
|
||||
cur = temp;
|
||||
}
|
||||
|
||||
if (cur == queue) {
|
||||
if (!cur)
|
||||
return nullptr;
|
||||
return cur->nextAnimObject;
|
||||
}
|
||||
|
||||
if (!cur->nextAnimObject) {
|
||||
if (cur == rem) {
|
||||
if (!prev)
|
||||
return nullptr;
|
||||
else
|
||||
prev->nextAnimObject = nullptr;
|
||||
}
|
||||
} else {
|
||||
if (cur == rem)
|
||||
prev->nextAnimObject = rem->nextAnimObject;
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
Animator_LoK::AnimObject *Animator_LoK::objectAddHead(AnimObject *queue, AnimObject *head) {
|
||||
head->nextAnimObject = queue;
|
||||
return head;
|
||||
}
|
||||
|
||||
Animator_LoK::AnimObject *Animator_LoK::objectQueue(AnimObject *queue, AnimObject *add) {
|
||||
if (!queue || add->drawY <= queue->drawY) {
|
||||
add->nextAnimObject = queue;
|
||||
return add;
|
||||
}
|
||||
AnimObject *cur = queue;
|
||||
AnimObject *prev = queue;
|
||||
while (add->drawY > cur->drawY) {
|
||||
AnimObject *temp = cur->nextAnimObject;
|
||||
if (!temp)
|
||||
break;
|
||||
prev = cur;
|
||||
cur = temp;
|
||||
}
|
||||
|
||||
if (add->drawY <= cur->drawY) {
|
||||
prev->nextAnimObject = add;
|
||||
add->nextAnimObject = cur;
|
||||
} else {
|
||||
cur->nextAnimObject = add;
|
||||
add->nextAnimObject = nullptr;
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
void Animator_LoK::addObjectToQueue(AnimObject *object) {
|
||||
if (!_objectQueue)
|
||||
_objectQueue = objectAddHead(nullptr, object);
|
||||
else
|
||||
_objectQueue = objectQueue(_objectQueue, object);
|
||||
}
|
||||
|
||||
void Animator_LoK::refreshObject(AnimObject *object) {
|
||||
_objectQueue = objectRemoveQueue(_objectQueue, object);
|
||||
if (_objectQueue)
|
||||
_objectQueue = objectQueue(_objectQueue, object);
|
||||
else
|
||||
_objectQueue = objectAddHead(nullptr, object);
|
||||
}
|
||||
|
||||
void Animator_LoK::makeBrandonFaceMouse() {
|
||||
Common::Point mouse = _vm->getMousePos();
|
||||
if (mouse.x >= _vm->_currentCharacter->x1)
|
||||
_vm->_currentCharacter->facing = 3;
|
||||
else
|
||||
_vm->_currentCharacter->facing = 5;
|
||||
animRefreshNPC(0);
|
||||
updateAllObjectShapes();
|
||||
}
|
||||
|
||||
int16 Animator_LoK::fetchAnimWidth(const uint8 *shape, int16 mult) {
|
||||
if (_vm->gameFlags().useAltShapeHeader)
|
||||
shape += 2;
|
||||
return (((int16)READ_LE_UINT16((shape + 3))) * mult) >> 8;
|
||||
}
|
||||
|
||||
int16 Animator_LoK::fetchAnimHeight(const uint8 *shape, int16 mult) {
|
||||
if (_vm->gameFlags().useAltShapeHeader)
|
||||
shape += 2;
|
||||
return (int16)(((int8)*(shape + 2)) * mult) >> 8;
|
||||
}
|
||||
|
||||
void Animator_LoK::setBrandonAnimSeqSize(int width, int height) {
|
||||
restoreAllObjectBackgrounds();
|
||||
_brandonAnimSeqSizeWidth = _actors[0].width;
|
||||
_brandonAnimSeqSizeHeight = _actors[0].height;
|
||||
_actors[0].width = width + 1;
|
||||
_actors[0].height = height;
|
||||
preserveAllBackgrounds();
|
||||
}
|
||||
|
||||
void Animator_LoK::resetBrandonAnimSeqSize() {
|
||||
restoreAllObjectBackgrounds();
|
||||
_actors[0].width = _brandonAnimSeqSizeWidth;
|
||||
_actors[0].height = _brandonAnimSeqSizeHeight;
|
||||
preserveAllBackgrounds();
|
||||
}
|
||||
|
||||
void Animator_LoK::animRefreshNPC(int character) {
|
||||
AnimObject *animObj = &_actors[character];
|
||||
Character *ch = &_vm->characterList()[character];
|
||||
|
||||
animObj->refreshFlag = 1;
|
||||
animObj->bkgdChangeFlag = 1;
|
||||
int facing = ch->facing;
|
||||
if (facing >= 1 && facing <= 3)
|
||||
animObj->flags |= 1;
|
||||
else if (facing >= 5 && facing <= 7)
|
||||
animObj->flags &= 0xFFFFFFFE;
|
||||
|
||||
animObj->drawY = ch->y1;
|
||||
animObj->sceneAnimPtr = _vm->shapes()[ch->currentAnimFrame];
|
||||
animObj->animFrameNumber = ch->currentAnimFrame;
|
||||
if (character == 0) {
|
||||
if (_vm->brandonStatus() & 10) {
|
||||
animObj->animFrameNumber = 88;
|
||||
ch->currentAnimFrame = 88;
|
||||
}
|
||||
if (_vm->brandonStatus() & 2) {
|
||||
animObj->animFrameNumber = _brandonDrawFrame;
|
||||
ch->currentAnimFrame = _brandonDrawFrame;
|
||||
animObj->sceneAnimPtr = _vm->shapes()[_brandonDrawFrame];
|
||||
if (_vm->_brandonStatusBit0x02Flag) {
|
||||
++_brandonDrawFrame;
|
||||
// TODO: check this
|
||||
// UPDATE: From DOS floppy disasm: _brandonDrawFrame > 122 --> Test where this actually occurs
|
||||
if (_brandonDrawFrame >= 122) {
|
||||
_brandonDrawFrame = 113;
|
||||
_vm->_brandonStatusBit0x02Flag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xOffset = _vm->_defaultShapeTable[ch->currentAnimFrame - 7].xOffset;
|
||||
int yOffset = _vm->_defaultShapeTable[ch->currentAnimFrame - 7].yOffset;
|
||||
|
||||
if (_vm->_scaleMode) {
|
||||
animObj->x1 = ch->x1;
|
||||
animObj->y1 = ch->y1;
|
||||
|
||||
int newScale = _vm->_scaleTable[ch->y1];
|
||||
_brandonScaleX = newScale;
|
||||
_brandonScaleY = newScale;
|
||||
|
||||
animObj->x1 += (_brandonScaleX * xOffset) >> 8;
|
||||
animObj->y1 += (_brandonScaleY * yOffset) >> 8;
|
||||
} else {
|
||||
animObj->x1 = ch->x1 + xOffset;
|
||||
animObj->y1 = ch->y1 + yOffset;
|
||||
}
|
||||
animObj->width2 = 4;
|
||||
animObj->height2 = 3;
|
||||
|
||||
refreshObject(animObj);
|
||||
}
|
||||
|
||||
void Animator_LoK::setCharacterDefaultFrame(int character) {
|
||||
static const uint16 initFrameTable[] = {
|
||||
7, 41, 77, 0, 0
|
||||
};
|
||||
assert(character < ARRAYSIZE(initFrameTable));
|
||||
Character *edit = &_vm->characterList()[character];
|
||||
edit->sceneId = 0xFFFF;
|
||||
edit->facing = 0;
|
||||
edit->currentAnimFrame = initFrameTable[character];
|
||||
// edit->unk6 = 1;
|
||||
}
|
||||
|
||||
void Animator_LoK::setCharactersHeight() {
|
||||
static const int8 initHeightTable[] = {
|
||||
48, 40, 48, 47, 56,
|
||||
44, 42, 47, 38, 35,
|
||||
40
|
||||
};
|
||||
for (int i = 0; i < 11; ++i)
|
||||
_vm->characterList()[i].height = initHeightTable[i];
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
126
engines/kyra/graphics/animator_lok.h
Normal file
126
engines/kyra/graphics/animator_lok.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_ANIMATOR_LOK_H
|
||||
#define KYRA_ANIMATOR_LOK_H
|
||||
|
||||
namespace Kyra {
|
||||
class KyraEngine_LoK;
|
||||
class Screen;
|
||||
|
||||
class Animator_LoK {
|
||||
public:
|
||||
struct AnimObject {
|
||||
uint8 index;
|
||||
uint32 active;
|
||||
uint32 refreshFlag;
|
||||
uint32 bkgdChangeFlag;
|
||||
bool disable;
|
||||
uint32 flags;
|
||||
int16 drawY;
|
||||
uint8 *sceneAnimPtr;
|
||||
int16 animFrameNumber;
|
||||
uint8 *background;
|
||||
uint16 rectSize;
|
||||
int16 x1, y1;
|
||||
int16 x2, y2;
|
||||
uint16 width;
|
||||
uint16 height;
|
||||
uint16 width2;
|
||||
uint16 height2;
|
||||
AnimObject *nextAnimObject;
|
||||
};
|
||||
|
||||
Animator_LoK(KyraEngine_LoK *vm, OSystem *system);
|
||||
virtual ~Animator_LoK();
|
||||
|
||||
operator bool() const { return _initOk; }
|
||||
|
||||
void init(int actors, int items, int sprites);
|
||||
void close();
|
||||
|
||||
AnimObject *objects() { return _screenObjects; }
|
||||
AnimObject *actors() { return _actors; }
|
||||
AnimObject *items() { return _items; }
|
||||
AnimObject *sprites() { return _sprites; }
|
||||
|
||||
void initAnimStateList();
|
||||
void preserveAllBackgrounds();
|
||||
void flagAllObjectsForBkgdChange();
|
||||
void flagAllObjectsForRefresh();
|
||||
void restoreAllObjectBackgrounds();
|
||||
void preserveAnyChangedBackgrounds();
|
||||
virtual void prepDrawAllObjects();
|
||||
void copyChangedObjectsForward(int refreshFlag, bool refreshScreen = true);
|
||||
|
||||
void updateAllObjectShapes(bool refreshScreen = true);
|
||||
void animRemoveGameItem(int index);
|
||||
void animAddGameItem(int index, uint16 sceneId);
|
||||
void animAddNPC(int character);
|
||||
void animRefreshNPC(int character);
|
||||
|
||||
void clearQueue() { _objectQueue = 0; }
|
||||
void addObjectToQueue(AnimObject *object);
|
||||
void refreshObject(AnimObject *object);
|
||||
|
||||
void makeBrandonFaceMouse();
|
||||
void setBrandonAnimSeqSize(int width, int height);
|
||||
void resetBrandonAnimSeqSize();
|
||||
void setCharacterDefaultFrame(int character);
|
||||
void setCharactersHeight();
|
||||
|
||||
int16 fetchAnimWidth(const uint8 *shape, int16 mult);
|
||||
int16 fetchAnimHeight(const uint8 *shape, int16 mult);
|
||||
|
||||
int _noDrawShapesFlag;
|
||||
uint16 _brandonDrawFrame;
|
||||
int _brandonScaleX;
|
||||
int _brandonScaleY;
|
||||
|
||||
protected:
|
||||
KyraEngine_LoK *_vm;
|
||||
Screen *_screen;
|
||||
OSystem *_system;
|
||||
bool _initOk;
|
||||
|
||||
AnimObject *_screenObjects;
|
||||
|
||||
AnimObject *_actors;
|
||||
AnimObject *_items;
|
||||
AnimObject *_sprites;
|
||||
|
||||
uint8 *_actorBkgBackUp[2];
|
||||
|
||||
AnimObject *objectRemoveQueue(AnimObject *queue, AnimObject *rem);
|
||||
AnimObject *objectAddHead(AnimObject *queue, AnimObject *head);
|
||||
AnimObject *objectQueue(AnimObject *queue, AnimObject *add);
|
||||
|
||||
void preserveOrRestoreBackground(AnimObject *obj, bool restore);
|
||||
|
||||
AnimObject *_objectQueue;
|
||||
|
||||
int _brandonAnimSeqSizeWidth;
|
||||
int _brandonAnimSeqSizeHeight;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
455
engines/kyra/graphics/animator_mr.cpp
Normal file
455
engines/kyra/graphics/animator_mr.cpp
Normal file
@@ -0,0 +1,455 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/engine/kyra_mr.h"
|
||||
#include "kyra/resource/resource.h"
|
||||
#include "kyra/graphics/wsamovie.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
void KyraEngine_MR::restorePage3() {
|
||||
screen()->copyBlockToPage(2, 0, 0, 320, 200, _gamePlayBuffer);
|
||||
}
|
||||
|
||||
void KyraEngine_MR::clearAnimObjects() {
|
||||
for (int i = 0; i < 67; ++i)
|
||||
_animObjects[i].enabled = false;
|
||||
|
||||
_animObjects[0].index = 0;
|
||||
_animObjects[0].type = 0;
|
||||
_animObjects[0].enabled = true;
|
||||
_animObjects[0].specialRefresh = 1;
|
||||
_animObjects[0].flags = 0x800;
|
||||
_animObjects[0].width = 57;
|
||||
_animObjects[0].height = 91;
|
||||
_animObjects[0].width2 = 4;
|
||||
_animObjects[0].height2 = 10;
|
||||
|
||||
for (int i = 1; i < 17; ++i) {
|
||||
_animObjects[i].index = i;
|
||||
_animObjects[i].type = 2;
|
||||
_animObjects[i].flags = 0;
|
||||
_animObjects[i].enabled = false;
|
||||
_animObjects[i].needRefresh = 0;
|
||||
_animObjects[i].specialRefresh = 1;
|
||||
}
|
||||
|
||||
for (int i = 17; i <= 66; ++i) {
|
||||
_animObjects[i].index = i;
|
||||
_animObjects[i].type = 1;
|
||||
_animObjects[i].specialRefresh = 1;
|
||||
_animObjects[i].flags = 0x800;
|
||||
_animObjects[i].width = 24;
|
||||
_animObjects[i].height = 20;
|
||||
_animObjects[i].width2 = 0;
|
||||
_animObjects[i].height2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::animSetupPaletteEntry(AnimObj *anim) {
|
||||
int layer = _screen->getLayer(anim->xPos1, anim->yPos1) - 1;
|
||||
int16 count = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
count += _sceneDatPalette[layer*3+i];
|
||||
count /= 3;
|
||||
count *= -1;
|
||||
count = MAX<int16>(0, MIN<int16>(count, 10));
|
||||
anim->palette = count / 3;
|
||||
}
|
||||
|
||||
void KyraEngine_MR::drawAnimObjects() {
|
||||
for (AnimObj *curObject = _animList; curObject; curObject = curObject->nextObject) {
|
||||
if (!curObject->enabled)
|
||||
continue;
|
||||
|
||||
int x = curObject->xPos2 - (_screen->getScreenDim(2)->sx << 3);
|
||||
int y = curObject->yPos2 - _screen->getScreenDim(2)->sy;
|
||||
int layer = 7;
|
||||
|
||||
if (curObject->flags & 0x800) {
|
||||
if (!curObject->specialRefresh)
|
||||
layer = 0;
|
||||
else
|
||||
layer = getDrawLayer(curObject->xPos1, curObject->yPos1);
|
||||
}
|
||||
|
||||
if (curObject->index)
|
||||
drawSceneAnimObject(curObject, x, y, layer);
|
||||
else
|
||||
drawCharacterAnimObject(curObject, x, y, layer);
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::drawSceneAnimObject(AnimObj *obj, int x, int y, int layer) {
|
||||
if (obj->type == 1) {
|
||||
if (obj->shapeIndex1 == 0xFFFF)
|
||||
return;
|
||||
int scale = getScale(obj->xPos1, obj->yPos1);
|
||||
_screen->drawShape(2, getShapePtr(obj->shapeIndex1), x, y, 2, obj->flags | 0x104, _paletteOverlay, obj->palette, layer, scale, scale);
|
||||
} else {
|
||||
if (obj->shapePtr) {
|
||||
_screen->drawShape(2, obj->shapePtr, x, y, 2, obj->flags, 7);
|
||||
} else {
|
||||
if (obj->shapeIndex3 == 0xFFFF || obj->animNum == 0xFFFF)
|
||||
return;
|
||||
uint16 flags = 0x4000;
|
||||
if (obj->flags & 0x800)
|
||||
flags |= 0x8000;
|
||||
x = obj->xPos2 - _sceneAnimMovie[obj->animNum]->xAdd();
|
||||
y = obj->yPos2 - _sceneAnimMovie[obj->animNum]->yAdd();
|
||||
_sceneAnimMovie[obj->animNum]->displayFrame(obj->shapeIndex3, 2, x, y, flags | layer, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::drawCharacterAnimObject(AnimObj *obj, int x, int y, int layer) {
|
||||
if (_drawNoShapeFlag)
|
||||
return;
|
||||
|
||||
if (_mainCharacter.animFrame < 9)
|
||||
_mainCharacter.animFrame = 87;
|
||||
|
||||
if (obj->shapeIndex1 == 0xFFFF || _mainCharacter.animFrame == 87)
|
||||
return;
|
||||
|
||||
_screen->drawShape(2, getShapePtr(421), _mainCharacter.x3, _mainCharacter.y3, 2, obj->flags | 0x304, _paletteOverlay, 3, layer, _charScale, _charScale);
|
||||
uint8 *shape = getShapePtr(_mainCharacter.animFrame);
|
||||
if (shape)
|
||||
_screen->drawShape(2, shape, x, y, 2, obj->flags | 4, layer, _charScale, _charScale);
|
||||
}
|
||||
|
||||
void KyraEngine_MR::refreshAnimObjects(int force) {
|
||||
for (AnimObj *curObject = _animList; curObject; curObject = curObject->nextObject) {
|
||||
if (!curObject->enabled)
|
||||
continue;
|
||||
if (!curObject->needRefresh && !force)
|
||||
continue;
|
||||
|
||||
const int scale = (curObject->index == 0) ? _charScale : 0;
|
||||
|
||||
int x = curObject->xPos2 - curObject->width2;
|
||||
if (scale)
|
||||
x -= (0x100 - scale) >> 4;
|
||||
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x >= 320)
|
||||
x = 319;
|
||||
|
||||
int y = curObject->yPos2 - curObject->height2;
|
||||
if (scale)
|
||||
y -= (0x100 - scale) >> 3;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
if (y >= (_interfaceCommandLineY1 - 1))
|
||||
y = _interfaceCommandLineY1 - 2;
|
||||
|
||||
int width = curObject->width + curObject->width2 + 8;
|
||||
int height = curObject->height + curObject->height2*2;
|
||||
if (width + x > 320)
|
||||
width -= width + x - 322;
|
||||
|
||||
const int maxY = (_inventoryState ? _interfaceCommandLineY2 : _interfaceCommandLineY1) - 1;
|
||||
if (height + y > maxY)
|
||||
height -= height + y - (maxY + 1);
|
||||
|
||||
if (height > 0) {
|
||||
_screen->copyRegion(x, y, x, y, width, height, 2, 0, Screen::CR_NO_P_CHECK);
|
||||
}
|
||||
|
||||
curObject->needRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::updateItemAnimations() {
|
||||
bool nextFrame = false;
|
||||
|
||||
if (_itemAnimDefinition[0].itemIndex == -1)
|
||||
return;
|
||||
|
||||
const ItemAnimDefinition *s = &_itemAnimDefinition[_nextAnimItem];
|
||||
ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
|
||||
_nextAnimItem = (_nextAnimItem + 1) % 10;
|
||||
|
||||
if (_system->getMillis() < a->nextFrameTime)
|
||||
return;
|
||||
|
||||
uint16 shpIdx = s->frames[a->currentFrame].index + 248;
|
||||
if (s->itemIndex == _mouseState && s->itemIndex == _itemInHand && _screen->isMouseVisible()) {
|
||||
nextFrame = true;
|
||||
_screen->setMouseCursor(12, 19, getShapePtr(shpIdx));
|
||||
}
|
||||
|
||||
if (_inventoryState) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (s->itemIndex == _mainCharacter.inventory[i]) {
|
||||
nextFrame = true;
|
||||
_screen->drawShape(2, getShapePtr(422 + i), 9, 0, 0, 0);
|
||||
_screen->drawShape(2, getShapePtr(shpIdx), 9, 0, 0, 0);
|
||||
_screen->copyRegion(9, 0, _inventoryX[i], _inventoryY[i], 24, 20, 2, 0, Screen::CR_NO_P_CHECK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_screen->updateScreen();
|
||||
|
||||
for (int i = 17; i < 66; i++) {
|
||||
AnimObj *animObject = &_animObjects[i];
|
||||
if (animObject->shapeIndex2 == s->itemIndex + 248) {
|
||||
animObject->shapePtr = getShapePtr(shpIdx);
|
||||
animObject->shapeIndex1 = shpIdx;
|
||||
animObject->needRefresh = true;
|
||||
nextFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextFrame) {
|
||||
a->nextFrameTime = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
|
||||
a->currentFrame = (a->currentFrame + 1) % s->numFrames;
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::updateCharacterAnim(int charId) {
|
||||
AnimObj *obj = &_animObjects[0];
|
||||
obj->needRefresh = true;
|
||||
obj->flags &= ~1;
|
||||
obj->xPos1 = _mainCharacter.x1;
|
||||
obj->yPos1 = _mainCharacter.y1;
|
||||
obj->shapePtr = getShapePtr(_mainCharacter.animFrame);
|
||||
obj->shapeIndex1 = obj->shapeIndex2 = _mainCharacter.animFrame;
|
||||
|
||||
int shapeOffsetX = 0, shapeOffsetY = 0;
|
||||
if (_mainCharacter.animFrame >= 50 && _mainCharacter.animFrame <= 87) {
|
||||
shapeOffsetX = _malcolmShapeXOffset;
|
||||
shapeOffsetY = _malcolmShapeYOffset;
|
||||
} else {
|
||||
shapeOffsetX = _animShapeXAdd;
|
||||
shapeOffsetY = _animShapeYAdd;
|
||||
}
|
||||
|
||||
obj->xPos2 = _mainCharacter.x1;
|
||||
obj->yPos2 = _mainCharacter.y1;
|
||||
_charScale = getScale(_mainCharacter.x1, _mainCharacter.y1);
|
||||
obj->xPos2 += (shapeOffsetX * _charScale) >> 8;
|
||||
obj->yPos2 += (shapeOffsetY * _charScale) >> 8;
|
||||
_mainCharacter.x3 = _mainCharacter.x1 - (_charScale >> 4) - 1;
|
||||
_mainCharacter.y3 = _mainCharacter.y1 - (_charScale >> 6) - 1;
|
||||
if (_charBackUpWidth2 == -1) {
|
||||
obj->width2 = 4;
|
||||
obj->height2 = 10;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 16; ++i) {
|
||||
if (_animObjects[i].enabled && _animObjects[i].specialRefresh)
|
||||
_animObjects[i].needRefresh = true;
|
||||
}
|
||||
|
||||
_animList = deleteAnimListEntry(_animList, obj);
|
||||
if (_animList)
|
||||
_animList = addToAnimListSorted(_animList, obj);
|
||||
else
|
||||
_animList = initAnimList(_animList, obj);
|
||||
|
||||
if (!_loadingState)
|
||||
updateCharPal(1);
|
||||
}
|
||||
|
||||
void KyraEngine_MR::updateSceneAnim(int anim, int newFrame) {
|
||||
AnimObj *animObject = &_animObjects[1+anim];
|
||||
if (!animObject->enabled)
|
||||
return;
|
||||
|
||||
animObject->needRefresh = true;
|
||||
|
||||
if (_sceneAnims[anim].flags & 2)
|
||||
animObject->flags |= 1;
|
||||
else
|
||||
animObject->flags &= ~1;
|
||||
|
||||
if (_sceneAnims[anim].flags & 4) {
|
||||
animObject->shapePtr = _sceneShapes[newFrame];
|
||||
animObject->shapeIndex2 = 0xFFFF;
|
||||
animObject->shapeIndex3 = 0xFFFF;
|
||||
animObject->animNum = 0xFFFF;
|
||||
} else {
|
||||
animObject->shapePtr = nullptr;
|
||||
animObject->shapeIndex3 = newFrame;
|
||||
animObject->animNum = anim;
|
||||
}
|
||||
|
||||
animObject->xPos1 = _sceneAnims[anim].x;
|
||||
animObject->yPos1 = _sceneAnims[anim].y;
|
||||
animObject->xPos2 = _sceneAnims[anim].x2;
|
||||
animObject->yPos2 = _sceneAnims[anim].y2;
|
||||
|
||||
if (_sceneAnims[anim].flags & 0x20) {
|
||||
_animList = deleteAnimListEntry(_animList, animObject);
|
||||
if (!_animList)
|
||||
_animList = initAnimList(_animList, animObject);
|
||||
else
|
||||
_animList = addToAnimListSorted(_animList, animObject);
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_MR::setupSceneAnimObject(int animId, uint16 flags, int x, int y, int x2, int y2, int w,
|
||||
int h, int unk10, int specialSize, int unk14, int shape, const char *filename) {
|
||||
restorePage3();
|
||||
SceneAnim &anim = _sceneAnims[animId];
|
||||
anim.flags = flags;
|
||||
anim.x = x;
|
||||
anim.y = y;
|
||||
anim.x2 = x2;
|
||||
anim.y2 = y2;
|
||||
anim.width = w;
|
||||
anim.height = h;
|
||||
anim.specialSize = specialSize;
|
||||
anim.shapeIndex = shape;
|
||||
if (filename)
|
||||
Common::strlcpy(anim.filename, filename, sizeof(anim.filename));
|
||||
|
||||
if (flags & 8) {
|
||||
_sceneAnimMovie[animId]->open(filename, 1, nullptr);
|
||||
if (_sceneAnimMovie[animId]->opened()) {
|
||||
anim.wsaFlag = 1;
|
||||
if (x2 == -1)
|
||||
x2 = _sceneAnimMovie[animId]->xAdd();
|
||||
if (y2 == -1)
|
||||
y2 = _sceneAnimMovie[animId]->yAdd();
|
||||
if (w == -1)
|
||||
w = _sceneAnimMovie[animId]->width();
|
||||
if (h == -1)
|
||||
h = _sceneAnimMovie[animId]->height();
|
||||
if (x == -1)
|
||||
x = (w >> 1) + x2;
|
||||
if (y == -1)
|
||||
y = y2 + h - 1;
|
||||
|
||||
anim.x = x;
|
||||
anim.y = y;
|
||||
anim.x2 = x2;
|
||||
anim.y2 = y2;
|
||||
anim.width = w;
|
||||
anim.height = h;
|
||||
}
|
||||
}
|
||||
|
||||
AnimObj *obj = &_animObjects[1+animId];
|
||||
obj->enabled = true;
|
||||
obj->needRefresh = true;
|
||||
|
||||
obj->specialRefresh = (anim.flags & 0x20) ? 1 : 0;
|
||||
obj->flags = (anim.flags & 0x10) ? 0x800 : 0;
|
||||
if (anim.flags & 2)
|
||||
obj->flags |= 1;
|
||||
|
||||
obj->xPos1 = anim.x;
|
||||
obj->yPos1 = anim.y;
|
||||
|
||||
if ((anim.flags & 4) && anim.shapeIndex != -1)
|
||||
obj->shapePtr = _sceneShapes[anim.shapeIndex];
|
||||
else
|
||||
obj->shapePtr = nullptr;
|
||||
|
||||
if (anim.flags & 8) {
|
||||
obj->shapeIndex3 = anim.shapeIndex;
|
||||
obj->animNum = animId;
|
||||
} else {
|
||||
obj->shapeIndex3 = 0xFFFF;
|
||||
obj->animNum = 0xFFFF;
|
||||
}
|
||||
|
||||
obj->xPos3 = obj->xPos2 = anim.x2;
|
||||
obj->yPos3 = obj->yPos2 = anim.y2;
|
||||
obj->width = anim.width;
|
||||
obj->height = anim.height;
|
||||
obj->width2 = obj->height2 = anim.specialSize;
|
||||
|
||||
if (_animList)
|
||||
_animList = addToAnimListSorted(_animList, obj);
|
||||
else
|
||||
_animList = initAnimList(_animList, obj);
|
||||
}
|
||||
|
||||
void KyraEngine_MR::removeSceneAnimObject(int anim, int refresh) {
|
||||
AnimObj *obj = &_animObjects[anim+1];
|
||||
restorePage3();
|
||||
obj->shapeIndex3 = 0xFFFF;
|
||||
obj->animNum = 0xFFFF;
|
||||
obj->needRefresh = true;
|
||||
|
||||
if (refresh)
|
||||
refreshAnimObjectsIfNeed();
|
||||
|
||||
obj->enabled = false;
|
||||
_animList = deleteAnimListEntry(_animList, obj);
|
||||
_sceneAnimMovie[anim]->close();
|
||||
}
|
||||
|
||||
void KyraEngine_MR::setCharacterAnimDim(int w, int h) {
|
||||
restorePage3();
|
||||
_charBackUpWidth = _animObjects[0].width;
|
||||
_charBackUpWidth2 = _animObjects[0].width2;
|
||||
_charBackUpHeight = _animObjects[0].height;
|
||||
_charBackUpHeight2 = _animObjects[0].height2;
|
||||
|
||||
_animObjects[0].width2 = (w - _charBackUpWidth) / 2;
|
||||
_animObjects[0].height2 = h - _charBackUpHeight;
|
||||
_animObjects[0].width = w;
|
||||
_animObjects[0].height = h;
|
||||
}
|
||||
|
||||
void KyraEngine_MR::resetCharacterAnimDim() {
|
||||
restorePage3();
|
||||
_animObjects[0].width2 = _charBackUpWidth2;
|
||||
_animObjects[0].height2 = _charBackUpHeight2;
|
||||
_animObjects[0].width = _charBackUpWidth;
|
||||
_animObjects[0].height = _charBackUpHeight;
|
||||
_charBackUpWidth2 = _charBackUpHeight2 = -1;
|
||||
_charBackUpWidth = _charBackUpHeight = -1;
|
||||
}
|
||||
|
||||
void KyraEngine_MR::showIdleAnim() {
|
||||
if (_mainCharacter.sceneId == 20 || _mainCharacter.sceneId == 21
|
||||
|| _mainCharacter.sceneId == 12 || _mainCharacter.sceneId == 11)
|
||||
return;
|
||||
|
||||
if (_mainCharacter.animFrame == 87)
|
||||
return;
|
||||
|
||||
if (!_nextIdleType && !talkObjectsInCurScene()) {
|
||||
randomSceneChat();
|
||||
} else {
|
||||
static const char *const facingTable[] = {
|
||||
"A", "R", "R", "FR", "FX", "FL", "L", "L"
|
||||
};
|
||||
|
||||
Common::String filename = Common::String::format( "MI0%s%.02d.EMC", facingTable[_mainCharacter.facing], _characterShapeFile);
|
||||
|
||||
if (_res->exists(filename.c_str()))
|
||||
runAnimationScript(filename.c_str(), 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
_nextIdleType = !_nextIdleType;
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
233
engines/kyra/graphics/animator_tim.cpp
Normal file
233
engines/kyra/graphics/animator_tim.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/script/script_tim.h"
|
||||
#include "kyra/graphics/wsamovie.h"
|
||||
#include "kyra/graphics/screen_lol.h"
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
#include "kyra/engine/lol.h"
|
||||
#else
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
#endif
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
TimAnimator::TimAnimator(LoLEngine *engine, Screen_v2 *screen_v2, OSystem *system, bool useParts) : _vm(engine), _screen(screen_v2), _system(system), _useParts(useParts) {
|
||||
#else
|
||||
TimAnimator::TimAnimator(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSystem *system, bool useParts) : _vm(engine), _screen(screen_v2), _system(system), _useParts(useParts) {
|
||||
#endif
|
||||
_animations = new Animation[TIM::kWSASlots]();
|
||||
assert(_animations);
|
||||
|
||||
if (_useParts) {
|
||||
for (int i = 0; i < TIM::kWSASlots; i++) {
|
||||
_animations[i].parts = new AnimPart[TIM::kAnimParts]();
|
||||
assert(_animations[i].parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimAnimator::~TimAnimator() {
|
||||
for (int i = 0; i < TIM::kWSASlots; i++) {
|
||||
delete _animations[i].wsa;
|
||||
if (_useParts)
|
||||
delete[] _animations[i].parts;
|
||||
}
|
||||
|
||||
delete[] _animations;
|
||||
}
|
||||
|
||||
void TimAnimator::init(int animIndex, Movie *wsa, int x, int y, int wsaCopyParams, int frameDelay) {
|
||||
Animation *anim = &_animations[animIndex];
|
||||
anim->wsa = wsa;
|
||||
anim->x = x;
|
||||
anim->y = y;
|
||||
anim->wsaCopyParams = wsaCopyParams;
|
||||
anim->frameDelay = frameDelay;
|
||||
anim->enable = 0;
|
||||
anim->lastPart = -1;
|
||||
}
|
||||
|
||||
void TimAnimator::reset(int animIndex, bool clearStruct) {
|
||||
Animation *anim = &_animations[animIndex];
|
||||
anim->field_D = 0;
|
||||
anim->enable = 0;
|
||||
delete anim->wsa;
|
||||
anim->wsa = nullptr;
|
||||
|
||||
if (clearStruct) {
|
||||
if (_useParts)
|
||||
delete[] anim->parts;
|
||||
|
||||
memset(anim, 0, sizeof(Animation));
|
||||
|
||||
if (_useParts) {
|
||||
anim->parts = new AnimPart[TIM::kAnimParts];
|
||||
memset(anim->parts, 0, TIM::kAnimParts * sizeof(AnimPart));
|
||||
assert(anim->parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimAnimator::displayFrame(int animIndex, int page, int frame, int flags) {
|
||||
Animation *anim = &_animations[animIndex];
|
||||
if ((anim->wsaCopyParams & 0x4000) != 0)
|
||||
page = 2;
|
||||
// WORKAROUND for some bugged scripts that will try to display frames of non-existent animations
|
||||
if (anim->wsa)
|
||||
anim->wsa->displayFrame(frame, page, anim->x, anim->y, (flags == -1) ? (anim->wsaCopyParams & 0xF0FF) : flags, nullptr, nullptr);
|
||||
if (!page)
|
||||
_screen->updateScreen();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
void TimAnimator::setupPart(int animIndex, int part, int firstFrame, int lastFrame, int cycles, int nextPart, int partDelay, int f, int sfxIndex, int sfxFrame) {
|
||||
AnimPart *a = &_animations[animIndex].parts[part];
|
||||
a->firstFrame = firstFrame;
|
||||
a->lastFrame = lastFrame;
|
||||
a->cycles = cycles;
|
||||
a->nextPart = nextPart;
|
||||
a->partDelay = partDelay;
|
||||
a->field_A = f;
|
||||
a->sfxIndex = sfxIndex;
|
||||
a->sfxFrame = sfxFrame;
|
||||
}
|
||||
|
||||
void TimAnimator::start(int animIndex, int part) {
|
||||
if (!_vm || !_system || !_screen)
|
||||
return;
|
||||
|
||||
Animation *anim = &_animations[animIndex];
|
||||
anim->curPart = part;
|
||||
AnimPart *p = &anim->parts[part];
|
||||
anim->enable = 1;
|
||||
anim->nextFrame = _system->getMillis() + anim->frameDelay * _vm->_tickLength;
|
||||
anim->curFrame = p->firstFrame;
|
||||
anim->cyclesCompleted = 0;
|
||||
|
||||
// WORKAROUND for some bugged scripts that will try to display frames of non-existent animations
|
||||
if (anim->wsa)
|
||||
anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0, 0, 0);
|
||||
}
|
||||
|
||||
void TimAnimator::stop(int animIndex) {
|
||||
Animation *anim = &_animations[animIndex];
|
||||
anim->enable = 0;
|
||||
anim->field_D = 0;
|
||||
if (animIndex == 5) {
|
||||
delete anim->wsa;
|
||||
anim->wsa = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TimAnimator::update(int animIndex) {
|
||||
if (!_vm || !_system || !_screen)
|
||||
return;
|
||||
|
||||
Animation *anim = &_animations[animIndex];
|
||||
if (!anim->enable || anim->nextFrame >= _system->getMillis())
|
||||
return;
|
||||
|
||||
AnimPart *p = &anim->parts[anim->curPart];
|
||||
anim->nextFrame = 0;
|
||||
|
||||
int step = 0;
|
||||
if (p->lastFrame >= p->firstFrame) {
|
||||
step = 1;
|
||||
anim->curFrame++;
|
||||
} else {
|
||||
step = -1;
|
||||
anim->curFrame--;
|
||||
}
|
||||
|
||||
if (anim->curFrame == (p->lastFrame + step)) {
|
||||
anim->cyclesCompleted++;
|
||||
|
||||
if ((anim->cyclesCompleted > p->cycles) || anim->field_D) {
|
||||
anim->lastPart = anim->curPart;
|
||||
|
||||
if ((p->nextPart == -1) || (anim->field_D && p->field_A)) {
|
||||
anim->enable = 0;
|
||||
anim->field_D = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
anim->nextFrame += (p->partDelay * _vm->_tickLength);
|
||||
anim->curPart = p->nextPart;
|
||||
|
||||
p = &anim->parts[anim->curPart];
|
||||
anim->curFrame = p->firstFrame;
|
||||
anim->cyclesCompleted = 0;
|
||||
|
||||
} else {
|
||||
anim->curFrame = p->firstFrame;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->sfxIndex != -1 && p->sfxFrame == anim->curFrame)
|
||||
_vm->snd_playSoundEffect(p->sfxIndex, -1);
|
||||
|
||||
anim->nextFrame += (anim->frameDelay * _vm->_tickLength);
|
||||
|
||||
anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0, 0, 0);
|
||||
anim->nextFrame += _system->getMillis();
|
||||
}
|
||||
|
||||
void TimAnimator::playPart(int animIndex, int firstFrame, int lastFrame, int delay) {
|
||||
if (!_vm || !_system || !_screen)
|
||||
return;
|
||||
|
||||
Animation *anim = &_animations[animIndex];
|
||||
// WORKAROUND for some bugged scripts that will try to play invalid animations
|
||||
if (!anim->wsa)
|
||||
return;
|
||||
|
||||
int step = (lastFrame >= firstFrame) ? 1 : -1;
|
||||
for (int i = firstFrame; i != (lastFrame + step); i += step) {
|
||||
uint32 next = _system->getMillis() + delay * _vm->_tickLength;
|
||||
if (anim->wsaCopyParams & 0x4000) {
|
||||
_screen->copyRegion(112, 0, 112, 0, 176, 120, 6, 2);
|
||||
anim->wsa->displayFrame(i - 1, 2, anim->x, anim->y, anim->wsaCopyParams & 0x1000 ? 0x5000 : 0x4000, _vm->_transparencyTable1, _vm->_transparencyTable2);
|
||||
_screen->copyRegion(112, 0, 112, 0, 176, 120, 2, 0);
|
||||
_screen->updateScreen();
|
||||
} else {
|
||||
anim->wsa->displayFrame(i - 1, 0, anim->x, anim->y, 0, 0, 0);
|
||||
_screen->updateScreen();
|
||||
}
|
||||
int32 del = (int32)(next - _system->getMillis());
|
||||
if (del > 0)
|
||||
_vm->delay(del, true);
|
||||
}
|
||||
}
|
||||
|
||||
int TimAnimator::resetLastPart(int animIndex) {
|
||||
Animation *anim = &_animations[animIndex];
|
||||
int8 res = -1;
|
||||
SWAP(res, anim->lastPart);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace Kyra
|
||||
184
engines/kyra/graphics/animator_v2.cpp
Normal file
184
engines/kyra/graphics/animator_v2.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/engine/kyra_v2.h"
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
void KyraEngine_v2::allocAnimObjects(int actors, int anims, int items) {
|
||||
_animObjects = new AnimObj[actors + anims + items]();
|
||||
assert(_animObjects);
|
||||
|
||||
_animActor = _animObjects;
|
||||
_animAnims = _animObjects + actors;
|
||||
_animItems = _animObjects + actors + anims;
|
||||
}
|
||||
|
||||
KyraEngine_v2::AnimObj *KyraEngine_v2::initAnimList(AnimObj *list, AnimObj *entry) {
|
||||
entry->nextObject = list;
|
||||
return entry;
|
||||
}
|
||||
|
||||
KyraEngine_v2::AnimObj *KyraEngine_v2::addToAnimListSorted(AnimObj *list, AnimObj *add) {
|
||||
add->nextObject = nullptr;
|
||||
|
||||
if (!list)
|
||||
return add;
|
||||
|
||||
if (add->yPos1 <= list->yPos1) {
|
||||
add->nextObject = list;
|
||||
return add;
|
||||
}
|
||||
|
||||
AnimObj *cur = list;
|
||||
AnimObj *prev = list;
|
||||
while (add->yPos1 > cur->yPos1) {
|
||||
AnimObj *temp = cur->nextObject;
|
||||
if (!temp)
|
||||
break;
|
||||
prev = cur;
|
||||
cur = temp;
|
||||
}
|
||||
|
||||
if (add->yPos1 <= cur->yPos1) {
|
||||
prev->nextObject = add;
|
||||
add->nextObject = cur;
|
||||
} else {
|
||||
cur->nextObject = add;
|
||||
add->nextObject = nullptr;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
KyraEngine_v2::AnimObj *KyraEngine_v2::deleteAnimListEntry(AnimObj *list, AnimObj *entry) {
|
||||
if (!list)
|
||||
return nullptr;
|
||||
|
||||
AnimObj *old = nullptr;
|
||||
AnimObj *cur = list;
|
||||
|
||||
while (true) {
|
||||
if (cur == entry)
|
||||
break;
|
||||
if (!cur->nextObject)
|
||||
break;
|
||||
old = cur;
|
||||
cur = cur->nextObject;
|
||||
}
|
||||
|
||||
if (cur != entry)
|
||||
return list;
|
||||
|
||||
if (cur == list) {
|
||||
if (!cur->nextObject)
|
||||
return nullptr;
|
||||
cur = cur->nextObject;
|
||||
return cur;
|
||||
}
|
||||
|
||||
if (!cur->nextObject) {
|
||||
if (!old)
|
||||
return nullptr;
|
||||
old->nextObject = nullptr;
|
||||
return list;
|
||||
}
|
||||
|
||||
if (cur != entry)
|
||||
return list;
|
||||
|
||||
old->nextObject = entry->nextObject;
|
||||
return list;
|
||||
}
|
||||
|
||||
void KyraEngine_v2::refreshAnimObjectsIfNeed() {
|
||||
for (AnimObj *curEntry = _animList; curEntry; curEntry = curEntry->nextObject) {
|
||||
if (curEntry->enabled && curEntry->needRefresh) {
|
||||
restorePage3();
|
||||
drawAnimObjects();
|
||||
refreshAnimObjects(0);
|
||||
screen()->updateScreen();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KyraEngine_v2::flagAnimObjsForRefresh() {
|
||||
for (AnimObj *curEntry = _animList; curEntry; curEntry = curEntry->nextObject)
|
||||
curEntry->needRefresh = 1;
|
||||
}
|
||||
|
||||
void KyraEngine_v2::flagAnimObjsSpecialRefresh() {
|
||||
for (AnimObj *curEntry = _animList; curEntry; curEntry = curEntry->nextObject)
|
||||
curEntry->specialRefresh = 1;
|
||||
}
|
||||
|
||||
void KyraEngine_v2::addItemToAnimList(int item) {
|
||||
assert(item >= 0 && item < _itemListSize);
|
||||
|
||||
restorePage3();
|
||||
|
||||
AnimObj *animObj = _animItems + item;
|
||||
|
||||
animObj->enabled = 1;
|
||||
animObj->needRefresh = 1;
|
||||
|
||||
int itemId = _itemList[item].id;
|
||||
|
||||
animObj->xPos2 = animObj->xPos1 = _itemList[item].x;
|
||||
animObj->yPos2 = animObj->yPos1 = _itemList[item].y;
|
||||
|
||||
animObj->shapePtr = getShapePtr(itemId + _desc.itemShapeStart);
|
||||
animSetupPaletteEntry(animObj);
|
||||
animObj->shapeIndex2 = animObj->shapeIndex1 = itemId + _desc.itemShapeStart;
|
||||
|
||||
int scaleY, scaleX;
|
||||
scaleY = scaleX = getScale(animObj->xPos1, animObj->yPos1);
|
||||
|
||||
uint8 *shapePtr = getShapePtr(itemId + _desc.itemShapeStart);
|
||||
animObj->xPos3 = (animObj->xPos2 -= (screen_v2()->getShapeScaledWidth(shapePtr, scaleX) >> 1));
|
||||
animObj->yPos3 = (animObj->yPos2 -= screen_v2()->getShapeScaledHeight(shapePtr, scaleY));
|
||||
|
||||
animObj->width2 = animObj->height2 = 0;
|
||||
|
||||
_animList = addToAnimListSorted(_animList, animObj);
|
||||
animObj->needRefresh = 1;
|
||||
}
|
||||
|
||||
void KyraEngine_v2::deleteItemAnimEntry(int item) {
|
||||
assert(item < _itemListSize);
|
||||
|
||||
AnimObj *animObj = _animItems + item;
|
||||
|
||||
restorePage3();
|
||||
|
||||
animObj->shapePtr = nullptr;
|
||||
animObj->shapeIndex1 = 0xFFFF;
|
||||
animObj->shapeIndex2 = 0xFFFF;
|
||||
animObj->needRefresh = 1;
|
||||
|
||||
refreshAnimObjectsIfNeed();
|
||||
|
||||
animObj->enabled = 0;
|
||||
_animList = deleteAnimListEntry(_animList, animObj);
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
4215
engines/kyra/graphics/screen.cpp
Normal file
4215
engines/kyra/graphics/screen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
967
engines/kyra/graphics/screen.h
Normal file
967
engines/kyra/graphics/screen.h
Normal file
@@ -0,0 +1,967 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_H
|
||||
#define KYRA_SCREEN_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/func.h"
|
||||
#include "common/list.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/rendermode.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Graphics {
|
||||
class FontSJIS;
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
typedef Common::Functor0<void> UpdateFunctor;
|
||||
|
||||
class KyraEngine_v1;
|
||||
class Screen;
|
||||
|
||||
struct ScreenDim {
|
||||
uint16 sx;
|
||||
uint16 sy;
|
||||
uint16 w;
|
||||
uint16 h;
|
||||
uint16 col1;
|
||||
uint16 col2;
|
||||
uint16 line;
|
||||
uint16 column;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that handles KYRA fonts.
|
||||
*/
|
||||
class Font {
|
||||
public:
|
||||
/* Font types
|
||||
* Currently, we actually only care about oneByte and twoByte, but
|
||||
* naming it like this makes it easier to extend if the need arises.
|
||||
*/
|
||||
enum Type {
|
||||
kASCII = 0,
|
||||
kJIS_X0201,
|
||||
kSJIS,
|
||||
kBIG5,
|
||||
kJohab
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~Font() {}
|
||||
|
||||
/**
|
||||
* Tries to load a file from the given stream
|
||||
*/
|
||||
virtual bool load(Common::SeekableReadStream &file) = 0;
|
||||
|
||||
/**
|
||||
* Whether the font draws on the overlay.
|
||||
*/
|
||||
virtual bool usesOverlay() const { return false; }
|
||||
|
||||
/**
|
||||
* Whether the font is Ascii or Sjis.
|
||||
*/
|
||||
virtual Type getType() const = 0;
|
||||
|
||||
/**
|
||||
* The font height.
|
||||
*/
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
/**
|
||||
* The font width, this is the maximal character
|
||||
* width.
|
||||
*/
|
||||
virtual int getWidth() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the width of a specific character.
|
||||
*/
|
||||
virtual int getCharWidth(uint16 c) const = 0;
|
||||
|
||||
/**
|
||||
* Gets the height of a specific character. The only font that needs this
|
||||
* is the SegaCD one. For all other fonts this is a fixed value.
|
||||
*/
|
||||
virtual int getCharHeight(uint16 c) const { return getHeight(); }
|
||||
|
||||
/**
|
||||
* Sets a text palette map. The map contains 16 entries.
|
||||
*/
|
||||
virtual void setColorMap(const uint8 *src) = 0;
|
||||
|
||||
/**
|
||||
* Sets a text 16bit palette map. Only used in in EOB II FM-Towns. The map contains 2 entries.
|
||||
*/
|
||||
virtual void set16bitColorMap(const uint16 *src) {}
|
||||
|
||||
enum FontStyle {
|
||||
kStyleNone = 0,
|
||||
kStyleLeftShadow = 1 << 0,
|
||||
kStyleBorder = 1 << 1,
|
||||
kStyleFat = 1 << 2,
|
||||
kStyleNarrow1 = 1 << 3,
|
||||
kStyleNarrow2 = 1 << 4,
|
||||
kStyleFullWidth = 1 << 5,
|
||||
kStyleForceOneByte = 1 << 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a drawing style. Only rudimentary implementation based on what is needed.
|
||||
*/
|
||||
virtual void setStyles(int styles) {}
|
||||
|
||||
/**
|
||||
* Draws a specific character.
|
||||
*
|
||||
* TODO/FIXME: Replace this with a nicer API. Currently
|
||||
* the user has to assure that the character fits.
|
||||
* We use this API, since it's hard to assure dirty rect
|
||||
* handling from outside Screen.
|
||||
*/
|
||||
virtual void drawChar(uint16 c, byte *dst, int pitch, int bpp) const = 0;
|
||||
|
||||
virtual void drawChar(uint16 c, byte *dst, int pitch, int xOffs, int yOffs) const {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the Font interface for DOS fonts.
|
||||
*
|
||||
* TODO: Clean up the implementation. For example we might be able
|
||||
* to not to keep the whole font in memory.
|
||||
*/
|
||||
class DOSFont : public Font {
|
||||
public:
|
||||
DOSFont();
|
||||
~DOSFont() override { unload(); }
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
Type getType() const override { return kASCII; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override { _colorMap = src; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
void unload();
|
||||
|
||||
const uint8 *_colorMap;
|
||||
|
||||
uint8 *_data;
|
||||
|
||||
int _width, _height;
|
||||
|
||||
int _numGlyphs;
|
||||
|
||||
uint8 *_widthTable;
|
||||
uint8 *_heightTable;
|
||||
uint16 *_bitmapOffsets;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the Font interface for Kyra 1 style (non-native AmigaDOS) AMIGA fonts.
|
||||
*/
|
||||
class AMIGAFont : public Font {
|
||||
public:
|
||||
AMIGAFont();
|
||||
~AMIGAFont() override { unload(); }
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
Type getType() const override { return kASCII; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override {}
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
void unload();
|
||||
|
||||
int _width, _height;
|
||||
|
||||
struct Character {
|
||||
uint8 yOffset, xOffset, width;
|
||||
|
||||
struct Graphics {
|
||||
uint16 width, height;
|
||||
uint8 *bitmap;
|
||||
} graphics;
|
||||
};
|
||||
|
||||
Character _chars[255];
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the Font interface for FM-Towns/PC98 fonts
|
||||
*/
|
||||
class SJISFont : public Font {
|
||||
public:
|
||||
SJISFont(Common::SharedPtr<Graphics::FontSJIS> &font, const uint8 invisColor, bool is16Color, bool drawOutline, int extraSpacing);
|
||||
~SJISFont() override {}
|
||||
|
||||
bool usesOverlay() const override { return true; }
|
||||
Type getType() const override { return kSJIS; }
|
||||
|
||||
bool load(Common::SeekableReadStream &) override { return true; }
|
||||
int getHeight() const override;
|
||||
int getWidth() const override;
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override;
|
||||
void setStyles(int style) override { _style = style; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
protected:
|
||||
const uint8 *_colorMap;
|
||||
Common::SharedPtr<Graphics::FontSJIS> _font;
|
||||
const bool _drawOutline;
|
||||
int _style;
|
||||
|
||||
private:
|
||||
const uint8 _invisColor;
|
||||
const bool _isTextMode;
|
||||
// We use this for cases where the font width returned by getWidth() or getCharWidth() does not match the original.
|
||||
// The original Japanese game versions use hard coded sjis font widths of 8 or 9. However, this does not necessarily
|
||||
// depend on whether an outline is used or not (neither LOL/PC-9801 nor LOL/FM-TOWNS use an outline, but the first
|
||||
// version uses a font width of 8 where the latter uses a font width of 9).
|
||||
const int _sjisWidthOffset;
|
||||
};
|
||||
|
||||
class ChineseFont : public Font {
|
||||
public:
|
||||
ChineseFont(int pitch, int renderWidth, int renderHeight, int spacingWidth, int spacingHeight, int extraSpacingWidth, int extraSpacingHeight);
|
||||
~ChineseFont() override;
|
||||
|
||||
virtual Type getType() const override { return kBIG5; }
|
||||
|
||||
bool load(Common::SeekableReadStream &data) override;
|
||||
|
||||
void setStyles(int styles) override { _border = (styles & kStyleBorder); }
|
||||
int getHeight() const override { return _spacingHeight + (_border ? _borderExtraSpacingHeight : 0); }
|
||||
int getWidth() const override { return _spacingWidth + (_border ? _borderExtraSpacingWidth : 0); }
|
||||
int getCharWidth(uint16 c) const override { return hasGlyphForCharacter(c) ? getWidth() : -1; }
|
||||
int getCharHeight(uint16 c) const override { return hasGlyphForCharacter(c) ? _renderHeight + (_border ? _borderExtraSpacingHeight : 0) : -1; }
|
||||
void setColorMap(const uint8 *src) override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
protected:
|
||||
uint32 getGlyphDataSize() const { return _glyphDataSize; }
|
||||
uint16 _textColor[2];
|
||||
bool _pixelColorShading;
|
||||
const uint8 *_colorMap;
|
||||
bool _border;
|
||||
|
||||
private:
|
||||
virtual bool hasGlyphForCharacter(uint16 c) const = 0;
|
||||
virtual uint32 getFontOffset(uint16 c) const = 0;
|
||||
virtual void processColorMap() = 0;
|
||||
|
||||
const int _spacingWidth, _spacingHeight;
|
||||
const int _borderExtraSpacingWidth, _borderExtraSpacingHeight;
|
||||
const int _renderWidth, _renderHeight;
|
||||
|
||||
const uint8 *_glyphData;
|
||||
uint32 _glyphDataSize;
|
||||
const uint16 _pitch;
|
||||
};
|
||||
|
||||
class JohabFontLoK final : public Font {
|
||||
public:
|
||||
JohabFontLoK(Font *&font8fat, const uint16 *lookupTable, uint32 lookupTableSize);
|
||||
~JohabFontLoK() override;
|
||||
|
||||
enum {
|
||||
kNumJongseong = 191,
|
||||
kNumJungseong = 85,
|
||||
kNumChoseong = 109
|
||||
};
|
||||
|
||||
bool load(Common::SeekableReadStream &data) override;
|
||||
Type getType() const override { return kJohab; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
int getCharHeight(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
const uint8 *createGlyph(uint16 chr) const;
|
||||
void processColorMap();
|
||||
void renderGlyph(byte *dst, const uint8 *glyph, uint8 col, int pitch) const;
|
||||
|
||||
int _width, _height;
|
||||
const uint8 *_colorMap;
|
||||
|
||||
Font *&_font8fat;
|
||||
const uint8 *_fileData;
|
||||
const uint8 *_glyphData[3];
|
||||
const uint16 *_2byteTables[7];
|
||||
uint8 *_glyphTemp;
|
||||
};
|
||||
|
||||
class ChineseOneByteFontLoK final : public ChineseFont {
|
||||
public:
|
||||
ChineseOneByteFontLoK(int pitch);
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return !(c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override { return (c & 0x7F) * 14; }
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
class ChineseTwoByteFontLoK final : public ChineseFont {
|
||||
public:
|
||||
ChineseTwoByteFontLoK(int pitch, const uint16 *lookupTable, uint32 lookupTableSize);
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override;
|
||||
uint32 getFontOffset(uint16 c) const override;
|
||||
void processColorMap() override;
|
||||
|
||||
const uint16 *_lookupTable;
|
||||
uint32 _lookupTableSize;
|
||||
};
|
||||
|
||||
class ChineseOneByteFontMR final : public ChineseFont {
|
||||
public:
|
||||
ChineseOneByteFontMR(int pitch) : ChineseFont(pitch, 7, 14, 9, 14, 0, 2) {}
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return (c == 0x6187) || !(c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override { return ((c == 0x6187) ? 128 : (c & 0x7F)) * 14; }
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
class ChineseTwoByteFontMR final : public ChineseFont {
|
||||
public:
|
||||
ChineseTwoByteFontMR(int pitch) : ChineseFont(pitch, 15, 14, 18, 14, 0, 2) {}
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return (c != 0x6187) && (c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override;
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
|
||||
class ChineseOneByteFontLoL final : public ChineseFont {
|
||||
public:
|
||||
ChineseOneByteFontLoL(int pitch) : ChineseFont(pitch, 8, 14, 8, 16, 0, 0) { _pixelColorShading = false; }
|
||||
void setStyles(int styles) override {}
|
||||
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return !(c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override { return (c & 0x7F) * 14; }
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
class ChineseTwoByteFontLoL final : public ChineseFont {
|
||||
public:
|
||||
ChineseTwoByteFontLoL(int pitch) : ChineseFont(pitch, 16, 14, 16, 16, 0, 0) { _pixelColorShading = false; }
|
||||
void setStyles(int styles) override {}
|
||||
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return (c & 0x80) && getFontOffset(c) < getGlyphDataSize(); }
|
||||
uint32 getFontOffset(uint16 c) const override;
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class ChineseOneByteFontHOF final : public ChineseFont {
|
||||
public:
|
||||
ChineseOneByteFontHOF(int pitch) : ChineseFont(pitch, 8, 14, 9, 15, 0, 0) {}
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return !(c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override { return (c & 0x7F) * 14; }
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
class ChineseTwoByteFontHOF final : public ChineseFont {
|
||||
public:
|
||||
ChineseTwoByteFontHOF(int pitch) : ChineseFont(pitch, 16, 14, 18, 15, 0, 0) {}
|
||||
private:
|
||||
bool hasGlyphForCharacter(uint16 c) const override { return (c & 0x80); }
|
||||
uint32 getFontOffset(uint16 c) const override;
|
||||
void processColorMap() override;
|
||||
};
|
||||
|
||||
class MultiSubsetFont final : public Font {
|
||||
public:
|
||||
MultiSubsetFont(Common::Array<Font*> *subsets) : Font(), _subsets(subsets) {}
|
||||
~MultiSubsetFont() override;
|
||||
Type getType() const override { return kBIG5; }
|
||||
|
||||
// Caveat: This method will try to load a font into the first subset slot it finds.
|
||||
// It expects the load method of the subset font to return false if the slot has
|
||||
// already been filled. It will then try the next slot. So, unlike other fonts the
|
||||
// subset fonts cannot be allowed to call the load method as often as they want
|
||||
// (which we never did anyway - we only ever load each font exactly one time).
|
||||
// But this also means that different
|
||||
bool load(Common::SeekableReadStream &data) override;
|
||||
|
||||
void setStyles(int styles) override;
|
||||
int getHeight() const override;
|
||||
int getWidth() const override;
|
||||
int getCharWidth(uint16 c) const override;
|
||||
int getCharHeight(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
Common::Array<Font*> *_subsets;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages KYRA palettes.
|
||||
*
|
||||
* This class stores the palette data as VGA RGB internally.
|
||||
*/
|
||||
class Palette {
|
||||
public:
|
||||
Palette(const int numColors);
|
||||
~Palette();
|
||||
|
||||
enum {
|
||||
kVGABytesPerColor = 3,
|
||||
kPC98BytesPerColor = 3,
|
||||
kAmigaBytesPerColor = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a VGA palette from the given stream.
|
||||
*/
|
||||
void loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors);
|
||||
|
||||
/**
|
||||
* Load a HiColor palette from the given stream.
|
||||
*/
|
||||
void loadHiColorPalette(Common::ReadStream &stream, int startIndex, int colors);
|
||||
|
||||
/**
|
||||
* Load a EGA palette from the given stream.
|
||||
*/
|
||||
void loadEGAPalette(Common::ReadStream &stream, int startIndex, int colors);
|
||||
|
||||
/**
|
||||
* Set default CGA palette. We only need the cyan/magenta/grey mode.
|
||||
*/
|
||||
enum CGAIntensity {
|
||||
kIntensityLow = 0,
|
||||
kIntensityHigh = 1
|
||||
};
|
||||
|
||||
void setCGAPalette(int palIndex, CGAIntensity intensity);
|
||||
|
||||
/**
|
||||
* Load a AMIGA palette from the given stream.
|
||||
*/
|
||||
void loadAmigaPalette(Common::ReadStream &stream, int startIndex, int colors);
|
||||
|
||||
/**
|
||||
* Load a PC98 16 color palette from the given stream.
|
||||
*/
|
||||
void loadPC98Palette(Common::ReadStream &stream, int startIndex, int colors);
|
||||
|
||||
/**
|
||||
* Return the number of colors this palette manages.
|
||||
*/
|
||||
int getNumColors() const { return _numColors; }
|
||||
|
||||
/**
|
||||
* Set all palette colors to black.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Fill the given indexes with the given component value.
|
||||
*
|
||||
* @param firstCol the first color, which should be overwritten.
|
||||
* @param numCols number of colors, which schould be overwritten.
|
||||
* @param value color component value, which should be stored.
|
||||
*/
|
||||
void fill(int firstCol, int numCols, uint8 value);
|
||||
|
||||
/**
|
||||
* Copy data from another palette.
|
||||
*
|
||||
* @param source palette to copy data from.
|
||||
* @param firstCol the first color of the source which should be copied.
|
||||
* @param numCols number of colors, which should be copied. -1 all remaining colors.
|
||||
* @param dstStart the first color, which should be ovewritten. If -1 firstCol will be used as start.
|
||||
*/
|
||||
void copy(const Palette &source, int firstCol = 0, int numCols = -1, int dstStart = -1);
|
||||
|
||||
/**
|
||||
* Copy data from a raw VGA palette.
|
||||
*
|
||||
* @param source source buffer
|
||||
* @param firstCol the first color of the source which should be copied.
|
||||
* @param numCols number of colors, which should be copied.
|
||||
* @param dstStart the first color, which should be ovewritten. If -1 firstCol will be used as start.
|
||||
*/
|
||||
void copy(const uint8 *source, int firstCol, int numCols, int dstStart = -1);
|
||||
|
||||
/**
|
||||
* Fetch a RGB palette.
|
||||
*
|
||||
* @return a pointer to the RGB palette data, the client must delete[] it.
|
||||
*/
|
||||
uint8 *fetchRealPalette() const;
|
||||
|
||||
//XXX
|
||||
uint8 &operator[](const int index) {
|
||||
assert(index >= 0 && index <= _numColors * 3);
|
||||
return _palData[index];
|
||||
}
|
||||
|
||||
const uint8 &operator[](const int index) const {
|
||||
assert(index >= 0 && index <= _numColors * 3);
|
||||
return _palData[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets raw access to the palette.
|
||||
*
|
||||
* TODO: Get rid of this.
|
||||
*/
|
||||
uint8 *getData() { return _palData; }
|
||||
const uint8 *getData() const { return _palData; }
|
||||
|
||||
private:
|
||||
uint8 *_palData;
|
||||
const int _numColors;
|
||||
|
||||
static const uint8 _egaColors[];
|
||||
static const int _egaNumColors;
|
||||
static const uint8 _cgaColors[4][12];
|
||||
static const int _cgaNumColors;
|
||||
};
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
enum {
|
||||
SCREEN_W = 320,
|
||||
SCREEN_H = 200,
|
||||
SCREEN_H_SEGA_NTSC = 224,
|
||||
SCREEN_PAGE_SIZE = 320 * 200 + 1024,
|
||||
SCREEN_OVL_SJIS_SIZE = 640 * 400,
|
||||
SCREEN_PAGE_NUM = 16,
|
||||
SCREEN_OVLS_NUM = 6,
|
||||
|
||||
SCREEN_IDLEREFRESH_RESTART_MSEC = 250,
|
||||
SCREEN_IDLEREFRESH_RATE_MSEC = 16
|
||||
};
|
||||
|
||||
enum CopyRegionFlags {
|
||||
CR_NO_P_CHECK = 0x01
|
||||
};
|
||||
|
||||
enum DrawShapeFlags {
|
||||
kDRAWSHP_XFLIP = 0x01,
|
||||
kDRAWSHP_YFLIP = 0x02,
|
||||
kDRAWSHP_SCALE = 0x04,
|
||||
kDRAWSHP_WINREL = 0x10,
|
||||
kDRAWSHP_CENTER = 0x20,
|
||||
kDRAWSHP_FADE = 0x100,
|
||||
kDRAWSHP_PREDATOR = 0x200,
|
||||
kDRAWSHP_COMPACT = 0x400,
|
||||
kDRAWSHP_PRIORITY = 0x800,
|
||||
kDRAWSHP_TRANSPARENT = 0x1000,
|
||||
kDRAWSHP_BCKGRNDFADE = 0x2000,
|
||||
kDRAWSHP_MORPH = 0x4000,
|
||||
kDRAWSHP_COLOR = 0x8000
|
||||
};
|
||||
|
||||
enum FontId {
|
||||
FID_6_FNT = 0,
|
||||
FID_8_FNT,
|
||||
FID_9_FNT,
|
||||
FID_CRED6_FNT,
|
||||
FID_CRED8_FNT,
|
||||
FID_BOOKFONT_FNT,
|
||||
FID_GOLDFONT_FNT,
|
||||
FID_INTRO_FNT,
|
||||
FID_SJIS_FNT,
|
||||
FID_SJIS_TEXTMODE_FNT,
|
||||
FID_SJIS_LARGE_FNT,
|
||||
FID_SJIS_SMALL_FNT,
|
||||
FID_CHINESE_FNT,
|
||||
FID_KOREAN_FNT,
|
||||
FID_NUM
|
||||
};
|
||||
|
||||
Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize);
|
||||
virtual ~Screen();
|
||||
|
||||
// init
|
||||
virtual bool init();
|
||||
virtual void setResolution();
|
||||
virtual void enableHiColorMode(bool enabled);
|
||||
|
||||
// refresh
|
||||
int updateScreen();
|
||||
void updateBackendScreen(bool force);
|
||||
|
||||
uint32 _idleUpdateTimer;
|
||||
|
||||
// debug functions
|
||||
bool queryScreenDebug() const { return _debugEnabled; }
|
||||
bool enableScreenDebug(bool enable);
|
||||
|
||||
// page cur. functions
|
||||
int setCurPage(int pageNum);
|
||||
void clearCurPage();
|
||||
|
||||
void copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src,
|
||||
int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2);
|
||||
|
||||
// page 0 functions
|
||||
void copyToPage0(int y, int h, uint8 page, uint8 *seqBuf);
|
||||
void shakeScreen(int times);
|
||||
|
||||
// page functions
|
||||
void copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags=0);
|
||||
void copyPage(uint8 srcPage, uint8 dstPage);
|
||||
|
||||
void copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *dest);
|
||||
void copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint8 *src);
|
||||
|
||||
void shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPage, int ticks, bool transparent);
|
||||
void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false);
|
||||
|
||||
void clearPage(int pageNum);
|
||||
|
||||
int getPagePixel(int pageNum, int x, int y);
|
||||
void setPagePixel(int pageNum, int x, int y, uint8 color);
|
||||
|
||||
const uint8 *getCPagePtr(int pageNum) const;
|
||||
uint8 *getPageRect(int pageNum, int x, int y, int w, int h);
|
||||
|
||||
// palette handling
|
||||
void fadeFromBlack(int delay=0x54, const UpdateFunctor *upFunc = 0);
|
||||
void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0);
|
||||
|
||||
virtual void fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc = 0);
|
||||
virtual void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff);
|
||||
virtual int fadePalStep(const Palette &pal, int diff);
|
||||
|
||||
void setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue);
|
||||
virtual void setScreenPalette(const Palette &pal);
|
||||
|
||||
// SegaCD version
|
||||
// This is a somewhat hacky but probably least invasive way to
|
||||
// move the whole ingame screen output down a couple of lines.
|
||||
void transposeScreenOutputY(int yAdd);
|
||||
|
||||
// AMIGA version only
|
||||
bool isInterfacePaletteEnabled() const { return _dualPaletteModeSplitY; }
|
||||
void enableDualPaletteMode(int splitY);
|
||||
void disableDualPaletteMode();
|
||||
|
||||
virtual void getRealPalette(int num, uint8 *dst);
|
||||
Palette &getPalette(int num);
|
||||
void copyPalette(const int dst, const int src);
|
||||
|
||||
// gui specific (processing on _curPage)
|
||||
void drawLine(bool vertical, int x, int y, int length, int color);
|
||||
void drawClippedLine(int x1, int y1, int x2, int y2, int color);
|
||||
virtual void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2);
|
||||
void drawBox(int x1, int y1, int x2, int y2, int color);
|
||||
|
||||
// font/text handling
|
||||
virtual bool loadFont(FontId fontId, const char *filename);
|
||||
FontId setFont(FontId fontId);
|
||||
|
||||
int getFontHeight() const;
|
||||
int getFontWidth() const;
|
||||
|
||||
int getCharWidth(uint16 c) const;
|
||||
int getCharHeight(uint16 c) const;
|
||||
int getTextWidth(const char *str, bool nextWordOnly = false);
|
||||
int getNumberOfCharacters(const char *str);
|
||||
|
||||
void printText(const char *str, int x, int y, uint8 color1, uint8 color2, int pitch = -1);
|
||||
|
||||
virtual void setTextColorMap(const uint8 *cmap) = 0;
|
||||
void setTextColor(const uint8 *cmap, int a, int b);
|
||||
void setTextColor16bit(const uint16 *cmap16);
|
||||
int setFontStyles(FontId fontId, int styles);
|
||||
|
||||
const ScreenDim *getScreenDim(int dim) const;
|
||||
void modifyScreenDim(int dim, int x, int y, int w, int h);
|
||||
int screenDimTableCount() const { return _dimTableCount; }
|
||||
|
||||
void setScreenDim(int dim);
|
||||
int curDimIndex() const { return _curDimIndex; }
|
||||
|
||||
void setTextMarginRight(int x) { _textMarginRight = x; }
|
||||
uint16 _textMarginRight;
|
||||
bool _overdrawMargin;
|
||||
|
||||
const ScreenDim *_curDim;
|
||||
|
||||
Common::String _lineBreakChars;
|
||||
|
||||
// shape handling
|
||||
uint8 *encodeShape(int x, int y, int w, int h, int flags);
|
||||
|
||||
int setNewShapeHeight(uint8 *shape, int height);
|
||||
int resetShapeHeight(uint8 *shape);
|
||||
|
||||
virtual void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...);
|
||||
|
||||
// mouse handling
|
||||
void hideMouse();
|
||||
void showMouse();
|
||||
bool isMouseVisible() const;
|
||||
virtual void setMouseCursor(int x, int y, const byte *shape);
|
||||
|
||||
// rect handling
|
||||
virtual int getRectSize(int w, int h) = 0;
|
||||
|
||||
void rectClip(int &x, int &y, int w, int h);
|
||||
|
||||
// misc
|
||||
virtual void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip=false);
|
||||
|
||||
virtual bool loadPalette(const char *filename, Palette &pal);
|
||||
bool loadPaletteTable(const char *filename, int firstPalette);
|
||||
virtual void loadPalette(const byte *data, Palette &pal, int bytes);
|
||||
|
||||
void setAnimBlockPtr(int size);
|
||||
|
||||
void setShapePages(int page1, int page2, int minY = -1, int maxY = 201);
|
||||
|
||||
virtual byte getShapeFlag1(int x, int y);
|
||||
virtual byte getShapeFlag2(int x, int y);
|
||||
|
||||
virtual int getDrawLayer(int x, int y);
|
||||
virtual int getDrawLayer2(int x, int y, int height);
|
||||
|
||||
void blockInRegion(int x, int y, int width, int height);
|
||||
void blockOutRegion(int x, int y, int width, int height);
|
||||
|
||||
int _charSpacing;
|
||||
int _lineSpacing;
|
||||
int _curPage;
|
||||
uint8 *_shapePages[2];
|
||||
int _maskMinY, _maskMaxY;
|
||||
FontId _currentFont;
|
||||
|
||||
// decoding functions
|
||||
static void decodeFrame1(const uint8 *src, uint8 *dst, uint32 size);
|
||||
static uint16 decodeEGAGetCode(const uint8 *&pos, uint8 &nib);
|
||||
|
||||
static void decodeFrame3(const uint8 *src, uint8 *dst, uint32 size, bool isAmiga);
|
||||
static uint decodeFrame4(const uint8 *src, uint8 *dst, uint32 dstSize);
|
||||
static void decodeFrameDelta(uint8 *dst, const uint8 *src, bool noXor = false);
|
||||
static void decodeFrameDeltaPage(uint8 *dst, const uint8 *src, const int pitch, bool noXor);
|
||||
|
||||
static void convertAmigaGfx(uint8 *data, int w, int h, int depth = 5, bool wsa = false, int bytesPerPlane = -1);
|
||||
static void convertAmigaMsc(uint8 *data);
|
||||
|
||||
// This seems to be a variant of shuffleScreen (which is used in LoK). At the time of coding (and long after that) the
|
||||
// fact that this is a double implementation went unnoticed. My - admittedly limited - efforts to get rid of one of these
|
||||
// implementations were unsatisfactory, though. Each method seems to be optimized to produce accurate results for its
|
||||
// specifc purpose (LoK for shuffleScreen, EoB/LoL for crossFadeRegion). Merging these methods has no priority, since we
|
||||
// can well afford the 20 lines of extra code.
|
||||
void crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage);
|
||||
|
||||
uint16 *get16bitPalette() { return _16bitPalette; }
|
||||
void set16bitShadingLevel(int lvl) { _16bitShadingLevel = lvl; }
|
||||
|
||||
protected:
|
||||
void resetPagePtrsAndBuffers(int pageSize);
|
||||
uint8 *getPagePtr(int pageNum);
|
||||
virtual void updateDirtyRects();
|
||||
void updateDirtyRectsAmiga();
|
||||
void updateDirtyRectsOvl();
|
||||
|
||||
template<typename srcType, typename scaleToType> void scale2x(uint8 *dst, int dstPitch, const uint8 *src, int srcPitch, int w, int h);
|
||||
template<typename pixelType> void mergeOverlayImpl(int x, int y, int w, int h);
|
||||
virtual void mergeOverlay(int x, int y, int w, int h) {
|
||||
if (_useHiColorScreen)
|
||||
mergeOverlayImpl<uint16>(x, y, w, h);
|
||||
else
|
||||
mergeOverlayImpl<uint8>(x, y, w, h);
|
||||
}
|
||||
|
||||
// overlay specific
|
||||
byte *getOverlayPtr(int pageNum);
|
||||
void clearOverlayPage(int pageNum);
|
||||
void clearOverlayRect(int pageNum, int x, int y, int w, int h);
|
||||
void copyOverlayRegion(int x, int y, int x2, int y2, int w, int h, int srcPage, int dstPage);
|
||||
|
||||
// font/text specific
|
||||
uint16 fetchChar(const char *&s) const;
|
||||
void drawChar(uint16 c, int x, int y, int pitch = -1);
|
||||
|
||||
int16 encodeShapeAndCalculateSize(uint8 *from, uint8 *to, int size);
|
||||
|
||||
template<bool noXor> static void wrapped_decodeFrameDelta(uint8 *dst, const uint8 *src);
|
||||
template<bool noXor> static void wrapped_decodeFrameDeltaPage(uint8 *dst, const uint8 *src, const int pitch);
|
||||
|
||||
uint8 *_pagePtrs[16];
|
||||
const uint8 *_pagePtrsBuff;
|
||||
uint8 *_sjisOverlayPtrs[SCREEN_OVLS_NUM];
|
||||
uint8 _pageMapping[SCREEN_PAGE_NUM];
|
||||
|
||||
bool _useOverlays;
|
||||
bool _useSJIS;
|
||||
int _fontStyles;
|
||||
|
||||
Font *_fonts[FID_NUM];
|
||||
uint8 _textColorsMap[16];
|
||||
uint16 _textColorsMap16bit[2];
|
||||
|
||||
uint8 *_textRenderBuffer;
|
||||
int _textRenderBufferSize;
|
||||
|
||||
Common::SharedPtr<Graphics::FontSJIS> _sjisFontShared;
|
||||
uint8 _sjisInvisibleColor;
|
||||
bool _sjisMixedFontMode;
|
||||
|
||||
// colors/palette specific
|
||||
bool _use16ColorMode;
|
||||
bool _useShapeShading;
|
||||
bool _4bitPixelPacking;
|
||||
bool _useHiResEGADithering;
|
||||
bool _useHiColorScreen;
|
||||
bool _isAmiga;
|
||||
bool _useAmigaExtraColors;
|
||||
bool _isSegaCD;
|
||||
Common::RenderMode _renderMode;
|
||||
int _bytesPerPixel;
|
||||
int _screenPageSize;
|
||||
const int _screenHeight;
|
||||
int _yTransOffs;
|
||||
|
||||
Palette *_screenPalette;
|
||||
Common::Array<Palette *> _palettes;
|
||||
Palette *_internFadePalette;
|
||||
|
||||
uint16 shade16bitColor(uint16 col);
|
||||
|
||||
uint16 *_16bitPalette;
|
||||
uint16 *_16bitConversionPalette;
|
||||
uint8 _16bitShadingLevel;
|
||||
|
||||
uint8 *_animBlockPtr;
|
||||
int _animBlockSize;
|
||||
|
||||
// dimension handling
|
||||
const ScreenDim *const _dimTable;
|
||||
ScreenDim **_customDimTable;
|
||||
const int _dimTableCount;
|
||||
int _curDimIndex;
|
||||
|
||||
// mouse handling
|
||||
int _mouseLockCount;
|
||||
const uint8 _cursorColorKey;
|
||||
|
||||
virtual void postProcessCursor(uint8 *data, int w, int h, int pitch) {}
|
||||
|
||||
enum {
|
||||
kMaxDirtyRects = 50
|
||||
};
|
||||
|
||||
bool _forceFullUpdate;
|
||||
bool _paletteChanged;
|
||||
Common::List<Common::Rect> _dirtyRects;
|
||||
|
||||
void addDirtyRect(int x, int y, int w, int h);
|
||||
|
||||
OSystem *_system;
|
||||
KyraEngine_v1 *_vm;
|
||||
|
||||
// shape
|
||||
typedef void (Screen::*DsPlotFunc)(uint8*, uint8);
|
||||
typedef int (Screen::*DsMarginSkipFunc)(uint8*&, const uint8*&, int&);
|
||||
typedef void (Screen::*DsLineFunc)(uint8*&, const uint8*&, const DsPlotFunc, int&, int16);
|
||||
|
||||
int drawShapeMarginNoScaleUpwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
int drawShapeMarginNoScaleDownwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
int drawShapeMarginScaleUpwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
int drawShapeMarginScaleDownwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
int drawShapeSkipScaleUpwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
int drawShapeSkipScaleDownwind(uint8 *&dst, const uint8 *&src, int &cnt);
|
||||
void drawShapeProcessLineNoScaleUpwind(uint8 *&dst, const uint8 *&src, const DsPlotFunc plot, int &cnt, int16);
|
||||
void drawShapeProcessLineNoScaleDownwind(uint8 *&dst, const uint8 *&src, const DsPlotFunc plot, int &cnt, int16);
|
||||
void drawShapeProcessLineScaleUpwind(uint8 *&dst, const uint8 *&src, const DsPlotFunc plot, int &cnt, int16 scaleState);
|
||||
void drawShapeProcessLineScaleDownwind(uint8 *&dst, const uint8 *&src, const DsPlotFunc plot, int &cnt, int16 scaleState);
|
||||
|
||||
void drawShapePlotType0(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType1(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType3_7(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType4(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType5(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType6(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType8(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType9(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType11_15(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType12(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType13(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType14(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType16(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType20(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType21(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType33(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType37(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType48(uint8 *dst, uint8 cmd);
|
||||
void drawShapePlotType52(uint8 *dst, uint8 cmd);
|
||||
|
||||
const uint8 *_dsShapeFadingTable;
|
||||
int _dsShapeFadingLevel;
|
||||
const uint8 *_dsColorTable;
|
||||
const uint8 *_dsTransparencyTable1;
|
||||
const uint8 *_dsTransparencyTable2;
|
||||
const uint8 *_dsBackgroundFadingTable;
|
||||
int _dsDrawLayer;
|
||||
uint8 *_dsDstPage;
|
||||
int _dsTmpWidth;
|
||||
int _dsOffscreenLeft;
|
||||
int _dsOffscreenRight;
|
||||
int _dsScaleW;
|
||||
int _dsScaleH;
|
||||
int _dsOffscreenScaleVal1;
|
||||
int _dsOffscreenScaleVal2;
|
||||
int _drawShapeVar1;
|
||||
int _drawShapeVar3;
|
||||
int _drawShapeVar4;
|
||||
int _drawShapeVar5;
|
||||
|
||||
// AMIGA version
|
||||
int _dualPaletteModeSplitY;
|
||||
|
||||
// debug
|
||||
bool _debugEnabled;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
2324
engines/kyra/graphics/screen_eob.cpp
Normal file
2324
engines/kyra/graphics/screen_eob.cpp
Normal file
File diff suppressed because it is too large
Load Diff
536
engines/kyra/graphics/screen_eob.h
Normal file
536
engines/kyra/graphics/screen_eob.h
Normal file
@@ -0,0 +1,536 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_EOB_H
|
||||
#define KYRA_SCREEN_EOB_H
|
||||
|
||||
#ifdef ENABLE_EOB
|
||||
|
||||
#include "graphics/big5.h"
|
||||
|
||||
#include "kyra/graphics/screen.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class EoBCoreEngine;
|
||||
class SegaRenderer;
|
||||
class SegaAnimator;
|
||||
class Screen_EoB : public Screen {
|
||||
friend class SegaRenderer;
|
||||
public:
|
||||
// The purpose of this enum is to keep better track of which page is used
|
||||
// when and for which purpose. We use the pages for more backup operations
|
||||
// than the original and also have to deal with the different ports which
|
||||
// all do their own things. This is supposed to help avoid using pages that
|
||||
// are already in use for something else. It also allows for quick fixes
|
||||
// if necessary.
|
||||
enum {
|
||||
kSegaInitShapesPage = 7,
|
||||
kSegaRenderPage = 8,
|
||||
kDefeatMsgBackupPage = 10,
|
||||
kCheckPwBackupPage = 10,
|
||||
kSpellbookBackupPage = 10,
|
||||
kEoB2ScriptHelperPage = 12,
|
||||
kCampMenuBackupPage = 12
|
||||
};
|
||||
|
||||
public:
|
||||
Screen_EoB(EoBCoreEngine *vm, OSystem *system);
|
||||
~Screen_EoB() override;
|
||||
|
||||
bool init() override;
|
||||
|
||||
void setClearScreenDim(int dim);
|
||||
void clearCurDim();
|
||||
void clearCurDimOvl(int pageNum);
|
||||
|
||||
void setMouseCursor(int x, int y, const byte *shape) override;
|
||||
void setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl);
|
||||
|
||||
void loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size);
|
||||
|
||||
void printShadedText(const char *string, int x, int y, int col1, int col2, int shadowCol, int pitch = -1);
|
||||
|
||||
static void eob2ChineseLZUncompress(byte *dest, uint32 destSize, Common::SeekableReadStream *src);
|
||||
void loadChineseEOB2LZBitmap(Common::SeekableReadStream *s, int pageNum, uint32 size);
|
||||
void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip = false) override;
|
||||
void loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage);
|
||||
void loadShapeSetBitmap(const char *file, int tempPage, int destPage);
|
||||
|
||||
void convertPage(int srcPage, int dstPage, const uint8 *cgaMapping);
|
||||
|
||||
void setScreenPalette(const Palette &pal) override;
|
||||
void getRealPalette(int num, uint8 *dst) override;
|
||||
|
||||
uint8 *encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit = false, const uint8 *cgaMapping = 0);
|
||||
void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd = -1, int flags = 0, ...) override;
|
||||
void drawT1Shape(uint8 pageNum, const byte *t1data, int x, int y, int sd);
|
||||
const uint8 *scaleShape(const uint8 *shapeData, int blockDistance);
|
||||
const uint8 *scaleShapeStep(const uint8 *shp);
|
||||
const uint8 *generateShapeOverlay(const uint8 *shp, const uint8 *fadingTable);
|
||||
|
||||
void setShapeFrame(int x1, int y1, int x2, int y2);
|
||||
void enableShapeBackgroundFading(bool enable);
|
||||
void setShapeFadingLevel(int val);
|
||||
|
||||
void setGfxParameters(int x, int y, int col);
|
||||
void drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize);
|
||||
void drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize);
|
||||
|
||||
void fadeTextColor(Palette *pal, int color, int rate);
|
||||
bool delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate);
|
||||
|
||||
void setTextColorMap(const uint8 *cmap) override {}
|
||||
int getRectSize(int w, int h) override;
|
||||
|
||||
void setFadeTable(const uint8 *table);
|
||||
void createFadeTable(const uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight);
|
||||
void createFadeTable16bit(const uint16 *palData, uint16 *dst, uint16 rootColor, uint8 weight);
|
||||
|
||||
const uint16 *getCGADitheringTable(int index);
|
||||
const uint8 *getEGADitheringTable();
|
||||
|
||||
bool loadFont(FontId fontId, const char *filename) override;
|
||||
|
||||
// FM-Towns specific
|
||||
void decodeSHP(const uint8 *data, int dstPage);
|
||||
void convertToHiColor(int page);
|
||||
void shadeRect(int x1, int y1, int x2, int y2, int shadingLevel);
|
||||
|
||||
// PC-98 specific
|
||||
void selectPC98Palette(int palID, Palette &dest, int brightness = 0, bool set = false);
|
||||
void decodeBIN(const uint8 *src, uint8 *dst, uint16 inSize);
|
||||
void decodePC98PlanarBitmap(uint8 *srcDstBuffer, uint8 *tmpBuffer, uint16 size = 64000);
|
||||
|
||||
struct PalCycleData {
|
||||
const int8 *data;
|
||||
uint8 delay;
|
||||
};
|
||||
|
||||
void initPC98PaletteCycle(int palID, PalCycleData *data);
|
||||
void updatePC98PaletteCycle(int brightness);
|
||||
|
||||
PalCycleData *_activePalCycle;
|
||||
uint8 *_cyclePalette;
|
||||
|
||||
// Amiga specific
|
||||
void loadSpecialAmigaCPS(const char *fileName, int destPage, bool isGraphics);
|
||||
// This is a simple way of emulating the Amiga copper list palette magic for more than 32 colors.
|
||||
// I use colors 32 to 63 for these extra colors (which the Amiga copper sends to the color
|
||||
// registers on the fly at vertical beam position 120).
|
||||
void setDualPalettes(Palette &top, Palette &bottom);
|
||||
|
||||
// SegaCD specific
|
||||
void sega_initGraphics();
|
||||
void sega_selectPalette(int srcPalID, int dstPalID, bool set = false);
|
||||
void sega_loadCustomPaletteData(Common::ReadStream *in);
|
||||
void sega_updatePaletteFaders(int palID);
|
||||
void sega_fadePalette(int delay, int16 brEnd, int dstPalID = -1, bool waitForCompletion = true, bool noUpdate = false);
|
||||
void sega_fadeToBlack(int delay) { sega_fadePalette(delay, -7); }
|
||||
void sega_fadeToWhite(int delay) { sega_fadePalette(delay, 7); }
|
||||
void sega_fadeToNeutral(int delay) { sega_fadePalette(delay, 0); }
|
||||
void sega_paletteOps(int16 opPal, int16 par1, int16 par2);
|
||||
void sega_setTextBuffer(uint8 *buffer, uint32 bufferSize);
|
||||
void sega_clearTextBuffer(uint8 col);
|
||||
void sega_loadTextBackground(const uint8 *src, uint16 size);
|
||||
void sega_drawTextBox(int pW, int pH, int x, int y, int w, int h, uint8 color1, uint8 color2);
|
||||
void sega_loadTextBufferToVRAM(uint16 srcOffset, uint16 addr, int size);
|
||||
void sega_gfxScale(uint8 *out, uint16 w, uint16 h, uint16 pitch, const uint8 *in, const uint16 *stampMap, const uint16 *traceVectors);
|
||||
void sega_drawClippedLine(int pW, int pH, int x, int y, int w, int h, uint8 color);
|
||||
uint8 *sega_convertShape(const uint8 *src, int w, int h, int pal, int hOffs = 0);
|
||||
void sega_encodeShapesFromSprites(const uint8 **dst, const uint8 *src, int numShapes, int w, int h, int pal, bool removeSprites = true);
|
||||
|
||||
SegaRenderer *sega_getRenderer() const { return _segaRenderer; }
|
||||
SegaAnimator *sega_getAnimator() const { return _segaAnimator; }
|
||||
|
||||
private:
|
||||
void updateDirtyRects() override;
|
||||
void ditherRect(const uint8 *src, uint8 *dst, int dstPitch, int srcW, int srcH, int colorKey = -1);
|
||||
|
||||
void drawShapeSetPixel(uint8 *dst, uint8 col);
|
||||
void scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc);
|
||||
void scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src);
|
||||
bool posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2);
|
||||
|
||||
void setPagePixel16bit(int pageNum, int x, int y, uint16 color);
|
||||
|
||||
void generateEGADitheringTable(const Palette &pal);
|
||||
void generateCGADitheringTables(const uint8 *mappingData);
|
||||
|
||||
int _dsDiv, _dsRem, _dsScaleTrans;
|
||||
uint8 *_cgaScaleTable;
|
||||
int16 _gfxX, _gfxY;
|
||||
uint16 _gfxCol;
|
||||
const uint8 *_gfxMaxY;
|
||||
|
||||
int16 _dsX1, _dsX2, _dsY1, _dsY2;
|
||||
|
||||
bool _dsBackgroundFading;
|
||||
int16 _dsBackgroundFadingXOffs;
|
||||
uint8 _shapeOverlay[16];
|
||||
|
||||
uint8 *_dsTempPage;
|
||||
uint8 *_shpBuffer;
|
||||
uint8 *_convertHiColorBuffer;
|
||||
|
||||
uint16 *_cgaDitheringTables[2];
|
||||
const uint8 *_cgaMappingDefault;
|
||||
|
||||
uint8 *_egaDitheringTable;
|
||||
uint8 *_egaDitheringTempPage;
|
||||
|
||||
Common::String _cpsFilePattern;
|
||||
|
||||
const uint16 _cursorColorKey16Bit;
|
||||
|
||||
static const uint8 _egaMatchTable[];
|
||||
static const ScreenDim _screenDimTableIntl[];
|
||||
static const ScreenDim _screenDimTableZH[];
|
||||
static const int _screenDimTableCount;
|
||||
|
||||
// SegaCD specific
|
||||
struct PaletteFader {
|
||||
PaletteFader() : _brCur(0), _brDest(0), _fadeIncr(0), _fadeDelay(0), _fadeTimer(0), _needRefresh(false) {}
|
||||
int16 _brCur;
|
||||
int16 _brDest;
|
||||
int16 _fadeIncr;
|
||||
int16 _fadeDelay;
|
||||
int16 _fadeTimer;
|
||||
bool _needRefresh;
|
||||
};
|
||||
|
||||
PaletteFader *_palFaders;
|
||||
bool _specialColorReplace;
|
||||
SegaRenderer *_segaRenderer;
|
||||
SegaAnimator *_segaAnimator;
|
||||
uint16 _segaCurPalette[64];
|
||||
uint16 *_segaCustomPalettes;
|
||||
uint8 *_defaultRenderBuffer;
|
||||
int _defaultRenderBufferSize;
|
||||
|
||||
Common::SharedPtr<Graphics::Big5Font> _big5;
|
||||
};
|
||||
|
||||
class ChineseTwoByteFontEoB final : public Font {
|
||||
public:
|
||||
ChineseTwoByteFontEoB(Common::SharedPtr<Graphics::Big5Font> big5, Font *singleByte) : _big5(big5), _singleByte(singleByte), _border(false), _colorMap(nullptr) {}
|
||||
|
||||
virtual Type getType() const override { return kBIG5; }
|
||||
|
||||
bool load(Common::SeekableReadStream &data) override {
|
||||
return _singleByte->load(data);
|
||||
}
|
||||
|
||||
void setStyles(int styles) override { _border = (styles & kStyleBorder); _singleByte->setStyles(styles); }
|
||||
int getHeight() const override { return MAX(_big5->getFontHeight(), _singleByte->getHeight()); }
|
||||
int getWidth() const override { return MAX(_big5->kChineseTraditionalWidth + 2, _singleByte->getWidth()); }
|
||||
void setColorMap(const uint8 *src) override { _colorMap = src; _singleByte->setColorMap(src); }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
int getCharHeight(uint16 c) const override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int bpp) const override;
|
||||
|
||||
private:
|
||||
uint16 translateBig5(uint16 in) const;
|
||||
Common::SharedPtr<Graphics::Big5Font> _big5;
|
||||
Common::ScopedPtr<Font> _singleByte;
|
||||
bool _border;
|
||||
const uint8 *_colorMap;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the Font interface for old DOS fonts used
|
||||
* in EOB and EOB II.
|
||||
*
|
||||
*/
|
||||
class OldDOSFont : public Font {
|
||||
public:
|
||||
OldDOSFont(Common::RenderMode mode, uint8 shadowColor, bool remapCharacters = true);
|
||||
~OldDOSFont() override;
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
bool loadPCBIOSTall();
|
||||
Type getType() const override { return kASCII; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
bool usesOverlay() const override { return _useOverlay; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override;
|
||||
void set16bitColorMap(const uint16 *src) override { _colorMap16bit = src; }
|
||||
void setStyles(int styles) override { _style = styles; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int bpp) const override;
|
||||
|
||||
protected:
|
||||
void unload();
|
||||
|
||||
int _style;
|
||||
const uint8 *_colorMap8bit;
|
||||
uint8 *_data;
|
||||
uint16 *_bitmapOffsets;
|
||||
int _width, _height;
|
||||
int _numGlyphs;
|
||||
uint8 _shadowColor;
|
||||
|
||||
uint16 _numGlyphsMax;
|
||||
bool _useOverlay;
|
||||
int _scaleV;
|
||||
|
||||
private:
|
||||
void drawCharIntern(uint16 c, byte *dst, int pitch, int bpp, int col1, int col2) const;
|
||||
virtual uint16 convert(uint16 c) const;
|
||||
Common::RenderMode _renderMode;
|
||||
const uint16 *_colorMap16bit;
|
||||
bool _remapCharacters;
|
||||
|
||||
static uint16 *_cgaDitheringTable;
|
||||
static int _numRef;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the Font interface for native AmigaDOS system fonts (normally to be loaded via diskfont.library)
|
||||
*/
|
||||
class Resource;
|
||||
class AmigaDOSFont : public Font {
|
||||
public:
|
||||
AmigaDOSFont(Resource *res, bool needsLocalizedFont = false);
|
||||
~AmigaDOSFont() override { unload(); }
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
Type getType() const override { return kASCII; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void setColorMap(const uint8 *src) override { _colorMap = src; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
static void errorDialog(int index);
|
||||
|
||||
private:
|
||||
void unload();
|
||||
|
||||
struct TextFont {
|
||||
TextFont() : data(0), bitmap(0), location(0), spacing(0), kerning(0), height(0), width(0), baseLine(0), firstChar(0), lastChar(0), modulo(0) {}
|
||||
~TextFont() {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
uint16 height;
|
||||
uint16 width;
|
||||
uint16 baseLine;
|
||||
uint8 firstChar;
|
||||
uint8 lastChar;
|
||||
uint16 modulo;
|
||||
const uint8 *data;
|
||||
const uint8 *bitmap;
|
||||
const uint16 *location;
|
||||
const int16 *spacing;
|
||||
const int16 *kerning;
|
||||
};
|
||||
|
||||
TextFont *loadContentFile(const Common::Path &fileName);
|
||||
void selectMode(int mode);
|
||||
|
||||
struct FontContent {
|
||||
FontContent() : height(0), style(0), flags(0) {}
|
||||
~FontContent() {
|
||||
data.reset();
|
||||
}
|
||||
|
||||
Common::String contentFile;
|
||||
Common::SharedPtr<TextFont> data;
|
||||
uint16 height;
|
||||
uint8 style;
|
||||
uint8 flags;
|
||||
};
|
||||
|
||||
int _width, _height;
|
||||
uint8 _first, _last;
|
||||
FontContent *_content;
|
||||
uint16 _numElements;
|
||||
uint16 _selectedElement;
|
||||
|
||||
const uint8 *_colorMap;
|
||||
const uint16 _maxPathLen;
|
||||
const bool _needsLocalizedFont;
|
||||
|
||||
static uint8 _errorDialogDisplayed;
|
||||
|
||||
Resource *_res;
|
||||
};
|
||||
|
||||
/**
|
||||
* SJIS Font variant used in EOB I PC-98. It converts 1-byte characters into 2-byte characters and has a specific shadowing to the left.
|
||||
*/
|
||||
class SJISFontEoB1PC98 : public SJISFont {
|
||||
public:
|
||||
SJISFontEoB1PC98(Common::SharedPtr<Graphics::FontSJIS> &font, /*uint8 shadowColor,*/ const uint16 *convTable1, const uint16 *convTable2);
|
||||
~SJISFontEoB1PC98() override {}
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
uint16 convert(uint16 c) const;
|
||||
const uint16 *_convTable1, *_convTable2;
|
||||
bool _defaultConv;
|
||||
};
|
||||
|
||||
/**
|
||||
* SJIS Font variant used in EOB II PC-98. It converts 1-byte characters into 2-byte characters.
|
||||
*/
|
||||
class SJISFontEoB2PC98 : public SJISFont {
|
||||
public:
|
||||
SJISFontEoB2PC98(Common::SharedPtr<Graphics::FontSJIS> &font, /*uint8 shadowColor,*/ const char *convTable1, const char *convTable2);
|
||||
~SJISFontEoB2PC98() override {}
|
||||
int getCharWidth(uint16 c) const override;
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
uint16 convert(uint16 c) const;
|
||||
const char *_convTable1, *_convTable2;
|
||||
//bool _defaultConv;
|
||||
};
|
||||
|
||||
/**
|
||||
* OldDOSFont variant used in EOB I PC-98. It uses the same drawing routine, but has a different loader. It contains
|
||||
* ASCII and Katakana characters in JIS X 0201 and requires several conversion tables to display these. It gets drawn on the hires overlay.
|
||||
*/
|
||||
class Font12x12PC98 : public OldDOSFont{
|
||||
public:
|
||||
Font12x12PC98(uint8 shadowColor, const uint16 *convTable1, const uint16 *convTable2, const uint8 *lookupTable);
|
||||
~Font12x12PC98() override;
|
||||
bool usesOverlay() const override { return true; }
|
||||
Type getType() const override { return kJIS_X0201; }
|
||||
int getHeight() const override { return _height >> 1; }
|
||||
int getWidth() const override { return _width >> 1; }
|
||||
int getCharWidth(uint16 c) const override { return _width >> 1; };
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
|
||||
private:
|
||||
uint16 convert(uint16 c) const override;
|
||||
const uint16 *_convTable1, *_convTable2;
|
||||
uint16 *_bmpOffs;
|
||||
};
|
||||
|
||||
/**
|
||||
* OldDOSFont variant used in EOB II PC-98 which supports twice the number of characters. Some font files may include kana characters. The font supports
|
||||
* weird vertical scaling and can be drawn on the hires overlay.
|
||||
*/
|
||||
class PC98Font : public OldDOSFont {
|
||||
public:
|
||||
PC98Font(uint8 shadowColor, bool useOverlay, int scaleV, const uint8 *convTable1 = 0, const char *convTable2 = 0, const char *convTable3 = 0);
|
||||
~PC98Font() override {}
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
int getHeight() const override { return _outputHeight; }
|
||||
int getWidth() const override { return _outputWidth; }
|
||||
int getCharWidth(uint16 c) const override { return _outputWidth; };
|
||||
Type getType() const override { return _type; }
|
||||
|
||||
private:
|
||||
uint16 convert(uint16 c) const override;
|
||||
uint16 makeTwoByte(uint16 c) const;
|
||||
|
||||
const uint8 *_convTable1;
|
||||
const char *_convTable2, *_convTable3;
|
||||
|
||||
int _outputHeight;
|
||||
int _outputWidth;
|
||||
const Type _type;
|
||||
};
|
||||
|
||||
/**
|
||||
* SJIS Font variant used in the intro and outro of EOB II FM-Towns. It appears twice as large, since it is not rendered on the hires overlay pages.
|
||||
*/
|
||||
class SJISFontLarge : public SJISFont {
|
||||
public:
|
||||
SJISFontLarge(Common::SharedPtr<Graphics::FontSJIS> &font);
|
||||
~SJISFontLarge() override {}
|
||||
|
||||
int getHeight() const override;
|
||||
int getWidth() const override;
|
||||
int getCharWidth(uint16 c) const override;
|
||||
|
||||
bool usesOverlay() const override { return false; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* 12 x 12 SJIS font for EOB II FM-Towns. The data for this font comes from a file, not from the font rom.
|
||||
*/
|
||||
class SJISFont12x12 : public Font {
|
||||
public:
|
||||
SJISFont12x12(const uint16 *searchTable);
|
||||
~SJISFont12x12() override { unload(); }
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
Type getType() const override { return kSJIS; }
|
||||
bool usesOverlay() const override { return true; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override { return _width; }
|
||||
void setColorMap(const uint8 *src) override { _colorMap = src; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int) const override;
|
||||
|
||||
private:
|
||||
void unload();
|
||||
|
||||
uint8 *_data;
|
||||
Common::HashMap<uint16, uint8> _searchTable;
|
||||
|
||||
const uint8 *_colorMap;
|
||||
const int _height, _width;
|
||||
};
|
||||
|
||||
class SegaCDFont : public Font {
|
||||
public:
|
||||
SegaCDFont(Common::Language lang, const uint16 *convTable1, const uint16 *convTable2, const uint8 *widthTable1, const uint8 *widthTable2, const uint8 *widthTable3);
|
||||
~SegaCDFont() override;
|
||||
|
||||
bool load(Common::SeekableReadStream &file) override;
|
||||
Type getType() const override { return _forceOneByte ? kASCII : kSJIS; }
|
||||
int getHeight() const override { return _height; }
|
||||
int getWidth() const override { return _width; }
|
||||
int getCharWidth(uint16 c) const override;
|
||||
int getCharHeight(uint16 c) const override;
|
||||
void setStyles(int styles) override;
|
||||
void setColorMap(const uint8 *src) override { _colorMap = src; }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int bpp) const override { drawChar(c, dst, pitch, 0, 0); }
|
||||
void drawChar(uint16 c, byte *dst, int pitch, int xOffs, int yOffs) const override;
|
||||
|
||||
private:
|
||||
const uint8 *getGlyphData(uint16 c, uint8 &charWidth, uint8 &charHeight, uint8 &pitch) const;
|
||||
|
||||
const uint8 *_data;
|
||||
const uint8 *_buffer;
|
||||
bool _forceTwoByte;
|
||||
bool _forceOneByte;
|
||||
Common::Language _lang;
|
||||
uint8 _style;
|
||||
|
||||
const uint8 *_colorMap;
|
||||
const int _height, _width;
|
||||
const uint16 *_convTable1, *_convTable2;
|
||||
const uint8 *_widthTable1, *_widthTable2, *_widthTable3;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_EOB
|
||||
|
||||
#endif
|
||||
411
engines/kyra/graphics/screen_eob_amiga.cpp
Normal file
411
engines/kyra/graphics/screen_eob_amiga.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef ENABLE_EOB
|
||||
|
||||
#include "kyra/resource/resource.h"
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "gui/error.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
static uint32 _decodeFrameAmiga_x = 0;
|
||||
|
||||
bool decodeFrameAmiga_readNextBit(const uint8 *&data, uint32 &code, uint32 &chk) {
|
||||
_decodeFrameAmiga_x = code & 1;
|
||||
code >>= 1;
|
||||
if (code)
|
||||
return _decodeFrameAmiga_x;
|
||||
|
||||
data -= 4;
|
||||
code = READ_BE_UINT32(data);
|
||||
chk ^= code;
|
||||
_decodeFrameAmiga_x = code & 1;
|
||||
code = (code >> 1) | (1 << 31);
|
||||
|
||||
return _decodeFrameAmiga_x;
|
||||
}
|
||||
|
||||
uint32 decodeFrameAmiga_readBits(const uint8 *&data, uint32 &code, uint32 &chk, int count) {
|
||||
uint32 res = 0;
|
||||
while (count--) {
|
||||
decodeFrameAmiga_readNextBit(data, code, chk);
|
||||
uint32 bt1 = _decodeFrameAmiga_x;
|
||||
_decodeFrameAmiga_x = res >> 31;
|
||||
res = (res << 1) | bt1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Screen_EoB::loadSpecialAmigaCPS(const char *fileName, int destPage, bool isGraphics) {
|
||||
uint32 fileSize = 0;
|
||||
const uint8 *file = _vm->resource()->fileData(fileName, &fileSize);
|
||||
|
||||
if (!file)
|
||||
error("Screen_EoB::loadSpecialAmigaCPS(): Failed to load file '%s'", fileName);
|
||||
|
||||
uint32 inSize = READ_BE_UINT32(file);
|
||||
const uint8 *pos = file;
|
||||
|
||||
// Check whether the file starts with the actual compression header.
|
||||
// If this is not the case, there should a palette before the header.
|
||||
// Unlike normal CPS files these files never have more than one palette.
|
||||
if (((inSize + 15) & ~3) != ((fileSize + 3) & ~3)) {
|
||||
Common::MemoryReadStream in(pos, 64);
|
||||
_palettes[0]->loadAmigaPalette(in, 0, 32);
|
||||
pos += 64;
|
||||
}
|
||||
|
||||
inSize = READ_BE_UINT32(pos);
|
||||
uint32 outSize = READ_BE_UINT32(pos + 4);
|
||||
uint32 chk = READ_BE_UINT32(pos + 8);
|
||||
|
||||
pos = pos + 8 + inSize;
|
||||
uint8 *dstStart = _pagePtrs[destPage];
|
||||
uint8 *dst = dstStart + outSize;
|
||||
|
||||
uint32 val = READ_BE_UINT32(pos);
|
||||
_decodeFrameAmiga_x = 0;
|
||||
chk ^= val;
|
||||
|
||||
while (dst > dstStart) {
|
||||
int para = -1;
|
||||
int para2 = 0;
|
||||
|
||||
if (decodeFrameAmiga_readNextBit(pos, val, chk)) {
|
||||
uint32 code = decodeFrameAmiga_readBits(pos, val, chk, 2);
|
||||
|
||||
if (code == 3) {
|
||||
para = para2 = 8;
|
||||
} else {
|
||||
int cnt = 0;
|
||||
if (code < 2) {
|
||||
cnt = 3 + code;
|
||||
para2 = 9 + code;
|
||||
} else {
|
||||
cnt = decodeFrameAmiga_readBits(pos, val, chk, 8) + 1;
|
||||
para2 = 12;
|
||||
}
|
||||
|
||||
code = decodeFrameAmiga_readBits(pos, val, chk, para2);
|
||||
while (cnt--) {
|
||||
dst--;
|
||||
*dst = dst[code & 0xFFFF];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (decodeFrameAmiga_readNextBit(pos, val, chk)) {
|
||||
uint32 code = decodeFrameAmiga_readBits(pos, val, chk, 8);
|
||||
dst--;
|
||||
*dst = dst[code & 0xFFFF];
|
||||
dst--;
|
||||
*dst = dst[code & 0xFFFF];
|
||||
|
||||
} else {
|
||||
para = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (para > 0) {
|
||||
uint32 code = decodeFrameAmiga_readBits(pos, val, chk, para);
|
||||
uint32 cnt = (code & 0xFFFF) + para2 + 1;
|
||||
|
||||
while (cnt--) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
decodeFrameAmiga_readNextBit(pos, val, chk);
|
||||
uint32 bt1 = _decodeFrameAmiga_x;
|
||||
_decodeFrameAmiga_x = code >> 31;
|
||||
code = (code << 1) | bt1;
|
||||
}
|
||||
*(--dst) = code & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] file;
|
||||
|
||||
if (chk)
|
||||
error("Screen_EoB::loadSpecialAmigaCPS(): Checksum error");
|
||||
|
||||
if (isGraphics)
|
||||
convertAmigaGfx(_pagePtrs[destPage], 320, 200);
|
||||
}
|
||||
|
||||
void Screen_EoB::setDualPalettes(Palette &top, Palette &bottom) {
|
||||
// The original supports simultaneous fading of both palettes, but doesn't make any use of that
|
||||
// feature. The fade rate is always set to 0. So I see no need to implement that.
|
||||
_palettes[0]->copy(top, 0, 32, 0);
|
||||
_palettes[0]->copy(bottom, 0, 32, 32);
|
||||
setScreenPalette(*_palettes[0]);
|
||||
enableDualPaletteMode(120);
|
||||
}
|
||||
|
||||
AmigaDOSFont::AmigaDOSFont(Resource *res, bool needsLocalizedFont) : _res(res), _needsLocalizedFont(needsLocalizedFont), _width(0), _height(0), _first(0), _last(0), _content(0), _numElements(0), _selectedElement(0), _maxPathLen(256), _colorMap(nullptr) {
|
||||
assert(_res);
|
||||
}
|
||||
|
||||
bool AmigaDOSFont::load(Common::SeekableReadStream &file) {
|
||||
unload();
|
||||
|
||||
uint16 id = file.readUint16BE();
|
||||
// We only support type 0x0f00, since this is the only type used for EOB
|
||||
if (id != 0x0f00)
|
||||
return false;
|
||||
|
||||
_numElements = file.readUint16BE();
|
||||
_content = new FontContent[_numElements];
|
||||
char *cfile = new char[_maxPathLen];
|
||||
|
||||
for (int i = 0; i < _numElements; ++i) {
|
||||
file.read(cfile, _maxPathLen);
|
||||
_content[i].height = file.readUint16BE();
|
||||
_content[i].style = file.readByte();
|
||||
_content[i].flags = file.readByte();
|
||||
_content[i].contentFile = cfile;
|
||||
|
||||
for (int ii = 0; ii < i; ++ii) {
|
||||
if (_content[ii].contentFile == _content[i].contentFile && _content[ii].data.get())
|
||||
_content[i].data = _content[ii].data;
|
||||
}
|
||||
|
||||
if (!_content[i].data.get()) {
|
||||
TextFont *contentData = loadContentFile(cfile);
|
||||
if (contentData) {
|
||||
_content[i].data = Common::SharedPtr<TextFont>(contentData);
|
||||
} else {
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_content[i].flags & 0x40) && (_content[i].height != _content[i].data->height)) {
|
||||
warning("Amiga DOS Font construction / scaling not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
delete[] cfile;
|
||||
|
||||
selectMode(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int AmigaDOSFont::getCharWidth(uint16 c) const {
|
||||
if (c < _first || c > _last)
|
||||
return 0;
|
||||
c -= _first;
|
||||
|
||||
int width = _content[_selectedElement].data->spacing ? _content[_selectedElement].data->spacing[c] : _content[_selectedElement].data->width;
|
||||
|
||||
/*if (_content[_selectedElement].data->kerning)
|
||||
width += _content[_selectedElement].data->kerning[c];*/
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
void AmigaDOSFont::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
if (c < _first || c > _last || !dst)
|
||||
return;
|
||||
|
||||
static const uint16 table[] = {
|
||||
0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
|
||||
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff
|
||||
};
|
||||
|
||||
c -= _first;
|
||||
|
||||
int w = _content[_selectedElement].data->spacing ? _content[_selectedElement].data->spacing[c] : _content[_selectedElement].data->width;
|
||||
int xbits = _content[_selectedElement].data->location[c * 2 + 1];
|
||||
int h = _content[_selectedElement].data->height;
|
||||
|
||||
uint16 bitPos = _content[_selectedElement].data->location[c * 2] & 0x0F;
|
||||
uint16 mod = _content[_selectedElement].data->modulo;
|
||||
const uint8 *data = _content[_selectedElement].data->bitmap + ((_content[_selectedElement].data->location[c * 2] >> 3) & ~1);
|
||||
uint32 xbt_mask = xbits ? table[(xbits - 1) & 0x0F] << 16 : 0;
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
uint32 mask = 0x80000000;
|
||||
uint32 bits = (READ_BE_UINT32(data) << bitPos) & xbt_mask;
|
||||
data += mod;
|
||||
|
||||
for (int x = 0; x < w; ++x) {
|
||||
if (bits & mask) {
|
||||
if (_colorMap[1])
|
||||
*dst = _colorMap[1];
|
||||
} else {
|
||||
if (_colorMap[0])
|
||||
*dst = _colorMap[0];
|
||||
}
|
||||
mask >>= 1;
|
||||
dst++;
|
||||
}
|
||||
dst += (pitch - w);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 AmigaDOSFont::_errorDialogDisplayed = 0;
|
||||
|
||||
void AmigaDOSFont::errorDialog(int index) {
|
||||
if (_errorDialogDisplayed & (1 << index))
|
||||
return;
|
||||
_errorDialogDisplayed |= (1 << index);
|
||||
|
||||
// I've made rather elaborate dialogs here, since the Amiga font file handling is quite prone to cause problems for users.
|
||||
// This will hopefully prevent unnecessary forum posts and bug reports.
|
||||
if (index == 0) {
|
||||
::GUI::displayErrorDialog(_(
|
||||
"This AMIGA version requires the following font files:\n\nEOBF6.FONT\nEOBF6/6\nEOBF8.FONT\nEOBF8/8\n\n"
|
||||
"If you used the original installer for the installation these files\nshould be located in the AmigaDOS system 'Fonts/' folder.\n"
|
||||
"Please copy them into the EOB game data directory.\n"
|
||||
));
|
||||
|
||||
error("Failed to load font files.");
|
||||
} else if (index == 1) {
|
||||
::GUI::displayErrorDialog(_(
|
||||
"This AMIGA version requires the following font files:\n\nEOBF6.FONT\nEOBF6/6\nEOBF8.FONT\nEOBF8/8\n\n"
|
||||
"This is a localized (non-English) version of EOB II which uses language specific characters\n"
|
||||
"contained only in the specific font files that came with your game. You cannot use the font\n"
|
||||
"files from the English version or from any EOB I game which seems to be what you are doing.\n\n"
|
||||
"The game will continue, but the language specific characters will not be displayed.\n"
|
||||
"Please copy the correct font files into your EOB II game data directory.\n\n"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void AmigaDOSFont::unload() {
|
||||
delete[] _content;
|
||||
}
|
||||
|
||||
AmigaDOSFont::TextFont *AmigaDOSFont::loadContentFile(const Common::Path &fileName) {
|
||||
Common::SeekableReadStreamEndian *str = _res->createEndianAwareReadStream(fileName);
|
||||
|
||||
if (!str && !fileName.getParent().empty()) {
|
||||
// These content files are usually located in sub directories (i. e. the eobf8.font
|
||||
// has a sub dir named 'eobf8' with a file '8' in it). In case someone put the content
|
||||
// files directly in the game directory we still try to open it.
|
||||
Common::Path fileNameAlt(fileName.baseName(), Common::Path::kNoSeparator);
|
||||
str = _res->createEndianAwareReadStream(fileNameAlt);
|
||||
|
||||
if (!str) {
|
||||
// Someone might even have copied the floppy disks to the game directory with the
|
||||
// full sub directory structure. So we also try that...
|
||||
fileNameAlt = Common::Path("fonts");
|
||||
fileNameAlt.joinInPlace(fileName);
|
||||
|
||||
str = _res->createEndianAwareReadStream(fileNameAlt);
|
||||
}
|
||||
|
||||
if (!str)
|
||||
errorDialog(0);
|
||||
}
|
||||
|
||||
assert(str);
|
||||
uint32 hunkId = str->readUint32();
|
||||
// Except for some sanity checks we skip all of the Amiga hunk file magic
|
||||
if (hunkId != 0x03f3)
|
||||
return 0;
|
||||
str->seek(20, SEEK_CUR);
|
||||
|
||||
uint32 hunkType = str->readUint32();
|
||||
if (hunkType != 0x3E9)
|
||||
return 0;
|
||||
uint32 dataSize = str->readUint32() * 4;
|
||||
int32 hunkStartPos = str->pos();
|
||||
|
||||
str->seek(34, SEEK_CUR);
|
||||
TextFont *fnt = new TextFont();
|
||||
int32 fntStartPos = str->pos();
|
||||
str->seek(44, SEEK_CUR);
|
||||
fnt->height = str->readUint16();
|
||||
str->seek(2, SEEK_CUR);
|
||||
fnt->width = str->readUint16();
|
||||
fnt->baseLine = str->readUint16();
|
||||
str->seek(4, SEEK_CUR);
|
||||
fnt->firstChar = str->readByte();
|
||||
fnt->lastChar = str->readByte();
|
||||
|
||||
if (_needsLocalizedFont && fnt->lastChar <= 127)
|
||||
errorDialog(1);
|
||||
|
||||
str->seek(18, SEEK_CUR);
|
||||
int32 curPos = str->pos();
|
||||
uint32 bufferSize = dataSize - (curPos - fntStartPos);
|
||||
uint8 *buffer = new uint8[bufferSize];
|
||||
str->read(buffer, bufferSize);
|
||||
|
||||
str->seek(curPos - 18, SEEK_SET);
|
||||
uint32 offset = str->readUint32();
|
||||
fnt->bitmap = offset ? buffer + offset - (curPos - hunkStartPos) : nullptr;
|
||||
assert(fnt->bitmap);
|
||||
fnt->modulo = str->readUint16();
|
||||
|
||||
offset = str->readUint32();
|
||||
uint16 *loc = (uint16*)(offset ? buffer + offset - (curPos - hunkStartPos) : nullptr);
|
||||
assert(loc);
|
||||
for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i)
|
||||
loc[i] = READ_BE_UINT16(&loc[i]);
|
||||
fnt->location = loc;
|
||||
|
||||
offset = str->readUint32();
|
||||
int16 *idat = offset ? (int16*)(buffer + offset - (curPos - hunkStartPos)) : nullptr;
|
||||
if (idat) {
|
||||
for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i)
|
||||
idat[i] = (int16)READ_BE_UINT16(&idat[i]);
|
||||
}
|
||||
fnt->spacing = idat;
|
||||
|
||||
offset = str->readUint32();
|
||||
// This warning will only show up if someone tries to use this code elsewhere. It cannot happen with EOB fonts.
|
||||
if (offset)
|
||||
warning("Trying to load an AmigaDOS font with kerning data. This is not implemented. Font Rendering will not be accurate.");
|
||||
idat = offset ? (int16*)(buffer + offset - (curPos - hunkStartPos)) : nullptr;
|
||||
if (idat) {
|
||||
for (int i = 0; i <= (fnt->lastChar - fnt->firstChar) * 2 + 1; ++i)
|
||||
idat[i] = (int16)READ_BE_UINT16(&idat[i]);
|
||||
}
|
||||
fnt->kerning = idat;
|
||||
|
||||
fnt->data = buffer;
|
||||
|
||||
delete str;
|
||||
|
||||
return fnt;
|
||||
}
|
||||
|
||||
void AmigaDOSFont::selectMode(int mode) {
|
||||
if (mode < 0 || mode > _numElements - 1)
|
||||
return;
|
||||
|
||||
_selectedElement = mode;
|
||||
|
||||
_width = _content[mode].data->width;
|
||||
_height = _content[mode].data->height;
|
||||
_first = _content[mode].data->firstChar;
|
||||
_last = _content[mode].data->lastChar;
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_EOB
|
||||
399
engines/kyra/graphics/screen_eob_pc98.cpp
Normal file
399
engines/kyra/graphics/screen_eob_pc98.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef ENABLE_EOB
|
||||
|
||||
#include "kyra/resource/resource.h"
|
||||
#include "graphics/sjis.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
void Screen_EoB::selectPC98Palette(int palID, Palette &dest, int brightness, bool set) {
|
||||
if (palID < 0 || palID > 9)
|
||||
return;
|
||||
if (!_use16ColorMode)
|
||||
return;
|
||||
|
||||
int temp = 0;
|
||||
const uint8 *pal16c = _vm->staticres()->loadRawData(kEoB1Palettes16c, temp);
|
||||
if (!pal16c)
|
||||
return;
|
||||
|
||||
uint8 pal[48];
|
||||
for (int i = 0; i < 48; ++i)
|
||||
pal[i] = CLIP<int>(pal16c[palID * 48 + i] + brightness, 0, 15);
|
||||
loadPalette(pal, dest, 48);
|
||||
|
||||
if (set)
|
||||
setScreenPalette(dest);
|
||||
}
|
||||
|
||||
void Screen_EoB::decodeBIN(const uint8 *src, uint8 *dst, uint16 inSize) {
|
||||
const uint8 *end = src + inSize;
|
||||
memset(_dsTempPage, 0, 2048);
|
||||
int tmpDstOffs = 0;
|
||||
|
||||
while (src < end) {
|
||||
uint8 code = *src++;
|
||||
if (!(code & 0x80)) {
|
||||
int offs = code << 4;
|
||||
code = *src++;
|
||||
offs |= (code >> 4);
|
||||
int len = (code & 0x0F) + 2;
|
||||
int tmpSrcOffs = (tmpDstOffs - offs) & 0x7FF;
|
||||
const uint8 *tmpSrc2 = dst;
|
||||
|
||||
for (int len2 = len; len2; len2--) {
|
||||
*dst++ = _dsTempPage[tmpSrcOffs++];
|
||||
tmpSrcOffs &= 0x7FF;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
_dsTempPage[tmpDstOffs++] = *tmpSrc2++;
|
||||
tmpDstOffs &= 0x7FF;
|
||||
}
|
||||
|
||||
} else if (code & 0x40) {
|
||||
int len = code & 7;
|
||||
if (code & 0x20)
|
||||
len = (len << 8) | *src++;
|
||||
len += 2;
|
||||
|
||||
int planes = ((code >> 3) & 3) + 1;
|
||||
while (len--) {
|
||||
for (int i = 0; i < planes; ++i) {
|
||||
*dst++ = _dsTempPage[tmpDstOffs++] = src[i];
|
||||
tmpDstOffs &= 0x7FF;
|
||||
}
|
||||
}
|
||||
src += planes;
|
||||
} else {
|
||||
for (int len = (code & 0x3F) + 1; len; len--) {
|
||||
*dst++ = _dsTempPage[tmpDstOffs++] = *src++;
|
||||
tmpDstOffs &= 0x7FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_EoB::decodePC98PlanarBitmap(uint8 *srcDstBuffer, uint8 *tmpBuffer, uint16 size) {
|
||||
assert(tmpBuffer != srcDstBuffer);
|
||||
memcpy(tmpBuffer, srcDstBuffer, size);
|
||||
const uint8 *src = tmpBuffer;
|
||||
uint8 *dst1 = srcDstBuffer;
|
||||
uint8 *dst2 = srcDstBuffer + 4;
|
||||
size >>= 3;
|
||||
while (size--) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
uint8 col1 = 0;
|
||||
uint8 col2 = 0;
|
||||
for (int ii = 0; ii < 4; ++ii) {
|
||||
col1 |= ((src[ii] >> (7 - i)) & 1) << ii;
|
||||
col2 |= ((src[ii] >> (3 - i)) & 1) << ii;
|
||||
}
|
||||
*dst1++ = col1;
|
||||
*dst2++ = col2;
|
||||
}
|
||||
src += 4;
|
||||
dst1 += 4;
|
||||
dst2 += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_EoB::initPC98PaletteCycle(int palID, PalCycleData *data) {
|
||||
if (!_use16ColorMode || !_cyclePalette)
|
||||
return;
|
||||
if (palID < 0 || palID > 9)
|
||||
return;
|
||||
|
||||
_activePalCycle = data;
|
||||
int temp = 0;
|
||||
const uint8 *pal16c = _vm->staticres()->loadRawData(kEoB1Palettes16c, temp);
|
||||
if (!pal16c)
|
||||
return;
|
||||
|
||||
if (data)
|
||||
memcpy(_cyclePalette, &pal16c[palID * 48], 48);
|
||||
else
|
||||
memset(_cyclePalette, 0, 48);
|
||||
}
|
||||
|
||||
void Screen_EoB::updatePC98PaletteCycle(int brightness) {
|
||||
if (_activePalCycle) {
|
||||
for (int i = 0; i < 48; ++i) {
|
||||
if (--_activePalCycle[i].delay)
|
||||
continue;
|
||||
for (int8 in = 32; in == 32; ) {
|
||||
in = *_activePalCycle[i].data++;
|
||||
if (in < 16 && in > -16) {
|
||||
_cyclePalette[i] += in;
|
||||
_activePalCycle[i].delay = *_activePalCycle[i].data++;
|
||||
} else if (in < 32) {
|
||||
_cyclePalette[i] = in - 16;
|
||||
_activePalCycle[i].delay = *_activePalCycle[i].data++;
|
||||
} else if (in == 32)
|
||||
_activePalCycle[i].data += READ_BE_INT16(_activePalCycle[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 pal[48];
|
||||
for (int i = 0; i < 48; ++i)
|
||||
pal[i] = CLIP<int>(_cyclePalette[i] + brightness, 0, 15);
|
||||
loadPalette(pal, *_palettes[0], 48);
|
||||
setScreenPalette(*_palettes[0]);
|
||||
}
|
||||
|
||||
SJISFontEoB1PC98::SJISFontEoB1PC98(Common::SharedPtr<Graphics::FontSJIS> &font, /*uint8 shadowColor,*/ const uint16 *convTable1, const uint16 *convTable2) : SJISFont(font, 0, false, false, 0),
|
||||
/*_shadowColor(shadowColor),*/ _convTable1(convTable1), _convTable2(convTable2), _defaultConv(true) {
|
||||
assert(_convTable1);
|
||||
assert(_convTable2);
|
||||
}
|
||||
|
||||
int SJISFontEoB1PC98::getCharWidth(uint16 c) const {
|
||||
return SJISFont::getCharWidth(convert(c));
|
||||
}
|
||||
|
||||
void SJISFontEoB1PC98::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
c = convert(c);
|
||||
_font->setDrawingMode(_style == kStyleLeftShadow ? Graphics::FontSJIS::kShadowLeftMode : Graphics::FontSJIS::kDefaultMode);
|
||||
_font->toggleFatPrint(false);
|
||||
_font->drawChar(dst, c, 640, 1, _colorMap[1], _colorMap[0], 640, 400);
|
||||
}
|
||||
|
||||
uint16 SJISFontEoB1PC98::convert(uint16 c) const {
|
||||
uint8 l = c & 0xFF;
|
||||
uint8 h = c >> 8;
|
||||
|
||||
if (c < 128) {
|
||||
assert(l > 31);
|
||||
c = _convTable2[l - 32];
|
||||
} else if (l > 160 && l < 225) {
|
||||
bool done = false;
|
||||
if (_defaultConv) {
|
||||
if (h == 0xDE) {
|
||||
if ((l >= 182 && l <= 196) || (l >= 202 && l <= 206)) {
|
||||
c = _convTable1[l - 182];
|
||||
done = true;
|
||||
}
|
||||
} else if (h == 0xDF) {
|
||||
if (l >= 202 && l <= 206) {
|
||||
c = _convTable1[l - 177];
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done)
|
||||
c = _convTable2[l - 64];
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
SJISFontEoB2PC98::SJISFontEoB2PC98(Common::SharedPtr<Graphics::FontSJIS> &font, /*uint8 shadowColor,*/ const char *convTable1, const char *convTable2) : SJISFont(font, 0, false, false, 0),
|
||||
/*_shadowColor(shadowColor),*/ _convTable1(convTable1), _convTable2(convTable2)/*, _defaultConv(true)*/ {
|
||||
assert(_convTable1);
|
||||
assert(_convTable2);
|
||||
}
|
||||
|
||||
int SJISFontEoB2PC98::getCharWidth(uint16 c) const {
|
||||
return SJISFont::getCharWidth(convert(c));
|
||||
}
|
||||
|
||||
void SJISFontEoB2PC98::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
SJISFont::drawChar(convert(c), dst, pitch, 0);
|
||||
}
|
||||
|
||||
uint16 SJISFontEoB2PC98::convert(uint16 c) const {
|
||||
uint8 l = c & 0xFF;
|
||||
uint8 h = c >> 8;
|
||||
|
||||
if (h || l < 32 || l == 127) {
|
||||
return c;
|
||||
} else if (l < 127) {
|
||||
c = (l - 32) * 2;
|
||||
assert(c < 190);
|
||||
l = _convTable1[c];
|
||||
h = _convTable1[c + 1];
|
||||
} else if (l < 212) {
|
||||
h = l - 64;
|
||||
l = 0x83;
|
||||
} else {
|
||||
c = (l - 212) * 2;
|
||||
assert(c < 8);
|
||||
l = _convTable2[c];
|
||||
h = _convTable2[c + 1];
|
||||
}
|
||||
|
||||
return (h << 8) | l;
|
||||
}
|
||||
|
||||
Font12x12PC98::Font12x12PC98(uint8 shadowColor, const uint16 *convTable1, const uint16 *convTable2, const uint8 *lookupTable) : OldDOSFont(Common::kRenderDefault, 12), _convTable1(convTable1), _convTable2(convTable2) {
|
||||
assert(convTable1);
|
||||
assert(convTable2);
|
||||
assert(lookupTable);
|
||||
|
||||
_width = _height = 12;
|
||||
_numGlyphs = 275;
|
||||
_bmpOffs = new uint16[_numGlyphs];
|
||||
for (int i = 0; i < _numGlyphs; ++i)
|
||||
_bmpOffs[i] = lookupTable[i] * 24;
|
||||
}
|
||||
|
||||
Font12x12PC98::~Font12x12PC98() {
|
||||
delete[] _bmpOffs;
|
||||
}
|
||||
|
||||
bool Font12x12PC98::load(Common::SeekableReadStream &file) {
|
||||
unload();
|
||||
|
||||
_width = _height = 12;
|
||||
_numGlyphs = 275;
|
||||
_bitmapOffsets = _bmpOffs;
|
||||
|
||||
_data = new uint8[file.size()];
|
||||
assert(_data);
|
||||
|
||||
file.read(_data, file.size());
|
||||
if (file.err())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 Font12x12PC98::convert(uint16 c) const {
|
||||
uint8 l = c & 0xFF;
|
||||
uint8 h = c >> 8;
|
||||
|
||||
if (c < 128) {
|
||||
c = _convTable2[l - 32];
|
||||
} else if (l > 160 && l < 225) {
|
||||
bool done = false;
|
||||
if (h == 0xDE) {
|
||||
if ((l >= 182 && l <= 196) || (l >= 202 && l <= 206)) {
|
||||
c = _convTable1[l - 182];
|
||||
done = true;
|
||||
}
|
||||
} else if (h == 0xDF) {
|
||||
if (l >= 202 && l <= 206) {
|
||||
c = _convTable1[l - 177];
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (!done)
|
||||
c = _convTable2[l - 64];
|
||||
}
|
||||
|
||||
c = SWAP_BYTES_16(c);
|
||||
if (c < 0x813F)
|
||||
c = 1;
|
||||
else if (c < 0x824F)
|
||||
c -= 0x813F;
|
||||
else if (c < 0x833F)
|
||||
c -= 0x81EE;
|
||||
else if (c > 0x839F)
|
||||
c = 1;
|
||||
else
|
||||
c -= 0x828D;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
PC98Font::PC98Font(uint8 shadowColor, bool useOverlay, int scaleV, const uint8 *convTable1, const char *convTable2, const char *convTable3) : OldDOSFont(Common::kRenderVGA, shadowColor),
|
||||
_convTable1(convTable1), _convTable2(convTable2), _convTable3(convTable3), _outputWidth(0), _outputHeight(0), _type(convTable1 && convTable2 && convTable3 ? kSJIS : kASCII) {
|
||||
_numGlyphsMax = 256;
|
||||
_useOverlay = useOverlay;
|
||||
_scaleV = scaleV;
|
||||
|
||||
}
|
||||
|
||||
bool PC98Font::load(Common::SeekableReadStream &file) {
|
||||
bool res = OldDOSFont::load(file);
|
||||
|
||||
_outputWidth = _width;
|
||||
_outputHeight = _height * _scaleV;
|
||||
|
||||
if (_useOverlay) {
|
||||
_outputWidth >>= 1;
|
||||
_outputHeight >>= 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16 PC98Font::convert(uint16 c) const {
|
||||
if (_type == kSJIS)
|
||||
c = makeTwoByte(c);
|
||||
|
||||
if (!_convTable1 || c < 128)
|
||||
return c;
|
||||
|
||||
uint8 lo = c & 0xff;
|
||||
uint8 hi = c >> 8;
|
||||
|
||||
if (lo == 0x81) {
|
||||
if (hi >= 0x40 && hi <= 0xac)
|
||||
return _convTable1[hi - 0x40];
|
||||
} else if (lo == 0x82) {
|
||||
if (hi >= 0x4f && hi <= 0x58)
|
||||
return hi - 31;
|
||||
if (hi >= 0x60 && hi <= 0x79)
|
||||
return hi - 31;
|
||||
if (hi >= 0x81 && hi <= 0x9a)
|
||||
return hi - 32;
|
||||
} else if (lo == 0x83 && hi >= 0x40 && hi <= 0x93) {
|
||||
return hi + 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 PC98Font::makeTwoByte(uint16 c) const {
|
||||
if (!_convTable2 || !_convTable3)
|
||||
return c;
|
||||
|
||||
uint8 l = c & 0xFF;
|
||||
uint8 h = c >> 8;
|
||||
|
||||
if (h || l < 32 || l == 127) {
|
||||
return c;
|
||||
} else if (l < 127) {
|
||||
c = (l - 32) * 2;
|
||||
assert(c < 190);
|
||||
l = _convTable2[c];
|
||||
h = _convTable2[c + 1];
|
||||
} else if (l < 212) {
|
||||
h = l - 64;
|
||||
l = 0x83;
|
||||
} else {
|
||||
c = (l - 212) * 2;
|
||||
assert(c < 8);
|
||||
l = _convTable3[c];
|
||||
h = _convTable3[c + 1];
|
||||
}
|
||||
|
||||
return (h << 8) | l;
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_EOB
|
||||
1276
engines/kyra/graphics/screen_eob_segacd.cpp
Normal file
1276
engines/kyra/graphics/screen_eob_segacd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
212
engines/kyra/graphics/screen_eob_segacd.h
Normal file
212
engines/kyra/graphics/screen_eob_segacd.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_EOB_SEGACD_H
|
||||
#define KYRA_SCREEN_EOB_SEGACD_H
|
||||
|
||||
#ifdef ENABLE_EOB
|
||||
|
||||
#define SEGA_PERFORMANCE true
|
||||
#define SEGA_USE_MEMPOOL true
|
||||
|
||||
#include "kyra/graphics/screen_eob.h"
|
||||
|
||||
#if SEGA_USE_MEMPOOL
|
||||
#include "common/memorypool.h"
|
||||
#endif
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class SegaRenderer {
|
||||
public:
|
||||
enum Plane {
|
||||
kPlaneA = 0,
|
||||
kPlaneB = 1,
|
||||
kWindowPlane = 2
|
||||
};
|
||||
|
||||
enum WindowMode {
|
||||
kWinToLeft = 0,
|
||||
kWinToTop = 0,
|
||||
kWinToRight = 1,
|
||||
kWinToBottom = 1
|
||||
};
|
||||
|
||||
enum HScrollMode {
|
||||
kHScrollFullScreen = 0,
|
||||
kHScroll8PixelRows,
|
||||
kHScroll1PixelRows
|
||||
};
|
||||
|
||||
enum VScrollMode {
|
||||
kVScrollFullScreen = 0,
|
||||
kVScroll16PixelStrips
|
||||
};
|
||||
|
||||
public:
|
||||
SegaRenderer(Screen_EoB *screen);
|
||||
~SegaRenderer();
|
||||
|
||||
void setResolution(int w, int h);
|
||||
void setPlaneTableLocation(int plane, uint16 addr);
|
||||
// The hardware allows/demands separate modification of the vertical and horizontal properties.
|
||||
// To allow this without making another function the w/h parameters can be set to -1 which will
|
||||
// keep the existing value for that property.
|
||||
void setupPlaneAB(int pixelWidth, int pixelHeigth);
|
||||
// The hardware allows/demands separate modification of the vertical and horizontal properties.
|
||||
// To allow this without making another function the blockX/Y parameters can be set to -1 which
|
||||
// will keep the existing value for that property.
|
||||
void setupWindowPlane(int blockX, int blockY, int horizontalMode, int verticalMode);
|
||||
void setHScrollTableLocation(int addr);
|
||||
void setSpriteTableLocation(int addr);
|
||||
void setPitch(int pitch);
|
||||
void setHScrollMode(int mode);
|
||||
void setVScrollMode(int mode);
|
||||
|
||||
void loadToVRAM(const void *data, uint16 dataSize, uint16 addr);
|
||||
void loadStreamToVRAM(Common::SeekableReadStream *in, uint16 addr, bool compressedData = false);
|
||||
void memsetVRAM(int addr, uint8 val, int len);
|
||||
void fillRectWithTiles(int vramArea, int x, int y, int w, int h, uint16 nameTblEntry, bool incr = false, bool topToBottom = false, const uint16 *patternTable = 0);
|
||||
void writeUint16VSRAM(int addr, uint16 value);
|
||||
void writeUint8VRAM(int addr, uint8 value);
|
||||
void writeUint16VRAM(int addr, uint16 value);
|
||||
void clearPlanes();
|
||||
|
||||
void render(int destPageNum, int renderLeft = -1, int renderTop = -1, int renderWidth = -1, int renderHeight = -1, bool spritesOnly = false);
|
||||
private:
|
||||
void renderPlanePart(int plane, uint8 *dstBuffer, int x1, int y1, int x2, int y2);
|
||||
void renderPlaneTile(uint8 *dst, int destX, const uint16 *nameTable, int vScrollLSBStart, int vScrollLSBEnd, int hScrollTableIndex, uint16 pitch);
|
||||
void renderSpriteTile(uint8 *dst, uint8 *mask, int x, int y, uint16 tile, uint8 pal, bool vflip, bool hflip, bool prio);
|
||||
#if SEGA_PERFORMANCE
|
||||
template<bool hflip, bool oddStart, bool oddEnd> void renderLineFragmentM(uint8 *dst, uint8 *mask, const uint8 *src, int start, int end, uint8 pal);
|
||||
template<bool hflip, bool oddStart, bool oddEnd> void renderLineFragmentD(uint8 *dst, const uint8 *src, int start, int end, uint8 pal);
|
||||
typedef void(SegaRenderer::*renderFuncM)(uint8*, uint8*, const uint8*, int, int, uint8);
|
||||
typedef void(SegaRenderer::*renderFuncD)(uint8*, const uint8*, int, int, uint8);
|
||||
const renderFuncM *_renderLineFragmentM;
|
||||
const renderFuncD *_renderLineFragmentD;
|
||||
#else
|
||||
template<bool hflip> void renderLineFragment(uint8 *dst, uint8 *mask, const uint8 *src, int start, int end, uint8 pal);
|
||||
#endif
|
||||
|
||||
void initPrioRenderTask(uint8 *dst, uint8 *mask, const uint8 *src, int start, int end, uint8 pal, bool hflip);
|
||||
void clearPrioChain();
|
||||
|
||||
struct SegaPlane {
|
||||
SegaPlane() : blockX(0), blockY(0), w(0), h(0), mod(0), nameTable(0), nameTableSize(0) {}
|
||||
int blockX, blockY;
|
||||
uint16 w, h, mod;
|
||||
uint16 *nameTable;
|
||||
uint16 nameTableSize;
|
||||
};
|
||||
|
||||
SegaPlane _planes[3];
|
||||
uint8 *_vram;
|
||||
uint16 *_vsram;
|
||||
uint16 *_hScrollTable;
|
||||
uint16 *_spriteTable;
|
||||
uint8 *_spriteMask;
|
||||
uint8 _hScrollMode;
|
||||
uint8 _vScrollMode;
|
||||
uint16 _pitch;
|
||||
uint16 _numSpritesMax;
|
||||
|
||||
struct PrioTileRenderObj {
|
||||
PrioTileRenderObj(PrioTileRenderObj *chainEnd, uint8 *dst, uint8 *mask, const uint8 *src, int start, int end, uint8 pal, bool hflip) :
|
||||
_pred(chainEnd), _next(0), _dst(dst), _mask(mask), _src(src), _start(start), _end(end), _pal(pal), _hflip(hflip) {
|
||||
if (_pred)
|
||||
_pred->_next = this;
|
||||
}
|
||||
uint8 *_dst;
|
||||
uint8 *_mask;
|
||||
const uint8 *_src;
|
||||
int _start;
|
||||
int _end;
|
||||
uint8 _pal;
|
||||
bool _hflip;
|
||||
PrioTileRenderObj *_pred;
|
||||
PrioTileRenderObj *_next;
|
||||
};
|
||||
|
||||
#if SEGA_USE_MEMPOOL
|
||||
Common::ObjectPool<PrioTileRenderObj> _prioRenderMemPool;
|
||||
#endif
|
||||
PrioTileRenderObj *_prioChainStart, *_prioChainEnd;
|
||||
uint16 _screenW, _screenH, _blocksW, _blocksH;
|
||||
Screen_EoB *_screen;
|
||||
};
|
||||
|
||||
class SegaAnimator {
|
||||
public:
|
||||
SegaAnimator(SegaRenderer *renderer);
|
||||
~SegaAnimator();
|
||||
|
||||
void initSprite(int id, int16 x, int16 y, uint16 nameTbl, uint16 hw);
|
||||
void clearSprites();
|
||||
void moveMorphSprite(int id, uint16 nameTbl, int16 addX, int16 addY);
|
||||
void moveSprites(int id, uint16 num, int16 addX, int16 addY);
|
||||
void moveSprites2(int id, uint16 num, int16 addX, int16 addY);
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
struct Sprite {
|
||||
int16 x;
|
||||
int16 y;
|
||||
uint16 nameTbl;
|
||||
uint16 hw;
|
||||
};
|
||||
|
||||
uint16 *_tempBuffer;
|
||||
Sprite *_sprites;
|
||||
SegaRenderer *_renderer;
|
||||
bool _needUpdate;
|
||||
};
|
||||
|
||||
class ScrollManager {
|
||||
public:
|
||||
ScrollManager(SegaRenderer *renderer);
|
||||
~ScrollManager();
|
||||
|
||||
void setVScrollTimers(uint16 destA, int incrA, int delayA, uint16 destB, int incrB, int delayB);
|
||||
void setHScrollTimers(uint16 destA, int incrA, int delayA, uint16 destB, int incrB, int delayB);
|
||||
void updateScrollTimers();
|
||||
void fastForward();
|
||||
|
||||
private:
|
||||
struct ScrollTimer {
|
||||
ScrollTimer() : _offsCur(0), _offsDest(0), _incr(0), _delay(0), _timer(0) {}
|
||||
int16 _offsCur;
|
||||
int16 _offsDest;
|
||||
int16 _incr;
|
||||
int16 _delay;
|
||||
int16 _timer;
|
||||
};
|
||||
|
||||
ScrollTimer *_vScrollTimers;
|
||||
ScrollTimer *_hScrollTimers;
|
||||
SegaRenderer *_renderer;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_EOB
|
||||
|
||||
#endif
|
||||
173
engines/kyra/graphics/screen_eob_towns.cpp
Normal file
173
engines/kyra/graphics/screen_eob_towns.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef ENABLE_EOB
|
||||
|
||||
#include "kyra/resource/resource.h"
|
||||
#include "graphics/sjis.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
void Screen_EoB::decodeSHP(const uint8 *data, int dstPage) {
|
||||
int32 bytesLeft = READ_LE_UINT32(data);
|
||||
const uint8 *src = data + 4;
|
||||
uint8 *dst = getPagePtr(dstPage);
|
||||
|
||||
if (bytesLeft < 0) {
|
||||
memcpy(dst, data, 64000);
|
||||
return;
|
||||
}
|
||||
|
||||
while (bytesLeft > 0) {
|
||||
uint8 code = *src++;
|
||||
bytesLeft--;
|
||||
|
||||
for (int i = 8; i; i--) {
|
||||
if (code & 0x80) {
|
||||
uint16 copyOffs = (src[0] << 4) | (src[1] >> 4);
|
||||
uint8 count = (src[1] & 0x0F) + 3;
|
||||
src += 2;
|
||||
bytesLeft -= 2;
|
||||
const uint8 *copySrc = dst - 1 - copyOffs;
|
||||
while (count--)
|
||||
*dst++ = *copySrc++;
|
||||
} else if (bytesLeft) {
|
||||
*dst++ = *src++;
|
||||
bytesLeft--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
code <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_EoB::convertToHiColor(int page) {
|
||||
if (!_16bitPalette)
|
||||
return;
|
||||
uint16 *dst = (uint16 *)getPagePtr(page);
|
||||
memcpy(_convertHiColorBuffer, dst, SCREEN_H * SCREEN_W);
|
||||
uint8 *src = _convertHiColorBuffer;
|
||||
for (int s = SCREEN_H * SCREEN_W; s; --s)
|
||||
*dst++ = _16bitPalette[*src++];
|
||||
}
|
||||
|
||||
void Screen_EoB::shadeRect(int x1, int y1, int x2, int y2, int shadingLevel) {
|
||||
if (!_16bitPalette)
|
||||
return;
|
||||
|
||||
int l = _16bitShadingLevel;
|
||||
_16bitShadingLevel = shadingLevel;
|
||||
|
||||
if (_curPage == 0 || _curPage == 1)
|
||||
addDirtyRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
|
||||
uint16 *dst = (uint16*)(getPagePtr(_curPage) + y1 * SCREEN_W * _bytesPerPixel + x1 * _bytesPerPixel);
|
||||
|
||||
for (; y1 < y2; ++y1) {
|
||||
uint16 *ptr = dst;
|
||||
for (int i = 0; i < x2 - x1; i++) {
|
||||
*ptr = shade16bitColor(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
dst += SCREEN_W;
|
||||
}
|
||||
|
||||
_16bitShadingLevel = l;
|
||||
}
|
||||
|
||||
SJISFontLarge::SJISFontLarge(Common::SharedPtr<Graphics::FontSJIS> &font) : SJISFont(font, 0, false, false, 0) {
|
||||
}
|
||||
|
||||
int SJISFontLarge::getHeight() const {
|
||||
return _font->getFontHeight();
|
||||
}
|
||||
|
||||
int SJISFontLarge::getWidth() const {
|
||||
return _font->getMaxFontWidth();
|
||||
}
|
||||
|
||||
int SJISFontLarge::getCharWidth(uint16 c) const {
|
||||
if (c <= 0x7F || (c >= 0xA1 && c <= 0xDF))
|
||||
return _font->getCharWidth('a');
|
||||
else
|
||||
return getWidth();
|
||||
}
|
||||
|
||||
void SJISFontLarge::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
_font->setDrawingMode(Graphics::FontSJIS::kDefaultMode);
|
||||
_font->toggleFatPrint(false);
|
||||
_font->drawChar(dst, c, 320, 1, _colorMap[1], _colorMap[0], 320, 200);
|
||||
}
|
||||
|
||||
SJISFont12x12::SJISFont12x12(const uint16 *searchTable) : _height(6), _width(6), _data(0), _colorMap(nullptr) {
|
||||
assert(searchTable);
|
||||
for (int i = 0; i < 148; i++)
|
||||
_searchTable[searchTable[i]] = i + 1;
|
||||
}
|
||||
|
||||
bool SJISFont12x12::load(Common::SeekableReadStream &file) {
|
||||
delete[] _data;
|
||||
int size = 148 * 24;
|
||||
if (file.size() < size)
|
||||
return false;
|
||||
|
||||
_data = new uint8[size];
|
||||
file.read(_data, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SJISFont12x12::unload() {
|
||||
delete[] _data;
|
||||
_data = 0;
|
||||
_searchTable.clear();
|
||||
}
|
||||
|
||||
void SJISFont12x12::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
if (!_searchTable.contains(c))
|
||||
return;
|
||||
|
||||
const uint8 *src = _data + (_searchTable[c] - 1) * 24;
|
||||
uint8 color1 = _colorMap[1];
|
||||
|
||||
int bt = 0;
|
||||
uint16 chr = 0;
|
||||
|
||||
for (int i = 0; i < 192; ++i) {
|
||||
if (!bt) {
|
||||
chr = *src++;
|
||||
bt = 8;
|
||||
}
|
||||
if (chr & 0x80)
|
||||
*dst = color1;
|
||||
dst++;
|
||||
if (--bt)
|
||||
chr <<= 1;
|
||||
else if (i & 8)
|
||||
dst += (pitch - 16);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_EOB
|
||||
112
engines/kyra/graphics/screen_hof.cpp
Normal file
112
engines/kyra/graphics/screen_hof.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/graphics/screen_hof.h"
|
||||
#include "kyra/engine/kyra_hof.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Screen_HoF::Screen_HoF(KyraEngine_HoF *vm, OSystem *system)
|
||||
: Screen_v2(vm, system, _screenDimTable, _screenDimTableCount), _vm(vm) {
|
||||
}
|
||||
|
||||
void Screen_HoF::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag) {
|
||||
Palette tmpPal(lastColor);
|
||||
|
||||
for (int i = 0; i != lastColor; i++) {
|
||||
if (flag) {
|
||||
int v = ((((srcPal[3 * i] & 0x3F) + (srcPal[3 * i + 1] & 0x3F)
|
||||
+ (srcPal[3 * i + 2] & 0x3F)) / 3) * factor) / 0x40;
|
||||
tmpPal[3 * i] = tmpPal[3 * i + 1] = tmpPal[3 * i + 2] = v & 0xFF;
|
||||
} else {
|
||||
int v = (((srcPal[3 * i] & 0x3F) * factor) / 0x40) + addR;
|
||||
tmpPal[3 * i] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
v = (((srcPal[3 * i + 1] & 0x3F) * factor) / 0x40) + addG;
|
||||
tmpPal[3 * i + 1] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
v = (((srcPal[3 * i + 2] & 0x3F) * factor) / 0x40) + addB;
|
||||
tmpPal[3 * i + 2] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < lastColor; i++)
|
||||
grayOverlay[i] = findLeastDifferentColor(tmpPal.getData() + 3 * i, srcPal, 0, lastColor);
|
||||
}
|
||||
|
||||
void Screen_HoF::cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int srcY, int dstPage, int dstW,
|
||||
int dstH, int dstX, int dstY, int cmpW, int cmpH, int cmpPage) {
|
||||
|
||||
if (!cmpW || !cmpH)
|
||||
return;
|
||||
|
||||
int r1, r2, r3, r4, r5, r6;
|
||||
|
||||
int X1 = srcX;
|
||||
int Y1 = srcY;
|
||||
int W1 = cmpW;
|
||||
int H1 = cmpH;
|
||||
|
||||
if (!calcBounds(srcW, srcH, X1, Y1, W1, H1, r1, r2, r3))
|
||||
return;
|
||||
|
||||
int X2 = dstX;
|
||||
int Y2 = dstY;
|
||||
int W2 = W1;
|
||||
int H2 = H1;
|
||||
|
||||
if (!calcBounds(dstW, dstH, X2, Y2, W2, H2, r4, r5, r6))
|
||||
return;
|
||||
|
||||
const uint8 *src = getPagePtr(srcPage) + srcW * (Y1 + r5);
|
||||
uint8 *dst = getPagePtr(dstPage) + dstW * (Y2 + r2);
|
||||
const uint8 *cmp = getPagePtr(cmpPage);
|
||||
|
||||
while (H2--) {
|
||||
const uint8 *s = src + r4 + X1;
|
||||
uint8 *d = dst + r1 + X2;
|
||||
|
||||
for (int i = 0; i < W2; i++) {
|
||||
int ix = (*s++ << 8) + *d;
|
||||
*d++ = cmp[ix];
|
||||
}
|
||||
|
||||
src += W1;
|
||||
dst += W2;
|
||||
}
|
||||
}
|
||||
|
||||
void ChineseOneByteFontHOF::processColorMap() {
|
||||
_textColor[0] = _colorMap[1];
|
||||
_textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
|
||||
_pixelColorShading = false;
|
||||
}
|
||||
|
||||
uint32 ChineseTwoByteFontHOF::getFontOffset(uint16 c) const {
|
||||
c = ((c & 0x7F00) >> 2) | (c & 0x3F);
|
||||
return c * 28;
|
||||
}
|
||||
|
||||
void ChineseTwoByteFontHOF::processColorMap() {
|
||||
_textColor[0] = TO_LE_16(_colorMap[1] | ((_colorMap[1] + 1) << 8));
|
||||
_textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
|
||||
_pixelColorShading = !(_colorMap[1] == 207 || _colorMap[1] > 240);
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
49
engines/kyra/graphics/screen_hof.h
Normal file
49
engines/kyra/graphics/screen_hof.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_HOF_H
|
||||
#define KYRA_SCREEN_HOF_H
|
||||
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class KyraEngine_HoF;
|
||||
|
||||
class Screen_HoF : public Screen_v2 {
|
||||
friend class Debugger_v2;
|
||||
public:
|
||||
Screen_HoF(KyraEngine_HoF *vm, OSystem *system);
|
||||
|
||||
// sequence player
|
||||
void generateGrayOverlay(const Palette &pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag);
|
||||
void cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int srcY, int dstPage, int dstW, int dstH, int dstX, int dstY, int cmpW, int cmpH, int cmpPage);
|
||||
|
||||
private:
|
||||
KyraEngine_HoF *_vm;
|
||||
|
||||
static const ScreenDim _screenDimTable[];
|
||||
static const int _screenDimTableCount;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
679
engines/kyra/graphics/screen_lok.cpp
Normal file
679
engines/kyra/graphics/screen_lok.cpp
Normal file
@@ -0,0 +1,679 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/graphics/screen_lok.h"
|
||||
#include "kyra/engine/kyra_lok.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Screen_LoK::Screen_LoK(KyraEngine_LoK *vm, OSystem *system)
|
||||
: Screen(vm, system, _screenDimTable, _screenDimTableCount) {
|
||||
_vm = vm;
|
||||
_unkPtr1 = _unkPtr2 = nullptr;
|
||||
_bitBlitNum = 0;
|
||||
memset(_saveLoadPage, 0, sizeof(_saveLoadPage));
|
||||
memset(_saveLoadPageOvl, 0, sizeof(_saveLoadPageOvl));
|
||||
}
|
||||
|
||||
Screen_LoK::~Screen_LoK() {
|
||||
for (int i = 0; i < ARRAYSIZE(_saveLoadPage); ++i) {
|
||||
delete[] _saveLoadPage[i];
|
||||
_saveLoadPage[i] = nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveLoadPageOvl); ++i) {
|
||||
delete[] _saveLoadPageOvl[i];
|
||||
_saveLoadPageOvl[i] = nullptr;
|
||||
}
|
||||
|
||||
delete[] _unkPtr1;
|
||||
delete[] _unkPtr2;
|
||||
}
|
||||
|
||||
bool Screen_LoK::init() {
|
||||
if (!Screen::init())
|
||||
return false;
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_bitBlitRects); i++) {
|
||||
_bitBlitRects[i].left = 0;
|
||||
_bitBlitRects[i].top = 0;
|
||||
_bitBlitRects[i].right = 0;
|
||||
_bitBlitRects[i].bottom = 0;
|
||||
}
|
||||
_bitBlitNum = 0;
|
||||
memset(_saveLoadPage, 0, sizeof(_saveLoadPage));
|
||||
memset(_saveLoadPageOvl, 0, sizeof(_saveLoadPageOvl));
|
||||
|
||||
_unkPtr1 = new uint8[getRectSize(1, 144)]();
|
||||
assert(_unkPtr1);
|
||||
_unkPtr2 = new uint8[getRectSize(1, 144)]();
|
||||
assert(_unkPtr2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Screen_LoK::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) {
|
||||
const char *ext = filename + strlen(filename) - 3;
|
||||
|
||||
Screen::loadBitmap(filename, tempPage, dstPage, pal, skip);
|
||||
|
||||
if (_isAmiga) {
|
||||
if (!scumm_stricmp(ext, "MSC"))
|
||||
Screen::convertAmigaMsc(getPagePtr(dstPage));
|
||||
else
|
||||
Screen::convertAmigaGfx(getPagePtr(dstPage), 320, 200);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime) {
|
||||
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
|
||||
return;
|
||||
|
||||
assert(_vm->palTable1()[palIndex]);
|
||||
|
||||
Palette tempPal(getPalette(0).getNumColors());
|
||||
tempPal.copy(getPalette(0));
|
||||
tempPal.copy(_vm->palTable1()[palIndex], 0, size, startIndex);
|
||||
|
||||
fadePalette(tempPal, fadeTime * 18);
|
||||
|
||||
getPalette(0).copy(tempPal, startIndex, size);
|
||||
setScreenPalette(getPalette(0));
|
||||
updateBackendScreen(true);
|
||||
}
|
||||
|
||||
void Screen_LoK::addBitBlitRect(int x, int y, int w, int h) {
|
||||
if (_bitBlitNum >= kNumBitBlitRects)
|
||||
error("too many bit blit rects");
|
||||
|
||||
_bitBlitRects[_bitBlitNum].left = x;
|
||||
_bitBlitRects[_bitBlitNum].top = y;
|
||||
_bitBlitRects[_bitBlitNum].right = x + w;
|
||||
_bitBlitRects[_bitBlitNum].bottom = y + h;
|
||||
++_bitBlitNum;
|
||||
}
|
||||
|
||||
void Screen_LoK::bitBlitRects() {
|
||||
Common::Rect *cur = _bitBlitRects;
|
||||
while (_bitBlitNum) {
|
||||
_bitBlitNum--;
|
||||
copyRegion(cur->left, cur->top, cur->left, cur->top, cur->width(), cur->height(), 2, 0);
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK::savePageToDisk(const char *file, int page) {
|
||||
if (!_saveLoadPage[page / 2]) {
|
||||
_saveLoadPage[page / 2] = new uint8[SCREEN_W * SCREEN_H];
|
||||
assert(_saveLoadPage[page / 2]);
|
||||
}
|
||||
memcpy(_saveLoadPage[page / 2], getPagePtr(page), SCREEN_W * SCREEN_H);
|
||||
|
||||
if (_useOverlays) {
|
||||
if (!_saveLoadPageOvl[page / 2]) {
|
||||
_saveLoadPageOvl[page / 2] = new uint8[SCREEN_OVL_SJIS_SIZE];
|
||||
assert(_saveLoadPageOvl[page / 2]);
|
||||
}
|
||||
|
||||
uint8 *srcPage = getOverlayPtr(page);
|
||||
if (!srcPage) {
|
||||
warning("trying to save unsupported overlay page %d", page);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(_saveLoadPageOvl[page / 2], srcPage, SCREEN_OVL_SJIS_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK::loadPageFromDisk(const char *file, int page) {
|
||||
if (!_saveLoadPage[page / 2]) {
|
||||
warning("trying to restore page %d, but no backup found", page);
|
||||
return;
|
||||
}
|
||||
|
||||
copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page / 2]);
|
||||
delete[] _saveLoadPage[page / 2];
|
||||
_saveLoadPage[page / 2] = nullptr;
|
||||
|
||||
if (_saveLoadPageOvl[page / 2]) {
|
||||
uint8 *dstPage = getOverlayPtr(page);
|
||||
if (!dstPage) {
|
||||
warning("trying to restore unsupported overlay page %d", page);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dstPage, _saveLoadPageOvl[page / 2], SCREEN_OVL_SJIS_SIZE);
|
||||
delete[] _saveLoadPageOvl[page / 2];
|
||||
_saveLoadPageOvl[page / 2] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) {
|
||||
if (!_saveLoadPage[page / 2]) {
|
||||
warning("trying to query page %d, but no backup found", page);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(buffer, _saveLoadPage[page / 2], SCREEN_W * SCREEN_H);
|
||||
}
|
||||
|
||||
void Screen_LoK::deletePageFromDisk(int page) {
|
||||
delete[] _saveLoadPage[page / 2];
|
||||
_saveLoadPage[page / 2] = nullptr;
|
||||
|
||||
if (_saveLoadPageOvl[page / 2]) {
|
||||
delete[] _saveLoadPageOvl[page / 2];
|
||||
_saveLoadPageOvl[page / 2] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK::copyBackgroundBlock(int x, int page, int flag) {
|
||||
if (x < 1)
|
||||
return;
|
||||
|
||||
int height = 128;
|
||||
if (flag)
|
||||
height += 8;
|
||||
if (!(x & 1))
|
||||
++x;
|
||||
if (x == 19)
|
||||
x = 17;
|
||||
|
||||
uint8 *ptr1 = _unkPtr1;
|
||||
uint8 *ptr2 = _unkPtr2;
|
||||
int oldVideoPage = _curPage;
|
||||
_curPage = page;
|
||||
|
||||
int curX = x;
|
||||
copyRegionToBuffer(_curPage, 8, 8, 8, height, ptr2);
|
||||
for (int i = 0; i < 19; ++i) {
|
||||
int tempX = curX + 1;
|
||||
copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr1);
|
||||
copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr2);
|
||||
int newXPos = curX + x;
|
||||
if (newXPos > 37)
|
||||
newXPos = newXPos % 38;
|
||||
|
||||
tempX = newXPos + 1;
|
||||
copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr2);
|
||||
copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr1);
|
||||
curX += x * 2;
|
||||
if (curX > 37) {
|
||||
curX = curX % 38;
|
||||
}
|
||||
}
|
||||
_curPage = oldVideoPage;
|
||||
}
|
||||
|
||||
void Screen_LoK::copyBackgroundBlock2(int x) {
|
||||
copyBackgroundBlock(x, 4, 1);
|
||||
}
|
||||
|
||||
void Screen_LoK::setTextColorMap(const uint8 *cmap) {
|
||||
setTextColor(cmap, 0, 11);
|
||||
}
|
||||
|
||||
int Screen_LoK::getRectSize(int x, int y) {
|
||||
if (x < 1)
|
||||
x = 1;
|
||||
else if (x > 40)
|
||||
x = 40;
|
||||
|
||||
if (y < 1)
|
||||
y = 1;
|
||||
else if (y > 200)
|
||||
y = 200;
|
||||
|
||||
return ((x * y) << 3);
|
||||
}
|
||||
|
||||
void Screen_LoK::setInterfacePalette(const Palette &pal, uint8 r, uint8 g, uint8 b) {
|
||||
if (!_isAmiga)
|
||||
return;
|
||||
|
||||
uint8 screenPal[32 * 3];
|
||||
|
||||
assert(32 <= pal.getNumColors());
|
||||
|
||||
for (int i = 0; i < pal.getNumColors(); ++i) {
|
||||
if (i != 0x10) {
|
||||
screenPal[3 * i + 0] = (pal[i * 3 + 0] * 0xFF) / 0x3F;
|
||||
screenPal[3 * i + 1] = (pal[i * 3 + 1] * 0xFF) / 0x3F;
|
||||
screenPal[3 * i + 2] = (pal[i * 3 + 2] * 0xFF) / 0x3F;
|
||||
} else {
|
||||
screenPal[3 * i + 0] = (r * 0xFF) / 0x3F;
|
||||
screenPal[3 * i + 1] = (g * 0xFF) / 0x3F;
|
||||
screenPal[3 * i + 2] = (b * 0xFF) / 0x3F;
|
||||
}
|
||||
}
|
||||
|
||||
_paletteChanged = true;
|
||||
_system->getPaletteManager()->setPalette(screenPal, 32, pal.getNumColors());
|
||||
}
|
||||
|
||||
void Screen_LoK::postProcessCursor(uint8 *data, int width, int height, int pitch) {
|
||||
if (_vm->gameFlags().platform == Common::kPlatformAmiga && _dualPaletteModeSplitY) {
|
||||
pitch -= width;
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
if (*data != _cursorColorKey)
|
||||
*data += 32;
|
||||
++data;
|
||||
}
|
||||
|
||||
data += pitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
Screen_LoK_16::Screen_LoK_16(KyraEngine_LoK *vm, OSystem *system) : Screen_LoK(vm, system) {
|
||||
memset(_paletteDither, 0, sizeof(_paletteDither));
|
||||
}
|
||||
|
||||
void Screen_LoK_16::setScreenPalette(const Palette &pal) {
|
||||
_screenPalette->copy(pal);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2);
|
||||
|
||||
set16ColorPalette(_palette16);
|
||||
_forceFullUpdate = true;
|
||||
}
|
||||
|
||||
void Screen_LoK_16::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) {
|
||||
uint8 notBlackFlag = 0;
|
||||
for (int i = 0; i < 768; ++i) {
|
||||
if ((*_screenPalette)[i])
|
||||
notBlackFlag |= 1;
|
||||
if (pal[i])
|
||||
notBlackFlag |= 2;
|
||||
}
|
||||
|
||||
if (notBlackFlag == 1 || notBlackFlag == 2) {
|
||||
bool upFade = false;
|
||||
|
||||
for (int i = 0; i < 768; ++i) {
|
||||
if ((*_screenPalette)[i] < pal[i]) {
|
||||
upFade = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (upFade) {
|
||||
for (int i = 0; i < 256; ++i)
|
||||
paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2);
|
||||
_forceFullUpdate = true;
|
||||
}
|
||||
|
||||
uint8 color16Palette[16 * 3];
|
||||
|
||||
if (upFade)
|
||||
memset(color16Palette, 0, sizeof(color16Palette));
|
||||
else
|
||||
memcpy(color16Palette, _palette16, sizeof(color16Palette));
|
||||
|
||||
set16ColorPalette(color16Palette);
|
||||
updateScreen();
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
set16ColorPalette(color16Palette);
|
||||
|
||||
for (int k = 0; k < 48; ++k) {
|
||||
if (upFade) {
|
||||
if (color16Palette[k] < _palette16[k])
|
||||
++color16Palette[k];
|
||||
} else {
|
||||
if (color16Palette[k] > 0)
|
||||
--color16Palette[k];
|
||||
}
|
||||
}
|
||||
|
||||
if (upFunc && upFunc->isValid())
|
||||
(*upFunc)();
|
||||
else
|
||||
updateBackendScreen(true);
|
||||
|
||||
_vm->delay((delay >> 5) * _vm->tickLength());
|
||||
}
|
||||
}
|
||||
|
||||
setScreenPalette(pal);
|
||||
}
|
||||
|
||||
void Screen_LoK_16::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) {
|
||||
error("Screen_LoK_16::getFadeParams called");
|
||||
}
|
||||
|
||||
int Screen_LoK_16::fadePalStep(const Palette &pal, int diff) {
|
||||
error("Screen_LoK_16::fadePalStep called");
|
||||
return 0; // for compilers that don't support NORETURN
|
||||
}
|
||||
|
||||
void Screen_LoK_16::paletteMap(uint8 idx, int r, int g, int b) {
|
||||
const int red = r;
|
||||
const int green = g;
|
||||
const int blue = b;
|
||||
|
||||
uint16 rgbDiff = 1000;
|
||||
int rDiff = 0, gDiff = 0, bDiff = 0;
|
||||
|
||||
int index1 = -1;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const int realR = _palette16[i * 3 + 0] << 4;
|
||||
const int realG = _palette16[i * 3 + 1] << 4;
|
||||
const int realB = _palette16[i * 3 + 2] << 4;
|
||||
|
||||
uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB);
|
||||
|
||||
if (diff < rgbDiff) {
|
||||
rgbDiff = diff;
|
||||
index1 = i;
|
||||
|
||||
rDiff = r - realR;
|
||||
gDiff = g - realG;
|
||||
bDiff = b - realB;
|
||||
}
|
||||
}
|
||||
|
||||
r = rDiff / 4 + red;
|
||||
g = gDiff / 4 + green;
|
||||
b = bDiff / 4 + blue;
|
||||
|
||||
rgbDiff = 1000;
|
||||
int index2 = -1;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const int realR = _palette16[i * 3 + 0] << 4;
|
||||
const int realG = _palette16[i * 3 + 1] << 4;
|
||||
const int realB = _palette16[i * 3 + 2] << 4;
|
||||
|
||||
uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB);
|
||||
|
||||
if (diff < rgbDiff) {
|
||||
rgbDiff = diff;
|
||||
index2 = i;
|
||||
}
|
||||
}
|
||||
|
||||
_paletteDither[idx].bestMatch = index1;
|
||||
_paletteDither[idx].invertMatch = index2;
|
||||
}
|
||||
|
||||
void Screen_LoK_16::convertTo16Colors(uint8 *page, int w, int h, int pitch, int keyColor) {
|
||||
const int rowAdd = pitch * 2 - w;
|
||||
|
||||
uint8 *row1 = page;
|
||||
uint8 *row2 = page + pitch;
|
||||
|
||||
for (int i = 0; i < h; i += 2) {
|
||||
for (int k = 0; k < w; k += 2) {
|
||||
if (keyColor == -1 || keyColor != *row1) {
|
||||
const PaletteDither &dither = _paletteDither[*row1];
|
||||
|
||||
*row1++ = dither.bestMatch;
|
||||
*row1++ = dither.invertMatch;
|
||||
*row2++ = dither.invertMatch;
|
||||
*row2++ = dither.bestMatch;
|
||||
} else {
|
||||
row1 += 2;
|
||||
row2 += 2;
|
||||
}
|
||||
}
|
||||
|
||||
row1 += rowAdd;
|
||||
row2 += rowAdd;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK_16::mergeOverlay(int x, int y, int w, int h) {
|
||||
byte *dst = _sjisOverlayPtrs[0] + y * 640 + x;
|
||||
|
||||
// We do a game screen rect to 16 color dithering here. It is
|
||||
// important that we do not dither the overlay, since else the
|
||||
// japanese fonts will look wrong.
|
||||
convertTo16Colors(dst, w, h, 640);
|
||||
|
||||
const byte *src = _sjisOverlayPtrs[1] + y * 640 + x;
|
||||
|
||||
int add = 640 - w;
|
||||
|
||||
while (h--) {
|
||||
for (x = 0; x < w; ++x, ++dst) {
|
||||
byte col = *src++;
|
||||
if (col != _sjisInvisibleColor)
|
||||
*dst = _paletteDither[col].bestMatch;
|
||||
}
|
||||
dst += add;
|
||||
src += add;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoK_16::set16ColorPalette(const uint8 *pal) {
|
||||
uint8 palette[16 * 3];
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
palette[i * 3 + 0] = (pal[i * 3 + 0] * 0xFF) / 0x0F;
|
||||
palette[i * 3 + 1] = (pal[i * 3 + 1] * 0xFF) / 0x0F;
|
||||
palette[i * 3 + 2] = (pal[i * 3 + 2] * 0xFF) / 0x0F;
|
||||
}
|
||||
|
||||
_system->getPaletteManager()->setPalette(palette, 0, 16);
|
||||
}
|
||||
|
||||
ChineseOneByteFontLoK::ChineseOneByteFontLoK(int pitch) : ChineseFont(pitch, 8, 14, 9, 17, 0, 0) {
|
||||
_border = _pixelColorShading = false;
|
||||
}
|
||||
|
||||
void ChineseOneByteFontLoK::processColorMap() {
|
||||
_textColor[0] = _colorMap[1];
|
||||
_textColor[1] = _colorMap[0];
|
||||
}
|
||||
|
||||
ChineseTwoByteFontLoK::ChineseTwoByteFontLoK(int pitch, const uint16 *lookupTable, uint32 lookupTableSize) : ChineseFont(pitch, 15, 14, 18, 17, 0, 3),
|
||||
_lookupTable(lookupTable), _lookupTableSize(lookupTableSize) {
|
||||
assert(lookupTable);
|
||||
}
|
||||
|
||||
bool ChineseTwoByteFontLoK::hasGlyphForCharacter(uint16 c) const {
|
||||
for (uint32 i = 0; i < _lookupTableSize; ++i) {
|
||||
if (_lookupTable[i] == c)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 ChineseTwoByteFontLoK::getFontOffset(uint16 c) const {
|
||||
for (uint32 i = 0; i < _lookupTableSize; ++i) {
|
||||
if (_lookupTable[i] == c)
|
||||
return i * 28;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ChineseTwoByteFontLoK::processColorMap() {
|
||||
_border = (_colorMap[0] == 12);
|
||||
uint8 cs = _colorMap[1];
|
||||
|
||||
if (_colorMap[1] == 9)
|
||||
cs = 83;
|
||||
else if (_colorMap[1] == 5)
|
||||
cs = 207;
|
||||
else if (_colorMap[1] == 2)
|
||||
cs = 74;
|
||||
else if (_colorMap[1] == 15)
|
||||
cs = 161;
|
||||
else if (_colorMap[1] > 15 && _colorMap[1] < 248)
|
||||
cs += 1;
|
||||
|
||||
_textColor[0] = _colorMap[1] | (cs << 8);
|
||||
_textColor[0] = TO_LE_16(_textColor[0]);
|
||||
_textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
|
||||
}
|
||||
|
||||
JohabFontLoK::JohabFontLoK(Font *&font8fat, const uint16 *lookupTable, uint32 lookupTableSize) : _font8fat(font8fat), _height(15), _width(15), _fileData(0), _colorMap(0), _glyphTemp(0) {
|
||||
assert(lookupTable);
|
||||
assert(lookupTableSize == 224);
|
||||
for (int i = 0; i < 7; ++i)
|
||||
_2byteTables[i] = &lookupTable[i << 5];
|
||||
memset(_glyphData, 0, sizeof(_glyphData));
|
||||
_glyphTemp = new uint8[30];
|
||||
}
|
||||
|
||||
JohabFontLoK::~JohabFontLoK() {
|
||||
delete[] _fileData;
|
||||
delete[] _glyphTemp;
|
||||
}
|
||||
|
||||
bool JohabFontLoK::load(Common::SeekableReadStream &data) {
|
||||
if (_fileData)
|
||||
return false;
|
||||
|
||||
if (!data.size())
|
||||
return false;
|
||||
|
||||
uint32 fileSize = data.size();
|
||||
|
||||
if (fileSize != (kNumJongseong + kNumJungseong + kNumChoseong) * 30) {
|
||||
warning("HangulFontLoK::load(): Invalid font file size '%d' (expected: '%d').", fileSize, (kNumJongseong + kNumJungseong + kNumChoseong) * 30);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 *dst = new uint8[fileSize];
|
||||
if (!dst)
|
||||
return false;
|
||||
|
||||
data.read(dst, fileSize);
|
||||
_fileData = dst;
|
||||
|
||||
_glyphData[0] = _fileData;
|
||||
_glyphData[1] = _glyphData[0] + (kNumJongseong * 30);
|
||||
_glyphData[2] = _glyphData[1] + (kNumJungseong * 30);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int JohabFontLoK::getCharWidth(uint16 c) const {
|
||||
assert(_font8fat);
|
||||
return (c >= 0x80) ? _width + 1 : _font8fat->getCharWidth(c);
|
||||
}
|
||||
|
||||
int JohabFontLoK::getCharHeight(uint16 c) const {
|
||||
return _colorMap[3] ? _height + 2 : _height;
|
||||
}
|
||||
|
||||
void JohabFontLoK::setColorMap(const uint8 *src) {
|
||||
_colorMap = src;
|
||||
assert(_font8fat);
|
||||
_font8fat->setColorMap(src);
|
||||
}
|
||||
|
||||
void JohabFontLoK::drawChar(uint16 c, byte *dst, int pitch, int) const {
|
||||
if (c < 0x80) {
|
||||
assert(_font8fat);
|
||||
_font8fat->drawChar(c, dst + (c == '\"' ? 0 : 5) * pitch, pitch, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8 *glyph = createGlyph(c);
|
||||
dst += (pitch + 1);
|
||||
|
||||
if (_colorMap[3]) {
|
||||
renderGlyph(dst - 1, glyph, _colorMap[3], pitch);
|
||||
renderGlyph(dst + 1, glyph, _colorMap[3], pitch);
|
||||
renderGlyph(dst - pitch, glyph, _colorMap[3], pitch);
|
||||
renderGlyph(dst + pitch, glyph, _colorMap[3], pitch);
|
||||
}
|
||||
|
||||
renderGlyph(dst, glyph, _colorMap[1], pitch);
|
||||
}
|
||||
|
||||
const uint8 *JohabFontLoK::createGlyph(uint16 chr) const {
|
||||
memset(_glyphTemp, 0, 30);
|
||||
|
||||
uint16 t[3];
|
||||
memset(t, 0, sizeof(t));
|
||||
|
||||
chr = (chr << 8) | (chr >> 8);
|
||||
uint8 i1 = chr & 0x1f;
|
||||
uint8 i2 = (chr >> 5) & 0x1f;
|
||||
uint8 i3 = (chr >> 10) & 0x1f;
|
||||
|
||||
// determine jungseong glyph part
|
||||
uint16 r1 = _2byteTables[1][i2];
|
||||
if ((int16)r1 > 0)
|
||||
r1 += (_2byteTables[3][i3] + _2byteTables[6][i1] - 3);
|
||||
|
||||
// determine jongseong glyph part
|
||||
uint16 r2 = _2byteTables[0][i3];
|
||||
if ((int16)r2 > 0)
|
||||
r2 += (_2byteTables[4][i2] + _2byteTables[6][i1]);
|
||||
|
||||
// determine choseong glyph part
|
||||
uint16 r3 = _2byteTables[2][i1];
|
||||
if ((int16)r3 > 0)
|
||||
r3 += (_2byteTables[5][i2] - 3);
|
||||
|
||||
t[0] = r2 >> 5;
|
||||
t[1] = (r1 >> 5) - 2;
|
||||
t[2] = (r3 >> 5) - 2;
|
||||
|
||||
const uint8 lim[3] = { kNumJongseong, kNumJungseong, kNumChoseong };
|
||||
|
||||
for (int l = 0; l < 3; ++l) {
|
||||
if (t[l] <= lim[l]) {
|
||||
const uint8 *src = &_glyphData[l][t[l] * 30];
|
||||
for (int i = 0; i < 30; ++i)
|
||||
_glyphTemp[i] |= *src++;
|
||||
}
|
||||
}
|
||||
|
||||
return _glyphTemp;
|
||||
}
|
||||
|
||||
void JohabFontLoK::renderGlyph(byte *dst, const uint8 *glyph, uint8 col, int pitch) const {
|
||||
const uint8 *src = glyph;
|
||||
pitch -= 15;
|
||||
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
uint8 m = 0;
|
||||
uint8 in = 0;
|
||||
for (int x = 0; x < _width; ++x) {
|
||||
if (m == 0) {
|
||||
in = *src++;
|
||||
m = 0x80;
|
||||
}
|
||||
if (in & m)
|
||||
*dst = col;
|
||||
dst++;
|
||||
m >>= 1;
|
||||
}
|
||||
dst += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
113
engines/kyra/graphics/screen_lok.h
Normal file
113
engines/kyra/graphics/screen_lok.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_LOK_H
|
||||
#define KYRA_SCREEN_LOK_H
|
||||
|
||||
#include "kyra/graphics/screen.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class KyraEngine_LoK;
|
||||
|
||||
class Screen_LoK : public Screen {
|
||||
public:
|
||||
Screen_LoK(KyraEngine_LoK *vm, OSystem *system);
|
||||
~Screen_LoK() override;
|
||||
|
||||
bool init() override;
|
||||
|
||||
void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip = false) override;
|
||||
|
||||
int getRectSize(int w, int h) override;
|
||||
|
||||
void setTextColorMap(const uint8 *cmap) override;
|
||||
|
||||
void fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime);
|
||||
|
||||
void savePageToDisk(const char *file, int page);
|
||||
void loadPageFromDisk(const char *file, int page);
|
||||
void queryPageFromDisk(const char *file, int page, uint8 *buffer);
|
||||
void deletePageFromDisk(int page);
|
||||
|
||||
void copyBackgroundBlock(int x, int page, int flag);
|
||||
void copyBackgroundBlock2(int x);
|
||||
|
||||
void addBitBlitRect(int x, int y, int w, int h);
|
||||
void bitBlitRects();
|
||||
|
||||
// AMIGA specific
|
||||
void setInterfacePalette(const Palette &pal, uint8 r, uint8 g, uint8 b);
|
||||
void postProcessCursor(uint8 *data, int width, int height, int pitch) override;
|
||||
|
||||
protected:
|
||||
enum {
|
||||
kNumBitBlitRects = 10
|
||||
};
|
||||
|
||||
KyraEngine_LoK *_vm;
|
||||
|
||||
static const ScreenDim _screenDimTable[];
|
||||
static const int _screenDimTableCount;
|
||||
|
||||
Common::Rect _bitBlitRects[kNumBitBlitRects];
|
||||
int _bitBlitNum;
|
||||
uint8 *_unkPtr1, *_unkPtr2;
|
||||
|
||||
uint8 *_saveLoadPage[8];
|
||||
uint8 *_saveLoadPageOvl[8];
|
||||
};
|
||||
|
||||
class Screen_LoK_16 : public Screen_LoK {
|
||||
public:
|
||||
Screen_LoK_16(KyraEngine_LoK *vm, OSystem *system);
|
||||
|
||||
void setScreenPalette(const Palette &pal) override;
|
||||
|
||||
void fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc = 0) override;
|
||||
void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) override;
|
||||
int fadePalStep(const Palette &pal, int diff) override;
|
||||
private:
|
||||
void updateDirtyRectsOvl();
|
||||
|
||||
void convertTo16Colors(uint8 *page, int w, int h, int pitch, int keyColor = -1);
|
||||
void postProcessCursor(uint8 *data, int width, int height, int pitch) override {
|
||||
convertTo16Colors(data, width, height, pitch, _cursorColorKey);
|
||||
}
|
||||
void mergeOverlay(int x, int y, int w, int h) override;
|
||||
|
||||
void set16ColorPalette(const uint8 *pal);
|
||||
|
||||
void paletteMap(uint8 idx, int r, int g, int b);
|
||||
|
||||
struct PaletteDither {
|
||||
uint8 bestMatch;
|
||||
uint8 invertMatch;
|
||||
};
|
||||
|
||||
PaletteDither _paletteDither[256];
|
||||
|
||||
static const uint8 _palette16[48];
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
904
engines/kyra/graphics/screen_lol.cpp
Normal file
904
engines/kyra/graphics/screen_lol.cpp
Normal file
@@ -0,0 +1,904 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
|
||||
#include "kyra/graphics/screen_lol.h"
|
||||
#include "kyra/engine/lol.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : vm->gameFlags().lang == Common::Language::ZH_TWN ? _screenDimTableZH : _screenDimTable256C, _screenDimTableCount) {
|
||||
_paletteOverlay1 = new uint8[0x100]();
|
||||
_paletteOverlay2 = new uint8[0x100]();
|
||||
_grayOverlay = new uint8[0x100]();
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
_levelOverlays[i] = new uint8[256];
|
||||
|
||||
_fadeFlag = 2;
|
||||
}
|
||||
|
||||
Screen_LoL::~Screen_LoL() {
|
||||
for (int i = 0; i < 8; i++)
|
||||
delete[] _levelOverlays[i];
|
||||
|
||||
delete[] _paletteOverlay1;
|
||||
delete[] _paletteOverlay2;
|
||||
delete[] _grayOverlay;
|
||||
}
|
||||
|
||||
void Screen_LoL::fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint flags, ...) {
|
||||
if (!format)
|
||||
return;
|
||||
|
||||
char string[240];
|
||||
va_list vaList;
|
||||
va_start(vaList, flags);
|
||||
vsnprintf(string, sizeof(string), format, vaList);
|
||||
va_end(vaList);
|
||||
|
||||
if (flags & 1)
|
||||
x -= (getTextWidth(string) >> 1);
|
||||
|
||||
if (flags & 2)
|
||||
x -= getTextWidth(string);
|
||||
|
||||
if (_use16ColorMode) {
|
||||
if (flags & 12) {
|
||||
printText(string, x - 1, y, 0x44, col2);
|
||||
printText(string, x, y + 1, 0x44, col2);
|
||||
}
|
||||
} else {
|
||||
if (flags & 4) {
|
||||
printText(string, x - 1, y, 1, col2);
|
||||
printText(string, x, y + 1, 1, col2);
|
||||
}
|
||||
|
||||
if (flags & 8) {
|
||||
printText(string, x - 1, y, 227, col2);
|
||||
printText(string, x, y + 1, 227, col2);
|
||||
}
|
||||
}
|
||||
|
||||
printText(string, x, y, col1, col2);
|
||||
}
|
||||
|
||||
void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint flags, ...) {
|
||||
char buffer[400];
|
||||
|
||||
va_list args;
|
||||
va_start(args, flags);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
if ((flags & 0x0F00) == 0x100)
|
||||
x -= getTextWidth(buffer) >> 1;
|
||||
if ((flags & 0x0F00) == 0x200)
|
||||
x -= getTextWidth(buffer);
|
||||
|
||||
if ((flags & 0x00F0) == 0x20) {
|
||||
printText(buffer, x - 1, y, c3, c2);
|
||||
printText(buffer, x, y + 1, c3, c2);
|
||||
}
|
||||
|
||||
printText(buffer, x, y, c1, c2);
|
||||
}
|
||||
|
||||
void Screen_LoL::drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2) {
|
||||
assert(x1 >= 0 && y1 >= 0);
|
||||
hideMouse();
|
||||
|
||||
fillRect(x1, y1, x2, y1 + 1, color1);
|
||||
fillRect(x1, y1, x1 + 1, y2, color1);
|
||||
|
||||
drawClippedLine(x2, y1, x2, y2, color2);
|
||||
drawClippedLine(x2 - 1, y1 + 1, x2 - 1, y2 - 1, color2);
|
||||
drawClippedLine(x1 + 1, y2 - 1, x2, y2 - 1, color2);
|
||||
drawClippedLine(x1, y2, x2, y2, color2);
|
||||
|
||||
if (_use16ColorMode && color1 > color2)
|
||||
drawBox(x1, y1, x2, y2, 0x44);
|
||||
|
||||
showMouse();
|
||||
}
|
||||
|
||||
void Screen_LoL::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors) {
|
||||
Palette tmpPal(lastColor);
|
||||
|
||||
for (int i = 0; i != lastColor; i++) {
|
||||
int v = (((srcPal[3 * i] & 0x3F) * factor) / 0x40) + addR;
|
||||
tmpPal[3 * i] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
v = (((srcPal[3 * i + 1] & 0x3F) * factor) / 0x40) + addG;
|
||||
tmpPal[3 * i + 1] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
v = (((srcPal[3 * i + 2] & 0x3F) * factor) / 0x40) + addB;
|
||||
tmpPal[3 * i + 2] = (v > 0x3F) ? 0x3F : v & 0xFF;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lastColor; i++)
|
||||
grayOverlay[i] = findLeastDifferentColor(tmpPal.getData() + 3 * i, srcPal, 0, lastColor, skipSpecialColors);
|
||||
}
|
||||
|
||||
void Screen_LoL::createTransparencyTablesIntern(const uint8 *ovl, int a, const uint8 *fxPal1, const uint8 *fxPal2, uint8 *outTable1, uint8 *outTable2, int b) {
|
||||
Palette screenPal(256);
|
||||
screenPal.copy(fxPal2, 0, 256);
|
||||
|
||||
memset(outTable1, 0xFF, 256);
|
||||
|
||||
for (int i = 0; i < a; i++)
|
||||
outTable1[ovl[i]] = i;
|
||||
|
||||
for (int i = 0; i < a; i++) {
|
||||
if (ovl[i]) {
|
||||
uint8 tcol[3];
|
||||
uint16 fcol[3];
|
||||
uint16 scol[3];
|
||||
|
||||
uint16 t1 = (b << 6) / 100;
|
||||
uint16 t2 = 64 - t1;
|
||||
|
||||
uint8 c = ovl[i];
|
||||
fcol[0] = fxPal1[3 * c];
|
||||
fcol[1] = fxPal1[3 * c + 1];
|
||||
fcol[2] = fxPal1[3 * c + 2];
|
||||
|
||||
uint8 *o = &outTable2[i << 8];
|
||||
|
||||
for (int ii = 0; ii < 256; ii++) {
|
||||
scol[0] = screenPal[3 * ii];
|
||||
scol[1] = screenPal[3 * ii + 1];
|
||||
scol[2] = screenPal[3 * ii + 2];
|
||||
|
||||
tcol[0] = CLIP(((fcol[0] * t2) >> 6) + ((scol[0] * t1) >> 6), 0, 63);
|
||||
tcol[1] = CLIP(((fcol[1] * t2) >> 6) + ((scol[1] * t1) >> 6), 0, 63);
|
||||
tcol[2] = CLIP(((fcol[2] * t2) >> 6) + ((scol[2] * t1) >> 6), 0, 63);
|
||||
|
||||
o[ii] = findLeastDifferentColor(tcol, screenPal, 0, 255);
|
||||
}
|
||||
|
||||
} else {
|
||||
memset(&outTable2[i << 8], 0, 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::drawGridBox(int x, int y, int w, int h, int col) {
|
||||
if (w <= 0 || x >= 320 || h <= 0 || y >= 200)
|
||||
return;
|
||||
|
||||
if (x < 0) {
|
||||
x += w;
|
||||
if (x <= 0)
|
||||
return;
|
||||
w = x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
int tmp = x + w;
|
||||
if (tmp >= 320) {
|
||||
w = 320 - x;
|
||||
}
|
||||
|
||||
int pitch = 320 - w;
|
||||
|
||||
if (y < 0) {
|
||||
y += h;
|
||||
if (y <= 0)
|
||||
return;
|
||||
h = y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
tmp = y + h;
|
||||
if (tmp >= 200) {
|
||||
h = 200 - y;
|
||||
}
|
||||
|
||||
tmp = (y + x) & 1;
|
||||
uint8 *p = getPagePtr(_curPage) + y * 320 + x;
|
||||
bool oddWidth = w & 1;
|
||||
|
||||
w >>= 1;
|
||||
int w2 = w;
|
||||
|
||||
while (h--) {
|
||||
if (w) {
|
||||
while (w--) {
|
||||
*(p + tmp) = col;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (oddWidth) {
|
||||
if (tmp == 0)
|
||||
*p = col;
|
||||
p++;
|
||||
}
|
||||
tmp ^= 1;
|
||||
p += pitch;
|
||||
w = w2;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::fadeClearSceneWindow(int delay) {
|
||||
if (_fadeFlag == 1)
|
||||
return;
|
||||
|
||||
if (_use16ColorMode) {
|
||||
fadeToBlack(delay);
|
||||
fillRect(112, 0, 288, 120, 0x44);
|
||||
} else {
|
||||
Palette tpal(getPalette(0).getNumColors());
|
||||
tpal.copy(getPalette(0), 128);
|
||||
|
||||
loadSpecialColors(tpal);
|
||||
fadePalette(tpal, delay);
|
||||
|
||||
fillRect(112, 0, 288, 120, 0);
|
||||
}
|
||||
|
||||
_fadeFlag = 1;
|
||||
}
|
||||
|
||||
void Screen_LoL::backupSceneWindow(int srcPageNum, int dstPageNum) {
|
||||
uint8 *src = getPagePtr(srcPageNum) + 112;
|
||||
uint8 *dst = getPagePtr(dstPageNum) + 0xA500;
|
||||
|
||||
for (int h = 0; h < 120; h++) {
|
||||
for (int w = 0; w < 176; w++)
|
||||
*dst++ = *src++;
|
||||
src += 144;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::restoreSceneWindow(int srcPageNum, int dstPageNum) {
|
||||
uint8 *src = getPagePtr(srcPageNum) + 0xA500;
|
||||
uint8 *dst = getPagePtr(dstPageNum) + 112;
|
||||
|
||||
for (int h = 0; h < 120; h++) {
|
||||
memcpy(dst, src, 176);
|
||||
src += 176;
|
||||
dst += 320;
|
||||
}
|
||||
|
||||
if (!dstPageNum)
|
||||
addDirtyRect(112, 0, 176, 120);
|
||||
}
|
||||
|
||||
void Screen_LoL::clearGuiShapeMemory(int pageNum) {
|
||||
uint8 *dst = getPagePtr(pageNum) + 0x79B0;
|
||||
for (int i = 0; i < 23; i++) {
|
||||
memset(dst, 0, 176);
|
||||
dst += 320;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::copyGuiShapeFromSceneBackupBuffer(int srcPageNum, int dstPageNum) {
|
||||
uint8 *src = getPagePtr(srcPageNum) + 0x79C3;
|
||||
uint8 *dst = getPagePtr(dstPageNum);
|
||||
|
||||
for (int i = 0; i < 23; i++) {
|
||||
uint8 len = 0;
|
||||
uint8 v = 0;
|
||||
|
||||
do {
|
||||
v = *src++;
|
||||
len++;
|
||||
} while (!v);
|
||||
|
||||
*dst++ = len;
|
||||
|
||||
len = 69 - len;
|
||||
memcpy(dst, src, len);
|
||||
src += (len + 251);
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::copyGuiShapeToSurface(int srcPageNum, int dstPageNum) {
|
||||
uint8 *src = getPagePtr(srcPageNum);
|
||||
uint8 *dst = getPagePtr(dstPageNum) + 0xE7C3;
|
||||
|
||||
for (int i = 0; i < 23; i++) {
|
||||
uint8 v = *src++;
|
||||
uint8 len = 69 - v;
|
||||
dst += v;
|
||||
memcpy(dst, src, len);
|
||||
src += (len - 1);
|
||||
dst += len;
|
||||
|
||||
for (int ii = 0; ii < len; ii++)
|
||||
*dst++ = *src--;
|
||||
|
||||
src += (len + 1);
|
||||
dst += (v + 38);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollZoomStepTop(int srcPageNum, int dstPageNum, int x, int y) {
|
||||
uint8 *src = getPagePtr(srcPageNum) + 0xA500 + y * 176 + x;
|
||||
uint8 *dst = getPagePtr(dstPageNum) + 0xA500;
|
||||
|
||||
x <<= 1;
|
||||
uint16 width = 176 - x;
|
||||
uint16 scaleX = (((x + 1) << 8) / width + 0x100);
|
||||
uint16 cntW = scaleX >> 8;
|
||||
scaleX <<= 8;
|
||||
width--;
|
||||
uint16 widthCnt = width;
|
||||
|
||||
uint16 height = 46 - y;
|
||||
uint16 scaleY = (((y + 1) << 8) / height + 0x100);
|
||||
scaleY <<= 8;
|
||||
|
||||
uint32 scaleYc = 0;
|
||||
while (height) {
|
||||
uint32 scaleXc = 0;
|
||||
do {
|
||||
scaleXc += scaleX;
|
||||
int numbytes = cntW + (scaleXc >> 16);
|
||||
scaleXc &= 0xFFFF;
|
||||
memset(dst, *src++, numbytes);
|
||||
dst += numbytes;
|
||||
} while (--widthCnt);
|
||||
|
||||
*dst++ = *src++;
|
||||
widthCnt = width;
|
||||
|
||||
src += x;
|
||||
scaleYc += scaleY;
|
||||
|
||||
if (scaleYc >> 16) {
|
||||
scaleYc = 0;
|
||||
src -= 176;
|
||||
continue;
|
||||
}
|
||||
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollZoomStepBottom(int srcPageNum, int dstPageNum, int x, int y) {
|
||||
uint8 *src = getPagePtr(srcPageNum) + 0xC4A0 + x;
|
||||
uint8 *dst = getPagePtr(dstPageNum) + 0xC4A0;
|
||||
|
||||
x <<= 1;
|
||||
uint16 width = 176 - x;
|
||||
uint16 scaleX = (((x + 1) << 8) / width + 0x100);
|
||||
uint16 cntW = scaleX >> 8;
|
||||
scaleX <<= 8;
|
||||
width--;
|
||||
uint16 widthCnt = width;
|
||||
|
||||
uint16 height = 74 - y;
|
||||
uint16 scaleY = (((y + 1) << 8) / height + 0x100);
|
||||
scaleY <<= 8;
|
||||
|
||||
uint32 scaleYc = 0;
|
||||
while (height) {
|
||||
uint32 scaleXc = 0;
|
||||
do {
|
||||
scaleXc += scaleX;
|
||||
int numbytes = cntW + (scaleXc >> 16);
|
||||
scaleXc &= 0xFFFF;
|
||||
memset(dst, *src++, numbytes);
|
||||
dst += numbytes;
|
||||
} while (--widthCnt);
|
||||
|
||||
*dst++ = *src++;
|
||||
widthCnt = width;
|
||||
|
||||
src += x;
|
||||
scaleYc += scaleY;
|
||||
|
||||
if (scaleYc >> 16) {
|
||||
scaleYc = 0;
|
||||
src -= 176;
|
||||
continue;
|
||||
}
|
||||
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollHorizontalStep(int pageNum, int srcX, int dstX, int w) {
|
||||
uint8 *d = getPagePtr(pageNum);
|
||||
uint8 *s = d + 112 + srcX;
|
||||
|
||||
int w2 = srcX + w - dstX;
|
||||
int pitchS = 320 + w2 - (w << 1);
|
||||
|
||||
int pitchD = 320 - w;
|
||||
int h = 120;
|
||||
|
||||
while (h--) {
|
||||
for (int i = 0; i < w; i++)
|
||||
*d++ = *s++;
|
||||
d -= w;
|
||||
s -= w2;
|
||||
|
||||
for (int i = 0; i < w; i++)
|
||||
*s++ = *d++;
|
||||
|
||||
s += pitchS;
|
||||
d += pitchD;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollTurnStep1(int srcPage1Num, int srcPage2Num, int dstPageNum) {
|
||||
uint8 *s = getPagePtr(srcPage1Num) + 273;
|
||||
uint8 *d = getPagePtr(dstPageNum) + 0xA500;
|
||||
|
||||
for (int i = 0; i < 120; i++) {
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
|
||||
for (int ii = 0; ii < 14; ii++) {
|
||||
a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
}
|
||||
|
||||
s += 305;
|
||||
d += 132;
|
||||
}
|
||||
|
||||
s = getPagePtr(srcPage2Num) + 112;
|
||||
d = getPagePtr(dstPageNum) + 0xA52C;
|
||||
|
||||
for (int i = 0; i < 120; i++) {
|
||||
for (int ii = 0; ii < 33; ii++) {
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
}
|
||||
|
||||
s += 221;
|
||||
d += 44;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollTurnStep2(int srcPage1Num, int srcPage2Num, int dstPageNum) {
|
||||
uint8 *s = getPagePtr(srcPage1Num) + 244;
|
||||
uint8 *d = getPagePtr(dstPageNum) + 0xA500;
|
||||
|
||||
for (int k = 0; k < 2; k++) {
|
||||
for (int i = 0; i < 120; i++) {
|
||||
for (int ii = 0; ii < 44; ii++) {
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
}
|
||||
|
||||
s += 276;
|
||||
d += 88;
|
||||
}
|
||||
|
||||
s = getPagePtr(srcPage2Num) + 112;
|
||||
d = getPagePtr(dstPageNum) + 0xA558;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::smoothScrollTurnStep3(int srcPage1Num, int srcPage2Num, int dstPageNum) {
|
||||
uint8 *s = getPagePtr(srcPage1Num) + 189;
|
||||
uint8 *d = getPagePtr(dstPageNum) + 0xA500;
|
||||
|
||||
for (int i = 0; i < 120; i++) {
|
||||
for (int ii = 0; ii < 33; ii++) {
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
}
|
||||
|
||||
s += 221;
|
||||
d += 44;
|
||||
}
|
||||
|
||||
s = getPagePtr(srcPage2Num) + 112;
|
||||
d = getPagePtr(dstPageNum) + 0xA584;
|
||||
|
||||
for (int i = 0; i < 120; i++) {
|
||||
for (int ii = 0; ii < 14; ii++) {
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
}
|
||||
|
||||
uint8 a = *s++;
|
||||
*d++ = a;
|
||||
*d++ = a;
|
||||
|
||||
s += 305;
|
||||
d += 132;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::copyRegionSpecial(int page1, int w1, int h1, int x1, int y1, int page2, int w2, int h2, int x2, int y2, int w3, int h3, int mode, ...) {
|
||||
if (!w3 || !h3)
|
||||
return;
|
||||
|
||||
uint8 *table1 = 0;
|
||||
uint8 *table2 = 0;
|
||||
|
||||
if (mode == 2) {
|
||||
va_list args;
|
||||
va_start(args, mode);
|
||||
table1 = va_arg(args, uint8 *);
|
||||
table2 = va_arg(args, uint8 *);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int na = 0, nb = 0, nc = w3;
|
||||
if (!calcBounds(w1, h1, x1, y1, w3, h3, na, nb, nc))
|
||||
return;
|
||||
|
||||
int iu5_1 = na;
|
||||
int iu6_1 = nb;
|
||||
int ibw_1 = w3;
|
||||
int dx_1 = x1;
|
||||
int dy_1 = y1;
|
||||
|
||||
if (!calcBounds(w2, h2, x2, y2, w3, h3, na, nb, nc))
|
||||
return;
|
||||
|
||||
int iu5_2 = na;
|
||||
int iu6_2 = nb;
|
||||
int ibw_2 = w3;
|
||||
int ibh_2 = h3;
|
||||
int dx_2 = x2;
|
||||
int dy_2 = y2;
|
||||
|
||||
uint8 *src = getPagePtr(page1) + (dy_1 + iu6_2) * w1;
|
||||
uint8 *dst = getPagePtr(page2) + (dy_2 + iu6_1) * w2;
|
||||
|
||||
for (int i = 0; i < ibh_2; i++) {
|
||||
uint8 *s = src + iu5_2 + dx_1;
|
||||
uint8 *d = dst + iu5_1 + dx_2;
|
||||
|
||||
if (mode == 0) {
|
||||
memcpy(d, s, ibw_2);
|
||||
|
||||
} else if (mode == 1) {
|
||||
if (!(i & 1)) {
|
||||
s++;
|
||||
d++;
|
||||
}
|
||||
|
||||
for (int ii = (i & 1) ^ 1; ii < ibw_2; ii += 2) {
|
||||
*d = *s;
|
||||
d += 2;
|
||||
s += 2;
|
||||
}
|
||||
|
||||
} else if (mode == 2) {
|
||||
for (int ii = 0; ii < ibw_2; ii++) {
|
||||
uint8 cmd = *s++;
|
||||
uint8 offs = table1[cmd];
|
||||
if (!(offs & 0x80))
|
||||
cmd = table2[(offs << 8) | *d];
|
||||
*d++ = cmd;
|
||||
}
|
||||
|
||||
} else if (mode == 3) {
|
||||
s = s - iu5_2 + ibw_1;
|
||||
s = s - iu5_2 - 1;
|
||||
for (int ii = 0; ii < ibw_2; ii++)
|
||||
*d++ = *s--;
|
||||
}
|
||||
|
||||
dst += w2;
|
||||
src += w1;
|
||||
}
|
||||
|
||||
if (!page2)
|
||||
addDirtyRect(x2, y2, w2, h2);
|
||||
}
|
||||
|
||||
void Screen_LoL::copyBlockAndApplyOverlay(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, uint8 *ovl) {
|
||||
if (!w || !h || !ovl)
|
||||
return;
|
||||
|
||||
const ScreenDim *cdim = getScreenDim(dim);
|
||||
int ix = cdim->sx << 3;
|
||||
int iy = cdim->sy;
|
||||
int iw = cdim->w << 3;
|
||||
int ih = cdim->h;
|
||||
|
||||
int na = 0, nb = 0, nc = w;
|
||||
if (!calcBounds(iw, ih, x2, y2, w, h, na, nb, nc))
|
||||
return;
|
||||
|
||||
uint8 *src = getPagePtr(page1) + y1 * 320 + x1;
|
||||
uint8 *dst = getPagePtr(page2) + (y2 + iy) * 320;
|
||||
|
||||
for (int i = 0; i < h; i++) {
|
||||
uint8 *s = src + na;
|
||||
uint8 *d = dst + (x2 + ix);
|
||||
|
||||
for (int ii = 0; ii < w; ii++) {
|
||||
uint8 p = ovl[*s++];
|
||||
if (p)
|
||||
*d = p;
|
||||
d++;
|
||||
}
|
||||
|
||||
dst += 320;
|
||||
src += 320;
|
||||
}
|
||||
|
||||
if (!page2)
|
||||
addDirtyRect(x2 + ix, y2 + iy, w, h);
|
||||
}
|
||||
|
||||
void Screen_LoL::applyOverlaySpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, int flag, uint8 *ovl) {
|
||||
if (!w || !h || !ovl)
|
||||
return;
|
||||
|
||||
const ScreenDim *cdim = getScreenDim(dim);
|
||||
int ix = cdim->sx << 3;
|
||||
int iy = cdim->sy;
|
||||
int iw = cdim->w << 3;
|
||||
int ih = cdim->h;
|
||||
|
||||
int na = 0, nb = 0, nc = w;
|
||||
if (!calcBounds(iw, ih, x2, y2, w, h, na, nb, nc))
|
||||
return;
|
||||
|
||||
uint8 *src = getPagePtr(page1) + y1 * 320 + x1;
|
||||
uint8 *dst = getPagePtr(page2) + (y2 + iy) * 320;
|
||||
|
||||
for (int i = 0; i < h; i++) {
|
||||
uint8 *s = src + na;
|
||||
uint8 *d = dst + (x2 + ix);
|
||||
|
||||
if (flag)
|
||||
d += (i >> 1);
|
||||
|
||||
for (int ii = 0; ii < w; ii++) {
|
||||
if (*s++)
|
||||
*d = ovl[*d];
|
||||
d++;
|
||||
}
|
||||
|
||||
dst += 320;
|
||||
src += 320;
|
||||
}
|
||||
|
||||
if (!page2)
|
||||
addDirtyRect(x2 + ix, y2 + iy, w, h);
|
||||
}
|
||||
|
||||
void Screen_LoL::copyBlockAndApplyOverlayOutro(int srcPage, int dstPage, const uint8 *ovl) {
|
||||
if (!ovl)
|
||||
return;
|
||||
|
||||
const byte *src = getCPagePtr(srcPage);
|
||||
byte *dst = getPagePtr(dstPage);
|
||||
|
||||
for (int y = 0; y < 200; ++y) {
|
||||
for (int x = 0; x < 80; ++x) {
|
||||
uint32 srcData = READ_LE_UINT32(src); src += 4;
|
||||
uint32 dstData = READ_LE_UINT32(dst);
|
||||
uint16 offset = 0;
|
||||
|
||||
offset = ((srcData & 0xFF) << 8) + (dstData & 0xFF);
|
||||
*dst++ = ovl[offset];
|
||||
|
||||
offset = (srcData & 0xFF00) + ((dstData & 0xFF00) >> 8);
|
||||
*dst++ = ovl[offset];
|
||||
|
||||
srcData >>= 16;
|
||||
dstData >>= 16;
|
||||
|
||||
offset = ((srcData & 0xFF) << 8) + (dstData & 0xFF);
|
||||
*dst++ = ovl[offset];
|
||||
|
||||
offset = (srcData & 0xFF00) + ((dstData & 0xFF00) >> 8);
|
||||
*dst++ = ovl[offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::fadeToBlack(int delay, const UpdateFunctor *upFunc) {
|
||||
Screen::fadeToBlack(delay, upFunc);
|
||||
_fadeFlag = 2;
|
||||
}
|
||||
|
||||
void Screen_LoL::fadeToPalette1(int delay) {
|
||||
loadSpecialColors(getPalette(1));
|
||||
fadePalette(getPalette(1), delay);
|
||||
_fadeFlag = 0;
|
||||
}
|
||||
|
||||
void Screen_LoL::loadSpecialColors(Palette &dst) {
|
||||
if (_use16ColorMode)
|
||||
return;
|
||||
|
||||
dst.copy(*_screenPalette, 192, 4);
|
||||
}
|
||||
|
||||
void Screen_LoL::copyColor(int dstColorIndex, int srcColorIndex) {
|
||||
uint8 *s = _screenPalette->getData() + srcColorIndex * 3;
|
||||
uint8 *d = _screenPalette->getData() + dstColorIndex * 3;
|
||||
memcpy(d, s, 3);
|
||||
|
||||
uint8 ci[3];
|
||||
ci[0] = (d[0] << 2) | (d[0] & 3);
|
||||
ci[1] = (d[1] << 2) | (d[1] & 3);
|
||||
ci[2] = (d[2] << 2) | (d[2] & 3);
|
||||
|
||||
_system->getPaletteManager()->setPalette(ci, dstColorIndex, 1);
|
||||
}
|
||||
|
||||
bool Screen_LoL::fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTicks, uint32 totalTicks) {
|
||||
if (_use16ColorMode)
|
||||
return false;
|
||||
|
||||
const uint8 *dst = _screenPalette->getData() + 3 * dstColorIndex;
|
||||
const uint8 *src = _screenPalette->getData() + 3 * srcColorIndex;
|
||||
uint8 *p = getPalette(1).getData() + 3 * dstColorIndex;
|
||||
|
||||
bool res = false;
|
||||
|
||||
int16 srcV = 0;
|
||||
int16 dstV = 0;
|
||||
int32 outV = 0;
|
||||
|
||||
uint8 tmpPalEntry[3];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (elapsedTicks < totalTicks) {
|
||||
srcV = *src & 0x3F;
|
||||
dstV = *dst & 0x3F;
|
||||
|
||||
outV = srcV - dstV;
|
||||
if (outV)
|
||||
res = true;
|
||||
|
||||
outV = dstV + ((((outV << 8) / (int32)totalTicks) * (int32)elapsedTicks) >> 8);
|
||||
} else {
|
||||
*p = outV = *src;
|
||||
res = false;
|
||||
}
|
||||
|
||||
tmpPalEntry[i] = outV & 0xFF;
|
||||
src++;
|
||||
dst++;
|
||||
p++;
|
||||
}
|
||||
|
||||
_internFadePalette->copy(*_screenPalette);
|
||||
_internFadePalette->copy(tmpPalEntry, 0, 1, dstColorIndex);
|
||||
setScreenPalette(*_internFadePalette);
|
||||
updateScreen();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Palette **Screen_LoL::generateFadeTable(Palette **dst, Palette *src1, Palette *src2, int numTabs) {
|
||||
int len = _use16ColorMode ? 48 : 768;
|
||||
if (!src1)
|
||||
src1 = _screenPalette;
|
||||
|
||||
uint8 *p1 = (*dst++)->getData();
|
||||
uint8 *p2 = src1->getData();
|
||||
uint8 *p3 = src2->getData();
|
||||
uint8 *p4 = p1;
|
||||
uint8 *p5 = p2;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
int8 val = (int8)*p3++ - (int8)*p2++;
|
||||
*p4++ = (uint8)val;
|
||||
}
|
||||
|
||||
int16 t = 0;
|
||||
int16 d = 256 / numTabs;
|
||||
|
||||
for (int i = 1; i < numTabs - 1; i++) {
|
||||
p2 = p5;
|
||||
p3 = p1;
|
||||
t += d;
|
||||
p4 = (*dst++)->getData();
|
||||
|
||||
for (int ii = 0; ii < len; ii++) {
|
||||
int16 val = (((int8)*p3++ * t) >> 8) + (int8)*p2++;
|
||||
*p4++ = (uint8)val;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(p1, p5, len);
|
||||
(*dst)->copy(*src2);
|
||||
|
||||
return ++dst;
|
||||
}
|
||||
|
||||
uint8 Screen_LoL::getShapePaletteSize(const uint8 *shp) {
|
||||
return shp[10];
|
||||
}
|
||||
|
||||
void Screen_LoL::mergeOverlay(int x, int y, int w, int h) {
|
||||
// For now we convert to 16 colors on overlay merging. If that gives
|
||||
// any problems, like Screen functionallity not prepared for the
|
||||
// format PC98 16 color uses, we'll need to think of a better way.
|
||||
//
|
||||
// We must do this before merging the overlay, else the font colors
|
||||
// will be wrong.
|
||||
if (_use16ColorMode)
|
||||
convertPC98Gfx(_sjisOverlayPtrs[0] + y * 640 + x, w, h, 640);
|
||||
|
||||
Screen_v2::mergeOverlay(x, y, w, h);
|
||||
}
|
||||
|
||||
void Screen_LoL::convertPC98Gfx(uint8 *data, int w, int h, int pitch) {
|
||||
while (h--) {
|
||||
for (int i = 0; i < w; ++i) {
|
||||
*data = (*data >> 4) & (*data & 0x0F);
|
||||
++data;
|
||||
}
|
||||
|
||||
data += pitch - w;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_LoL::postProcessCursor(uint8 *data, int w, int h, int pitch) {
|
||||
if (!_use16ColorMode)
|
||||
return;
|
||||
|
||||
while (h--) {
|
||||
for (int i = 0; i < w; ++i) {
|
||||
if (*data != _cursorColorKey)
|
||||
*data = (*data >> 4) & (*data & 0x0F);
|
||||
++data;
|
||||
}
|
||||
|
||||
data += pitch - w;
|
||||
}
|
||||
}
|
||||
|
||||
void ChineseOneByteFontLoL::processColorMap() {
|
||||
_textColor[0] = _colorMap[1];
|
||||
_textColor[1] = _colorMap[0];
|
||||
}
|
||||
|
||||
uint32 ChineseTwoByteFontLoL::getFontOffset(uint16 c) const {
|
||||
c = ((c & 0x7F00) >> 2) | (c & 0x3F);
|
||||
return c * 28;
|
||||
}
|
||||
|
||||
void ChineseTwoByteFontLoL::processColorMap() {
|
||||
_textColor[0] = _colorMap[1];
|
||||
_textColor[1] = _colorMap[0];
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif // ENABLE_LOL
|
||||
105
engines/kyra/graphics/screen_lol.h
Normal file
105
engines/kyra/graphics/screen_lol.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_LOL
|
||||
|
||||
#ifndef KYRA_SCREEN_LOL_H
|
||||
#define KYRA_SCREEN_LOL_H
|
||||
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class LoLEngine;
|
||||
|
||||
class Screen_LoL : public Screen_v2 {
|
||||
public:
|
||||
Screen_LoL(LoLEngine *vm, OSystem *system);
|
||||
~Screen_LoL() override;
|
||||
|
||||
void fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint flags, ...) GCC_PRINTF(2, 8);
|
||||
void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint flags, ...) GCC_PRINTF(2, 9);
|
||||
|
||||
void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2) override;
|
||||
|
||||
void drawGridBox(int x, int y, int w, int h, int col);
|
||||
void fadeClearSceneWindow(int delay);
|
||||
|
||||
// smooth scrolling
|
||||
void backupSceneWindow(int srcPageNum, int dstPageNum);
|
||||
void restoreSceneWindow(int srcPageNum, int dstPageNum);
|
||||
void clearGuiShapeMemory(int pageNum);
|
||||
void copyGuiShapeFromSceneBackupBuffer(int srcPageNum, int dstPageNum);
|
||||
void copyGuiShapeToSurface(int srcPageNum, int dstPageNum);
|
||||
void smoothScrollZoomStepTop(int srcPageNum, int dstPageNum, int x, int y);
|
||||
void smoothScrollZoomStepBottom(int srcPageNum, int dstPageNum, int x, int y);
|
||||
void smoothScrollHorizontalStep(int pageNum, int x, int u2, int w);
|
||||
void smoothScrollTurnStep1(int srcPage1Num, int srcPage2Num, int dstPageNum);
|
||||
void smoothScrollTurnStep2(int srcPage1Num, int srcPage2Num, int dstPageNum);
|
||||
void smoothScrollTurnStep3(int srcPage1Num, int srcPage2Num, int dstPageNum);
|
||||
|
||||
void copyRegionSpecial(int page1, int w1, int h1, int x1, int y1, int page2, int w2, int h2, int x2, int y2, int w3, int h3, int mode, ...);
|
||||
|
||||
// palette stuff
|
||||
void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0);
|
||||
void fadeToPalette1(int delay);
|
||||
void loadSpecialColors(Palette &dst);
|
||||
void copyColor(int dstColorIndex, int srcColorIndex);
|
||||
bool fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTicks, uint32 totalTicks);
|
||||
Palette **generateFadeTable(Palette **dst, Palette *src1, Palette *src2, int numTabs);
|
||||
|
||||
void generateGrayOverlay(const Palette &Pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors);
|
||||
uint8 *getLevelOverlay(int index) { return _levelOverlays[index]; }
|
||||
|
||||
void createTransparencyTablesIntern(const uint8 *ovl, int a, const uint8 *fxPal1, const uint8 *fxPal2, uint8 *outTable1, uint8 *outTable2, int b);
|
||||
|
||||
void copyBlockAndApplyOverlay(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, uint8 *ovl);
|
||||
void applyOverlaySpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, int flag, uint8 *ovl);
|
||||
|
||||
void copyBlockAndApplyOverlayOutro(int srcPage, int dstPage, const uint8 *ovl);
|
||||
|
||||
uint8 getShapePaletteSize(const uint8 *shp);
|
||||
|
||||
uint8 *_paletteOverlay1;
|
||||
uint8 *_paletteOverlay2;
|
||||
uint8 *_grayOverlay;
|
||||
int _fadeFlag;
|
||||
|
||||
// PC98 specific
|
||||
static void convertPC98Gfx(uint8 *data, int w, int h, int pitch);
|
||||
|
||||
private:
|
||||
static const ScreenDim _screenDimTable256C[];
|
||||
static const ScreenDim _screenDimTable16C[];
|
||||
static const ScreenDim _screenDimTableZH[];
|
||||
static const int _screenDimTableCount;
|
||||
|
||||
uint8 *_levelOverlays[8];
|
||||
|
||||
void mergeOverlay(int x, int y, int w, int h) override;
|
||||
void postProcessCursor(uint8 *data, int width, int height, int pitch) override;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ENABLE_LOL
|
||||
156
engines/kyra/graphics/screen_mr.cpp
Normal file
156
engines/kyra/graphics/screen_mr.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/graphics/screen_mr.h"
|
||||
#include "kyra/engine/kyra_mr.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Screen_MR::Screen_MR(KyraEngine_MR *vm, OSystem *system)
|
||||
: Screen_v2(vm, system, _screenDimTable, _screenDimTableCount), _interfaceCommandLineY1(vm->gameFlags().extraLang != Common::UNK_LANG ? 185 : 188) {
|
||||
}
|
||||
|
||||
Screen_MR::~Screen_MR() {
|
||||
}
|
||||
|
||||
int Screen_MR::getLayer(int x, int y) {
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
else if (x >= 320)
|
||||
x = 319;
|
||||
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
} else if (y >= 187) {
|
||||
y = 187;
|
||||
// The original actually limits the _maskMin/MaxY check to cases where y has already been clipped to 187.
|
||||
// Whether this was intentional or not: Scenes actually require that we do it that way or animations may
|
||||
// be drawn on the wrong layer (bug #11312).
|
||||
if (y < _maskMinY || y > _maskMaxY)
|
||||
return 15;
|
||||
}
|
||||
|
||||
uint8 pixel = *(getCPagePtr(5) + y * 320 + x);
|
||||
pixel &= 0x7F;
|
||||
pixel >>= 3;
|
||||
|
||||
return CLIP<uint8>(pixel, 1, 15);
|
||||
}
|
||||
|
||||
byte Screen_MR::getShapeFlag1(int x, int y) {
|
||||
if (y < _maskMinY || y > _maskMaxY)
|
||||
return 0;
|
||||
|
||||
uint8 color = _shapePages[0][y * SCREEN_W + x];
|
||||
color &= 0x80;
|
||||
color ^= 0x80;
|
||||
|
||||
if (color & 0x80)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte Screen_MR::getShapeFlag2(int x, int y) {
|
||||
if (y < _maskMinY || y > _maskMaxY)
|
||||
return 0;
|
||||
|
||||
uint8 color = _shapePages[0][y * SCREEN_W + x];
|
||||
color &= 0x7F;
|
||||
color &= 0x87;
|
||||
return color;
|
||||
}
|
||||
|
||||
int Screen_MR::getDrawLayer(int x, int y) {
|
||||
int xpos = x - 8;
|
||||
int ypos = y;
|
||||
int layer = 1;
|
||||
|
||||
for (int curX = xpos; curX < xpos + 24; ++curX) {
|
||||
int tempLayer = getShapeFlag2(curX, ypos);
|
||||
|
||||
if (layer < tempLayer)
|
||||
layer = tempLayer;
|
||||
|
||||
if (layer >= 7)
|
||||
return 7;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
int Screen_MR::getDrawLayer2(int x, int y, int height) {
|
||||
int xpos = x - 8;
|
||||
int ypos = y;
|
||||
int layer = 1;
|
||||
|
||||
for (int useX = xpos; useX < xpos + 24; ++useX) {
|
||||
for (int useY = ypos - height; useY < ypos; ++useY) {
|
||||
int tempLayer = getShapeFlag2(useX, useY);
|
||||
|
||||
if (tempLayer > layer)
|
||||
layer = tempLayer;
|
||||
|
||||
if (tempLayer >= 7)
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
void Screen_MR::drawFilledBox(int x1, int y1, int x2, int y2, uint8 c1, uint8 c2, uint8 c3) {
|
||||
fillRect(x1, y1, x2, y2, c1);
|
||||
|
||||
fillRect(x1, y1, x2, y1+1, c2);
|
||||
fillRect(x2-1, y1, x2, y2, c2);
|
||||
|
||||
drawClippedLine(x1, y1, x1, y2, c3);
|
||||
drawClippedLine(x1+1, y1+1, x1+1, y2-2, c3);
|
||||
drawClippedLine(x1, y2, x2, y2, c3);
|
||||
drawClippedLine(x1, y2-1, x2-1, y2-1, c3);
|
||||
}
|
||||
|
||||
void ChineseOneByteFontMR::processColorMap() {
|
||||
_textColor[0] = _colorMap[1] | (_colorMap[1] << 8);
|
||||
if (_textColor[0]) {
|
||||
_textColor[0] -= 0x100;
|
||||
if (_colorMap[1] == 0xFF)
|
||||
_textColor[0] -= 0x100;
|
||||
}
|
||||
_textColor[0] = TO_LE_16(_textColor[0]);
|
||||
_textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
|
||||
}
|
||||
|
||||
uint32 ChineseTwoByteFontMR::getFontOffset(uint16 c) const {
|
||||
c = ((c & 0x7F00) >> 2) | (c & 0x3F);
|
||||
return c * 28;
|
||||
}
|
||||
|
||||
void ChineseTwoByteFontMR::processColorMap() {
|
||||
_textColor[0] = _colorMap[1] | (_colorMap[1] << 8);
|
||||
if (_textColor[0]) {
|
||||
_textColor[0] -= 0x100;
|
||||
if (_colorMap[1] == 0xFF)
|
||||
_textColor[0] -= 0x100;
|
||||
}
|
||||
_textColor[0] = TO_LE_16(_textColor[0]);
|
||||
_textColor[1] = _colorMap[0] | (_colorMap[0] << 8);
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
53
engines/kyra/graphics/screen_mr.h
Normal file
53
engines/kyra/graphics/screen_mr.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_MR_H
|
||||
#define KYRA_SCREEN_MR_H
|
||||
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class KyraEngine_MR;
|
||||
|
||||
class Screen_MR : public Screen_v2 {
|
||||
public:
|
||||
Screen_MR(KyraEngine_MR *vm, OSystem *system);
|
||||
~Screen_MR() override;
|
||||
|
||||
int getLayer(int x, int y) override;
|
||||
|
||||
byte getShapeFlag1(int x, int y) override;
|
||||
byte getShapeFlag2(int x, int y) override;
|
||||
|
||||
int getDrawLayer(int x, int y) override;
|
||||
int getDrawLayer2(int x, int y, int height) override;
|
||||
|
||||
void drawFilledBox(int x1, int y1, int x2, int y2, uint8 c1, uint8 c2, uint8 c3);
|
||||
private:
|
||||
static const ScreenDim _screenDimTable[];
|
||||
static const int _screenDimTableCount;
|
||||
const int _interfaceCommandLineY1;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
456
engines/kyra/graphics/screen_v2.cpp
Normal file
456
engines/kyra/graphics/screen_v2.cpp
Normal file
@@ -0,0 +1,456 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/graphics/screen_v2.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
Screen_v2::Screen_v2(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize)
|
||||
: Screen(vm, system, dimTable, dimTableSize), _wsaFrameAnimBuffer(nullptr) {
|
||||
_wsaFrameAnimBuffer = new uint8[1024];
|
||||
assert(_wsaFrameAnimBuffer);
|
||||
}
|
||||
|
||||
Screen_v2::~Screen_v2() {
|
||||
delete[] _wsaFrameAnimBuffer;
|
||||
}
|
||||
|
||||
uint8 *Screen_v2::generateOverlay(const Palette &pal, uint8 *buffer, int opColor, uint weight, int maxColor) {
|
||||
if (!buffer)
|
||||
return buffer;
|
||||
|
||||
weight = MIN<uint>(weight, 255) >> 1;
|
||||
|
||||
const byte opR = pal[opColor * 3 + 0];
|
||||
const byte opG = pal[opColor * 3 + 1];
|
||||
const byte opB = pal[opColor * 3 + 2];
|
||||
|
||||
uint8 *dst = buffer;
|
||||
*dst++ = 0;
|
||||
|
||||
int maxIndex = maxColor;
|
||||
if (maxIndex == -1) {
|
||||
if (_vm->game() == GI_LOL) {
|
||||
if (_use16ColorMode)
|
||||
maxIndex = 255;
|
||||
else
|
||||
maxIndex = 127;
|
||||
} else {
|
||||
maxIndex = 255;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i != 256; ++i) {
|
||||
const byte curR = pal[i * 3 + 0] - (((pal[i * 3 + 0] - opR) * weight) >> 7);
|
||||
const byte curG = pal[i * 3 + 1] - (((pal[i * 3 + 1] - opG) * weight) >> 7);
|
||||
const byte curB = pal[i * 3 + 2] - (((pal[i * 3 + 2] - opB) * weight) >> 7);
|
||||
|
||||
uint16 idxSum = _use16ColorMode ? 0xFFFF : 0x7FFF;
|
||||
byte index = opColor;
|
||||
|
||||
for (int curIdx = 1; curIdx <= maxIndex; ++curIdx) {
|
||||
if (!_use16ColorMode && i == curIdx)
|
||||
continue;
|
||||
|
||||
int diff = 0;
|
||||
uint16 sum = 0;
|
||||
|
||||
diff = pal[curIdx * 3 + 0] - curR;
|
||||
sum += diff * diff;
|
||||
diff = pal[curIdx * 3 + 1] - curG;
|
||||
sum += diff * diff;
|
||||
diff = pal[curIdx * 3 + 2] - curB;
|
||||
sum += diff * diff;
|
||||
|
||||
if (!sum) {
|
||||
index = curIdx;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sum <= idxSum) {
|
||||
if (!_use16ColorMode || (curIdx == opColor || curIdx != i)) {
|
||||
idxSum = sum;
|
||||
index = curIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*dst++ = index;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Screen_v2::applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay) {
|
||||
if (pageNum == 0 || pageNum == 1)
|
||||
addDirtyRect(x, y, w, h);
|
||||
|
||||
uint8 *dst = getPagePtr(pageNum) + y * 320 + x;
|
||||
while (h--) {
|
||||
for (int wi = 0; wi < w; ++wi) {
|
||||
uint8 index = *dst;
|
||||
*dst++ = overlay[index];
|
||||
}
|
||||
dst += 320 - w;
|
||||
}
|
||||
}
|
||||
|
||||
int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const Palette &pal, uint8 firstColor, uint16 numColors, bool skipSpecialColors) {
|
||||
int m = 0x7FFF;
|
||||
int r = 0x101;
|
||||
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
if (skipSpecialColors && i >= 0xC0 && i <= 0xC3)
|
||||
continue;
|
||||
|
||||
int v = paletteEntry[0] - pal[(i + firstColor) * 3 + 0];
|
||||
int c = v * v;
|
||||
v = paletteEntry[1] - pal[(i + firstColor) * 3 + 1];
|
||||
c += (v * v);
|
||||
v = paletteEntry[2] - pal[(i + firstColor) * 3 + 2];
|
||||
c += (v * v);
|
||||
|
||||
if (c <= m) {
|
||||
m = c;
|
||||
r = i;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Screen_v2::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) {
|
||||
int maxDiff = 0;
|
||||
diff = 0;
|
||||
for (int i = 0; i < pal.getNumColors() * 3; ++i) {
|
||||
diff = ABS(pal[i] - (*_screenPalette)[i]);
|
||||
maxDiff = MAX(maxDiff, diff);
|
||||
}
|
||||
|
||||
delayInc = delay << 8;
|
||||
if (maxDiff != 0) {
|
||||
delayInc /= maxDiff;
|
||||
delayInc = MIN(delayInc, 0x7FFF);
|
||||
}
|
||||
|
||||
delay = delayInc;
|
||||
for (diff = 1; diff <= maxDiff; ++diff) {
|
||||
if (delayInc >= 256)
|
||||
break;
|
||||
delayInc += delay;
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen_v2::timedPaletteFadeStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 totalTime) {
|
||||
Palette &p1 = getPalette(1);
|
||||
|
||||
bool res = false;
|
||||
for (int i = 0; i < p1.getNumColors() * 3; i++) {
|
||||
uint8 out = 0;
|
||||
|
||||
if (elapsedTime < totalTime) {
|
||||
int32 d = ((pal2[i] & 0x3F) - (pal1[i] & 0x3F));
|
||||
if (d)
|
||||
res = true;
|
||||
|
||||
int32 val = ((((d << 8) / (int32)totalTime) * (int32)elapsedTime) >> 8);
|
||||
out = ((pal1[i] & 0x3F) + (int8)val);
|
||||
} else {
|
||||
out = p1[i] = (pal2[i] & 0x3F);
|
||||
res = false;
|
||||
}
|
||||
|
||||
(*_internFadePalette)[i] = out;
|
||||
}
|
||||
|
||||
setScreenPalette(*_internFadePalette);
|
||||
updateScreen();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const uint8 *Screen_v2::getPtrToShape(const uint8 *shpFile, int shape) {
|
||||
uint16 shapes = READ_LE_UINT16(shpFile);
|
||||
|
||||
if (shapes <= shape)
|
||||
return nullptr;
|
||||
|
||||
uint32 offset = READ_LE_UINT32(shpFile + (shape << 2) + 2);
|
||||
|
||||
return shpFile + offset + 2;
|
||||
}
|
||||
|
||||
uint8 *Screen_v2::getPtrToShape(uint8 *shpFile, int shape) {
|
||||
uint16 shapes = READ_LE_UINT16(shpFile);
|
||||
|
||||
if (shapes <= shape)
|
||||
return nullptr;
|
||||
|
||||
uint32 offset = READ_LE_UINT32(shpFile + (shape << 2) + 2);
|
||||
|
||||
return shpFile + offset + 2;
|
||||
}
|
||||
|
||||
int Screen_v2::getShapeScaledWidth(const uint8 *shpFile, int scale) {
|
||||
if (!shpFile)
|
||||
return 0;
|
||||
int width = READ_LE_UINT16(shpFile + 3);
|
||||
return (width * scale) >> 8;
|
||||
}
|
||||
|
||||
int Screen_v2::getShapeScaledHeight(const uint8 *shpFile, int scale) {
|
||||
if (!shpFile)
|
||||
return 0;
|
||||
int height = shpFile[2];
|
||||
return (height * scale) >> 8;
|
||||
}
|
||||
|
||||
uint16 Screen_v2::getShapeSize(const uint8 *shp) {
|
||||
if (!shp)
|
||||
return 0;
|
||||
return READ_LE_UINT16(shp + 6);
|
||||
}
|
||||
|
||||
uint8 *Screen_v2::makeShapeCopy(const uint8 *src, int index) {
|
||||
const uint8 *shape = getPtrToShape(src, index);
|
||||
if (!shape)
|
||||
return nullptr;
|
||||
|
||||
int size = getShapeSize(shape);
|
||||
|
||||
uint8 *copy = new uint8[size];
|
||||
assert(copy);
|
||||
memcpy(copy, shape, size);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
int Screen_v2::getLayer(int x, int y) {
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
else if (x >= 320)
|
||||
x = 319;
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
else if (y >= 144)
|
||||
y = 143;
|
||||
|
||||
uint8 pixel = *(getCPagePtr(5) + y * 320 + x);
|
||||
pixel &= 0x7F;
|
||||
pixel >>= 3;
|
||||
|
||||
return CLIP<uint8>(pixel, 1, 15);
|
||||
}
|
||||
|
||||
int Screen_v2::getRectSize(int w, int h) {
|
||||
if (w > 320 || h > 200)
|
||||
return 0;
|
||||
return w * h;
|
||||
}
|
||||
|
||||
void Screen_v2::setTextColorMap(const uint8 *cmap) {
|
||||
setTextColor(cmap, 0, 15);
|
||||
}
|
||||
|
||||
void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2,
|
||||
int w1, int h1, int w2, int h2, int srcPage, int dstPage, int dim) {
|
||||
|
||||
if (!w1 || !h1 || !w2 || !h2)
|
||||
return;
|
||||
|
||||
ScreenDim cdm = *getScreenDim(dim);
|
||||
cdm.sx <<= 3;
|
||||
cdm.w <<= 3;
|
||||
|
||||
int na = 0, nb = 0, nc = w2;
|
||||
|
||||
if (!calcBounds(cdm.w, cdm.h, x2, y2, w2, h2, na, nb, nc))
|
||||
return;
|
||||
|
||||
const uint8 *src = getPagePtr(srcPage) + y1 * 320;
|
||||
uint8 *dst = getPagePtr(dstPage) + (y2 + cdm.sy) * 320;
|
||||
|
||||
int u = -1;
|
||||
|
||||
do {
|
||||
int t = (nb * h1) / h2;
|
||||
if (t != u) {
|
||||
u = t;
|
||||
const uint8 *s = src + x1 + t * 320;
|
||||
uint8 *dt = (uint8 *)_wsaFrameAnimBuffer;
|
||||
|
||||
t = w2 - w1;
|
||||
if (!t) {
|
||||
memcpy(dt, s, w2);
|
||||
} else if (t > 0) {
|
||||
if (w1 == 1) {
|
||||
memset(dt, *s, w2);
|
||||
} else {
|
||||
t = ((((((w2 - w1 + 1) & 0xFFFF) << 8) / w1) + 0x100) & 0xFFFF) << 8;
|
||||
int bp = 0;
|
||||
for (int i = 0; i < w1; i++) {
|
||||
int cnt = (t >> 16);
|
||||
bp += (t & 0xFFFF);
|
||||
if (bp > 0xFFFF) {
|
||||
bp -= 0xFFFF;
|
||||
cnt++;
|
||||
}
|
||||
memset(dt, *s++, cnt);
|
||||
dt += cnt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (w2 == 1) {
|
||||
*dt = *s;
|
||||
} else {
|
||||
t = (((((w1 - w2) & 0xFFFF) << 8) / w2) & 0xFFFF) << 8;
|
||||
int bp = 0;
|
||||
for (int i = 0; i < w2; i++) {
|
||||
*dt++ = *s++;
|
||||
bp += (t & 0xFFFF);
|
||||
if (bp > 0xFFFF) {
|
||||
bp -= 0xFFFF;
|
||||
s++;
|
||||
}
|
||||
s += (t >> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(dst + x2 + cdm.sx, _wsaFrameAnimBuffer + na, w2);
|
||||
dst += 320;
|
||||
} while (++nb < h2);
|
||||
|
||||
if (!dstPage)
|
||||
addDirtyRect(x2, y2, w2, h2);
|
||||
}
|
||||
|
||||
void Screen_v2::copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes) {
|
||||
const uint8 *src = getPagePtr(srcPage) + srcPos;
|
||||
uint8 *dst = getPagePtr(dstPage) + dstPos;
|
||||
memcpy(dst, src, numBytes);
|
||||
}
|
||||
|
||||
void Screen_v2::copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX, int dstY, int dstW, int dstH, const ScreenDim *dim, bool flag) {
|
||||
int x0 = dim->sx << 3;
|
||||
int y0 = dim->sy;
|
||||
int w0 = dim->w << 3;
|
||||
int h0 = dim->h;
|
||||
|
||||
int x1 = dstX;
|
||||
int y1 = dstY;
|
||||
int w1 = dstW;
|
||||
int h1 = dstH;
|
||||
|
||||
int x2, y2, w2;
|
||||
|
||||
calcBounds(w0, h0, x1, y1, w1, h1, x2, y2, w2);
|
||||
|
||||
const uint8 *src = getPagePtr(srcPage) + (320 * srcH) + srcW;
|
||||
uint8 *dst = getPagePtr(dstPage) + 320 * (y0 + y1);
|
||||
|
||||
for (int y = 0; y < h1; y++) {
|
||||
const uint8 *s = src + x2;
|
||||
uint8 *d = dst + x0 + x1;
|
||||
|
||||
if (flag)
|
||||
d += (h1 >> 1);
|
||||
|
||||
for (int x = 0; x < w1; x++) {
|
||||
if (*s)
|
||||
*d = *s;
|
||||
s++;
|
||||
d++;
|
||||
}
|
||||
dst += 320;
|
||||
src += 320;
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, int &x2, int &y2, int &w2) {
|
||||
x2 = 0;
|
||||
y2 = 0;
|
||||
w2 = w1;
|
||||
|
||||
int t = x1 + w1;
|
||||
if (t < 1) {
|
||||
w1 = h1 = -1;
|
||||
} else {
|
||||
if (t <= x1) {
|
||||
x2 = w1 - t;
|
||||
w1 = t;
|
||||
x1 = 0;
|
||||
}
|
||||
t = w0 - x1;
|
||||
if (t < 1) {
|
||||
w1 = h1 = -1;
|
||||
} else {
|
||||
if (t <= w1) {
|
||||
w1 = t;
|
||||
}
|
||||
w2 -= w1;
|
||||
t = h1 + y1;
|
||||
if (t < 1) {
|
||||
w1 = h1 = -1;
|
||||
} else {
|
||||
if (t <= y1) {
|
||||
y2 = h1 - t;
|
||||
h1 = t;
|
||||
y1 = 0;
|
||||
}
|
||||
t = h0 - y1;
|
||||
if (t < 1) {
|
||||
w1 = h1 = -1;
|
||||
} else {
|
||||
if (t <= h1) {
|
||||
h1 = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return w1 != -1;
|
||||
}
|
||||
|
||||
void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) {
|
||||
const uint32 *src = (const uint32 *)getPagePtr(srcPage);
|
||||
uint32 *dst = (uint32 *)getPagePtr(dstPage);
|
||||
uint32 *page0 = (uint32 *)getPagePtr(0);
|
||||
|
||||
bool updated = false;
|
||||
|
||||
for (int y = 0; y < 200; ++y) {
|
||||
for (int x = 0; x < 80; ++x, ++src, ++dst, ++page0) {
|
||||
if (*src != *dst) {
|
||||
updated = true;
|
||||
*dst = *page0 = *src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
addDirtyRect(0, 0, 320, 200);
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
80
engines/kyra/graphics/screen_v2.h
Normal file
80
engines/kyra/graphics/screen_v2.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_SCREEN_V2_H
|
||||
#define KYRA_SCREEN_V2_H
|
||||
|
||||
#include "kyra/graphics/screen.h"
|
||||
#include "kyra/engine/kyra_v2.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class Screen_v2 : public Screen {
|
||||
public:
|
||||
Screen_v2(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize);
|
||||
~Screen_v2() override;
|
||||
|
||||
// screen page handling
|
||||
void checkedPageUpdate(int srcPage, int dstPage);
|
||||
|
||||
// palette handling
|
||||
uint8 *generateOverlay(const Palette &pal, uint8 *buffer, int color, uint weight, int maxColor = -1);
|
||||
void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay);
|
||||
int findLeastDifferentColor(const uint8 *paletteEntry, const Palette &pal, uint8 firstColor, uint16 numColors, bool skipSpecialColors = false);
|
||||
|
||||
void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) override;
|
||||
|
||||
bool timedPaletteFadeStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 totalTime);
|
||||
|
||||
// shape handling
|
||||
uint8 *getPtrToShape(uint8 *shpFile, int shape);
|
||||
const uint8 *getPtrToShape(const uint8 *shpFile, int shape);
|
||||
|
||||
int getShapeScaledWidth(const uint8 *shpFile, int scale);
|
||||
int getShapeScaledHeight(const uint8 *shpFile, int scale);
|
||||
|
||||
uint16 getShapeSize(const uint8 *shp);
|
||||
|
||||
uint8 *makeShapeCopy(const uint8 *src, int index);
|
||||
|
||||
// rect handling
|
||||
int getRectSize(int w, int h) override;
|
||||
bool calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, int &x2, int &y2, int &w2);
|
||||
|
||||
// text display
|
||||
void setTextColorMap(const uint8 *cmap) override;
|
||||
|
||||
// layer handling
|
||||
virtual int getLayer(int x, int y);
|
||||
|
||||
// special WSA handling
|
||||
void wsaFrameAnimationStep(int x1, int y1, int x2, int y2, int w1, int h1, int w2, int h2, int srcPage, int dstPage, int dim);
|
||||
|
||||
// used in non-interactive HoF/LoL demos
|
||||
void copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes);
|
||||
void copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX,int dstY, int dstW, int dstH, const ScreenDim *d, bool flag = false);
|
||||
protected:
|
||||
uint8 *_wsaFrameAnimBuffer;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
662
engines/kyra/graphics/vqa.cpp
Normal file
662
engines/kyra/graphics/vqa.cpp
Normal file
@@ -0,0 +1,662 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Player for Kyrandia 3 VQA movies, based on the information found at
|
||||
// https://multimedia.cx/VQA_INFO.TXT
|
||||
//
|
||||
// The benchl.vqa movie (or whatever it is) is not supported. It does not have
|
||||
// a FINF chunk.
|
||||
//
|
||||
// The jung2.vqa movie does work, but only thanks to a grotesque hack.
|
||||
|
||||
#include "kyra/kyra_v1.h"
|
||||
#include "kyra/graphics/vqa.h"
|
||||
#include "kyra/graphics/screen.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/events.h"
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
static uint32 readTag(Common::SeekableReadStream *stream) {
|
||||
// Some tags have to be on an even offset, so they are padded with a
|
||||
// zero byte. Skip that.
|
||||
|
||||
uint32 tag = stream->readUint32BE();
|
||||
|
||||
if (stream->eos())
|
||||
return 0;
|
||||
|
||||
if (!(tag & 0xFF000000)) {
|
||||
tag = (tag << 8) | stream->readByte();
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
VQADecoder::VQADecoder() : _fileStream(nullptr), _frameInfo(nullptr) {
|
||||
memset(&_header, 0, sizeof(_header));
|
||||
}
|
||||
|
||||
VQADecoder::~VQADecoder() {
|
||||
close();
|
||||
delete[] _frameInfo;
|
||||
}
|
||||
|
||||
bool VQADecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
close();
|
||||
_fileStream = stream;
|
||||
|
||||
if (_fileStream->readUint32BE() != MKTAG('F','O','R','M')) {
|
||||
warning("VQADecoder::loadStream(): Cannot find `FORM' tag");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore the size of the FORM chunk. We're only interested in its
|
||||
// children.
|
||||
_fileStream->readUint32BE();
|
||||
|
||||
if (_fileStream->readUint32BE() != MKTAG('W','V','Q','A')) {
|
||||
warning("VQADecoder::loadStream(): Cannot find `WVQA' tag");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We want to find both a VQHD chunk containing the header, and a FINF
|
||||
// chunk containing the frame offsets.
|
||||
|
||||
bool foundVQHD = false;
|
||||
bool foundFINF = false;
|
||||
|
||||
VQAAudioTrack *audioTrack = nullptr;
|
||||
|
||||
// The information we need is stored in two chunks: VQHD and FINF. We
|
||||
// need both of them before we can begin decoding the movie.
|
||||
|
||||
while (!foundVQHD || !foundFINF) {
|
||||
uint32 tag = readTag(stream);
|
||||
uint32 size = _fileStream->readUint32BE();
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('V','Q','H','D'):
|
||||
handleVQHD(_fileStream);
|
||||
if (_header.flags & 1) {
|
||||
audioTrack = new VQAAudioTrack(&_header, getSoundType());
|
||||
addTrack(audioTrack);
|
||||
}
|
||||
foundVQHD = true;
|
||||
break;
|
||||
case MKTAG('F','I','N','F'):
|
||||
if (!foundVQHD) {
|
||||
warning("VQADecoder::loadStream(): Found `FINF' before `VQHD'");
|
||||
return false;
|
||||
}
|
||||
if (size != 4 * getFrameCount()) {
|
||||
warning("VQADecoder::loadStream(): Expected size %d for `FINF' chunk, but got %u", 4 * getFrameCount(), size);
|
||||
return false;
|
||||
}
|
||||
handleFINF(_fileStream);
|
||||
foundFINF = true;
|
||||
break;
|
||||
default:
|
||||
warning("VQADecoder::loadStream(): Unknown tag `%s'", tag2str(tag));
|
||||
_fileStream->seek(size, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VQADecoder::handleVQHD(Common::SeekableReadStream *stream) {
|
||||
_header.version = stream->readUint16LE();
|
||||
_header.flags = stream->readUint16LE();
|
||||
_header.numFrames = stream->readUint16LE();
|
||||
_header.width = stream->readUint16LE();
|
||||
_header.height = stream->readUint16LE();
|
||||
_header.blockW = stream->readByte();
|
||||
_header.blockH = stream->readByte();
|
||||
_header.frameRate = stream->readByte();
|
||||
_header.cbParts = stream->readByte();
|
||||
_header.colors = stream->readUint16LE();
|
||||
_header.maxBlocks = stream->readUint16LE();
|
||||
_header.unk1 = stream->readUint32LE();
|
||||
_header.unk2 = stream->readUint16LE();
|
||||
_header.freq = stream->readUint16LE();
|
||||
_header.channels = stream->readByte();
|
||||
_header.bits = stream->readByte();
|
||||
_header.unk3 = stream->readUint32LE();
|
||||
_header.unk4 = stream->readUint16LE();
|
||||
_header.maxCBFZSize = stream->readUint32LE();
|
||||
_header.unk5 = stream->readUint32LE();
|
||||
|
||||
_frameInfo = new uint32[_header.numFrames + 1];
|
||||
|
||||
VQAVideoTrack *videoTrack = new VQAVideoTrack(&_header);
|
||||
addTrack(videoTrack);
|
||||
|
||||
// Kyrandia 3 uses version 1 VQA files, and is the only known game to
|
||||
// do so. This version of the format has some implicit default values.
|
||||
|
||||
if (_header.version == 1) {
|
||||
if (_header.freq == 0)
|
||||
_header.freq = 22050;
|
||||
if (_header.channels == 0)
|
||||
_header.channels = 1;
|
||||
if (_header.bits == 0)
|
||||
_header.bits = 8;
|
||||
}
|
||||
|
||||
if (_header.flags & 1) {
|
||||
// Kyrandia 3 uses 8-bit sound, and so far testing indicates
|
||||
// that it's all mono.
|
||||
//
|
||||
// This is good, because it means we won't have to worry about
|
||||
// the confusing parts of the VQA spec, where 8- and 16-bit
|
||||
// data have different signedness and stereo sample layout
|
||||
// varies between different games.
|
||||
|
||||
assert(_header.bits == 8);
|
||||
assert(_header.channels == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void VQADecoder::handleFINF(Common::SeekableReadStream *stream) {
|
||||
for (int i = 0; i < _header.numFrames; i++) {
|
||||
_frameInfo[i] = 2 * stream->readUint32LE();
|
||||
}
|
||||
|
||||
// HACK: This flag is set in jung2.vqa, and its purpose - if it has
|
||||
// one - is currently unknown. It can't be a general purpose flag,
|
||||
// because in large movies the frame offset can be large enough to
|
||||
// set this flag, though of course never for the first frame.
|
||||
//
|
||||
// At least in my copy of Kyrandia 3, _frameInfo[0] is 0x81000098, and
|
||||
// the desired index is 0x4716. So the value should be 0x80004716, but
|
||||
// I don't want to hard-code it. Instead, scan the file for the offset
|
||||
// to the first VQFR chunk.
|
||||
|
||||
if (_frameInfo[0] & 0x01000000) {
|
||||
uint32 oldPos = stream->pos();
|
||||
|
||||
while (1) {
|
||||
uint32 scanTag = readTag(stream);
|
||||
uint32 scanSize = stream->readUint32BE();
|
||||
|
||||
if (stream->eos())
|
||||
break;
|
||||
|
||||
if (scanTag == MKTAG('V','Q','F','R')) {
|
||||
_frameInfo[0] = (stream->pos() - 8) | 0x80000000;
|
||||
break;
|
||||
}
|
||||
|
||||
stream->seek(scanSize, SEEK_CUR);
|
||||
}
|
||||
|
||||
stream->seek(oldPos);
|
||||
}
|
||||
|
||||
_frameInfo[_header.numFrames] = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
void VQADecoder::readNextPacket() {
|
||||
VQAVideoTrack *videoTrack = (VQAVideoTrack *)getTrack(0);
|
||||
VQAAudioTrack *audioTrack = (VQAAudioTrack *)getTrack(1);
|
||||
|
||||
assert(videoTrack);
|
||||
|
||||
int curFrame = videoTrack->getCurFrame();
|
||||
|
||||
// Stop if reading the tag is enough to put us ahead of the next frame
|
||||
int32 end = (_frameInfo[curFrame + 1] & 0x7FFFFFFF) - 7;
|
||||
|
||||
// At this point, we probably only need to adjust for the offset in the
|
||||
// stream to be even. But we may as well do this to really make sure
|
||||
// we have the correct offset.
|
||||
if (curFrame >= 0) {
|
||||
_fileStream->seek(_frameInfo[curFrame] & 0x7FFFFFFF);
|
||||
if (_frameInfo[curFrame] & 0x80000000) {
|
||||
videoTrack->setHasDirtyPalette();
|
||||
}
|
||||
}
|
||||
|
||||
while (!_fileStream->eos() && _fileStream->pos() < end) {
|
||||
uint32 tag = readTag(_fileStream);
|
||||
uint32 size;
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('S','N','D','0'): // Uncompressed sound
|
||||
assert(audioTrack);
|
||||
audioTrack->handleSND0(_fileStream);
|
||||
break;
|
||||
case MKTAG('S','N','D','1'): // Compressed sound, almost like AUD
|
||||
assert(audioTrack);
|
||||
audioTrack->handleSND1(_fileStream);
|
||||
break;
|
||||
case MKTAG('S','N','D','2'): // Compressed sound
|
||||
assert(audioTrack);
|
||||
audioTrack->handleSND2(_fileStream);
|
||||
break;
|
||||
case MKTAG('V','Q','F','R'):
|
||||
videoTrack->handleVQFR(_fileStream);
|
||||
break;
|
||||
case MKTAG('C','M','D','S'):
|
||||
// The purpose of this is unknown, but it's known to
|
||||
// exist so don't warn about it.
|
||||
size = _fileStream->readUint32BE();
|
||||
_fileStream->seek(size, SEEK_CUR);
|
||||
break;
|
||||
default:
|
||||
warning("VQADecoder::readNextPacket(): Unknown tag `%s'", tag2str(tag));
|
||||
size = _fileStream->readUint32BE();
|
||||
_fileStream->seek(size, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
VQADecoder::VQAAudioTrack::VQAAudioTrack(const VQAHeader *header, Audio::Mixer::SoundType soundType) :
|
||||
AudioTrack(soundType) {
|
||||
_audioStream = Audio::makeQueuingAudioStream(header->freq, false);
|
||||
}
|
||||
|
||||
VQADecoder::VQAAudioTrack::~VQAAudioTrack() {
|
||||
delete _audioStream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *VQADecoder::VQAAudioTrack::getAudioStream() const {
|
||||
return _audioStream;
|
||||
}
|
||||
|
||||
void VQADecoder::VQAAudioTrack::handleSND0(Common::SeekableReadStream *stream) {
|
||||
uint32 size = stream->readUint32BE();
|
||||
byte *buf = (byte *)malloc(size);
|
||||
stream->read(buf, size);
|
||||
_audioStream->queueBuffer(buf, size, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
|
||||
}
|
||||
|
||||
void VQADecoder::VQAAudioTrack::handleSND1(Common::SeekableReadStream *stream) {
|
||||
stream->readUint32BE();
|
||||
uint16 outsize = stream->readUint16LE();
|
||||
uint16 insize = stream->readUint16LE();
|
||||
byte *inbuf = (byte *)malloc(insize);
|
||||
|
||||
stream->read(inbuf, insize);
|
||||
|
||||
if (insize == outsize) {
|
||||
_audioStream->queueBuffer(inbuf, insize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
|
||||
} else {
|
||||
const int8 WSTable2Bit[] = { -2, -1, 0, 1 };
|
||||
const int8 WSTable4Bit[] = {
|
||||
-9, -8, -6, -5, -4, -3, -2, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 8
|
||||
};
|
||||
|
||||
byte *outbuf = (byte *)malloc(outsize);
|
||||
byte *in = inbuf;
|
||||
byte *out = outbuf;
|
||||
int16 curSample = 0x80;
|
||||
uint16 bytesLeft = outsize;
|
||||
|
||||
while (bytesLeft > 0) {
|
||||
uint16 input = *in++ << 2;
|
||||
byte code = (input >> 8) & 0xFF;
|
||||
int8 count = (input & 0xFF) >> 2;
|
||||
int i;
|
||||
|
||||
switch (code) {
|
||||
case 2:
|
||||
if (count & 0x20) {
|
||||
/* NOTE: count is signed! */
|
||||
count <<= 3;
|
||||
curSample += (count >> 3);
|
||||
*out++ = curSample;
|
||||
bytesLeft--;
|
||||
} else {
|
||||
for (; count >= 0; count--) {
|
||||
*out++ = *in++;
|
||||
bytesLeft--;
|
||||
}
|
||||
curSample = *(out - 1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (; count >= 0; count--) {
|
||||
code = *in++;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
curSample += WSTable4Bit[code & 0x0F];
|
||||
curSample = CLIP<int16>(curSample, 0, 255);
|
||||
code >>= 4;
|
||||
*out++ = curSample;
|
||||
}
|
||||
|
||||
bytesLeft -= 2;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
for (; count >= 0; count--) {
|
||||
code = *in++;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
curSample += WSTable2Bit[code & 0x03];
|
||||
curSample = CLIP<int16>(curSample, 0, 255);
|
||||
code >>= 2;
|
||||
*out++ = curSample;
|
||||
}
|
||||
|
||||
bytesLeft -= 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (; count >= 0; count--) {
|
||||
*out++ = curSample;
|
||||
bytesLeft--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_audioStream->queueBuffer(outbuf, outsize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
|
||||
free(inbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void VQADecoder::VQAAudioTrack::handleSND2(Common::SeekableReadStream *stream) {
|
||||
uint32 size = stream->readUint32BE();
|
||||
warning("VQADecoder::VQAAudioTrack::handleSND2(): `SND2' is not implemented");
|
||||
stream->seek(size, SEEK_CUR);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
VQADecoder::VQAVideoTrack::VQAVideoTrack(const VQAHeader *header) {
|
||||
memset(_palette, 0, sizeof(_palette));
|
||||
_dirtyPalette = false;
|
||||
|
||||
_width = header->width;
|
||||
_height = header->height;
|
||||
_blockW = header->blockW;
|
||||
_blockH = header->blockH;
|
||||
_cbParts = header->cbParts;
|
||||
|
||||
_newFrame = false;
|
||||
|
||||
_curFrame = -1;
|
||||
_frameCount = header->numFrames;
|
||||
_frameRate = header->frameRate;
|
||||
|
||||
_codeBookSize = 0xF00 * header->blockW * header->blockH;
|
||||
_compressedCodeBook = false;
|
||||
_codeBook = new byte[_codeBookSize]();
|
||||
_partialCodeBookSize = 0;
|
||||
_numPartialCodeBooks = 0;
|
||||
_partialCodeBook = new byte[_codeBookSize]();
|
||||
_numVectorPointers = (header->width / header->blockW) * (header->height * header->blockH);
|
||||
_vectorPointers = new uint16[_numVectorPointers]();
|
||||
|
||||
_surface = new Graphics::Surface();
|
||||
_surface->create(header->width, header->height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
}
|
||||
|
||||
VQADecoder::VQAVideoTrack::~VQAVideoTrack() {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
delete[] _codeBook;
|
||||
delete[] _partialCodeBook;
|
||||
delete[] _vectorPointers;
|
||||
}
|
||||
|
||||
uint16 VQADecoder::VQAVideoTrack::getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint16 VQADecoder::VQAVideoTrack::getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat VQADecoder::VQAVideoTrack::getPixelFormat() const {
|
||||
return _surface->format;
|
||||
}
|
||||
|
||||
int VQADecoder::VQAVideoTrack::getCurFrame() const {
|
||||
return _curFrame;
|
||||
}
|
||||
|
||||
int VQADecoder::VQAVideoTrack::getFrameCount() const {
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const {
|
||||
return _frameRate;
|
||||
}
|
||||
|
||||
void VQADecoder::VQAVideoTrack::setHasDirtyPalette() {
|
||||
_dirtyPalette = true;
|
||||
}
|
||||
|
||||
bool VQADecoder::VQAVideoTrack::hasDirtyPalette() const {
|
||||
return _dirtyPalette;
|
||||
}
|
||||
|
||||
const byte *VQADecoder::VQAVideoTrack::getPalette() const {
|
||||
_dirtyPalette = false;
|
||||
return _palette;
|
||||
}
|
||||
|
||||
const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeNextFrame() {
|
||||
if (_newFrame) {
|
||||
_newFrame = false;
|
||||
|
||||
int blockPitch = _width / _blockW;
|
||||
|
||||
for (int by = 0; by < _height / _blockH; by++) {
|
||||
for (int bx = 0; bx < blockPitch; bx++) {
|
||||
byte *dst = (byte *)_surface->getBasePtr(bx * _blockW, by * _blockH);
|
||||
int val = _vectorPointers[by * blockPitch + bx];
|
||||
int i;
|
||||
|
||||
if ((val & 0xFF00) == 0xFF00) {
|
||||
// Solid color
|
||||
for (i = 0; i < _blockH; i++) {
|
||||
memset(dst, 255 - (val & 0xFF), _blockW);
|
||||
dst += _width;
|
||||
}
|
||||
} else {
|
||||
// Copy data from _vectorPointers. I'm not sure
|
||||
// why we don't use the three least significant
|
||||
// bits of 'val'.
|
||||
byte *src = &_codeBook[(val >> 3) * _blockW * _blockH];
|
||||
|
||||
for (i = 0; i < _blockH; i++) {
|
||||
memcpy(dst, src, _blockW);
|
||||
src += _blockW;
|
||||
dst += _width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_numPartialCodeBooks == _cbParts) {
|
||||
if (_compressedCodeBook) {
|
||||
Screen::decodeFrame4(_partialCodeBook, _codeBook, _codeBookSize);
|
||||
} else {
|
||||
memcpy(_codeBook, _partialCodeBook, _partialCodeBookSize);
|
||||
}
|
||||
_numPartialCodeBooks = 0;
|
||||
_partialCodeBookSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_curFrame++;
|
||||
return _surface;
|
||||
}
|
||||
|
||||
void VQADecoder::VQAVideoTrack::handleVQFR(Common::SeekableReadStream *stream) {
|
||||
uint32 size = stream->readUint32BE();
|
||||
int32 end = stream->pos() + size - 8;
|
||||
byte *inbuf;
|
||||
|
||||
_newFrame = true;
|
||||
|
||||
while (stream->pos() < end) {
|
||||
uint32 tag = readTag(stream);
|
||||
uint32 i;
|
||||
size = stream->readUint32BE();
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('C','B','F','0'): // Full codebook
|
||||
stream->read(_codeBook, size);
|
||||
break;
|
||||
case MKTAG('C','B','F','Z'): // Full codebook
|
||||
inbuf = (byte *)malloc(size);
|
||||
stream->read(inbuf, size);
|
||||
Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize);
|
||||
free(inbuf);
|
||||
break;
|
||||
case MKTAG('C','B','P','0'): // Partial codebook
|
||||
_compressedCodeBook = false;
|
||||
stream->read(_partialCodeBook + _partialCodeBookSize, size);
|
||||
_partialCodeBookSize += size;
|
||||
_numPartialCodeBooks++;
|
||||
break;
|
||||
case MKTAG('C','B','P','Z'): // Partial codebook
|
||||
_compressedCodeBook = true;
|
||||
stream->read(_partialCodeBook + _partialCodeBookSize, size);
|
||||
_partialCodeBookSize += size;
|
||||
_numPartialCodeBooks++;
|
||||
break;
|
||||
case MKTAG('C','P','L','0'): // Palette
|
||||
assert(size <= 3 * 256);
|
||||
stream->read(_palette, size);
|
||||
break;
|
||||
case MKTAG('C','P','L','Z'): // Palette
|
||||
inbuf = (byte *)malloc(size);
|
||||
stream->read(inbuf, size);
|
||||
Screen::decodeFrame4(inbuf, _palette, 3 * 256);
|
||||
free(inbuf);
|
||||
break;
|
||||
case MKTAG('V','P','T','0'): // Frame data
|
||||
assert(size / 2 <= _numVectorPointers);
|
||||
for (i = 0; i < size / 2; i++)
|
||||
_vectorPointers[i] = stream->readUint16LE();
|
||||
break;
|
||||
case MKTAG('V','P','T','Z'): // Frame data
|
||||
inbuf = (byte *)malloc(size);
|
||||
stream->read(inbuf, size);
|
||||
size = Screen::decodeFrame4(inbuf, (uint8 *)_vectorPointers, 2 * _numVectorPointers);
|
||||
for (i = 0; i < size / 2; i++)
|
||||
_vectorPointers[i] = TO_LE_16(_vectorPointers[i]);
|
||||
free(inbuf);
|
||||
break;
|
||||
default:
|
||||
warning("VQADecoder::VQAVideoTrack::handleVQFR(): Unknown `VQFR' sub-tag `%s'", tag2str(tag));
|
||||
stream->seek(size, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
VQAMovie::VQAMovie(KyraEngine_v1 *vm, OSystem *system) {
|
||||
_system = system;
|
||||
_vm = vm;
|
||||
_screen = _vm->screen();
|
||||
_decoder = new VQADecoder();
|
||||
}
|
||||
|
||||
VQAMovie::~VQAMovie() {
|
||||
close();
|
||||
delete _decoder;
|
||||
}
|
||||
|
||||
bool VQAMovie::open(const char *filename) {
|
||||
if (_file.open(filename)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VQAMovie::close() {
|
||||
if (_file.isOpen()) {
|
||||
_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void VQAMovie::play() {
|
||||
if (_decoder->loadStream(&_file)) {
|
||||
Common::EventManager *eventMan = _vm->getEventManager();
|
||||
int width = _decoder->getWidth();
|
||||
int height = _decoder->getHeight();
|
||||
int x = (Screen::SCREEN_W - width) / 2;
|
||||
int y = (Screen::SCREEN_H - height) / 2;
|
||||
|
||||
_decoder->start();
|
||||
|
||||
// Note that decoding starts at frame -1. That's because there
|
||||
// is usually sound data before the first frame, probably to
|
||||
// avoid sound underflow.
|
||||
|
||||
while (!_decoder->endOfVideo()) {
|
||||
Common::Event event;
|
||||
while (eventMan->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_KEYDOWN:
|
||||
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
|
||||
return;
|
||||
break;
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
case Common::EVENT_QUIT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_decoder->needsUpdate()) {
|
||||
const Graphics::Surface *surface = _decoder->decodeNextFrame();
|
||||
if (_decoder->hasDirtyPalette()) {
|
||||
const byte *decoderPalette = _decoder->getPalette();
|
||||
byte systemPalette[256 * 3];
|
||||
for (int i = 0; i < ARRAYSIZE(systemPalette); i++) {
|
||||
systemPalette[i] = (decoderPalette[i] * 0xFF) / 0x3F;
|
||||
}
|
||||
_system->getPaletteManager()->setPalette(systemPalette, 0, 256);
|
||||
}
|
||||
|
||||
_system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, x, y, width, height);
|
||||
}
|
||||
|
||||
_screen->updateBackendScreen(true);
|
||||
_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
160
engines/kyra/graphics/vqa.h
Normal file
160
engines/kyra/graphics/vqa.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_VQA_H
|
||||
#define KYRA_VQA_H
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
#include "common/file.h"
|
||||
#include "common/rational.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Audio {
|
||||
class QueuingAudioStream;
|
||||
} // End of namespace Audio
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class KyraEngine_v1;
|
||||
class Screen;
|
||||
|
||||
class VQADecoder : public Video::VideoDecoder {
|
||||
public:
|
||||
VQADecoder();
|
||||
~VQADecoder() override;
|
||||
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
void readNextPacket() override;
|
||||
|
||||
private:
|
||||
Common::SeekableReadStream *_fileStream;
|
||||
|
||||
void handleVQHD(Common::SeekableReadStream *stream);
|
||||
void handleFINF(Common::SeekableReadStream *stream);
|
||||
|
||||
struct VQAHeader {
|
||||
uint16 version;
|
||||
uint16 flags;
|
||||
uint16 numFrames;
|
||||
uint16 width;
|
||||
uint16 height;
|
||||
uint8 blockW;
|
||||
uint8 blockH;
|
||||
uint8 frameRate;
|
||||
uint8 cbParts;
|
||||
uint16 colors;
|
||||
uint16 maxBlocks;
|
||||
uint32 unk1;
|
||||
uint16 unk2;
|
||||
uint16 freq;
|
||||
uint8 channels;
|
||||
uint8 bits;
|
||||
uint32 unk3;
|
||||
uint16 unk4;
|
||||
uint32 maxCBFZSize;
|
||||
uint32 unk5;
|
||||
};
|
||||
|
||||
VQAHeader _header;
|
||||
uint32 *_frameInfo;
|
||||
|
||||
class VQAAudioTrack : public AudioTrack {
|
||||
public:
|
||||
VQAAudioTrack(const VQAHeader *header, Audio::Mixer::SoundType soundType);
|
||||
~VQAAudioTrack() override;
|
||||
|
||||
void handleSND0(Common::SeekableReadStream *stream);
|
||||
void handleSND1(Common::SeekableReadStream *stream);
|
||||
void handleSND2(Common::SeekableReadStream *stream);
|
||||
|
||||
protected:
|
||||
Audio::AudioStream *getAudioStream() const override;
|
||||
|
||||
private:
|
||||
Audio::QueuingAudioStream *_audioStream;
|
||||
};
|
||||
|
||||
class VQAVideoTrack : public FixedRateVideoTrack {
|
||||
public:
|
||||
VQAVideoTrack(const VQAHeader *header);
|
||||
~VQAVideoTrack() override;
|
||||
|
||||
uint16 getWidth() const override;
|
||||
uint16 getHeight() const override;
|
||||
Graphics::PixelFormat getPixelFormat() const override;
|
||||
int getCurFrame() const override;
|
||||
int getFrameCount() const override;
|
||||
const Graphics::Surface *decodeNextFrame() override;
|
||||
|
||||
void setHasDirtyPalette();
|
||||
bool hasDirtyPalette() const override;
|
||||
const byte *getPalette() const override;
|
||||
|
||||
void handleVQFR(Common::SeekableReadStream *stream);
|
||||
|
||||
protected:
|
||||
Common::Rational getFrameRate() const override;
|
||||
|
||||
private:
|
||||
Graphics::Surface *_surface;
|
||||
byte _palette[3 * 256];
|
||||
mutable bool _dirtyPalette;
|
||||
|
||||
bool _newFrame;
|
||||
|
||||
uint16 _width, _height;
|
||||
uint8 _blockW, _blockH;
|
||||
uint8 _cbParts;
|
||||
int _frameCount;
|
||||
int _curFrame;
|
||||
byte _frameRate;
|
||||
|
||||
uint32 _codeBookSize;
|
||||
bool _compressedCodeBook;
|
||||
byte *_codeBook;
|
||||
int _partialCodeBookSize;
|
||||
int _numPartialCodeBooks;
|
||||
byte *_partialCodeBook;
|
||||
uint32 _numVectorPointers;
|
||||
uint16 *_vectorPointers;
|
||||
};
|
||||
};
|
||||
|
||||
class VQAMovie {
|
||||
public:
|
||||
VQAMovie(KyraEngine_v1 *vm, OSystem *system);
|
||||
~VQAMovie();
|
||||
|
||||
bool open(const char *filename);
|
||||
void close();
|
||||
void play();
|
||||
private:
|
||||
OSystem *_system;
|
||||
KyraEngine_v1 *_vm;
|
||||
Screen *_screen;
|
||||
VQADecoder *_decoder;
|
||||
Common::File _file;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
458
engines/kyra/graphics/wsamovie.cpp
Normal file
458
engines/kyra/graphics/wsamovie.cpp
Normal file
@@ -0,0 +1,458 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/graphics/wsamovie.h"
|
||||
#include "kyra/resource/resource.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
WSAMovie_v1::WSAMovie_v1(KyraEngine_v1 *vm) : Movie(vm), _frameData(nullptr), _frameOffsTable(nullptr),
|
||||
_offscreenBuffer(nullptr), _deltaBuffer(nullptr), _currentFrame(0), _numFrames(0), _width(0), _height(0), _flags(0), _deltaBufferSize(0) {
|
||||
}
|
||||
|
||||
WSAMovie_v1::~WSAMovie_v1() {
|
||||
close();
|
||||
}
|
||||
|
||||
int WSAMovie_v1::open(const char *filename, int offscreenDecode, Palette *palBuf) {
|
||||
close();
|
||||
|
||||
uint32 flags = 0;
|
||||
uint32 fileSize;
|
||||
uint8 *p = _vm->resource()->fileData(filename, &fileSize);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
const uint8 *wsaData = p;
|
||||
_numFrames = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_width = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_height = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_offscreenBuffer = nullptr;
|
||||
_flags = 0;
|
||||
if (_vm->gameFlags().useAltShapeHeader) {
|
||||
flags = READ_LE_UINT16(wsaData);
|
||||
wsaData += 2;
|
||||
}
|
||||
|
||||
uint32 offsPal = 0;
|
||||
if (flags & 1) {
|
||||
offsPal = 0x300;
|
||||
_flags |= WF_HAS_PALETTE;
|
||||
if (palBuf)
|
||||
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300);
|
||||
}
|
||||
|
||||
if (offscreenDecode) {
|
||||
_flags |= WF_OFFSCREEN_DECODE;
|
||||
const int offscreenBufferSize = _width * _height;
|
||||
_offscreenBuffer = new uint8[offscreenBufferSize]();
|
||||
}
|
||||
|
||||
if (_numFrames & 0x8000) {
|
||||
// This is used in the Amiga version.
|
||||
if (_vm->gameFlags().platform != Common::kPlatformAmiga)
|
||||
warning("Unhandled wsa flags 0x8000");
|
||||
_flags |= WF_FLIPPED;
|
||||
_numFrames &= 0x7FFF;
|
||||
}
|
||||
_currentFrame = _numFrames;
|
||||
|
||||
_deltaBuffer = new uint8[_deltaBufferSize]();
|
||||
|
||||
// read frame offsets
|
||||
_frameOffsTable = new uint32[_numFrames + 2];
|
||||
_frameOffsTable[0] = 0;
|
||||
uint32 frameDataOffs = READ_LE_UINT32(wsaData); wsaData += 4;
|
||||
bool firstFrame = true;
|
||||
|
||||
if (frameDataOffs == 0) {
|
||||
firstFrame = false;
|
||||
frameDataOffs = READ_LE_UINT32(wsaData);
|
||||
_flags |= WF_NO_FIRST_FRAME;
|
||||
}
|
||||
|
||||
for (int i = 1; i < _numFrames + 2; ++i) {
|
||||
_frameOffsTable[i] = READ_LE_UINT32(wsaData);
|
||||
if (_frameOffsTable[i])
|
||||
_frameOffsTable[i] -= frameDataOffs;
|
||||
wsaData += 4;
|
||||
}
|
||||
|
||||
if (!_frameOffsTable[_numFrames + 1])
|
||||
_flags |= WF_NO_LAST_FRAME;
|
||||
|
||||
// skip palette
|
||||
wsaData += offsPal;
|
||||
|
||||
// read frame data
|
||||
const int frameDataSize = p + fileSize - wsaData;
|
||||
_frameData = new uint8[frameDataSize];
|
||||
memcpy(_frameData, wsaData, frameDataSize);
|
||||
|
||||
// decode first frame
|
||||
if (firstFrame)
|
||||
Screen::decodeFrame4(_frameData, _deltaBuffer, _deltaBufferSize);
|
||||
|
||||
delete[] p;
|
||||
_opened = true;
|
||||
|
||||
return _numFrames;
|
||||
}
|
||||
|
||||
void WSAMovie_v1::close() {
|
||||
if (_opened) {
|
||||
delete[] _deltaBuffer;
|
||||
delete[] _offscreenBuffer;
|
||||
delete[] _frameOffsTable;
|
||||
delete[] _frameData;
|
||||
_opened = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WSAMovie_v1::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) {
|
||||
if (frameNum >= _numFrames || frameNum < 0 || !_opened)
|
||||
return;
|
||||
|
||||
_x = x;
|
||||
_y = y;
|
||||
_drawPage = pageNum;
|
||||
|
||||
uint8 *dst = nullptr;
|
||||
if (_flags & WF_OFFSCREEN_DECODE)
|
||||
dst = _offscreenBuffer;
|
||||
else
|
||||
dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height);
|
||||
|
||||
if (_currentFrame == _numFrames) {
|
||||
if (!(_flags & WF_NO_FIRST_FRAME)) {
|
||||
if (_flags & WF_OFFSCREEN_DECODE)
|
||||
Screen::decodeFrameDelta(dst, _deltaBuffer);
|
||||
else
|
||||
Screen::decodeFrameDeltaPage(dst, _deltaBuffer, _width, (_flags & WF_XOR) == 0);
|
||||
}
|
||||
_currentFrame = 0;
|
||||
}
|
||||
|
||||
// try to reduce the number of needed frame operations
|
||||
int diffCount = ABS(_currentFrame - frameNum);
|
||||
int frameStep = 1;
|
||||
int frameCount;
|
||||
if (_currentFrame < frameNum) {
|
||||
frameCount = _numFrames - frameNum + _currentFrame;
|
||||
if (diffCount > frameCount && !(_flags & WF_NO_LAST_FRAME))
|
||||
frameStep = -1;
|
||||
else
|
||||
frameCount = diffCount;
|
||||
} else {
|
||||
frameCount = _numFrames - _currentFrame + frameNum;
|
||||
if (frameCount >= diffCount || (_flags & WF_NO_LAST_FRAME)) {
|
||||
frameStep = -1;
|
||||
frameCount = diffCount;
|
||||
}
|
||||
}
|
||||
|
||||
// process
|
||||
if (frameStep > 0) {
|
||||
uint16 cf = _currentFrame;
|
||||
while (frameCount--) {
|
||||
cf += frameStep;
|
||||
processFrame(cf, dst);
|
||||
if (cf == _numFrames)
|
||||
cf = 0;
|
||||
}
|
||||
} else {
|
||||
uint16 cf = _currentFrame;
|
||||
while (frameCount--) {
|
||||
if (cf == 0)
|
||||
cf = _numFrames;
|
||||
processFrame(cf, dst);
|
||||
cf += frameStep;
|
||||
}
|
||||
}
|
||||
|
||||
// display
|
||||
_currentFrame = frameNum;
|
||||
if (_flags & WF_OFFSCREEN_DECODE) {
|
||||
int pageBackUp = _screen->setCurPage(_drawPage);
|
||||
|
||||
int plotFunc = (flags & 0xFF00) >> 12;
|
||||
int unk1 = flags & 0xFF;
|
||||
|
||||
_screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2);
|
||||
|
||||
_screen->_curPage = pageBackUp;
|
||||
}
|
||||
}
|
||||
|
||||
void WSAMovie_v1::processFrame(int frameNum, uint8 *dst) {
|
||||
if (!_opened)
|
||||
return;
|
||||
assert(frameNum <= _numFrames);
|
||||
const uint8 *src = _frameData + _frameOffsTable[frameNum];
|
||||
Screen::decodeFrame4(src, _deltaBuffer, _deltaBufferSize);
|
||||
if (_flags & WF_OFFSCREEN_DECODE)
|
||||
Screen::decodeFrameDelta(dst, _deltaBuffer);
|
||||
else
|
||||
Screen::decodeFrameDeltaPage(dst, _deltaBuffer, _width, false);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
WSAMovieAmiga::WSAMovieAmiga(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _buffer(nullptr) {}
|
||||
|
||||
int WSAMovieAmiga::open(const char *filename, int offscreenDecode, Palette *palBuf) {
|
||||
int res = WSAMovie_v1::open(filename, offscreenDecode, palBuf);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
_buffer = new uint8[_width * _height];
|
||||
assert(_buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
void WSAMovieAmiga::close() {
|
||||
if (_opened) {
|
||||
delete[] _buffer;
|
||||
_buffer = nullptr;
|
||||
}
|
||||
WSAMovie_v1::close();
|
||||
}
|
||||
|
||||
void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) {
|
||||
if (frameNum >= _numFrames || frameNum < 0 || !_opened)
|
||||
return;
|
||||
|
||||
_x = x;
|
||||
_y = y;
|
||||
_drawPage = pageNum;
|
||||
|
||||
uint8 *dst;
|
||||
dst = _buffer;
|
||||
memset(_buffer, 0, _width * _height);
|
||||
|
||||
if (_currentFrame == _numFrames) {
|
||||
if (!(_flags & WF_NO_FIRST_FRAME)) {
|
||||
Screen::decodeFrameDelta(dst, _deltaBuffer, true);
|
||||
Screen::convertAmigaGfx(dst, _width, _height, 5, (_flags & WF_FLIPPED) != 0);
|
||||
|
||||
if (_flags & WF_OFFSCREEN_DECODE) {
|
||||
dst = _offscreenBuffer;
|
||||
const uint8 *src = _buffer;
|
||||
int size = _width * _height;
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
*dst++ ^= *src++;
|
||||
|
||||
dst = _buffer;
|
||||
} else {
|
||||
_screen->copyBlockToPage(_drawPage, _x, _y, _width, _height, _buffer);
|
||||
}
|
||||
}
|
||||
_currentFrame = 0;
|
||||
}
|
||||
|
||||
// try to reduce the number of needed frame operations
|
||||
int diffCount = ABS(_currentFrame - frameNum);
|
||||
int frameStep = 1;
|
||||
int frameCount;
|
||||
if (_currentFrame < frameNum) {
|
||||
frameCount = _numFrames - frameNum + _currentFrame;
|
||||
if (diffCount > frameCount && !(_flags & WF_NO_LAST_FRAME))
|
||||
frameStep = -1;
|
||||
else
|
||||
frameCount = diffCount;
|
||||
} else {
|
||||
frameCount = _numFrames - _currentFrame + frameNum;
|
||||
if (frameCount >= diffCount || (_flags & WF_NO_LAST_FRAME)) {
|
||||
frameStep = -1;
|
||||
frameCount = diffCount;
|
||||
}
|
||||
}
|
||||
|
||||
// process
|
||||
if (frameStep > 0) {
|
||||
uint16 cf = _currentFrame;
|
||||
while (frameCount--) {
|
||||
cf += frameStep;
|
||||
processFrame(cf, dst);
|
||||
if (cf == _numFrames)
|
||||
cf = 0;
|
||||
}
|
||||
} else {
|
||||
uint16 cf = _currentFrame;
|
||||
while (frameCount--) {
|
||||
if (cf == 0)
|
||||
cf = _numFrames;
|
||||
processFrame(cf, dst);
|
||||
cf += frameStep;
|
||||
}
|
||||
}
|
||||
|
||||
// display
|
||||
_currentFrame = frameNum;
|
||||
if (_flags & WF_OFFSCREEN_DECODE) {
|
||||
int pageBackUp = _screen->setCurPage(_drawPage);
|
||||
|
||||
int plotFunc = (flags & 0xFF00) >> 12;
|
||||
int unk1 = flags & 0xFF;
|
||||
|
||||
_screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2);
|
||||
|
||||
_screen->_curPage = pageBackUp;
|
||||
}
|
||||
}
|
||||
|
||||
void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) {
|
||||
if (!_opened)
|
||||
return;
|
||||
assert(frameNum <= _numFrames);
|
||||
|
||||
memset(dst, 0, _width * _height);
|
||||
|
||||
const uint8 *src = _frameData + _frameOffsTable[frameNum];
|
||||
Screen::decodeFrame4(src, _deltaBuffer, _deltaBufferSize);
|
||||
Screen::decodeFrameDelta(dst, _deltaBuffer, true);
|
||||
Screen::convertAmigaGfx(dst, _width, _height, 5, (_flags & WF_FLIPPED) != 0);
|
||||
|
||||
src = dst;
|
||||
dst = nullptr;
|
||||
int dstPitch = 0;
|
||||
if (_flags & WF_OFFSCREEN_DECODE) {
|
||||
dst = _offscreenBuffer;
|
||||
dstPitch = _width;
|
||||
} else {
|
||||
dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height);
|
||||
dstPitch = Screen::SCREEN_W;
|
||||
}
|
||||
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
for (int x = 0; x < _width; ++x)
|
||||
*dst++ ^= *src++;
|
||||
dst += dstPitch - _width;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
WSAMovie_v2::WSAMovie_v2(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _xAdd(0), _yAdd(0) {}
|
||||
|
||||
int WSAMovie_v2::open(const char *filename, int unk1, Palette *palBuf) {
|
||||
close();
|
||||
|
||||
uint32 flags = 0;
|
||||
uint32 fileSize;
|
||||
uint8 *p = _vm->resource()->fileData(filename, &fileSize);
|
||||
if (!p) {
|
||||
warning("couldn't load wsa file: '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8 *wsaData = p;
|
||||
_numFrames = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_xAdd = (int16)(READ_LE_UINT16(wsaData)); wsaData += 2;
|
||||
_yAdd = (int16)(READ_LE_UINT16(wsaData)); wsaData += 2;
|
||||
_width = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_height = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
_offscreenBuffer = nullptr;
|
||||
_flags = 0;
|
||||
flags = READ_LE_UINT16(wsaData); wsaData += 2;
|
||||
|
||||
uint32 offsPal = 0;
|
||||
if (flags & 1) {
|
||||
offsPal = 0x300;
|
||||
_flags |= WF_HAS_PALETTE;
|
||||
if (palBuf)
|
||||
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300);
|
||||
}
|
||||
|
||||
if (flags & 2) {
|
||||
if (_vm->gameFlags().use16ColorMode) {
|
||||
offsPal = 0x30;
|
||||
_flags |= WF_HAS_PALETTE;
|
||||
if (palBuf)
|
||||
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x30);
|
||||
}
|
||||
|
||||
_flags |= WF_XOR;
|
||||
}
|
||||
|
||||
|
||||
if (!(unk1 & 2)) {
|
||||
_flags |= WF_OFFSCREEN_DECODE;
|
||||
const int offscreenBufferSize = _width * _height;
|
||||
_offscreenBuffer = new uint8[offscreenBufferSize]();
|
||||
}
|
||||
|
||||
if (_numFrames & 0x8000) {
|
||||
warning("Unhandled wsa flags 0x80");
|
||||
_flags |= 0x80;
|
||||
_numFrames &= 0x7FFF;
|
||||
}
|
||||
_currentFrame = _numFrames;
|
||||
|
||||
_deltaBuffer = new uint8[_deltaBufferSize]();
|
||||
|
||||
// read frame offsets
|
||||
_frameOffsTable = new uint32[_numFrames + 2];
|
||||
_frameOffsTable[0] = 0;
|
||||
uint32 frameDataOffs = READ_LE_UINT32(wsaData); wsaData += 4;
|
||||
bool firstFrame = true;
|
||||
if (frameDataOffs == 0) {
|
||||
firstFrame = false;
|
||||
frameDataOffs = READ_LE_UINT32(wsaData);
|
||||
_flags |= WF_NO_FIRST_FRAME;
|
||||
}
|
||||
|
||||
for (int i = 1; i < _numFrames + 2; ++i) {
|
||||
_frameOffsTable[i] = READ_LE_UINT32(wsaData);
|
||||
if (_frameOffsTable[i])
|
||||
_frameOffsTable[i] -= frameDataOffs;
|
||||
wsaData += 4;
|
||||
}
|
||||
|
||||
if (!_frameOffsTable[_numFrames + 1])
|
||||
_flags |= WF_NO_LAST_FRAME;
|
||||
|
||||
// skip palette
|
||||
wsaData += offsPal;
|
||||
|
||||
// read frame data
|
||||
const int frameDataSize = p + fileSize - wsaData;
|
||||
|
||||
_frameData = new uint8[frameDataSize];
|
||||
memcpy(_frameData, wsaData, frameDataSize);
|
||||
|
||||
// decode first frame
|
||||
if (firstFrame)
|
||||
Screen::decodeFrame4(_frameData, _deltaBuffer, _deltaBufferSize);
|
||||
|
||||
delete[] p;
|
||||
_opened = true;
|
||||
|
||||
return _numFrames;
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
133
engines/kyra/graphics/wsamovie.h
Normal file
133
engines/kyra/graphics/wsamovie.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KYRA_WSAMOVIE_H
|
||||
#define KYRA_WSAMOVIE_H
|
||||
|
||||
#include "kyra/kyra_v1.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
class Palette;
|
||||
|
||||
class Movie {
|
||||
public:
|
||||
Movie(KyraEngine_v1 *vm) : _vm(vm), _screen(vm->screen()), _opened(false), _x(-1), _y(-1), _drawPage(-1) {}
|
||||
virtual ~Movie() {}
|
||||
|
||||
virtual bool opened() { return _opened; }
|
||||
|
||||
virtual int xAdd() const { return 0; }
|
||||
virtual int yAdd() const { return 0; }
|
||||
|
||||
virtual int width() const = 0;
|
||||
virtual int height() const = 0;
|
||||
|
||||
virtual int open(const char *filename, int offscreen, Palette *palette) = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual int frames() = 0;
|
||||
|
||||
virtual void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) = 0;
|
||||
|
||||
protected:
|
||||
KyraEngine_v1 *_vm;
|
||||
Screen *_screen;
|
||||
bool _opened;
|
||||
|
||||
int _x, _y;
|
||||
int _drawPage;
|
||||
};
|
||||
|
||||
class WSAMovie_v1 : public Movie {
|
||||
public:
|
||||
WSAMovie_v1(KyraEngine_v1 *vm);
|
||||
~WSAMovie_v1() override;
|
||||
|
||||
int width() const override { return _width; }
|
||||
int height() const override { return _height; }
|
||||
|
||||
int open(const char *filename, int offscreen, Palette *palette) override;
|
||||
void close() override;
|
||||
|
||||
int frames() override { return _opened ? _numFrames : -1; }
|
||||
|
||||
void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) override;
|
||||
|
||||
enum WSAFlags {
|
||||
WF_OFFSCREEN_DECODE = 0x10,
|
||||
WF_NO_LAST_FRAME = 0x20,
|
||||
WF_NO_FIRST_FRAME = 0x40,
|
||||
WF_FLIPPED = 0x80,
|
||||
WF_HAS_PALETTE = 0x100,
|
||||
WF_XOR = 0x200
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void processFrame(int frameNum, uint8 *dst);
|
||||
|
||||
uint16 _currentFrame;
|
||||
uint16 _numFrames;
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
uint16 _flags;
|
||||
uint8 *_deltaBuffer;
|
||||
uint32 _deltaBufferSize;
|
||||
uint8 *_offscreenBuffer;
|
||||
uint32 *_frameOffsTable;
|
||||
uint8 *_frameData;
|
||||
};
|
||||
|
||||
class WSAMovieAmiga : public WSAMovie_v1 {
|
||||
public:
|
||||
WSAMovieAmiga(KyraEngine_v1 *vm);
|
||||
int open(const char *filename, int offscreen, Palette *palette) override;
|
||||
void close() override;
|
||||
|
||||
void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) override;
|
||||
private:
|
||||
void processFrame(int frameNum, uint8 *dst) override;
|
||||
|
||||
uint8 *_buffer;
|
||||
};
|
||||
|
||||
class WSAMovie_v2 : public WSAMovie_v1 {
|
||||
public:
|
||||
WSAMovie_v2(KyraEngine_v1 *vm);
|
||||
|
||||
int open(const char *filename, int unk1, Palette *palette) override;
|
||||
void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) override {
|
||||
WSAMovie_v1::displayFrame(frameNum, pageNum, x + _xAdd, y + _yAdd, flags, table1, table2);
|
||||
}
|
||||
|
||||
int xAdd() const override { return _xAdd; }
|
||||
int yAdd() const override { return _yAdd; }
|
||||
|
||||
void setWidth(int w) { _width = w; }
|
||||
void setHeight(int h) { _height = h; }
|
||||
protected:
|
||||
int16 _xAdd;
|
||||
int16 _yAdd;
|
||||
};
|
||||
|
||||
} // End of namespace Kyra
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user