ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_Amiga.h
Revision: 1.6
Committed: 2009-01-11T11:32:38Z (13 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +2 -2 lines
Log Message:
const correctness

File Contents

# Content
1 /*
2 * Display_Amiga.h - C64 graphics display, emulator window handling,
3 * Amiga specific stuff
4 *
5 * Frodo (C) 1994-1997,2002-2009 Christian Bauer
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <exec/types.h>
23 #include <exec/memory.h>
24 #include <intuition/intuition.h>
25 #include <libraries/gadtools.h>
26 #include <libraries/asl.h>
27 #include <proto/exec.h>
28 #include <proto/graphics.h>
29 #include <proto/intuition.h>
30 #include <proto/dos.h>
31 #include <proto/gadtools.h>
32 #include <proto/diskfont.h>
33 #include <proto/asl.h>
34
35 #include "C64.h"
36 #include "SAM.h"
37 #include "Version.h"
38
39
40 /*
41 C64 keyboard matrix:
42
43 Bit 7 6 5 4 3 2 1 0
44 0 CUD F5 F3 F1 F7 CLR RET DEL
45 1 SHL E S Z 4 A W 3
46 2 X T F C 6 D R 5
47 3 V U H B 8 G Y 7
48 4 N O K M 0 J I 9
49 5 , @ : . - L P +
50 6 / ^ = SHR HOM ; * £
51 7 R/S Q C= SPC 2 CTL <- 1
52 */
53
54
55 /*
56 Tables for key translation
57 Bit 0..2: row/column in C64 keyboard matrix
58 Bit 3 : implicit shift
59 Bit 5 : joystick emulation (bit 0..4: mask)
60 */
61
62 const int key_byte[128] = {
63 7, 7, 7, 1, 1, 2, 2, 3,
64 3, 4, 4, 5, 5, 6, -1,0x30,
65 7, 1, 1, 2, 2, 3, 3, 4,
66 4, 5, 5, 6, -1,0x26,0x22,0x2a,
67 1, 1, 2, 2, 3, 3, 4, 4,
68 5, 5, 6, 6, -1,0x24,0x30,0x28,
69 6, 1, 2, 2, 3, 3, 4, 4,
70 5, 5, 6, -1, -1,0x25,0x21,0x29,
71 7, 0, -1, 0, 0, 7, 6, -1,
72 -1, -1, -1, -1,8+0, 0, 0, 8+0,
73 0,8+0, 0,8+0, 0, 8+0, 0, 8+0,
74 -1, -1, 6, 6, -1, -1, -1, -1,
75 1, 6, 1, 7, 7, 7, 7, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, -1,
78 -1, -1, -1, -1, -1, -1, -1, -1
79 };
80
81 const int key_bit[128] = {
82 1, 0, 3, 0, 3, 0, 3, 0,
83 3, 0, 3, 0, 3, 0, -1, -1,
84 6, 1, 6, 1, 6, 1, 6, 1,
85 6, 1, 6, 1, -1, -1, -1, -1,
86 2, 5, 2, 5, 2, 5, 2, 5,
87 2, 5, 2, 5, -1, -1, -1, -1,
88 6, 4, 7, 4, 7, 4, 7, 4,
89 7, 4, 7, -1, -1, -1, -1, -1,
90 4, 0, -1, 1, 1, 7, 3, -1,
91 -1, -1, -1, -1, 7, 7, 2, 2,
92 4, 4, 5, 5, 6, 6, 3, 3,
93 -1, -1, 6, 5, -1, -1, -1, -1,
94 7, 4, 7, 2, 5, 5, 5, -1,
95 -1, -1, -1, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, -1,
97 -1, -1, -1, -1, -1, -1, -1, -1
98 };
99
100
101 /*
102 * Menu definitions
103 */
104
105 const struct NewMenu new_menus[] = {
106 NM_TITLE, "Frodo", NULL, 0, 0, NULL,
107 NM_ITEM, "About Frodo...", NULL, 0, 0, NULL,
108 NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
109 NM_ITEM, "Preferences...", "P", 0, 0, NULL,
110 NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
111 NM_ITEM, "Reset C64", NULL, 0, 0, NULL,
112 NM_ITEM, "Insert next disk", "D", 0, 0, NULL,
113 NM_ITEM, "SAM...", "M", 0, 0, NULL,
114 NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
115 NM_ITEM, "Load snapshot...", "O", 0, 0, NULL,
116 NM_ITEM, "Save snapshot...", "S", 0, 0, NULL,
117 NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
118 NM_ITEM, "Quit Frodo", "Q", 0, 0, NULL,
119 NM_END, NULL, NULL, 0, 0, NULL
120 };
121
122
123 /*
124 * Font attributes
125 */
126
127 const struct TextAttr led_font_attr = {
128 "Helvetica.font", 11, FS_NORMAL, 0
129 };
130
131 const struct TextAttr speedo_font_attr = {
132 "Courier.font", 11, FS_NORMAL, 0
133 };
134
135
136 /*
137 * Display constructor: Create window/screen
138 */
139
140 C64Display::C64Display(C64 *the_c64) : TheC64(the_c64)
141 {
142 int i;
143
144 // LEDs off
145 for (i=0; i<4; i++)
146 led_state[i] = old_led_state[i] = LED_OFF;
147
148 // Allocate chunky buffer to draw into
149 chunky_buf = new UBYTE[DISPLAY_X * DISPLAY_Y];
150
151 // Open fonts
152 led_font = OpenDiskFont(&led_font_attr);
153 speedo_font = OpenDiskFont(&speedo_font_attr);
154
155 // Open window on default pubscreen
156 the_window = OpenWindowTags(NULL,
157 WA_Left, 0,
158 WA_Top, 0,
159 WA_InnerWidth, DISPLAY_X,
160 WA_InnerHeight, DISPLAY_Y + 16,
161 WA_Title, (ULONG)"Frodo",
162 WA_ScreenTitle, (ULONG)"Frodo C64 Emulator",
163 WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | IDCMP_MENUPICK | IDCMP_REFRESHWINDOW,
164 WA_DragBar, TRUE,
165 WA_DepthGadget, TRUE,
166 WA_CloseGadget, TRUE,
167 WA_SimpleRefresh, TRUE,
168 WA_Activate, TRUE,
169 WA_NewLookMenus, TRUE,
170 TAG_DONE);
171 the_screen = the_window->WScreen;
172 the_rp = the_window->RPort;
173 xo = the_window->BorderLeft;
174 yo = the_window->BorderTop;
175
176 // Create menus
177 the_visual_info = GetVisualInfo(the_screen, NULL);
178 the_menus = CreateMenus(new_menus, GTMN_FullMenu, TRUE, TAG_DONE);
179 LayoutMenus(the_menus, the_visual_info, GTMN_NewLookMenus, TRUE, TAG_DONE);
180 SetMenuStrip(the_window, the_menus);
181
182 // Obtain 16 pens for the C64 colors
183 for (i=0; i<16; i++)
184 pens[i] = ObtainBestPen(the_screen->ViewPort.ColorMap,
185 palette_red[i] * 0x01010101, palette_green[i] * 0x01010101, palette_blue[i] * 0x01010101);
186
187 // Allocate temporary RastPort for WritePixelArra8()
188 temp_bm = AllocBitMap(DISPLAY_X, 1, 8, 0, NULL);
189 InitRastPort(&temp_rp);
190 temp_rp.BitMap = temp_bm;
191
192 // Draw LED bar
193 draw_led_bar();
194
195 // Allocate file requesters
196 open_req = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
197 ASLFR_Window, (ULONG)the_window,
198 ASLFR_SleepWindow, TRUE,
199 ASLFR_TitleText, (ULONG)"Frodo: Load snapshot...",
200 ASLFR_RejectIcons, TRUE,
201 TAG_DONE);
202 save_req = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
203 ASLFR_Window, (ULONG)the_window,
204 ASLFR_SleepWindow, TRUE,
205 ASLFR_TitleText, (ULONG)"Frodo: Save snapshot...",
206 ASLFR_DoSaveMode, TRUE,
207 ASLFR_RejectIcons, TRUE,
208 TAG_DONE);
209 }
210
211
212 /*
213 * Display destructor
214 */
215
216 C64Display::~C64Display()
217 {
218 // Free file requesters
219 if (open_req != NULL)
220 FreeAslRequest(open_req);
221 if (save_req != NULL)
222 FreeAslRequest(save_req);
223
224 // Free temporary RastPort
225 if (temp_bm != NULL)
226 FreeBitMap(temp_bm);
227
228 // Free pens
229 for (int i=0; i<16; i++)
230 ReleasePen(the_screen->ViewPort.ColorMap, pens[i]);
231
232 // Delete menus
233 if (the_menus != NULL) {
234 if (the_window != NULL)
235 ClearMenuStrip(the_window);
236 FreeMenus(the_menus);
237 }
238
239 // Delete VisualInfo
240 if (the_visual_info != NULL)
241 FreeVisualInfo(the_visual_info);
242
243 // Close window
244 if (the_window != NULL)
245 CloseWindow(the_window);
246
247 // Close fonts
248 CloseFont(speedo_font);
249 CloseFont(led_font);
250
251 // Free chunky buffer
252 delete chunky_buf;
253 }
254
255
256 /*
257 * Prefs may have changed
258 */
259
260 void C64Display::NewPrefs(Prefs *prefs)
261 {
262 }
263
264
265 /*
266 * Redraw bitmap
267 */
268
269 void C64Display::Update(void)
270 {
271 // Update C64 display
272 WritePixelArray8(the_rp, xo, yo, DISPLAY_X + xo - 1, DISPLAY_Y + yo - 1,
273 chunky_buf, &temp_rp);
274
275 // Update drive LEDs
276 for (int i=0; i<4; i++)
277 if (led_state[i] != old_led_state[i]) {
278 draw_led(i, led_state[i]);
279 old_led_state[i] = led_state[i];
280 }
281 }
282
283
284 /*
285 * Draw LED bar at the bottom of the window
286 */
287
288 void C64Display::draw_led_bar(void)
289 {
290 int i;
291 char str[16];
292
293 SetAPen(the_rp, pens[15]); // Light gray
294 SetBPen(the_rp, pens[15]); // Light gray
295 RectFill(the_rp, xo, yo+DISPLAY_Y, xo+DISPLAY_X-1, yo+DISPLAY_Y+15);
296
297 SetAPen(the_rp, pens[1]); // White
298 Move(the_rp, xo, yo+DISPLAY_Y); Draw(the_rp, xo+DISPLAY_X-1, yo+DISPLAY_Y);
299 for (i=0; i<5; i++) {
300 Move(the_rp, xo+DISPLAY_X*i/5, yo+DISPLAY_Y); Draw(the_rp, xo+DISPLAY_X*i/5, yo+DISPLAY_Y+14);
301 }
302 for (i=2; i<6; i++) {
303 Move(the_rp, xo+DISPLAY_X*i/5-23, yo+DISPLAY_Y+11); Draw(the_rp, xo+DISPLAY_X*i/5-9, yo+DISPLAY_Y+11);
304 Move(the_rp, xo+DISPLAY_X*i/5-9, yo+DISPLAY_Y+11); Draw(the_rp, xo+DISPLAY_X*i/5-9, yo+DISPLAY_Y+5);
305 }
306
307 SetAPen(the_rp, pens[12]); // Medium gray
308 Move(the_rp, xo, yo+DISPLAY_Y+15); Draw(the_rp, xo+DISPLAY_X-1, yo+DISPLAY_Y+15);
309 for (i=1; i<6; i++) {
310 Move(the_rp, xo+DISPLAY_X*i/5-1, yo+DISPLAY_Y+1); Draw(the_rp, xo+DISPLAY_X*i/5-1, yo+DISPLAY_Y+15);
311 }
312 for (i=2; i<6; i++) {
313 Move(the_rp, xo+DISPLAY_X*i/5-24, yo+DISPLAY_Y+11); Draw(the_rp, xo+DISPLAY_X*i/5-24, yo+DISPLAY_Y+4);
314 Move(the_rp, xo+DISPLAY_X*i/5-24, yo+DISPLAY_Y+4); Draw(the_rp, xo+DISPLAY_X*i/5-9, yo+DISPLAY_Y+4);
315 }
316
317 SetFont(the_rp, led_font);
318 for (i=0; i<4; i++) {
319 sprintf(str, "Drive %d", i+8);
320 SetAPen(the_rp, pens[0]); // Black
321 Move(the_rp, xo+DISPLAY_X*(i+1)/5+8, yo+DISPLAY_Y+11);
322 Text(the_rp, str, strlen(str));
323 draw_led(i, LED_OFF);
324 }
325 }
326
327
328 /*
329 * Draw one LED
330 */
331
332 void C64Display::draw_led(int num, int state)
333 {
334 switch (state) {
335 case LED_OFF:
336 case LED_ERROR_OFF:
337 SetAPen(the_rp, pens[0]); // Black;
338 break;
339 case LED_ON:
340 SetAPen(the_rp, pens[5]); // Green
341 break;
342 case LED_ERROR_ON:
343 SetAPen(the_rp, pens[2]); // Red
344 break;
345 }
346 RectFill(the_rp, xo+DISPLAY_X*(num+2)/5-23, yo+DISPLAY_Y+5, xo+DISPLAY_X*(num+2)/5-10, yo+DISPLAY_Y+10);
347 }
348
349
350 /*
351 * Update speedometer
352 */
353
354 void C64Display::Speedometer(int speed)
355 {
356 static int delay = 0;
357
358 if (delay >= 20) {
359 char str[16];
360 sprintf(str, "%d%%", speed);
361 SetAPen(the_rp, pens[15]); // Light gray
362 RectFill(the_rp, xo+1, yo+DISPLAY_Y+1, xo+DISPLAY_X/5-2, yo+DISPLAY_Y+14);
363 SetAPen(the_rp, pens[0]); // Black
364 SetFont(the_rp, speedo_font);
365 Move(the_rp, xo+24, yo+DISPLAY_Y+10);
366 Text(the_rp, str, strlen(str));
367 delay = 0;
368 } else
369 delay++;
370 }
371
372
373 /*
374 * Return pointer to bitmap data
375 */
376
377 UBYTE *C64Display::BitmapBase(void)
378 {
379 return chunky_buf;
380 }
381
382
383 /*
384 * Return number of bytes per row
385 */
386
387 int C64Display::BitmapXMod(void)
388 {
389 return DISPLAY_X;
390 }
391
392
393 /*
394 * Handle IDCMP messages
395 */
396
397 void C64Display::PollKeyboard(UBYTE *key_matrix, UBYTE *rev_matrix, UBYTE *joystick)
398 {
399 struct IntuiMessage *msg;
400
401 // Get and analyze all pending window messages
402 while ((msg = (struct IntuiMessage *)GetMsg(the_window->UserPort)) != NULL) {
403
404 // Extract data and reply message
405 ULONG iclass = msg->Class;
406 USHORT code = msg->Code;
407 ReplyMsg((struct Message *)msg);
408
409 // Action depends on message class
410 switch (iclass) {
411
412 case IDCMP_CLOSEWINDOW: // Closing the window quits Frodo
413 TheC64->Quit();
414 break;
415
416 case IDCMP_RAWKEY:
417 switch (code) {
418
419 case 0x58: // F9: NMI (Restore)
420 TheC64->NMI();
421 break;
422
423 case 0x59: // F10: Reset
424 TheC64->Reset();
425 break;
426
427 case 0x5e: // '+' on keypad: Increase SkipFrames
428 ThePrefs.SkipFrames++;
429 break;
430
431 case 0x4a: // '-' on keypad: Decrease SkipFrames
432 if (ThePrefs.SkipFrames > 1)
433 ThePrefs.SkipFrames--;
434 break;
435
436 case 0x5d: // '*' on keypad: Toggle speed limiter
437 ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed;
438 break;
439
440 case 0x5c:{ // '/' on keypad: Toggle processor-level 1541 emulation
441 Prefs *prefs = new Prefs(ThePrefs);
442 prefs->Emul1541Proc = !prefs->Emul1541Proc;
443 TheC64->NewPrefs(prefs);
444 ThePrefs = *prefs;
445 delete prefs;
446 break;
447 }
448
449 default:{
450 // Convert Amiga keycode to C64 row/column
451 int c64_byte = key_byte[code & 0x7f];
452 int c64_bit = key_bit[code & 0x7f];
453
454 if (c64_byte != -1) {
455 if (!(c64_byte & 0x20)) {
456
457 // Normal keys
458 bool shifted = c64_byte & 8;
459 c64_byte &= 7;
460 if (!(code & 0x80)) {
461
462 // Key pressed
463 if (shifted) {
464 key_matrix[6] &= 0xef;
465 rev_matrix[4] &= 0xbf;
466 }
467 key_matrix[c64_byte] &= ~(1 << c64_bit);
468 rev_matrix[c64_bit] &= ~(1 << c64_byte);
469 } else {
470
471 // Key released
472 if (shifted) {
473 key_matrix[6] |= 0x10;
474 rev_matrix[4] |= 0x40;
475 }
476 key_matrix[c64_byte] |= (1 << c64_bit);
477 rev_matrix[c64_bit] |= (1 << c64_byte);
478 }
479 } else {
480
481 // Joystick emulation
482 c64_byte &= 0x1f;
483 if (code & 0x80)
484 *joystick |= c64_byte;
485 else
486 *joystick &= ~c64_byte;
487 }
488 }
489 }
490 }
491 break;
492
493 case IDCMP_MENUPICK:{
494 if (code == MENUNULL)
495 break;
496
497 // Get item number
498 int item_number = ITEMNUM(code);
499 switch (item_number) {
500
501 case 0: { // About Frodo
502 TheC64->Pause();
503 char str[256];
504 sprintf(str, "%s by Christian Bauer\n<Christian.Bauer@uni-mainz.de>\nİ Copyright 1994-1997,2002-2005", VERSION_STRING);
505 ShowRequester(str, "OK");
506 TheC64->Resume();
507 break;
508 }
509
510 case 2: // Preferences
511 TheC64->Pause();
512 be_app->RunPrefsEditor();
513 TheC64->Resume();
514 break;
515
516 case 4: // Reset C64
517 TheC64->Reset();
518 break;
519
520 case 5: // Insert next disk
521 if (strlen(ThePrefs.DrivePath[0]) > 4) {
522 char str[256];
523 strcpy(str, ThePrefs.DrivePath[0]);
524 char *p = str + strlen(str) - 5;
525
526 // If path matches "*.?64", increment character before the '.'
527 if (p[1] == '.' && p[3] == '6' && p[4] == '4') {
528 p[0]++;
529
530 // If no such file exists, set character before the '.' to '1', 'a' or 'A'
531 FILE *file;
532 if ((file = fopen(str, "rb")) == NULL) {
533 if (isdigit(p[0]))
534 p[0] = '1';
535 else if (isupper(p[0]))
536 p[0] = 'A';
537 else
538 p[0] = 'a';
539 } else
540 fclose(file);
541
542 // Set new prefs
543 Prefs *prefs = new Prefs(ThePrefs);
544 strcpy(prefs->DrivePath[0], str);
545 TheC64->NewPrefs(prefs);
546 ThePrefs = *prefs;
547 delete prefs;
548 }
549 }
550 break;
551
552 case 6: // SAM
553 TheC64->Pause();
554 SAM(TheC64);
555 TheC64->Resume();
556 break;
557
558 case 8: // Load snapshot
559 if (open_req != NULL && AslRequest(open_req, NULL)) {
560 char path[256];
561 strncpy(path, open_req->fr_Drawer, 255);
562 AddPart(path, open_req->fr_File, 255);
563 TheC64->Pause();
564 TheC64->LoadSnapshot(path);
565 TheC64->Resume();
566 }
567 break;
568
569 case 9: // Save snapshot
570 if (save_req != NULL && AslRequest(save_req, NULL)) {
571 char path[256];
572 strncpy(path, save_req->fr_Drawer, 255);
573 AddPart(path, save_req->fr_File, 255);
574 TheC64->Pause();
575 TheC64->SaveSnapshot(path);
576 TheC64->Resume();
577 }
578 break;
579
580 case 11: // Quit Frodo
581 TheC64->Quit();
582 break;
583 }
584 break;
585 }
586
587 case IDCMP_REFRESHWINDOW:
588 BeginRefresh(the_window);
589 draw_led_bar();
590 EndRefresh(the_window, TRUE);
591 break;
592 }
593 }
594 }
595
596
597 /*
598 * Check if NumLock is down (for switching the joystick keyboard emulation)
599 */
600
601 bool C64Display::NumLock(void)
602 {
603 return FALSE;
604 }
605
606
607 /*
608 * Allocate C64 colors
609 */
610
611 void C64Display::InitColors(UBYTE *colors)
612 {
613 // Spread pens into colors array
614 for (int i=0; i<256; i++)
615 colors[i] = pens[i & 0x0f];
616 }
617
618
619 /*
620 * Show a requester
621 */
622
623 long ShowRequester(const char *str, const char *button1, const char *button2)
624 {
625 struct EasyStruct es;
626 char gads[256];
627
628 strcpy(gads, button1);
629 if (button2) {
630 strcat(gads, "|");
631 strcat(gads, button2);
632 }
633
634 es.es_StructSize = sizeof(struct EasyStruct);
635 es.es_Flags = 0;
636 es.es_Title = "Frodo";
637 es.es_TextFormat = str;
638 es.es_GadgetFormat = gads;
639
640 return EasyRequestArgs(NULL, &es, NULL, NULL) % 1;
641 }