1 /*
2 * Abuse - dark 2D side-scrolling platform game
3 * Copyright (c) 1995 Crack dot Com
4 * Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 * This software was released into the Public Domain. As with most public
7 * domain software, no warranty is made or implied by Crack dot Com, by
8 * Jonathan Clark, or by Sam Hocevar.
9 */
10
11 #if defined HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include "common.h"
16
17 #include "pcxread.h"
18 #include "specs.h"
19
20 enum PCX_type { not_PCX, PCX_8, PCX_24 };
21
22 struct PCX_header_type
23 {
24 char manufactururer,version,encoding,bits_per_pixel;
25 short xmin,ymin,xmax,ymax,hres,vres;
26 char palette[48];
27 char reserved,color_planes;
28 short bytes_per_line,palette_type;
29 char filter[58];
30 } PCX_header;
31
read_PCX_header(FILE * fp)32 int read_PCX_header(FILE *fp)
33 {
34 if (!fread(&PCX_header.manufactururer,1,1,fp)) return 0;
35 if (!fread(&PCX_header.version,1,1,fp)) return 0;
36 if (!fread(&PCX_header.encoding,1,1,fp)) return 0;
37 if (!fread(&PCX_header.bits_per_pixel,1,1,fp)) return 0;
38 PCX_header.xmin=read_uint16(fp);
39 PCX_header.ymin=read_uint16(fp);
40 PCX_header.xmax=read_uint16(fp);
41 PCX_header.ymax=read_uint16(fp);
42 PCX_header.hres=read_uint16(fp);
43 PCX_header.vres=read_uint16(fp);
44 if (!fread(PCX_header.palette,1,48,fp)) return 0;
45 if (!fread(&PCX_header.reserved,1,1,fp)) return 0;
46 if (!fread(&PCX_header.color_planes,1,1,fp)) return 0;
47 PCX_header.bytes_per_line=read_uint16(fp);
48 PCX_header.palette_type=read_uint16(fp);
49 if (!fread(PCX_header.filter,1,58,fp)) return 0;
50 return 1;
51 }
52
write_PCX_header(FILE * fp)53 int write_PCX_header(FILE *fp)
54 {
55 if (!fwrite(&PCX_header.manufactururer,1,1,fp)) return 0;
56 if (!fwrite(&PCX_header.version,1,1,fp)) return 0;
57 if (!fwrite(&PCX_header.encoding,1,1,fp)) return 0;
58 if (!fwrite(&PCX_header.bits_per_pixel,1,1,fp)) return 0;
59 write_uint16(fp,PCX_header.xmin);
60 write_uint16(fp,PCX_header.ymin);
61 write_uint16(fp,PCX_header.xmax);
62 write_uint16(fp,PCX_header.ymax);
63 write_uint16(fp,PCX_header.hres);
64 write_uint16(fp,PCX_header.vres);
65 if (!fwrite(PCX_header.palette,1,48,fp)) return 0;
66 if (!fwrite(&PCX_header.reserved,1,1,fp)) return 0;
67 if (!fwrite(&PCX_header.color_planes,1,1,fp)) return 0;
68 write_uint16(fp,PCX_header.bytes_per_line);
69 write_uint16(fp,PCX_header.palette_type);
70 if (!fwrite(PCX_header.filter,1,58,fp)) return 0;
71 return 1;
72 }
73
PCX_file_type(char const * filename)74 PCX_type PCX_file_type(char const *filename)
75 {
76 FILE *fp=fopen(filename,"rb");
77 if (!fp)
78 return not_PCX;
79
80 if (!read_PCX_header(fp))
81 {
82 fclose(fp);
83 return not_PCX;
84 }
85 fclose(fp);
86 if (PCX_header.manufactururer!=10)
87 return not_PCX;
88 if (PCX_header.color_planes==3 && PCX_header.bits_per_pixel==8)
89 return PCX_24;
90 else if (PCX_header.color_planes==1 && PCX_header.bits_per_pixel==8)
91 return PCX_8;
92 else return not_PCX;
93 }
94
read_PCX_line(FILE * fp,unsigned char * start,short skip,int width)95 void read_PCX_line(FILE *fp, unsigned char *start, short skip, int width)
96 {
97 int c,n=0,i;
98
99 do
100 {
101 c=fgetc(fp)&0xff;
102 if ((c&0xc0)==0xc0)
103 {
104 i=c&0x3f;
105 c=fgetc(fp);
106 while (i--)
107 {
108 *start=c;
109 start+=skip;
110 n++;
111 }
112 }
113 else
114 {
115 *start=c;
116 start+=skip;
117 n++;
118 }
119 } while (n<width);
120 }
121
read_PCX(char const * filename,palette * & pal)122 image *read_PCX(char const *filename, palette *&pal)
123 {
124 if (PCX_file_type(filename)!=PCX_8) return NULL;
125 FILE *fp=fopen(filename,"rb");
126 read_PCX_header(fp);
127
128 image *im=new image(vec2i(PCX_header.xmax-PCX_header.xmin+1,
129 PCX_header.ymax-PCX_header.ymin+1));
130 int y;
131 for (y=0;y<im->Size().y;y++)
132 read_PCX_line(fp,im->scan_line(y),1,PCX_header.bytes_per_line);
133 unsigned char palette_confirm;
134 if (!fread(&palette_confirm,1,1,fp) || palette_confirm!=12)
135 {
136 pal=new palette;
137 pal->defaults();
138 }
139 else
140 {
141 pal=new palette;
142 fread(pal->addr(),1,256*3,fp);
143 }
144 fclose(fp);
145 return im;
146 }
147
write_PCX(image * im,palette * pal,char const * filename)148 void write_PCX(image *im, palette *pal, char const *filename)
149 {
150 FILE *fp=fopen(filename,"wb");
151 if (!fp)
152 return ;
153
154 PCX_header.manufactururer=10;
155 PCX_header.version=5;
156 PCX_header.encoding=1;
157 PCX_header.bits_per_pixel=8;
158 PCX_header.xmin=0;
159 PCX_header.ymin=0;
160 PCX_header.xmax=im->Size().x-1;
161 PCX_header.ymax=im->Size().y-1;
162 PCX_header.hres=320;
163 PCX_header.vres=200;
164 PCX_header.reserved=0;
165 PCX_header.color_planes=1;
166 PCX_header.bytes_per_line=im->Size().x;
167 PCX_header.palette_type=0;
168 memset(PCX_header.filter,0,58);
169
170 if (!write_PCX_header(fp))
171 {
172 fclose(fp);
173 return;
174 }
175
176 int y,run_length,x;
177 unsigned char *sl,code;
178 for (y=0; y<im->Size().y; y++)
179 {
180 sl=im->scan_line(y);
181 for (x=0; x<im->Size().x; )
182 {
183 run_length=1;
184 while (x+run_length<im->Size().x && sl[x]==sl[x+run_length])
185 run_length++;
186 if (run_length==1 && sl[x]<64)
187 fputc(sl[x],fp);
188 else
189 {
190 if (run_length>=64)
191 run_length=63;
192 code=0xc0 | run_length;
193 fputc(code,fp);
194 fputc(sl[x],fp);
195
196 }
197 x+=run_length;
198
199 }
200 }
201 fputc(12,fp); // note that there is a palette attached
202 fwrite(pal->addr(),1,256*3,fp);
203 fclose(fp);
204 }
205
206