rnd-19980930-1
[rocksndiamonds.git] / src / msdos.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  msdos.c                                                 *
12 ***********************************************************/
13
14 #ifdef MSDOS
15 #include "main.h"
16 #include "tools.h"
17 #include "sound.h"
18 #include "files.h"
19 #include "joystick.h"
20
21 DECLARE_GFX_DRIVER_LIST(
22         GFX_DRIVER_VBEAF
23         GFX_DRIVER_VESA2L
24         GFX_DRIVER_VESA1)
25 DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8)
26 DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB)
27 DECLARE_MIDI_DRIVER_LIST()
28 DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD)
29
30 static int key_buffer[OSD_MAX_KEY];
31 static XEvent event_buffer[MAX_EVENT_BUFFER];
32 static int pending_events;
33 static BOOL joystick_event;
34 static BOOL mouse_installed = FALSE;
35 static int last_mouse_pos;
36 static int last_mouse_b;
37 static int last_joystick_state;
38 static BITMAP* video_bitmap;
39
40 BOOL wait_for_vsync;
41
42 extern int playing_sounds;
43 extern struct SoundControl playlist[MAX_SOUNDS_PLAYING];
44 extern struct SoundControl emptySoundControl;
45
46 void allegro_drivers()
47 {
48   int i;
49
50   for(i = 0; i < MAX_EVENT_BUFFER; i++);
51         event_buffer[i].type = 0;
52   for(i=0; i < OSD_MAX_KEY; i++) key_buffer[i] = KeyReleaseMask;
53   last_mouse_pos = mouse_pos;
54   last_mouse_b = 0;
55
56   pending_events = 0;
57   clear_keybuf();
58
59   i_love_bill = TRUE;
60   install_keyboard();
61   install_timer();
62   if (install_mouse() > 0) mouse_installed = TRUE;
63   install_joystick(JOY_TYPE_2PADS);
64
65   load_joystick_data(JOYDAT_FILE);
66   last_joystick_state = 0;
67   joystick_event = FALSE;
68
69   reserve_voices(MAX_SOUNDS_PLAYING, 0);
70   if(install_sound(DIGI_AUTODETECT, MIDI_NONE, "ROCKS.SND") == -1)
71     if(install_sound(DIGI_SB, MIDI_NONE, NULL) == -1) sound_status = SOUND_OFF;
72
73 }
74
75 BOOL hide_mouse(Display *display, int x, int y, unsigned int width, unsigned int height)
76 {
77   if(mouse_x + display->mouse_ptr->w < x || mouse_x > x+width) return FALSE;
78   if(mouse_y + display->mouse_ptr->h < y || mouse_y > y+height) return FALSE;
79   show_mouse(NULL);
80   return(TRUE);
81 }
82
83 void unhide_mouse(Display *display)
84 {
85   if(mouse_installed) show_mouse(video_bitmap);
86 }
87
88 int get_joystick_state()
89 {
90   int state = 0;
91   poll_joystick();
92
93   if (joy[joystick_nr].stick[0].axis[0].d1) state |= JOY_LEFT;
94   if (joy[joystick_nr].stick[0].axis[0].d2) state |= JOY_RIGHT;
95   if (joy[joystick_nr].stick[0].axis[1].d1) state |= JOY_UP;
96   if (joy[joystick_nr].stick[0].axis[1].d2) state |= JOY_DOWN;
97   if (joy[joystick_nr].button[0].b) state |= JOY_BUTTON_1;
98
99   switch (state)
100   {
101     case (JOY_DOWN | JOY_LEFT):
102         state = XK_KP_1;
103         break;
104     case (JOY_DOWN):
105         state = XK_KP_2;
106         break;
107     case (JOY_DOWN | JOY_RIGHT):
108         state = XK_KP_3;
109         break;
110     case (JOY_LEFT):
111         state = XK_KP_4;
112         break;
113     case (JOY_RIGHT):
114         state = XK_KP_6;
115         break;
116     case (JOY_UP | JOY_LEFT):
117         state = XK_KP_7;
118         break;
119     case (JOY_UP):
120         state = XK_KP_8;
121         break;
122     case (JOY_UP | JOY_RIGHT):
123         state = XK_KP_9;
124         break;
125
126     case (JOY_DOWN | JOY_BUTTON_1):
127         state = XK_X;
128         break;
129     case (JOY_LEFT | JOY_BUTTON_1):
130         state = XK_S;
131         break;
132     case (JOY_RIGHT | JOY_BUTTON_1):
133         state = XK_D;
134         break;
135     case (JOY_UP | JOY_BUTTON_1):
136         state = XK_E;
137         break;
138  
139    default:
140         state = 0;
141   }
142
143   return(state);
144 }
145
146 unsigned char get_ascii(KeySym key)
147 {
148   switch(key) {
149
150         case OSD_KEY_Q: return 'Q';
151         case OSD_KEY_W: return 'W';
152         case OSD_KEY_E: return 'E';
153         case OSD_KEY_R: return 'R';
154         case OSD_KEY_T: return 'T';
155         case OSD_KEY_Y: return 'Y';
156         case OSD_KEY_U: return 'U';
157         case OSD_KEY_I: return 'I';
158         case OSD_KEY_O: return 'O';
159         case OSD_KEY_P: return 'P';
160         case OSD_KEY_A: return 'A';
161         case OSD_KEY_S: return 'S';
162         case OSD_KEY_D: return 'D';
163         case OSD_KEY_F: return 'F';
164         case OSD_KEY_G: return 'G';
165         case OSD_KEY_H: return 'H';
166         case OSD_KEY_J: return 'J';
167         case OSD_KEY_K: return 'K';
168         case OSD_KEY_L: return 'L';
169         case OSD_KEY_Z: return 'Z';
170         case OSD_KEY_X: return 'X';
171         case OSD_KEY_C: return 'C';
172         case OSD_KEY_V: return 'V';
173         case OSD_KEY_B: return 'B';
174         case OSD_KEY_N: return 'N';
175         case OSD_KEY_M: return 'M';
176         case OSD_KEY_1: return '1';
177         case OSD_KEY_2: return '2';
178         case OSD_KEY_3: return '3';
179         case OSD_KEY_4: return '4';
180         case OSD_KEY_5: return '5';
181         case OSD_KEY_6: return '6';
182         case OSD_KEY_7: return '7';
183         case OSD_KEY_8: return '8';
184         case OSD_KEY_9: return '9';
185         case OSD_KEY_0: return '0';
186         case OSD_KEY_SPACE: return ' ';
187  }
188   return (0);
189 }
190
191 long osd_key_pressed(int keycode)
192 {
193   if (keycode == OSD_KEY_RCONTROL) keycode = KEY_RCONTROL;
194   if (keycode == OSD_KEY_ALTGR) keycode = KEY_ALTGR;
195
196   if (key[keycode])
197         return(KeyPressMask);
198   else
199         return(KeyReleaseMask);
200 }
201
202 void XMapWindow(Display* display, Window w)
203 {
204   int x, y;
205   unsigned int width, height;
206   BOOL mouse_off;
207
208   x = display->screens[display->default_screen].x;
209   y = display->screens[display->default_screen].y;
210   width = display->screens[display->default_screen].width;
211   height = display->screens[display->default_screen].height;
212
213   mouse_off = hide_mouse(display, x, y, width, height);
214   blit((BITMAP *)w, video_bitmap, 0, 0, x, y, width, height);
215   if(mouse_off) unhide_mouse(display);
216 }
217
218 Display *XOpenDisplay(char* dummy)
219 {
220   Screen *MyScreens;
221   Display *MyDisplay;
222   BITMAP *MyMouse = NULL;
223   RGB pal[256];
224
225   MyScreens = malloc(sizeof(Screen));
226   MyDisplay = malloc(sizeof(Display));
227
228   if(MOUSE_FILENAME)
229           MyMouse = load_gif(MOUSE_FILENAME, pal);
230
231   MyScreens[0].cmap = 0;
232   MyScreens[0].root = 0;
233   MyScreens[0].white_pixel = 0xFF;
234   MyScreens[0].black_pixel = 0x00;
235   MyScreens[0].video_bitmap = NULL;
236
237   MyDisplay->default_screen = 0;
238   MyDisplay->screens = MyScreens;
239   MyDisplay->mouse_ptr = MyMouse;
240
241   allegro_init();
242   allegro_drivers();
243   set_color_depth(8);
244   set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0); // force Windows 95 to switch to fullscreen mode
245   rest(200);
246   set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0);
247
248   return(MyDisplay);
249 }
250
251 Window XCreateSimpleWindow(
252         Display* display,
253         Window parent,
254         int x,
255         int y,
256         unsigned int width,
257         unsigned int height,
258         unsigned int border_width,
259         unsigned long border,
260         unsigned long background)
261 {
262   video_bitmap = create_video_bitmap(XRES, YRES);
263   clear_to_color(video_bitmap, background);
264
265   display->screens[display->default_screen].video_bitmap = video_bitmap;
266   display->screens[display->default_screen].x = x;
267   display->screens[display->default_screen].y = y;
268   display->screens[display->default_screen].width = XRES;
269   display->screens[display->default_screen].height = YRES;
270
271   set_mouse_sprite(display->mouse_ptr);
272   set_mouse_range(display->screens[display->default_screen].x+1,
273                   display->screens[display->default_screen].y+1,
274                   display->screens[display->default_screen].x+WIN_XSIZE+1,
275                   display->screens[display->default_screen].y+WIN_YSIZE+1);
276
277   show_video_bitmap(video_bitmap);
278
279   return((Window) video_bitmap);
280 }
281
282 int XReadBitmapFile(
283         Display* display,
284         Drawable d,
285         char* filename,
286         unsigned int* width_return,
287         unsigned int* height_return,
288         Pixmap* bitmap_return,
289         int* x_hot_return,
290         int* y_hot_return)
291 {
292   BITMAP *bmp;
293   RGB pal[256];
294
295   if((bmp = load_gif(filename, pal)) == NULL)
296         return(BitmapOpenFailed);
297
298   *width_return = bmp->w;
299   *height_return = bmp->h;
300   *x_hot_return = -1;
301   *y_hot_return = -1;
302   *bitmap_return = (Pixmap) bmp;
303
304   return(BitmapSuccess);
305 }
306
307 Status XStringListToTextProperty(char** list, int count, XTextProperty* text_prop_return)
308 {
309   char *string;
310
311   if(count >= 1)
312   {
313         string = malloc(strlen(list[0]+1));
314         strcpy(string, list[0]);
315         text_prop_return->value = (unsigned char *) string;
316         return(1);
317   }
318   else
319   {
320         text_prop_return = NULL;
321   }
322     return(0);
323 }
324
325 void XFree(void* data)
326 {
327   if(data) free(data);
328 }
329
330 GC XCreateGC(Display* display, Drawable d, unsigned long value_mask, XGCValues* values)
331 {
332   XGCValues *gcv;
333   gcv = malloc(sizeof(XGCValues));
334   gcv->foreground = values->foreground;
335   gcv->background = values->background;
336   gcv->graphics_exposures = values->graphics_exposures;
337   gcv->clip_mask = values->clip_mask;
338   gcv->clip_x_origin = values->clip_x_origin;
339   gcv->clip_y_origin = values->clip_y_origin;
340   gcv->value_mask = value_mask;
341   return((GC) gcv);
342 }
343
344 void XFillRectangle(
345         Display* display,
346         Drawable d,
347         GC gc,
348         int x,
349         int y,
350         unsigned int width,
351         unsigned int height)
352 {
353   BOOL mouse_off;
354
355   if((BITMAP *) d == video_bitmap)
356   {
357         x += display->screens[display->default_screen].x;
358         y += display->screens[display->default_screen].y;
359         freeze_mouse_flag = TRUE;
360         mouse_off = hide_mouse(display, x, y, width, height);
361   }
362
363   rectfill((BITMAP *) d, x, y, x+width, y+height, ((XGCValues *)gc)->foreground);
364   if(mouse_off) unhide_mouse(display);
365   freeze_mouse_flag = FALSE;
366 }
367
368 Pixmap XCreatePixmap(
369         Display* display,
370         Drawable d,
371         unsigned int width,
372         unsigned int height,
373         unsigned int depth)
374 {
375   BITMAP *MyBitmap = NULL;
376
377   if(GFX_HW_VRAM_BLIT&gfx_capabilities && width == FXSIZE && height == FYSIZE)
378     MyBitmap = create_video_bitmap(width, height);
379
380   if(MyBitmap == NULL)
381     MyBitmap = create_bitmap(width, height);
382
383   return((Pixmap) MyBitmap);
384 }
385
386 inline void XCopyArea(
387         Display* display,
388         Drawable src,
389         Drawable dest,
390         GC gc,
391         int src_x,
392         int src_y,
393         unsigned int width,
394         unsigned int height,
395         int dest_x,
396         int dest_y)
397 {
398   BOOL mouse_off;
399
400   if((BITMAP *) src == video_bitmap )
401   {
402         src_x += display->screens[display->default_screen].x;
403         src_y += display->screens[display->default_screen].y;
404   }
405   if((BITMAP *) dest == video_bitmap )
406   {
407         dest_x += display->screens[display->default_screen].x;
408         dest_y += display->screens[display->default_screen].y;
409         freeze_mouse_flag = TRUE;
410         mouse_off = hide_mouse(display, dest_x, dest_y, width, height);
411   }
412
413   if(wait_for_vsync)
414   {
415     wait_for_vsync = FALSE;
416     vsync();
417   }
418
419   if(((XGCValues *)gc)->value_mask&GCClipMask)
420     masked_blit((BITMAP *) src, (BITMAP *) dest, src_x, src_y, dest_x, dest_y, width, height);
421   else
422     blit((BITMAP *) src, (BITMAP *) dest, src_x, src_y, dest_x, dest_y, width, height);
423
424   if(mouse_off) unhide_mouse(display);
425   freeze_mouse_flag = FALSE;
426 }
427
428 int XpmReadFileToPixmap(
429         Display* display,
430         Drawable d,
431         char* filename,
432         Pixmap* pixmap_return,
433         Pixmap* shapemask_return,
434         XpmAttributes* attributes)
435 {
436   BITMAP *bmp;
437   RGB pal[256];
438
439   if((bmp = load_gif(filename, pal)) == NULL)
440         return(XpmOpenFailed);
441
442   *pixmap_return = (Pixmap) bmp;
443   set_pallete(pal);
444
445   return(XpmSuccess);
446 }
447
448 void XFreePixmap(Display* display, Pixmap pixmap)
449 {
450   if( pixmap != DUMMY_MASK &&
451      (is_memory_bitmap((BITMAP *) pixmap) || is_screen_bitmap((BITMAP *) pixmap)) )
452           destroy_bitmap((BITMAP *) pixmap);
453 }
454
455 void XFreeGC(Display* display, GC gc)
456 {
457   XGCValues *gcv;
458
459   gcv = (XGCValues *) gc;
460   if(gcv) free(gcv);
461 }
462
463 void XCloseDisplay(Display* display)
464 {
465   BITMAP * bmp;
466   bmp = video_bitmap;
467
468   if(is_screen_bitmap(bmp))
469         destroy_bitmap(bmp);
470   if(display->screens)
471         free(display->screens);
472   if(display)
473         free(display);
474 }
475
476 void XNextEvent(Display* display, XEvent* event_return)
477 {
478   while(!pending_events) XPending(display);
479
480   memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent));
481   pending_events--;
482 }
483
484 int XPending(Display* display)
485 {
486   int i, state;
487   static BOOL joy_button_2 = FALSE;
488
489   XKeyEvent *xkey;
490   XButtonEvent *xbutton;
491   XMotionEvent *xmotion;
492
493   // joystick event (simulating keyboard event)
494
495   state = get_joystick_state();
496
497   if (joy[joystick_nr].button[1].b && !joy_button_2)
498   {
499       pending_events++;
500       xkey = (XKeyEvent *) &event_buffer[pending_events];
501       xkey->type = KeyPress;
502       xkey->state = XK_B;
503       joy_button_2 = TRUE;
504   }
505   else if (!joy[joystick_nr].button[1].b && joy_button_2)
506   {
507       pending_events++;
508       xkey = (XKeyEvent *) &event_buffer[pending_events];
509       xkey->type = KeyRelease;
510       xkey->state = XK_B;
511       joy_button_2 = FALSE;
512   }
513
514   if(state && !joystick_event)
515   {
516       pending_events++;
517       xkey = (XKeyEvent *) &event_buffer[pending_events];
518       xkey->type = KeyPress;
519       xkey->state = state;
520       joystick_event = TRUE;
521       last_joystick_state = state;
522   }
523   else if((state != last_joystick_state) && joystick_event)
524   {
525       pending_events++;
526       xkey = (XKeyEvent *) &event_buffer[pending_events];
527       xkey->type = KeyRelease;
528       xkey->state = last_joystick_state;
529       joystick_event = FALSE;
530   }
531
532   // keyboard event
533
534   for(i=0; i < OSD_MAX_KEY+1 && pending_events < MAX_EVENT_BUFFER; i++)
535   {
536     state = osd_key_pressed(i);
537
538     if(state != key_buffer[i])
539     {
540         key_buffer[i] = state;
541         pending_events++;
542         xkey = (XKeyEvent *) &event_buffer[pending_events];
543         xkey->type = state&KeyPressMask ? KeyPress : KeyRelease;
544         xkey->state = i;
545     }
546   }
547
548   // mouse motion event
549
550   if((mouse_pos != last_mouse_pos && mouse_b != last_mouse_b))
551   {
552         last_mouse_pos = mouse_pos;
553         pending_events++;
554         xmotion = (XMotionEvent *) &event_buffer[pending_events];
555         xmotion->type = MotionNotify;
556         xmotion->x = mouse_x - display->screens[display->default_screen].x;
557         xmotion->y = mouse_y - display->screens[display->default_screen].y;
558         return;
559   }
560
561   // mouse button event
562
563   if(mouse_b != last_mouse_b)
564   {
565     for(i = 1; i<4; i<<=1)
566     {
567       if((last_mouse_b&i) != (mouse_b&i))
568       {
569         pending_events++;
570         xbutton = (XButtonEvent *) &event_buffer[pending_events];
571         xbutton->type = mouse_b&i ? ButtonPress : ButtonRelease;
572         xbutton->button = i;
573         xbutton->x = mouse_x - display->screens[display->default_screen].x;
574         xbutton->y = mouse_y - display->screens[display->default_screen].y;
575       }
576     }
577     last_mouse_b = mouse_b;
578   }
579
580   return pending_events;
581 }
582
583 KeySym XLookupKeysym(XKeyEvent* key_event, int index)
584 {
585   return(key_event->state);
586 }
587
588 void sound_handler(struct SoundControl snd_ctrl)
589 {
590     int i;
591
592     if (snd_ctrl.fade_sound)
593     {
594       if (!playing_sounds)
595         return;
596
597       for(i=0;i<MAX_SOUNDS_PLAYING;i++)
598         if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) && !playlist[i].fade_sound) {
599           playlist[i].fade_sound = TRUE;
600           if(voice_check(playlist[i].voice))
601             voice_ramp_volume(playlist[i].voice, 1000, 0);
602           playlist[i].loop = PSND_NO_LOOP;
603         }
604     }
605     else if (snd_ctrl.stop_all_sounds)
606     {
607       if (!playing_sounds)
608         return;
609       SoundServer_StopAllSounds();
610     }
611     else if (snd_ctrl.stop_sound)
612     {
613       if (!playing_sounds)
614         return;
615       SoundServer_StopSound(snd_ctrl.nr);
616     }
617
618     for(i=0;i<MAX_SOUNDS_PLAYING;i++)
619     {
620       if (!playlist[i].active || playlist[i].loop)
621         continue;
622
623       playlist[i].playingpos = voice_get_position(playlist[i].voice);
624       playlist[i].volume = voice_get_volume(playlist[i].voice);
625       if (playlist[i].playingpos == -1 || !playlist[i].volume)
626       {
627         deallocate_voice(playlist[i].voice);
628         playlist[i] = emptySoundControl;
629         playing_sounds--;
630       }
631     }
632
633     if (snd_ctrl.active)
634       SoundServer_InsertNewSound(snd_ctrl);
635
636 }
637
638
639 // GIF Loader
640 // by Paul Bartrum
641
642 int _color_load_depth(int depth);
643
644 struct LZW_STRING
645 {
646         short base;
647         char new;
648         short length;
649 };
650
651 PACKFILE *f;
652 int empty_string, curr_bit_size, bit_overflow;
653 int bit_pos, data_pos, data_len, entire, code;
654 int cc, string_length, i, bit_size;
655 unsigned char string[4096];
656 struct LZW_STRING str[4096];
657 BITMAP *bmp;
658 int image_x, image_y, image_w, image_h, x, y;
659 int interlace;
660
661
662 void clear_table(void)
663 {
664         empty_string = cc + 2;
665         curr_bit_size = bit_size + 1;
666         bit_overflow = 0;
667 }
668
669
670 void get_code(void)
671 {
672         if(bit_pos + curr_bit_size > 8) {
673                 if(data_pos >= data_len) { data_len = pack_getc(f); data_pos = 0; }
674                 entire = (pack_getc(f) << 8) + entire;
675                 data_pos ++;
676         }
677         if(bit_pos + curr_bit_size > 16) {
678                 if(data_pos >= data_len) { data_len = pack_getc(f); data_pos = 0; }
679                 entire = (pack_getc(f) << 16) + entire;
680                 data_pos ++;
681         }
682         code = (entire >> bit_pos) & ((1 << curr_bit_size) - 1);
683         if(bit_pos + curr_bit_size > 8)
684                 entire >>= 8;
685         if(bit_pos + curr_bit_size > 16)
686                 entire >>= 8;
687         bit_pos = (bit_pos + curr_bit_size) % 8;
688         if(bit_pos == 0) {
689                 if(data_pos >= data_len) { data_len = pack_getc(f); data_pos = 0; }
690                 entire = pack_getc(f);
691                 data_pos ++;
692         }
693 }
694
695
696 void get_string(int num)
697 {
698         if(num < cc)
699         {
700                 string_length = 1;
701                 string[0] = str[num].new;
702         }
703         else
704         {
705                 i = str[num].length;
706                 string_length = i;
707                 while(i > 0)
708                 {
709                         i --;
710                         string[i] = str[num].new;
711                         num = str[num].base;
712                 }
713                 /* if(num != -1) **-{[ERROR]}-** */
714         }
715 }
716
717
718 void output_string(void)
719 {
720         for(i = 0; i < string_length; i ++)
721         {
722                 putpixel(bmp, x, y, string[i]);
723                 x ++;
724                 if(x >= image_x + image_w)
725                 {
726                         x = image_x;
727                         y += interlace;
728                         if(interlace)
729                         {
730                                 if(y >= image_y + image_h)
731                                 {
732                                         if(interlace == 8 && (y - image_y) % 8 == 0) {
733                                                 interlace = 8;
734                                                 y = image_y + 4;
735                                         }
736                                         else if(interlace == 8  && (y - image_y) % 8 == 4) {
737                                                 interlace = 4;
738                                                 y = image_y + 2;
739                                         }
740                                         else if(interlace == 4) {
741                                                 interlace = 2;
742                                                 y = image_y + 1;
743                                         }
744                                 }
745                         }
746                 }
747         }
748 }
749
750 /* load_gif:
751  *  Loads a 2-256 colour GIF file onto a bitmap, returning the bitmap
752  *  structure and storing the pallete data in the specified pallete (this
753  *  should be an array of at least 256 RGB structures).
754  */
755 BITMAP *load_gif(char *filename, RGB *pal)
756 {
757         int width, height, depth;
758         int old;
759         BITMAP *bmp2;
760         int dest_depth;
761
762         f = pack_fopen(filename, F_READ);
763         if (!f) /* can't open file */
764                 return NULL;
765
766         i  = pack_mgetw(f) << 8;
767         i += pack_getc(f);
768         if(i != 0x474946) /* is it really a GIF? */
769         {
770                 pack_fclose(f);
771                 return NULL;
772         }
773         pack_fseek(f, 3); /* skip version */
774
775         width = pack_igetw(f);
776         height = pack_igetw(f);
777
778         bmp = create_bitmap_ex(8, width, height);
779         if(bmp == NULL) {
780                 pack_fclose(f);
781                 return NULL;
782         }
783         clear(bmp);
784
785         i = pack_getc(f);
786         if(i & 128) /* no global colour table? */
787                 depth = (i & 7) + 1;
788         else
789                 depth = 0;
790
791         pack_fseek(f, 2);       /* skip background colour and aspect ratio */
792
793         if(pal && depth) /* only read palette if pal and depth are not 0 */
794         {
795                 for(i = 0; i < (1 << depth); i ++)
796                 {
797                         pal[i].r = pack_getc(f) / 4;
798                         pal[i].g = pack_getc(f) / 4;
799                         pal[i].b = pack_getc(f) / 4;
800                 }
801         }
802         else
803                 if(depth)
804                         pack_fseek(f, (1 << depth) * 3);
805
806         do
807         {
808                 i = pack_getc(f);
809                 switch(i)
810                 {
811                         case 0x2C: /* Image Descriptor */
812                                 image_x = pack_igetw(f);
813                                 image_y = pack_igetw(f); /* individual image dimensions */
814                                 image_w = pack_igetw(f);
815                                 image_h = pack_igetw(f);
816
817                                 i = pack_getc(f);
818                                 if(i & 64)
819                                         interlace = 8;
820                                 else
821                                         interlace = 1;
822
823                                 if(i & 128)
824                                 {
825                                         depth = (i & 7) + 1;
826                                         if(pal)
827                                         {
828                                                 for(i = 0; i < (1 << depth); i ++)
829                                                 {
830                                                         pal[i].r = pack_getc(f) / 4;
831                                                         pal[i].g = pack_getc(f) / 4;
832                                                         pal[i].b = pack_getc(f) / 4;
833                                                 }
834                                         }
835                                         else
836                                                 pack_fseek(f, (1 << depth) * 3);
837                                 }
838
839                                 /* lzw stream starts now */
840                                 bit_size = pack_getc(f);
841                                 cc = 1 << bit_size;
842
843                                 /* initialise string table */
844                                 for(i = 0; i < cc; i ++)
845                                 {
846                                         str[i].base = -1;
847                                         str[i].new = i;
848                                         str[i].length = 1;
849                                 }
850
851                                 /* initialise the variables */
852                                 bit_pos = 0;
853                                 data_len = pack_getc(f); data_pos = 0;
854                                 entire = pack_getc(f); data_pos ++;
855                                 string_length = 0; x = image_x; y = image_y;
856
857                                 /* starting code */
858                                 clear_table();
859                                 get_code();
860                                 if(code == cc)
861                                         get_code();
862                                 get_string(code);
863                                 output_string();
864                                 old = code;
865
866                                 while(TRUE)
867                                 {
868                                         get_code();
869
870                                         if(code == cc)
871                                         {
872                                                 /* starting code */
873                                                 clear_table();
874                                                 get_code();
875                                                 get_string(code);
876                                                 output_string();
877                                                 old = code;
878                                         }
879                                         else if(code == cc + 1)
880                                         {
881                                                 break;
882                                         }
883                                         else if(code < empty_string)
884                                         {
885                                                 get_string(code);
886                                                 output_string();
887
888                                                 if(bit_overflow == 0) {
889                                                         str[empty_string].base = old;
890                                                         str[empty_string].new = string[0];
891                                                         str[empty_string].length = str[old].length + 1;
892                                                         empty_string ++;
893                                                         if(empty_string == (1 << curr_bit_size))
894                                                                 curr_bit_size ++;
895                                                         if(curr_bit_size == 13) {
896                                                                 curr_bit_size = 12;
897                                                                 bit_overflow = 1;
898                                                         }
899                                                 }
900
901                                                 old = code;
902                                         }
903                                         else
904                                         {
905                                                 get_string(old);
906                                                 string[str[old].length] = string[0];
907                                                 string_length ++;
908
909                                                 if(bit_overflow == 0) {
910                                                         str[empty_string].base = old;
911                                                         str[empty_string].new = string[0];
912                                                         str[empty_string].length = str[old].length + 1;
913                                                         empty_string ++;
914                                                         if(empty_string == (1 << curr_bit_size))
915                                                                 curr_bit_size ++;
916                                                         if(curr_bit_size == 13) {
917                                                                 curr_bit_size = 12;
918                                                                 bit_overflow = 1;
919                                                         }
920                                                 }
921
922                                                 output_string();
923                                                 old = code;
924                                         }
925                                 }
926                                 break;
927                         case 0x21: /* Extension Introducer */
928                                 i = pack_getc(f);
929                                 if(i == 0xF9) /* Graphic Control Extension */
930                                 {
931                                         pack_fseek(f, 1); /* skip size (it's 4) */
932                                         i = pack_getc(f);
933                                         if(i & 1) /* is transparency enabled? */
934                                         {
935                                                 pack_fseek(f, 2);
936                                                 pack_getc(f); /* transparent colour */
937                                         }
938                                         else
939                                                 pack_fseek(f, 3);
940                                 }
941                                 i = pack_getc(f);
942                                 while(i) /* skip Data Sub-blocks */
943                                 {
944                                         pack_fseek(f, i);
945                                         i = pack_getc(f);
946                                 }
947                                 break;
948                         case 0x3B: /* Trailer - end of data */
949                                 pack_fclose(f);
950
951                                 /* convert to correct colour depth */
952                                 dest_depth = _color_load_depth(8);
953
954                                 if (dest_depth != 8)
955                                 {
956                                         bmp2 = create_bitmap_ex(dest_depth, bmp->w, bmp->h);
957                                         if (!bmp2)
958                                         {
959                                                 destroy_bitmap(bmp);
960                                                 return NULL;
961                                         }
962
963                                         select_palette(pal);
964                                         blit(bmp, bmp2, 0, 0, 0, 0, bmp->w, bmp->h);
965                                         unselect_palette();
966
967                                         destroy_bitmap(bmp);
968                                         bmp = bmp2;
969                                 }
970
971                                 return bmp;
972                 }
973         } while(TRUE);
974
975         /* this is never executed but DJGPP complains if you leave it out */
976         return NULL;
977 }
978
979 #endif