10e34a16128c09ca11b945e5a2ba5aa3629d4296
[fp-git.git] / PR / src / lib / object / image / image256.c
1 /*  Princed V3 - Prince of Persia Level Editor for PC Version
2     Copyright (C) 2003 Princed Development Team
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18     The authors of this program may be contacted at http://forum.princed.com.ar
19 */
20
21 /*
22 compress.c: Princed Resources : Image Compressor
23 ¯¯¯¯¯¯¯¯¯¯
24  Copyright 2003 Princed Development Team
25   Created: 24 Aug 2003
26
27   Author: Enrique Calot <ecalot.cod@princed.com.ar>
28   Version: 1.01 (2003-Oct-23)
29
30  Note:
31   DO NOT remove this copyright notice
32 */
33
34 /***************************************************************\
35 |                  I M P L E M E N T A T I O N                  |
36 \***************************************************************/
37
38 #include <stdio.h>
39 #include <string.h>
40 #include "compress.h"
41 #include "memory.h"
42
43 //reserved memory for the Lzx algorithm
44 #define MAX_MOD_SIZE_IN_LZX 32001                     /* 38401 */
45 //modulus to be used in the 10 bits of the algorithm
46 #define MAX_MXD_SIZE_IN_LZX 0x400
47
48 /***************************************************************\
49 |                Compression algorithm handling                 |
50 \***************************************************************/
51
52 //Determines where the transposed byte must be saved
53 int transpose(int x,int n,int m) {
54         return ((x%m)*((n+1)/2))+(int)(x/m);
55 }
56
57 //B3 and B4 expansion algorithm sub function
58 unsigned char popBit(unsigned char *byte) {
59   unsigned char bit=(unsigned char)((*byte)&1);
60   (*byte)>>=1;
61   return bit;
62 }
63
64 //Expands B3/B4 algorithm
65 void expandLzx(unsigned /* note: if error remove signed */char* array,tImage* img, int *i,int cursor, int virtualSize) {
66         char k;
67         int pos,h;
68         unsigned char maskbyte,rep;
69
70         for(pos=0;pos<MAX_MXD_SIZE_IN_LZX;(*img).pix[pos]=0,pos++); //clean output garbage
71         while (cursor<virtualSize) {
72                 maskbyte=array[*i];(*i)++;
73                 for (k=8;k&&(cursor<virtualSize);k--) {
74                         if (popBit(&maskbyte)) {
75                                 (*img).pix[cursor]=array[*i];(*i)++;cursor++;
76                         } else {
77                                 pos=66+((0x100)*((rep=array[*i])&3))+(unsigned char)array[(*i)+1];(*i)+=2;
78                                 rep=(unsigned char)((rep>>2)+3);
79                                 while (rep--) { //Be careful in big images
80                                         h=cursor/MAX_MXD_SIZE_IN_LZX-(pos%MAX_MXD_SIZE_IN_LZX>cursor%MAX_MXD_SIZE_IN_LZX);
81                                         (*img).pix[cursor]=(*img).pix[((h<0)?0:h)*MAX_MXD_SIZE_IN_LZX+pos%MAX_MXD_SIZE_IN_LZX];cursor++;pos++;
82                                 }
83                         }
84                 }
85         }
86 }
87
88 //Compress B1/B2 algorithm
89 void compressRle(unsigned char* data,tImage* img,int *dataSize) {
90         //Declare pointers
91         unsigned char* cursorData  = data;
92         char*          counter;
93         unsigned char* cursorPix   = (*img).pix;
94         unsigned char* imgEnd      = (*img).pix+(*dataSize);
95
96         while (cursorPix<imgEnd) {
97                 //Step 1: Create counter
98                 *(counter=(char*)(cursorData++))=-1;
99
100                 //Step 2: Look and copy the string until a repeated byte is found
101                 while (
102                         (cursorPix<imgEnd)&&
103                         (
104                                 (*cursorPix!=*(cursorPix+1))||
105                                 (
106                                         (*cursorPix==*(cursorPix+1))&&
107                                         ((cursorPix+1)<imgEnd)&&
108                                         (*cursorPix!=*(cursorPix+2))
109                                 )
110                         )&&
111                         ((*counter)!=127)
112                 ) {
113                         *(cursorData)=*(cursorPix);
114                         (*counter)++;
115                         cursorPix++;
116                         cursorData++;
117                 }
118
119                 //Step 3: If there was a repeated string, let's ignore it and add the cursor with the repetitions
120                 if (*counter==-1) {
121                         while ((cursorPix<imgEnd)&&(*cursorPix==(*(cursorPix+1)))&&((*counter)!=-128)) {
122                                 cursorPix++;
123                                 (*counter)--;
124                         }
125
126                         *(cursorData)=*(cursorPix); //Print repeated char
127                         cursorPix++;
128                         cursorData++;
129                 }
130         }
131         *(cursorData++)=0;
132         *(cursorData++)=*(cursorPix);
133         *dataSize=(int)((long int)cursorData-(long int)data); //Note: casted to long for portability with 64 bits architectures
134 }
135
136 //Expands an array into an image
137 int mExpandGraphic(unsigned char* array,tImage *image, int virtualSize) {
138         /*
139                 Reads array and extracts tImage
140                 returns the next image address or -1 in case of error
141
142                 Header info:
143                  char checksum, short int height, short int width, (char)0, char compressionType
144                  normaly: (* ignored types)
145                  checksum* - height - 00 - width - 00 - 00* - compression type
146         */
147
148   int cursor=0;
149   int i=1;
150
151   //Get memory for the image
152         image->height=((unsigned char)array[(i)])+256*((unsigned char)array[(i+1)]) ;
153         i=i+2;
154         image->width =((unsigned char)array[(i)])+256*((unsigned char)array[(i+1)]);
155         i=i+2;
156         (*image).size  =(*image).height*(*image).width;
157         virtualSize=(((*image).height*((*image).width+((*image).width&1)))>>1);
158         i++;
159
160   switch ((unsigned char)array[i++]) {
161                 case PG_COMP_RAW: //No Compression Algorithm
162                   if (((*image).pix=getMemory(virtualSize))==NULL) return -1;
163                   while (cursor<virtualSize) {
164                                 (*image).pix[cursor++]=array[i++];
165                         }
166                         break;
167                 case PG_COMP_RLE_LR: //RLE Left to Right Compression Algorithm
168                   if (((*image).pix=getMemory(virtualSize))==NULL) return -1;
169                   while (cursor<virtualSize) {
170                                 if ((signed char)array[i]<0) {
171                                         //negative
172                                         while (array[i]++) (*image).pix[(cursor++)]=array[i+1];
173                                         i+=2;
174                                 } else {
175                                         //Positive
176                                         signed char cx=(signed char)(array[i++]+1);
177                                         while (cx--) (*image).pix[(cursor++)]=array[i++];
178                                 }
179                         }
180                         break;
181                 case PG_COMP_RLE_UD: //RLE Up to Down Compression Algorithm
182                   if (((*image).pix=getMemory(virtualSize))==NULL) return -1;
183                   while (cursor<virtualSize) {
184                                 if ((signed char)array[i]<0) {
185                                         //negative
186                                         while (array[i]++) (*image).pix[(transpose(cursor++,(*image).width,(*image).height))]=array[i+1];
187                                         i+=2;
188                                 } else {
189                                         //Positive
190                                         signed char cx=(signed char)(array[i++]+1);
191                                         while (cx--) (*image).pix[transpose(cursor++,(*image).width,(*image).height)]=array[i++];
192                                 }
193                         }
194                         break;
195                 case PG_COMP_LZX_LR: //LZ Groody Up to Down Version Compression Algorithm
196                   if (((*image).pix=getMemory(MAX_MOD_SIZE_IN_LZX))==NULL) return -1;
197                         expandLzx(array,image,&i,cursor,virtualSize);
198                         break;
199                 case PG_COMP_LZX_UD: //LZ Groody Left to Right Version Compression Algorithm
200                   if (((*image).pix=getMemory(MAX_MOD_SIZE_IN_LZX))==NULL) return -1;
201                         {
202                         unsigned char* outputaux=getMemory(virtualSize);
203                         expandLzx(array,image,&i,cursor,virtualSize);
204                         //Transpose
205                   while (cursor<virtualSize) outputaux[transpose(cursor,(*image).width,(*image).height)]=(*image).pix[cursor++];
206                         free((*image).pix);
207                         (*image).pix=outputaux;
208                         }
209                         break;
210                 default:
211                  return -1;
212         }
213         return i;
214 }
215
216 #define COMPRESS_WORKING_ALGORITHMS 3
217
218 //Compress an image into an array
219 int mCompressGraphic(unsigned char* data,tImage* i, int* size) {
220         //Declare variables
221         int            compressedSize [COMPRESS_WORKING_ALGORITHMS];
222         int            algorithm;
223         int            cursor;
224         int            virtualsize;
225         unsigned char* compressed     [COMPRESS_WORKING_ALGORITHMS];
226         unsigned char* outputaux;
227
228         //Initialize variables
229         virtualsize=(((i->width)+1)>>1)*i->height;
230         outputaux=getMemory(virtualsize);
231         for (cursor=0;cursor<COMPRESS_WORKING_ALGORITHMS;cursor++) compressedSize[cursor]=virtualsize;
232         cursor=0;
233
234         //B0
235         compressed[0]=getMemory(compressedSize[0]);
236         memcpy(compressed[0],i->pix,compressedSize[0]);
237
238         //B1
239         compressed[1]=getMemory(10*virtualsize+50); //This will reserve 10*(image size)+50 bytes, to allocate the compressed file
240         compressRle(compressed[1],i,&(compressedSize[1]));
241
242         //B2
243         compressed[2]=getMemory(10*virtualsize+50); //This will reserve 10*(image size)+50 bytes, to allocate the compressed file
244         //Transpose
245   while (cursor<=virtualsize) {
246                 outputaux[cursor]=i->pix[transpose(cursor,i->width,i->height)];
247                 cursor++;
248         }
249         free(i->pix);
250         i->pix=outputaux;
251         compressRle(compressed[2],i,&(compressedSize[2]));
252
253         /*Process results*/
254
255         //Select the best compression (find minimum)
256         *size=compressedSize[0];
257         algorithm=0;
258         for (cursor=1;cursor<3;cursor++) {
259                 if ((*size)>compressedSize[cursor]) {
260                         (*size)=compressedSize[cursor];
261                         algorithm=cursor;
262                 }
263         }
264
265         //Copy the best algorithm in the compressed data
266         memcpy(data+6,compressed[algorithm],*size);
267         (*size)+=6;
268
269         //Write header
270         //(16 bits)height (Intel short int format)
271         data[0]=i->height;
272         data[1]=i->height>>8;
273         //(16 bits)width (Intel short int format)
274         data[2]=i->width;
275         data[3]=i->width>>8;
276         //(12 bits)000000001011+(4 bits)algorithm
277         data[4]=0;
278         data[5]=0xB0+algorithm;
279
280         //Free all compression attempts
281         for (cursor=0;cursor<COMPRESS_WORKING_ALGORITHMS;cursor++) free(compressed[cursor]);
282
283         return 1;
284 }