From 8f65711a28b0cdedca29cdd1787b40546d448575 Mon Sep 17 00:00:00 2001 From: James Brown Date: Fri, 15 Oct 2004 06:06:47 +0000 Subject: Merge in some of LordHotos kyra code, with some changes. It's still non-functional, but once I merge in some more of my local changes things should actually be moving a long a bit. svn-id: r15554 --- kyra/codecs.cpp | 322 ++++++++++++++++++++++++++++++++++ kyra/codecs.h | 43 +++++ kyra/cpsimage.cpp | 183 +++++++++++++++++++ kyra/font.cpp | 329 ++++++++++++++++++++++++++++++++++ kyra/kyra.cpp | 142 ++++++++++++--- kyra/kyra.h | 35 +++- kyra/module.mk | 3 +- kyra/palette.cpp | 80 +++++++++ kyra/resource.cpp | 254 +++++++++++++++++++++++++++ kyra/resource.h | 201 +++++++++++++++++++++ kyra/script.cpp | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++++ kyra/script.h | 155 ++++++++++++++++ kyra/script_v1.cpp | 220 +++++++++++++++++++++++ kyra/wsamovie.cpp | 119 +++++++++++++ kyra/wsamovie.h | 82 +++++++++ 15 files changed, 2646 insertions(+), 28 deletions(-) create mode 100644 kyra/codecs.cpp create mode 100644 kyra/codecs.h create mode 100644 kyra/cpsimage.cpp create mode 100644 kyra/font.cpp create mode 100644 kyra/palette.cpp create mode 100644 kyra/resource.cpp create mode 100644 kyra/resource.h create mode 100644 kyra/script.cpp create mode 100644 kyra/script.h create mode 100644 kyra/script_v1.cpp create mode 100644 kyra/wsamovie.cpp create mode 100644 kyra/wsamovie.h diff --git a/kyra/codecs.cpp b/kyra/codecs.cpp new file mode 100644 index 0000000000..96404f0679 --- /dev/null +++ b/kyra/codecs.cpp @@ -0,0 +1,322 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + + +#include "stdafx.h" +#include "codecs.h" + +/***************************************************************************** + * decode.c - Decoding routines for format80, format40, format20 + * and format3 type graphics + * Author: Olaf van der spek + * Modified for FreeCNC by Kareem Dana + * Modified for Kyra by Jack Burton + * Format3 decoding added by Jack Burton + * Modified for ScummVM by Johannes Schickel + ****************************************************************************/ + +/** decompress format 80 compressed data. + * @param compressed data. + * @param pointer to output uncompressed data. + * @returns size of uncompressed data. + */ +namespace Kyra { +int Compression::decode80(const uint8* image_in, uint8* image_out) { + /* + 0 copy 0cccpppp p + 1 copy 10cccccc + 2 copy 11cccccc p p + 3 fill 11111110 c c v + 4 copy 11111111 c c p p + */ + + const uint8* copyp; + const uint8* readp = image_in; + uint8* writep = image_out; + uint16 code; + uint16 count; + +#ifdef SCUMM_BIG_ENDIAN + uint16 bigend; /* temporary big endian var */ +#endif + + while (1) + { + code = *readp++; + if (~code & 0x80) + { + //bit 7 = 0 + //command 0 (0cccpppp p): copy + count = (code >> 4) + 3; + copyp = writep - (((code & 0xf) << 8) + *readp++); + while (count--) + *writep++ = *copyp++; + } + else + { + //bit 7 = 1 + count = code & 0x3f; + if (~code & 0x40) + { + //bit 6 = 0 + if (!count) + //end of image + break; + //command 1 (10cccccc): copy + while (count--) + *writep++ = *readp++; + } + else + { + //bit 6 = 1 + if (count < 0x3e) + { + //command 2 (11cccccc p p): copy + count += 3; + +#ifdef SCUMM_BIG_ENDIAN + memcpy(&bigend, readp, 2); + copyp = (const uint8*)&image_out[*(const_cast((const uint16*)SWAP_BYTES_16(bigend))]; +#else + copyp = (const uint8*)&image_out[*(const_cast((const uint16*)readp))]; +#endif + + readp += 2; + while (count--) + *writep++ = *copyp++; + } + else if (count == 0x3e) + { + //command 3 (11111110 c c v): fill + +#ifdef SCUMM_BIG_ENDIAN + memset(&count, 0, sizeof(uint32)); + memcpy(&count, readp, 2); + count = const_cast((const uint16*)SWAP_BYTES_16(count)); +#else + count = *(const_cast((const uint16*)readp)); +#endif + readp += 2; + code = *readp++; + while (count--) + *writep++ = code; + } + else + { + //command 4 (copy 11111111 c c p p): copy + +#ifdef SCUMM_BIG_ENDIAN + memset(&count, 0, sizeof(uint32)); + memcpy(&count, readp, 2); + count = const_cast((const uint16*)SWAP_BYTES_16(count)); +#else + count = *(const_cast((const uint16*)readp)); +#endif + readp += 2; + +#ifdef SCUMM_BIG_ENDIAN + memcpy(&bigend, readp, 2); + copyp = (const uint8*)&image_out[*(const_cast((const uint16*)SWAP_BYTES_16(bigend))]; +#else + copyp = (const uint8*)&image_out[*(const_cast((const uint16*)readp))]; +#endif + readp += 2; + while (count--) + *writep++ = *copyp++; + } + } + } + } + + return (writep - image_out); +} + +/** decompress format 40 compressed data. + * @param compressed data. + * @param pointer to put uncompressed data in. + * @returns size of uncompressed data. + */ +int Compression::decode40(const uint8* image_in, uint8* image_out) { + /* + 0 fill 00000000 c v + 1 copy 0ccccccc + 2 skip 10000000 c 0ccccccc + 3 copy 10000000 c 10cccccc + 4 fill 10000000 c 11cccccc v + 5 skip 1ccccccc + */ + + const uint8* readp = image_in; + uint8* writep = image_out; + uint16 code; + uint16 count; + + while (1) { + code = *readp++; + if (~code & 0x80) + { + //bit 7 = 0 + if (!code) + { + //command 0 (00000000 c v): fill + count = *readp++; + code = *readp++; + while (count--) + *writep++ ^= code; + } + else + { + //command 1 (0ccccccc): copy + count = code; + while (count--) + *writep++ ^= *readp++; + } + + } + else + { + //bit 7 = 1 + if (!(count = code & 0x7f)) + { + +#ifdef SCUMM_BIG_ENDIAN + memset(&count, 0, sizeof(uint32)); + memcpy(&count, readp, 2); + count = const_cast((const uint16*)SWAP_BYTES_16(count)); +#else + count = *(const_cast((const uint16*)readp)); +#endif + readp += 2; + code = count >> 8; + if (~code & 0x80) + { + //bit 7 = 0 + //command 2 (10000000 c 0ccccccc): skip + if (!count) + // end of image + break; + writep += count; + } + else + { + //bit 7 = 1 + count &= 0x3fff; + if (~code & 0x40) + { + //bit 6 = 0 + //command 3 (10000000 c 10cccccc): copy + while (count--) + *writep++ ^= *readp++; + } + else + { + //bit 6 = 1 + //command 4 (10000000 c 11cccccc v): fill + code = *readp++; + while (count--) + *writep++ ^= code; + } + } + } + else //command 5 (1ccccccc): skip + writep += count; + } + } + return (writep - image_out); +} + +/** decompress format 3 compressed data. + * @param compressed data. + * @param pointer to put uncompressed data in. + * @param size of uncompressed image. + */ +int Compression::decode3(const uint8* image_in, uint8* image_out, int size) +{ /* Untested on BIG-Endian machines */ + + /* + 0 copy + 1 fill + 2 fill + */ + const uint8* readp = image_in; + uint8* writep = image_out; + int16 code; + int16 count; + + do { + code = *const_cast((const int8*)readp++); + if (code > 0) // Copy + { + count = code ; + while (count--) + *writep++ = *readp++; + } + else if (code == 0) // Fill(1) + { + count = *(const_cast((const uint16*)readp)); + +#ifdef SCUMM_LITTLE_ENDIAN + count = SWAP_BYTES_16(count); +#endif + + readp += 2; + code = *readp++; + while (count--) + *writep++ = (uint8)code; + } + else if (code < 0) // Fill (2) + { + count = -code; + code = *readp++; + while (count--) + *writep++ = (uint8)code; + } + } while ((writep - image_out) < size); + + //and, to be uniform to other decomp. functions... + return (writep - image_out); +} + +/** decompress format 20 compressed data. + * @param compressed data. + * @param pointer to pu uncompressed data in. + * @param size of compressed data? + * @returns size of uncompressed data? + */ +int Compression::decode2(const uint8* s, uint8* d, int cb_s) { + const uint8* r = s; + const uint8* r_end = s + cb_s; + uint8* w = d; + while (r < r_end) { + int v = *r++; + if (v) + *w++ = v; + else { + v = *r++; + memset(w, 0, v); + w += v; + } + } + return w - d; + +} +} // end of namespace Kyra + diff --git a/kyra/codecs.h b/kyra/codecs.h new file mode 100644 index 0000000000..58447d1a10 --- /dev/null +++ b/kyra/codecs.h @@ -0,0 +1,43 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +/** Various decompression routines */ +#ifndef __COMPRESSION_H +#define __COMPRESSION_H + +// THIS CODE WAS TAKEN FROM FreeKyra Tools Module + +#include "common/stdafx.h" +#include "common/scummsys.h" + +namespace Kyra { + class Compression + { + public: + static int decode80(const uint8* image_in, uint8* image_out); + static int decode40(const uint8* image_in, uint8* image_out); + static int decode3(const uint8* image_in, uint8* image_out, int s); + static int decode2(const uint8* s, uint8* d, int cb_s); + }; +} // end of namespace Kyra + +#endif + diff --git a/kyra/cpsimage.cpp b/kyra/cpsimage.cpp new file mode 100644 index 0000000000..20b72438fe --- /dev/null +++ b/kyra/cpsimage.cpp @@ -0,0 +1,183 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "codecs.h" + +#include "common/stream.h" + +namespace Kyra { + + struct CPSResource { + uint32 size; + uint16 width; + }; + + static const CPSResource CPSResourceTable[] = { + { 64000, 320 }, { 7740, 180 }, { 46080, 320 }, { 0, 0 } + }; + + static int16 getWidthFromCPSRes(uint32 size) { + int16 c = 0; + + for (; CPSResourceTable[c].size; ++c) { + if (CPSResourceTable[c].size == size) + return CPSResourceTable[c].width; + } + + return -1; + } + + CPSImage::CPSImage(uint8* buffer, uint32 size) { + if (!buffer) { + error("resource created without data"); + } + Common::MemoryReadStream bufferstream(buffer, size); + + // reads in the Header + _cpsHeader._filesize = bufferstream.readUint16LE() + 2; + _cpsHeader._format = bufferstream.readUint16LE(); + _cpsHeader._imagesize = bufferstream.readUint16LE(); + _cpsHeader._pal = bufferstream.readUint32LE(); + + // 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); + } + + _image = new uint8[_cpsHeader._imagesize]; + assert(_image); + + uint8* imagebuffer = &buffer[bufferstream.pos()]; + assert(imagebuffer); + + if(_cpsHeader._format == 4) { + Compression::decode80(imagebuffer, _image); + } else if(_cpsHeader._format == 3) { + Compression::decode3(imagebuffer, _image, _cpsHeader._imagesize); + } else { + error("unknown CPS format %d", _cpsHeader._format); + } + + int16 width = getWidthFromCPSRes(_cpsHeader._imagesize); + + if(width == -1) { + warning("unknown CPS width(imagesize: %d)", _cpsHeader._imagesize); + delete [] buffer; + return; + } + + _width = (uint16)width; + _height = _cpsHeader._imagesize / _width; + + _transparency = -1; + + delete [] buffer; + } + + CPSImage::~CPSImage() { + delete [] _image; + delete _ownPalette; + } + + void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y) { + 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; + src += _width; + } + + } 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) { + if (*src == _transparency) { + ++dst; + ++src; + } else { + *dst++ = *src++; + } + } + + dst += planepitch - _width; + } + } + } + + void CPSImage::drawToPlane(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 x, uint16 y, + uint16 srcx, uint16 srcy, uint16 srcwidth, uint16 srcheight) { + 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; + src += _width; + } + + } 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) { + if (*src == _transparency) { + ++dst; + ++src; + } else { + *dst++ = *src++; + } + } + + dst += planepitch - _width; + src += _width - srcwidth; + } + } + } +} // end of namespace Kyra + diff --git a/kyra/font.cpp b/kyra/font.cpp new file mode 100644 index 0000000000..2131774073 --- /dev/null +++ b/kyra/font.cpp @@ -0,0 +1,329 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "common/stream.h" +#include "common/array.h" + +#ifdef DUMP_FILES +#include +#endif + +namespace Kyra { + const uint16 FontHeader_Magic1 = 0x0500; + const uint16 FontHeader_Magic2 = 0x000e; + const uint16 FontHeader_Magic3 = 0x0014; + + Font::Font(uint8* buffer, uint32 size) { + if (!buffer) { + error("resource created without data"); + } + + _buffer = buffer; + + Common::MemoryReadStream bufferstream(buffer, size); + + bufferstream.read(&_fontHeader, sizeof(_fontHeader)); + + // tests for the magic values + if(_fontHeader._magic1 != FontHeader_Magic1 || _fontHeader._magic2 != FontHeader_Magic2 || + _fontHeader._magic3 != FontHeader_Magic3) { + error("magic vars in the fontheader are corrupt\n" + "_magic1 = 0x%x, _magic2 = 0x%x, _magic3 = 0x%x", + _fontHeader._magic1, _fontHeader._magic2, _fontHeader._magic3); + } + + // init all the pointers + _offsetTable = (uint16*)&buffer[bufferstream.pos()]; + _charWidth = &buffer[_fontHeader._charWidthOffset]; + _charHeight = (uint16*)&buffer[_fontHeader._charHeightOffset]; + _charBits = &buffer[_fontHeader._charBitsOffset]; + + // now prerender =) + preRenderAllChars(bufferstream.pos()); + + // This value seems to be a version or language variable + // Known Values + // ------------ + // Russian Floppy: 0x1010 + // German Floppy and English CD: 0x1011 + // Kyrandia 2 should be 0x1012 + debug("_version = 0x%x", _fontHeader._version); + + delete [] _buffer; + _buffer = 0; + _offsetTable = 0; + _charHeight = 0; + _charWidth = 0; + _charBits = 0; + } + + Font::~Font() { + + } + + uint32 Font::getStringWidth(const char* string, char terminator) { + uint32 strsize; + + for (strsize = 0; string[strsize] != terminator; ++strsize) + ; + + uint32 stringwidth = 0; + + for (uint32 pos = 0; pos < strsize; ++pos) { + stringwidth += _preRenderedChars[string[pos]].width; + } + + return stringwidth; + } + + const uint8* Font::getChar(char c, uint8* width, uint8* height, uint8* heightadd) { + PreRenderedChar& c_ = _preRenderedChars[c]; + + *width = c_.width; + *height = c_.height; + *heightadd = c_.heightadd; + + return c_.c; + } + + // splits up the String in a word + const char* Font::getNextWord(const char* string, uint32* size) { + uint32 startpos = 0; + *size = 0; + + // gets start of the word + for (; string[startpos] == ' '; ++startpos) + ; + + // not counting size + for (*size = 0; string[startpos + *size] != ' ' && string[startpos + *size] != '\0'; ++(*size)) + ; + + ++(*size); + + return &string[startpos]; + } + + // Move this to Font declaration? + struct WordChunk { + const char* _string; + uint32 _size; + }; + + void Font::drawStringToPlane(const char* string, + uint8* plane, uint16 planewidth, uint16 planeheight, + uint16 x, uint16 y, uint8 color) { + + // lets do it word after word + Common::Array words; + + uint32 lastPos = 0; + uint32 lastSize = 0; + uint32 strlgt = strlen(string); + + while (true) { + WordChunk newchunk; + newchunk._string = getNextWord(&string[lastPos], &lastSize); + newchunk._size = lastSize; + + lastPos += lastSize; + + words.push_back(newchunk); + + if (lastPos >= strlgt) + break; + } + + uint16 current_x = x, current_y = y; + uint8 heighest = 0; + + const uint8* src = 0; + uint8 width = 0, height = 0, heightadd = 0; + + // now the have alle of these words + for (uint32 tmp = 0; tmp < words.size(); ++tmp) { + lastSize = getStringWidth(words[tmp]._string, ' '); + + // adjust x position + if (current_x + lastSize >= planewidth) { + // hmm lets move it a bit to the left + if (current_x == x && (int16)planewidth - (int16)lastSize >= 0) { + current_x = planewidth - lastSize; + } else { + current_x = x; + if (heighest) + current_y += heighest + 2; + else // now we are using just the fist char :) + current_y += _preRenderedChars[words[tmp]._string[0]].height; + heighest = 0; + } + } + + // TODO: maybe test if current_y >= planeheight ? + + // output word :) + for (lastPos = 0; lastPos < words[tmp]._size; ++lastPos) { + if (words[tmp]._string[lastPos] == '\0') + break; + + // gets our char :) + src = getChar(words[tmp]._string[lastPos], &width, &height, &heightadd); + + // lets draw our char + drawCharToPlane(src, color, width, height, plane, planewidth, planeheight, current_x, current_y + heightadd); + + current_x += width; + heighest = MAX(heighest, height); + } + } + } + + void Font::drawCharToPlane(const uint8* c, uint8 color, uint8 width, uint8 height, + uint8* plane, uint16 planewidth, uint16 planeheight, uint16 x, uint16 y) { + const uint8* src = c; + + // blit them to the screen + for (uint8 yadd = 0; yadd < height; ++yadd) { + for (uint8 xadd = 0; xadd < width; ++xadd) { + switch(*src) { + case 1: + plane[(y + yadd) * planewidth + x + xadd] = color; + break; + + case 2: + plane[(y + yadd) * planewidth + x + xadd] = 14; + break; + + case 3: + plane[(y + yadd) * planewidth + x + xadd] = 0; + break; + + default: + // nothing to do now + break; + }; + + ++src; + } + } + } + + void Font::preRenderAllChars(uint16 offsetTableOffset) { + uint16 startOffset = _offsetTable[0]; + uint16 currentOffset = offsetTableOffset; + uint8 currentChar = 0; + + for (; currentOffset < startOffset; ++currentChar, currentOffset += sizeof(uint16)) { + // lets prerender the char :) + + PreRenderedChar newChar; + + newChar.c = new uint8[(_charHeight[currentChar] >> 8) * _charWidth[currentChar]]; + assert(newChar.c); + memset(newChar.c, 0, sizeof(uint8) * (_charHeight[currentChar] >> 8) * _charWidth[currentChar]); + newChar.height = (_charHeight[currentChar] >> 8); + newChar.width = _charWidth[currentChar]; + newChar.heightadd = _charHeight[currentChar] & 0xFF; + + uint8* src = _buffer + _offsetTable[currentChar]; + uint8* dst = &newChar.c[0]; + uint8 index = 0; + +#ifdef DUMP_FILES + static char filename[32] = { 0 }; + sprintf(filename, "dumps/char%d.dmp", currentChar); + FILE* dump = fopen(filename, "w+"); + assert(dump); + + fprintf(dump, "This should be a '%c'\n", currentChar); +#endif + + // prerender the char + for (uint8 yadd = 0; yadd < newChar.height; ++yadd) { + for (uint8 xadd = 0; xadd < newChar.width; ++xadd) { + if (xadd % 2) { + index = ((*src) & 0xF0) >> 4; + ++src; + } else { + index = (*src) & 0x0F; + } + + switch(index) { + case 1: +#ifdef DUMP_FILES + fprintf(dump, "#"); +#endif + dst[yadd * newChar.width + xadd] = 1; + break; + + case 2: +#ifdef DUMP_FILES + fprintf(dump, "$"); +#endif + dst[yadd * newChar.width + xadd] = 2; + break; + + case 3: +#ifdef DUMP_FILES + fprintf(dump, "§"); +#endif + dst[yadd * newChar.width + xadd] = 3; + break; + + default: +#ifdef DUMP_FILES + fprintf(dump, "%d", index); +#endif + break; + }; + } + + if (newChar.width % 2) { + ++src; + } +#ifdef DUMP_FILES + fprintf(dump, "\n"); +#endif + } + +#ifdef DUMP_FILES + fprintf(dump, "\nThis is the created map:\n"); + // now print the whole thing again + for (uint8 yadd = 0; yadd < newChar.height; ++yadd) { + for (uint8 xadd = 0; xadd < newChar.width; ++xadd) { + fprintf(dump, "%d", dst[yadd * newChar.width + xadd]); + } + fprintf(dump, "\n"); + } + fclose(dump); +#endif + + _preRenderedChars[currentChar] = newChar; + + if (currentChar == 255) { + break; + } + } + } +} // end of namespace Kyra + diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp index b7875cb76a..a1ae6449c2 100644 --- a/kyra/kyra.cpp +++ b/kyra/kyra.cpp @@ -1,5 +1,5 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2003 The ScummVM project +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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 @@ -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 @@ -28,35 +28,58 @@ #include "sound/mixer.h" #include "common/file.h" #include "common/config-manager.h" -#include "kyra.h" -static const GameSettings kyra_setting = - { "kyra", "Legend of Kyrandia", 0 }; +#include "kyra.h" +#include "resource.h" +#include "script.h" + +struct KyraGameSettings { + const char *name; + const char *description; + uint32 features; + const char *detectName; + GameSettings toGameSettings() const { + GameSettings dummy = { name, description, features }; + return dummy; + } +}; + +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} +}; GameList Engine_KYRA_gameList() { GameList games; + const KyraGameSettings *g = kyra_settings; + + while (g->name) { + games.push_back(g->toGameSettings()); + g++; + } - games.push_back(kyra_setting); return games; } -// TODO: Improve this :) DetectedGameList Engine_KYRA_detectGames(const FSList &fslist) { + const KyraGameSettings *game; DetectedGameList detectedGames; - File test_file; - - // Iterate over all files in the given directory - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - const char *name = file->displayName().c_str(); - if ((0 == scumm_stricmp("chapter1.vrm", name)) || - (0 == scumm_stricmp("chapter5.vrm", name))) { - detectedGames.push_back(kyra_setting); - printf("Detecting Kyra...\n"); - break; + + for (game = kyra_settings; game->name; ++game) { + if (game->detectName == NULL) + continue; + + for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *name = file->displayName().c_str(); + if ((!scumm_stricmp(game->detectName, name))) { + detectedGames.push_back(game->toGameSettings()); + break; + } } } - return detectedGames; + return detectedGames; } Engine *Engine_KYRA_create(GameDetector *detector, OSystem *syst) { @@ -78,11 +101,37 @@ KyraEngine::KyraEngine(GameDetector *detector, OSystem *syst) //getGameDataPath(); - // Initialize backend - syst->initSize(320, 240); + // Initialize backen + syst->initSize(320, 200); + _screen = new uint8[320*200]; + memset((void*)_screen, 0, sizeof(_screen)); + + _resMgr = new Resourcemanager(this, getGameDataPath()); + assert(_resMgr); + + setCurrentPalette(_resMgr->loadPalette("PALETTE.COL")); + + // loads the 2 cursors + _mouse = _resMgr->loadImage("MOUSE.CPS"); //startup.pak + _items = _resMgr->loadImage("ITEMS.CPS"); + + // loads the Font + _font = _resMgr->loadFont("8FAT.FNT"); + printf("loading scripts\n"); + // loads out scripts + _npcScript = _resMgr->loadScript("_NPC.EMC"); + _currentScript = _resMgr->loadScript("_STARTUP.EMC"); + printf("done\n"); + } KyraEngine::~KyraEngine() { + delete _resMgr; + delete _mouse; + delete _items; + delete _npcScript; + delete _currentScript; + delete _font; } void KyraEngine::errorString(const char *buf1, char *buf2) { @@ -91,10 +140,61 @@ void KyraEngine::errorString(const char *buf1, char *buf2) { void KyraEngine::go() { warning("Kyrandia Engine ::go()"); + // starts the init script + if (!_currentScript->startScript(kSetupScene)) { + error("couldn't init '_STARTUP.EMC' script"); + } + + if (_currentScript->contScript() != kScriptStopped) { + if (_currentScript->state() == kScriptError) { + error("couldn't run script"); + } else { + warning("init script returned: %d", _currentScript->state()); + } + } + + while(true) { + OSystem::Event event; + //if (_debugger->isAttached()) + // _debugger->onFrame(); + + updateScreen(); + while (g_system->pollEvent(event)) { + switch (event.event_code) { + case OSystem::EVENT_QUIT: + g_system->quit(); + break; + default: + break; + } + } + _system->delayMillis(10); + } } void KyraEngine::shutdown() { _system->quit(); } + +void KyraEngine::updateScreen(void) { + _system->copyRectToScreen(_screen, 320, 0, 0, 320, 240); + _system->updateScreen(); +} + +void KyraEngine::setCurrentPalette(Palette* pal, bool delNextTime) { +// if (_delPalNextTime) +// delete _currentPal; + +// _delPalNextTime = delNextTime; + +// _currentPal = pal; + + if (pal->getData()) { + _system->setPalette(pal->getData(), 0, 256); + } else { + warning("palette contains no data"); + } +} + } // End of namespace KYRA diff --git a/kyra/kyra.h b/kyra/kyra.h index 9bcf09e3c4..14a5c7855e 100644 --- a/kyra/kyra.h +++ b/kyra/kyra.h @@ -22,26 +22,49 @@ #ifndef KYRA_H #define KYRA_H -#include "common/scummsys.h" +//#include "common/scummsys.h" #include "base/engine.h" #include "base/gameDetector.h" #include "common/util.h" +enum { + GF_FLOPPY = 1 << 0, + GF_TALKIE = 1 << 1, + GF_KYRA1 = 1 << 2, + GF_KYRA2 = 1 << 3 +}; + namespace Kyra { + class Resourcemanager; + class CPSImage; + class Font; + class Palette; + class VMContext; class KyraEngine : public Engine { - +public: + KyraEngine(GameDetector *detector, OSystem *syst); + ~KyraEngine(); void errorString( const char *buf_input, char *buf_output); + void updateScreen(void); + void setCurrentPalette(Palette* pal, bool delNextTime = true); + + Resourcemanager* resManager(void) { return _resMgr; } +// MidiDriver* midiDriver(void) { return _midiDriver; } + protected: void go(); void shutdown(); + Resourcemanager* _resMgr; + uint8 *_screen; -public: - - KyraEngine(GameDetector *detector, OSystem *syst); - virtual ~KyraEngine(); + Font* _font; + CPSImage* _mouse; + CPSImage* _items; + VMContext* _currentScript; // our current script + VMContext* _npcScript; // script from NPCs }; } // End of namespace Kyra diff --git a/kyra/module.mk b/kyra/module.mk index bf81faf477..5c4cf5d18b 100644 --- a/kyra/module.mk +++ b/kyra/module.mk @@ -1,7 +1,8 @@ MODULE := kyra MODULE_OBJS = \ - kyra/kyra.o + kyra/kyra.o kyra/codecs.o kyra/script.o kyra/script_v1.o kyra/resource.o \ + kyra/wsamovie.o kyra/palette.o kyra/cpsimage.o kyra/font.o MODULE_DIRS += \ kyra diff --git a/kyra/palette.cpp b/kyra/palette.cpp new file mode 100644 index 0000000000..a9836c8ef9 --- /dev/null +++ b/kyra/palette.cpp @@ -0,0 +1,80 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "resource.h" + +#include "common/stream.h" +#include "codecs.h" + +namespace Kyra { + + Palette::Palette(uint8* data, uint32 size) { + if (!data) { + error("resource created without data"); + } + + if (size != 768) { + Common::MemoryReadStream datastream(data, size); + + datastream.readSint32LE(); + int imageSize = datastream.readSint16LE(); + + if (imageSize != 768) { + error("decompresed palette is not 768 byte long!"); + } + + // lets uncompress this palette :) + _palette = new uint8[imageSize]; + assert(_palette); + + // made decompression + if (Compression::decode80(data + 10, _palette) != 768) { + error("decode80 decompressesize != 768 bytes"); + } + + delete [] data; + data = _palette; + } + + // hmm.. common/system.h Docu is wrong or SDL Backend has a bug :) + // a palette should have this order: + // R1-G1-B1-A1-R2-G2-B2-A2-... + // so we need 4 bytes per color + _palette = new uint8[256 * 4]; + + uint8* currentpossrc = &data[0]; + uint8* currentposdst = &_palette[0]; + + // creates the original pallette (only first 6 bits are used) + for (uint32 i = 0; i < 256; i++) { + currentposdst[0] = currentpossrc[0] << 2; + currentposdst[1] = currentpossrc[1] << 2; + currentposdst[2] = currentpossrc[2] << 2; + currentpossrc += 3; + currentposdst += 4; + } + + delete [] data; + } + +} // end of namespace Kyra + diff --git a/kyra/resource.cpp b/kyra/resource.cpp new file mode 100644 index 0000000000..6e56ff3a08 --- /dev/null +++ b/kyra/resource.cpp @@ -0,0 +1,254 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "wsamovie.h" + +#include "common/file.h" +#include "script.h" + +namespace Kyra { + Resourcemanager::Resourcemanager(KyraEngine* engine, const char* gamedir) { + _gameDir = gamedir; + + // prefetches all PAK Files + + // ugly a hardcoded list + // TODO: use the FS Backend to get all .PAK Files and load them + static const char* kyraFilelist[] = { + "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 + }; + + for (uint32 tmp = 0; kyraFilelist[tmp]; ++tmp) { + + // prefetch file + PAKFile* file = new PAKFile(getPath() + kyraFilelist[tmp]); + assert(file); + + if (file->isValid()) + _pakfiles.push_back(file); + else + warning("couldn't load file '%s' correctly", kyraFilelist[tmp]); + } + } + + Resourcemanager::~Resourcemanager() { + Common::List::iterator start = _pakfiles.begin(); + + for (;start != _pakfiles.end(); ++start) { + delete *start; + *start = 0; + } + } + + 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((getPath() + file).c_str())) { + + *size = file_.size(); + + buffer = new uint8[*size]; + assert(buffer); + + file_.read(buffer, *size); + + file_.close(); + + } else { + // opens the file in a PAK File + Common::List::iterator start = _pakfiles.begin(); + + for (;start != _pakfiles.end(); ++start) { + *size = (*start)->getFileSize(file); + + 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 buffer; + } + + Palette* Resourcemanager::loadPalette(const char* file) { + uint32 size = 0; + uint8* buffer = 0; + buffer = fileData(file, &size); + if (!buffer) + return 0; + return new Palette(buffer, size); + } + + CPSImage* Resourcemanager::loadImage(const char* file) { + uint32 size = 0; + uint8* buffer = 0; + buffer = fileData(file, &size); + if (!buffer) + return 0; + return new CPSImage(buffer, size); + } + + Font* Resourcemanager::loadFont(const char* file) { + uint32 size = 0; + uint8* buffer = 0; + buffer = fileData(file, &size); + if (!buffer) + return 0; + return new Font(buffer, size); + } + + Movie* Resourcemanager::loadMovie(const char* file) { + // TODO: we have to check the Extenion to create the right movie + uint32 size = 0; + uint8* buffer = 0; + buffer = fileData(file, &size); + if (!buffer) + return 0; + return new WSAMovieV1(buffer, size); + } + + VMContext* Resourcemanager::loadScript(const char* file) { + VMContext* context = new VMContext(_engine); + context->loadScript(file); + return context; + } + + Common::String Resourcemanager::getPath(void) { + assert(_gameDir); + int32 len = strlen(_gameDir); + + if(len < 1) + error("no valid gamedir"); + + // tests for an path seperator at the end + if (_gameDir[len - 1] == '\\') { + return string(_gameDir); + } else if (_gameDir[len - 1 ] == '/') { + return string(_gameDir); + } + + // creates a path seperator at the end + // we are always using the path seperator from the system + // even if Windows shoudl accept '/' +#ifdef WIN32 + return string(_gameDir) + "\\"; +#else + return string(_gameDir) + "/"; +#endif + } + +/////////////////////////////////////////// +// Pak file manager + #define PAKFile_Iterate Common::List::iterator start=_files.begin();start != _files.end(); ++start + + PAKFile::PAKFile(const Common::String& file) { + File pakfile; + + if (!pakfile.open(file.c_str())) { + warning("PAKFile couldn't open: '%s'", file.c_str()); + return; + } + + uint32 filesize = pakfile.size(); + _buffer = new uint8[filesize]; + assert(_buffer); + + pakfile.read(_buffer, filesize); + pakfile.close(); + + // works with the file + uint32 pos = 0, startoffset = 0, endoffset = 0; + + startoffset = *(reinterpret_cast((_buffer + pos))); + pos += 4; + + while (pos < filesize) { + PakChunk* chunk = new PakChunk; + assert(chunk); + + // saves the name + chunk->_name = reinterpret_cast(_buffer + pos); + pos += strlen(chunk->_name) + 1; + if(!chunk->_name) + break; + + endoffset = *(reinterpret_cast((_buffer + pos))); + pos += 4; + + chunk->_data = _buffer + startoffset; + chunk->_size = endoffset - startoffset; + + startoffset = endoffset; + + _files.push_back(chunk); + } + } + + PAKFile::~PAKFile() { + delete [] _buffer; + _buffer = 0; + + for (PAKFile_Iterate) { + delete *start; + *start = 0; + } + } + + const uint8* PAKFile::getFile(const char* file) { + for (PAKFile_Iterate) { + if (!scumm_stricmp((*start)->_name, file)) + return (*start)->_data; + } + + return 0; + } + + uint32 PAKFile::getFileSize(const char* file) { + for (PAKFile_Iterate) { + if (!scumm_stricmp((*start)->_name, file)) + return (*start)->_size; + } + + return 0; + } +} // end of namespace Kyra + diff --git a/kyra/resource.h b/kyra/resource.h new file mode 100644 index 0000000000..b0a73beaa5 --- /dev/null +++ b/kyra/resource.h @@ -0,0 +1,201 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef RESOURCE_H +#define RESOURCE_H + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/str.h" +#include "common/list.h" +#include "common/map.h" + +#include "kyra.h" + +namespace Kyra { + + // standard Package format for Kyrandia games + class PAKFile { + + struct PakChunk { + const char* _name; + const uint8* _data; + uint32 _size; + }; + + public: + + PAKFile(const Common::String& file); + ~PAKFile(); + + const uint8* getFile(const char* file); + uint32 getFileSize(const char* file); + + bool isValid(void) { return (_buffer != 0); } + + private: + + uint8* _buffer; // the whole file + Common::List _files; // the entries + + }; + + // some resource types + class Palette; + class CPSImage; + class Font; + class Movie; + class VMContext; + + // out resource manager + class Resourcemanager { + typedef Common::String string; + + public: + + Resourcemanager(KyraEngine* engine, const char* gamedir); + virtual ~Resourcemanager(); + + uint8* fileData(const char* file, uint32* size); + + Palette* loadPalette(const char* file); + CPSImage* loadImage(const char* file); + Font* loadFont(const char* file); + Movie* loadMovie(const char* file); + VMContext* loadScript(const char* file); + + protected: + KyraEngine* _engine; + + string getPath(void); + const char* _gameDir; + Common::List _pakfiles; + + }; + + class Palette { + + public: + + Palette(uint8* data, uint32 size); + ~Palette() { delete [] _palette; } + + uint8* getData(void) { return _palette; } + + protected: + + uint8* _palette; + + }; + + class CPSImage { + + public: + + CPSImage(uint8* buffer, uint32 size); + ~CPSImage(); + + Palette* palette(void) { return _ownPalette; } + bool hasPalette(void) { return (_ownPalette != 0); } + + // if col == -1 then no transparany + void setTransparencyColor(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, + uint16 srcx, uint16 srcy, uint16 srcwidth, uint16 srcheight); + + // only for testing :) + uint8 getColor(uint16 x, uint16 y) { return _image[y * _width + x]; } + + uint8& operator[](uint16 index) { if(index > _width * _height) return _image[0]; return _image[index]; } + + protected: + + struct CPSHeader { + uint16 _filesize; + uint16 _format; + uint16 _imagesize; + uint32 _pal; + } _cpsHeader; + + Palette* _ownPalette; + uint8* _image; + + uint16 _width, _height; + int16 _transparency; + }; + + class Font { + + public: + + Font(uint8* buffer, uint32 size); + ~Font(); + + uint32 getStringWidth(const char* string, char terminator = '\0'); + void drawStringToPlane(const char* string, + uint8* plane, uint16 planewidth, uint16 planeheight, + uint16 x, uint16 y, uint8 color); + + protected: + + void drawCharToPlane(const uint8* c, uint8 color, uint8 width, uint8 height, + uint8* plane, uint16 planewidth, uint16 planeheight, uint16 x, uint16 y); + const uint8* getChar(char c, uint8* width, uint8* height, uint8* heightadd); + const char* getNextWord(const char* string, uint32* size); + + void preRenderAllChars(uint16 offsetTableOffset); + + uint8* _buffer; + + uint16* _offsetTable; + uint8* _charWidth; + uint16* _charHeight; + uint8* _charBits; + + // the chars I call 'prerendered' aren't really prerendered + // they are only 'decoded' + struct PreRenderedChar { + uint8* c; + uint8 width, height, heightadd; + }; + + Common::Map _preRenderedChars; // our prerendered chars :) + + // INFO: + // _magic1 = 0x0500 + // _magic2 = 0x000e + // _magic3 = 0x0014 +#pragma START_PACK_STRUCTS + struct FontHeader { + uint16 _size; + uint16 _magic1, _magic2, _magic3; + uint16 _charWidthOffset, _charBitsOffset, _charHeightOffset; + uint16 _version; + uint16 _countChars; + uint8 _width, _height; + } GCC_PACK _fontHeader; +#pragma END_PACK_STRUCTS + }; +} // end of namespace Kyra + +#endif diff --git a/kyra/script.cpp b/kyra/script.cpp new file mode 100644 index 0000000000..8b5e18287a --- /dev/null +++ b/kyra/script.cpp @@ -0,0 +1,506 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "kyra.h" +#include "script.h" +#include "resource.h" + +#include "common/stream.h" + +#define COMMAND(x) { &VMContext::x, #x } +#define OPCODE(x) { &VMContext::x, #x } + +namespace Kyra { + VMContext::VMContext(KyraEngine* engine) { + _engine = engine; + + // now we create a list of all Command/Opcode procs and so + static CommandEntry commandProcs[] = { + // 0 + COMMAND(c1_goToLine), + COMMAND(c1_setReturn), + COMMAND(c1_pushRetRec), + COMMAND(c1_push), + COMMAND(c1_push), + COMMAND(c1_pushVar), + COMMAND(c1_pushFrameNeg), + COMMAND(c1_pushFramePos), + COMMAND(c1_popRetRec), + COMMAND(c1_popVar), + + // 10 + COMMAND(c1_popFrameNeg), + COMMAND(c1_popFramePos), + COMMAND(c1_addToSP), + COMMAND(c1_subFromSP), + COMMAND(c1_execOpcode), + COMMAND(c1_ifNotGoTo), + COMMAND(c1_negate), + COMMAND(c1_evaluate), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 20 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 30 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 40 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 50 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 60 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 70 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 80 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 90 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 100 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 110 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 120 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 130 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 140 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 150 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 160 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 170 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 180 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 190 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 200 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 210 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 220 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 230 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 240 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + + // 250 + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + COMMAND(c1_unknownCommand), + { 0, 0 } + }; + + _scriptFile = NULL; + _scriptFileSize = 0; + } + + void VMContext::loadScript(const char* file) { + printf("a\n"); + if (_scriptFile) { + delete [] _scriptFile; + _scriptFileSize = 0; + } + + debug("--------------"); + + // loads the new file + _scriptFile = _engine->resManager()->fileData(file, &_scriptFileSize); + printf("c\n"); + + if (!_scriptFileSize || !_scriptFile) { + error("couldn't load script file '%s'", file); + } + + Common::MemoryReadStream script(_scriptFile, _scriptFileSize); + memset(_chunks, 0, sizeof(ScriptChunk) * kCountChunkTypes); + uint8 chunkName[sizeof("EMC2ORDR") + 1]; + + // so lets look for our chunks :) + 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((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); + } else if (!scumm_stricmp((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); + + script.seek(script.pos() + text_size); + } else if (!scumm_stricmp((char*)chunkName, "DATA")) { + _chunks[kData]._size = script.readUint32BE(); + _chunks[kData]._data = _scriptFile + script.pos(); + debug("_chunks[kData]._size = %d", _chunks[kData]._size); + + // 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 { + // read next 4 chars + script.read(&chunkName[4], sizeof(uint8) * 4); + chunkName[8] = '\0'; + debug("chunk name(8 chars): '%s'", chunkName); + + if (!scumm_stricmp((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); + + script.seek(script.pos() + _chunks[kEmc2Ordr]._size * 2); + } else { + // any unkown chunk or problems with seeking through the file + error("unknown chunk"); + } + } + } + + // so file loaded + debug("--------------"); + } + + int32 VMContext::param(int32 index) { + if (_stackPos - index + 1 >= 16 || _stackPos - index + 1 < 0) + return -0xFFFF; + return _stack[_stackPos - index + 1]; + } + + const char* VMContext::stringAtIndex(int32 index) { + if (index < 0 || (uint32)index >= _chunks[kText]._size) + return 0; + + return (char*)(_chunks[kText]._additional + _chunks[kText]._data[index]); + } + + bool VMContext::startScript(int32 func) { + if ((uint32)func >= _chunks[kEmc2Ordr]._size || func < 0) { + debug("script doesn't support function %d", func); + return false; + } + + _instructionPos = (READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1) + 2; + _stackPos = 0; + _tempPos = 0; + _delay = 0; + _scriptState = kScriptRunning; + return true; + } + + uint32 VMContext::contScript(void) { + uint8* script_start = _chunks[kData]._data; + assert(script_start); + + uint32 scriptStateAtStart = _scriptState; + + // runs the script + while(true) { + if ((uint32)_instructionPos > _chunks[kData]._size) { + debug("_instructionPos( = %d) > _chunks[kData]._size( = %d)", _instructionPos, _chunks[kData]._size); + _error = true; + break; + } + + _currentCommand = *(script_start + _instructionPos++); + + // gets out + if (_currentCommand & 0x80) { + _argument = ((_currentCommand & 0x0F) << 8) | *(script_start + _instructionPos++); + _currentCommand &= 0xF0; + } else if (_currentCommand & 0x40) { + _argument = *(script_start + _instructionPos++); + } else if (_currentCommand & 0x20) { + _instructionPos++; + + uint16 tmp = *(uint16*)(script_start + _instructionPos); + tmp &= 0xFF7F; + + _argument = READ_BE_UINT16(&tmp); + _instructionPos += 2; + } else { + debug("unknown way of getting the command"); + } + + _currentCommand &= 0x1f; + + CommandProc currentProc = _commands[_currentCommand].proc; + (this->*currentProc)(); + + if (_error) { + _scriptState = kScriptError; + break; + } + + if (scriptStateAtStart != _scriptState) { + break; + } + } + + return _scriptState; + } +} // end of namespace Kyra diff --git a/kyra/script.h b/kyra/script.h new file mode 100644 index 0000000000..0100a9dd6a --- /dev/null +++ b/kyra/script.h @@ -0,0 +1,155 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef VM_H +#define VM_H + +namespace Kyra { + // TODO: + // find out more script functions + enum ScriptFunc { + kSetupScene = 0, + kClickEvent = 1, // _registers[1] and _registers[2] are mouse x, y _registers[4] is action + kActorEvent = 2, + kEnterEvent = 4, + kExitEvent = 5, + kLoadResources = 7 + }; + + enum ScriptState { + kScriptStopped = 0, + kScriptRunning = 1, + kScriptWaiting = 2, + kScriptError = 3 + }; + + class VMContext { + + public: + + VMContext(KyraEngine* engine); + ~VMContext() { delete [] _scriptFile; } + + void loadScript(const char* file); + + const char* stringAtIndex(int32 index); + + // TODO: check for 'over'flow + void pushStack(int32 value) { _stack[_stackPos++] = value; } + void registerValue(int32 reg, int32 value) { _registers[reg] = value; } + int32 checkReg(int32 reg) { return _registers[reg]; } + + uint32 state(void) { return _scriptState; } + + bool startScript(int32 func); + uint32 contScript(void); + + protected: + KyraEngine* _engine; + uint8* _scriptFile; + uint32 _scriptFileSize; + + uint32 _scriptState; + uint32 _delay; + + int32 _registers[32]; // registers of the interpreter + int32 _stack[32]; // our stack + + // TODO: check for 'under'flow + int32 popStack(void) { return _stack[_stackPos--]; } + int32& topStack(void) { return _stack[_stackPos]; } + + uint32 _returnValue; + + int32 _instructionPos; + int32 _stackPos; + int32 _tempPos; + + // used by command & opcode procs + uint16 _argument; + uint8 _currentCommand; + uint32 _currentOpcode; + + int32 param(int32 index); + const char* paramString(int32 index) { return stringAtIndex(param(index)); } + + bool _error; // used by all command- and opcodefuncs + + enum ScriptChunkTypes { + kForm = 0, + kEmc2Ordr = 1, + kText = 2, + kData = 3, + kCountChunkTypes + }; + + struct ScriptChunk { + uint32 _size; + uint8* _data; // by TEXT used for count of texts, by EMC2ODRD it is used for a count of somewhat + uint8* _additional; // currently only used for TEXT + }; + + ScriptChunk _chunks[kCountChunkTypes]; + + typedef void (VMContext::*CommandProc)(); + struct CommandEntry { + CommandProc proc; + const char* desc; + }; + + typedef void (VMContext::*OpcodeProc)(); + struct OpcodeEntry { + OpcodeProc proc; + const char* desc; + }; + + const CommandEntry* _commands; + const OpcodeEntry* _opcodes; + + protected: + // the command procs + void c1_goToLine(void); // 0x00 + void c1_setReturn(void); // 0x01 + void c1_pushRetRec(void); // 0x02 + void c1_push(void); // 0x03 & 0x04 + void c1_pushVar(void); // 0x05 + void c1_pushFrameNeg(void); // 0x06 + void c1_pushFramePos(void); // 0x07 + void c1_popRetRec(void); // 0x08 + void c1_popVar(void); // 0x09 + void c1_popFrameNeg(void); // 0x0A + void c1_popFramePos(void); // 0x0B + void c1_addToSP(void); // 0x0C + void c1_subFromSP(void); // 0x0D + void c1_execOpcode(void); // 0x0E + void c1_ifNotGoTo(void); // 0x0F + void c1_negate(void); // 0x10 + void c1_evaluate(void); // 0x11 + void c1_unknownCommand(void); + + // the opcode procs + void o1_0x68(void); // 0x68 + void o1_unknownOpcode(void); + }; +} // end of namespace Kyra + +#endif + diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp new file mode 100644 index 0000000000..8b306f52e1 --- /dev/null +++ b/kyra/script_v1.cpp @@ -0,0 +1,220 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" + +#include "kyra.h" +#include "script.h" + +namespace Kyra { + // Command procs + + void VMContext::c1_unknownCommand(void) { + debug("unknown command '0x%x'.", _currentCommand); + debug("\targument: '0x%x'", _argument); + + _error = true; + } + + void VMContext::c1_goToLine(void) { + _instructionPos = _argument << 1; + } + + void VMContext::c1_setReturn(void) { + _returnValue = _argument; + } + + void VMContext::c1_pushRetRec(void) { + if (!_argument) { + pushStack(_returnValue); + } else { + int32 rec = ((int16)_tempPos << 16) | ((_instructionPos >> 1) + 1); + pushStack(rec); + _tempPos = _instructionPos; + } + } + + void VMContext::c1_push(void) { + pushStack(_argument); + } + + void VMContext::c1_pushVar(void) { + pushStack(_registers[_argument]); + } + + void VMContext::c1_pushFrameNeg(void) { + pushStack(_stack[_tempPos + _argument]); + } + + void VMContext::c1_pushFramePos(void) { + pushStack(_stack[_tempPos - _argument]); + } + + void VMContext::c1_popRetRec(void) { + if (!_argument) { + _returnValue = popStack(); + } else { + if (_stackPos <= 0) { + _scriptState = kScriptStopped; + } + int32 rec = popStack(); + + _tempPos = (int16)((rec & 0xFFFF0000) >> 16); + _instructionPos = (rec & 0x0000FFFF) * 2; + } + } + + void VMContext::c1_popVar(void) { + _registers[_argument] = popStack(); + } + + void VMContext::c1_popFrameNeg(void) { + _stack[_tempPos + _argument] = popStack(); + } + + void VMContext::c1_popFramePos(void) { + _stack[_tempPos - _argument] = popStack(); + } + + void VMContext::c1_addToSP(void) { + _stackPos -= _argument; + } + + void VMContext::c1_subFromSP(void) { + _stackPos += _argument; + } + + void VMContext::c1_execOpcode(void) { + OpcodeProc proc = _opcodes[_argument].proc; + (this->*proc)(); + } + + void VMContext::c1_ifNotGoTo(void) { + if (!popStack()) { + _instructionPos = _argument << 1; + } + } + + void VMContext::c1_negate(void) { + switch(_argument) { + case 0: + topStack() = !topStack(); + break; + + case 1: + topStack() = -topStack(); + break; + + case 2: + topStack() = ~topStack(); + break; + + default: + debug("unkown negate instruction %d", _argument); + _error = true; + break; + }; + } + + void VMContext::c1_evaluate(void) { + int32 x, y; + int32 res = false; + + x = popStack(); + y = popStack(); + + switch(_argument) { + case 0: + res = x && y; + break; + + case 1: + res = x || y; + break; + + case 3: + res = x != y; + break; + + case 4: + res = x < y; + break; + + case 5: + res = x <= y; + break; + + case 6: + res = x > y; + break; + + case 7: + res = x >= y; + break; + + case 8: + res = x + y; + break; + + case 9: + res = x - y; + break; + + case 10: + res = x * y; + break; + + case 11: + res = x / y; + break; + + case 12: + res = x >> y; + break; + + case 13: + res = x << y; + break; + + case 14: + res = x & y; + break; + + case 15: + res = x | y; + break; + + case 16: + res = x % y; + break; + + case 17: + res = x ^ y; + break; + + default: + debug("unknown evaluate command"); + break; + }; + + pushStack(res); + } +} // end of namespace Kyra diff --git a/kyra/wsamovie.cpp b/kyra/wsamovie.cpp new file mode 100644 index 0000000000..5b89dccf7e --- /dev/null +++ b/kyra/wsamovie.cpp @@ -0,0 +1,119 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "wsamovie.h" +#include "codecs.h" + +#include "common/stream.h" + +namespace Kyra { + WSAMovieV1::WSAMovieV1(uint8* data, uint32 size) { + if (!data) { + error("resource created without data"); + } + + _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 2 with the WSA version 1 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 */; + } + + _frameCount = _wsaHeader._numFrames; + _offsetTable = new uint32[_wsaHeader._numFrames + 2]; + assert(!_offsetTable); + + // loads the offset table + for (uint32 tmp = 0; tmp < _wsaHeader._numFrames; ++tmp) { + _offsetTable[tmp] = datastream.readUint32LE() + offsetAdd; + } + + if (offsetAdd) { + uint8* palbuffer = new uint8[offsetAdd]; + assert(!palbuffer); + + _ownPalette = new Palette(palbuffer, offsetAdd); + assert(!_ownPalette); + } + } + + WSAMovieV1::~WSAMovieV1() { + delete [] _buffer; + delete [] _offsetTable; + delete _ownPalette; + } + + const uint8* WSAMovieV1::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); + } + + uint8* frameData = 0; + uint8 image40[64000]; // I think this crash on Plam OS :) + + if (frame = _prefetchedFrame + 1) { + frameData = _buffer + _offsetTable[frame] + (hasPalette() ? 768 : 0); + Compression::decode80(frameData, image40); + Compression::decode40(image40, _currentFrame); + } else { + memset(_currentFrame, 0, _wsaHeader._width * _wsaHeader._height); + + for (uint32 i = 0; i <= frame; i++) + { + frameData = _buffer + _offsetTable[i] + (hasPalette() ? 768 : 0); + Compression::decode80(frameData, image40); + Compression::decode40(image40, _currentFrame); + } + } + + _prefetchedFrame = frame; + return _currentFrame; + } + + return 0; + } +} // end of namespace Kyra + diff --git a/kyra/wsamovie.h b/kyra/wsamovie.h new file mode 100644 index 0000000000..2f23a5c4c2 --- /dev/null +++ b/kyra/wsamovie.h @@ -0,0 +1,82 @@ +/* ScummVM - Kyrandia Interpreter + * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef MOVIES_H +#define MOVIES_H + +#include "resource.h" + +namespace Kyra { + + // a generic movie + class Movie { + + public: + + virtual ~Movie() {} + + virtual const uint8* loadFrame(uint16 frame, uint16* width = 0, uint16* height = 0) = 0; + virtual uint16 countFrames(void) { return _frameCount; } + + virtual bool hasPalette(void) { return (_ownPalette != 0); } + virtual Palette* palette(void) { return _ownPalette; } + + protected: + 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(); + + const uint8* loadFrame(uint16 frame, uint16* width, uint16* height); + protected: + + uint8* _buffer; + +#pragma START_PACK_STRUCTS + 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 _delta; // could be wrong + uint16 _type; // should be right + } GCC_PACK _wsaHeader; +#pragma END_PACK_STRUCTS + + uint32* _offsetTable; + + uint8* _currentFrame; + uint16 _prefetchedFrame; + }; +} // end of namespace Kyra + +#endif + -- cgit v1.2.3