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