From 3830ac06b367b920ca012c5c734e1bc32fcbcd73 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Mon, 8 May 2006 10:21:17 +0000 Subject: Add initial DXA support for HE games svn-id: r22384 --- engines/scumm/he/animation_he.cpp | 274 ++++++++++++++++++++++++++++++++++++++ engines/scumm/he/animation_he.h | 72 ++++++++++ engines/scumm/he/intern_he.h | 3 + engines/scumm/he/script_v90he.cpp | 23 ++-- engines/scumm/he/wiz_he.cpp | 39 +++--- engines/scumm/he/wiz_he.h | 2 +- engines/scumm/module.mk | 1 + engines/scumm/scumm.cpp | 6 + 8 files changed, 391 insertions(+), 29 deletions(-) create mode 100644 engines/scumm/he/animation_he.cpp create mode 100644 engines/scumm/he/animation_he.h (limited to 'engines/scumm') diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp new file mode 100644 index 0000000000..c7f9455a46 --- /dev/null +++ b/engines/scumm/he/animation_he.cpp @@ -0,0 +1,274 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" + +#include "common/rect.h" + +#include "scumm/he/animation_he.h" +#include "scumm/he/intern_he.h" + +#ifdef USE_ZLIB +#include +#endif + +namespace Scumm { + +MoviePlayer::MoviePlayer(ScummEngine_v90he *vm) + : _vm(vm) { + + _frameBuffer1 = 0; + _frameBuffer2 = 0; + + _width = 0; + _height = 0; + + _frameSize = 0; + _framesCount = 0; + _frameNum = 0; + _framesPerSec = 0; + _frameTicks = 0; + + _flags = 0; + _wizResNum = 0; +} + +MoviePlayer::~MoviePlayer() { +} + +int MoviePlayer::getWidth() { + if (_fd.isOpen() == false) + return 0; + return _width; +} + +int MoviePlayer::getHeight() { + if (_fd.isOpen() == false) + return 0; + return _height; +} + +int MoviePlayer::getCurFrame() { + if (_fd.isOpen() == false) + return -1; + return _frameNum; +} + +int MoviePlayer::getFrameCount() { + if (_fd.isOpen() == false) + return 0; + return _framesCount; +} + +int MoviePlayer::getImageNum() { + if (_fd.isOpen() == false) + return 0; + return _wizResNum; +} + +int MoviePlayer::load(const char *filename, int flags, int image) { + char filename2[100]; + uint32 tag; + int32 frameRate; + + if (_fd.isOpen() == true) { + close(); + } + + // Change file extension to dxa + strcpy(filename2, filename); + int len = strlen(filename2) - 3; + filename2[len++] = 'd'; + filename2[len++] = 'x'; + filename2[len++] = 'a'; + + if (_fd.open(filename2) == false) { + warning("Failed to load video file %s", filename2); + return -1; + } + debug(0, "Playing video %s", filename2); + + tag = _fd.readUint32BE(); + assert(tag == MKID_BE('DEXA')); + + _fd.readByte(); + _framesCount = _fd.readUint16BE(); + frameRate = _fd.readUint32BE(); + + if (frameRate > 0) + _framesPerSec = 1000 / frameRate; + else if (frameRate < 0) + _framesPerSec = 100000 / (-frameRate); + else + _framesPerSec = 10; + + if (frameRate < 0) + _frameTicks = -frameRate / 100; + else + _frameTicks = frameRate; + + _width = _fd.readUint16BE(); + _height = _fd.readUint16BE(); + + // Skip sound tag + _fd.readUint32BE(); + + debug(0, "frames_count %d width %d height %d rate %d ticks %d", _framesCount, _width, _height, _framesPerSec, _frameTicks); + + _frameSize = _width * _height; + _frameBuffer1 = (uint8 *)malloc(_frameSize); + _frameBuffer2 = (uint8 *)malloc(_frameSize); + if (!_frameBuffer1 || !_frameBuffer2) { + error("error allocating frame tables, size %d\n", _frameSize); + } + + if (flags & 2) { + _vm->_wiz->createWizEmptyImage(image, 0, 0, _width, _height); + } + + _frameNum = 0; + + _flags = flags; + _wizResNum = image; + + return 0; +} + +void MoviePlayer::close() { + _fd.close(); + free(_frameBuffer1); + free(_frameBuffer2); +} + +void MoviePlayer::handleNextFrame() { + if (_fd.isOpen() == false) { + return; + } + + VirtScreen *pvs = &_vm->virtscr[kMainVirtScreen]; + uint8 *dst; + + decodeFrame(); + + if (_flags & 2) { + uint8 *dstPtr = _vm->getResourceAddress(rtImage, _wizResNum); + assert(dstPtr); + dst = _vm->findWrappedBlock(MKID_BE('WIZD'), dstPtr, 0, 0); + assert(dst); + copyFrame(dst, 0, 0); + } else if (_flags & 1) { + dst = pvs->getBackPixels(0, 0); + copyFrame(dst, 0, 0); + + Common::Rect imageRect(_width, _height); + _vm->gdi.copyVirtScreenBuffers(imageRect); + } else { + dst = pvs->getPixels(0, 0); + copyFrame(dst, 0, 0); + + _vm->markRectAsDirty(kMainVirtScreen, 0, 0, _width, _height); + } + + _frameNum++; + if (_frameNum == _framesCount) { + close(); + } +} + +void MoviePlayer::copyFrame(byte *dst, uint x, uint y) { + uint h = _height; + uint w = _width; + + dst += y * _vm->_screenWidth + x; + byte *src = _frameBuffer1; + + do { + memcpy(dst, src, w); + dst += _vm->_screenWidth; + src += _width; + } while (--h); +} + +void MoviePlayer::decodeZlib(uint8 *data, int size, int totalSize) { +#ifdef USE_ZLIB + uint8 *temp = (uint8 *)malloc(size); + if (temp) { + memcpy(temp, data, size); + z_stream d_stream; + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + d_stream.next_in = temp; + d_stream.avail_in = size; + d_stream.total_in = size; + d_stream.next_out = data; + d_stream.avail_out = totalSize; + inflateInit(&d_stream); + inflate(&d_stream, Z_FINISH); + inflateEnd(&d_stream); + free(temp); + } +#endif +} + +void MoviePlayer::decodeFrame() { + uint32 tag; + + tag = _fd.readUint32BE(); + if (tag == MKID_BE('CMAP')) { + uint8 rgb[768]; + + _fd.read(rgb, ARRAYSIZE(rgb)); + _vm->setPaletteFromPtr(rgb, 256); + } + + tag = _fd.readUint32BE(); + if (tag == MKID_BE('FRAM')) { + uint8 type = _fd.readByte(); + uint32 size = _fd.readUint32BE(); + debug(0, "frame %d type %d size %d", _frameNum, type, size); + + _fd.read(_frameBuffer2, size); + + switch (type) { + case 2: + case 3: + decodeZlib(_frameBuffer2, size, _frameSize); + break; + default: + error("decodeFrame: Unknown compression type %d", type); + } + if (type == 2) { + memcpy(_frameBuffer1, _frameBuffer2, _frameSize); + } else { + for (int j = 0; j < _height; ++j) { + for (int i = 0; i < _width; ++i) { + const int offs = j * _width + i; + _frameBuffer1[offs] ^= _frameBuffer2[offs]; + } + } + } + } +} + +} // End of namespace Simon diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h new file mode 100644 index 0000000000..d55f2feb05 --- /dev/null +++ b/engines/scumm/he/animation_he.h @@ -0,0 +1,72 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef ANIMATION_H +#define ANIMATION_H + +#include "common/file.h" + +namespace Scumm { + +class ScummEngine_v90he; + +class MoviePlayer { + ScummEngine_v90he *_vm; + + Common::File _fd; + uint8 *_frameBuffer1; + uint8 *_frameBuffer2; + uint16 _width; + uint16 _height; + uint16 _framesCount; + uint32 _framesPerSec; + uint16 _frameNum; + uint32 _frameSize; + uint32 _frameTicks; + + uint32 _flags; + uint32 _wizResNum; + +public: + MoviePlayer(ScummEngine_v90he *vm); + ~MoviePlayer(); + + int getWidth(); + int getHeight(); + int getCurFrame(); + int getFrameCount(); + int getImageNum(); + int load(const char *filename, int flags, int image = 0); + + void handleNextFrame(); + void close(); + +private: + void copyFrame(byte *dst, uint x, uint y); + void decodeFrame(); + void decodeZlib(uint8 *data, int size, int totalSize); +}; + +} // End of namespace Simon + +#endif diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index ad67e47032..a58271d636 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -40,6 +40,7 @@ namespace Scumm { #ifndef DISABLE_HE class ResExtractor; class LogicHE; +class MoviePlayer; class Sprite; #endif @@ -402,6 +403,7 @@ protected: class ScummEngine_v90he : public ScummEngine_v80he { friend class LogicHE; + friend class MoviePlayer; friend class Sprite; protected: @@ -439,6 +441,7 @@ public: virtual void resetScumm(); LogicHE *_logicHE; + MoviePlayer *_moviePlay; Sprite *_sprite; protected: diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index e0e023585c..fc00579919 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -25,6 +25,7 @@ #include "scumm/actor.h" #include "scumm/charset.h" +#include "scumm/he/animation_he.h" #include "scumm/he/intern_he.h" #include "scumm/he/logic_he.h" #include "scumm/object.h" @@ -515,6 +516,7 @@ void ScummEngine_v90he::o90_videoOps() { int status = fetchScriptByte(); int subOp = status - 49; + debug(0, "o90_videoOps stub (%d)", subOp); switch (subOp) { case 0: copyScriptString(_videoParams.filename, sizeof(_videoParams.filename)); @@ -542,21 +544,20 @@ void ScummEngine_v90he::o90_videoOps() { _videoParams.flags = 4; if (_videoParams.flags == 2) { - // result = startVideo(_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); - // VAR(119) = result; + int result = _moviePlay->load((const char *)_videoParams.filename, _videoParams.flags, _videoParams.wizResNum); + VAR(119) = result; } else { - // result = startVideo(_videoParams.filename, _videoParams.flags); - // VAR(119) = result; + int result = _moviePlay->load((const char *)_videoParams.filename, _videoParams.flags); + VAR(119) = result; } } else if (_videoParams.status == 165) { // Stop video + _moviePlay->close(); } break; default: error("o90_videoOps: unhandled case %d", subOp); } - - debug(1, "o90_videoOps stub (%d)", subOp); } void ScummEngine_v90he::o90_getVideoData() { @@ -564,32 +565,36 @@ void ScummEngine_v90he::o90_getVideoData() { byte subOp = fetchScriptByte(); subOp -= 32; + debug(0, "o90_getVideoData stub (%d)", subOp); switch (subOp) { case 0: // Get width pop(); + push(_moviePlay->getWidth()); break; case 1: // Get height pop(); + push(_moviePlay->getHeight()); break; case 4: // Get frame count pop(); + push(_moviePlay->getFrameCount()); break; case 20: // Get current frame pop(); + push(_moviePlay->getCurFrame()); break; case 31: // Get image number pop(); + push(_moviePlay->getImageNum()); break; case 107: // Get statistics pop(); pop(); + push(0); break; default: error("o90_getVideoData: unhandled case %d", subOp); } - - push(-1); - debug(1, "o90_getVideoData stub (%d)", subOp); } void ScummEngine_v90he::o90_wizImageOps() { diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index 55de8831ce..5597741578 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -1617,21 +1617,7 @@ void Wiz::displayWizComplexImage(const WizParameters *params) { } } -void Wiz::createWizEmptyImage(const WizParameters *params) { - int img_w = 640; - if (params->processFlags & kWPFUseDefImgWidth) { - img_w = params->resDefImgW; - } - int img_h = 480; - if (params->processFlags & kWPFUseDefImgHeight) { - img_h = params->resDefImgH; - } - int img_x = 0; - int img_y = 0; - if (params->processFlags & 1) { - img_x = params->img.x1; - img_y = params->img.y1; - } +void Wiz::createWizEmptyImage(int resNum, int img_x, int img_y, int img_w, int img_h) { const uint16 flags = 0xB; int res_size = 0x1C; if (flags & 1) { @@ -1651,7 +1637,7 @@ void Wiz::createWizEmptyImage(const WizParameters *params) { } else { palPtr = _vm->_currentPalette; } - uint8 *res_data = _vm->res.createResource(rtImage, params->img.resNum, res_size); + uint8 *res_data = _vm->res.createResource(rtImage, resNum, res_size); if (!res_data) { _vm->VAR(119) = -1; } else { @@ -1685,7 +1671,7 @@ void Wiz::createWizEmptyImage(const WizParameters *params) { WRITE_BE_UINT32(res_data, 'WIZD'); res_data += 4; WRITE_BE_UINT32(res_data, 8 + img_w * img_h); res_data += 4; } - _vm->res.setModified(rtImage, params->img.resNum); + _vm->res.setModified(rtImage, resNum); } void Wiz::fillWizRect(const WizParameters *params) { @@ -1971,8 +1957,23 @@ void Wiz::processWizImage(const WizParameters *params) { // TODO: Capture polygon _vm->res.setModified(rtImage, params->img.resNum); break; - case 8: - createWizEmptyImage(params); + case 8: { + int img_w = 640; + if (params->processFlags & kWPFUseDefImgWidth) { + img_w = params->resDefImgW; + } + int img_h = 480; + if (params->processFlags & kWPFUseDefImgHeight) { + img_h = params->resDefImgH; + } + int img_x = 0; + int img_y = 0; + if (params->processFlags & 1) { + img_x = params->img.x1; + img_y = params->img.y1; + } + createWizEmptyImage(params->img.resNum, img_x, img_y, img_w, img_h); + } break; case 9: fillWizRect(params); diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h index f9cd884b7d..88e0db50a9 100644 --- a/engines/scumm/he/wiz_he.h +++ b/engines/scumm/he/wiz_he.h @@ -163,7 +163,7 @@ public: void polygonRotatePoints(Common::Point *pts, int num, int alpha); void polygonTransform(int resNum, int state, int po_x, int po_y, int angle, int zoom, Common::Point *vert); - void createWizEmptyImage(const WizParameters *params); + void createWizEmptyImage(int resNum, int x1, int y1, int width, int height); void fillWizRect(const WizParameters *params); void fillWizLine(const WizParameters *params); void fillWizPixel(const WizParameters *params); diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 8e65e36b84..c1e1c8b475 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -85,6 +85,7 @@ endif ifndef DISABLE_HE MODULE_OBJS += \ + he/animation_he.o\ he/floodfill_he.o \ he/logic_he.o \ he/palette_he.o \ diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 1ffb9ae534..a8c5c5c542 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -43,6 +43,7 @@ #include "scumm/smush/smush_mixer.h" #include "scumm/insane/insane.h" #include "scumm/intern.h" +#include "scumm/he/animation_he.h" #include "scumm/he/intern_he.h" #include "scumm/he/logic_he.h" #include "scumm/he/sound_he.h" @@ -882,6 +883,7 @@ ScummEngine_v80he::ScummEngine_v80he(OSystem *syst, const DetectorResult &dr) ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v80he(syst, dr) { + _moviePlay = new MoviePlayer(this); _sprite = new Sprite(this); VAR_NUM_SPRITE_GROUPS = 0xFF; @@ -894,6 +896,7 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr) } ScummEngine_v90he::~ScummEngine_v90he() { + delete _moviePlay; delete _sprite; if (_game.heversion >= 98) { delete _logicHE; @@ -1581,6 +1584,9 @@ int ScummEngine::scummLoop(int delta) { _rnd.getRandomNumber(2); #ifndef DISABLE_HE + if (_game.heversion >= 90) { + ((ScummEngine_v90he *)this)->_moviePlay->handleNextFrame(); + } if (_game.heversion >= 98) { ((ScummEngine_v90he *)this)->_logicHE->startOfFrame(); } -- cgit v1.2.3