/* FreePrince - POP1 remake
Copyright (C) 2003,2004 Princed Development Team
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
The authors of this program may be contacted at http://forum.princed.com.ar
*/
/*
resources.c: Princed Resources : DAT Extractor
�����������
Copyright 2003, 2004 Princed Development Team
Created: 24 Aug 2003
Author: Enrique Calot <ecalot.cod@princed.com.ar>
Version: 1.01 (2003-Oct-23)
Version: 1.20 (2004-Mar-07)
Version: 1.30 (2004-Mar-15)
Note:
DO NOT remove this copyright notice
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freeprince.h"
#include "resources.h"
#include "output.h"
#include "maps.h"
#include "compress.h"
#include "dat.h"
#include "disk.h"
/***************************************************************\
| I M P L E M E N T A T I O N |
\***************************************************************/
/*
* Resource creation
*/
/*
* Functions made to get data from the DAT files using some optimizations
*/
int res_getDataById(int id,int maxItems,tMemory* result) {
/* This function looks for a data resource in a dat file optimizing the search knowing
* that the id's starts in 0
*/
/* TODO: use static to remember where it is */
long int gotId;
int indexNumber;
/* main loop */
for (indexNumber=0;indexNumber<maxItems;indexNumber++) {
gotId=mReadFileInDatFile(
(indexNumber+id)%maxItems,
&(result->array),
(unsigned long *)&(result->size));
if (gotId==id) break;
}
/* Return value */
return (gotId==id); /* 1 if the id was found, 0 if not */
}
static const short res_list[]=RES_LIST;
static const char* res_file[]=RES_FILES;
void getOffsets(int *down, int *left, int *right, int from, int hasD, int hasL, int hasR,int total, int resource) {
const unsigned short* list;
short d,l,r;
int resourceInShorts=resource>>1;
total++;
total>>=1;
/* set the start of the list to the start od the offsets */
list=(const unsigned short*)(res_list+from-total*(hasD+hasL+hasR));
/* set the values */
if (hasD) {
d=list[resourceInShorts];
if (resource&1) {
*down=(d>>8)-64;
} else {
*down=(d&0xff)-64;
}
} else {
*down=0;
}
if (hasL) {
l=list[resourceInShorts+total*hasD];
if (resource&1) {
*left=(l>>8)-64;
} else {
*left=(l&0xff)-64;
}
} else {
*left=0;
}
if (hasR) {
r=list[resourceInShorts+total*(hasD+hasL)];
if (resource&1) {
*right=(r>>8)-64;
} else {
*right=(r&0xff)-64;
}
} else {
*right=0;
}
}
/**
* Public functions
* */
tData* resLoad(long id) {
/* Initialize abstract variables to read this new DAT file */
unsigned short int numberOfItems;
tData* result;
tMemory raw;
int mask=res_get_part_mods(id);
int total=res_get_part_size(id);
int from=res_get_part_from(id);
int type=res_get_part_type(id);
switch (type) {
case RES_TYPE_LVL:
if (total!=2) {
fprintf(stderr,"Fatal Error: resLoad: invalid level define!\n");
return NULL;
}
mask+=res_list[from+1];
if (!mReadBeginDatFile(&numberOfItems,res_file[res_list[from]])) {
fprintf(stderr,"Fatal Error: resLoad: level file not found!\n");
return NULL;
}
if(!res_getDataById(mask,numberOfItems,&raw)) {
fprintf(stderr,"Fatal Error: resLoad: level not found!\n");
return NULL;
}
result=(tData*)malloc(sizeof(tData));
result->frames=1; /* drop filename and palette */
result->type=eLevels;
result->pFrames=(void**)mapLoadLevel(raw);
mReadCloseDatFile();
return result; /* transform from raw to a loaded map */
case RES_TYPE_IMG: {
tMemory palette;
tImage image;
tPalette pal;
int has_D=((mask&RES_MODS_HAS_D)?1:0);
int has_L=((mask&RES_MODS_HAS_L)?1:0);
int has_R=((mask&RES_MODS_HAS_R)?1:0);
int down,left,right;
int invert=((mask&(RES_MODS_INVERT))==(RES_MODS_INVERT));
result=(tData*)malloc(sizeof(tData));
result->type=eImages;
if (!mReadBeginDatFile(&numberOfItems,res_file[res_list[from]])) {
fprintf(stderr,"Fatal Error: resLoad: level file not found!\n");
return NULL;
}
if (mask&RES_MODS_BW) { /* if black and white */
/* this palette is white, red, green, blue */
static const char bwpalettes[]=BW_COLORS;
static char bwpalette[]={0,0,0,0,0,0};
memcpy(bwpalette+3,bwpalettes+3*((mask>>5)&3),3);
pal.colors=2;
pal.color=(tColor*)bwpalette;
result->frames=total-1; /* drop filename */
} else {
from++;
if(!res_getDataById(res_list[from],numberOfItems,&palette)) {
fprintf(stderr,"Fatal Error: resLoad: palette not found!\n");
return NULL;
}
if (palette.size!=100) {
fprintf(stderr,"Fatal error: resLoad: invalid palette\n");
return NULL;
}
pal.colors=16;
pal.color=(tColor*)(palette.array+5);
result->frames=total-2; /* drop filename and palette */
}
from++;
result->pFrames=(void**)malloc(result->frames*sizeof(void*));
for (total=0;total<result->frames;total++) {
if(!res_getDataById(res_list[from+total],numberOfItems,&raw)) {
fprintf(stderr,"Fatal Error: resLoad: image not found!\n");
return NULL;
}
/* get the offsets to move the image */
if (pal.colors==16) {/* available only for 16 colors images */
getOffsets(&down,&left,&right,from-2,has_D,has_L,has_R,result->frames,total);
} else {
down=left=right=0;
}
/* expand raw image into an image structure */
mExpandGraphic(raw.array,&image,raw.size);
/* convert image structure into blittable output surfaces */
result->pFrames[total]=(void*)outputLoadBitmap(
image.pix,image.widthInBytes*image.height,pal,image.height,image.width,
invert,!(mask&RES_MODS_BW),down,invert?right:left
);
/* free intermediate image data */
free(image.pix);
}
mReadCloseDatFile();
return result;
}
}
return NULL; /* unknown type */
}
void resFree(tData* res) {
if (!res) return;
if (res->type==eImages) {
while (res->frames) { /* free all frames */
outputFreeBitmap(res->pFrames[--(res->frames)]);
}
free(res->pFrames); /* free the frame list */
} else if (res->type==eLevels) {
mapFreeLevel((tMap*)(res->pFrames)); /* free the map */
}
#ifdef RESOURCESDEBUG
fprintf(stderr,"ResFree activated\n");
#endif
free(res); /* free the resource structure */
}