1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /* Grafx2 - The Ultimate 256-color bitmap paint program
4
5 Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6
7 Grafx2 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; version 2
10 of the License.
11
12 Grafx2 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20
21 ///@file miscfileformats.c
22 /// Formats that aren't fully saving, either because of palette restrictions or other things
23
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #ifdef _MSC_VER
29 #include <stdio.h>
30 #if _MSC_VER < 1900
31 #define snprintf _snprintf
32 #endif
33 #define strdup _strdup
34 #endif
35
36 #include "global.h"
37 #include "io.h"
38 #include "loadsave.h"
39 #include "loadsavefuncs.h"
40 #include "misc.h"
41 #include "struct.h"
42 #include "windows.h"
43 #include "oldies.h"
44 #include "fileformats.h"
45 #include "gfx2mem.h"
46 #include "gfx2log.h"
47
48 //////////////////////////////////// PAL ////////////////////////////////////
49 //
50
51 // -- Test wether a file is in PAL format --------------------------------
Test_PAL(T_IO_Context * context,FILE * file)52 void Test_PAL(T_IO_Context * context, FILE * file)
53 {
54 char buffer[32];
55 long file_size;
56
57 (void)context;
58 File_error = 1;
59
60 file_size = File_length_file(file);
61 // First check for GrafX2 legacy palette format. The simplest one, 768 bytes
62 // of RGB data. It is a raw dump of the T_Palette structure. There is no
63 // header at all, so we check for the file size.
64 if (file_size == sizeof(T_Palette))
65 File_error = 0;
66 else if (file_size > 8)
67 {
68 // Bigger (or smaller ?) files may be in other formats. These have an
69 // header, so look for it.
70 if (!Read_bytes(file, buffer, 8))
71 return;
72 if (strncmp(buffer,"JASC-PAL",8) == 0)
73 {
74 // JASC file format, used by Paint Shop Pro and GIMP. This is also the
75 // one used for saving, as it brings greater interoperability.
76 File_error = 0;
77 }
78 else if(strncmp(buffer,"RIFF", 4) == 0)
79 {
80 // Microsoft RIFF file
81 // This is a data container (similar to IFF). We only check the first
82 // chunk header, and give up if that's not a palette.
83 fseek(file, 8, SEEK_SET);
84 if (!Read_bytes(file, buffer, 8))
85 return;
86 if (strncmp(buffer, "PAL data", 8) == 0)
87 {
88 File_error = 0;
89 }
90 }
91 }
92 }
93
94 /// Test for GPL (Gimp Palette) file format
Test_GPL(T_IO_Context * context,FILE * file)95 void Test_GPL(T_IO_Context * context, FILE * file)
96 {
97 char buffer[16];
98 long file_size;
99
100 (void)context;
101 File_error = 1;
102
103 file_size = File_length_file(file);
104 if (file_size > 33) {
105 // minimum header length == 33
106 // "GIMP Palette" == 12
107 if (!Read_bytes(file, buffer, 12))
108 return;
109 if (strncmp(buffer,"GIMP Palette",12) == 0)
110 File_error = 0;
111 }
112 }
113
114 /// skip the padding before a space-padded field.
skip_padding(FILE * file,int max_chars)115 static int skip_padding(FILE *file, int max_chars)
116 {
117 byte b;
118 int chars_read = 0;
119
120 do {
121 if (chars_read == max_chars)
122 return chars_read; // eof
123 if (!Read_byte(file, &b))
124 return chars_read;
125 chars_read++;
126 } while (b == ' ');
127
128 fseek(file, -1, SEEK_CUR);
129 return chars_read;
130 }
131
132 /// Load GPL (Gimp Palette) file format
Load_GPL(T_IO_Context * context)133 void Load_GPL(T_IO_Context * context)
134 {
135 FILE *file;
136 char buffer[256];
137
138 File_error = 1;
139
140 file = Open_file_read(context);
141 if (file == NULL)
142 return;
143
144 if (!Read_byte_line(file, buffer, sizeof(buffer)))
145 return;
146
147 if (memcmp(buffer,"GIMP Palette",12) == 0)
148 {
149 int i, r, g, b, columns;
150 size_t len;
151 // Name: xxxxx
152 if (!Read_byte_line(file, buffer, sizeof(buffer)))
153 return;
154 len = strlen(buffer);
155 while (len > 0)
156 {
157 len--;
158 if (buffer[len] == '\r' || buffer[len] == '\n')
159 buffer[len] = '\0';
160 }
161 GFX2_Log(GFX2_DEBUG, "GPL %s\n", buffer);
162 if (0 == memcmp(buffer, "Name: ", 6))
163 snprintf(context->Comment, sizeof(context->Comment), "GPL: %s", buffer + 6);
164
165 // Columns: 16
166 if (fscanf(file, "Columns: %d", &columns) != 1)
167 return;
168 Read_byte_line(file, buffer, sizeof(buffer));
169 /// @todo set grafx2 columns setting to match.
170 // #<newline>
171
172 for (i = 0; i < 256; i++)
173 {
174 for (;;)
175 {
176 // skip comments
177 int c = getc(file);
178 if (c == '#')
179 {
180 if (!Read_byte_line(file, buffer, sizeof(buffer)))
181 return;
182 GFX2_Log(GFX2_DEBUG, "comment: %s", buffer);
183 }
184 else
185 {
186 fseek(file, -1, SEEK_CUR);
187 break;
188 }
189 }
190 skip_padding(file, 32);
191 if (fscanf(file, "%d", &r) != 1)
192 break;
193 skip_padding(file, 32);
194 if (fscanf(file, "%d", &g) != 1)
195 break;
196 skip_padding(file, 32);
197 if (fscanf(file, "%d\t", &b) != 1)
198 break;
199 if (!Read_byte_line(file, buffer, sizeof(buffer)))
200 break;
201 len = strlen(buffer);
202 while (len > 1)
203 {
204 len--;
205 if (buffer[len] == '\r' || buffer[len] == '\n')
206 buffer[len] = '\0';
207 }
208 /// @todo analyze color names to build shade table
209
210 GFX2_Log(GFX2_DEBUG, "GPL: %3d: RGB(%3d,%3d,%3d) %s\n", i, r,g,b, buffer);
211 context->Palette[i].R = r;
212 context->Palette[i].G = g;
213 context->Palette[i].B = b;
214 }
215 if (i > 0) // at least one color was read
216 File_error = 0;
217 }
218 else
219 File_error = 2;
220
221 // close the file
222 fclose(file);
223 }
224
225
226 /// Save GPL (Gimp Palette) file format
227 void
Save_GPL(T_IO_Context * context)228 Save_GPL (T_IO_Context * context)
229 {
230 // Gimp is a unix program, so use Unix file endings (LF aka '\n')
231 FILE *file;
232
233 file = Open_file_write(context);
234
235 if (file != NULL )
236 {
237 int i;
238
239 File_error = 0;
240 fprintf (file, "GIMP Palette\n");
241 fprintf (file, "Name: %s\n", context->File_name);
242 // TODO: use actual columns value
243 fprintf (file, "Columns: %d\n#\n", 16);
244
245 for (i = 0; i < 256 && File_error==0; i++)
246 {
247 // TODO: build names from shade table data
248 if (fprintf(file,"%d %d %d\tUntitled\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0)
249 File_error=1;
250 }
251 fclose(file);
252
253 if (File_error)
254 Remove_file(context);
255 }
256 else
257 {
258 // unable to open output file, nothing saved.
259 File_error=1;
260 }
261 }
262
263
264
265 // -- Lire un fichier au format PAL -----------------------------------------
Load_PAL(T_IO_Context * context)266 void Load_PAL(T_IO_Context * context)
267 {
268 FILE *file; // Fichier du fichier
269
270 File_error=0;
271
272 // Ouverture du fichier
273 if ((file=Open_file_read(context)))
274 {
275 long file_size = File_length_file(file);
276 // Le fichier ne peut être au format PAL que si sa taille vaut 768 octets
277 if (file_size == sizeof(T_Palette))
278 {
279 T_Palette palette_64;
280 // Pre_load(context, ?); // Pas possible... pas d'image...
281
282 // Lecture du fichier dans context->Palette
283 if (Read_bytes(file, palette_64, sizeof(T_Palette)))
284 {
285 Palette_64_to_256(palette_64);
286 memcpy(context->Palette, palette_64, sizeof(T_Palette));
287 }
288 else
289 File_error = 2;
290 } else {
291 char buffer[16];
292 if (!Read_bytes(file, buffer, 8))
293 {
294 File_error = 2;
295 fclose(file);
296 return;
297 }
298 buffer[8] = '\0';
299 if (strncmp(buffer,"JASC-PAL",8) == 0)
300 {
301 int i, n, r, g, b;
302 i = fscanf(file, "%d",&n);
303 if(i != 1 || n != 100)
304 {
305 File_error = 2;
306 fclose(file);
307 return;
308 }
309 // Read color count
310 if (fscanf(file, "%d",&n) == 1)
311 {
312 for (i = 0; i < n; i++)
313 {
314 if (fscanf(file, "%d %d %d",&r, &g, &b) == 3)
315 {
316 context->Palette[i].R = r;
317 context->Palette[i].G = g;
318 context->Palette[i].B = b;
319 }
320 else
321 File_error = 2;
322 }
323 }
324 else
325 File_error = 2;
326 }
327 else if(strncmp(buffer, "RIFF", 4) == 0)
328 {
329 // Microsoft RIFF format.
330 fseek(file, 8, SEEK_SET);
331 Read_bytes(file, buffer, 8);
332 if (strncmp(buffer, "PAL data", 8) == 0)
333 {
334 word color_count;
335 word i = 0;
336
337 fseek(file, 22, SEEK_SET);
338 if (!Read_word_le(file, &color_count))
339 File_error = 2;
340 else
341 for(i = 0; i < color_count && File_error == 0; i++)
342 {
343 byte colors[4];
344 if (!Read_bytes(file, colors, 4))
345 File_error = 2;
346 context->Palette[i].R = colors[0];
347 context->Palette[i].G = colors[1];
348 context->Palette[i].B = colors[2];
349 }
350 } else File_error = 2;
351 } else
352 File_error = 2;
353 }
354
355 fclose(file);
356 }
357 else
358 // Si on n'a pas réussi à ouvrir le fichier, alors il y a eu une erreur
359 File_error=1;
360 }
361
362
363 // -- Sauver un fichier au format PAL ---------------------------------------
Save_PAL(T_IO_Context * context)364 void Save_PAL(T_IO_Context * context)
365 {
366 // JASC-PAL is a DOS/Windows format, so use CRLF line endings "\r\n"
367 FILE *file;
368
369 File_error=0;
370
371 // Open output file
372 if ((file=Open_file_write(context)) != NULL)
373 {
374 int i;
375
376 setvbuf(file, NULL, _IOFBF, 64*1024);
377
378 if (fputs("JASC-PAL\r\n0100\r\n256\r\n", file)==EOF)
379 File_error=1;
380 for (i = 0; i < 256 && File_error==0; i++)
381 {
382 if (fprintf(file,"%d %d %d\r\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0)
383 File_error=1;
384 }
385
386 fclose(file);
387
388 if (File_error)
389 Remove_file(context);
390 }
391 else
392 {
393 // unable to open output file, nothing saved.
394 File_error=1;
395 }
396 }
397
398
399 //////////////////////////////////// PKM ////////////////////////////////////
400 typedef struct
401 {
402 char Ident[3]; // String "PKM" }
403 byte Method; // Compression method
404 // 0 = per-line compression (c)KM
405 // others = unknown at the moment
406 byte Recog1; // Recognition byte 1
407 byte Recog2; // Recognition byte 2
408 word Width; // Image width
409 word Height; // Image height
410 T_Palette Palette;// RGB Palette 256*3, on a 1-64 scale for each component
411 word Jump; // Size of the jump between header and image:
412 // Used to insert a comment
413 } T_PKM_Header;
414
415 // -- Tester si un fichier est au format PKM --------------------------------
Test_PKM(T_IO_Context * context,FILE * file)416 void Test_PKM(T_IO_Context * context, FILE * file)
417 {
418 T_PKM_Header header;
419
420 (void)context;
421 File_error=1;
422
423 // Lecture du header du fichier
424 if (Read_bytes(file,&header.Ident,3) &&
425 Read_byte(file,&header.Method) &&
426 Read_byte(file,&header.Recog1) &&
427 Read_byte(file,&header.Recog2) &&
428 Read_word_le(file,&header.Width) &&
429 Read_word_le(file,&header.Height) &&
430 Read_bytes(file,&header.Palette,sizeof(T_Palette)) &&
431 Read_word_le(file,&header.Jump))
432 {
433 // On regarde s'il y a la signature PKM suivie de la méthode 0.
434 // La constante "PKM" étant un chaîne, elle se termine toujours par 0.
435 // Donc pas la peine de s'emm...er à regarder si la méthode est à 0.
436 if ( (!memcmp(&header,"PKM",4)) && header.Width && header.Height)
437 File_error=0;
438 }
439 }
440
441
442 // -- Lire un fichier au format PKM -----------------------------------------
Load_PKM(T_IO_Context * context)443 void Load_PKM(T_IO_Context * context)
444 {
445 FILE *file; // Fichier du fichier
446 T_PKM_Header header;
447 byte color;
448 byte temp_byte;
449 word len;
450 word index;
451 dword Compteur_de_pixels;
452 dword Compteur_de_donnees_packees;
453 dword image_size;
454 dword Taille_pack;
455 long file_size;
456
457 File_error=0;
458
459 if ((file=Open_file_read(context)))
460 {
461 file_size=File_length_file(file);
462
463 if (Read_bytes(file,&header.Ident,3) &&
464 Read_byte(file,&header.Method) &&
465 Read_byte(file,&header.Recog1) &&
466 Read_byte(file,&header.Recog2) &&
467 Read_word_le(file,&header.Width) &&
468 Read_word_le(file,&header.Height) &&
469 Read_bytes(file,&header.Palette,sizeof(T_Palette)) &&
470 Read_word_le(file,&header.Jump))
471 {
472 context->Comment[0]='\0'; // On efface le commentaire
473 if (header.Jump)
474 {
475 index=0;
476 while ( (index<header.Jump) && (!File_error) )
477 {
478 if (Read_byte(file,&temp_byte))
479 {
480 index+=2; // On rajoute le "Field-id" et "le Field-size" pas encore lu
481 switch (temp_byte)
482 {
483 case 0 : // Commentaire
484 if (Read_byte(file,&temp_byte))
485 {
486 if (temp_byte>COMMENT_SIZE)
487 {
488 color=temp_byte; // On se sert de color comme
489 temp_byte=COMMENT_SIZE; // variable temporaire
490 color-=COMMENT_SIZE;
491 }
492 else
493 color=0;
494
495 if (Read_bytes(file,context->Comment,temp_byte))
496 {
497 index+=temp_byte;
498 context->Comment[temp_byte]='\0';
499 if (color)
500 if (fseek(file,color,SEEK_CUR))
501 File_error=2;
502 }
503 else
504 File_error=2;
505 }
506 else
507 File_error=2;
508 break;
509
510 case 1 : // Dimensions de l'écran d'origine
511 if (Read_byte(file,&temp_byte))
512 {
513 if (temp_byte==4)
514 {
515 index+=4;
516 if ( ! Read_word_le(file,(word *) &Original_screen_X)
517 || !Read_word_le(file,(word *) &Original_screen_Y) )
518 File_error=2;
519 else
520 GFX2_Log(GFX2_DEBUG, "PKM original screen %dx%d\n", (int)Original_screen_X, (int)Original_screen_Y);
521 }
522 else
523 File_error=2;
524 }
525 else
526 File_error=2;
527 break;
528
529 case 2 : // color de transparence
530 if (Read_byte(file,&temp_byte))
531 {
532 if (temp_byte==1)
533 {
534 index++;
535 if (! Read_byte(file,&Back_color))
536 File_error=2;
537 }
538 else
539 File_error=2;
540 }
541 else
542 File_error=2;
543 break;
544
545 default:
546 if (Read_byte(file,&temp_byte))
547 {
548 index+=temp_byte;
549 if (fseek(file,temp_byte,SEEK_CUR))
550 File_error=2;
551 }
552 else
553 File_error=2;
554 }
555 }
556 else
557 File_error=2;
558 }
559 if ( (!File_error) && (index!=header.Jump) )
560 File_error=2;
561 }
562
563 /*Init_lecture();*/
564
565 if (!File_error)
566 {
567 Pre_load(context, header.Width,header.Height,file_size,FORMAT_PKM,PIXEL_SIMPLE,0);
568 if (File_error==0)
569 {
570
571 image_size=(dword)(context->Width*context->Height);
572 // Palette lue en 64
573 memcpy(context->Palette,header.Palette,sizeof(T_Palette));
574 Palette_64_to_256(context->Palette);
575
576 Compteur_de_donnees_packees=0;
577 Compteur_de_pixels=0;
578 // Header size is 780
579 Taille_pack=(file_size)-780-header.Jump;
580
581 // Boucle de décompression:
582 while ( (Compteur_de_pixels<image_size) && (Compteur_de_donnees_packees<Taille_pack) && (!File_error) )
583 {
584 if(Read_byte(file, &temp_byte)!=1)
585 {
586 File_error=2;
587 break;
588 }
589
590 // Si ce n'est pas un octet de reconnaissance, c'est un pixel brut
591 if ( (temp_byte!=header.Recog1) && (temp_byte!=header.Recog2) )
592 {
593 Set_pixel(context, Compteur_de_pixels % context->Width,
594 Compteur_de_pixels / context->Width,
595 temp_byte);
596 Compteur_de_donnees_packees++;
597 Compteur_de_pixels++;
598 }
599 else // Sinon, On regarde si on va décompacter un...
600 { // ... nombre de pixels tenant sur un byte
601 if (temp_byte==header.Recog1)
602 {
603 if(Read_byte(file, &color)!=1)
604 {
605 File_error=2;
606 break;
607 }
608 if(Read_byte(file, &temp_byte)!=1)
609 {
610 File_error=2;
611 break;
612 }
613 for (index=0; index<temp_byte; index++)
614 Set_pixel(context, (Compteur_de_pixels+index) % context->Width,
615 (Compteur_de_pixels+index) / context->Width,
616 color);
617 Compteur_de_pixels+=temp_byte;
618 Compteur_de_donnees_packees+=3;
619 }
620 else // ... nombre de pixels tenant sur un word
621 {
622 if(Read_byte(file, &color)!=1)
623 {
624 File_error=2;
625 break;
626 }
627 Read_word_be(file, &len);
628 for (index=0; index<len; index++)
629 Set_pixel(context, (Compteur_de_pixels+index) % context->Width,
630 (Compteur_de_pixels+index) / context->Width,
631 color);
632 Compteur_de_pixels+=len;
633 Compteur_de_donnees_packees+=4;
634 }
635 }
636 }
637 }
638 }
639 /*Close_lecture();*/
640 }
641 else // Lecture header impossible: Error ne modifiant pas l'image
642 File_error=1;
643
644 fclose(file);
645 }
646 else // Ouv. fichier impossible: Error ne modifiant pas l'image
647 File_error=1;
648 }
649
650
651 // -- Sauver un fichier au format PKM ---------------------------------------
652
653 // Trouver quels sont les octets de reconnaissance
Find_recog(byte * recog1,byte * recog2)654 void Find_recog(byte * recog1, byte * recog2)
655 {
656 dword Find_recon[256]; // Table d'utilisation de couleurs
657 byte best; // Meilleure couleur pour recon (recon1 puis recon2)
658 dword NBest; // Nombre d'occurences de cette couleur
659 word index;
660
661
662 // On commence par compter l'utilisation de chaque couleurs
663 Count_used_colors(Find_recon);
664
665 // Ensuite recog1 devient celle la moins utilisée de celles-ci
666 *recog1=0;
667 best=1;
668 NBest=INT_MAX; // Une même couleur ne pourra jamais être utilisée 1M de fois.
669 for (index=1;index<=255;index++)
670 if (Find_recon[index]<NBest)
671 {
672 best=index;
673 NBest=Find_recon[index];
674 }
675 *recog1=best;
676
677 // Enfin recog2 devient la 2ème moins utilisée
678 *recog2=0;
679 best=0;
680 NBest=INT_MAX;
681 for (index=0;index<=255;index++)
682 if ( (Find_recon[index]<NBest) && (index!=*recog1) )
683 {
684 best=index;
685 NBest=Find_recon[index];
686 }
687 *recog2=best;
688 }
689
690
Save_PKM(T_IO_Context * context)691 void Save_PKM(T_IO_Context * context)
692 {
693 FILE *file;
694 T_PKM_Header header;
695 dword Compteur_de_pixels;
696 dword image_size;
697 word repetitions;
698 byte last_color;
699 byte pixel_value;
700 size_t comment_size;
701
702
703
704 // Construction du header
705 memcpy(header.Ident,"PKM",3);
706 header.Method=0;
707 Find_recog(&header.Recog1,&header.Recog2);
708 header.Width=context->Width;
709 header.Height=context->Height;
710 memcpy(header.Palette,context->Palette,sizeof(T_Palette));
711 Palette_256_to_64(header.Palette);
712
713 // Calcul de la taille du Post-header
714 header.Jump=9; // 6 pour les dimensions de l'ecran + 3 pour la back-color
715 comment_size=strlen(context->Comment);
716 if (comment_size > 255) comment_size = 255;
717 if (comment_size)
718 header.Jump+=(word)comment_size+2;
719
720
721 File_error=0;
722
723 // Ouverture du fichier
724 if ((file=Open_file_write(context)))
725 {
726 setvbuf(file, NULL, _IOFBF, 64*1024);
727
728 // Ecriture du header
729 if (Write_bytes(file,&header.Ident,3) &&
730 Write_byte(file,header.Method) &&
731 Write_byte(file,header.Recog1) &&
732 Write_byte(file,header.Recog2) &&
733 Write_word_le(file,header.Width) &&
734 Write_word_le(file,header.Height) &&
735 Write_bytes(file,&header.Palette,sizeof(T_Palette)) &&
736 Write_word_le(file,header.Jump))
737 {
738
739 // Ecriture du commentaire
740 // (Compteur_de_pixels est utilisé ici comme simple index de comptage)
741 if (comment_size > 0)
742 {
743 Write_one_byte(file,0);
744 Write_one_byte(file,(byte)comment_size);
745 for (Compteur_de_pixels=0; Compteur_de_pixels<comment_size; Compteur_de_pixels++)
746 Write_one_byte(file,context->Comment[Compteur_de_pixels]);
747 }
748 // Ecriture des dimensions de l'écran
749 Write_one_byte(file,1);
750 Write_one_byte(file,4);
751 Write_one_byte(file,Screen_width&0xFF);
752 Write_one_byte(file,Screen_width>>8);
753 Write_one_byte(file,Screen_height&0xFF);
754 Write_one_byte(file,Screen_height>>8);
755 // Ecriture de la back-color
756 Write_one_byte(file,2);
757 Write_one_byte(file,1);
758 Write_one_byte(file,Back_color);
759
760 // Routine de compression PKM de l'image
761 image_size=(dword)(context->Width*context->Height);
762 Compteur_de_pixels=0;
763 pixel_value=Get_pixel(context, 0,0);
764
765 while ( (Compteur_de_pixels<image_size) && (!File_error) )
766 {
767 Compteur_de_pixels++;
768 repetitions=1;
769 last_color=pixel_value;
770 if(Compteur_de_pixels<image_size)
771 {
772 pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width);
773 }
774 while ( (pixel_value==last_color)
775 && (Compteur_de_pixels<image_size)
776 && (repetitions<65535) )
777 {
778 Compteur_de_pixels++;
779 repetitions++;
780 if(Compteur_de_pixels>=image_size) break;
781 pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width);
782 }
783
784 if ( (last_color!=header.Recog1) && (last_color!=header.Recog2) )
785 {
786 if (repetitions==1)
787 Write_one_byte(file,last_color);
788 else
789 if (repetitions==2)
790 {
791 Write_one_byte(file,last_color);
792 Write_one_byte(file,last_color);
793 }
794 else
795 if ( (repetitions>2) && (repetitions<256) )
796 { // RECON1/couleur/nombre
797 Write_one_byte(file,header.Recog1);
798 Write_one_byte(file,last_color);
799 Write_one_byte(file,repetitions&0xFF);
800 }
801 else
802 if (repetitions>=256)
803 { // RECON2/couleur/hi(nombre)/lo(nombre)
804 Write_one_byte(file,header.Recog2);
805 Write_one_byte(file,last_color);
806 Write_one_byte(file,repetitions>>8);
807 Write_one_byte(file,repetitions&0xFF);
808 }
809 }
810 else
811 {
812 if (repetitions<256)
813 {
814 Write_one_byte(file,header.Recog1);
815 Write_one_byte(file,last_color);
816 Write_one_byte(file,repetitions&0xFF);
817 }
818 else
819 {
820 Write_one_byte(file,header.Recog2);
821 Write_one_byte(file,last_color);
822 Write_one_byte(file,repetitions>>8);
823 Write_one_byte(file,repetitions&0xFF);
824 }
825 }
826 }
827 }
828 else
829 File_error=1;
830 fclose(file);
831 }
832 else
833 {
834 File_error=1;
835 fclose(file);
836 }
837 // S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser
838 // ce fichier pourri traîner... Ca fait pas propre.
839 if (File_error)
840 Remove_file(context);
841 }
842
843
844 //////////////////////////////////// CEL ////////////////////////////////////
845 typedef struct
846 {
847 word Width; // width de l'image
848 word Height; // height de l'image
849 } T_CEL_Header1;
850
851 typedef struct
852 {
853 byte Signature[4]; // Signature du format
854 byte Kind; // Type de fichier ($10=PALette $20=BitMaP)
855 byte Nb_bits; // Nombre de bits
856 word Filler1; // ???
857 word Width; // width de l'image
858 word Height; // height de l'image
859 word X_offset; // Offset en X de l'image
860 word Y_offset; // Offset en Y de l'image
861 byte Filler2[16]; // ???
862 } T_CEL_Header2;
863
864 // -- Tester si un fichier est au format CEL --------------------------------
865
Test_CEL(T_IO_Context * context,FILE * file)866 void Test_CEL(T_IO_Context * context, FILE * file)
867 {
868 int size;
869 T_CEL_Header1 header1;
870 T_CEL_Header2 header2;
871 int file_size;
872
873 (void)context;
874 File_error=0;
875
876 file_size = File_length_file(file);
877 if (Read_word_le(file,&header1.Width) &&
878 Read_word_le(file,&header1.Height) )
879 {
880 // Vu que ce header n'a pas de signature, il va falloir tester la
881 // cohérence de la dimension de l'image avec celle du fichier.
882
883 size=file_size-4;
884 if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) )
885 {
886 // Tentative de reconnaissance de la signature des nouveaux fichiers
887
888 fseek(file,0,SEEK_SET);
889 if (Read_bytes(file,&header2.Signature,4) &&
890 !memcmp(header2.Signature,"KiSS",4) &&
891 Read_byte(file,&header2.Kind) &&
892 (header2.Kind==0x20) &&
893 Read_byte(file,&header2.Nb_bits) &&
894 Read_word_le(file,&header2.Filler1) &&
895 Read_word_le(file,&header2.Width) &&
896 Read_word_le(file,&header2.Height) &&
897 Read_word_le(file,&header2.X_offset) &&
898 Read_word_le(file,&header2.Y_offset) &&
899 Read_bytes(file,&header2.Filler2,16))
900 {
901 // ok
902 }
903 else
904 File_error=1;
905 }
906 else
907 File_error=1;
908 }
909 else
910 {
911 File_error=1;
912 }
913 }
914
915
916 // -- Lire un fichier au format CEL -----------------------------------------
917
Load_CEL(T_IO_Context * context)918 void Load_CEL(T_IO_Context * context)
919 {
920 FILE *file;
921 T_CEL_Header1 header1;
922 T_CEL_Header2 header2;
923 short x_pos;
924 short y_pos;
925 byte last_byte=0;
926 long file_size;
927 const long int header_size = 4;
928
929 File_error=0;
930 if ((file=Open_file_read(context)))
931 {
932 if (Read_word_le(file,&(header1.Width))
933 && Read_word_le(file,&(header1.Height)))
934 {
935 file_size=File_length_file(file);
936 if ( (file_size>header_size)
937 && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-header_size) ) )
938 {
939 // Chargement d'un fichier CEL sans signature (vieux fichiers)
940 Pre_load(context, header1.Width, header1.Height,
941 file_size, FORMAT_CEL, PIXEL_SIMPLE, 0);
942 if (File_error==0)
943 {
944 Original_screen_X = context->Width;
945 Original_screen_Y = context->Height;
946 // Chargement de l'image
947 /*Init_lecture();*/
948 for (y_pos=0;((y_pos<context->Height) && (!File_error));y_pos++)
949 for (x_pos=0;((x_pos<context->Width) && (!File_error));x_pos++)
950 if ((x_pos & 1)==0)
951 {
952 if(Read_byte(file,&last_byte)!=1) File_error = 2;
953 Set_pixel(context, x_pos,y_pos,(last_byte >> 4));
954 }
955 else
956 Set_pixel(context, x_pos,y_pos,(last_byte & 15));
957 /*Close_lecture();*/
958 }
959 }
960 else
961 {
962 // On réessaye avec le nouveau format
963
964 fseek(file,0,SEEK_SET);
965 if (Read_bytes(file,header2.Signature,4)
966 && Read_byte(file,&(header2.Kind))
967 && Read_byte(file,&(header2.Nb_bits))
968 && Read_word_le(file,&(header2.Filler1))
969 && Read_word_le(file,&(header2.Width))
970 && Read_word_le(file,&(header2.Height))
971 && Read_word_le(file,&(header2.X_offset))
972 && Read_word_le(file,&(header2.Y_offset))
973 && Read_bytes(file,header2.Filler2,16)
974 )
975 {
976 // Chargement d'un fichier CEL avec signature (nouveaux fichiers)
977
978 Pre_load(context,
979 header2.Width + header2.X_offset,
980 header2.Height + header2.Y_offset,
981 file_size, FORMAT_CEL, PIXEL_SIMPLE, 0);
982 if (File_error==0)
983 {
984 Original_screen_X = context->Width;
985 Original_screen_Y = context->Height;
986 // Chargement de l'image
987 /*Init_lecture();*/
988
989 if (!File_error)
990 {
991 // Effacement du décalage
992 for (y_pos=0;y_pos<header2.Y_offset;y_pos++)
993 for (x_pos=0;x_pos<context->Width;x_pos++)
994 Set_pixel(context, x_pos,y_pos,0);
995 for (y_pos=header2.Y_offset;y_pos<context->Height;y_pos++)
996 for (x_pos=0;x_pos<header2.X_offset;x_pos++)
997 Set_pixel(context, x_pos,y_pos,0);
998
999 switch(header2.Nb_bits)
1000 {
1001 case 4:
1002 for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1003 for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1004 if ((x_pos & 1)==0)
1005 {
1006 if(Read_byte(file,&last_byte)!=1) File_error=2;
1007 Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte >> 4));
1008 }
1009 else
1010 Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15));
1011 break;
1012
1013 case 8:
1014 for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1015 for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1016 {
1017 byte byte_read;
1018 if(Read_byte(file,&byte_read)!=1) File_error = 2;
1019 Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,byte_read);
1020 }
1021 break;
1022
1023 default:
1024 File_error=1;
1025 }
1026 }
1027 /*Close_lecture();*/
1028 }
1029 }
1030 else
1031 File_error=1;
1032 }
1033 fclose(file);
1034 }
1035 else
1036 File_error=1;
1037 }
1038 else
1039 File_error=1;
1040 }
1041
1042
1043 // -- Ecrire un fichier au format CEL ---------------------------------------
1044
Save_CEL(T_IO_Context * context)1045 void Save_CEL(T_IO_Context * context)
1046 {
1047 FILE *file;
1048 T_CEL_Header1 header1;
1049 T_CEL_Header2 header2;
1050 short x_pos;
1051 short y_pos;
1052 byte last_byte=0;
1053 dword color_usage[256]; // Table d'utilisation de couleurs
1054
1055
1056 // On commence par compter l'utilisation de chaque couleurs
1057 Count_used_colors(color_usage);
1058
1059 File_error=0;
1060 if ((file=Open_file_write(context)))
1061 {
1062 setvbuf(file, NULL, _IOFBF, 64*1024);
1063
1064 // On regarde si des couleurs >16 sont utilisées dans l'image
1065 for (x_pos=16;((x_pos<256) && (!color_usage[x_pos]));x_pos++);
1066
1067 if (x_pos==256)
1068 {
1069 // Cas d'une image 16 couleurs (écriture à l'ancien format)
1070
1071 header1.Width =context->Width;
1072 header1.Height=context->Height;
1073
1074 if (Write_word_le(file,header1.Width)
1075 && Write_word_le(file,header1.Height)
1076 )
1077 {
1078 // Sauvegarde de l'image
1079 for (y_pos=0;((y_pos<context->Height) && (!File_error));y_pos++)
1080 {
1081 for (x_pos=0;((x_pos<context->Width) && (!File_error));x_pos++)
1082 if ((x_pos & 1)==0)
1083 last_byte=(Get_pixel(context, x_pos,y_pos) << 4);
1084 else
1085 {
1086 last_byte=last_byte | (Get_pixel(context, x_pos,y_pos) & 15);
1087 Write_one_byte(file,last_byte);
1088 }
1089
1090 if ((x_pos & 1)==1)
1091 Write_one_byte(file,last_byte);
1092 }
1093 }
1094 else
1095 File_error=1;
1096 fclose(file);
1097 }
1098 else
1099 {
1100 // Cas d'une image 256 couleurs (écriture au nouveau format)
1101
1102 // Recherche du décalage
1103 for (y_pos=0;y_pos<context->Height;y_pos++)
1104 {
1105 for (x_pos=0;x_pos<context->Width;x_pos++)
1106 if (Get_pixel(context, x_pos,y_pos)!=0)
1107 break;
1108 if (Get_pixel(context, x_pos,y_pos)!=0)
1109 break;
1110 }
1111 header2.Y_offset=y_pos;
1112 for (x_pos=0;x_pos<context->Width;x_pos++)
1113 {
1114 for (y_pos=0;y_pos<context->Height;y_pos++)
1115 if (Get_pixel(context, x_pos,y_pos)!=0)
1116 break;
1117 if (Get_pixel(context, x_pos,y_pos)!=0)
1118 break;
1119 }
1120 header2.X_offset=x_pos;
1121
1122 memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature
1123 header2.Kind=0x20; // Initialisation du type (BitMaP)
1124 header2.Nb_bits=8; // Initialisation du nombre de bits
1125 header2.Filler1=0; // Initialisation du filler 1 (?)
1126 header2.Width=context->Width-header2.X_offset; // Initialisation de la largeur
1127 header2.Height=context->Height-header2.Y_offset; // Initialisation de la hauteur
1128 for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?)
1129 header2.Filler2[x_pos]=0;
1130
1131 if (Write_bytes(file,header2.Signature,4)
1132 && Write_byte(file,header2.Kind)
1133 && Write_byte(file,header2.Nb_bits)
1134 && Write_word_le(file,header2.Filler1)
1135 && Write_word_le(file,header2.Width)
1136 && Write_word_le(file,header2.Height)
1137 && Write_word_le(file,header2.X_offset)
1138 && Write_word_le(file,header2.Y_offset)
1139 && Write_bytes(file,header2.Filler2,14)
1140 )
1141 {
1142 // Sauvegarde de l'image
1143 for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1144 for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1145 Write_one_byte(file,Get_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset));
1146 }
1147 else
1148 File_error=1;
1149 fclose(file);
1150 }
1151
1152 if (File_error)
1153 Remove_file(context);
1154 }
1155 else
1156 File_error=1;
1157 }
1158
1159
1160 //////////////////////////////////// KCF ////////////////////////////////////
1161 typedef struct
1162 {
1163 struct
1164 {
1165 struct
1166 {
1167 byte Byte1;
1168 byte Byte2;
1169 } color[16];
1170 } Palette[10];
1171 } T_KCF_Header;
1172
1173 // -- Tester si un fichier est au format KCF --------------------------------
1174
Test_KCF(T_IO_Context * context,FILE * file)1175 void Test_KCF(T_IO_Context * context, FILE * file)
1176 {
1177 T_KCF_Header header1;
1178 T_CEL_Header2 header2;
1179 int pal_index;
1180 int color_index;
1181
1182 (void)context;
1183 File_error=0;
1184 if (File_length_file(file)==320)
1185 {
1186 for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1187 for (color_index=0;color_index<16 && !File_error;color_index++)
1188 if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) ||
1189 !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2))
1190 File_error=1;
1191 // On vérifie une propriété de la structure de palette:
1192 for (pal_index=0;pal_index<10;pal_index++)
1193 for (color_index=0;color_index<16;color_index++)
1194 if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0)
1195 File_error=1;
1196 }
1197 else
1198 {
1199 if (Read_bytes(file,header2.Signature,4)
1200 && Read_byte(file,&(header2.Kind))
1201 && Read_byte(file,&(header2.Nb_bits))
1202 && Read_word_le(file,&(header2.Filler1))
1203 && Read_word_le(file,&(header2.Width))
1204 && Read_word_le(file,&(header2.Height))
1205 && Read_word_le(file,&(header2.X_offset))
1206 && Read_word_le(file,&(header2.Y_offset))
1207 && Read_bytes(file,header2.Filler2,14)
1208 )
1209 {
1210 if (memcmp(header2.Signature,"KiSS",4)==0)
1211 {
1212 if (header2.Kind!=0x10)
1213 File_error=1;
1214 }
1215 else
1216 File_error=1;
1217 }
1218 else
1219 File_error=1;
1220 }
1221 }
1222
1223
1224 // -- Lire un fichier au format KCF -----------------------------------------
1225
Load_KCF(T_IO_Context * context)1226 void Load_KCF(T_IO_Context * context)
1227 {
1228 FILE *file;
1229 T_KCF_Header header1;
1230 T_CEL_Header2 header2;
1231 byte bytes[3];
1232 int pal_index;
1233 int color_index;
1234 int index;
1235 long file_size;
1236
1237
1238 File_error=0;
1239 if ((file=Open_file_read(context)))
1240 {
1241 file_size=File_length_file(file);
1242 if (file_size==320)
1243 {
1244 // Fichier KCF à l'ancien format
1245 for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1246 for (color_index=0;color_index<16 && !File_error;color_index++)
1247 if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) ||
1248 !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2))
1249 File_error=1;
1250
1251 if (!File_error)
1252 {
1253 // Pre_load(context, ?); // Pas possible... pas d'image...
1254
1255 if (Config.Clear_palette)
1256 memset(context->Palette,0,sizeof(T_Palette));
1257
1258 // Chargement de la palette
1259 for (pal_index=0;pal_index<10;pal_index++)
1260 for (color_index=0;color_index<16;color_index++)
1261 {
1262 index=16+(pal_index*16)+color_index;
1263 context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4);
1264 context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4);
1265 context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4);
1266 }
1267
1268 for (index=0;index<16;index++)
1269 {
1270 context->Palette[index].R=context->Palette[index+16].R;
1271 context->Palette[index].G=context->Palette[index+16].G;
1272 context->Palette[index].B=context->Palette[index+16].B;
1273 }
1274
1275 }
1276 else
1277 File_error=1;
1278 }
1279 else
1280 {
1281 // Fichier KCF au nouveau format
1282
1283 if (Read_bytes(file,header2.Signature,4)
1284 && Read_byte(file,&(header2.Kind))
1285 && Read_byte(file,&(header2.Nb_bits))
1286 && Read_word_le(file,&(header2.Filler1))
1287 && Read_word_le(file,&(header2.Width))
1288 && Read_word_le(file,&(header2.Height))
1289 && Read_word_le(file,&(header2.X_offset))
1290 && Read_word_le(file,&(header2.Y_offset))
1291 && Read_bytes(file,header2.Filler2,14)
1292 )
1293 {
1294 // Pre_load(context, ?); // Pas possible... pas d'image...
1295
1296 index=(header2.Nb_bits==12)?16:0;
1297 for (pal_index=0;pal_index<header2.Height;pal_index++)
1298 {
1299 // Pour chaque palette
1300
1301 for (color_index=0;color_index<header2.Width;color_index++)
1302 {
1303 // Pour chaque couleur
1304
1305 switch(header2.Nb_bits)
1306 {
1307 case 12: // RRRR BBBB | 0000 VVVV
1308 Read_bytes(file,bytes,2);
1309 context->Palette[index].R=(bytes[0] >> 4) << 4;
1310 context->Palette[index].B=(bytes[0] & 15) << 4;
1311 context->Palette[index].G=(bytes[1] & 15) << 4;
1312 break;
1313
1314 case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB
1315 Read_bytes(file,bytes,3);
1316 context->Palette[index].R=bytes[0];
1317 context->Palette[index].G=bytes[1];
1318 context->Palette[index].B=bytes[2];
1319 }
1320
1321 index++;
1322 }
1323 }
1324
1325 if (header2.Nb_bits==12)
1326 for (index=0;index<16;index++)
1327 {
1328 context->Palette[index].R=context->Palette[index+16].R;
1329 context->Palette[index].G=context->Palette[index+16].G;
1330 context->Palette[index].B=context->Palette[index+16].B;
1331 }
1332
1333 }
1334 else
1335 File_error=1;
1336 }
1337 fclose(file);
1338 }
1339 else
1340 File_error=1;
1341 }
1342
1343
1344 // -- Ecrire un fichier au format KCF ---------------------------------------
1345
Save_KCF(T_IO_Context * context)1346 void Save_KCF(T_IO_Context * context)
1347 {
1348 FILE *file;
1349 T_KCF_Header header1;
1350 T_CEL_Header2 header2;
1351 byte bytes[3];
1352 int pal_index;
1353 int color_index;
1354 int index;
1355 dword color_usage[256]; // Table d'utilisation de couleurs
1356
1357 // On commence par compter l'utilisation de chaque couleurs
1358 Count_used_colors(color_usage);
1359
1360 File_error=0;
1361 if ((file=Open_file_write(context)))
1362 {
1363 setvbuf(file, NULL, _IOFBF, 64*1024);
1364 // Sauvegarde de la palette
1365
1366 // On regarde si des couleurs >16 sont utilisées dans l'image
1367 for (index=16;((index<256) && (!color_usage[index]));index++);
1368
1369 if (index==256)
1370 {
1371 // Cas d'une image 16 couleurs (écriture à l'ancien format)
1372
1373 for (pal_index=0;pal_index<10;pal_index++)
1374 for (color_index=0;color_index<16;color_index++)
1375 {
1376 index=16+(pal_index*16)+color_index;
1377 header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4);
1378 header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4;
1379 }
1380
1381 // Write all
1382 for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1383 for (color_index=0;color_index<16 && !File_error;color_index++)
1384 if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) ||
1385 !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2))
1386 File_error=1;
1387 }
1388 else
1389 {
1390 // Cas d'une image 256 couleurs (écriture au nouveau format)
1391
1392 memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature
1393 header2.Kind=0x10; // Initialisation du type (PALette)
1394 header2.Nb_bits=24; // Initialisation du nombre de bits
1395 header2.Filler1=0; // Initialisation du filler 1 (?)
1396 header2.Width=256; // Initialisation du nombre de couleurs
1397 header2.Height=1; // Initialisation du nombre de palettes
1398 header2.X_offset=0; // Initialisation du décalage X
1399 header2.Y_offset=0; // Initialisation du décalage Y
1400 for (index=0;index<16;index++) // Initialisation du filler 2 (?)
1401 header2.Filler2[index]=0;
1402
1403 if (!Write_bytes(file,header2.Signature,4)
1404 || !Write_byte(file,header2.Kind)
1405 || !Write_byte(file,header2.Nb_bits)
1406 || !Write_word_le(file,header2.Filler1)
1407 || !Write_word_le(file,header2.Width)
1408 || !Write_word_le(file,header2.Height)
1409 || !Write_word_le(file,header2.X_offset)
1410 || !Write_word_le(file,header2.Y_offset)
1411 || !Write_bytes(file,header2.Filler2,14)
1412 )
1413 File_error=1;
1414
1415 for (index=0;(index<256) && (!File_error);index++)
1416 {
1417 bytes[0]=context->Palette[index].R;
1418 bytes[1]=context->Palette[index].G;
1419 bytes[2]=context->Palette[index].B;
1420 if (! Write_bytes(file,bytes,3))
1421 File_error=1;
1422 }
1423 }
1424
1425 fclose(file);
1426
1427 if (File_error)
1428 Remove_file(context);
1429 }
1430 else
1431 File_error=1;
1432 }
1433
1434
1435 /////////////////////////////////// FLI/FLC /////////////////////////////////
1436 typedef struct {
1437 dword size; /* Size of FLIC including this header */
1438 word type; /* File type 0xAF11, 0xAF12, 0xAF30, 0xAF44, ... */
1439 word frames; /* Number of frames in first segment */
1440 word width; /* FLIC width in pixels */
1441 word height; /* FLIC height in pixels */
1442 word depth; /* Bits per pixel (usually 8) */
1443 word flags; /* Set to zero or to three */
1444 dword speed; /* Delay between frames */
1445 word reserved1; /* Set to zero */
1446 dword created; /* Date of FLIC creation (FLC only) */
1447 dword creator; /* Serial number or compiler id (FLC only) */
1448 dword updated; /* Date of FLIC update (FLC only) */
1449 dword updater; /* Serial number (FLC only), see creator */
1450 word aspect_dx; /* Width of square rectangle (FLC only) */
1451 word aspect_dy; /* Height of square rectangle (FLC only) */
1452 word ext_flags; /* EGI: flags for specific EGI extensions */
1453 word keyframes; /* EGI: key-image frequency */
1454 word totalframes; /* EGI: total number of frames (segments) */
1455 dword req_memory; /* EGI: maximum chunk size (uncompressed) */
1456 word max_regions; /* EGI: max. number of regions in a CHK_REGION chunk */
1457 word transp_num; /* EGI: number of transparent levels */
1458 byte reserved2[24]; /* Set to zero */
1459 dword oframe1; /* Offset to frame 1 (FLC only) */
1460 dword oframe2; /* Offset to frame 2 (FLC only) */
1461 byte reserved3[40]; /* Set to zero */
1462 } T_FLIC_Header;
1463
Load_FLI_Header(FILE * file,T_FLIC_Header * header)1464 static void Load_FLI_Header(FILE * file, T_FLIC_Header * header)
1465 {
1466 if (!(Read_dword_le(file,&header->size)
1467 && Read_word_le(file,&header->type)
1468 && Read_word_le(file,&header->frames)
1469 && Read_word_le(file,&header->width)
1470 && Read_word_le(file,&header->height)
1471 && Read_word_le(file,&header->depth)
1472 && Read_word_le(file,&header->flags)
1473 && Read_dword_le(file,&header->speed)
1474 && Read_word_le(file,&header->reserved1)
1475 && Read_dword_le(file,&header->created)
1476 && Read_dword_le(file,&header->creator)
1477 && Read_dword_le(file,&header->updated)
1478 && Read_dword_le(file,&header->updater)
1479 && Read_word_le(file,&header->aspect_dx)
1480 && Read_word_le(file,&header->aspect_dy)
1481 && Read_word_le(file,&header->ext_flags)
1482 && Read_word_le(file,&header->keyframes)
1483 && Read_word_le(file,&header->totalframes)
1484 && Read_dword_le(file,&header->req_memory)
1485 && Read_word_le(file,&header->max_regions)
1486 && Read_word_le(file,&header->transp_num)
1487 && Read_bytes(file,header->reserved2,24)
1488 && Read_dword_le(file,&header->oframe1)
1489 && Read_dword_le(file,&header->oframe2)
1490 && Read_bytes(file,header->reserved2,40) ))
1491 {
1492 File_error=1;
1493 }
1494 }
1495
1496 /**
1497 * Test for the Autodesk Animator FLI/FLC format.
1498 *
1499 * Not to be confused with Commodore 64 FLI.
1500 */
Test_FLI(T_IO_Context * context,FILE * file)1501 void Test_FLI(T_IO_Context * context, FILE * file)
1502 {
1503 T_FLIC_Header header;
1504 (void)context;
1505
1506 File_error=0;
1507 Load_FLI_Header(file, &header);
1508 if (File_error != 0) return;
1509
1510 switch (header.type)
1511 {
1512 case 0xAF11: // standard FLI
1513 case 0xAF12: // FLC (8bpp)
1514 #if 0
1515 case 0xAF30: // Huffman or BWT compression
1516 case 0xAF31: // frame shift compression
1517 case 0xAF44: // bpp != 8
1518 #endif
1519 File_error=0;
1520 break;
1521 default:
1522 File_error=1;
1523 }
1524 }
1525
1526 /**
1527 * Load file in the Autodesk Animator FLI/FLC format.
1528 *
1529 * Not to be confused with Commodore 64 FLI.
1530 */
Load_FLI(T_IO_Context * context)1531 void Load_FLI(T_IO_Context * context)
1532 {
1533 FILE * file;
1534 unsigned long file_size;
1535 T_FLIC_Header header;
1536 dword chunk_size;
1537 word chunk_type;
1538 word sub_chunk_count, sub_chunk_index;
1539 dword sub_chunk_size;
1540 word sub_chunk_type;
1541 word frame_delay, frame_width, frame_height;
1542 int current_frame = 0;
1543
1544 file = Open_file_read(context);
1545 if (file == NULL)
1546 {
1547 File_error=1;
1548 return;
1549 }
1550 File_error=0;
1551 file_size = File_length_file(file);
1552 Load_FLI_Header(file, &header);
1553 if (File_error != 0)
1554 {
1555 fclose(file);
1556 return;
1557 }
1558 if (header.size == 12)
1559 {
1560 // special "magic carpet" format
1561 header.depth = 8;
1562 header.speed = 66; // about 15fps
1563 fseek(file, 12, SEEK_SET);
1564 }
1565 else if (file_size != header.size)
1566 GFX2_Log(GFX2_WARNING, "Load_FLI(): file size mismatch in header %lu != %u\n", file_size, header.size);
1567
1568 if (header.speed == 0)
1569 {
1570 if (header.type == 0xAF11) // FLI
1571 header.speed = 1; // 1/70th seconds
1572 else
1573 header.speed = 10; // 10ms
1574 }
1575
1576 while (File_error == 0
1577 && Read_dword_le(file,&chunk_size) && Read_word_le(file,&chunk_type))
1578 {
1579 chunk_size -= 6;
1580 switch (chunk_type)
1581 {
1582 case 0xf1fa: // FRAME
1583 Read_word_le(file, &sub_chunk_count);
1584 Read_word_le(file, &frame_delay);
1585 fseek(file, 2, SEEK_CUR);
1586 Read_word_le(file, &frame_width);
1587 Read_word_le(file, &frame_height);
1588 if (frame_width == 0)
1589 frame_width = header.width;
1590 if (frame_height == 0)
1591 frame_height = header.height;
1592 if (frame_delay == 0)
1593 frame_delay = header.speed;
1594 chunk_size -= 10;
1595
1596 if (current_frame == 0)
1597 {
1598 Pre_load(context, header.width,header.height,file_size,FORMAT_FLI,PIXEL_SIMPLE,header.depth);
1599 Set_image_mode(context, IMAGE_MODE_ANIMATION);
1600 if (Config.Clear_palette)
1601 memset(context->Palette,0,sizeof(T_Palette));
1602 }
1603 else
1604 {
1605 Set_loading_layer(context, current_frame);
1606 if (context->Type == CONTEXT_MAIN_IMAGE && Get_image_mode(context) == IMAGE_MODE_ANIMATION)
1607 {
1608 // Copy the content of previous frame
1609 memcpy(
1610 Main.backups->Pages->Image[Main.current_layer].Pixels,
1611 Main.backups->Pages->Image[Main.current_layer-1].Pixels,
1612 Main.backups->Pages->Width*Main.backups->Pages->Height);
1613 }
1614 }
1615 if (header.type == 0xAF11) // FLI
1616 Set_frame_duration(context, (frame_delay * 100) / 7); // 1/70th sec
1617 else
1618 Set_frame_duration(context, frame_delay); // msec
1619 current_frame++;
1620
1621 for (sub_chunk_index = 0; sub_chunk_index < sub_chunk_count; sub_chunk_index++)
1622 {
1623 if (!(Read_dword_le(file,&sub_chunk_size) && Read_word_le(file,&sub_chunk_type)))
1624 File_error = 1;
1625 else
1626 {
1627 chunk_size -= sub_chunk_size;
1628 sub_chunk_size -= 6;
1629 if (sub_chunk_type == 0x04 || sub_chunk_type == 0x0b) // color map
1630 {
1631 word packet_count;
1632 int i = 0;
1633 sub_chunk_size -= 2;
1634 if (!Read_word_le(file, &packet_count))
1635 File_error = 1;
1636 else
1637 while (packet_count-- > 0 && File_error == 0)
1638 {
1639 byte skip, count;
1640 if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1641 File_error = 1;
1642 else
1643 {
1644 sub_chunk_size -= 2;
1645 i += skip; // count 0 means 256
1646 do
1647 {
1648 byte r, g, b;
1649 if (!(Read_byte(file, &r) && Read_byte(file, &g) && Read_byte(file, &b)))
1650 {
1651 File_error = 1;
1652 break;
1653 }
1654 if (sub_chunk_type == 0x0b || header.size == 12) // 6bit per color
1655 {
1656 r = (r << 2) | (r >> 4);
1657 g = (g << 2) | (g >> 4);
1658 b = (b << 2) | (b >> 4);
1659 }
1660 context->Palette[i].R = r;
1661 context->Palette[i].G = g;
1662 context->Palette[i].B = b;
1663 i++;
1664 sub_chunk_size -= 3;
1665 } while (--count != 0);
1666 }
1667 }
1668 }
1669 else if (sub_chunk_type == 0x0f) // full frame RLE
1670 {
1671 word x, y;
1672 for (y = 0; y < frame_height && File_error == 0; y++)
1673 {
1674 byte count, data;
1675 Read_byte(file, &count); // packet count, but dont rely on it
1676 sub_chunk_size--;
1677 for (x = 0; x < frame_width; )
1678 {
1679 if (!Read_byte(file, &count))
1680 {
1681 File_error = 1;
1682 break;
1683 }
1684 sub_chunk_size--;
1685 if ((count & 0x80) == 0)
1686 {
1687 if (!Read_byte(file, &data)) // repeat data count times
1688 {
1689 File_error = 1;
1690 break;
1691 }
1692 sub_chunk_size--;
1693 while (count-- > 0 && x < frame_width)
1694 Set_pixel(context, x++, y, data);
1695 }
1696 else
1697 while (count++ != 0 && x < frame_width) // copy count bytes
1698 {
1699 if (!Read_byte(file, &data))
1700 {
1701 File_error = 1;
1702 break;
1703 }
1704 Set_pixel(context, x++, y, data);
1705 sub_chunk_size--;
1706 }
1707 }
1708 }
1709 if (context->Type == CONTEXT_PREVIEW || context->Type == CONTEXT_PREVIEW_PALETTE)
1710 { // load only 1st frame in preview
1711 fclose(file);
1712 return;
1713 }
1714 }
1715 else if (sub_chunk_type == 0x0c) // delta image, RLE
1716 {
1717 word x, y, line_count;
1718
1719 Read_word_le(file, &y);
1720 Read_word_le(file, &line_count);
1721 sub_chunk_size -= 4;
1722 while (sub_chunk_size > 0 && line_count > 0 && File_error == 0)
1723 {
1724 byte packet_count;
1725
1726 x = 0;
1727 if (!Read_byte(file, &packet_count))
1728 File_error = 1;
1729 else
1730 {
1731 sub_chunk_size--;
1732 while (packet_count-- > 0 && File_error == 0)
1733 {
1734 byte skip, count, data;
1735 if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1736 File_error = 1;
1737 else
1738 {
1739 sub_chunk_size -= 2;
1740 x += skip;
1741 if (count & 0x80)
1742 {
1743 Read_byte(file, &data);
1744 sub_chunk_size--;
1745 while (count++ != 0)
1746 Set_pixel(context, x++, y, data);
1747 }
1748 else
1749 while (count-- > 0)
1750 {
1751 Read_byte(file, &data);
1752 sub_chunk_size--;
1753 Set_pixel(context, x++, y, data);
1754 }
1755 }
1756 }
1757 }
1758 y++;
1759 line_count--;
1760 }
1761 }
1762 else if (sub_chunk_type == 0x07) // FLC delta image
1763 {
1764 word opcode, y, line_count;
1765
1766 y = 0;
1767 Read_word_le(file, &line_count);
1768 sub_chunk_size -= 2;
1769 while (line_count > 0)
1770 {
1771 Read_word_le(file, &opcode);
1772 sub_chunk_size -= 2;
1773 if ((opcode & 0xc000) == 0x0000) // packet count
1774 {
1775 word x = 0;
1776 while (opcode-- > 0)
1777 {
1778 byte skip, count, data1, data2;
1779 if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1780 File_error = 1;
1781 else
1782 {
1783 sub_chunk_size -= 2;
1784 x += skip;
1785 if (count & 0x80)
1786 {
1787 Read_byte(file, &data1);
1788 Read_byte(file, &data2);
1789 sub_chunk_size -= 2;
1790 while (count++ != 0)
1791 {
1792 Set_pixel(context, x++, y, data1);
1793 Set_pixel(context, x++, y, data2);
1794 }
1795 }
1796 else
1797 while (count-- > 0)
1798 {
1799 Read_byte(file, &data1);
1800 Set_pixel(context, x++, y, data1);
1801 Read_byte(file, &data2);
1802 Set_pixel(context, x++, y, data2);
1803 sub_chunk_size -= 2;
1804 }
1805 }
1806 }
1807 y++;
1808 line_count--;
1809 }
1810 else if ((opcode & 0xc000) == 0xc000) // line skip
1811 {
1812 y -= opcode;
1813 }
1814 else if ((opcode & 0xc000) == 0x8000) // last byte
1815 {
1816 Set_pixel(context, frame_width - 1, y, opcode & 0xff);
1817 }
1818 else
1819 {
1820 GFX2_Log(GFX2_WARNING, "Unsupported opcode %04x\n", opcode);
1821 File_error = 2;
1822 break;
1823 }
1824 }
1825 }
1826 if (sub_chunk_size > 0)
1827 {
1828 fseek(file, sub_chunk_size, SEEK_CUR);
1829 }
1830 }
1831 }
1832 break;
1833 default: // skip
1834 GFX2_Log(GFX2_WARNING, "Load_FLI(): unrecognized chunk %04x\n", chunk_type);
1835 }
1836 if (chunk_size > 0 && header.size != 12)
1837 {
1838 fseek(file, chunk_size, SEEK_CUR);
1839 }
1840 }
1841 fclose(file);
1842 }
1843
1844 /////////////////////////////// Apple II Files //////////////////////////////
1845
1846 /**
1847 * Test for an Apple II HGR or DHGR raw file
1848 */
Test_HGR(T_IO_Context * context,FILE * file)1849 void Test_HGR(T_IO_Context * context, FILE * file)
1850 {
1851 long file_size;
1852
1853 (void)context;
1854 File_error = 1;
1855
1856 file_size = File_length_file(file);
1857 if (file_size == 8192) // HGR
1858 File_error = 0;
1859 else if(file_size == 16384) // DHGR
1860 File_error = 0;
1861 }
1862
1863 /**
1864 * Load HGR (280x192) or DHGR (560x192) Apple II pictures
1865 *
1866 * Creates 2 layers :
1867 * 1. Monochrome
1868 * 2. Color
1869 */
Load_HGR(T_IO_Context * context)1870 void Load_HGR(T_IO_Context * context)
1871 {
1872 unsigned long file_size;
1873 FILE * file;
1874 byte * vram[2];
1875 int bank;
1876 int x, y;
1877 int is_dhgr = 0;
1878
1879 file = Open_file_read(context);
1880 if (file == NULL)
1881 {
1882 File_error = 1;
1883 return;
1884 }
1885 file_size = File_length_file(file);
1886 if (file_size == 16384)
1887 is_dhgr = 1;
1888
1889 vram[0] = GFX2_malloc(8192);
1890 Read_bytes(file, vram[0], 8192);
1891 if (is_dhgr)
1892 {
1893 vram[1] = GFX2_malloc(8192);
1894 Read_bytes(file, vram[1], 8192);
1895 }
1896 else
1897 vram[1] = NULL;
1898 fclose(file);
1899
1900 if (Config.Clear_palette)
1901 memset(context->Palette,0,sizeof(T_Palette));
1902 if (is_dhgr)
1903 {
1904 DHGR_set_palette(context->Palette);
1905 Pre_load(context, 560, 192, file_size, FORMAT_HGR, PIXEL_TALL, 4);
1906 }
1907 else
1908 {
1909 HGR_set_palette(context->Palette);
1910 Pre_load(context, 280, 192, file_size, FORMAT_HGR, PIXEL_SIMPLE, 2);
1911 }
1912 for (y = 0; y < 192; y++)
1913 {
1914 byte palette = 0, color = 0;
1915 byte previous_palette = 0; // palette for the previous pixel pair
1916 int column, i;
1917 int offset = ((y & 7) << 10) + ((y & 070) << 4) + ((y >> 6) * 40);
1918 x = 0;
1919 for (column = 0; column < 40; column++)
1920 for (bank = 0; bank <= is_dhgr; bank++)
1921 {
1922 byte b = vram[bank][offset+column];
1923 if (!is_dhgr)
1924 palette = (b & 0x80) ? 4 : 0;
1925 else
1926 palette = (b & 0x80) ? 0 : 16;
1927 for (i = 0; i < 7; i++)
1928 {
1929 if (context->Type == CONTEXT_MAIN_IMAGE)
1930 {
1931 // monochrome
1932 Set_loading_layer(context, 0);
1933 Set_pixel(context, x, y, ((b & 1) * (is_dhgr ? 15 : 3)) + palette);
1934 Set_loading_layer(context, 1);
1935 }
1936 // color
1937 color = (color << 1) | (b & 1);
1938 if (is_dhgr)
1939 {
1940 if ((x & 3) == 0)
1941 previous_palette = palette; // what is important is the value when the 1st bit was read...
1942 /// emulate "chat mauve" DHGR mixed mode.
1943 /// see http://boutillon.free.fr/Underground/Anim_Et_Graph/Extasie_Chat_Mauve_Reloaded/Extasie_Chat_Mauve_Reloaded.html
1944 if (previous_palette) // BW
1945 Set_pixel(context, x, y, ((b & 1) * 15) + palette);
1946 else if ((x & 3) == 3)
1947 {
1948 Set_pixel(context, x - 3, y, (color & 15) + palette);
1949 Set_pixel(context, x - 2, y, (color & 15) + palette);
1950 Set_pixel(context, x - 1, y, (color & 15) + palette);
1951 Set_pixel(context, x, y, (color & 15) + palette);
1952 }
1953 }
1954 else
1955 {
1956 /// HGR emulation following the behaviour of a "Le Chat Mauve"
1957 /// RVB adapter for the Apple //c.
1958 /// Within the bit stream, the color of the middle pixel is :<br>
1959 /// <tt>
1960 /// 111 \ <br>
1961 /// 110 }- white <br>
1962 /// 011 / <br>
1963 /// 010 \ _ color <br>
1964 /// 101 / <br>
1965 /// 000 \ <br>
1966 /// 001 }- black <br>
1967 /// 100 / <br>
1968 /// </tt>
1969 /// Color depends on the selected palette for the current byte
1970 /// and the position of the pixel (odd or even).
1971 if ((color & 3) == 3) // 11 => white
1972 {
1973 Set_pixel(context, x - 1, y, 3 + previous_palette);
1974 Set_pixel(context, x, y, 3 + palette);
1975 }
1976 else if ((color & 1) == 0) // 0 => black
1977 Set_pixel(context, x, y, palette);
1978 else // 01 => color
1979 {
1980 if ((color & 7) == 5) // 101
1981 Set_pixel(context, x - 1, y, 2 - (x & 1) + previous_palette);
1982 Set_pixel(context, x, y, 2 - (x & 1) + palette);
1983 }
1984 previous_palette = palette;
1985 }
1986 b >>= 1;
1987 x++;
1988 }
1989 }
1990 }
1991 // show hidden data in HOLES
1992 for (y = 0; y < 64; y++)
1993 for (bank = 0; bank < 1; bank++)
1994 {
1995 byte b = 0;
1996 for (x = 0; x < 8; x++)
1997 b |= vram[bank][x + (y << 7) + 120];
1998 if (b != 0)
1999 GFX2_LogHexDump(GFX2_DEBUG, bank ? "AUX " : "MAIN", vram[bank], (y << 7) + 120, 8);
2000 }
2001 free(vram[0]);
2002 free(vram[1]);
2003 File_error = 0;
2004
2005 Set_image_mode(context, is_dhgr ? IMAGE_MODE_DHGR : IMAGE_MODE_HGR);
2006 }
2007
2008 /**
2009 * Save HGR (280x192) or DHGR (560x192) Apple II pictures
2010 *
2011 * The data saved is the "monochrome" data from layer 1
2012 */
Save_HGR(T_IO_Context * context)2013 void Save_HGR(T_IO_Context * context)
2014 {
2015 FILE * file;
2016 byte * vram[2];
2017 int bank;
2018 int x, y;
2019 int is_dhgr = 0;
2020
2021 File_error = 1;
2022 if (context->Height != 192 || (context->Width != 280 && context->Width != 560))
2023 {
2024 Warning_message("Picture must be 280x192 (HGR) or 560x192 (DHGR)");
2025 return;
2026 }
2027 if (context->Width == 560)
2028 is_dhgr = 1;
2029
2030 file = Open_file_write(context);
2031 if (file == NULL)
2032 return;
2033 vram[0] = calloc(8192, 1);
2034 if (vram[0] == NULL)
2035 {
2036 fclose(file);
2037 return;
2038 }
2039 if (is_dhgr)
2040 {
2041 vram[1] = calloc(8192, 1);
2042 if (vram[1] == NULL)
2043 {
2044 free(vram[0]);
2045 fclose(file);
2046 return;
2047 }
2048 }
2049 else
2050 vram[1] = NULL;
2051
2052 Set_saving_layer(context, 0); // "monochrome" layer
2053 for (y = 0; y < 192; y++)
2054 {
2055 int i, column = 0;
2056 int offset = ((y & 7) << 10) + ((y & 070) << 4) + ((y >> 6) * 40);
2057 x = 0;
2058 bank = 0;
2059 while (x < context->Width)
2060 {
2061 byte b;
2062 if (is_dhgr)
2063 b = (Get_pixel(context, x, y) & 16) ? 0 : 0x80;
2064 else
2065 b = (Get_pixel(context, x, y) & 4) ? 0x80 : 0;
2066 for (i = 0; i < 7; i++)
2067 {
2068 b = b | ((Get_pixel(context, x++, y) & 1) << i);
2069 }
2070 vram[bank][offset + column] = b;
2071 if (is_dhgr)
2072 {
2073 if (++bank > 1)
2074 {
2075 bank = 0;
2076 column++;
2077 }
2078 }
2079 else
2080 column++;
2081 }
2082 }
2083
2084 if (Write_bytes(file, vram[0], 8192))
2085 {
2086 if (is_dhgr)
2087 {
2088 if (Write_bytes(file, vram[1], 8192))
2089 File_error = 0;
2090 }
2091 else
2092 File_error = 0;
2093 }
2094
2095 free(vram[0]);
2096 free(vram[1]);
2097 fclose(file);
2098 }
2099
2100
2101 ///////////////////////////// HP-48 Grob Files ////////////////////////////
2102
2103 /**
2104 * HP48 addresses are 20bits (5 nibbles)
2105 * offset is in nibble (half byte)
2106 */
Read_HP48Address(const byte * buffer,int offset)2107 static dword Read_HP48Address(const byte * buffer, int offset)
2108 {
2109 dword data = 0;
2110 int i = 4;
2111 do
2112 {
2113 byte nibble;
2114 nibble = buffer[(offset + i) >> 1];
2115 if ((offset + i) & 1)
2116 nibble >>= 4;
2117 nibble &= 15;
2118 data = (data << 4) | nibble;
2119 }
2120 while (i-- > 0);
2121 return data;
2122 }
2123
2124 /**
2125 * Test for a HP-48 Grob file
2126 */
Test_GRB(T_IO_Context * context,FILE * file)2127 void Test_GRB(T_IO_Context * context, FILE * file)
2128 {
2129 byte buffer[18];
2130 unsigned long file_size;
2131 dword prologue, size, width, height;
2132
2133 (void)context;
2134 File_error = 1;
2135 file_size = File_length_file(file);
2136 if (!Read_bytes(file, buffer, 18))
2137 return;
2138 if(memcmp(buffer, "HPHP48-R", 8) != 0)
2139 return;
2140 prologue = Read_HP48Address(buffer+8, 0);
2141 size = Read_HP48Address(buffer+8, 5);
2142 GFX2_Log(GFX2_DEBUG, "HP48 File detected. %lu bytes prologue %05x %u nibbles\n",
2143 file_size, prologue, size);
2144 if (prologue != 0x02b1e)
2145 return;
2146 height = Read_HP48Address(buffer+8, 10);
2147 width = Read_HP48Address(buffer+8, 15);
2148 GFX2_Log(GFX2_DEBUG, " Grob dimensions : %ux%u\n", width, height);
2149 if ((file_size - 8) < ((size + 5) / 2))
2150 return;
2151 if (file_size < (18 + ((width + 7) >> 3) * height))
2152 return;
2153 File_error = 0;
2154 }
2155
Load_GRB(T_IO_Context * context)2156 void Load_GRB(T_IO_Context * context)
2157 {
2158 byte buffer[18];
2159 byte * bitplane[4];
2160 unsigned long file_size;
2161 dword prologue, size, width, height;
2162 byte bp, bpp;
2163 FILE * file;
2164 unsigned x, y;
2165
2166 File_error = 1;
2167 file = Open_file_read(context);
2168 if (file == NULL)
2169 return;
2170 file_size = File_length_file(file);
2171 if (!Read_bytes(file, buffer, 18))
2172 {
2173 fclose(file);
2174 return;
2175 }
2176 prologue = Read_HP48Address(buffer+8, 0);
2177 size = Read_HP48Address(buffer+8, 5);
2178 height = Read_HP48Address(buffer+8, 10);
2179 width = Read_HP48Address(buffer+8, 15);
2180 if (height >= 256)
2181 bpp = 4;
2182 else if (height >= 192)
2183 bpp = 3;
2184 else if (height >= 128)
2185 bpp = 2;
2186 else
2187 bpp = 1;
2188
2189 GFX2_Log(GFX2_DEBUG, "HP48: %05X size=%u %ux%u\n", prologue, size, width, height);
2190
2191 File_error = 0;
2192 Pre_load(context, width, height/bpp, file_size, FORMAT_GRB, PIXEL_SIMPLE, bpp);
2193 if (File_error == 0)
2194 {
2195 dword bytes_per_plane = ((width + 7) >> 3) * (height/bpp);
2196 dword offset = 0;
2197
2198 if (Config.Clear_palette)
2199 memset(context->Palette, 0, sizeof(T_Palette));
2200 for (x = 0; x < ((unsigned)1 << bpp); x++)
2201 {
2202 context->Palette[x].R = context->Palette[x].G = (x * 255) / ((1 << bpp) - 1);
2203 context->Palette[x].B = 127;
2204 }
2205
2206 // Load all bit planes
2207 for (bp = 0; bp < bpp; bp++)
2208 {
2209 bitplane[bp] = GFX2_malloc(bytes_per_plane);
2210 if (bitplane[bp])
2211 {
2212 if (!Read_bytes(file, bitplane[bp], bytes_per_plane))
2213 File_error = 1;
2214 }
2215 }
2216 // set pixels
2217 for (y = 0; y < (height/bpp) && File_error == 0; y++)
2218 {
2219 for (x = 0; x < width; x++)
2220 {
2221 byte b = 0;
2222 for (bp = 0; bp < bpp; bp++)
2223 b |= ((bitplane[bp][offset] >> (x & 7)) & 1) << bp;
2224 // invert because 1 is a black pixel on HP-48 LCD display
2225 Set_pixel(context, x, y, b ^ ((1 << bpp) - 1));
2226 if ((x & 7) == 7)
2227 offset++;
2228 }
2229 if ((x & 7) != 7)
2230 offset++;
2231 }
2232 // Free bit planes
2233 for (bp = 0; bp < bpp; bp++)
2234 free(bitplane[bp]);
2235 }
2236 fclose(file);
2237 }
2238