1 /* Sarien - A Sierra AGI resource interpreter engine
2 * Amiga files Copyright (C) 1999-2001 Paul Hill
3 *
4 * $Id: amiga.c,v 1.15 2001/09/02 21:53:43 cmatsuoka Exp $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; see docs/COPYING for further details.
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <devices/timer.h>
15 #include <sys/time.h>
16 #ifndef __DICE__
17 #include <proto/intuition.h>
18 #include <proto/graphics.h>
19 #include <proto/exec.h>
20 #include <proto/dos.h>
21 #include <proto/gadtools.h>
22 #endif
23 #include <graphics/gfxbase.h>
24 #include <graphics/rastport.h>
25 #include <intuition/intuition.h>
26 #include "amiga_keys.h"
27
28 #include "sarien.h"
29 #include "graphics.h"
30 #include "keyboard.h"
31
32 #define DEPTH 6
33
34 extern struct sarien_options opt;
35 extern struct gfx_driver *gfx;
36
37 static struct Screen *screen;
38 struct Window *window;
39 static UBYTE *ximage;
40
41 static struct RastPort video_temprp;
42 static struct BitMap video_tmp_bm = {
43 0, 0, 0, 0, 0,
44 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
45 };
46 APTR VisualInfo = NULL;
47
48 static int scale = 1;
49 static int key_control = 0;
50 static int key_alt = 0;
51 static unsigned int rgb_palette[32];
52
53 static int __argc;
54 static char **__argv;
55
56 #ifdef __DICE__
57 extern struct GfxBase *GfxBase;
58 #endif
59
60 #define KEY_QUEUE_SIZE 16
61 static int key_queue[KEY_QUEUE_SIZE];
62 static int key_queue_start = 0;
63 static int key_queue_end = 0;
64 #define key_enqueue(k) do { key_queue[key_queue_end++] = (k); \
65 key_queue_end %= KEY_QUEUE_SIZE; } while (0)
66 #define key_dequeue(k) do { (k) = key_queue[key_queue_start++]; \
67 key_queue_start %= KEY_QUEUE_SIZE; } while (0)
68
69 static int Amiga_init_vidmode (void);
70 static int Amiga_deinit_vidmode (void);
71 static UINT16 set_palette (UINT8 *, UINT16, UINT16);
72 static void Amiga_blit_block (int, int, int, int);
73 static void Amiga_put_pixel (int x, int y, int w, UINT8 *p);
74 static int Amiga_keypress (void);
75 static int Amiga_get_key (void);
76 static void Amiga_new_timer (void);
77
78
79 /* From timer.c */
80 int opentimer();
81 void closetimer();
82
die_die_die()83 static void die_die_die()
84 {
85 gfx->deinit_video_mode ();
86 deinit_sound();
87 deinit_machine();
88 exit(0);
89 }
90
91
92 static struct gfx_driver GFX_amiga = {
93 Amiga_init_vidmode,
94 Amiga_deinit_vidmode,
95 Amiga_blit_block,
96 Amiga_put_pixel,
97 Amiga_new_timer,
98 Amiga_keypress,
99 Amiga_get_key
100 };
101
__chkabort(void)102 void __chkabort(void){}
103
104
process_events()105 static void process_events ()
106 {
107 UWORD Code;
108 UWORD Qualifier;
109 ULONG Class;
110 struct IntuiMessage *imsg;
111 int goingup;
112 int key = 0;
113
114 while ((imsg = (struct IntuiMessage *)GT_GetIMsg(window->UserPort)))
115 {
116 Class = imsg->Class;
117 Code = imsg->Code;
118 Qualifier = imsg->Qualifier;
119
120 /* Get the message that's waiting for us */
121 GT_ReplyIMsg(imsg);
122
123 switch (Class)
124 {
125 case IDCMP_MOUSEBUTTONS:
126 switch (Code)
127 {
128 case IECODE_RBUTTON:
129 case IECODE_LBUTTON:
130 key = Code == IECODE_LBUTTON ?
131 BUTTON_LEFT : BUTTON_RIGHT;
132 mouse.button = TRUE;
133 mouse.x = (imsg->MouseX - window->BorderLeft) / opt.scale;
134 mouse.y = (imsg->MouseY - window->BorderTop) / opt.scale;
135 break;
136 case IECODE_LBUTTON | IECODE_UP_PREFIX:
137 case IECODE_RBUTTON | IECODE_UP_PREFIX:
138 mouse.button = FALSE;
139 break;
140 }
141 break;
142
143 case IDCMP_CLOSEWINDOW:
144 die_die_die();
145 break;
146
147 case IDCMP_VANILLAKEY:
148 if ((Code == 13) && (Qualifier == 0x8010))
149 {
150 /*
151 * [alt + enter] = switch between
152 * fullscreen and window mode
153 */
154 Amiga_deinit_vidmode();
155 opt.fullscreen = !opt.fullscreen;
156 Amiga_init_vidmode();
157 /* re-draw the screen */
158 printf("..................................................\n");
159 Amiga_blit_block (0, 0,
160 GFX_WIDTH * scale, GFX_HEIGHT * scale);
161 printf("..................................................\n");
162 } else {
163 key = Code;
164 }
165 break;
166
167 case IDCMP_RAWKEY:
168 goingup = Code & 0x080;
169 Code = (Code & 0x07F);
170
171 if(!goingup)
172 {
173 switch (Code)
174 {
175 /* Key press */
176 case XK_Up:
177 key = KEY_UP;
178 break;
179 case XK_Left:
180 key = KEY_LEFT;
181 break;
182 case XK_Down:
183 key = KEY_DOWN;
184 break;
185 case XK_Right:
186 key = KEY_RIGHT;
187 break;
188
189 case XK_F1:
190 key = 0x3b00;
191 break;
192 case XK_F2:
193 key = 0x3c00;
194 break;
195 case XK_F3:
196 key = 0x3d00;
197 break;
198 case XK_F4:
199 key = 0x3e00;
200 break;
201 case XK_F5:
202 key = 0x3f00;
203 break;
204 case XK_F6:
205 key = 0x4000;
206 break;
207 case XK_F7:
208 key = 0x4100;
209 break;
210 case XK_F8:
211 key = 0x4200;
212 break;
213 case XK_F9:
214 key = 0x4300;
215 break;
216 case XK_F10:
217 key = 0x4400;
218 break;
219 case XK_Return:
220 key = 0x0d;
221 break;
222 case XK_Escape:
223 key = 0x1b;
224 break;
225
226 case XK_Control_L:
227 key_control |= 1;
228 key = 0;
229 break;
230 #if 0
231 case XK_Control_R:
232 key_control |= 2;
233 key = 0;
234 break;
235 #endif
236 case XK_Shift_L:
237 case XK_Shift_R:
238 key = 0;
239 break;
240 case XK_Alt_L:
241 key_alt |= 1;
242 key = 0;
243 break;
244 case XK_Alt_R:
245 key_alt |= 2;
246 key = 0;
247 break;
248 #if 0
249 /* Amiga numpad doesn't return rawkeys... */
250 /* We'll have to make up with joystick support */
251 case XK_KP_Home:
252 key = KEY_UP_LEFT;
253 break;
254 case XK_KP_Page_Up:
255 key = KEY_UP_RIGHT;
256 break;
257 case XK_KP_Page_Down:
258 key = KEY_DOWN_RIGHT;
259 break;
260 case XK_KP_End:
261 key = KEY_DOWN_LEFT;
262 break;
263 case XK_KP_Enter:
264 key = KEY_ENTER;
265 break;
266 case XK_KP_Add:
267 key = '+';
268 break;
269 case XK_KP_Subtract:
270 key = '-';
271 break;
272 #endif
273
274 #if 0
275 #ifdef USE_CONSOLE
276 case XK_Help:
277 key = CONSOLE_ACTIVATE_KEY;
278 break;
279 case XK_Help:
280 key = CONSOLE_SWITCH_KEY;
281 break;
282 #endif
283 #endif
284 }
285 } else
286 {
287 /* Key Release */
288 switch (Code)
289 {
290 case XK_Control_L:
291 key_control &= ~1;
292 break;
293 #if 0
294 case XK_Control_R:
295 key_control &= ~2;
296 break;
297 #endif
298 case XK_Alt_L:
299 key_alt &= ~1;
300 break;
301 case XK_Alt_R:
302 key_alt &= ~2;
303 break;
304 default:
305 key = 0;
306 }
307 }
308
309 break;
310 }
311 if (key)
312 key_enqueue (key);
313 }
314 }
315
316
init_machine(int argc,char ** argv)317 int init_machine (int argc, char **argv)
318 {
319 gfx = &GFX_amiga;
320
321 /* Open the Amiga's timer.device */
322 opentimer(); /* !!! check result! */
323
324 __argc = argc;
325 __argv = argv;
326 scale = opt.scale;
327
328 /* ximage will be used to hold the chunky gfx data */
329 ximage = malloc ((GFX_WIDTH * scale) * (GFX_HEIGHT * scale));
330 if (!ximage) return err_Unk;
331
332 return err_OK;
333 }
334
335
deinit_machine(void)336 int deinit_machine(void)
337 {
338 if (ximage) free (ximage);
339 ximage = NULL;
340 closetimer();
341 return err_OK;
342 }
343
344
set_palette(UINT8 * pal,UINT16 scol,UINT16 numcols)345 static UINT16 set_palette (UINT8 *pal, UINT16 scol, UINT16 numcols)
346 {
347 ULONG r,g,b;
348 int i;
349
350 for (i = scol; i < scol + numcols; i++)
351 {
352 r = pal[i * 3] << 26;
353 g = pal[i * 3 + 1] << 26;
354 b = pal[i * 3 + 2] << 26;
355
356 if (opt.fullscreen)
357 {
358 rgb_palette[i] = i;
359 SetRGB4 (&screen->ViewPort, i,
360 pal[i * 3] >> 2,
361 pal[i * 3 + 1] >> 2,
362 pal[i * 3 + 2] >> 2);
363 }
364 else
365 {
366 if (GfxBase->LibNode.lib_Version >= 39)
367 rgb_palette[i] = ObtainBestPenA (
368 screen->ViewPort.ColorMap,
369 r, g, b, NULL);
370 }
371 }
372
373 return err_OK;
374 }
375
376
Amiga_init_vidmode(void)377 static int Amiga_init_vidmode (void)
378 {
379 char *PubScreen=NULL;
380 int i;
381
382 if (opt.fullscreen)
383 {
384 ULONG AmigaModeID=-1; /* Amiga screen ID */
385 /* Running full screen */
386 AmigaModeID = BestModeID (
387 BIDTAG_DesiredWidth, GFX_WIDTH * scale,
388 BIDTAG_DesiredHeight, GFX_HEIGHT * scale,
389 BIDTAG_NominalWidth, GFX_WIDTH * scale,
390 BIDTAG_NominalHeight, GFX_HEIGHT * scale,
391 BIDTAG_Depth, DEPTH,
392 TAG_END);
393 if (AmigaModeID==INVALID_ID) AmigaModeID=0;
394
395 screen = OpenScreenTags(NULL,
396 SA_Left, 0,
397 SA_Top, 0,
398 SA_Width, GFX_WIDTH * scale,
399 SA_Height, GFX_HEIGHT * scale,
400 SA_Depth, DEPTH,
401 SA_Title, (ULONG) "Amiga Sarien v" VERSION,
402 SA_DisplayID, AmigaModeID,
403 TAG_DONE);
404
405 if (screen) {
406 window = OpenWindowTags(NULL,
407 WA_Width, GFX_WIDTH * scale,
408 WA_Height, GFX_HEIGHT * scale,
409 WA_CloseGadget, FALSE,
410 WA_DepthGadget, FALSE,
411 WA_DragBar, FALSE,
412 WA_SizeGadget, FALSE,
413 WA_Activate, TRUE,
414 WA_Borderless, TRUE,
415 WA_IDCMP, IDCMP_CLOSEWINDOW |
416 IDCMP_RAWKEY |
417 IDCMP_VANILLAKEY |
418 IDCMP_MOUSEBUTTONS |
419 WFLG_RMBTRAP,
420 WA_Activate, TRUE,
421 WA_CustomScreen,(ULONG) screen,
422 TAG_END);
423 }
424 }
425 else
426 {
427 /* Running in a window */
428 screen = LockPubScreen(PubScreen);
429
430 if (screen)
431 {
432 window = OpenWindowTags(NULL,
433 WA_InnerWidth, GFX_WIDTH * scale,
434 WA_InnerHeight, GFX_HEIGHT * scale,
435 WA_Title, (ULONG)"Amiga Sarien v" VERSION,
436 WA_CloseGadget, TRUE,
437 WA_DepthGadget, TRUE,
438 WA_DragBar, TRUE,
439 WA_SizeGadget, FALSE,
440 WA_Activate, TRUE,
441 WA_RMBTrap, TRUE,
442 WA_PubScreenName,(ULONG) PubScreen,
443 WA_IDCMP, IDCMP_CLOSEWINDOW |
444 IDCMP_RAWKEY |
445 IDCMP_VANILLAKEY |
446 IDCMP_MOUSEBUTTONS,
447 TAG_END);
448 }
449 }
450
451 if (!screen)
452 {
453 fprintf(stderr, "Error opening/locking screen\n");
454 return err_Unk;
455 }
456
457 if (!window)
458 {
459 fprintf(stderr, "Error opening window\n");
460 if (screen)
461 {
462 if (opt.fullscreen)
463 CloseScreen(screen);
464 else
465 UnlockPubScreen(NULL,screen);
466 screen = NULL;
467 }
468 return err_Unk;
469 }
470
471 /* Setup the temporary rastport required for kickstarts < 3.1 */
472 if (GfxBase->LibNode.lib_Version < 39)
473 {
474 int depth;
475 InitBitMap (&video_tmp_bm, 1, (GFX_WIDTH * scale), 1);
476
477 for (depth = 0; depth < DEPTH; depth++)
478 {
479 if ((video_tmp_bm.Planes[depth] = (PLANEPTR)AllocRaster (GFX_WIDTH * scale, 1)) == NULL)
480 {
481 fprintf(stderr,"AllocRaster failed");
482 return 0;
483 }
484 }
485
486 video_temprp = *window->RPort;
487 video_temprp.Layer = NULL;
488 video_temprp.BitMap = &video_tmp_bm;
489 }
490
491 /* clear_buffer(); */
492
493 for (i=0;i<16;i++) {
494 rgb_palette[i] = -1;
495 }
496
497 set_palette (palette, 0, 32);
498
499 /* clear screen */
500 memset (ximage, rgb_palette[0], GFX_HEIGHT * scale * GFX_WIDTH * scale);
501 return err_OK;
502 }
503
Amiga_deinit_vidmode(void)504 static int Amiga_deinit_vidmode (void)
505 {
506 fprintf (stderr, "amiga: deiniting video mode\n");
507
508 /* Free the temporary rastport required for kickstarts < 3.1 */
509 if (GfxBase->LibNode.lib_Version < 39)
510 {
511 int depth;
512 for (depth = 0; depth < DEPTH; depth++)
513 {
514 if (video_tmp_bm.Planes[depth] != NULL)
515 {
516 FreeRaster (video_tmp_bm.Planes[depth],
517 (GFX_WIDTH * scale), 1);
518 video_tmp_bm.Planes[depth] = NULL;
519 }
520 }
521 }
522
523 if (opt.fullscreen)
524 {
525 /* release allocated colour pens */
526 if (screen)
527 {
528 int i;
529 for (i=0;i<16;i++)
530 {
531 if (rgb_palette[i] >= 0) {
532 ReleasePen (screen->ViewPort.ColorMap,
533 rgb_palette[i]);
534 }
535 rgb_palette[i] = -1;
536 }
537 }
538 }
539
540 if (window)
541 {
542 if (VisualInfo)
543 FreeVisualInfo(VisualInfo);
544 CloseWindow(window);
545 window = NULL;
546 }
547
548 if (screen)
549 {
550 if (opt.fullscreen)
551 CloseScreen(screen);
552 else
553 UnlockPubScreen(NULL,screen);
554 screen = NULL;
555 }
556
557 return err_OK;
558 }
559
560
561 /* put a block onto the screen */
Amiga_blit_block(int x1,int y1,int x2,int y2)562 static void Amiga_blit_block(int x1, int y1, int x2, int y2)
563 {
564 if (x1 >= GFX_WIDTH)
565 x1 = GFX_WIDTH - 1;
566 if (y1 >= GFX_HEIGHT)
567 y1 = GFX_HEIGHT - 1;
568 if (x2 >= GFX_WIDTH)
569 x2 = GFX_WIDTH - 1;
570 if (y2 >= GFX_HEIGHT)
571 y2 = GFX_HEIGHT - 1;
572
573 if (scale > 1) {
574 x1 *= scale;
575 y1 *= scale;
576 x2 = (x2 + 1) * scale - 1;
577 y2 = (y2 + 1) * scale - 1;
578 }
579
580 if (GfxBase->LibNode.lib_Version >= 39)
581 {
582 /* Kickstart 3.1+ */
583 static UBYTE *image;
584
585 if (scale == 1) {
586 image = ximage + (x1 + (y1 * GFX_WIDTH));
587 } else if (scale == 2) {
588 image = ximage + (x1 + (y1 * (GFX_WIDTH << 1)));
589 } else {
590 image = ximage + (x1 + (y1 * (GFX_WIDTH * scale)));
591 }
592 WriteChunkyPixels(window->RPort,
593 x1 + window->BorderLeft,
594 y1 + window->BorderTop,
595 x2 + window->BorderLeft,
596 y2 + window->BorderTop,
597 (UBYTE *) image,
598 GFX_WIDTH * scale);
599 }
600 else
601 {
602 /* Kickstart 2.0 -> 3.0 */
603 /* I don't bother to support these any more :-) */
604 }
605 }
606
607
608 /* put pixel routine */
Amiga_put_pixel(int x,int y,int w,UINT8 * p)609 static void Amiga_put_pixel (int x, int y, int w, UINT8 *p)
610 {
611 int cp, z;
612 register int i, j;
613
614 switch (scale) {
615 case 1:
616 while (w--) {
617 ximage[x + (y * GFX_WIDTH)] = rgb_palette[*p++];
618 x++;
619 }
620 break;
621 case 2:
622 x <<= 1;
623 y <<= 1;
624 z = y + 1;
625 while (w--) {
626 cp = rgb_palette[*p++];
627 ximage[(x ) + (y * (GFX_WIDTH << 1))] = cp;
628 ximage[(x++) + (z * (GFX_WIDTH << 1))] = cp;
629 ximage[(x ) + (y * (GFX_WIDTH << 1))] = cp;
630 ximage[(x++) + (z * (GFX_WIDTH << 1))] = cp;
631 }
632 break;
633 default:
634
635 x *= scale;
636 y *= scale;
637 while (w--) {
638 cp = rgb_palette[*p++];
639 for (i = 0; i < scale; i++) {
640 for (j = 0; j < scale; j++)
641 ximage[x + i + ((y + j) * (GFX_WIDTH << scale))] = cp;
642 }
643 x += scale;
644 }
645 break;
646 }
647 }
648
649
Amiga_keypress(void)650 static int Amiga_keypress (void)
651 {
652 process_events ();
653 return key_queue_start != key_queue_end;
654 }
655
656
Amiga_get_key(void)657 static int Amiga_get_key (void)
658 {
659 int k;
660
661 while (key_queue_start == key_queue_end) /* block */
662 Amiga_new_timer ();
663
664 key_dequeue(k);
665
666 return k;
667 }
668
669
Amiga_new_timer()670 static void Amiga_new_timer ()
671 {
672 struct timeval tv;
673 /* struct timezone tz; */
674 static double msec = 0.0;
675 double m;
676
677 gettimeofday (&tv, NULL);
678 m = 1000.0 * tv.tv_sec + tv.tv_usec / 1000.0;
679
680 while (m - msec < 42)
681 {
682 gettimeofday (&tv, NULL);
683 m = 1000.0 * tv.tv_sec + tv.tv_usec / 1000.0;
684 }
685 msec = m;
686
687 process_events ();
688 }
689
690