scummvm/engines/made/resource.cpp
Benjamin Haisch b6c7385eb4 - Renamed XmidiResource to GenericResource
- Added MIDI resource type
- Added ScriptFunctionsLgop2 and ScriptFunctionsMhne (for Leather Goddesses of Phobos 2 and The Manhole: New and Enhanced, resp.)
- Many changes for LGOP2 and The Manhole: N&E

Note about the new ScriptFunctions classes:
I copied the ScriptFunctionsRtz class and so duplicated a lot of code. Most of the opcode functions are the same in all games but there might be differences. Once all common opcode functions have been figured out, they'll be moved to a common place (like the ScriptFunctions class).

svn-id: r31871
2008-05-05 10:45:11 +00:00

432 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "common/endian.h"
#include "sound/mixer.h"
#include "made/resource.h"
#include "made/graphics.h"
#include "made/sound.h"
namespace Made {
/* Resource */
Resource::~Resource() {
}
/* PictureResource */
PictureResource::PictureResource() : _picture(NULL), _picturePalette(NULL) {
_hasPalette = false;
}
PictureResource::~PictureResource() {
if (_picture) {
delete _picture;
_picture = 0;
}
if (_picturePalette) {
delete[] _picturePalette;
_picturePalette = 0;
}
}
void PictureResource::load(byte *source, int size) {
Common::MemoryReadStream *sourceS = new Common::MemoryReadStream(source, size);
_hasPalette = (sourceS->readByte() != 0);
sourceS->readByte();
sourceS->readByte();
sourceS->readByte();
uint16 cmdOffs = sourceS->readUint16LE();
uint16 pixelOffs = sourceS->readUint16LE();
uint16 maskOffs = sourceS->readUint16LE();
uint16 lineSize = sourceS->readUint16LE();
/*uint16 u = */sourceS->readUint16LE();
uint16 width = sourceS->readUint16LE();
uint16 height = sourceS->readUint16LE();
_paletteColorCount = (cmdOffs - 18) / 3; // 18 = sizeof header
debug(2, "width = %d; height = %d\n", width, height);
if (_hasPalette) {
_picturePalette = new byte[_paletteColorCount * 3];
sourceS->read(_picturePalette, _paletteColorCount * 3);
}
_picture = new Graphics::Surface();
_picture->create(width, height, 1);
decompressImage(source, *_picture, cmdOffs, pixelOffs, maskOffs, lineSize);
delete sourceS;
}
/* AnimationResource */
AnimationResource::AnimationResource() {
}
AnimationResource::~AnimationResource() {
// TODO: Free anim frames
}
void AnimationResource::load(byte *source, int size) {
Common::MemoryReadStream *sourceS = new Common::MemoryReadStream(source, size);
sourceS->readUint32LE();
sourceS->readUint32LE();
sourceS->readUint16LE();
_flags = sourceS->readUint16LE();
_width = sourceS->readUint16LE();
_height = sourceS->readUint16LE();
sourceS->readUint32LE();
uint16 frameCount = sourceS->readUint16LE();
sourceS->readUint16LE();
sourceS->readUint16LE();
for (uint16 i = 0; i < frameCount; i++) {
sourceS->seek(26 + i * 4);
uint32 frameOffs = sourceS->readUint32LE();
sourceS->seek(frameOffs);
sourceS->readUint32LE();
sourceS->readUint32LE();
uint16 frameWidth = sourceS->readUint16LE();
uint16 frameHeight = sourceS->readUint16LE();
uint16 cmdOffs = sourceS->readUint16LE();
sourceS->readUint16LE();
uint16 pixelOffs = sourceS->readUint16LE();
sourceS->readUint16LE();
uint16 maskOffs = sourceS->readUint16LE();
sourceS->readUint16LE();
uint16 lineSize = sourceS->readUint16LE();
Graphics::Surface *frame = new Graphics::Surface();
frame->create(frameWidth, frameHeight, 1);
decompressImage(source + frameOffs, *frame, cmdOffs, pixelOffs, maskOffs, lineSize, _flags & 1);
_frames.push_back(frame);
}
delete sourceS;
}
/* SoundResource */
SoundResource::SoundResource() : _soundSize(0), _soundData(NULL) {
}
SoundResource::~SoundResource() {
if (_soundData)
delete[] _soundData;
}
void SoundResource::load(byte *source, int size) {
uint16 chunkCount = READ_LE_UINT16(source + 8);
uint16 chunkSize = READ_LE_UINT16(source + 12);
_soundSize = chunkCount * chunkSize;
_soundData = new byte[_soundSize];
decompressSound(source + 14, _soundData, chunkSize, chunkCount);
}
Audio::AudioStream *SoundResource::getAudioStream(int soundRate, bool loop) {
byte flags = Audio::Mixer::FLAG_UNSIGNED;
if (loop)
flags |= Audio::Mixer::FLAG_LOOP;
return Audio::makeLinearInputStream(_soundData, _soundSize, soundRate, flags, 0, 0);
}
/* MenuResource */
MenuResource::MenuResource() {
}
MenuResource::~MenuResource() {
}
void MenuResource::load(byte *source, int size) {
_strings.clear();
Common::MemoryReadStream *sourceS = new Common::MemoryReadStream(source, size);
sourceS->skip(4); // skip "MENU"
uint16 count = sourceS->readUint16LE();
for (uint16 i = 0; i < count; i++) {
uint16 offs = sourceS->readUint16LE();
const char *string = (const char*)(source + offs);
_strings.push_back(string);
debug(2, "%02d: %s\n", i, string);
}
fflush(stdout);
delete sourceS;
}
const char *MenuResource::getString(uint index) const {
if (index < _strings.size())
return _strings[index].c_str();
else
return NULL;
}
/* FontResource */
FontResource::FontResource() : _data(NULL), _size(0) {
}
FontResource::~FontResource() {
if (_data)
delete[] _data;
}
void FontResource::load(byte *source, int size) {
_data = new byte[size];
_size = size;
memcpy(_data, source, size);
}
int FontResource::getHeight() const {
return _data[0];
}
int FontResource::getCharWidth(uint c) const {
byte *charData = getCharData(c);
if (charData)
return charData[0];
else
return 0;
}
byte *FontResource::getChar(uint c) const {
byte *charData = getCharData(c);
if (charData)
return charData + 1;
else
return NULL;
}
int FontResource::getTextWidth(const char *text) {
int width = 0;
if (text) {
int len = strlen(text);
for (int pos = 0; pos < len; pos++)
width += getCharWidth(text[pos]);
}
return width;
}
byte *FontResource::getCharData(uint c) const {
if (c < 28 || c > 255)
return NULL;
return _data + 1 + (c - 28) * (getHeight() + 1);
}
/* GenericResource */
GenericResource::GenericResource() : _data(NULL), _size(0) {
}
GenericResource::~GenericResource() {
if (_data)
delete[] _data;
}
void GenericResource::load(byte *source, int size) {
_data = new byte[size];
_size = size;
memcpy(_data, source, size);
}
/* ProjectReader */
ProjectReader::ProjectReader() {
}
ProjectReader::~ProjectReader() {
}
void ProjectReader::open(const char *filename) {
_fd = new Common::File();
_fd->open(filename);
_fd->skip(0x18); // skip header for now
uint16 indexCount = _fd->readUint16LE();
for (uint16 i = 0; i < indexCount; i++) {
uint32 resType = _fd->readUint32BE();
uint32 indexOffs = _fd->readUint32LE();
_fd->readUint32LE();
_fd->readUint32LE();
_fd->readUint32LE();
_fd->readUint16LE();
_fd->readUint16LE();
// We don't need ARCH, FREE and OMNI resources
if (resType == kResARCH || resType == kResFREE || resType == kResOMNI)
continue;
//debug(2, "resType = %08X; indexOffs = %d\n", resType, indexOffs);
uint32 oldOffs = _fd->pos();
ResourceSlots *resSlots = new ResourceSlots();
_fd->seek(indexOffs);
loadIndex(resSlots);
_resSlots[resType] = resSlots;
_fd->seek(oldOffs);
}
_cacheCount = 0;
}
PictureResource *ProjectReader::getPicture(int index) {
return createResource<PictureResource>(kResFLEX, index);
}
AnimationResource *ProjectReader::getAnimation(int index) {
return createResource<AnimationResource>(kResANIM, index);
}
SoundResource *ProjectReader::getSound(int index) {
return createResource<SoundResource>(kResSNDS, index);
}
MenuResource *ProjectReader::getMenu(int index) {
return createResource<MenuResource>(kResMENU, index);
}
FontResource *ProjectReader::getFont(int index) {
return createResource<FontResource>(kResFONT, index);
}
GenericResource *ProjectReader::getXmidi(int index) {
return createResource<GenericResource>(kResXMID, index);
}
GenericResource *ProjectReader::getMidi(int index) {
return createResource<GenericResource>(kResMIDI, index);
}
void ProjectReader::loadIndex(ResourceSlots *slots) {
_fd->readUint32LE(); // skip INDX
_fd->readUint32LE(); // skip index size
_fd->readUint32LE(); // skip unknown
_fd->readUint32LE(); // skip res type
uint16 count = _fd->readUint16LE();
_fd->readUint16LE(); // skip unknown count
_fd->readUint16LE(); // skip unknown count
for (uint16 i = 0; i < count; i++) {
uint32 offs = _fd->readUint32LE();
uint32 size = _fd->readUint32LE();
slots->push_back(ResourceSlot(offs, size));
}
}
void ProjectReader::freeResource(Resource *resource) {
tossResourceFromCache(resource->slot);
}
bool ProjectReader::loadResource(ResourceSlot *slot, byte *&buffer, uint32 &size) {
if (slot && slot->size > 0) {
size = slot->size - 62;
buffer = new byte[size];
debug(2, "ProjectReader::loadResource() %08X\n", slot->offs + 62); fflush(stdout);
_fd->seek(slot->offs + 62);
_fd->read(buffer, size);
return true;
} else {
return false;
}
}
ResourceSlot *ProjectReader::getResourceSlot(uint32 resType, uint index) {
ResourceSlots *slots = _resSlots[resType];
if (index >= 1 && index < slots->size()) {
ResourceSlot *slot = &slots->operator[](index);
return slot;
} else {
return NULL;
}
}
Resource *ProjectReader::getResourceFromCache(ResourceSlot *slot) {
if (slot->res)
slot->refCount++;
return slot->res;
}
void ProjectReader::addResourceToCache(ResourceSlot *slot, Resource *res) {
if (_cacheCount >= kMaxResourceCacheCount) {
purgeCache();
}
slot->res = res;
slot->refCount = 0;
_cacheCount++;
}
void ProjectReader::tossResourceFromCache(ResourceSlot *slot) {
if (slot->res) {
slot->refCount--;
}
}
void ProjectReader::purgeCache() {
printf("ProjectReader::purgeCache()\n");
for (ResMap::const_iterator resTypeIter = _resSlots.begin(); resTypeIter != _resSlots.end(); ++resTypeIter) {
ResourceSlots *slots = (*resTypeIter)._value;
for (ResourceSlots::iterator slotIter = slots->begin(); slotIter != slots->end(); ++slotIter) {
ResourceSlot *slot = &(*slotIter);
if (slot->refCount <= 0 && slot->res) {
delete slot->res;
slot->res = NULL;
slot->refCount = 0;
_cacheCount--;
}
}
}
}
} // End of namespace Made