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