aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kyra/codecs.cpp10
-rw-r--r--kyra/cpsimage.cpp64
-rw-r--r--kyra/kyra.cpp133
-rw-r--r--kyra/kyra.h21
-rw-r--r--kyra/module.mk1
-rw-r--r--kyra/palette.cpp4
-rw-r--r--kyra/resource.cpp92
-rw-r--r--kyra/resource.h2
-rw-r--r--kyra/script.cpp84
-rw-r--r--kyra/script.h9
-rw-r--r--kyra/script_v1.cpp3
-rw-r--r--kyra/sound.cpp167
-rw-r--r--kyra/sound.h58
-rw-r--r--kyra/wsamovie.cpp339
-rw-r--r--kyra/wsamovie.h69
15 files changed, 905 insertions, 151 deletions
diff --git a/kyra/codecs.cpp b/kyra/codecs.cpp
index 1205442ec1..e90ebdcd68 100644
--- a/kyra/codecs.cpp
+++ b/kyra/codecs.cpp
@@ -84,9 +84,13 @@ int Compression::decode80(const uint8* image_in, uint8* image_out) {
copyp = (const uint8*)&image_out[READ_LE_UINT16(readp)];
readp += 2;
- memcpy(writep, copyp, count);
- writep += count;
- copyp += count;
+ // FIXME: Using memmove sometimes segfaults
+ // (reproducably for Ender), which suggests something Bad here
+ //memmove(writep, copyp, count);
+ //writep += count;
+ //copyp += count;
+ while (count--)
+ *writep++ = *copyp++;
} else if (count == 0x3e) {
//command 3 (11111110 c c v): fill
diff --git a/kyra/cpsimage.cpp b/kyra/cpsimage.cpp
index 20b72438fe..bb50c0a916 100644
--- a/kyra/cpsimage.cpp
+++ b/kyra/cpsimage.cpp
@@ -51,6 +51,7 @@ namespace Kyra {
if (!buffer) {
error("resource created without data");
}
+ _ownPalette = 0;
Common::MemoryReadStream bufferstream(buffer, size);
// reads in the Header
@@ -61,11 +62,15 @@ namespace Kyra {
// lets check a bit
if(_cpsHeader._pal == 0x3000000) {
- warning("CPS images with a palette aren't supported");
-
- // skip 768 bytes
// if this was a compressed palette you should have strange graphics
- bufferstream.seek(bufferstream.pos() + 768);
+
+ uint8* palbuffer = new uint8[768];
+ assert(palbuffer);
+
+ bufferstream.read(palbuffer, 768 * sizeof(uint8));
+
+ _ownPalette = new Palette(palbuffer, 768);
+ assert(palbuffer);
}
_image = new uint8[_cpsHeader._imagesize];
@@ -104,16 +109,15 @@ namespace Kyra {
}
void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y) {
+ uint8* src = _image;
+ uint8* dst = &plane[y * planepitch + x];
+ uint32 copysize = planepitch - x;
+
+ if (copysize > _width)
+ copysize = _width;
+
if (_transparency == -1) {
// 'fast' blitting
-
- uint8* src = _image;
- uint8* dst = &plane[y * planepitch + x];
- uint32 copysize = planepitch - x;
-
- if (copysize > _width)
- copysize = _width;
-
for (uint16 y_ = 0; y_ < _height && y + y_ < planeheight; ++y_) {
memcpy(dst, src, copysize * sizeof(uint8));
dst += planepitch;
@@ -122,11 +126,9 @@ namespace Kyra {
} else {
// oh no! we have transparency so we have a very slow copy :/
- uint8* src = _image;
- uint8* dst = &plane[y * planepitch + x];
for (uint16 yadd = 0; yadd < _height; ++yadd) {
- for (uint16 xadd = 0; xadd < _width; ++xadd) {
+ for (uint16 xadd = 0; xadd < copysize; ++xadd) {
if (*src == _transparency) {
++dst;
++src;
@@ -135,23 +137,26 @@ namespace Kyra {
}
}
- dst += planepitch - _width;
+ src += _width - copysize;
+ dst += planepitch - copysize;
}
}
}
void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y,
uint16 srcx, uint16 srcy, uint16 srcwidth, uint16 srcheight) {
+ uint8* src = &_image[srcy * _width + srcx];
+ uint8* dst = &plane[y * planepitch + x];
+ uint32 copysize = planepitch - x;
+
+ if (srcwidth > _width)
+ srcwidth = _width;
+
+ if (copysize > srcwidth)
+ copysize = srcwidth;
+
if (_transparency == -1) {
// 'fast' blitting
-
- uint8* src = &_image[srcy * _width + srcx];
- uint8* dst = &plane[y * planepitch + x];
- uint32 copysize = planepitch - x;
-
- if (copysize > srcwidth)
- copysize = srcwidth;
-
for (uint16 y_ = 0; y_ < srcheight && y + y_ < planeheight; ++y_) {
memcpy(dst, src, copysize * sizeof(uint8));
dst += planepitch;
@@ -160,12 +165,9 @@ namespace Kyra {
} else {
// oh no! we have transparency so we have a very slow copy :/
- // blit it without transparency
- uint8* src = &_image[srcy * _width + srcx];
- uint8* dst = &plane[y * planepitch + x];
- for (uint16 yadd = 0; yadd < _height; ++yadd) {
- for (uint16 xadd = 0; xadd < _width; ++xadd) {
+ for (uint16 yadd = 0; yadd < srcheight; ++yadd) {
+ for (uint16 xadd = 0; xadd < copysize; ++xadd) {
if (*src == _transparency) {
++dst;
++src;
@@ -174,8 +176,8 @@ namespace Kyra {
}
}
- dst += planepitch - _width;
- src += _width - srcwidth;
+ dst += planepitch - copysize;
+ src += _width - copysize;
}
}
}
diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp
index c5248e5a00..9247c84992 100644
--- a/kyra/kyra.cpp
+++ b/kyra/kyra.cpp
@@ -28,10 +28,13 @@
#include "sound/mixer.h"
#include "common/file.h"
#include "common/config-manager.h"
+#include "sound/mididrv.h"
#include "kyra.h"
#include "resource.h"
#include "script.h"
+#include "wsamovie.h"
+#include "sound.h"
struct KyraGameSettings {
const char *name;
@@ -44,10 +47,13 @@ struct KyraGameSettings {
}
};
-static const KyraGameSettings kyra_settings[] = {
- {"kyra1cd", "Legend of Kyrandia (CD)", GF_TALKIE & GF_KYRA1, "CHAPTER1.VRM"},
- {"kyra1", "Legend of Kyrandia (Floppy)", GF_FLOPPY & GF_KYRA1, "INTRO.SND"},
- { 0, 0, 0, 0}
+static const KyraGameSettings kyra_settings[] = {
+ {"kyra1", "Legend of Kyrandia (Floppy)", GF_FLOPPY | GF_KYRA1, "INTRO.SND"},
+ {"kyra1cd", "Legend of Kyrandia (CD)", GF_TALKIE | GF_KYRA1, "CHAPTER1.VRM"},
+ {"kyra2", "Hand of Fate (Floppy)", GF_FLOPPY | GF_KYRA2, 0 },
+ {"kyra2cd", "Hand of Fate (CD)", GF_TALKIE | GF_KYRA2, "AUDIO.PAK"},
+ {"kyra3", "Malcom's Revenge", GF_TALKIE | GF_KYRA3, "K3INTRO0.VQA"},
+ {0, 0, 0, 0}
};
GameList Engine_KYRA_gameList() {
@@ -99,10 +105,40 @@ KyraEngine::KyraEngine(GameDetector *detector, OSystem *syst)
_mixer->setVolume(ConfMan.getInt("sfx_volume") * ConfMan.getInt("master_volume") / 255);
+ // gets the game
+ if (detector->_game.features & GF_KYRA1) {
+ if (detector->_game.features & GF_FLOPPY)
+ _game = KYRA1;
+ else
+ _game = KYRA1CD;
+ } else if (detector->_game.features & GF_KYRA2) {
+ if (detector->_game.features & GF_FLOPPY)
+ _game = KYRA2;
+ else
+ _game = KYRA2CD;
+ } else if (detector->_game.features & GF_KYRA3) {
+ _game = KYRA3;
+ } else {
+ error("unknown game");
+ }
+
+ MidiDriver *driver = GameDetector::createMidi(GameDetector::detectMusicDriver(MDT_NATIVE | MDT_PREFER_NATIVE));
+ if (driver) {
+ if (ConfMan.getBool("native_mt32"))
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ _midiDriver = new MusicPlayer(driver, this);
+ assert(_midiDriver);
+ _midiDriver->hasNativeMT32(ConfMan.getBool("native_mt32"));
+ _midiDriver->setVolume(255);
+ } else {
+ warning("Couldn't create MIDI driver... No music!");
+ _midiDriver = NULL;
+ };
+
// Initialize backen
syst->initSize(320, 200);
- _screen = new uint8[320 * 200];
- memset(_screen, 0, 320 * 200);
+ _screen = new uint8[320*200];
+ memset(_screen, 0, sizeof(uint8) * 320 * 200);
_resMgr = new Resourcemanager(this);
assert(_resMgr);
@@ -110,15 +146,23 @@ KyraEngine::KyraEngine(GameDetector *detector, OSystem *syst)
setCurrentPalette(_resMgr->loadPalette("PALETTE.COL"));
// loads the 2 cursors
- _mouse = _resMgr->loadImage("MOUSE.CPS"); //startup.pak
+ _mouse = _resMgr->loadImage("MOUSE.CPS");
_items = _resMgr->loadImage("ITEMS.CPS");
// loads the Font
_font = _resMgr->loadFont("8FAT.FNT");
-
- // loads out scripts
+
_npcScript = _resMgr->loadScript("_NPC.EMC");
- _currentScript = _resMgr->loadScript("_STARTUP.EMC");
+
+ // loads the scripts (only Kyrandia 1)
+ if (_game == KYRA1 || _game == KYRA1CD) {
+ _currentScript = _resMgr->loadScript("_STARTUP.EMC");
+ } else {
+ error("game start files not known");
+ }
+
+ assert(_npcScript);
+ assert(_currentScript);
}
KyraEngine::~KyraEngine() {
@@ -138,7 +182,7 @@ void KyraEngine::errorString(const char *buf1, char *buf2) {
void KyraEngine::go() {
warning("Kyrandia Engine ::go()");
// starts the init script
- if (!_currentScript->startScript(kSetupScene)) {
+ /*if (!_currentScript->startScript(kSetupScene)) {
error("couldn't init '_STARTUP.EMC' script");
}
@@ -148,25 +192,67 @@ void KyraEngine::go() {
} else {
warning("init script returned: %d", _currentScript->state());
}
+ }*/
+
+ Movie* movie = _resMgr->loadMovie("MAL-KAL.WSA");
+ assert(movie);
+ CPSImage* image = _resMgr->loadImage("GEMCUT.CPS");
+ assert(image);
+
+ int16 currentFrame = 0;
+ uint32 lastFrameChange = 0;
+
+ image->transparency(0);
+ image->drawToPlane(_screen, 320, 200, 0, 0, 0, 0, 320, 136);
+ movie->setImageBackground(_screen, 320, 200);
+ movie->position(16, 58);
+
+ setCurrentPalette(_resMgr->loadPalette("MAL-KAL.COL"));
+
+ uint8* _buffer = new uint8[320 * 200];
+ assert(_buffer);
+ memcpy(_buffer, _screen, 320 * 200);
+ movie->renderFrame(_buffer, 320, 200, movie->countFrames() - 1);
+
+ if (_midiDriver) {
+ _midiDriver->playMusic("KYRA2A.XMI");
+ _midiDriver->playTrack(3);
}
-
+
while(true) {
OSystem::Event event;
//if (_debugger->isAttached())
// _debugger->onFrame();
-
+
+ memcpy(_screen, _buffer, 320 * 200);
+ if (lastFrameChange + movie->frameChange() < _system->getMillis()) {
+ lastFrameChange = _system->getMillis();
+ ++currentFrame;
+
+ if (currentFrame >= (int16)movie->countFrames()) {
+ currentFrame = 0;
+ }
+ }
+
+ movie->renderFrame(_screen, 320, 200, currentFrame);
+ _font->drawStringToPlane("This is only a test!", _screen, 320, 200, 75, 179, 136);
+ _font->drawStringToPlane("Nothing scripted!", _screen, 320, 200, 85, 189, 136);
updateScreen();
while (g_system->pollEvent(event)) {
switch (event.event_code) {
- case OSystem::EVENT_QUIT:
- g_system->quit();
- break;
- default:
- break;
+ case OSystem::EVENT_QUIT:
+ g_system->quit();
+ break;
+ default:
+ break;
}
}
_system->delayMillis(10);
}
+
+ delete movie;
+ delete image;
+ delete [] _buffer;
}
void KyraEngine::shutdown() {
@@ -179,12 +265,15 @@ void KyraEngine::updateScreen(void) {
}
void KyraEngine::setCurrentPalette(Palette* pal, bool delNextTime) {
-// if (_delPalNextTime)
-// delete _currentPal;
+ if (!pal)
+ return;
+
+// if (_delPalNextTime)
+// delete _currentPal;
-// _delPalNextTime = delNextTime;
+// _delPalNextTime = delNextTime;
-// _currentPal = pal;
+// _currentPal = pal;
if (pal->getData()) {
_system->setPalette(pal->getData(), 0, 256);
diff --git a/kyra/kyra.h b/kyra/kyra.h
index 2a6b5b1556..b0dfc34501 100644
--- a/kyra/kyra.h
+++ b/kyra/kyra.h
@@ -8,7 +8,7 @@
* 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
+ * 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
@@ -31,7 +31,17 @@ enum {
GF_FLOPPY = 1 << 0,
GF_TALKIE = 1 << 1,
GF_KYRA1 = 1 << 2,
- GF_KYRA2 = 1 << 3
+ GF_KYRA2 = 1 << 3,
+ GF_KYRA3 = 1 << 4,
+ GF_AUDIOCD = 1 << 5 // FM-Towns versions seems to use audio CD
+};
+
+enum {
+ KYRA1 = 0,
+ KYRA1CD = 1,
+ KYRA2 = 2,
+ KYRA2CD = 3,
+ KYRA3 = 4
};
namespace Kyra {
@@ -40,6 +50,7 @@ namespace Kyra {
class Font;
class Palette;
class VMContext;
+ class MusicPlayer;
class KyraEngine : public Engine {
public:
@@ -51,13 +62,17 @@ public:
void setCurrentPalette(Palette* pal, bool delNextTime = true);
Resourcemanager* resManager(void) { return _resMgr; }
-// MidiDriver* midiDriver(void) { return _midiDriver; }
+ MusicPlayer* midiDriver(void) { return _midiDriver; }
+
+ uint8 game(void) { return _game; }
protected:
void go();
void shutdown();
Resourcemanager* _resMgr;
+ MusicPlayer* _midiDriver;
uint8 *_screen;
+ uint8 _game;
Font* _font;
CPSImage* _mouse;
diff --git a/kyra/module.mk b/kyra/module.mk
index 57837decb4..1026f29468 100644
--- a/kyra/module.mk
+++ b/kyra/module.mk
@@ -9,6 +9,7 @@ MODULE_OBJS := \
kyra/resource.o \
kyra/script_v1.o \
kyra/script.o \
+ kyra/sound.o \
kyra/wsamovie.o
MODULE_DIRS += \
diff --git a/kyra/palette.cpp b/kyra/palette.cpp
index ee7826d127..8087672e6e 100644
--- a/kyra/palette.cpp
+++ b/kyra/palette.cpp
@@ -21,7 +21,7 @@
#include "stdafx.h"
#include "resource.h"
-
+
#include "common/stream.h"
#include "codecs.h"
@@ -52,7 +52,7 @@ namespace Kyra {
}
delete [] data;
- data = _palette;
+ data = _palette;
}
// hmm.. common/system.h Docu is wrong or SDL Backend has a bug :)
diff --git a/kyra/resource.cpp b/kyra/resource.cpp
index 2a91654d38..37b563f457 100644
--- a/kyra/resource.cpp
+++ b/kyra/resource.cpp
@@ -34,21 +34,48 @@ namespace Kyra {
// ugly a hardcoded list
// TODO: use the FS Backend to get all .PAK Files and load them
- static const char* kyraFilelist[] = {
+ // or any other thing to get all files
+ static const char* kyra1Filelist[] = {
"A_E.PAK", "DAT.PAK", "F_L.PAK", "MAP_5.PAK", "MSC.PAK", "M_S.PAK",
"S_Z.PAK", "WSA1.PAK", "WSA2.PAK", "WSA3.PAK", "WSA4.PAK", "WSA5.PAK",
- "WSA6.PAK", "startup.pak", "intro1.pak", 0
+ "WSA6.PAK", 0
};
- for (uint32 tmp = 0; kyraFilelist[tmp]; ++tmp) {
+ static const char* kyra1CDFilelist[] = {
+ "ADL.PAK", "BRINS.PAK", "CLIFF.PAK", "ENTER.PAK", "FORESTA.PAK", "GEM.PAK", "INTRO1.PAK",
+ "LEPHOLE.PAK", "OAKS.PAK", "SPELL.PAK", "WILLOW.PAK", "ALCHEMY.PAK", "BROKEN.PAK", "COL.PAK",
+ "EXTHEAL.PAK", "FORESTB.PAK", "GEMCUT.PAK", "INTRO2.PAK", "LIBRARY.PAK", "PLATEAU.PAK", "SPRING.PAK",
+ "WISE.PAK", "ALGAE.PAK", "BURN.PAK", "DARMS.PAK", "EXTPOT.PAK", "FORESTC.PAK", "GENCAVB.PAK",
+ "INTRO3.PAK", "MISC.PAK", "PLTCAVE.PAK", "SQUARE.PAK", "XEDGE.PAK", "ALTAR.PAK", "CASTLE.PAK",
+ "DEAD.PAK", "EXTSPEL.PAK", "FOUNTN.PAK", "GENHALL.PAK", "INTRO4.PAK", "MIX.PAK", "POTION.PAK",
+ "STARTUP.PAK", "XEDGEB.PAK", "ARCH.PAK", "CATACOM.PAK", "DNSTAIR.PAK", "FALLS.PAK", "FOYER.PAK",
+ "GEN_CAV.PAK", "KITCHEN.PAK", "MOONCAV.PAK", "RUBY.PAK", "STUMP.PAK", "XEDGEC.PAK", "BALCONY.PAK",
+ "CAVE.PAK", "DRAGON.PAK", "FESTSTH.PAK", "FSOUTH.PAK", "GLADE.PAK", "KYRAGEM.PAK", "NCLIFF.PAK",
+ "SICKWIL.PAK", "TEMPLE.PAK", "XMI.PAK", "BELROOM.PAK", "CAVEB.PAK", "EDGE.PAK", "FGOWEST.PAK",
+ "FSOUTHB.PAK", "GRAVE.PAK", "LAGOON.PAK", "NCLIFFB.PAK", "SND.PAK", "TRUNK.PAK", "ZROCK.PAK",
+ "BONKBG.PAK", "CGATE.PAK", "EDGEB.PAK", "FINALE.PAK", "FWSTSTH.PAK", "GRTHALL.PAK", "LANDING.PAK",
+ "NWCLIFB.PAK", "SONG.PAK", "UPSTAIR.PAK", "BRIDGE.PAK", "CHASM.PAK", "EMCAV.PAK", "FNORTH.PAK",
+ "GATECV.PAK", "HEALER.PAK", "LAVA.PAK", "NWCLIFF.PAK", "SORROW.PAK", "WELL.PAK", 0
+ };
+
+ const char** usedFilelist = 0;
+
+ if (_engine->game() == KYRA1)
+ usedFilelist = kyra1Filelist;
+ else if (_engine->game() == KYRA1CD)
+ usedFilelist = kyra1CDFilelist;
+ else
+ error("no filelist found for this game");
+
+ for (uint32 tmp = 0; usedFilelist[tmp]; ++tmp) {
// prefetch file
- PAKFile* file = new PAKFile(kyraFilelist[tmp]);
+ PAKFile* file = new PAKFile(usedFilelist[tmp]);
assert(file);
- if (file->isOpen() && file->isValid())
+ if (file->isOpen() && file->isValid())
_pakfiles.push_back(file);
else
- warning("couldn't load file '%s' correctly", kyraFilelist[tmp]);
+ debug("couldn't load file '%s' correctly", usedFilelist[tmp]);
}
}
@@ -63,11 +90,8 @@ namespace Kyra {
uint8* Resourcemanager::fileData(const char* file, uint32* size) {
uint8* buffer = 0;
-
- debug("looking for file '%s'", file);
-
File file_;
-
+
// test to open it in the main dir
if (file_.open(file)) {
@@ -83,37 +107,39 @@ namespace Kyra {
} else {
// opens the file in a PAK File
Common::List<PAKFile*>::iterator start = _pakfiles.begin();
-
+
for (;start != _pakfiles.end(); ++start) {
*size = (*start)->getFileSize(file);
-
- if (!*size)
+
+ if (!(*size))
continue;
-
+
buffer = new uint8[*size];
assert(buffer);
-
+
// creates a copy of the file
memcpy(buffer, (*start)->getFile(file), *size);
-
+
break;
}
}
if (!buffer || !(*size)) {
- warning("couldn't find file '%s'", file);
+ return 0;
}
return buffer;
}
- Palette* Resourcemanager::loadPalette(const char* file) {
+ Palette* Resourcemanager::loadPalette(const char* file) {
uint32 size = 0;
uint8* buffer = 0;
buffer = fileData(file, &size);
- if (!buffer)
+ if (!buffer) {
+ warning("ResMgr: Failed loading palette %s", file);
return 0;
+ }
return new Palette(buffer, size);
}
@@ -140,9 +166,12 @@ namespace Kyra {
uint32 size = 0;
uint8* buffer = 0;
buffer = fileData(file, &size);
- if (!buffer)
+ if (!buffer || !size)
return 0;
- return new WSAMovieV1(buffer, size);
+ if (_engine->game() == KYRA1 || _engine->game() == KYRA1CD)
+ return new WSAMovieV1(buffer, size, _engine->game());
+ else
+ return new WSAMovieV2(buffer, size);
}
VMContext* Resourcemanager::loadScript(const char* file) {
@@ -154,13 +183,13 @@ namespace Kyra {
///////////////////////////////////////////
// Pak file manager
#define PAKFile_Iterate Common::List<PakChunk*>::iterator start=_files.begin();start != _files.end(); ++start
- PAKFile::PAKFile(const Common::String& file) {
+ PAKFile::PAKFile(/*const Common::String &path, */const Common::String& file) {
File pakfile;
_buffer = 0;
_open = false;
- if (!pakfile.open(file.c_str())) {
- warning("PAKFile couldn't open: '%s'", file.c_str());
+ if (!pakfile.open(file.c_str())){ /*, File::kFileReadMode, path.c_str())) {*/
+ printf("pakfile couldn't open %s\n", file.c_str());
return;
}
@@ -184,18 +213,25 @@ namespace Kyra {
// saves the name
chunk->_name = reinterpret_cast<const char*>(_buffer + pos);
pos += strlen(chunk->_name) + 1;
- if(!chunk->_name)
+ if(!(*chunk->_name))
break;
endoffset = READ_LE_UINT32(_buffer + pos);
pos += 4;
+
+ if (endoffset == 0) {
+ endoffset = filesize;
+ }
chunk->_data = _buffer + startoffset;
chunk->_size = endoffset - startoffset;
- startoffset = endoffset;
-
_files.push_back(chunk);
+
+ if (endoffset == filesize)
+ break;
+
+ startoffset = endoffset;
}
_open = true;
}
@@ -212,7 +248,7 @@ namespace Kyra {
}
const uint8* PAKFile::getFile(const char* file) {
- for (PAKFile_Iterate) {
+ for (PAKFile_Iterate) {
if (!scumm_stricmp((*start)->_name, file))
return (*start)->_data;
}
diff --git a/kyra/resource.h b/kyra/resource.h
index 4aadd83b5a..9b159c427d 100644
--- a/kyra/resource.h
+++ b/kyra/resource.h
@@ -114,7 +114,7 @@ namespace Kyra {
bool hasPalette(void) { return (_ownPalette != 0); }
// if col == -1 then no transparany
- void setTransparencyColor(int16 col) { _transparency = col; }
+ void transparency(int16 col) { _transparency = col; }
void drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y);
void drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y,
diff --git a/kyra/script.cpp b/kyra/script.cpp
index 8f13eb44b6..bb58d2c887 100644
--- a/kyra/script.cpp
+++ b/kyra/script.cpp
@@ -25,6 +25,7 @@
#include "resource.h"
#include "common/stream.h"
+#include "common/util.h"
#define COMMAND(x) { &VMContext::x, #x }
#define OPCODE(x) { &VMContext::x, #x }
@@ -54,7 +55,7 @@ namespace Kyra {
// 0x0C
COMMAND(c1_addToSP),
COMMAND(c1_subFromSP),
- COMMAND(c1_execOpcode),
+ COMMAND(c1_execOpcode),
COMMAND(c1_ifNotGoTo),
// 0x10
COMMAND(c1_negate),
@@ -82,7 +83,7 @@ namespace Kyra {
// 0x0C
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x10
COMMAND(o1_unknownOpcode),
@@ -107,7 +108,7 @@ namespace Kyra {
// 0x20
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x24
COMMAND(o1_unknownOpcode),
@@ -132,7 +133,7 @@ namespace Kyra {
// 0x34
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x38
COMMAND(o1_unknownOpcode),
@@ -157,7 +158,7 @@ namespace Kyra {
// 0x48
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x4C
COMMAND(o1_unknownOpcode),
@@ -182,7 +183,7 @@ namespace Kyra {
// 0x5C
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x60
COMMAND(o1_unknownOpcode),
@@ -207,7 +208,7 @@ namespace Kyra {
// 0x70
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x74
COMMAND(o1_unknownOpcode),
@@ -232,7 +233,7 @@ namespace Kyra {
// 0x84
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0x88
COMMAND(o1_unknownOpcode),
@@ -262,7 +263,7 @@ namespace Kyra {
// 0x9C
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0xA0
COMMAND(o1_unknownOpcode),
@@ -287,7 +288,7 @@ namespace Kyra {
// 0xB0
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0xB4
COMMAND(o1_unknownOpcode),
@@ -312,7 +313,7 @@ namespace Kyra {
// 0xC4
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0xC8
COMMAND(o1_unknownOpcode),
@@ -337,7 +338,7 @@ namespace Kyra {
// 0xD8
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0xDC
COMMAND(o1_unknownOpcode),
@@ -362,7 +363,7 @@ namespace Kyra {
// 0xEC
COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
- COMMAND(o1_unknownOpcode),
+ COMMAND(o1_unknownOpcode),
COMMAND(o1_unknownOpcode),
// 0xF0
COMMAND(o1_unknownOpcode),
@@ -398,8 +399,8 @@ namespace Kyra {
_scriptFileSize = 0;
}
- debug("--------------");
-
+ memset(_stack, 0, sizeof(int32) * ARRAYSIZE(_stack));
+
// loads the new file
_scriptFile = _engine->resManager()->fileData(file, &_scriptFileSize);
@@ -415,32 +416,27 @@ namespace Kyra {
while(true) {
if (script.eof()) {
break;
- }
+ }
// lets read only the first 4 chars
script.read(chunkName, sizeof(uint8) * 4);
chunkName[4] = '\0';
- debug("chunk name(4 chars): '%s'", chunkName);
-
+
// check name of chunk
if (!scumm_stricmp((const char *)chunkName, "FORM")) {
// FreeKyra swaps the size I only read it in BigEndian :)
_chunks[kForm]._size = script.readUint32BE();
- debug("_chunks[kForm]._size = %d", _chunks[kForm]._size);
+ debug("_chunks[kForm]._size = %d", _chunks[kForm]._size);
} else if (!scumm_stricmp((const char *)chunkName, "TEXT")) {
uint32 text_size = script.readUint32BE();
text_size += text_size % 2 != 0 ? 1 : 0;
_chunks[kText]._data = _scriptFile + script.pos();
_chunks[kText]._size = READ_BE_UINT16(_chunks[kText]._data) >> 1;
- _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1);
- debug("_chunks[kText]._size = %d, real chunk size = %d", _chunks[kText]._size, text_size);
-
+ _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1);
script.seek(script.pos() + text_size);
} else if (!scumm_stricmp((const char *)chunkName, "DATA")) {
_chunks[kData]._size = script.readUint32BE();
- _chunks[kData]._data = _scriptFile + script.pos();
- debug("_chunks[kData]._size = %d", _chunks[kData]._size);
-
+ _chunks[kData]._data = _scriptFile + script.pos();
// mostly it will be the end of the file because all files should end with a 'DATA' chunk
script.seek(script.pos() + _chunks[kData]._size);
} else {
@@ -451,25 +447,20 @@ namespace Kyra {
if (!scumm_stricmp((const char *)chunkName, "EMC2ORDR")) {
_chunks[kEmc2Ordr]._size = script.readUint32BE() >> 1;
- _chunks[kEmc2Ordr]._data = _scriptFile + script.pos();
- debug("_chunks[kEmc2Ordr]._size = %d, real chunk size = %d", _chunks[kEmc2Ordr]._size, _chunks[kEmc2Ordr]._size * 2);
-
+ _chunks[kEmc2Ordr]._data = _scriptFile + script.pos();
script.seek(script.pos() + _chunks[kEmc2Ordr]._size * 2);
} else {
// any unkown chunk or problems with seeking through the file
- error("unknown chunk");
+ error("unknown chunk(%s)", chunkName);
}
}
}
-
- // so file loaded
- debug("--------------");
}
int32 VMContext::param(int32 index) {
- if (_stackPos - index + 1 >= 16 || _stackPos - index + 1 < 0)
+ if (_stackPos - index - 1 >= ARRAYSIZE(_stack) || _stackPos - index - 1 < 0)
return -0xFFFF;
- return _stack[_stackPos - index + 1];
+ return _stack[_stackPos - index - 1];
}
const char* VMContext::stringAtIndex(int32 index) {
@@ -485,11 +476,28 @@ namespace Kyra {
return false;
}
- _instructionPos = (READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1) + 2;
+ _instructionPos = READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1;
_stackPos = 0;
_tempPos = 0;
_delay = 0;
_scriptState = kScriptRunning;
+
+ uint32 pos = 0xFFFFFFFE;
+
+ // get start of next script
+ for (uint32 tmp = 0; tmp < _chunks[kEmc2Ordr]._size; ++tmp) {
+ if ((uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) > (uint32)_instructionPos &&
+ (uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) < pos) {
+ pos = ((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1));
+ }
+ }
+
+ if (pos > _scriptFileSize) {
+ pos = _scriptFileSize;
+ }
+
+ _nextScriptPos = pos;
+
return true;
}
@@ -505,6 +513,9 @@ namespace Kyra {
debug("_instructionPos( = %d) > _chunks[kData]._size( = %d)", _instructionPos, _chunks[kData]._size);
_error = true;
break;
+ } else if(_instructionPos >= _nextScriptPos) {
+ _scriptState = kScriptStopped;
+ break;
}
_currentCommand = *(script_start + _instructionPos++);
@@ -525,9 +536,12 @@ namespace Kyra {
_instructionPos += 2;
} else {
debug("unknown way of getting the command");
+ // next thing
+ continue;
}
_currentCommand &= 0x1f;
+
if (_currentCommand < _numCommands) {
CommandProc currentProc = _commands[_currentCommand].proc;
(this->*currentProc)();
diff --git a/kyra/script.h b/kyra/script.h
index ea04d87416..664850b62c 100644
--- a/kyra/script.h
+++ b/kyra/script.h
@@ -71,14 +71,15 @@ namespace Kyra {
uint32 _delay;
int32 _registers[32]; // registers of the interpreter
- int32 _stack[32]; // our stack
+ int32 _stack[64]; // our stack
// TODO: check for 'under'flow
- int32 popStack(void) { return _stack[_stackPos--]; }
+ int32 popStack(void) { return _stack[--_stackPos]; }
int32& topStack(void) { return _stack[_stackPos]; }
uint32 _returnValue;
+ int32 _nextScriptPos;
int32 _instructionPos;
int32 _stackPos;
int32 _tempPos;
@@ -131,7 +132,7 @@ namespace Kyra {
void c1_goToLine(void); // 0x00
void c1_setReturn(void); // 0x01
void c1_pushRetRec(void); // 0x02
- void c1_push(void); // 0x03 & 0x04
+ void c1_push(void); // 0x03 & 0x04
void c1_pushVar(void); // 0x05
void c1_pushFrameNeg(void); // 0x06
void c1_pushFramePos(void); // 0x07
@@ -148,7 +149,7 @@ namespace Kyra {
void c1_unknownCommand(void);
// the opcode procs
- void o1_0x68(void); // 0x68
+ void o1_0x68(void); // 0x68
void o1_unknownOpcode(void);
};
} // end of namespace Kyra
diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp
index ec9030d628..c69c58c514 100644
--- a/kyra/script_v1.cpp
+++ b/kyra/script_v1.cpp
@@ -237,6 +237,7 @@ namespace Kyra {
}
void VMContext::o1_0x68(void) {
- debug("o1_0x68 was called with param0: '%d' and param1: '%d'", param(0), param(1));
+ debug("o1_0x68 was called with param0: '%d'", param(0));
+ _error = true;
}
} // end of namespace Kyra
diff --git a/kyra/sound.cpp b/kyra/sound.cpp
new file mode 100644
index 0000000000..d631f35b5a
--- /dev/null
+++ b/kyra/sound.cpp
@@ -0,0 +1,167 @@
+#include "sound.h"
+#include "resource.h"
+
+// Instrument mapping for MT32 tracks emulated under GM.
+static const byte mt32_to_gm[128] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 0, 2, 4, 4, 5, 3, 16, 17, 18, 16, 16, 19, 20, 21, // 0x
+ 6, 6, 6, 7, 7, 7, 8, 112, 62, 62, 63, 63, 38, 38, 39, 39, // 1x
+ 88, 95, 52, 98, 97, 99, 14, 54, 102, 96, 53, 102, 81, 100, 14, 80, // 2x
+ 48, 48, 49, 45, 41, 40, 42, 42, 43, 46, 45, 24, 25, 28, 27, 104, // 3x
+ 32, 32, 34, 33, 36, 37, 35, 35, 79, 73, 72, 72, 74, 75, 64, 65, // 4x
+ 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, 57, 60, 60, 58, 61, // 5x
+ 61, 11, 11, 98, 14, 9, 14, 13, 12, 107, 107, 77, 78, 78, 76, 76, // 6x
+ 47, 117, 127, 118, 118, 116, 115, 119, 115, 112, 55, 124, 123, 0, 14, 117 // 7x
+};
+
+namespace Kyra {
+ MusicPlayer::MusicPlayer(MidiDriver* driver, KyraEngine* engine) {
+ _engine = engine;
+ _driver = driver;
+ _isPlaying = _nativeMT32 = false;
+
+ memset(_channel, 0, sizeof(MidiChannel*) * 16);
+ memset(_channelVolume, 255, sizeof(uint8) * 16);
+ _volume = 0;
+
+ int ret = open();
+ if (ret != MERR_ALREADY_OPEN && ret != 0) {
+ error("couldn't open midi driver");
+ }
+ }
+
+ MusicPlayer::~MusicPlayer() {
+ _driver->setTimerCallback(NULL, NULL);
+ close();
+ }
+
+ void MusicPlayer::setVolume(int volume) {
+ if (volume < 0)
+ volume = 0;
+ else if (volume > 255)
+ volume = 255;
+
+ if (_volume == volume)
+ return;
+
+ _volume = volume;
+
+ for (int i = 0; i < 16; ++i) {
+ if (_channel[i]) {
+ _channel[i]->volume(_channelVolume[i] * _volume / 255);
+ }
+ }
+ }
+
+ int MusicPlayer::open() {
+ // Don't ever call open without first setting the output driver!
+ if (!_driver)
+ return 255;
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+
+ _driver->setTimerCallback(this, &onTimer);
+ return 0;
+ }
+
+ void MusicPlayer::close() {
+ if (_driver)
+ _driver->close();
+ _driver = 0;
+ }
+
+ void MusicPlayer::send(uint32 b) {
+ uint8 channel = (byte)(b & 0x0F);
+ if ((b & 0xFFF0) == 0x07B0) {
+ // Adjust volume changes by master volume
+ uint8 volume = (uint8)((b >> 16) & 0x7F);
+ _channelVolume[channel] = volume;
+ volume = volume * _volume / 255;
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ } else if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | mt32_to_gm[(b >> 8) & 0xFF] << 8;
+ } else if ((b & 0xFFF0) == 0x007BB0) {
+ //Only respond to All Notes Off if this channel
+ //has currently been allocated
+ if (!_channel[channel])
+ return;
+ }
+
+ if (!_channel[channel])
+ _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+
+ if (_channel[channel])
+ _channel[channel]->send(b);
+ }
+
+ void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
+ switch (type) {
+ case 0x2F: // End of Track
+ _parser->jumpToTick(0);
+ break;
+ default:
+ warning("Unhandled meta event: 0x%02x", type);
+ break;
+ }
+ }
+
+ void MusicPlayer::playMusic(const char* file) {
+ uint32 size;
+ uint8* data = 0;
+
+ data = (_engine->resManager())->fileData(file, &size);
+
+ if (!data) {
+ warning("couldn't load '%s'", file);
+ return;
+ }
+
+ playMusic(data, size);
+ }
+
+ void MusicPlayer::playMusic(uint8* data, uint32 size) {
+ if (_isPlaying)
+ stopMusic();
+
+ _parser = MidiParser::createParser_XMIDI();
+ assert(_parser);
+
+ if (!_parser->loadMusic(data, size)) {
+ warning("Error reading track!");
+ delete _parser;
+ _parser = 0;
+ return;
+ }
+
+ _parser->setTrack(0);
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(getBaseTempo());
+
+ _isPlaying = true;
+ }
+
+ void MusicPlayer::stopMusic() {
+ _isPlaying = false;
+ if (_parser) {
+ _parser->unloadMusic();
+ delete _parser;
+ _parser = NULL;
+ }
+ }
+
+ void MusicPlayer::onTimer(void *refCon) {
+ MusicPlayer *music = (MusicPlayer *)refCon;
+ if (music->_isPlaying)
+ music->_parser->onTimer();
+ }
+
+ void MusicPlayer::playTrack(uint8 track) {
+ if (_parser) {
+ _isPlaying = true;
+ _parser->setTrack(track);
+ _parser->jumpToTick(0);
+ }
+ }
+} // end of namespace Kyra
diff --git a/kyra/sound.h b/kyra/sound.h
new file mode 100644
index 0000000000..dfe393e53c
--- /dev/null
+++ b/kyra/sound.h
@@ -0,0 +1,58 @@
+#ifndef SOUND_H
+#define SOUND_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "kyra.h"
+
+namespace Kyra {
+ class MusicPlayer : public MidiDriver {
+
+ public:
+
+ MusicPlayer(MidiDriver* driver, KyraEngine* engine);
+ ~MusicPlayer();
+
+ void setVolume(int volume);
+ int getVolume() { return _volume; }
+
+ void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
+
+ void playMusic(const char* file);
+ void playMusic(uint8* data, uint32 size);
+ void stopMusic();
+
+ void playTrack(uint8 track);
+
+ //MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+ void metaEvent(byte type, byte *data, uint16 length);
+
+ void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
+ uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
+
+ //Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+ protected:
+
+ static void onTimer(void *data);
+
+ MidiChannel* _channel[16];
+ uint8 _channelVolume[16];
+ MidiDriver* _driver;
+ bool _nativeMT32;
+ uint8 _volume;
+ bool _isPlaying;
+ MidiParser* _parser;
+ KyraEngine* _engine;
+
+ };
+} // end of namespace Kyra
+
+#endif
diff --git a/kyra/wsamovie.cpp b/kyra/wsamovie.cpp
index 056ece2770..1408482cf5 100644
--- a/kyra/wsamovie.cpp
+++ b/kyra/wsamovie.cpp
@@ -18,25 +18,67 @@
* $Header$
*
*/
-
+
#include "stdafx.h"
#include "wsamovie.h"
#include "codecs.h"
#include "common/stream.h"
+#ifdef DUMP_FILES
+#include <stdio.h>
+#endif
+
namespace Kyra {
- WSAMovieV1::WSAMovieV1(uint8* data, uint32 size) {
+ WSAMovieV1::WSAMovieV1(uint8* data, uint32 size, uint8 gameid) {
if (!data) {
error("resource created without data");
}
+ _background = 0;
+ _currentFrame = 0;
+ _ownPalette = 0;
+ _offsetTable = 0;
+ _prefetchedFrame = 0xFFFE;
_buffer = data;
// I like these Streams .... =)
Common::MemoryReadStream datastream(data, size);
datastream.read(&_wsaHeader, sizeof(_wsaHeader));
+
+#ifdef DUMP_FILES
+ FILE* wsaheader = fopen("dumps/wsaheader.txt", "w+");
+
+ if (wsaheader) {
+ for (uint32 pos = 0; pos < sizeof(_wsaHeader); ++pos)
+ fprintf(wsaheader, "%d pos. byte: %d\n", pos + 1, ((uint8*)&_wsaHeader)[pos]);
+ fprintf(wsaheader, "\n");
+ for (uint32 pos = 0; pos < sizeof(_wsaHeader) / 2; ++pos)
+ fprintf(wsaheader, "%d pos. word: %d\n", pos + 1, ((uint16*)&_wsaHeader)[pos]);
+ fprintf(wsaheader, "\n");
+ for (uint32 pos = 0; pos < sizeof(_wsaHeader) / 4; ++pos)
+ fprintf(wsaheader, "%d pos. dword: %d\n", pos + 1, ((uint32*)&_wsaHeader)[pos]);
+ }
+ fclose(wsaheader);
+#endif
+
+ if (gameid == KYRA1CD) {
+ uint16 tmp = _wsaHeader._delta;
+ _wsaHeader._delta = _wsaHeader._type;
+ _wsaHeader._type = tmp;
+
+ // skip 2 bytes
+ datastream.readUint16LE();
+ }
+
+ debug("_wsaHeader._numFrames = %d", _wsaHeader._numFrames);
+ debug("_wsaHeader._width = %d", _wsaHeader._width);
+ debug("_wsaHeader._height = %d", _wsaHeader._height);
+ debug("_wsaHeader._xPos = %d", _wsaHeader._xPos);
+ debug("_wsaHeader._yPos = %d", _wsaHeader._yPos);
+ debug("_wsaHeader._delta = %d", _wsaHeader._delta);
+ debug("_wsaHeader._type = %d", _wsaHeader._type);
// check for version
if (_wsaHeader._type) {
@@ -55,27 +97,34 @@ namespace Kyra {
offsetAdd = 768 /* 0x300 */;
}
- _frameCount = _wsaHeader._numFrames;
+ // last frame seems every time to be a empty one
+ _frameCount = _wsaHeader._numFrames - 1;
_offsetTable = new uint32[_wsaHeader._numFrames + 2];
- assert(!_offsetTable);
+ assert(_offsetTable);
// loads the offset table
- for (uint32 tmp = 0; tmp < _wsaHeader._numFrames; ++tmp) {
+ for (uint32 tmp = 0; tmp < (uint32)_wsaHeader._numFrames + 2; ++tmp) {
_offsetTable[tmp] = datastream.readUint32LE() + offsetAdd;
}
if (offsetAdd) {
uint8* palbuffer = new uint8[offsetAdd];
- assert(!palbuffer);
+ assert(palbuffer);
+
+ datastream.read(palbuffer, offsetAdd);
_ownPalette = new Palette(palbuffer, offsetAdd);
- assert(!_ownPalette);
- }
+ assert(_ownPalette);
+ }
+
+ // FIXME: Confirm the default value here?
+ _transparency = -1;
}
WSAMovieV1::~WSAMovieV1() {
delete [] _buffer;
delete [] _offsetTable;
+ delete [] _currentFrame;
delete _ownPalette;
}
@@ -89,21 +138,215 @@ namespace Kyra {
if (!_currentFrame) {
_currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height];
assert(_currentFrame);
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
}
+ if (frame >= _wsaHeader._numFrames)
+ return 0;
+
uint8* frameData = 0;
- uint8 image40[64000]; // I think this will crash on Plam OS :)
+ static uint8 image40[64000]; // I think this will crash on Plam OS :)
+ memset(image40, 0, ARRAYSIZE(image40));
if (frame == _prefetchedFrame + 1) {
- frameData = _buffer + _offsetTable[frame] + (hasPalette() ? 768 : 0);
+ frameData = _buffer + _offsetTable[frame];
Compression::decode80(frameData, image40);
Compression::decode40(image40, _currentFrame);
} else {
- memset(_currentFrame, 0, _wsaHeader._width * _wsaHeader._height);
+ if (_background) {
+ setImageBackground(_background, _backWidth, _backHeight);
+ } else {
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
+ }
+
+ for (uint32 i = 0; i <= frame; ++i)
+ {
+ frameData = _buffer + _offsetTable[i];
+ Compression::decode80(frameData, image40);
+ Compression::decode40(image40, _currentFrame);
+ }
+ }
+
+ _prefetchedFrame = frame;
+ return _currentFrame;
+ }
+
+ return 0;
+ }
+
+ void WSAMovieV1::renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame) {
+ if (!loadFrame(frame, 0, 0))
+ return;
+
+ uint8* src = _currentFrame;
+ uint8* dst = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos];
+ uint32 copysize = planepitch - _wsaHeader._xPos;
+
+ if (copysize > _wsaHeader._width)
+ copysize = _wsaHeader._width;
+
+ if (_transparency == -1) {
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < planeheight; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += planepitch;
+ src += _wsaHeader._width;
+ }
+ } else {
+ for (uint16 yadd = 0; yadd < _wsaHeader._height; ++yadd) {
+ for (uint16 xadd = 0; xadd < copysize; ++xadd) {
+ if (*src == _transparency) {
+ ++dst;
+ ++src;
+ } else {
+ *dst++ = *src++;
+ }
+ }
- for (uint32 i = 0; i <= frame; i++)
+ src += _wsaHeader._width - copysize;
+ dst += planepitch - copysize;
+ }
+ }
+ }
+
+ void WSAMovieV1::setImageBackground(uint8* plane, uint16 planepitch, uint16 height) {
+ assert(plane);
+
+ _background = plane;
+ _backWidth = planepitch; _backHeight = height;
+
+ if (!_currentFrame) {
+ _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height];
+ assert(_currentFrame);
+ }
+
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
+
+ uint8* src = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos];
+ uint8* dst = _currentFrame;
+ uint32 copysize = planepitch - _wsaHeader._xPos;
+
+ if (copysize > _wsaHeader._width)
+ copysize = _wsaHeader._width;
+
+ // now copy the rect of the plane
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += _wsaHeader._width;
+ src += planepitch;
+ }
+
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) {
+ for (uint16 x = 0; x < _wsaHeader._width; ++x) {
+ _currentFrame[y_ * _wsaHeader._width + x] ^= 0;
+ }
+ }
+
+ _prefetchedFrame = 0xFFFE;
+ }
+
+ // Kyrandia 2+ Movies
+ WSAMovieV2::WSAMovieV2(uint8* data, uint32 size) {
+ if (!data) {
+ error("resource created without data");
+ }
+
+ _background = 0;
+ _currentFrame = 0;
+ _ownPalette = 0;
+ _offsetTable = 0;
+ _prefetchedFrame = 0xFFFE;
+ _looping = false;
+ _buffer = data;
+
+ // I like these Streams .... =)
+ Common::MemoryReadStream datastream(data, size);
+
+ datastream.read(&_wsaHeader, sizeof(_wsaHeader));
+
+ // check for version
+ if (!_wsaHeader._type) {
+ error("loading a WSA version 1 with the WSA version 2 loader");
+ }
+
+ uint16 offsetAdd = 0;
+
+ // checks now for own palette
+ if (_wsaHeader._type % 2) {
+ // don't now if this will work right, because a few lines before we use
+ // _wsaHeader._type for detect the version of the WSA movie,
+ // but this code was from FreeKyra Tools so I think it will work
+
+ // if this is a packed palette we have a problem :)
+ offsetAdd = 768 /* 0x300 */;
+ }
+
+ _offsetTable = new uint32[_wsaHeader._numFrames + 2];
+ assert(_offsetTable);
+
+ // loads the offset table
+ for (uint32 tmp = 0; tmp < (uint32)_wsaHeader._numFrames + 2; ++tmp) {
+ _offsetTable[tmp] = datastream.readUint32LE() + offsetAdd;
+ }
+
+ if (offsetAdd) {
+ uint8* palbuffer = new uint8[offsetAdd];
+ assert(palbuffer);
+
+ datastream.read(palbuffer, offsetAdd);
+
+ _ownPalette = new Palette(palbuffer, offsetAdd);
+ assert(_ownPalette);
+ }
+
+ if (_offsetTable[_wsaHeader._numFrames + 1] - offsetAdd) {
+ ++_wsaHeader._numFrames;
+ _looping = true;
+ }
+
+ _frameCount = _wsaHeader._numFrames;
+ }
+
+ WSAMovieV2::~WSAMovieV2() {
+ delete [] _buffer;
+ delete [] _offsetTable;
+ delete [] _currentFrame;
+ delete _ownPalette;
+ }
+
+ const uint8* WSAMovieV2::loadFrame(uint16 frame, uint16* width, uint16* height) {
+ if (width) *width = _wsaHeader._width;
+ if (height) *height = _wsaHeader._height;
+
+ if (frame == _prefetchedFrame) {
+ return _currentFrame;
+ } else {
+ if (!_currentFrame) {
+ _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height];
+ assert(_currentFrame);
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
+ }
+
+ if (frame >= _wsaHeader._numFrames)
+ return 0;
+
+ uint8* frameData = 0;
+ static uint8 image40[64000]; // I think this will crash on Plam OS :)
+ memset(image40, 0, ARRAYSIZE(image40));
+
+ if (frame == _prefetchedFrame + 1) {
+ frameData = _buffer + _offsetTable[frame];
+ Compression::decode80(frameData, image40);
+ Compression::decode40(image40, _currentFrame);
+ } else {
+ if (_background) {
+ setImageBackground(_background, _backWidth, _backHeight);
+ } else {
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
+ }
+
+ for (uint32 i = 0; i <= frame; ++i)
{
- frameData = _buffer + _offsetTable[i] + (hasPalette() ? 768 : 0);
+ frameData = _buffer + _offsetTable[i];
Compression::decode80(frameData, image40);
Compression::decode40(image40, _currentFrame);
}
@@ -115,5 +358,75 @@ namespace Kyra {
return 0;
}
+
+ void WSAMovieV2::renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame) {
+ if (!loadFrame(frame, 0, 0))
+ return;
+
+ uint8* src = _currentFrame;
+ uint8* dst = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos];
+ uint32 copysize = planepitch - _wsaHeader._xPos;
+
+ if (copysize > _wsaHeader._width)
+ copysize = _wsaHeader._width;
+
+ if (_transparency == -1) {
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < planeheight; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += planepitch;
+ src += _wsaHeader._width;
+ }
+ } else {
+ for (uint16 yadd = 0; yadd < _wsaHeader._height; ++yadd) {
+ for (uint16 xadd = 0; xadd < copysize; ++xadd) {
+ if (*src == _transparency) {
+ ++dst;
+ ++src;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+
+ src += _wsaHeader._width - copysize;
+ dst += planepitch - copysize;
+ }
+ }
+ }
+
+ void WSAMovieV2::setImageBackground(uint8* plane, uint16 planepitch, uint16 height) {
+ assert(plane);
+
+ _background = plane;
+ _backWidth = planepitch; _backHeight = height;
+
+ if (!_currentFrame) {
+ _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height];
+ assert(_currentFrame);
+ }
+
+ memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height);
+
+ uint8* src = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos];
+ uint8* dst = _currentFrame;
+ uint32 copysize = planepitch - _wsaHeader._xPos;
+
+ if (copysize > _wsaHeader._width)
+ copysize = _wsaHeader._width;
+
+ // now copy the rect of the plane
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) {
+ memcpy(dst, src, copysize * sizeof(uint8));
+ dst += _wsaHeader._width;
+ src += planepitch;
+ }
+
+ for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) {
+ for (uint16 x = 0; x < _wsaHeader._width; ++x) {
+ _currentFrame[y_ * _wsaHeader._width + x] ^= 0;
+ }
+ }
+
+ _prefetchedFrame = 0xFFFE;
+ }
} // end of namespace Kyra
diff --git a/kyra/wsamovie.h b/kyra/wsamovie.h
index 2f23a5c4c2..62b7b8489d 100644
--- a/kyra/wsamovie.h
+++ b/kyra/wsamovie.h
@@ -31,30 +31,42 @@ namespace Kyra {
public:
- virtual ~Movie() {}
+ virtual ~Movie() { _transparency = -1; _ownPalette = 0; _frameCount = 0; }
+ virtual void renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame) = 0;
virtual const uint8* loadFrame(uint16 frame, uint16* width = 0, uint16* height = 0) = 0;
virtual uint16 countFrames(void) { return _frameCount; }
+ // could be deleted(not imdiantly maybe it's needed sometime)
+ virtual void transparency(int16 color) { _transparency = color; }
+ virtual void position(uint16 x, uint16 y) = 0;
+
virtual bool hasPalette(void) { return (_ownPalette != 0); }
virtual Palette* palette(void) { return _ownPalette; }
+
+ virtual bool looping(void) { return false; }
+ virtual uint32 frameChange(void) { return 100; }
+ virtual void setImageBackground(uint8* plane, uint16 planepitch, uint16 height) {};
protected:
+ int16 _transparency;
uint16 _frameCount;
Palette* _ownPalette;
};
// movie format for Kyrandia 1
- // there is also a new WSA Format for Kyrandia 2
- // which i will implement in future
class WSAMovieV1 : public Movie {
public:
- WSAMovieV1(uint8* data, uint32 size);
+ WSAMovieV1(uint8* data, uint32 size, uint8 gameid);
~WSAMovieV1();
+ void renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame);
const uint8* loadFrame(uint16 frame, uint16* width, uint16* height);
+ void setImageBackground(uint8* plane, uint16 planepitch, uint16 height);
+
+ void position(uint16 x, uint16 y) { _wsaHeader._xPos = x; _wsaHeader._yPos = y; }
protected:
uint8* _buffer;
@@ -62,19 +74,60 @@ namespace Kyra {
#pragma START_PACK_STRUCTS
struct WSAHeader {
uint16 _numFrames; // All right
+ uint16 _width; // All right
+ uint16 _height; // All right
+ uint8 _xPos; // is wrong
+ uint8 _yPos; // is wrong
+ uint16 _delta; // should be right
+ uint16 _type; // should be right
+ } GCC_PACK _wsaHeader;
+#pragma END_PACK_STRUCTS
+
+ uint32* _offsetTable;
+
+ uint8* _currentFrame;
+ uint16 _prefetchedFrame;
+
+ uint8* _background; // only a pointer to the screen
+ uint16 _backWidth, _backHeight;
+ };
+
+ // movie format for Kyrandia 2+
+ class WSAMovieV2 : public Movie {
+
+ public:
+ WSAMovieV2(uint8* data, uint32 size);
+ ~WSAMovieV2();
+
+ void renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame);
+ const uint8* loadFrame(uint16 frame, uint16* width, uint16* height);
+ void setImageBackground(uint8* plane, uint16 planepitch, uint16 height);
+
+ void position(uint16 x, uint16 y) { _wsaHeader._xPos = x; _wsaHeader._yPos = y; }
+ bool looping(void) { return _looping; }
+ protected:
+
+ uint8* _buffer;
+
+ struct WSAHeader {
+ uint16 _numFrames; // All right
uint16 _width; // should be right
uint16 _height; // should be right
- uint8 _xPos; // could be wrong
- uint8 _yPos; // could be wrong
+ uint16 _xPos; // could be wrong
+ uint16 _yPos; // could be wrong
uint16 _delta; // could be wrong
uint16 _type; // should be right
} GCC_PACK _wsaHeader;
-#pragma END_PACK_STRUCTS
-
+
uint32* _offsetTable;
uint8* _currentFrame;
uint16 _prefetchedFrame;
+
+ uint8* _background; // only a pointer to the screen
+ uint16 _backWidth, _backHeight;
+
+ bool _looping;
};
} // end of namespace Kyra