1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * ©1995 Artsoft Development *
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 *----------------------------------------------------------*
13 ***********************************************************/
26 /* allegro driver declarations */
27 DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1)
28 DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8)
29 DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB)
30 DECLARE_MIDI_DRIVER_LIST()
31 DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD)
33 /* allegro global variables */
34 extern volatile int key_shifts;
35 extern int num_joysticks;
36 extern JOYSTICK_INFO joy[];
37 extern int i_love_bill;
39 /* internal variables of msdos.c */
40 static int key_press_state[MAX_SCANCODES];
41 static XEvent event_buffer[MAX_EVENT_BUFFER];
42 static int pending_events;
43 static boolean joystick_event;
44 static boolean mouse_installed = FALSE;
45 static int last_mouse_pos;
46 static int last_mouse_b;
47 static int last_joystick_state;
48 static BITMAP* video_bitmap;
50 static RGB global_colormap[MAX_COLORS];
51 static int global_colormap_entries_used = 0;
53 boolean wait_for_vsync;
55 extern int playing_sounds;
56 extern struct SoundControl playlist[MAX_SOUNDS_PLAYING];
57 extern struct SoundControl emptySoundControl;
59 static BITMAP *Read_PCX_to_AllegroBitmap(char *);
61 static void allegro_drivers()
65 for (i=0; i<MAX_EVENT_BUFFER; i++)
66 event_buffer[i].type = 0;
68 for (i=0; i<MAX_SCANCODES; i++)
69 key_press_state[i] = KeyReleaseMask;
71 last_mouse_pos = mouse_pos;
77 /* enable Windows friendly timer mode (already default under Windows) */
82 if (install_mouse() > 0)
83 mouse_installed = TRUE;
85 last_joystick_state = 0;
86 joystick_event = FALSE;
88 reserve_voices(MAX_SOUNDS_PLAYING, 0);
89 if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "ROCKS.SND") == -1)
90 if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1)
91 sound_status = SOUND_OFF;
94 static boolean hide_mouse(Display *display, int x, int y,
95 unsigned int width, unsigned int height)
97 if (mouse_x + display->mouse_ptr->w < x || mouse_x > x + width)
99 if (mouse_y + display->mouse_ptr->h < y || mouse_y > y + height)
107 static void unhide_mouse(Display *display)
110 show_mouse(video_bitmap);
113 static KeySym ScancodeToKeySym(byte scancode)
117 case KEY_ESC: return XK_Escape;
118 case KEY_1: return XK_1;
119 case KEY_2: return XK_2;
120 case KEY_3: return XK_3;
121 case KEY_4: return XK_4;
122 case KEY_5: return XK_5;
123 case KEY_6: return XK_6;
124 case KEY_7: return XK_7;
125 case KEY_8: return XK_8;
126 case KEY_9: return XK_9;
127 case KEY_0: return XK_0;
128 case KEY_MINUS: return XK_minus;
129 case KEY_EQUALS: return XK_equal;
130 case KEY_BACKSPACE: return XK_BackSpace;
131 case KEY_TAB: return XK_Tab;
132 case KEY_Q: return XK_q;
133 case KEY_W: return XK_w;
134 case KEY_E: return XK_e;
135 case KEY_R: return XK_r;
136 case KEY_T: return XK_t;
137 case KEY_Y: return XK_y;
138 case KEY_U: return XK_u;
139 case KEY_I: return XK_i;
140 case KEY_O: return XK_o;
141 case KEY_P: return XK_p;
142 case KEY_OPENBRACE: return XK_braceleft;
143 case KEY_CLOSEBRACE: return XK_braceright;
144 case KEY_ENTER: return XK_Return;
145 case KEY_LCONTROL: return XK_Control_L;
146 case KEY_A: return XK_a;
147 case KEY_S: return XK_s;
148 case KEY_D: return XK_d;
149 case KEY_F: return XK_f;
150 case KEY_G: return XK_g;
151 case KEY_H: return XK_h;
152 case KEY_J: return XK_j;
153 case KEY_K: return XK_k;
154 case KEY_L: return XK_l;
155 case KEY_COLON: return XK_colon;
156 case KEY_QUOTE: return XK_apostrophe;
157 case KEY_TILDE: return XK_asciitilde;
158 case KEY_LSHIFT: return XK_Shift_L;
159 case KEY_BACKSLASH: return XK_backslash;
160 case KEY_Z: return XK_z;
161 case KEY_X: return XK_x;
162 case KEY_C: return XK_c;
163 case KEY_V: return XK_v;
164 case KEY_B: return XK_b;
165 case KEY_N: return XK_n;
166 case KEY_M: return XK_m;
167 case KEY_COMMA: return XK_comma;
168 case KEY_STOP: return XK_period;
169 case KEY_SLASH: return XK_slash;
170 case KEY_RSHIFT: return XK_Shift_R;
171 case KEY_ASTERISK: return XK_KP_Multiply;
172 case KEY_ALT: return XK_Alt_L;
173 case KEY_SPACE: return XK_space;
174 case KEY_CAPSLOCK: return XK_Caps_Lock;
175 case KEY_F1: return XK_F1;
176 case KEY_F2: return XK_F2;
177 case KEY_F3: return XK_F3;
178 case KEY_F4: return XK_F4;
179 case KEY_F5: return XK_F5;
180 case KEY_F6: return XK_F6;
181 case KEY_F7: return XK_F7;
182 case KEY_F8: return XK_F8;
183 case KEY_F9: return XK_F9;
184 case KEY_F10: return XK_F10;
185 case KEY_NUMLOCK: return XK_Num_Lock;
186 case KEY_SCRLOCK: return XK_Scroll_Lock;
187 case KEY_HOME: return XK_Home;
188 case KEY_UP: return XK_Up;
189 case KEY_PGUP: return XK_Page_Up;
190 case KEY_MINUS_PAD: return XK_KP_Subtract;
191 case KEY_LEFT: return XK_Left;
192 case KEY_5_PAD: return XK_KP_5;
193 case KEY_RIGHT: return XK_Right;
194 case KEY_PLUS_PAD: return XK_KP_Add;
195 case KEY_END: return XK_End;
196 case KEY_DOWN: return XK_Down;
197 case KEY_PGDN: return XK_Page_Down;
198 case KEY_INSERT: return XK_Insert;
199 case KEY_DEL: return XK_Delete;
200 case KEY_PRTSCR: return XK_Print;
201 case KEY_F11: return XK_F11;
202 case KEY_F12: return XK_F12;
203 case KEY_LWIN: return XK_Meta_L;
204 case KEY_RWIN: return XK_Meta_R;
205 case KEY_MENU: return XK_Menu;
206 case KEY_PAD: return XK_VoidSymbol;
207 case KEY_RCONTROL: return XK_Control_R;
208 case KEY_ALTGR: return XK_Alt_R;
209 case KEY_SLASH2: return XK_KP_Divide;
210 case KEY_PAUSE: return XK_Pause;
212 case NEW_KEY_BACKSLASH: return XK_backslash;
213 case NEW_KEY_1_PAD: return XK_KP_1;
214 case NEW_KEY_2_PAD: return XK_KP_2;
215 case NEW_KEY_3_PAD: return XK_KP_3;
216 case NEW_KEY_4_PAD: return XK_KP_4;
217 case NEW_KEY_5_PAD: return XK_KP_5;
218 case NEW_KEY_6_PAD: return XK_KP_6;
219 case NEW_KEY_7_PAD: return XK_KP_7;
220 case NEW_KEY_8_PAD: return XK_KP_8;
221 case NEW_KEY_9_PAD: return XK_KP_9;
222 case NEW_KEY_0_PAD: return XK_KP_0;
223 case NEW_KEY_STOP_PAD: return XK_KP_Separator;
224 case NEW_KEY_EQUALS_PAD: return XK_KP_Equal;
225 case NEW_KEY_SLASH_PAD: return XK_KP_Divide;
226 case NEW_KEY_ASTERISK_PAD: return XK_KP_Multiply;
227 case NEW_KEY_ENTER_PAD: return XK_KP_Enter;
229 default: return XK_VoidSymbol;
233 void XMapWindow(Display *display, Window window)
236 unsigned int width, height;
239 x = display->screens[display->default_screen].x;
240 y = display->screens[display->default_screen].y;
241 width = display->screens[display->default_screen].width;
242 height = display->screens[display->default_screen].height;
244 mouse_off = hide_mouse(display, x, y, width, height);
245 blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height);
248 unhide_mouse(display);
251 Display *XOpenDisplay(char *display_name)
255 BITMAP *mouse_bitmap = NULL;
258 filename = getPath3(options.base_directory, GRAPHICS_DIRECTORY,
261 mouse_bitmap = Read_PCX_to_AllegroBitmap(filename);
264 if (mouse_bitmap == NULL)
267 screen = malloc(sizeof(Screen));
268 display = malloc(sizeof(Display));
272 screen[0].white_pixel = 0xFF;
273 screen[0].black_pixel = 0x00;
274 screen[0].video_bitmap = NULL;
276 display->default_screen = 0;
277 display->screens = screen;
278 display->mouse_ptr = mouse_bitmap;
284 /* force Windows 95 to switch to fullscreen mode */
285 set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0);
287 set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0);
292 Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
293 unsigned int width, unsigned int height,
294 unsigned int border_width, unsigned long border,
295 unsigned long background)
297 video_bitmap = create_video_bitmap(XRES, YRES);
298 clear_to_color(video_bitmap, background);
300 display->screens[display->default_screen].video_bitmap = video_bitmap;
301 display->screens[display->default_screen].x = x;
302 display->screens[display->default_screen].y = y;
303 display->screens[display->default_screen].width = XRES;
304 display->screens[display->default_screen].height = YRES;
306 set_mouse_sprite(display->mouse_ptr);
307 set_mouse_speed(1, 1);
308 set_mouse_range(display->screens[display->default_screen].x + 1,
309 display->screens[display->default_screen].y + 1,
310 display->screens[display->default_screen].x + WIN_XSIZE + 1,
311 display->screens[display->default_screen].y + WIN_YSIZE + 1);
313 show_video_bitmap(video_bitmap);
315 return (Window)video_bitmap;
318 Status XStringListToTextProperty(char **list, int count,
319 XTextProperty *text_prop_return)
325 string = malloc(strlen(list[0] + 1));
326 strcpy(string, list[0]);
327 text_prop_return->value = (unsigned char *)string;
331 text_prop_return = NULL;
336 void XFree(void *data)
342 GC XCreateGC(Display *display, Drawable d, unsigned long value_mask,
346 gcv = malloc(sizeof(XGCValues));
347 gcv->foreground = values->foreground;
348 gcv->background = values->background;
349 gcv->graphics_exposures = values->graphics_exposures;
350 gcv->clip_mask = values->clip_mask;
351 gcv->clip_x_origin = values->clip_x_origin;
352 gcv->clip_y_origin = values->clip_y_origin;
353 gcv->value_mask = value_mask;
357 void XSetClipMask(Display *display, GC gc, Pixmap pixmap)
359 XGCValues *gcv = (XGCValues *)gc;
361 gcv->clip_mask = pixmap;
362 gcv->value_mask |= GCClipMask;
365 void XSetClipOrigin(Display *display, GC gc, int x, int y)
367 XGCValues *gcv = (XGCValues *)gc;
369 gcv->clip_x_origin = x;
370 gcv->clip_x_origin = y;
373 void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y,
374 unsigned int width, unsigned int height)
376 boolean mouse_off = FALSE;
378 if ((BITMAP *)d == video_bitmap)
380 x += display->screens[display->default_screen].x;
381 y += display->screens[display->default_screen].y;
382 freeze_mouse_flag = TRUE;
383 mouse_off = hide_mouse(display, x, y, width, height);
386 rectfill((BITMAP *)d, x, y, x + width, y + height,
387 ((XGCValues *)gc)->foreground);
390 unhide_mouse(display);
392 freeze_mouse_flag = FALSE;
395 Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width,
396 unsigned int height, unsigned int depth)
398 BITMAP *bitmap = NULL;
400 if (gfx_capabilities & GFX_HW_VRAM_BLIT &&
401 width == FXSIZE && height == FYSIZE)
402 bitmap = create_video_bitmap(width, height);
405 bitmap = create_bitmap(width, height);
407 return (Pixmap)bitmap;
410 void XSync(Display *display, Bool discard_events)
412 wait_for_vsync = TRUE;
415 inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc,
416 int src_x, int src_y,
417 unsigned int width, unsigned int height,
418 int dest_x, int dest_y)
420 boolean mouse_off = FALSE;
422 if ((BITMAP *)src == video_bitmap)
424 src_x += display->screens[display->default_screen].x;
425 src_y += display->screens[display->default_screen].y;
428 if ((BITMAP *)dest == video_bitmap)
430 dest_x += display->screens[display->default_screen].x;
431 dest_y += display->screens[display->default_screen].y;
432 freeze_mouse_flag = TRUE;
433 mouse_off = hide_mouse(display, dest_x, dest_y, width, height);
438 wait_for_vsync = FALSE;
442 if (((XGCValues *)gc)->value_mask & GCClipMask)
443 masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
446 blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
450 unhide_mouse(display);
452 freeze_mouse_flag = FALSE;
455 static BITMAP *Image_to_AllegroBitmap(Image *image)
458 byte *src_ptr = image->data;
459 byte pixel_mapping[MAX_COLORS];
460 unsigned int depth = 8;
463 /* allocate new allegro bitmap structure */
464 if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL)
469 /* try to use existing colors from the global colormap */
470 for (i=0; i<MAX_COLORS; i++)
474 if (!image->rgb.color_used[i])
477 r = image->rgb.red[i] >> 10;
478 g = image->rgb.green[i] >> 10;
479 b = image->rgb.blue[i] >> 10;
481 for (j=0; j<global_colormap_entries_used; j++)
483 if (r == global_colormap[j].r &&
484 g == global_colormap[j].g &&
485 b == global_colormap[j].b) /* color found */
487 pixel_mapping[i] = j;
492 if (j == global_colormap_entries_used) /* color not found */
494 if (global_colormap_entries_used < MAX_COLORS)
495 global_colormap_entries_used++;
497 global_colormap[j].r = r;
498 global_colormap[j].g = g;
499 global_colormap[j].b = b;
501 pixel_mapping[i] = j;
505 /* copy bitmap data */
506 for (y=0; y<image->height; y++)
507 for (x=0; x<image->width; x++)
508 putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]);
513 static BITMAP *Read_PCX_to_AllegroBitmap(char *filename)
518 /* read the graphic file in PCX format to internal image structure */
519 if ((image = Read_PCX_to_Image(filename)) == NULL)
522 /* convert internal image structure to allegro bitmap structure */
523 if ((bitmap = Image_to_AllegroBitmap(image)) == NULL)
526 set_pallete(global_colormap);
531 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
532 Pixmap *pixmap, Pixmap *pixmap_mask)
536 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
537 return PCX_FileInvalid;
539 *pixmap = (Pixmap)bitmap;
540 *pixmap_mask = (Pixmap)bitmap;
545 int XpmReadFileToPixmap(Display *display, Drawable d, char *filename,
546 Pixmap *pixmap_return, Pixmap *shapemask_return,
547 XpmAttributes *attributes)
551 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
552 return XpmOpenFailed;
554 *pixmap_return = (Pixmap)bitmap;
559 int XReadBitmapFile(Display *display, Drawable d, char *filename,
560 unsigned int *width_return, unsigned int *height_return,
561 Pixmap *bitmap_return,
562 int *x_hot_return, int *y_hot_return)
566 if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
567 return BitmapOpenFailed;
569 *width_return = bitmap->w;
570 *height_return = bitmap->h;
573 *bitmap_return = (Pixmap)bitmap;
575 return BitmapSuccess;
578 void XFreePixmap(Display *display, Pixmap pixmap)
580 if (pixmap != DUMMY_MASK &&
581 (is_memory_bitmap((BITMAP *)pixmap) ||
582 is_screen_bitmap((BITMAP *)pixmap)))
583 destroy_bitmap((BITMAP *)pixmap);
586 void XFreeGC(Display *display, GC gc)
590 gcv = (XGCValues *)gc;
595 void XCloseDisplay(Display *display)
597 BITMAP *bitmap = video_bitmap;
599 if (is_screen_bitmap(bitmap))
600 destroy_bitmap(bitmap);
602 if (display->screens)
603 free(display->screens);
608 /* return to text mode (or DOS box on Windows screen) */
609 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
612 void XNextEvent(Display *display, XEvent *event_return)
614 while (!pending_events)
617 memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent));
621 static void NewKeyEvent(int key_press_state, KeySym keysym)
625 if (pending_events >= MAX_EVENT_BUFFER)
629 xkey = (XKeyEvent *)&event_buffer[pending_events];
630 xkey->type = key_press_state;
631 xkey->state = (unsigned int)keysym;
634 #define HANDLE_RAW_KB_ALL_KEYS 0
635 #define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY 1
637 static int modifier_scancode[] =
653 static void HandleKeyboardRaw(int mode)
657 for (i=0; i<MAX_SCANCODES; i++)
659 int scancode, new_state, event_type;
662 if (mode == HANDLE_RAW_KB_MODIFIER_KEYS_ONLY)
664 if ((scancode = modifier_scancode[i]) == -1)
670 key_pressed = key[scancode];
671 new_state = (key_pressed ? KeyPressMask : KeyReleaseMask);
672 event_type = (key_pressed ? KeyPress : KeyRelease);
674 if (key_press_state[i] == new_state) /* state not changed */
677 key_press_state[i] = new_state;
679 NewKeyEvent(event_type, ScancodeToKeySym(scancode));
683 static void HandleKeyboardEvent()
687 int key_info = readkey();
688 int scancode = (key_info >> 8);
689 int ascii = (key_info & 0xff);
690 KeySym keysym = ScancodeToKeySym(scancode);
692 if (scancode == KEY_PAD)
694 /* keys on the numeric keypad return just scancode 'KEY_PAD'
695 for some reason, so we must handle them separately */
697 if (ascii >= '0' && ascii <= '9')
698 keysym = XK_KP_0 + (KeySym)(ascii - '0');
699 else if (ascii == '.')
700 keysym = XK_KP_Separator;
703 NewKeyEvent(KeyPress, keysym);
705 else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG))
707 /* the allegro function keypressed() does not give us single pressed
708 modifier keys, so we must detect them with the internal global
709 allegro variable 'key_shifts' and then handle them separately */
711 HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY);
715 int XPending(Display *display)
717 XButtonEvent *xbutton;
718 XMotionEvent *xmotion;
722 if (game_status == PLAYING)
723 HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS);
725 HandleKeyboardEvent();
727 /* mouse motion event */
728 /* generate mouse motion event only if any mouse buttons are pressed */
729 if (mouse_pos != last_mouse_pos && mouse_b)
731 last_mouse_pos = mouse_pos;
733 xmotion = (XMotionEvent *)&event_buffer[pending_events];
734 xmotion->type = MotionNotify;
735 xmotion->x = mouse_x - display->screens[display->default_screen].x;
736 xmotion->y = mouse_y - display->screens[display->default_screen].y;
739 /* mouse button event */
740 if (mouse_b != last_mouse_b)
742 for (i=1; i<4; i<<=1)
744 if ((last_mouse_b & i) != (mouse_b & i))
747 xbutton = (XButtonEvent *)&event_buffer[pending_events];
748 xbutton->type = (mouse_b & i ? ButtonPress : ButtonRelease);
750 xbutton->x = mouse_x - display->screens[display->default_screen].x;
751 xbutton->y = mouse_y - display->screens[display->default_screen].y;
754 last_mouse_b = mouse_b;
757 return pending_events;
760 KeySym XLookupKeysym(XKeyEvent *key_event, int index)
762 return key_event->state;
765 void sound_handler(struct SoundControl snd_ctrl)
769 if (snd_ctrl.fade_sound)
774 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
775 if ((snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr) &&
776 !playlist[i].fade_sound)
778 playlist[i].fade_sound = TRUE;
779 if (voice_check(playlist[i].voice))
780 voice_ramp_volume(playlist[i].voice, 1000, 0);
781 playlist[i].loop = PSND_NO_LOOP;
784 else if (snd_ctrl.stop_all_sounds)
788 SoundServer_StopAllSounds();
790 else if (snd_ctrl.stop_sound)
794 SoundServer_StopSound(snd_ctrl.nr);
797 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
799 if (!playlist[i].active || playlist[i].loop)
802 playlist[i].playingpos = voice_get_position(playlist[i].voice);
803 playlist[i].volume = voice_get_volume(playlist[i].voice);
804 if (playlist[i].playingpos == -1 || !playlist[i].volume)
806 deallocate_voice(playlist[i].voice);
807 playlist[i] = emptySoundControl;
813 SoundServer_InsertNewSound(snd_ctrl);
816 void NetworkServer(int port, int serveronly)
818 Error(ERR_WARN, "networking not supported in DOS version");