diff options
| author | James Brown | 2004-10-15 06:06:47 +0000 | 
|---|---|---|
| committer | James Brown | 2004-10-15 06:06:47 +0000 | 
| commit | 8f65711a28b0cdedca29cdd1787b40546d448575 (patch) | |
| tree | feafc61c0bdbd529ef1eb52acf743033395f3547 | |
| parent | 9e40ef7d29ccaca45708b39e1da92bbca088d6ac (diff) | |
| download | scummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.tar.gz scummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.tar.bz2 scummvm-rg350-8f65711a28b0cdedca29cdd1787b40546d448575.zip | |
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
| -rw-r--r-- | kyra/codecs.cpp | 322 | ||||
| -rw-r--r-- | kyra/codecs.h | 43 | ||||
| -rw-r--r-- | kyra/cpsimage.cpp | 183 | ||||
| -rw-r--r-- | kyra/font.cpp | 329 | ||||
| -rw-r--r-- | kyra/kyra.cpp | 142 | ||||
| -rw-r--r-- | kyra/kyra.h | 35 | ||||
| -rw-r--r-- | kyra/module.mk | 3 | ||||
| -rw-r--r-- | kyra/palette.cpp | 80 | ||||
| -rw-r--r-- | kyra/resource.cpp | 254 | ||||
| -rw-r--r-- | kyra/resource.h | 201 | ||||
| -rw-r--r-- | kyra/script.cpp | 506 | ||||
| -rw-r--r-- | kyra/script.h | 155 | ||||
| -rw-r--r-- | kyra/script_v1.cpp | 220 | ||||
| -rw-r--r-- | kyra/wsamovie.cpp | 119 | ||||
| -rw-r--r-- | kyra/wsamovie.h | 82 | 
15 files changed, 2646 insertions, 28 deletions
| 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<uint16*>((const uint16*)SWAP_BYTES_16(bigend))]; +#else +                    copyp = (const uint8*)&image_out[*(const_cast<uint16*>((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<uint16*>((const uint16*)SWAP_BYTES_16(count)); +#else +                    count = *(const_cast<uint16*>((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<uint16*>((const uint16*)SWAP_BYTES_16(count)); +#else +                    count = *(const_cast<uint16*>((const uint16*)readp)); +#endif +                    readp += 2; + +#ifdef SCUMM_BIG_ENDIAN +                    memcpy(&bigend, readp, 2); +                    copyp = (const uint8*)&image_out[*(const_cast<uint16*>((const uint16*)SWAP_BYTES_16(bigend))]; +#else +                    copyp = (const uint8*)&image_out[*(const_cast<uint16*>((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<uint16*>((const uint16*)SWAP_BYTES_16(count)); +#else +                count = *(const_cast<uint16*>((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<int8*>((const int8*)readp++); +        if (code > 0) // Copy  +        {      	 +        	count = code ; +        	while (count--) +        		*writep++ = *readp++;         +        } +        else if (code == 0) // Fill(1)  +        { +        	count = *(const_cast<uint16*>((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 <cstdio> +#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<WordChunk> 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<PAKFile*>::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<PAKFile*>::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<PakChunk*>::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<uint32*>((_buffer + pos))); +		pos += 4; + +		while (pos < filesize) { +			PakChunk* chunk = new PakChunk; +			assert(chunk); + +			// saves the name +			chunk->_name = reinterpret_cast<const char*>(_buffer + pos); +			pos += strlen(chunk->_name) + 1; +			if(!chunk->_name) +				break; + +			endoffset = *(reinterpret_cast<uint32*>((_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<PakChunk*> _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<PAKFile*> _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<uint8, PreRenderedChar> _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 + | 
