git » fp-git.git » commit bf66e74

added from PR code

author ecalot
2004-06-20 16:36:42 UTC
committer ecalot
2004-06-20 16:36:42 UTC
parent 518baa8fd44f1e268a94727451f0a0f28728a6d8

added from PR code

FP/src/res/compress.c +329 -0

diff --git a/FP/src/res/compress.c b/FP/src/res/compress.c
new file mode 100644
index 0000000..4f45131
--- /dev/null
+++ b/FP/src/res/compress.c
@@ -0,0 +1,329 @@
+/*  Princed V3 - Prince of Persia Level Editor for PC Version
+    Copyright (C) 2003 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
+*/
+
+/*
+compress.c: Princed Resources : Image Compression Library
+\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf
+ 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: 2.00 (2004-Mar-07)
+
+ Note:
+  DO NOT remove this copyright notice
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "compress.h"
+#include "memory.h"
+//#include "pr.h"
+#include "disk.h" /* array2short */
+
+/***************************************************************\
+|                  I M P L E M E N T A T I O N                  |
+\***************************************************************/
+
+/***************************************************************\
+|                        Image transpose                        |
+\***************************************************************/
+
+/* Determines where the transposed byte must be saved */
+int transpose(int x,int w,int h) {
+	return ((x%h)*(w))+(int)(x/h);
+}
+
+void transposeImage(tImage* image,int size) {
+	unsigned char* outputaux=getMemory(size);
+	int cursor=0;
+
+	while (cursor<size) {outputaux[transpose(cursor,image->widthInBytes,image->height)]=image->pix[cursor];cursor++;}
+	free(image->pix);
+	image->pix=outputaux;
+}
+
+void antiTransposeImage(tImage* image,int size) {
+	unsigned char* outputaux=getMemory(size);
+	int cursor=0;
+
+	while (cursor<size) {outputaux[cursor]=image->pix[transpose(cursor,image->widthInBytes,image->height)];cursor++;}
+	free(image->pix);
+	image->pix=outputaux;
+}
+
+/***************************************************************\
+|                    Uncompression algorithms                   |
+\***************************************************************/
+
+/* LZG expansion algorithm sub function */
+unsigned char popBit(unsigned char *byte) {
+	unsigned char bit=(unsigned char)((*byte)&1);
+	(*byte)>>=1;
+	return bit;
+}
+
+/* Expands LZ Groody algorithm. This is the core of PR */
+int expandLzg(const unsigned char* array, int arraySize, tImage* image, int imageSize) {
+	char k;
+	int location,h,cursor=0,pos=0;
+	unsigned char maskbyte,rep;
+
+	if ((image->pix=getMemory(/*imageSize*/MAX_MOD_SIZE_IN_LZG))==NULL) return COMPRESS_RESULT_FATAL; /* reserve memory */
+	for(location=0;location<MAX_MOD_SIZE_IN_LZG;image->pix[location]=0,location++); /* clean output garbage */
+
+	/* main loop */
+	while (cursor<imageSize) {
+		maskbyte=array[pos++];
+		for (k=8;k&&(cursor<imageSize);k--) {
+			if (popBit(&maskbyte)) {
+				image->pix[cursor++]=array[pos++];
+			} else {
+				location=66+(((rep=array[pos])&3)<<8)+(unsigned char)array[pos+1];pos+=2;
+				rep=(unsigned char)((rep>>2)+3);
+				while (rep--) { /* Be careful in big images */
+					h=cursor/MAX_MXD_SIZE_IN_LZG-((location%MAX_MXD_SIZE_IN_LZG)>(cursor%MAX_MXD_SIZE_IN_LZG));
+					image->pix[cursor++]=image->pix[((h<0)?0:h)*MAX_MXD_SIZE_IN_LZG+(location++)%MAX_MXD_SIZE_IN_LZG];
+/*
+					h=((cursor-(location&0x3FF))&(~0x3FF));
+					image->pix[cursor]=image->pix[((h<0)?0:h)+(location&0x3FF)];
+					cursor++;location++;
+*/
+				}
+			}
+		}
+	}
+	return ((pos==arraySize)&(cursor==imageSize))-1; /* WARNING or SUCCESS */
+}
+
+/* Expands RLE algorithm */
+int expandRle(const unsigned char* array, int arraySize, tImage* image, int imageSize) {
+	int cursor=0;
+	register signed char rep;
+	int pos=0;
+
+	if ((image->pix=getMemory(imageSize+128))==NULL) return COMPRESS_RESULT_FATAL; /* reserve memory */
+
+	/* main loop */
+	while (cursor<imageSize) {
+		rep=(signed char)(array[pos++]);
+		if (rep<0) {
+			/* Negative */
+			while (rep++) image->pix[cursor++]=array[pos];
+			pos++;
+		} else {
+			/* Positive */
+			rep=~rep;
+			while (rep++) image->pix[cursor++]=array[pos++];
+		}
+	}
+	return ((pos==arraySize)&(cursor==imageSize))-1; /* WARNING or SUCCESS */
+}
+
+/***************************************************************\
+|                    Compression algorithms                     |
+\***************************************************************/
+
+/* Compress using the Run Length Encoding algorithm */
+void compressRle(unsigned char* data,tImage* img,int *dataSize) {
+	/* Declare pointers */
+	unsigned char* cursorData  = data;
+	char*          counter;
+	unsigned char* cursorPix   = img->pix;
+	unsigned char* imgEnd      = img->pix+(*dataSize);
+
+	while (cursorPix<imgEnd) {
+		/* Step 1: Create counter */
+		*(counter=(char*)(cursorData++))=-1;
+
+		/* Step 2: Look and copy the string until a repeated byte is found */
+		while (
+			(cursorPix<imgEnd)&&
+			(
+				(*cursorPix!=*(cursorPix+1))||
+				(
+					/*(*cursorPix==*(cursorPix+1))&&*/
+					((cursorPix+1)<imgEnd)&&
+					(*cursorPix!=*(cursorPix+2))
+				)
+			)&&
+			((*counter)!=127)
+		) {
+			*(cursorData)=*(cursorPix);
+			(*counter)++;
+			cursorPix++;
+			cursorData++;
+		}
+
+		/* Step 3: If there was a repeated string, let's ignore it and add the cursor with the repetitions */
+		if (*counter==-1) {
+			while ((cursorPix+1<imgEnd)&&(*cursorPix==(*(cursorPix+1)))&&((*counter)!=-128)) {
+				cursorPix++;
+				(*counter)--;
+			}
+
+			*(cursorData)=*(cursorPix); /* Print repeated char */
+			cursorPix++;
+			cursorData++;
+		}
+	}
+
+	*(cursorData++)=0;
+	*(cursorData)=*(cursorPix);
+	*dataSize=(int)((long int)cursorData-(long int)data)-1; /* Note: casted to long for portability with 64 bits architectures */
+}
+
+/***************************************************************\
+|               Main compress and expand graphics               |
+\***************************************************************/
+
+/*
+		Header info:
+		 1 byte  - checksum           char checksum
+		 2 bytes - height             short int height
+		 2 bytes - width              short int width
+		 1 byte  - 00                 (char)0
+		 1 byte  - compression type   unsigned char compressionType
+*/
+
+/* Expands an array into an image */
+int mExpandGraphic(const unsigned char* data,tImage *image, int dataSizeInBytes) {
+	/*
+		Reads data and extracts tImage
+		returns the next image address or -1 in case of error
+	*/
+
+	int imageSizeInBytes;
+	int result;
+
+	data++;
+	image->height=array2short(data);//((unsigned char)data[0])+((unsigned char)data[1]<<8);data+=2;
+	data+=2;
+	image->width =array2short(data);//((unsigned char)data[0])+((unsigned char)data[1]<<8);data+=2;
+	data+=2;
+
+	if (*(data++)) return COMPRESS_RESULT_FATAL; /* Verify format */
+	image->type=(unsigned char)(*(data++));
+	dataSizeInBytes-=7;
+	if (image->type&0xB0) {
+		image->widthInBytes=(image->width+1)/2;
+	} else {
+		image->widthInBytes=(image->width+7)/8;
+	}
+	imageSizeInBytes=image->widthInBytes*image->height;
+
+	switch (getAlgor(image->type)) {
+		case COMPRESS_RAW: /* No Compression Algorithm */
+			if ((image->pix=getMemory(imageSizeInBytes))==NULL) return COMPRESS_RESULT_FATAL;
+			memcpy(image->pix,data,imageSizeInBytes);
+			result=COMPRESS_RESULT_SUCCESS;
+			break;
+		case COMPRESS_RLE_LR: /* RLE Left to Right Compression Algorithm */
+			result=expandRle(data,dataSizeInBytes,image,imageSizeInBytes);
+			break;
+		case COMPRESS_RLE_UD: /* RLE Up to Down Compression Algorithm */
+			result=expandRle(data,dataSizeInBytes,image,imageSizeInBytes);
+			if (result==COMPRESS_RESULT_FATAL) return COMPRESS_RESULT_FATAL;
+			transposeImage(image,imageSizeInBytes);
+			break;
+		case COMPRESS_LZG_LR: /* LZ Groody Left to Right Compression Algorithm */
+			result=expandLzg(data,dataSizeInBytes,image,imageSizeInBytes);
+			break;
+		case COMPRESS_LZG_UD: /* LZ Groody Up to Down Compression Algorithm */
+			result=expandLzg(data,dataSizeInBytes,image,imageSizeInBytes);
+			if (result==COMPRESS_RESULT_FATAL) return COMPRESS_RESULT_FATAL;
+			transposeImage(image,imageSizeInBytes);
+			break;
+		default:
+			result=COMPRESS_RESULT_FATAL;
+			break;
+	}
+	return result; /* Ok */
+}
+
+/* Compress an image into binary data */
+int mCompressGraphic(unsigned char* *data,tImage* image, int* dataSizeInBytes) {
+	/* Declare variables */
+	unsigned char* compressed     [COMPRESS_WORKING_ALGORITHMS];
+	int            compressedSize [COMPRESS_WORKING_ALGORITHMS];
+	int            algorithm;
+	int            i;
+	int            imageSizeInBytes;
+
+	/* Initialize variables */
+	imageSizeInBytes=image->widthInBytes*image->height;
+	for (i=0;i<COMPRESS_WORKING_ALGORITHMS;i++) compressedSize[i]=imageSizeInBytes;
+
+	/*
+		Perform all compressions
+	*/
+
+	/* COMPRESS_RAW */
+	compressed[COMPRESS_RAW]=getMemory(compressedSize[COMPRESS_RAW]);
+	memcpy(compressed[COMPRESS_RAW],image->pix,compressedSize[COMPRESS_RAW]);
+
+	/* COMPRESS_RLE_LR */
+	compressed[COMPRESS_RLE_LR]=getMemory((10*imageSizeInBytes+50)); /* This will reserve 10*(image size)+50 bytes, to allocate the compressed file */
+	compressRle(compressed[COMPRESS_RLE_LR],image,&(compressedSize[COMPRESS_RLE_LR]));
+
+	/* COMPRESS_RLE_UD */
+	compressed[COMPRESS_RLE_UD]=getMemory(10*imageSizeInBytes+50); /* This will reserve 10*(image size)+50 bytes, to allocate the compressed file */
+	antiTransposeImage(image,imageSizeInBytes);
+	compressRle(compressed[COMPRESS_RLE_UD],image,&(compressedSize[COMPRESS_RLE_UD]));
+
+	/*
+		Process results
+	*/
+
+	/* Select the best compression (find minimum) */
+	*dataSizeInBytes=compressedSize[COMPRESS_RAW];
+	algorithm=COMPRESS_RAW;
+	for (i=COMPRESS_RLE_LR;i<COMPRESS_WORKING_ALGORITHMS;i++) {
+		if ((*dataSizeInBytes)>compressedSize[i]) {
+			(*dataSizeInBytes)=compressedSize[i];
+			algorithm=i;
+		}
+	}
+
+	/* Copy the best algorithm in the compressed data */
+	*data=getMemory(*dataSizeInBytes+6);
+	memcpy(*data+6,compressed[algorithm],*dataSizeInBytes);
+	(*dataSizeInBytes)+=6;
+
+	/*
+		Write header
+	*/
+
+	/* (16 bits)height (Intel short int format) */
+	(*data)[0]=image->height;
+	(*data)[1]=image->height>>8;
+	/* (16 bits)width (Intel short int format) */
+	(*data)[2]=image->width;
+	(*data)[3]=image->width>>8;
+	/* (8 bits)00000000+(4 bits)palette type+(4 bits)algorithm */
+	(*data)[4]=0;
+	(*data)[5]=image->type|algorithm;
+
+	/* Free all compression attempts */
+	for (i=COMPRESS_RAW;i<COMPRESS_WORKING_ALGORITHMS;i++) free(compressed[i]);
+	return 1;
+}
+