1 /*
2  *  UAE - The Un*x Amiga Emulator
3  *
4  *  BeBox port specific stuff
5  *
6  *  (c) 1996-1998 Christian Bauer
7  *  (c) 1996 Patrick Hanevold
8  */
9 
10 #include <AppKit.h>
11 #include <InterfaceKit.h>
12 #include <KernelKit.h>
13 #include <MediaKit.h>
14 #include <StorageKit.h>
15 #include <device/Joystick.h>
16 
17 extern "C" {
18 #include "sysconfig.h"
19 #include "sysdeps.h"
20 #include "config.h"
21 #include "options.h"
22 #include "threaddep/penguin.h"
23 #include "uae.h"
24 #include "gensound.h"
25 #include "sounddep/sound.h"
26 #include "events.h"
27 #include "memory.h"
28 #include "custom.h"
29 #include "readcpu.h"
30 #include "newcpu.h"
31 #include "disk.h"
32 #include "gui.h"
33 #include "debug.h"
34 #include "xwin.h"
35 #include "joystick.h"
36 #include "keyboard.h"
37 #include "keybuf.h"
38 #include "gui.h"
39 #include "zfile.h"
40 #include "picasso96.h"
41 }
42 
43 
44 // Constants
45 const char APP_SIGNATURE[] = "application/x-vnd.cebix-UAE";
46 
47 const uint32 MSG_INSERT_DF0 = 'idf0';	// Messages
48 const uint32 MSG_EJECT_DF0 = 'edf0';
49 const uint32 MSG_INSERT_DF1 = 'idf1';
50 const uint32 MSG_EJECT_DF1 = 'edf1';
51 const uint32 MSG_INSERT_DF2 = 'idf2';
52 const uint32 MSG_EJECT_DF2 = 'edf2';
53 const uint32 MSG_INSERT_DF3 = 'idf3';
54 const uint32 MSG_EJECT_DF3 = 'edf3';
55 const uint32 MSG_FLOPPY_PANEL_RETURNED = 'flpn';
56 const uint32 MSG_FR1 = 'mfr1';
57 const uint32 MSG_FR2 = 'mfr2';
58 const uint32 MSG_FR3 = 'mfr3';
59 const uint32 MSG_FR4 = 'mfr4';
60 const uint32 MSG_FR5 = 'mfr5';
61 const uint32 MSG_FR6 = 'mfr6';
62 const uint32 MSG_RESET = 'rset';
63 const uint32 MSG_DEBUG = 'dbug';
64 const uint32 MSG_REDRAW = 'draw';
65 const uint32 MSG_QUIT = 'quit';
66 const uint32 MSG_ABOUT = 'abut';
67 
68 const rgb_color PowerDark = {0x40, 0x00, 0x00, 0};	// LED colors
69 const rgb_color PowerLight = {0xff, 0x00, 0x00, 0};
70 const rgb_color DriveDark = {0x00, 0x40, 0x00, 0};
71 const rgb_color DriveLight = {0x00, 0xff, 0x00, 0};
72 
73 
74 // Array for converting Be keycodes to Amiga keycodes
75 static const int keycode2amiga[128] = {
76 	-1, AK_ESC, AK_F1, AK_F2, AK_F3, AK_F4, AK_F5, AK_F6,
77 	AK_F7, AK_F8, AK_F9, AK_F10, -1, AK_mousestuff, -1, -1,
78 
79 	-1, AK_BACKQUOTE, AK_1, AK_2, AK_3, AK_4, AK_5, AK_6,
80 	AK_7, AK_8, AK_9, AK_0, AK_MINUS, AK_EQUAL, AK_BS, AK_HELP,
81 
82 	AK_NPLPAREN, AK_NPRPAREN, -1, AK_NPDIV, AK_NPMUL, AK_NPSUB, AK_TAB, AK_Q,
83 	AK_W, AK_E, AK_R, AK_T, AK_Y, AK_U, AK_I, AK_O,
84 
85 	AK_P, AK_LBRACKET, AK_RBRACKET, AK_BACKSLASH, AK_DEL, AK_LALT, AK_RALT, AK_NP7,
86 	AK_NP8, AK_NP9, AK_NPADD, AK_CAPSLOCK, AK_A, AK_S, AK_D, AK_F,
87 
88 	AK_G, AK_H, AK_J, AK_K, AK_L, AK_SEMICOLON, AK_QUOTE, AK_RET,
89 	AK_NP4, AK_NP5, AK_NP6, AK_LSH, AK_Z, AK_X, AK_C, AK_V,
90 
91 	AK_B, AK_N, AK_M, AK_COMMA, AK_PERIOD, AK_SLASH, AK_RSH, AK_UP,
92 	AK_NP1, AK_NP2, AK_NP3, AK_ENT, AK_CTRL, AK_LAMI, AK_SPC, AK_RAMI,
93 
94 	AK_RALT, AK_LF, AK_DN, AK_RT, AK_NP0, AK_NPDEL, AK_LALT, AK_RALT,
95 	AK_LTGT, -1, -1, -1, -1, -1, -1, -1,
96 
97 	-1, -1, -1, -1, -1, -1, -1, -1,
98 	-1, -1, -1, -1, -1, -1, -1, -1
99 };
100 
101 
102 // Global variables
103 static bool reset_thyself = false;
104 
105 static key_info old_key_info;
106 static bool window_open;
107 static bool LEDs[4];
108 
109 static int the_argc;
110 static char **the_argv;
111 
112 static BJoystick *joy;
113 
114 
115 /*
116  *  A simple view class for blitting a bitmap on the screen
117  */
118 
119 class BitmapView : public BView {
120 public:
121 	BitmapView(BRect frame, BBitmap *bitmap);
122 	virtual void Draw(BRect update);
123 	virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
124 	void Draw(BRect from, BRect to);
125 
126 private:
127 	BBitmap *the_bitmap;
128 };
129 
130 static BitmapView *bitmap_view;
131 
132 
133 /*
134  *  The window in which the Amiga graphics are displayed, handles I/O
135  */
136 
137 class UAEWindow : public BWindow {
138 public:
139 	UAEWindow(BRect frame, BBitmap *bitmap);
140 	virtual bool QuitRequested(void);
141 	virtual void MessageReceived(BMessage *msg);
142 
143 private:
144 	BMessenger this_messenger;
145 	BitmapView *main_view;
146 	BFilePanel *floppy_panel;
147 	int panel_drive_num;
148 };
149 
150 static UAEWindow *bitmap_window;
151 
152 
153 /*
154  *  The BeOS application object
155  */
156 
157 class UAE : public BApplication {
158 public:
159 	UAE();
160 	virtual void ReadyToRun(void);
161 	virtual bool QuitRequested(void);
162 
163 	int GraphicsInit(void);
164 	void GraphicsLeave(void);
165 
166 private:
167 	static long thread_func(void *obj);
168 
169 	BBitmap *the_bitmap;
170 	UAEWindow *main_window;
171 	thread_id the_thread;
172 };
173 
174 static UAE *the_app;
175 
176 
177 /*
178  *	LED
179  */
180 
181 class LEDView : public BView {
182 public:
183 	LEDView(BRect frame, rgb_color active, rgb_color idle);
184 	virtual void Draw(BRect update);
185 	void SetState(bool new_state);
186 
187 private:
188 	BRect bounds;
189 	rgb_color active_color;
190 	rgb_color idle_color;
191 	bool state;
192 };
193 
194 static LEDView *PowerLED, *DriveLED[4];
195 
196 
197 /*
198  *  Create application object and start it
199  */
200 
main(int argc,char ** argv)201 int main(int argc, char **argv)
202 {
203 	// Copy command line arguments
204 	the_argc = argc;
205 	the_argv = new char *[argc];
206 	for (int i=0; i<argc; i++)
207 		the_argv[i] = strdup(argv[i]);
208 
209 	the_app = new UAE();
210 	the_app->Run();
211 	delete the_app;
212 	return 0;
213 }
214 
215 
216 /*
217  *  UAE Constructor: Initialize member variables
218  */
219 
UAE()220 UAE::UAE() : BApplication('UAEm')
221 {
222 	// Find application directory and cwd to it
223 	app_info the_info;
224 	GetAppInfo(&the_info);
225 	BEntry the_file(&the_info.ref);
226 	BEntry the_dir;
227 	the_file.GetParent(&the_dir);
228 	BPath the_path;
229 	the_dir.GetPath(&the_path);
230 	chdir(the_path.Path());
231 
232 	// Initialize other variables
233 	the_bitmap = NULL;
234 	main_window = NULL;
235 	window_open = false;
236 }
237 
238 
239 /*
240  *  Arguments processed, create and start emulation
241  */
242 
ReadyToRun(void)243 void UAE::ReadyToRun(void)
244 {
245 	// Start the emulation thread
246 	the_thread = spawn_thread(thread_func, "UAE 68000", B_NORMAL_PRIORITY, this);
247 	resume_thread(the_thread);
248 }
249 
250 
251 /*
252  *  Quit requested (either by menu or by closing the window)
253  */
254 
QuitRequested(void)255 bool UAE::QuitRequested(void)
256 {
257 	// Quit the thread
258 	uae_quit();
259 	status_t l;
260 	wait_for_thread(the_thread, &l);
261 	return true;
262 }
263 
264 
265 /*
266  *  The thread's main function
267  */
268 
thread_func(void * obj)269 long UAE::thread_func(void *obj)
270 {
271 	real_main(the_argc, the_argv);
272 	return 0;
273 }
274 
275 
276 /*
277  *  UAE Window constructor
278  */
279 
UAEWindow(BRect frame,BBitmap * bitmap)280 UAEWindow::UAEWindow(BRect frame, BBitmap *bitmap) : BWindow(frame,"UAE", B_TITLED_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE), this_messenger(this)
281 {
282 	int i;
283 
284 	// Initialize xcolors
285 	{
286 		BScreen scr(this);
287 		i = 0;
288 		for (int r=0; r<16; r++) {
289 			for (int g=0; g<16; g++) {
290 				for (int b=0; b<16; b++)
291 					xcolors[i++] = scr.IndexForColor(r<<4 | r, g<<4 | g, b<<4 | b);
292 			}
293 		}
294 	}
295 
296 	// Move window to right position
297 	Lock();
298 	MoveTo(80, 80);
299 
300 	// Set up menus
301 	BRect bounds = Bounds();
302 	bounds.OffsetBy(0, bounds.IntegerHeight() + 1);
303 	BMenuBar *bar = new BMenuBar(bounds, "menu");
304 	BMenu *menu = new BMenu("UAE");
305 	menu->AddItem(new BMenuItem("About UAE" B_UTF8_ELLIPSIS, new BMessage(MSG_ABOUT)));
306 	menu->AddItem(new BSeparatorItem);
307 	BMenu *submenu = new BMenu("Framerate");
308 	submenu->AddItem(new BMenuItem("1/1", new BMessage(MSG_FR1)));
309 	submenu->AddItem(new BMenuItem("1/2", new BMessage(MSG_FR2)));
310 	submenu->AddItem(new BMenuItem("1/3", new BMessage(MSG_FR3)));
311 	submenu->AddItem(new BMenuItem("1/4", new BMessage(MSG_FR4)));
312 	submenu->AddItem(new BMenuItem("1/5", new BMessage(MSG_FR5)));
313 	submenu->AddItem(new BMenuItem("1/6", new BMessage(MSG_FR6)));
314 	submenu->SetRadioMode(true);
315 	menu->AddItem(submenu);
316 	menu->AddItem(new BMenuItem("Reset", new BMessage(MSG_RESET)));
317 	menu->AddItem(new BMenuItem("Debugger", new BMessage(MSG_DEBUG)));
318 	menu->AddItem(new BSeparatorItem);
319 	menu->AddItem(new BMenuItem("Quit", new BMessage(MSG_QUIT)));
320 	bar->AddItem(menu);
321 	menu = new BMenu("Floppy");
322 	submenu = new BMenu("DF0");
323 	submenu->AddItem(new BMenuItem("Insert" B_UTF8_ELLIPSIS, new BMessage(MSG_INSERT_DF0)));
324 	submenu->AddItem(new BMenuItem("Eject", new BMessage(MSG_EJECT_DF0)));
325 	menu->AddItem(submenu);
326 	submenu = new BMenu("DF1");
327 	submenu->AddItem(new BMenuItem("Insert" B_UTF8_ELLIPSIS, new BMessage(MSG_INSERT_DF1)));
328 	submenu->AddItem(new BMenuItem("Eject", new BMessage(MSG_EJECT_DF1)));
329 	menu->AddItem(submenu);
330 	submenu = new BMenu("DF2");
331 	submenu->AddItem(new BMenuItem("Insert" B_UTF8_ELLIPSIS, new BMessage(MSG_INSERT_DF2)));
332 	submenu->AddItem(new BMenuItem("Eject", new BMessage(MSG_EJECT_DF2)));
333 	menu->AddItem(submenu);
334 	submenu = new BMenu("DF3");
335 	submenu->AddItem(new BMenuItem("Insert" B_UTF8_ELLIPSIS, new BMessage(MSG_INSERT_DF3)));
336 	submenu->AddItem(new BMenuItem("Eject", new BMessage(MSG_EJECT_DF3)));
337 	menu->AddItem(submenu);
338 	bar->AddItem(menu);
339 	AddChild(bar);
340 	bar->ResizeBy(-5*4, 0);	// Make room for LEDs
341 	int mbar_height = bar->Frame().IntegerHeight() + 1;
342 
343 	// Resize window to fit menu bar
344 	ResizeBy(0, mbar_height);
345 
346 	// Create LEDs
347 	BRect PowerRect = bar->Frame();
348 	PowerRect.left = PowerRect.right+1;
349 	PowerRect.right = PowerRect.left+3;
350 	PowerLED = new LEDView(PowerRect, PowerLight, PowerDark);
351 	AddChild(PowerLED);
352 
353 	BRect DriveRect = PowerRect;
354 	for (i=0; i<4; i++) {
355 		DriveRect.left += 4;
356 		DriveRect.right += 4;
357 		DriveLED[i] = new LEDView(DriveRect, DriveLight, DriveDark);
358 		AddChild(DriveLED[i]);
359 	}
360 
361 	// Create bitmap view
362 	BRect BitmapRect = frame;
363 	main_view = new BitmapView(BitmapRect, bitmap);
364 	AddChild(main_view);
365 	main_view->MakeFocus();
366 	get_key_info(&old_key_info);
367 
368 	bitmap_view = main_view;
369 	bitmap_window = this;
370 
371 	// Create file panel
372 	floppy_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, 0, false, new BMessage(MSG_FLOPPY_PANEL_RETURNED));
373 	panel_drive_num = 0;
374 
375 	// Show window
376 	Unlock();
377 	Show();
378 	window_open = true;
379 }
380 
381 
382 /*
383  *  Message received
384  */
385 
MessageReceived(BMessage * msg)386 void UAEWindow::MessageReceived(BMessage *msg)
387 {
388 	BMessage *msg2;
389 
390 	switch(msg->what) {
391 		case MSG_INSERT_DF0:
392 			panel_drive_num = 0;
393 			floppy_panel->Hide();
394 			floppy_panel->Window()->SetTitle("UAE: Insert floppy in DF0:");
395 			floppy_panel->Show();
396 			break;
397 
398 		case MSG_EJECT_DF0:
399 			disk_eject(0);
400 			break;
401 
402 		case MSG_INSERT_DF1:
403 			panel_drive_num = 1;
404 			floppy_panel->Hide();
405 			floppy_panel->Window()->SetTitle("UAE: Insert floppy in DF1:");
406 			floppy_panel->Show();
407 			break;
408 
409 		case MSG_EJECT_DF1:
410 			disk_eject(1);
411 			break;
412 
413 		case MSG_INSERT_DF2:
414 			panel_drive_num = 2;
415 			floppy_panel->Hide();
416 			floppy_panel->Window()->SetTitle("UAE: Insert floppy in DF2:");
417 			floppy_panel->Show();
418 			break;
419 
420 		case MSG_EJECT_DF2:
421 			disk_eject(2);
422 			break;
423 
424 		case MSG_INSERT_DF3:
425 			panel_drive_num = 3;
426 			floppy_panel->Hide();
427 			floppy_panel->Window()->SetTitle("UAE: Insert floppy in DF3:");
428 			floppy_panel->Show();
429 			break;
430 
431 		case MSG_EJECT_DF3:
432 			disk_eject(3);
433 			break;
434 
435 		case MSG_FLOPPY_PANEL_RETURNED: {
436 			entry_ref the_ref;
437 			BEntry the_entry;
438 			if (msg->FindRef("refs", &the_ref) == B_NO_ERROR)
439 				if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
440 					BPath the_path;
441 					the_entry.GetPath(&the_path);
442 					disk_eject(panel_drive_num);
443 					disk_insert(panel_drive_num, the_path.Path());
444 				}
445 			break;
446 		}
447 
448 		case MSG_FR1:
449 			currprefs.framerate = 1;
450 			break;
451 		case MSG_FR2:
452 			currprefs.framerate = 2;
453 			break;
454 		case MSG_FR3:
455 			currprefs.framerate = 3;
456 			break;
457 		case MSG_FR4:
458 			currprefs.framerate = 4;
459 			break;
460 		case MSG_FR5:
461 			currprefs.framerate = 5;
462 			break;
463 		case MSG_FR6:
464 			currprefs.framerate = 6;
465 			break;
466 
467 		case MSG_RESET:
468 			reset_thyself = true;
469 			break;
470 
471 		case MSG_DEBUG:
472 			activate_debugger();
473 			break;
474 
475 		case MSG_QUIT:
476 			be_app->PostMessage(B_QUIT_REQUESTED);
477 			break;
478 
479 		case MSG_ABOUT: {
480 			char str[256];
481 			sprintf(str, "     Un*x Amiga Emulator V%d.%d.%d\n"
482 				     	"          by Bernd Schmidt\n"
483 				     	"    BeBox port by Christian Bauer\n"
484 				     	"Additional porting by Patrick Hanevold", UAEMAJOR, UAEMINOR, UAEURSAMINOR);
485 			BAlert *the_alert = new BAlert("", str, "OK");
486 			the_alert->Go();
487 			break;
488 		}
489 
490 		case MSG_REDRAW:
491 			MessageQueue()->Lock();
492 			while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
493 				MessageQueue()->RemoveMessage(msg2);
494 				delete msg2;
495 			}
496 			MessageQueue()->Unlock();
497 			Lock();
498 			main_view->Draw(BRect(0, 0, currprefs.gfx_width-1, currprefs.gfx_height-1));
499 			Unlock();
500 			break;
501 
502 		default:
503 			BWindow::MessageReceived(msg);
504 			break;
505 	}
506 }
507 
508 
509 /*
510  *  Closing the window quits UAE
511  */
512 
QuitRequested(void)513 bool UAEWindow::QuitRequested(void)
514 {
515 	window_open = false;
516 	be_app->PostMessage(B_QUIT_REQUESTED);
517 	return false;
518 }
519 
520 
521 /*
522  *  Bitmap view constructor
523  */
524 
BitmapView(BRect frame,BBitmap * bitmap)525 BitmapView::BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW)
526 {
527 	the_bitmap = bitmap;
528 }
529 
530 
531 /*
532  *  Blit the bitmap
533  */
534 
Draw(BRect update)535 void BitmapView::Draw(BRect update)
536 {
537 	DrawBitmap(the_bitmap, update, update);
538 }
539 
Draw(BRect from,BRect to)540 void BitmapView::Draw(BRect from, BRect to)
541 {
542 	DrawBitmap(the_bitmap, from, to);
543 }
544 
545 
546 /*
547  *  Mouse moved
548  */
549 
MouseMoved(BPoint point,uint32 transit,const BMessage * message)550 void BitmapView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
551 {
552 	newmousecounters = 0;
553 	switch (transit) {
554 		case B_ENTERED_VIEW:
555 			newmousecounters = 1;
556 			lastmx = point.x;
557 			lastmy = point.y;
558 			break;
559 		case B_EXITED_VIEW:
560 			break;
561 		case B_INSIDE_VIEW:
562 			lastmx = point.x;
563 			lastmy = point.y;
564 			break;
565 	}
566 }
567 
568 
569 /*
570  *  LED
571  */
572 
LEDView(BRect frame,rgb_color active,rgb_color idle)573 LEDView::LEDView(BRect frame, rgb_color active, rgb_color idle) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW)
574 {
575 	active_color = active;
576 	idle_color = idle;
577 	state = false;
578 	SetViewColor(idle_color);
579 	SetHighColor(idle_color);
580 	bounds = Bounds();
581 }
582 
Draw(BRect update)583 void LEDView::Draw(BRect update)
584 {
585 	FillRect(bounds);
586 }
587 
SetState(bool new_state)588 void LEDView::SetState(bool new_state)
589 {
590 	if (new_state != state) {
591 		state = new_state;
592 		Window()->Lock();
593 		if (state) {
594 			SetViewColor(active_color);
595 			SetHighColor(active_color);
596 		} else {
597 			SetViewColor(idle_color);
598 			SetHighColor(idle_color);
599 		}
600 		Draw(bounds);
601 		Window()->Unlock();
602 	}
603 }
604 
605 
606 /*
607  *  Redraw a line
608  */
609 
flush_line(int y)610 void flush_line(int y)
611 {
612 	if (window_open) {
613 		bitmap_window->Lock();
614 		bitmap_view->Draw(BRect(0, y, currprefs.gfx_width-1, y));
615 		bitmap_window->Unlock();
616 	}
617 }
618 
619 
620 /*
621  *  Redraw a block
622  */
623 
flush_block(int ystart,int ystop)624 void flush_block(int ystart, int ystop)
625 {
626 }
627 
628 
629 /*
630  *  Redraw the screen
631  */
632 
flush_screen(int ystart,int ystop)633 void flush_screen(int ystart, int ystop)
634 {
635 	if (window_open)
636 		bitmap_window->PostMessage(new BMessage(MSG_REDRAW));
637 }
638 
639 
640 /*
641  *  Init graphics
642  */
643 
graphics_setup(void)644 int graphics_setup(void)
645 {
646 	return 1;
647 }
648 
graphics_init(void)649 int graphics_init(void)
650 {
651 	return the_app->GraphicsInit();
652 }
653 
GraphicsInit(void)654 int UAE::GraphicsInit(void)
655 {
656 	if (currprefs.color_mode > 5)
657 		fprintf(stderr, "Bad color mode selected. Using default.\n"), currprefs.color_mode = 0;
658 
659 	if (currprefs.gfx_width < 320)
660 		currprefs.gfx_width = 320;
661 	if (currprefs.gfx_height < 200)
662 		currprefs.gfx_height = 200;
663 	if (currprefs.gfx_height > 300 && ! currprefs.gfx_linedbl)
664 		currprefs.gfx_height = 300;
665 	if (currprefs.gfx_height > 600)
666 		currprefs.gfx_height = 600;
667 
668 	gfxvidinfo.width = currprefs.gfx_width;
669 	gfxvidinfo.height = currprefs.gfx_height;
670 	gfxvidinfo.can_double = 1;
671 
672 	// Allocate bitmap
673 	the_bitmap = new BBitmap(BRect(0, 0, currprefs.gfx_width-1, currprefs.gfx_height-1), B_COLOR_8_BIT);
674 
675 	// Set up vidinfo
676 	gfxvidinfo.pixbytes = 1;
677 	gfxvidinfo.rowbytes = the_bitmap->BytesPerRow();
678 	gfxvidinfo.bufmem = (char *)the_bitmap->Bits();
679 	gfxvidinfo.linemem = NULL;
680 	gfxvidinfo.maxblocklines = 100; /* whatever... */
681 
682 	// Open window
683 	main_window = new UAEWindow(BRect(0, 0, currprefs.gfx_width-1, currprefs.gfx_height-1), the_bitmap);
684 
685 	// Initialize mouse and keyboard variables
686 	buttonstate[0] = buttonstate[1] = buttonstate[2] = 0;
687 	lastmx = lastmy = 0;
688 	newmousecounters = 0;
689 
690 	return true;
691 }
692 
693 
694 /*
695  * Exit graphics
696  */
697 
graphics_leave(void)698 void graphics_leave(void)
699 {
700 	the_app->GraphicsLeave();
701 }
702 
GraphicsLeave(void)703 void UAE::GraphicsLeave(void)
704 {
705 	// Deallocate bitmap
706 	delete the_bitmap;
707 }
708 
709 
710 /*
711  *  Poll mouse and keyboard
712  */
713 
handle_events(void)714 void handle_events(void)
715 {
716 	key_info the_key_info;
717 	int be_code, be_byte, be_bit, amiga_code;
718 	BPoint mouse_point;
719 	uint32 mouse_buttons;
720 
721 	if (reset_thyself) {
722 		uae_reset();
723 		reset_thyself = false;
724 	}
725 
726 	// Redraw drive LEDs
727 	for (int i=0; i<4; i++)
728 		DriveLED[i]->SetState(LEDs[i]);
729 
730 	if (window_open && bitmap_window->IsActive()) {
731 
732 		get_key_info(&the_key_info);
733 		bitmap_window->Lock();
734 		bitmap_view->GetMouse(&mouse_point, &mouse_buttons, false);
735 		bitmap_window->Unlock();
736 
737 		// Keyboard
738 		if (memcmp(the_key_info.key_states, old_key_info.key_states, sizeof(the_key_info.key_states))) {
739 			for (be_code=0; be_code<0x80; be_code++) {
740 				be_byte = be_code >> 3;
741 				be_bit = 1 << (~be_code & 7);
742 
743 				// Key state changed?
744 				if ((the_key_info.key_states[be_byte] & be_bit)
745 				     != (old_key_info.key_states[be_byte] & be_bit)) {
746 
747 					amiga_code = keycode2amiga[be_code];
748 					if (the_key_info.key_states[be_byte] & be_bit) {
749 
750 						// Key pressed
751 						if (amiga_code == AK_mousestuff)
752 							togglemouse();
753 						else
754 							record_key(amiga_code << 1);
755 					} else {
756 
757 						// Key released
758 						record_key((amiga_code << 1) | 1);
759 					}
760 				}
761 			}
762 			old_key_info = the_key_info;
763 		}
764 
765 		// "Affengriff"
766 		if ((the_key_info.key_states[0x5c >> 3] & (1 << (~0x5c & 7)))
767 		 && (the_key_info.key_states[0x5d >> 3] & (1 << (~0x5d & 7)))
768 		 && (the_key_info.key_states[0x5f >> 3] & (1 << (~0x5f & 7))))
769 			m68k_reset();
770 
771 		// Scroll lock toggles inhibit_frame
772 		if (inhibit_frame != 2)
773 			inhibit_frame = the_key_info.key_states[0x0f >> 3] & (1 << (~0x0f & 7));
774 
775 		// Mouse buttons
776 		if (mouse_point.x >= 0 && mouse_point.y >= 0 && mouse_point.x < currprefs.gfx_width && mouse_point.y < currprefs.gfx_height) {
777 			buttonstate[0] = mouse_buttons & B_PRIMARY_MOUSE_BUTTON;
778 			buttonstate[1] = mouse_buttons & B_TERTIARY_MOUSE_BUTTON;
779 			buttonstate[2] = mouse_buttons & B_SECONDARY_MOUSE_BUTTON;
780 		}
781 	}
782 }
783 
784 
785 /*
786  *  Joystick routines
787  */
788 
789 extern "C" {
790 void init_joystick(void);
791 void close_joystick(void);
792 void read_joystick(int nr, unsigned int *dir, int *button);
793 };
794 
795 int nr_joysticks;
796 
read_joystick(int nr,unsigned int * dir,int * button)797 void read_joystick(int nr, unsigned int *dir, int *button)
798 {
799 	static int joy_minx = 32767, joy_maxx = 0,
800 			   joy_miny = 32767, joy_maxy = 0;
801 	int left = 0, right = 0, top = 0, bot = 0;
802 
803 	*dir = 0;
804 	*button = 0;
805 
806 	if (nr >= nr_joysticks)
807 		return;
808 
809 	if (joy->Update() != B_ERROR) {
810 		if (joy->horizontal > joy_maxx)
811 			joy_maxx = joy->horizontal;
812 		if (joy->horizontal < joy_minx)
813 			joy_minx = joy->horizontal;
814 		if (joy->vertical > joy_maxy)
815 			joy_maxy = joy->vertical;
816 		if (joy->vertical < joy_miny)
817 			joy_miny = joy->vertical;
818 
819 		if (joy_maxx-joy_minx < 100 || joy_maxy-joy_miny < 100)
820 			return;
821 
822 		if (joy->horizontal < (joy_minx + (joy_maxx-joy_minx)/3))
823 			right = 1;
824 		else if (joy->horizontal > (joy_minx + 2*(joy_maxx-joy_minx)/3))
825 			left = 1;
826 
827 		if (joy->vertical < (joy_miny + (joy_maxy-joy_miny)/3))
828 			bot = 1;
829 		else if (joy->vertical > (joy_miny + 2*(joy_maxy-joy_miny)/3))
830 			top = 1;
831 
832 		if (left) top = !top;
833 		if (right) bot = !bot;
834 	    *dir = bot | (right << 1) | (top << 8) | (left << 9);
835 	    *button = !joy->button1;
836 	}
837 }
838 
init_joystick(void)839 void init_joystick(void)
840 {
841 	joy = new BJoystick();
842 	joy->Open("joystick1");
843 	nr_joysticks = 1;
844 }
845 
close_joystick(void)846 void close_joystick(void)
847 {
848 	joy->Close();
849 	delete joy;
850 }
851 
852 
853 /*
854  *  Sound routines
855  */
856 
857 extern "C" {
858 extern int sound_available;
859 extern int smplcnt;
860 extern int init_sound(void);
861 extern int setup_sound(void);
862 extern void flush_sound_buffer(void);
863 extern void init_sound_table16(void);
864 extern void sample16_handler(void);
865 };
866 
867 uae_u16 *sndbuffer;
868 uae_u16 *sndbufpt;
869 int sndbufsize;
870 
871 static uint8 *buffers[2] = {NULL, NULL};
872 static int buf_num;
873 static BDACStream *the_stream;
874 static BSubscriber *the_sub;
875 static bool sound_ready = false;
876 static sem_id sound_sync_sem;
877 
878 bool stream_func(void *arg, char *buf, size_t count, void *header);
879 
init_sound(void)880 int init_sound(void)
881 {
882 	sound_sync_sem = create_sem(0, "UAE Sound Sync Semaphore");
883 	the_stream = new BDACStream();
884 	the_sub = new BSubscriber("UAE DAC subscriber");
885 
886 	if (!currprefs.produce_sound)
887 		return 0;
888 	sound_ready = the_sub->Subscribe(the_stream) == B_NO_ERROR;
889 	if (!sound_ready)
890 		return 0;
891 
892 	sndbufsize = 44100 / 8 * 4;
893 	buffers[0] = new uint8[sndbufsize];
894 	buffers[1] = new uint8[sndbufsize];
895 	memset(buffers[0], 0, sndbufsize);
896 	memset(buffers[1], 0, sndbufsize);
897 	buf_num = 0;
898 	sndbufpt = sndbuffer = (uae_u16 *)buffers[buf_num];
899 
900 	init_sound_table16();
901 	eventtab[ev_sample].handler = sample16_handler;
902 	scaled_sample_evtime = (unsigned long)maxhpos * maxvpos * vblank_hz * CYCLE_UNIT / 44100;
903 	scaled_sample_evtime_ok = 1;
904 
905 	sound_available = 1;
906 	the_stream->SetSamplingRate(44100);
907 	the_stream->SetStreamBuffers(sndbufsize, 4);
908 	the_sub->EnterStream(NULL, true, NULL, stream_func, NULL, true);
909 	return 1;
910 }
911 
setup_sound(void)912 int setup_sound(void)
913 {
914 	sound_available = 1;
915 	return 1;
916 }
917 
close_sound(void)918 void close_sound(void)
919 {
920 	if (sound_ready) {
921 		the_sub->ExitStream(true);
922 		the_stream->SetStreamBuffers(4096, 8);
923 		the_sub->Unsubscribe();
924 		sound_ready = false;
925 	}
926 	delete the_sub;
927 	delete the_stream;
928 
929 	delete_sem(sound_sync_sem);
930 
931 	delete buffers[0];
932 	delete buffers[1];
933 }
934 
flush_sound_buffer(void)935 void flush_sound_buffer(void)
936 {
937 	if (sound_ready) {
938 		long l;
939 		get_sem_count(sound_sync_sem, &l);
940 		if (l > 0)
941 			acquire_sem_etc(sound_sync_sem, l+1, 0, 0);
942 		else
943 			acquire_sem(sound_sync_sem);
944 	}
945 
946 	sndbufpt = sndbuffer = (uae_u16 *)buffers[buf_num];
947 	buf_num ^= 1;
948 }
949 
stream_func(void * arg,char * buf,size_t count,void * header)950 bool stream_func(void *arg, char *buf, size_t count, void *header)
951 {
952 	memcpy(buf, buffers[buf_num], count);
953 	release_sem(sound_sync_sem);
954 	return true;
955 }
956 
957 
958 /*
959  *  Misc routines
960  */
961 
debuggable(void)962 int debuggable(void)
963 {
964     return true;
965 }
966 
needmousehack(void)967 int needmousehack(void)
968 {
969     return true;
970 }
971 
LED(int on)972 void LED(int on)
973 {
974 	PowerLED->SetState(!on);
975 }
976 
setup_brkhandler(void)977 void setup_brkhandler(void)
978 {
979 }
980 
gui_changesettings(void)981 void gui_changesettings(void)
982 {
983 }
984 
gui_led(int led,int on)985 void gui_led(int led, int on)
986 {
987 	if (led > 0 && led < 5)
988 		LEDs[led-1] = on;
989 }
990 
gui_init(void)991 int gui_init(void)
992 {
993 	LEDs[0] = LEDs[1] = LEDs[2] = LEDs[3] = false;
994 	quit_program = 0;
995 	return 0;
996 }
997 
gui_exit(void)998 void gui_exit(void)
999 {
1000 }
1001 
gui_update(void)1002 int gui_update(void)
1003 {
1004 	return 0;
1005 }
1006 
gui_filename(int num,const char * name)1007 void gui_filename(int num, const char *name)
1008 {
1009 }
1010 
getline(char * p)1011 static void getline(char *p)
1012 {
1013 }
1014 
gui_handle_events(void)1015 void gui_handle_events(void)
1016 {
1017 }
1018