source: trunk/JPGPROC/source/gbmsrc/gbmspr.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 20.9 KB
Line 
1/*
2
3gbmspr.c - Archimedes Sprite from RiscOS Format support
4
5In Archimedes terminology, a sprite is a bitmap with an optional mask plane.
6
7Reads a sprite from file created by *ScreenSave or *SSave command.
8Will also write such a file containing a single sprite.
9
10Input options: index=# (default: 0)
11
12*/
13
14/*...sincludes:0:*/
15#include <stdio.h>
16#include <ctype.h>
17#include <stddef.h>
18#include <stdlib.h>
19#include <string.h>
20#include "gbm.h"
21#include "gbmhelp.h"
22
23/*...vgbm\46\h:0:*/
24/*...vgbmhelp\46\h:0:*/
25
26#ifndef min
27#define min(a,b) (((a)<(b))?(a):(b))
28#endif
29/*...e*/
30/*...suseful:0:*/
31#define low_byte(w) ((byte) ((w)&0x00ff) )
32#define high_byte(w) ((byte) (((w)&0xff00)>>8))
33#define make_word(a,b) (((word)a) + (((word)b) << 8))
34
35/*...sread_word:0:*/
36static BOOLEAN read_word(int fd, word *w)
37 {
38 byte low = 0, high = 0;
39
40 gbm_file_read(fd, (char *) &low, 1);
41 gbm_file_read(fd, (char *) &high, 1);
42 *w = (word) (low + ((word) high << 8));
43 return TRUE;
44 }
45/*...e*/
46/*...sread_dword:0:*/
47static BOOLEAN read_dword(int fd, dword *d)
48 {
49 word low, high;
50
51 read_word(fd, &low);
52 read_word(fd, &high);
53 *d = low + ((dword) high << 16);
54 return TRUE;
55 }
56/*...e*/
57/*...swrite_word:0:*/
58static BOOLEAN write_word(int fd, word w)
59 {
60 byte low = (byte) w;
61 byte high = (byte) (w >> 8);
62
63 return gbm_file_write(fd, &low, 1) == 1 && gbm_file_write(fd, &high, 1) == 1;
64 }
65/*...e*/
66/*...swrite_dword:0:*/
67static BOOLEAN write_dword(int fd, dword d)
68 {
69 return write_word(fd, (word) d) && write_word(fd, (word) (d >> 16));
70 }
71/*...e*/
72/*...e*/
73
74static GBMFT spr_gbmft =
75 {
76 "Sprite",
77 "Archimedes Sprite from RiscOS",
78 "SPR SPRITE",
79 GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|
80 GBM_FT_W1|GBM_FT_W4|GBM_FT_W8,
81 };
82
83#define GBM_ERR_SPR_FIRST ((GBM_ERR) 1400)
84#define GBM_ERR_SPR_MODE ((GBM_ERR) 1401)
85#define GBM_ERR_SPR_OFFSET ((GBM_ERR) 1402)
86#define GBM_ERR_SPR_PAL8 ((GBM_ERR) 1403)
87
88typedef struct
89 {
90 long pos_palette, pos_image, pos_mask;
91 dword bytes_per_line, first_bit, last_bit, actual_bpp;
92 } SPR_PRIV;
93
94/*...sbpp_of_mode\44\ mode_of_bpp:0:*/
95static int bpp_of_mode[] =
96 {
97 1, /* 0: 640x256 */
98 2, /* 1: 320x256 */
99 4, /* 2: 160x256 */
100 -1, /* 3: Text only */
101 1, /* 4: 320x256 */
102 2, /* 5: 160x256 */
103 2, /* 6: 160x256 */
104 -1, /* 7: Teletext */
105 2, /* 8: 640x256 */
106 4, /* 9: 320x256 */
107 8, /* 10: 160x256 */
108 2, /* 11: 640x250 */
109 4, /* 12: 640x256 */
110 8, /* 13: 320x256 */
111 4, /* 14: 640x250 */
112 8, /* 15: 640x256 */
113 4, /* 16: 1056x250 */
114 4, /* 17: 1056x256 */
115 1, /* 18: 640x512 multisync-monitor */
116 2, /* 19: 640x512 multisync-monitor */
117 4, /* 20: 640x512 multisync-monitor */
118 8, /* 21: 640x512 multisync-monitor */
119 -1, /* 22: ? */
120 1, /* 23: 1152x896 61.2Hz-hires-montor */
121 8, /* 24: 1056x256 */
122 1, /* 25: 640x480 multisync-or-60Hz-VGA-monitor */
123 2, /* 26: 640x480 multisync-or-60Hz-VGA-monitor */
124 4, /* 27: 640x480 multisync-or-60Hz-VGA-monitor */
125 8, /* 28: 640x480 multisync-or-60Hz-VGA-monitor */
126 };
127
128#define N_MODES 29
129
130/* Return highest resolution mode for given bits per pixel. */
131
132static int mode_of_bpp[] = { -1,23,-1,-1,17,-1,-1,-1,24 };
133/*...e*/
134/*...squick tables:0:*/
135/* These are to account for the reverse ordering of pixels in a scan line. */
136
137static byte nibble_swap[0x100] =
138 {
139 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,
140 0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,
141 0x01,0x11,0x21,0x31,0x41,0x51,0x61,0x71,
142 0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
143 0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
144 0x82,0x92,0xa2,0xb2,0xc2,0xd2,0xe2,0xf2,
145 0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x73,
146 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,
147 0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x74,
148 0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,
149 0x05,0x15,0x25,0x35,0x45,0x55,0x65,0x75,
150 0x85,0x95,0xa5,0xb5,0xc5,0xd5,0xe5,0xf5,
151 0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x76,
152 0x86,0x96,0xa6,0xb6,0xc6,0xd6,0xe6,0xf6,
153 0x07,0x17,0x27,0x37,0x47,0x57,0x67,0x77,
154 0x87,0x97,0xa7,0xb7,0xc7,0xd7,0xe7,0xf7,
155 0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78,
156 0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,
157 0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x79,
158 0x89,0x99,0xa9,0xb9,0xc9,0xd9,0xe9,0xf9,
159 0x0a,0x1a,0x2a,0x3a,0x4a,0x5a,0x6a,0x7a,
160 0x8a,0x9a,0xaa,0xba,0xca,0xda,0xea,0xfa,
161 0x0b,0x1b,0x2b,0x3b,0x4b,0x5b,0x6b,0x7b,
162 0x8b,0x9b,0xab,0xbb,0xcb,0xdb,0xeb,0xfb,
163 0x0c,0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,
164 0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,
165 0x0d,0x1d,0x2d,0x3d,0x4d,0x5d,0x6d,0x7d,
166 0x8d,0x9d,0xad,0xbd,0xcd,0xdd,0xed,0xfd,
167 0x0e,0x1e,0x2e,0x3e,0x4e,0x5e,0x6e,0x7e,
168 0x8e,0x9e,0xae,0xbe,0xce,0xde,0xee,0xfe,
169 0x0f,0x1f,0x2f,0x3f,0x4f,0x5f,0x6f,0x7f,
170 0x8f,0x9f,0xaf,0xbf,0xcf,0xdf,0xef,0xff,
171 };
172static byte bit_swap[0x100] =
173 {
174 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
175 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
176 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
177 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
178 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
179 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
180 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
181 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
182 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
183 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
184 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
185 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
186 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
187 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
188 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
189 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
190 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
191 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
192 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
193 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
194 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
195 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
196 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
197 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
198 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
199 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
200 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
201 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
202 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
203 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
204 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
205 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff,
206 };
207
208static byte pair_swap[0x10] =
209 {
210 0x00,0x10,0x20,0x30,0x01,0x11,0x21,0x31,
211 0x02,0x12,0x22,0x32,0x03,0x13,0x23,0x33,
212 };
213/*...e*/
214
215/*...sspr_qft:0:*/
216GBM_ERR spr_qft(GBMFT *gbmft)
217 {
218 *gbmft = spr_gbmft;
219 return GBM_ERR_OK;
220 }
221/*...e*/
222/*...sspr_rhdr:0:*/
223GBM_ERR spr_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
224 {
225 SPR_PRIV *priv = (SPR_PRIV *) gbm->priv;
226 const char *index;
227 int i;
228 dword num_sprites, offset_sprite, pos_sprite;
229 dword dword_w, scans_h, first_bit, last_bit, bits_per_line;
230 dword offset_image, offset_mask, mode;
231
232 fn=fn; /* Suppress 'unref arg' compiler warnings */
233
234 if ( (index = gbm_find_word_prefix(opt, "index=")) != NULL )
235 sscanf(index + 6, "%d", &i);
236 else
237 i = 0;
238
239 read_dword(fd, &num_sprites);
240 if ( (dword) i >= num_sprites )
241 return GBM_ERR_SPR_OFFSET;
242 read_dword(fd, &offset_sprite);
243 pos_sprite = gbm_file_lseek(fd, offset_sprite - 4L, SEEK_SET);
244
245 while ( i-- > 0 )
246 {
247 read_dword(fd, &offset_sprite);
248 pos_sprite = gbm_file_lseek(fd, pos_sprite + offset_sprite, SEEK_SET);
249 }
250
251 gbm_file_lseek(fd, 16, SEEK_CUR); /* Skip 4 byte next-ptr + 12 byte name */
252 read_dword(fd, &dword_w); /* Width in dwords - 1 */
253 read_dword(fd, &scans_h); /* Scan lines high - 1 */
254 read_dword(fd, &first_bit); /* First bit used (left end of row) */
255 read_dword(fd, &last_bit); /* Last bit used (right end of row) */
256 read_dword(fd, &offset_image); /* Offset of image data */
257 read_dword(fd, &offset_mask); /* Offset of mask plane or above if none */
258 read_dword(fd, &mode); /* Mode sprite defined in */
259
260 if ( first_bit & 7 )
261 return GBM_ERR_SPR_FIRST;
262 if ( mode >= N_MODES )
263 return GBM_ERR_SPR_MODE;
264 if ( (gbm->bpp = priv->actual_bpp = bpp_of_mode[mode]) == -1 )
265 return GBM_ERR_SPR_MODE;
266
267 gbm->h = (int) (scans_h+1);
268 if ( gbm->h < 0 || gbm->h > 10000 )
269 return GBM_ERR_BAD_SIZE;
270
271 if ( gbm->bpp == 2 )
272 gbm->bpp = 4;
273
274 bits_per_line = ((dword_w+1) * 32) - first_bit - (32 - (last_bit+1));
275 gbm->w = (int) (bits_per_line / priv->actual_bpp);
276 if ( gbm->w < 0 || gbm->w > 10000 )
277 return GBM_ERR_BAD_SIZE;
278
279 priv->pos_palette = gbm_file_lseek(fd, 0L, SEEK_CUR);
280 priv->pos_image = (long) pos_sprite + offset_image;
281 priv->pos_mask = (long) pos_sprite + offset_mask;
282 priv->bytes_per_line = (dword_w + 1) * 4;
283 priv->first_bit = first_bit;
284 priv->last_bit = last_bit;
285
286 return GBM_ERR_OK;
287 }
288/*...e*/
289/*...sspr_rpal:0:*/
290/*...sread_pal:0:*/
291/* Palette entry is 2 dwords, which are same if no flashing */
292/* We will simply use first dword in each case */
293
294static BOOLEAN read_pal(int fd, GBMRGB *gbmrgb)
295 {
296 byte pal[8];
297 if ( gbm_file_read(fd, pal, 8) != 8 )
298 return FALSE;
299 gbmrgb->r = pal[1];
300 gbmrgb->g = pal[2];
301 gbmrgb->b = pal[3];
302 return TRUE;
303 }
304/*...e*/
305
306/*...sgbmrgb_1bpp:0:*/
307/*
308I do not expect the palette to be missing from a file defined in a mode with 2
309colours because the Wimp uses 16 colours, and I am led to beleive it is the
310only thing that saves files without the palette. However, if I am wrong...
311*/
312
313static GBMRGB gbmrgb_1bpp[2] =
314 {
315 {0xff,0xff,0xff}, /* 0=White */
316 {0x00,0x00,0x00}, /* 1=black */
317 };
318/*...e*/
319/*...sgbmrgb_2bpp:0:*/
320/*
321I do not expect the palette to be missing from a file defined in a mode with 4
322colours because the Wimp uses 16 colours, and I am led to beleive it is the
323only thing that saves files without the palette. However, if I am wrong...
324*/
325
326static GBMRGB gbmrgb_2bpp[4] =
327 {
328 {0xff,0xff,0xff},
329 {0xaa,0xaa,0xaa},
330 {0x55,0x55,0x55},
331 {0x00,0x00,0x00},
332 };
333/*...e*/
334/*...sgbmrgb_4bpp:0:*/
335/*
336This is the default Wimp defined 16 colour palette.
337The exact r,g,b values are not known so some nice bold examples of each,
338according to their descriptions in the RiscOS books have been found manually.
339*/
340
341static GBMRGB gbmrgb_4bpp[16] =
342 {
343 {0xff,0xff,0xff}, /* 0=white */
344 {0xdb,0xdb,0xdb}, /* 1=grey */
345 {0xb6,0xb6,0xb6}, /* 2=grey */
346 {0x92,0x92,0x92}, /* 3=grey */
347 {0x6d,0x6d,0x6d}, /* 4=grey */
348 {0x49,0x49,0x49}, /* 5=grey */
349 {0x24,0x24,0x24}, /* 6=grey */
350 {0x00,0x00,0x00}, /* 7=black */
351 {0x00,0x00,0xff}, /* 8=dark blue */
352 {0xff,0xff,0x00}, /* 9=yellow */
353 {0x00,0xff,0x00}, /* a=green */
354 {0xff,0x00,0x00}, /* b=red */
355 {0xff,0xd8,0xd8}, /* c=cream */
356 {0x40,0x80,0x40}, /* d=army green */
357 {0xff,0x9c,0x00}, /* e=orange */
358 {0x00,0xb9,0xff}, /* f=light blue */
359 };
360/*...e*/
361/*...sexpand_0x10:0:*/
362/*
363The Archimedes does not have 0x100 palette registers, it has 0x10 VIDC registers.
364Given an 8 bit pixel :-
365 Bits 3-0 are bits 3-0 of palette index
366 Bit 4 overrides red bit 7
367 Bit 5 overrides green bit 6
368 Bit 6 overrides green bit 7
369 Bit 7 overrides blue bit 7
370So we duplicate the 0x10 values we have read, and make the others from them.
371*/
372
373static void expand_0x10(GBMRGB *gbmrgb)
374 {
375 int i, bank;
376
377 for ( bank = 0x10; bank < 0x100; bank += 0x10 )
378 {
379 byte override_r = ((bank & 0x10) << 3);
380 byte override_g = ((bank & 0x60) << 1);
381 byte override_b = (bank & 0x80) ;
382 for ( i = 0; i < 0x10; i++ )
383 {
384 gbmrgb[bank + i].r = ((gbmrgb[i].r & 0x7f) | override_r);
385 gbmrgb[bank + i].g = ((gbmrgb[i].g & 0x3f) | override_g);
386 gbmrgb[bank + i].b = ((gbmrgb[i].b & 0x7f) | override_b);
387 }
388 }
389 }
390/*...e*/
391/*...sexpand_0x40:0:*/
392/*
393The Archimedes does not have 0x100 palette registers, it has 0x10.
394Planning for the future, files can be written with 0x40 palette entries.
395Given an 8 bit pixel :-
396 Bits 5-0 are bits 5-0 of palette index
397 Bit 6 overrides green bit 7
398 Bit 7 overrides blue bit 7
399So we duplicate the 0x40 values we have read, and make the others from them.
400Now, although we have seen files with 0x40 entries, when you take the first
4010x10, and perform expand_0x10 on them, the result is the same as this routine.
402Clearly Acorn are looking forward to a day when the VIDC chip has 0x40
403registers.
404*/
405
406static void expand_0x40(GBMRGB *gbmrgb)
407 {
408 int i, bank;
409
410 for ( bank = 0; bank < 0x100; bank += 0x40 )
411 {
412 byte override_g = ((bank & 0x40) << 1);
413 byte override_b = (bank & 0x80) ;
414 for ( i = 0; i < 0x40; i++ )
415 {
416 gbmrgb[bank + i].r = gbmrgb[i].r;
417 gbmrgb[bank + i].g = ((gbmrgb[i].g & 0x7f) | override_g);
418 gbmrgb[bank + i].b = ((gbmrgb[i].b & 0x7f) | override_b);
419 }
420 }
421 }
422/*...e*/
423
424GBM_ERR spr_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
425 {
426 SPR_PRIV *priv = (SPR_PRIV *) gbm->priv;
427 int npal = (priv->pos_image - priv->pos_palette) / 8;
428
429 if ( npal == 0 )
430/*...sno palette in file\44\ use the default Wimp one:16:*/
431switch ( priv->actual_bpp )
432 {
433 case 1: memcpy(gbmrgb, gbmrgb_1bpp, sizeof(gbmrgb_1bpp)); break;
434 case 2: memcpy(gbmrgb, gbmrgb_2bpp, sizeof(gbmrgb_2bpp)); break;
435 case 4: memcpy(gbmrgb, gbmrgb_4bpp, sizeof(gbmrgb_4bpp)); break;
436 case 8:
437/*...sdefault palette:32:*/
438{
439int i;
440for ( i = 0; i < 0x10; i++ )
441 {
442 byte tint = ((i & 0x03) << 4);
443 gbmrgb[i].r = tint + ((i & 0x04) << 4);
444 gbmrgb[i].g = tint;
445 gbmrgb[i].b = tint + ((i & 0x08) << 3);
446 }
447expand_0x10(gbmrgb);
448}
449/*...e*/
450 break;
451 }
452
453/*...e*/
454 else
455/*...sread palette from disk:16:*/
456{
457int i;
458gbm_file_lseek(fd, priv->pos_palette, SEEK_SET);
459for ( i = 0; i < npal; i++ )
460 if ( !read_pal(fd, gbmrgb + i) )
461 return GBM_ERR_READ;
462
463if ( gbm->bpp == 8 )
464 /* Handle getting too few palette entries */
465 {
466 if ( npal == 0x40 )
467 expand_0x40(gbmrgb);
468 else if ( npal == 0x10 )
469 expand_0x10(gbmrgb);
470 else
471 return GBM_ERR_SPR_PAL8;
472 }
473}
474/*...e*/
475
476 return GBM_ERR_OK;
477 }
478/*...e*/
479/*...sspr_rdata:0:*/
480GBM_ERR spr_rdata(int fd, GBM *gbm, byte *data)
481 {
482 int stride = ((gbm->bpp * gbm->w + 31) / 32) * 4;
483 SPR_PRIV *priv = (SPR_PRIV *) gbm->priv;
484 int scan_stride = priv->bytes_per_line;
485 int scan_first = ((priv->first_bit) >> 3);
486 int scan_bytes, i, j;
487 byte *datal = data + (gbm->h - 1) * stride;
488
489 gbm_file_lseek(fd, priv->pos_image, SEEK_SET);
490
491 switch ( priv->actual_bpp )
492 {
493/*...s8 \45\ read mapped pixels:16:*/
494case 8:
495 scan_bytes = gbm->w;
496 for ( j = 0; j < gbm->h; j++, datal -= stride )
497 {
498 gbm_file_lseek(fd, priv->pos_image + j * scan_stride + scan_first, SEEK_SET);
499 if ( gbm_file_read(fd, datal, scan_bytes) != scan_bytes )
500 return GBM_ERR_READ;
501 }
502 break;
503/*...e*/
504/*...s4 \45\ read pixels\44\ nibble swapping:16:*/
505case 4:
506 scan_bytes = ((unsigned)(gbm->w + 1) >> 1);
507 for ( j = 0; j < gbm->h; j++, datal -= stride )
508 {
509 gbm_file_lseek(fd, priv->pos_image + j * scan_stride + scan_first, SEEK_SET);
510 if ( gbm_file_read(fd, datal, scan_bytes) != scan_bytes )
511 return GBM_ERR_READ;
512 for ( i = 0; i < scan_bytes; i++ )
513 datal[i] = nibble_swap[datal[i]];
514 }
515 break;
516/*...e*/
517/*...s2 \45\ read pixels\44\ bit\45\pair reversing and expanding:16:*/
518/*
519Data is coming in a 2bpp, but we don't actually support this.
520So we will expand the data to 4bpp as we read it.
521We will do this inline, by reading into the second half.
522*/
523
524case 2:
525 scan_bytes = ((unsigned)(gbm->w + 3) >> 2);
526 for ( j = 0; j < gbm->h; j++, datal -= stride )
527 {
528 gbm_file_lseek(fd, priv->pos_image + j * scan_stride + scan_first, SEEK_SET);
529 if ( gbm_file_read(fd, datal + scan_bytes, scan_bytes) != scan_bytes )
530 return GBM_ERR_READ;
531 for ( i = 0; i < scan_bytes; i++ )
532 {
533 datal[i * 2 ] = pair_swap[datal[scan_bytes + i] & 0x0f];
534 datal[i * 2 + 1] = pair_swap[datal[scan_bytes + i] >> 4 ];
535 }
536 }
537 break;
538/*...e*/
539/*...s1 \45\ read pixels\44\ bit reversing:16:*/
540case 1:
541 scan_bytes = ((unsigned)(gbm->w + 7) >> 3);
542 for ( j = 0; j < gbm->h; j++, datal -= stride )
543 {
544 gbm_file_lseek(fd, priv->pos_image + j * scan_stride + scan_first, SEEK_SET);
545 if ( gbm_file_read(fd, datal, scan_bytes) != scan_bytes )
546 return GBM_ERR_READ;
547 for ( i = 0; i < scan_bytes; i++ )
548 datal[i] = bit_swap[datal[i]];
549 }
550 break;
551/*...e*/
552 }
553
554 return GBM_ERR_OK;
555 }
556/*...e*/
557/*...sspr_w:0:*/
558/*
559We have a problem here for 256 colour modes.
560The 256 colours we are asked to write can be any colours and unrelated.
561There are only 16 VIDC palette registers, and the other 4 bits in an 8 bit
562byte override specific palette entry bits.
563We will ignore all but the top 4 bits of each colour component. ie: just 7-4.
564Therefore we will write a specifically fixed palette :-
565 Bits 1 to 0 will be bits 5 and 4 for all 3 guns.
566 Bit 2 will be red bit 6
567 Bit 3 will be blue bit 6
568 Bit 4 will be red bit 7
569 Bit 5 will be green bit 6
570 Bit 6 will be green bit 7
571 Bit 7 will be blue bit 7
572This is the default palette used by RiscOS.
573We will map all incoming palette entrys first, to give a quick lookup table.
574*/
575
576/*...swrite_pal:0:*/
577static BOOLEAN write_pal(int fd, GBMRGB gbmrgb)
578 {
579 byte pal[8];
580 int j;
581 pal[0] = pal[4] = 0x00;
582 pal[1] = pal[5] = (byte) (gbmrgb.r & 0xf0);
583 pal[2] = pal[6] = (byte) (gbmrgb.g & 0xf0);
584 pal[3] = pal[7] = (byte) (gbmrgb.b & 0xf0);
585 for ( j = 0; j < 8; j++ )
586 pal[j] += (pal[j] >> 4);
587 return gbm_file_write(fd, pal, 8) == 8;
588 }
589/*...e*/
590
591GBM_ERR spr_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
592 {
593 int stride = ((gbm->bpp * gbm->w + 31) / 32) * 4;
594 int i, j, npal = ( 1 << gbm->bpp );
595 dword dword_w, last_bit, offset_image, mode;
596 char name[12];
597 byte qpal[0x100], *buf;
598 BOOLEAN ok;
599
600 opt=opt; /* Suppress 'unref arg' warning */
601
602 if ( gbm->bpp == 24 )
603 return GBM_ERR_NOT_SUPP;
604
605 if ( npal == 0x100 )
606 npal = 0x10;
607
608 ok = write_dword(fd, 1); /* Number of sprites */
609 ok &= write_dword(fd, 12 + 4); /* Offset to sprite */
610 ok &= write_dword(fd, (12 + 44 + npal * 8 + stride * gbm->h) + 4);
611 /* Offset to free word (beyond sprites) */
612 ok &= write_dword(fd, 44 + npal * 8 + stride * gbm->h);
613
614/*...sbuild a name:8:*/
615/*
616We will use the supplied filename to build the name field.
617We will ignore the path part (if any present).
618Also we will chop of the file extension of .spr if present.
619(This change was by customer request).
620Also, map to lower case to keep RiscOS programs happy.
621This isn't documented, but appears to be the case.
622*/
623
624{
625const char *p = fn;
626char *q;
627if ( (q = strrchr(p, '\\')) != NULL )
628 p = q + 1;
629if ( (q = strrchr(p, '/')) != NULL )
630 p = q + 1;
631memset(name, 0, 12);
632strncpy(name, p, 11);
633if ( (q = strrchr(name, '.')) != NULL && gbm_same(q + 1, "spr", 4) )
634 memset(q, '\0', 4);
635for ( q = name; (q - name) < 12 && *q != '\0'; q++ )
636 *q = tolower(*q);
637}
638/*...e*/
639 ok &= ( gbm_file_write(fd, name, 12) == 12 );
640
641 dword_w = ((gbm->w * gbm->bpp + 31) / 32) - 1;
642 ok &= write_dword(fd, dword_w); /* Width in dwords - 1 */
643 ok &= write_dword(fd, gbm->h - 1); /* Scan lines high - 1 */
644 ok &= write_dword(fd, 0); /* First bit used (left end of row) */
645 last_bit = ((gbm->w * gbm->bpp - 1) & 0x1f);
646 ok &= write_dword(fd, last_bit); /* Last bit used (right end of row) */
647 offset_image = ( 44 + npal * 8 );
648 ok &= write_dword(fd, offset_image); /* Offset of image data */
649 ok &= write_dword(fd, offset_image); /* Offset of mask plane or above if none */
650 mode = mode_of_bpp[gbm->bpp];
651 ok &= write_dword(fd, mode); /* Mode sprite defined in */
652
653 if ( !ok )
654 return GBM_ERR_WRITE;
655
656 /* Write palette */
657
658 switch ( gbm->bpp )
659 {
660/*...s8 \45\ write RiscOS default palette\44\ and work out mapping:16:*/
661case 8:
662
663 /* Write the fixed RiscOS default palette */
664 for ( i = 0; i < 0x10; i++ )
665 {
666 GBMRGB gbmrgb_def;
667 byte tint = ((i & 0x03) << 4);
668 gbmrgb_def.r = tint + ((i & 0x04) << 4);
669 gbmrgb_def.g = tint;
670 gbmrgb_def.b = tint + ((i & 0x08) << 3);
671 if ( !write_pal(fd, gbmrgb_def) )
672 return GBM_ERR_WRITE;
673 }
674
675 /* Determine palette mapping */
676 for ( i = 0; i < 0x100; i++ )
677 {
678 byte r = gbmrgb[i].r;
679 byte g = gbmrgb[i].g;
680 byte b = gbmrgb[i].b;
681 byte k32 = ((((r & 0x30) + (g & 0x30) + (b & 0x30)) / 3) & 0x30);
682 qpal[i] = (b & 0x80U) +
683 ((g & 0xc0U) >> 1) +
684 ((r & 0x80U) >> 3) +
685 ((b & 0x40U) >> 3) +
686 ((r & 0x40U) >> 4) +
687 (k32 >> 4);
688 }
689 break;
690/*...e*/
691/*...s4\44\1 \45\ write 16 or 2 entry palette:16:*/
692case 4:
693case 1:
694 /* Write the palette */
695 for ( i = 0; i < (1 << gbm->bpp); i++ )
696 if ( !write_pal(fd, gbmrgb[i]) )
697 return GBM_ERR_WRITE;
698 break;
699/*...e*/
700 }
701
702 /* Write data */
703
704 if ( (buf = malloc((size_t) stride)) == NULL )
705 return GBM_ERR_MEM;
706 memset(buf, 0, stride);
707
708 data += (gbm->h - 1) * stride; /* Start at the top */
709 switch ( gbm->bpp )
710 {
711/*...s8 \45\ write mapped pixels\44\ funny order:16:*/
712case 8:
713 for ( j = 0; j < gbm->h; j++, data -= stride )
714 {
715 for ( i = 0; i < stride; i++ )
716 buf[i] = qpal[data[i]];
717 if ( gbm_file_write(fd, buf, stride) != stride )
718 {
719 free(buf);
720 return GBM_ERR_WRITE;
721 }
722 }
723 break;
724/*...e*/
725/*...s4 \45\ write pixels\44\ funny order:16:*/
726case 4:
727 for ( j = 0; j < gbm->h; j++, data -= stride )
728 {
729 for ( i = 0; i < stride; i++ )
730 buf[i] = nibble_swap[data[i]];
731 if ( gbm_file_write(fd, buf, stride) != stride )
732 {
733 free(buf);
734 return GBM_ERR_WRITE;
735 }
736 }
737 break;
738/*...e*/
739/*...s1 \45\ write pixels\44\ funny order:16:*/
740case 1:
741 for ( j = 0; j < gbm->h; j++, data -= stride )
742 {
743 for ( i = 0; i < stride; i++ )
744 buf[i] = bit_swap[data[i]];
745 if ( gbm_file_write(fd, buf, stride) != stride )
746 {
747 free(buf);
748 return GBM_ERR_WRITE;
749 }
750 }
751 break;
752/*...e*/
753 }
754
755 free(buf);
756
757 return GBM_ERR_OK;
758 }
759/*...e*/
760/*...sspr_err:0:*/
761const char *spr_err(GBM_ERR rc)
762 {
763 switch ( (int) rc )
764 {
765 case GBM_ERR_SPR_FIRST:
766 return "sprite has first bit that is not a multiple of 8";
767 case GBM_ERR_SPR_MODE:
768 return "sprite defined in unknown mode";
769 case GBM_ERR_SPR_OFFSET:
770 return "less sprites in file than index requested";
771 case GBM_ERR_SPR_PAL8:
772 return "8 bit file does not have 0, 16 or 64 palette entries in it";
773 }
774 return NULL;
775 }
776/*...e*/
Note: See TracBrowser for help on using the repository browser.