1 #include "SpriteFile.h"
5 static int alloc_sprite_index(SpriteFile
*si
, int nsprites
) {
6 si
->offsets
= calloc(4, nsprites
);
10 static void *readfunc_n(unsigned char *in
, unsigned *out
, int bpp
)
15 *out
|= (*(in
++) << 24); /*fall-through*/
17 *out
|= (*(in
++) << 16); /*fall-through*/
19 *out
|= (*(in
++) << 8); /*fall-through*/
21 *out
|= (*(in
++) << 0); /*fall-through*/
26 static void writefunc_n(unsigned char *out
, int n
, unsigned value
, int bpp
)
32 out
[i
++] = (value
& 0xff000000) >> 24; /*fall-through*/
34 out
[i
++] = (value
& 0xff0000) >> 16; /*fall-through*/
36 out
[i
++] = (value
& 0xff00) >> 8; /*fall-through*/
38 out
[i
++] = (value
& 0xff) >> 0; /*fall-through*/
42 static char* unpackl(signed char *out
, signed char *in
, int size
, int bpp
)
46 signed char c
= *(in
++);
51 in
= readfunc_n(in
, &val
, bpp
);
53 if (n
>= size
) return 0;
54 writefunc_n(out
, n
++, val
, bpp
);
59 if (n
>= size
) return 0;
60 in
= readfunc_n(in
, &val
, bpp
);
61 writefunc_n(out
, n
++, val
, bpp
);
68 static int ags_unpack(ImageData
*d
) {
70 unsigned outsize
= d
->width
*d
->height
*d
->bytesperpixel
;
71 unsigned char *out
= malloc(outsize
), *p
= d
->data
, *q
= out
;
73 for(y
= 0; y
< d
->height
; ++y
, q
+=d
->width
*d
->bytesperpixel
) {
74 p
= unpackl(q
, p
, d
->width
, d
->bytesperpixel
);
78 d
->data_size
= outsize
;
82 static unsigned readfunc_p(unsigned char *in
, int n
, int bpp
)
88 out
|= (*(in
++) << 24); /*fall-through*/
90 out
|= (*(in
++) << 16); /*fall-through*/
92 out
|= (*(in
++) << 8); /*fall-through*/
94 out
|= (*(in
++) << 0); /*fall-through*/
99 static void* writefunc_p(unsigned char *out
, unsigned value
, int bpp
)
103 *(out
++) = (value
& 0xff000000) >> 24; /*fall-through*/
105 *(out
++) = (value
& 0xff0000) >> 16; /*fall-through*/
107 *(out
++) = (value
& 0xff00) >> 8; /*fall-through*/
109 *(out
++) = (value
& 0xff) >> 0; /*fall-through*/
115 static char* packl(unsigned char *out
, unsigned char *in
, int size
, int bpp
)
120 int i
= n
, j
= n
+ 1, jmax
= j
+ 126;
121 if (jmax
>= size
) jmax
= size
- 1;
123 col
= readfunc_p(in
, n
++, bpp
);
124 out
= writefunc_p(out
, 0, 1);
125 out
= writefunc_p(out
, col
, bpp
);
126 } else if(readfunc_p(in
, i
, bpp
) == readfunc_p(in
, j
, bpp
)) {
127 while((j
< jmax
) && (readfunc_p(in
, j
, bpp
) == readfunc_p(in
, j
+ 1, bpp
))) ++j
;
128 col
= readfunc_p(in
, i
, bpp
);
129 out
= writefunc_p(out
, i
-j
, 1);
130 out
= writefunc_p(out
, col
, bpp
);
133 while ((j
< jmax
) && (readfunc_p(in
, j
, bpp
) != readfunc_p(in
, j
+ 1, bpp
))) ++j
;
135 out
= writefunc_p(out
, c
++, 1);
136 memcpy(out
, in
+i
*bpp
, c
*bpp
);
144 static int ags_pack(ImageData
*d
) {
145 /* ags has no code for 24bit images :( */
146 assert(d
->bytesperpixel
!= 3 && d
->bytesperpixel
<= 4);
148 /* worst case length: entire file consisting of sequences of 2
149 identical, and one different pixel, resulting in
150 1 byte flag + 1 pixel + 1 byte flag + 1 pixel. in the case of
151 8 bit, that's 1 byte overhead every 3 pixels.
152 since this compression is linebased, additional overhead of
153 1color/line is accounted for.
155 unsigned outsize
= d
->width
*d
->height
*d
->bytesperpixel
;
156 outsize
+= 1 + (outsize
/d
->bytesperpixel
/3) + (d
->height
*d
->bytesperpixel
);
157 unsigned char *out
= malloc(outsize
), *p
= d
->data
, *q
= out
;
160 for(y
= 0; y
< d
->height
; ++y
, p
+=d
->width
*d
->bytesperpixel
) {
161 unsigned char *next
= packl(q
, p
, d
->width
, d
->bytesperpixel
);
162 outsize
+= (next
- q
);
167 d
->data_size
= outsize
;
171 int SpriteFile_extract(AF
* f
, SpriteFile
*sf
, int spriteno
, ImageData
*data
) {
172 if(spriteno
>= sf
->num_sprites
+1) return 0;
173 if(sf
->offsets
[spriteno
] == 0) return 0;
174 AF_set_pos(f
, sf
->offsets
[spriteno
]);
175 data
->bytesperpixel
= AF_read_short(f
);
176 data
->width
= AF_read_short(f
);
177 data
->height
= AF_read_short(f
);
178 if(sf
->compressed
) data
->data_size
= AF_read_uint(f
);
179 else data
->data_size
= data
->bytesperpixel
* data
->width
* data
->height
;
180 data
->data
= malloc(data
->data_size
);
181 if(!data
->data
) return 0;
182 if(AF_read(f
, data
->data
, data
->data_size
) != data
->data_size
) {
188 if(sf
->compressed
&& !ags_unpack(data
)) goto oops
;
192 #include "endianness.h"
193 #define f_set_pos(F, P) fseeko(F, P, SEEK_SET)
194 #define f_get_pos(F) ftello(F)
195 #define f_write(F, P, L) fwrite(P, 1, L, F)
196 #define f_write_int(F, I) do { unsigned _x = end_htole32(I); f_write(F, &_x, 4); } while(0)
197 #define f_write_uint(F, I) f_write_int(F, I)
198 #define f_write_short(F, I) do { unsigned short _x = end_htole16(I); f_write(F, &_x, 2); } while(0)
199 #define f_write_ushort(F, I) f_write_short(F, I)
201 int SpriteFile_write_header(FILE *f
, SpriteFile
*sf
) {
202 f_write_short(f
, sf
->version
);
203 if(13 != f_write(f
, " Sprite File ", 13)) return 0;
204 switch(sf
->version
) {
205 /* override user-set compression setting,
206 if required by chosen format */
207 case 5: sf
->compressed
= 1; break;
208 case 4: sf
->compressed
= 0; break;
209 /* in case of version >= 6, set by caller*/
211 if(sf
->version
>= 6) {
212 if(1 != f_write(f
, "\0\1"+(!!sf
->compressed
), 1)) return 0;
213 f_write_int(f
, sf
->id
);
214 } else if (sf
->version
< 5) {
215 if(3*256 != f_write(f
, sf
->palette
, 3*256))
218 sf
->sc_off
= f_get_pos(f
);
219 f_write_ushort(f
, 0); /* number of sprites */
224 int SpriteFile_add(FILE *f
, SpriteFile
*sf
, ImageData
*data
) {
225 f_write_ushort(f
, data
->bytesperpixel
);
226 if(data
->bytesperpixel
) {
227 f_write_ushort(f
, data
->width
);
228 f_write_ushort(f
, data
->height
);
231 f_write_uint(f
, data
->data_size
);
233 f_write(f
, data
->data
, data
->data_size
);
239 int SpriteFile_finalize(FILE* f
, SpriteFile
*sf
) {
240 f_set_pos(f
, sf
->sc_off
);
241 f_write_ushort(f
, sf
->num_sprites
-1);
245 int SpriteFile_read(AF
* f
, SpriteFile
*sf
) {
247 sf
->version
= AF_read_short(f
);
249 ssize_t n
= AF_read(f
, buf
, 13);
250 if(n
!= 13) return 0;
251 if(memcmp(buf
, " Sprite File ", 13)) return 0;
253 if(sf
->version
< 4 || sf
->version
> 6) return 0;
254 if(sf
->version
== 4) sf
->compressed
= 0;
255 else if(sf
->version
== 5) sf
->compressed
= 1;
256 else if(sf
->version
>= 6) {
258 sf
->compressed
= (buf
[0] == 1);
259 sf
->id
= AF_read_int(f
);
262 if(sf
->version
< 5) {
263 sf
->palette
= malloc(256*3);
264 AF_read(f
, sf
->palette
, 256*3);
265 } else sf
->palette
= 0;
267 sf
->num_sprites
= AF_read_ushort(f
);
268 if(sf
->version
< 4) sf
->num_sprites
= 200;
270 alloc_sprite_index(sf
, sf
->num_sprites
);
273 for(i
= 0; i
< sf
->num_sprites
; ++i
) {
274 sf
->offsets
[i
] = AF_get_pos(f
);
275 int coldep
= AF_read_short(f
);
280 int w
= AF_read_short(f
);
281 int h
= AF_read_short(f
);
282 unsigned sprite_data_size
;
283 if(sf
->compressed
) sprite_data_size
= AF_read_uint(f
);
284 else sprite_data_size
= coldep
* w
* h
;
285 AF_read_junk(f
, sprite_data_size
);
290 /* create sprindex.dat, use after SpriteFile_read() */
291 int SpriteFile_write_sprindex(AF
* f
, SpriteFile
*sf
, FILE *outf
)
293 unsigned short *h
= calloc(2, sf
->num_sprites
);
294 unsigned short *w
= calloc(2, sf
->num_sprites
);
295 f_write(outf
, "SPRINDEX", 8);
297 /* version, figure out when v1 is needed */
298 f_write_int(outf
, version
);
299 if(version
>= 2) f_write_int(outf
, sf
->id
);
300 f_write_uint(outf
, sf
->num_sprites
-1);
301 f_write_uint(outf
, sf
->num_sprites
);
303 for(i
=0; i
<sf
->num_sprites
;++i
) {
304 AF_set_pos(f
, sf
->offsets
[i
]);
305 int coldep
= AF_read_short(f
);
306 if(coldep
== 0) sf
->offsets
[i
] = 0;
308 w
[i
] = AF_read_short(f
);
309 h
[i
] = AF_read_short(f
);
312 for(i
=0; i
<sf
->num_sprites
;++i
)
313 f_write_short(outf
, w
[i
]);
314 for(i
=0; i
<sf
->num_sprites
;++i
)
315 f_write_short(outf
, h
[i
]);
316 for(i
=0; i
<sf
->num_sprites
;++i
)
317 f_write_uint(outf
, sf
->offsets
[i
]);