/* 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 "cruise/cruise_main.h" namespace Cruise { enum fileTypeEnum { type_UNK, type_SPL, type_SET, type_FNT }; int loadSingleFile; // TODO: Unify decodeGfxFormat1, decodeGfxFormat4 and decodeGfxFormat5 void decodeGfxFormat1(dataFileEntry *pCurrentFileEntry) { uint8 *buffer; uint8 *dataPtr = pCurrentFileEntry->subData.ptr; int spriteSize = pCurrentFileEntry->height * pCurrentFileEntry->width; int x = 0; buffer = (uint8 *) malloc(spriteSize); while (x < spriteSize) { uint8 c; uint16 p0; p0 = (dataPtr[0] << 8) | dataPtr[1]; /* decode planes */ for (c = 0; c < 16; c++) { buffer[x + c] = ((p0 >> 15) & 1); p0 <<= 1; } x += 16; dataPtr += 2; } pCurrentFileEntry->subData.ptr = buffer; } void decodeGfxFormat4(dataFileEntry *pCurrentFileEntry) { uint8 *buffer; uint8 *dataPtr = pCurrentFileEntry->subData.ptr; int spriteSize = pCurrentFileEntry->height * pCurrentFileEntry->width; int x = 0; buffer = (uint8 *) malloc(spriteSize); while (x < spriteSize) { uint8 c; uint16 p0; uint16 p1; uint16 p2; uint16 p3; p0 = (dataPtr[0] << 8) | dataPtr[1]; p1 = (dataPtr[2] << 8) | dataPtr[3]; p2 = (dataPtr[4] << 8) | dataPtr[5]; p3 = (dataPtr[6] << 8) | dataPtr[7]; /* decode planes */ for (c = 0; c < 16; c++) { buffer[x + c] = ((p0 >> 15) & 1) | ((p1 >> 14) & 2) | ((p2 >> 13) & 4) | ((p3 >> 12) & 8); p0 <<= 1; p1 <<= 1; p2 <<= 1; p3 <<= 1; } x += 16; dataPtr += 8; } pCurrentFileEntry->subData.ptr = buffer; } void decodeGfxFormat5(dataFileEntry *pCurrentFileEntry) { uint8 *buffer; uint8 *dataPtr = pCurrentFileEntry->subData.ptr; int spriteSize = pCurrentFileEntry->height * pCurrentFileEntry->widthInColumn; int x = 0; int range = pCurrentFileEntry->height * pCurrentFileEntry->width; buffer = (uint8 *) malloc(spriteSize); while (x < spriteSize) { uint8 c; uint16 p0; uint16 p1; uint16 p2; uint16 p3; uint16 p4; p0 = (dataPtr[0 + range * 0] << 8) | dataPtr[1 + range * 0]; p1 = (dataPtr[0 + range * 1] << 8) | dataPtr[1 + range * 1]; p2 = (dataPtr[0 + range * 2] << 8) | dataPtr[1 + range * 2]; p3 = (dataPtr[0 + range * 3] << 8) | dataPtr[1 + range * 3]; p4 = (dataPtr[0 + range * 4] << 8) | dataPtr[1 + range * 4]; /* decode planes */ for (c = 0; c < 16; c++) { buffer[x + c] = ((p0 >> 15) & 1) | ((p1 >> 14) & 2) | ((p2 >> 13) & 4) | ((p3 >> 12) & 8) | ((p4 >> 11) & 16); p0 <<= 1; p1 <<= 1; p2 <<= 1; p3 <<= 1; p4 <<= 1; } x += 16; dataPtr += 2; } pCurrentFileEntry->subData.ptr = buffer; } int updateResFileEntry(int height, int width, int entryNumber, int resType) { int div = 0; resetFileEntry(entryNumber); filesDatabase[entryNumber].subData.compression = 0; int maskSize = height * width; // for sprites: width * height if (resType == 4) { div = maskSize / 4; } else if (resType == 5) { width = (width * 8) / 5; } filesDatabase[entryNumber].subData.ptr = (uint8 *) mallocAndZero(maskSize + div); if (!filesDatabase[entryNumber].subData.ptr) return (-2); filesDatabase[entryNumber].widthInColumn = width; filesDatabase[entryNumber].subData.ptrMask = (uint8 *) mallocAndZero(maskSize); filesDatabase[entryNumber].width = width / 8; filesDatabase[entryNumber].resType = resType; filesDatabase[entryNumber].height = height; filesDatabase[entryNumber].subData.index = -1; return entryNumber; } int createResFileEntry(int width, int height, int resType) { int i; int entryNumber; int div = 0; int size; printf("Executing untested createResFileEntry!\n"); exit(1); for (i = 0; i < 257; i++) { if (!filesDatabase[i].subData.ptr) break; } if (i >= 257) { return (-19); } entryNumber = i; filesDatabase[entryNumber].subData.compression = 0; size = width * height; // for sprites: width * height if (resType == 4) { div = size / 4; } else if (resType == 5) { width = (width * 8) / 5; } filesDatabase[entryNumber].subData.ptr = (uint8 *) mallocAndZero(size + div); if (filesDatabase[entryNumber].subData.ptr) { return (-2); } filesDatabase[entryNumber].widthInColumn = width; filesDatabase[entryNumber].subData.ptrMask = filesDatabase[entryNumber].subData.ptr + size; filesDatabase[entryNumber].width = width / 8; filesDatabase[entryNumber].resType = resType; filesDatabase[entryNumber].height = height; filesDatabase[entryNumber].subData.index = -1; return entryNumber; } fileTypeEnum getFileType(const char *name) { char extentionBuffer[16]; fileTypeEnum newFileType = type_UNK; getFileExtention(name, extentionBuffer); if (!strcmp(extentionBuffer, ".SPL")) { newFileType = type_SPL; } else if (!strcmp(extentionBuffer, ".SET")) { newFileType = type_SET; } else if (!strcmp(extentionBuffer, ".FNT")) { newFileType = type_FNT; } ASSERT(newFileType != type_UNK); return newFileType; } int getNumMaxEntiresInSet(uint8 *ptr) { uint16 numEntries = *(uint16 *) (ptr + 4); flipShort(&numEntries); return numEntries; } int loadFile(const char* name, int idx, int destIdx) { uint8 *ptr = NULL; fileTypeEnum fileType; fileType = getFileType(name); loadFileSub1(&ptr, name, NULL); switch (fileType) { case type_SET: { int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr); if (idx > numMaxEntriesInSet) { return 0; // exit if limit is reached } return loadSetEntry(name, ptr, idx, destIdx ); break; } case type_FNT: { return loadFNTSub(ptr, idx); break; } case type_UNK: { break; } case type_SPL: { break; } } return -1; } int loadFileRange(const char *name, int startIdx, int currentEntryIdx, int numIdx) { uint8 *ptr = NULL; fileTypeEnum fileType; fileType = getFileType(name); loadFileSub1(&ptr, name, NULL); switch (fileType) { case type_SET: { int i; int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr); for (i = 0; i < numIdx; i++) { if ((startIdx + i) > numMaxEntriesInSet) { return 0; // exit if limit is reached } loadSetEntry(name, ptr, startIdx + i, currentEntryIdx + i ); } break; } case type_FNT: { loadFNTSub(ptr, startIdx); break; } case type_UNK: { break; } case type_SPL: { break; } } return 0; } int loadFullBundle(const char *name, int startIdx) { uint8 *ptr = NULL; fileTypeEnum fileType; fileType = getFileType(name); loadFileSub1(&ptr, name, NULL); switch (fileType) { case type_SET: { int i; int numMaxEntriesInSet; numMaxEntriesInSet = getNumMaxEntiresInSet(ptr); // get maximum number of sprites/animations in SET file for (i = 0; i < numMaxEntriesInSet; i++) { loadSetEntry(name, ptr, i, startIdx + i); } break; } case type_FNT: { loadFNTSub(ptr, startIdx); break; } case type_UNK: { break; } case type_SPL: { break; } } return 0; } int loadFNTSub(uint8 *ptr, int destIdx) { uint8 *ptr2 = ptr; uint8 *destPtr; int fileIndex; uint32 fontSize; ptr2 += 4; memcpy(&loadFileVar1, ptr2, 4); flipLong(&loadFileVar1); if (destIdx == -1) { fileIndex = createResFileEntry(loadFileVar1, 1, 1); } else { fileIndex = updateResFileEntry(loadFileVar1, 1, destIdx, 1); } destPtr = filesDatabase[fileIndex].subData.ptr; memcpy(destPtr, ptr2, loadFileVar1); memcpy(&fontSize, ptr2, 4); flipLong(&fontSize); if (destPtr != NULL) { int32 i; uint8 *currentPtr; destPtr = filesDatabase[fileIndex].subData.ptr; flipLong((int32 *) destPtr); flipLong((int32 *) (destPtr + 4)); flipGen(destPtr + 8, 6); currentPtr = destPtr + 14; for (i = 0; i < *(int16 *) (destPtr + 8); i++) { flipLong((int32 *) currentPtr); currentPtr += 4; flipGen(currentPtr, 8); currentPtr += 8; } } return 1; } int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry) { uint8 *ptr2; uint8 *ptr3; int offset; int sec = 0; uint16 numIdx; if (!strcmp((char*)ptr, "SEC")) { sec = 1; } ptr2 = ptr + 4; memcpy(&numIdx, ptr2, 2); flipShort(&numIdx); ptr3 = ptr + 6; offset = currentEntryIdx * 16; { uint8 *ptr4; int resourceSize; int fileIndex; setHeaderEntry localBuffer; uint8 *ptr5; ptr4 = ptr + offset + 6; memcpy(&localBuffer, ptr4, sizeof(setHeaderEntry)); flipLong((int32 *) & localBuffer.field_0); flipGen(&localBuffer.width, 12); if ((sec == 1) || (localBuffer.type == 5)) { localBuffer.width = localBuffer.width - (localBuffer.type * 2); // Type 1: Width - (1*2) , Type 5: Width - (5*2) } resourceSize = localBuffer.width * localBuffer.height; if (currentDestEntry == -1) { fileIndex = createResFileEntry(localBuffer.width, localBuffer.height, localBuffer.type); } else { fileIndex = updateResFileEntry(localBuffer.height, localBuffer.width, currentDestEntry, localBuffer.type); } if (fileIndex < 0) { return -1; // TODO: buffer is not freed } ptr5 = ptr3 + localBuffer.field_0 + numIdx * 16; memcpy(filesDatabase[fileIndex].subData.ptr, ptr5, resourceSize); ptr5 += resourceSize; switch (localBuffer.type) { case 0: { filesDatabase[fileIndex].subData.resourceType = 8; break; } case 1: { filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn * 8; filesDatabase[fileIndex].subData.resourceType = 2; decodeGfxFormat1(&filesDatabase[fileIndex]); filesDatabase[fileIndex].subData.index = currentDestEntry; filesDatabase[fileIndex].subData.transparency = localBuffer.transparency % 0x10; break; } case 4: { filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn * 2; filesDatabase[fileIndex].subData.resourceType = 4; decodeGfxFormat4(&filesDatabase[fileIndex]); filesDatabase[fileIndex].subData.index = currentDestEntry; filesDatabase[fileIndex].subData.transparency = localBuffer.transparency % 0x10; break; } case 5: { if (sec == 0) { // TODO sec type 5 needs special conversion. cut out 2 bytes at every width/5 position. // ASSERT(0); // return -1; } filesDatabase[fileIndex].subData.resourceType = 4; decodeGfxFormat5(&filesDatabase[fileIndex]); filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn; filesDatabase[fileIndex].subData.index = currentDestEntry; filesDatabase[fileIndex].subData.transparency = localBuffer.transparency; break; } case 8: { filesDatabase[fileIndex].subData.resourceType = 4; filesDatabase[fileIndex].width = filesDatabase[fileIndex].widthInColumn; filesDatabase[fileIndex].subData.index = currentDestEntry; filesDatabase[fileIndex].subData.transparency = localBuffer.transparency; break; } default: { printf("Unsuported gfx loading type: %d\n", localBuffer.type); break; } } strcpy(filesDatabase[fileIndex].subData.name, name); // create the mask switch(localBuffer.type) { case 1: case 4: case 5: case 8: { int maskX; int maskY; memset(filesDatabase[fileIndex].subData.ptrMask, 0, filesDatabase[fileIndex].width/8 * filesDatabase[fileIndex].height); for(maskY=0; maskY> (maskX&7); } } } break; } default: { } } } // TODO: free return 1; } } // End of namespace Cruise