ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_Be.h
Revision: 1.3
Committed: 2003-07-09T13:54:01Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.2: +221 -17 lines
Log Message:
faster display (including dirty hardware hacks)

File Contents

# Content
1 /*
2 * Display_Be.h - C64 graphics display, emulator window handling,
3 * Be specific stuff
4 *
5 * Frodo (C) 1994-1997,2002-2003 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 <AppKit.h>
23 #include <InterfaceKit.h>
24 #include <GameKit.h>
25 #include <string.h>
26
27 #include "C64.h"
28 #include "main.h"
29
30
31 #define BIT_BANG 0
32 #define MGA_HACK 1
33
34
35 // Window thread messages
36 const uint32 MSG_REDRAW = 1;
37
38
39 // C64 display and window frame
40 const BRect DisplayFrame = BRect(0, 0, DISPLAY_X-1, DISPLAY_Y-1);
41 const BRect WindowFrame = BRect(0, 0, DISPLAY_X-1, DISPLAY_Y-1 + 16);
42
43
44 // Background color
45 const rgb_color fill_gray = {208, 208, 208, 0};
46 const rgb_color shine_gray = {232, 232, 232, 0};
47 const rgb_color shadow_gray = {152, 152, 152, 0};
48
49
50 /*
51 C64 keyboard matrix:
52
53 Bit 7 6 5 4 3 2 1 0
54 0 CUD F5 F3 F1 F7 CLR RET DEL
55 1 SHL E S Z 4 A W 3
56 2 X T F C 6 D R 5
57 3 V U H B 8 G Y 7
58 4 N O K M 0 J I 9
59 5 , @ : . - L P +
60 6 / ^ = SHR HOM ; * £
61 7 R/S Q C= SPC 2 CTL <- 1
62 */
63
64
65 /*
66 Tables for key translation
67 Bit 0..2: row/column in C64 keyboard matrix
68 Bit 3 : implicit shift
69 Bit 5 : joystick emulation (bit 0..4: mask)
70 */
71
72 const int key_byte[128] = {
73 -1, 7, 0,8+0, 0,8+0, 0, 8+0,
74 0, 8+0, -1, -1, -1, -1, -1, -1,
75
76 7, 7, 7, 7, 1, 1, 2, 2,
77 3, 3, 4, 4, 5, 5, 0, 8+0,
78
79 6, 6, -1, -1, -1, -1, -1, 7,
80 1, 1, 2, 2, 3, 3, 4, 4,
81
82 5, 5, 6, 6, 0, 6, 6,0x25,
83 0x21,0x29, -1, 1, 1, 1, 2, 2,
84
85 3, 3, 4, 4, 5, 5, 6, 0,
86 0x24,0x30,0x28, 1, 1, 2, 2, 3,
87
88 3, 4, 4, 5, 5, 6, 6, 8+0,
89 0x26,0x22,0x2a, 0, 7, -1, 7, -1,
90
91 0x30, 8+0, 0, 0,0x30, -1, 7, 7,
92 -1, -1, -1, -1, -1, -1, -1, -1,
93
94 -1, -1, -1, -1, -1, -1, -1, -1,
95 -1, -1, -1, -1, -1, -1, -1, -1
96 };
97
98 const int key_bit[128] = {
99 -1, 7, 4, 4, 5, 5, 6, 6,
100 3, 3, -1, -1, -1, -1, -1, -1,
101
102 7, 1, 0, 3, 0, 3, 0, 3,
103 0, 3, 0, 3, 0, 3, 0, 0,
104
105 3, 0, -1, -1, -1, -1, -1, 6,
106 1, 6, 1, 6, 1, 6, 1, 6,
107
108 1, 6, 1, 6, 0, 0, 5, -1,
109 -1, -1, -1, 7, 2, 5, 2, 5,
110
111 2, 5, 2, 5, 2, 5, 2, 1,
112 -1, -1, -1, 7, 4, 7, 4, 7,
113
114 4, 7, 4, 7, 4, 7, 4, 7,
115 -1, -1, -1, 1, 2, -1, 4, -1,
116
117 5, 2, 7, 2, -1, -1, 5, 5,
118 -1, -1, -1, -1, -1, -1, -1, -1,
119
120 -1, -1, -1, -1, -1, -1, -1, -1,
121 -1, -1, -1, -1, -1, -1, -1, -1
122 };
123
124
125 /*
126 * A simple view class for blitting a bitmap on the screen
127 */
128
129 class BitmapView : public BView {
130 public:
131 BitmapView(BRect frame, BBitmap *bitmap);
132 virtual void Draw(BRect update);
133 virtual void KeyDown(const char *bytes, int32 numBytes);
134 void ChangeBitmap(BBitmap *bitmap);
135
136 private:
137 BBitmap *the_bitmap;
138 };
139
140
141 /*
142 * Class for the main C64 display window
143 */
144
145 class SpeedoView;
146 class LEDView;
147
148 class C64Window : public BDirectWindow {
149 public:
150 C64Window();
151
152 virtual bool QuitRequested(void);
153 virtual void MessageReceived(BMessage *msg);
154 virtual void DirectConnected(direct_buffer_info *info);
155
156 BBitmap *TheBitmap[2];
157 SpeedoView *Speedometer;
158 LEDView *LED[4];
159
160 #if BIT_BANG
161 uint8 *bits;
162 int bytes_per_row;
163 #endif
164
165 private:
166 BitmapView *main_view;
167 };
168
169
170 /*
171 * Class for the main C64 display using the GameKit
172 */
173
174 class C64Screen : public BWindowScreen {
175 public:
176 C64Screen(C64Display *display) : BWindowScreen("Frodo", B_8_BIT_640x480, &error), the_display(display)
177 {
178 Lock();
179 TheBitmap = new BBitmap(DisplayFrame, B_COLOR_8_BIT);
180 main_view = new BitmapView(Bounds(), TheBitmap);
181 AddChild(main_view);
182 main_view->MakeFocus();
183 Connected = false;
184 first_connected = true;
185 #if MGA_HACK
186 mga_ready = false;
187 #endif
188 Unlock();
189 }
190 ~C64Screen()
191 {
192 delete TheBitmap;
193 }
194
195 virtual void ScreenConnected(bool active);
196 virtual void DispatchMessage(BMessage *msg, BHandler *handler);
197 void DrawLED(int i, int state);
198 void DrawSpeedometer(void);
199 void FillRect(int x1, int y1, int x2, int y2, int color);
200
201 bool Connected; // Flag: screen connected
202 int Speed;
203 char SpeedoStr[16]; // Speedometer value converted to a string
204 BBitmap *TheBitmap;
205
206 private:
207 C64Display *the_display;
208 BitmapView *main_view;
209 bool first_connected;
210 status_t error;
211
212 #if MGA_HACK
213 area_id mga_clone_area;
214 volatile uint8 *isa_io;
215 bool mga_ready;
216
217 void CRTC_out(int reg, uint8 val) {isa_io[0x3d4] = reg; __eieio(); isa_io[0x3d5] = val; __eieio();}
218 uint8 CRTC_in(int reg) {isa_io[0x3d4] = reg; __eieio(); return isa_io[0x3d5];}
219 void SEQ_out(int reg, uint8 val) {isa_io[0x3c4] = reg; __eieio(); isa_io[0x3c5] = val; __eieio();}
220 uint8 SEQ_in(int reg) {isa_io[0x3c4] = reg; __eieio(); return isa_io[0x3c5];}
221 void GDC_out(int reg, uint8 val) {isa_io[0x3ce] = reg; __eieio(); isa_io[0x3cf] = val; __eieio();}
222 uint8 GDC_in(int reg) {isa_io[0x3ce] = reg; __eieio(); return isa_io[0x3cf];}
223 void ATC_out(int reg, uint8 val) {isa_io[0x3c0] = reg; __eieio(); isa_io[0x3c0] = val; __eieio();}
224 #endif
225 };
226
227
228 /*
229 * Class for speedometer
230 */
231
232 class SpeedoView : public BView {
233 public:
234 SpeedoView(BRect frame);
235 virtual void Draw(BRect update);
236 virtual void Pulse(void);
237 void SetValue(int percent);
238
239 private:
240 char speedostr[16]; // Speedometer value converted to a string
241 BRect bounds;
242 };
243
244
245 /*
246 * Class for drive LED
247 */
248
249 class LEDView : public BView {
250 public:
251 LEDView(BRect frame, const char *label);
252 virtual void Draw(BRect update);
253 virtual void Pulse(void);
254 void DrawLED(void);
255 void SetState(int state);
256
257 private:
258 int current_state;
259 const char *the_label;
260 BRect bounds;
261 };
262
263
264 /*
265 * Display constructor: Create window/screen
266 */
267
268 C64Display::C64Display(C64 *the_c64) : TheC64(the_c64)
269 {
270 // LEDs off
271 for (int i=0; i<4; i++)
272 led_state[i] = old_led_state[i] = LED_OFF;
273
274 // Open window/screen
275 draw_bitmap = 1;
276 if (ThePrefs.DisplayType == DISPTYPE_SCREEN) {
277 using_screen = true;
278 the_screen = new C64Screen(this);
279 the_screen->Show();
280 while (!the_screen->Connected)
281 snooze(20000);
282 } else {
283 using_screen = false;
284 the_window = new C64Window();
285 the_window->Show();
286 }
287
288 // Prepare key_info buffer
289 get_key_info(&old_key_info);
290 }
291
292
293 /*
294 * Display destructor
295 */
296
297 C64Display::~C64Display()
298 {
299 if (using_screen) {
300 the_screen->Lock();
301 the_screen->Quit();
302 } else {
303 the_window->Lock();
304 the_window->Quit();
305 }
306 }
307
308
309 /*
310 * Prefs may have changed
311 */
312
313 void C64Display::NewPrefs(Prefs *prefs)
314 {
315 if (prefs->DisplayType == DISPTYPE_SCREEN) {
316 if (!using_screen) {
317 // Switch to full screen display
318 using_screen = true;
319 the_window->Lock();
320 the_window->Quit();
321 the_screen = new C64Screen(this);
322 the_screen->Show();
323 while (!the_screen->Connected)
324 snooze(20000);
325 }
326 } else {
327 if (using_screen) {
328 // Switch to window display
329 using_screen = false;
330 the_screen->Lock();
331 the_screen->Quit();
332 the_window = new C64Window();
333 the_window->Show();
334 }
335 }
336 }
337
338
339 /*
340 * Redraw bitmap (let the window thread do it)
341 */
342
343 void C64Display::Update(void)
344 {
345 if (using_screen) {
346
347 // Update LEDs/speedometer
348 for (int i=0; i<4; i++)
349 the_screen->DrawLED(i, led_state[i]);
350 the_screen->DrawSpeedometer();
351
352 // Update C64 display in dobule scan mode
353 if (ThePrefs.DoubleScan) {
354 uint8 *src = (uint8 *)the_screen->TheBitmap->Bits();
355 uint32 src_xmod = the_screen->TheBitmap->BytesPerRow();
356 src += src_xmod * 16 + 32;
357 uint8 *dest = (uint8 *)the_screen->CardInfo()->frame_buffer;
358 uint32 dest_xmod = the_screen->CardInfo()->bytes_per_row;
359 #ifdef __POWERPC__
360 double tmp[1];
361 for (int y=0; y<240; y++) {
362 uint32 *p = (uint32 *)src - 1;
363 double *q1 = (double *)dest - 1;
364 double *q2 = q1 + dest_xmod / sizeof(double);
365 for (int x=0; x<80; x++) {
366 uint32 val = *(++p);
367 uint8 *r = (uint8 *)&tmp[1];
368 *(--r) = val;
369 *(--r) = val;
370 val >>= 8;
371 *(--r) = val;
372 *(--r) = val;
373 val >>= 8;
374 *(--r) = val;
375 *(--r) = val;
376 val >>= 8;
377 *(--r) = val;
378 *(--r) = val;
379 double tmp2 = tmp[0];
380 *(++q1) = tmp2;
381 *(++q2) = tmp2;
382 }
383 src += src_xmod;
384 dest += dest_xmod * 2;
385 }
386 #else
387 for (int y=0; y<240; y++) {
388 uint32 *p = (uint32 *)src;
389 uint32 *q1 = (uint32 *)dest;
390 uint32 *q2 = q1 + dest_xmod / sizeof(uint32);
391 for (int x=0; x<80; x++) {
392 uint32 val = *p++;
393 uint32 tmp = val & 0x000000ff;
394 tmp |= (val << 8) & 0x0000ff00;
395 tmp |= (val << 8) & 0x00ff0000;
396 tmp |= (val << 16) & 0xff000000;
397 *q1++ = tmp;
398 *q2++ = tmp;
399 tmp = (val >> 16) & 0x000000ff;
400 tmp |= (val >> 8) & 0x0000ff00;
401 tmp |= (val >> 8) & 0x00ff0000;
402 tmp |= val & 0xff000000;
403 *q1++ = tmp;
404 *q2++ = tmp;
405 }
406 src += src_xmod;
407 dest += dest_xmod * 2;
408 }
409 #endif
410 }
411
412 } else {
413
414 #if !BIT_BANG
415 // Update C64 display
416 BMessage msg(MSG_REDRAW);
417 msg.AddInt32("bitmap", draw_bitmap);
418 the_window->PostMessage(&msg);
419 draw_bitmap ^= 1;
420 #endif
421
422 // Update LEDs
423 for (int i=0; i<4; i++)
424 if (led_state[i] != old_led_state[i]) {
425 the_window->LED[i]->SetState(led_state[i]);
426 old_led_state[i] = led_state[i];
427 }
428 }
429 }
430
431
432 /*
433 * Set value displayed by the speedometer
434 */
435
436 void C64Display::Speedometer(int speed)
437 {
438 if (using_screen) {
439 the_screen->Speed = speed;
440 sprintf(the_screen->SpeedoStr, "%3d%%", speed);
441 } else
442 the_window->Speedometer->SetValue(speed);
443 }
444
445
446 /*
447 * Return pointer to bitmap data
448 */
449
450 uint8 *C64Display::BitmapBase(void)
451 {
452 if (using_screen) {
453 if (ThePrefs.DoubleScan)
454 return (uint8 *)the_screen->TheBitmap->Bits();
455 else
456 return (uint8 *)the_screen->CardInfo()->frame_buffer;
457 } else
458 #if BIT_BANG
459 return (uint8 *)the_window->bits;
460 #else
461 return (uint8 *)the_window->TheBitmap[draw_bitmap]->Bits();
462 #endif
463 }
464
465
466 /*
467 * Return number of bytes per row
468 */
469
470 int C64Display::BitmapXMod(void)
471 {
472 if (using_screen) {
473 if (ThePrefs.DoubleScan)
474 return the_screen->TheBitmap->BytesPerRow();
475 else
476 return the_screen->CardInfo()->bytes_per_row;
477 } else
478 #if BIT_BANG
479 return the_window->bytes_per_row;
480 #else
481 return the_window->TheBitmap[draw_bitmap]->BytesPerRow();
482 #endif
483 }
484
485
486 /*
487 * Poll the keyboard
488 */
489
490 void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick)
491 {
492 key_info the_key_info;
493 int be_code, be_byte, be_bit, c64_byte, c64_bit;
494 bool shifted;
495
496 // Window must be active, command key must be up
497 if (using_screen) {
498 if (!the_screen->Connected)
499 return;
500 } else
501 if (!the_window->IsActive())
502 return;
503 if (!(modifiers() & B_COMMAND_KEY)) {
504
505 // Read the state of all keys
506 get_key_info(&the_key_info);
507
508 // Did anything change at all?
509 if (!memcmp(&old_key_info, &the_key_info, sizeof(key_info)))
510 return;
511
512 // Loop to convert BeOS keymap to C64 keymap
513 for (be_code=0; be_code<0x68; be_code++) {
514 be_byte = be_code >> 3;
515 be_bit = 1 << (~be_code & 7);
516
517 // Key state changed?
518 if ((the_key_info.key_states[be_byte] & be_bit)
519 != (old_key_info.key_states[be_byte] & be_bit)) {
520
521 c64_byte = key_byte[be_code];
522 c64_bit = key_bit[be_code];
523 if (c64_byte != -1) {
524 if (!(c64_byte & 0x20)) {
525
526 // Normal keys
527 shifted = c64_byte & 8;
528 c64_byte &= 7;
529 if (the_key_info.key_states[be_byte] & be_bit) {
530
531 // Key pressed
532 if (shifted) {
533 key_matrix[6] &= 0xef;
534 rev_matrix[4] &= 0xbf;
535 }
536 key_matrix[c64_byte] &= ~(1 << c64_bit);
537 rev_matrix[c64_bit] &= ~(1 << c64_byte);
538 } else {
539
540 // Key released
541 if (shifted) {
542 key_matrix[6] |= 0x10;
543 rev_matrix[4] |= 0x40;
544 }
545 key_matrix[c64_byte] |= (1 << c64_bit);
546 rev_matrix[c64_bit] |= (1 << c64_byte);
547 }
548 } else {
549
550 // Joystick emulation
551 c64_byte &= 0x1f;
552 if (the_key_info.key_states[be_byte] & be_bit)
553 *joystick &= ~c64_byte;
554 else
555 *joystick |= c64_byte;
556 }
557 }
558 }
559 }
560
561 old_key_info = the_key_info;
562 }
563 }
564
565
566 /*
567 * Check if NumLock is down (for switching the joystick keyboard emulation)
568 */
569
570 bool C64Display::NumLock(void)
571 {
572 return modifiers() & B_NUM_LOCK;
573 }
574
575
576 /*
577 * Allocate C64 colors
578 */
579
580 void C64Display::InitColors(uint8 *colors)
581 {
582 BScreen scr(using_screen ? (BWindow *)the_screen : the_window);
583 for (int i=0; i<256; i++)
584 colors[i] = scr.IndexForColor(palette_red[i & 0x0f], palette_green[i & 0x0f], palette_blue[i & 0x0f]);
585 }
586
587
588 /*
589 * Pause display (GameKit only)
590 */
591
592 void C64Display::Pause(void)
593 {
594 if (using_screen)
595 the_screen->Hide();
596 }
597
598
599 /*
600 * Resume display (GameKit only)
601 */
602
603 void C64Display::Resume(void)
604 {
605 if (using_screen)
606 the_screen->Show();
607 }
608
609
610 /*
611 * Window constructor
612 */
613
614 C64Window::C64Window() : BDirectWindow(WindowFrame, "Frodo", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
615 {
616 // Move window to right position
617 Lock();
618 MoveTo(80, 60);
619
620 // Set up menus
621 BMenuBar *bar = new BMenuBar(Bounds(), "");
622 BMenu *menu = new BMenu("Frodo");
623 menu->AddItem(new BMenuItem("About Frodo" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)));
624 menu->AddItem(new BSeparatorItem);
625 menu->AddItem(new BMenuItem("Preferences" B_UTF8_ELLIPSIS, new BMessage(MSG_PREFS), 'P'));
626 menu->AddItem(new BSeparatorItem);
627 menu->AddItem(new BMenuItem("Reset C64", new BMessage(MSG_RESET)));
628 menu->AddItem(new BMenuItem("Insert next disk", new BMessage(MSG_NEXTDISK), 'D'));
629 menu->AddItem(new BMenuItem("SAM" B_UTF8_ELLIPSIS, new BMessage(MSG_SAM), 'M'));
630 menu->AddItem(new BSeparatorItem);
631 menu->AddItem(new BMenuItem("Load snapshot" B_UTF8_ELLIPSIS, new BMessage(MSG_OPEN_SNAPSHOT), 'O'));
632 menu->AddItem(new BMenuItem("Save snapshot" B_UTF8_ELLIPSIS, new BMessage(MSG_SAVE_SNAPSHOT), 'S'));
633 menu->AddItem(new BSeparatorItem);
634 menu->AddItem(new BMenuItem("Quit Frodo", new BMessage(B_QUIT_REQUESTED), 'Q'));
635 menu->SetTargetForItems(be_app);
636 bar->AddItem(menu);
637 AddChild(bar);
638 SetKeyMenuBar(bar);
639 int mbar_height = int(bar->Frame().bottom) + 1;
640
641 // Resize window to fit menu bar
642 ResizeBy(0, mbar_height);
643
644 // Allocate bitmaps
645 TheBitmap[0] = new BBitmap(DisplayFrame, B_COLOR_8_BIT);
646 TheBitmap[1] = new BBitmap(DisplayFrame, B_COLOR_8_BIT);
647
648 // Create top view
649 BRect b = Bounds();
650 BView *top = new BView(BRect(0, mbar_height, b.right, b.bottom), "top", B_FOLLOW_NONE, 0);
651 AddChild(top);
652
653 // Create bitmap view
654 main_view = new BitmapView(DisplayFrame, TheBitmap[0]);
655 top->AddChild(main_view);
656 main_view->MakeFocus();
657
658 // Create speedometer
659 Speedometer = new SpeedoView(BRect(0, DISPLAY_Y, DISPLAY_X/5-1, DISPLAY_Y+15));
660 top->AddChild(Speedometer);
661
662 // Create drive LEDs
663 LED[0] = new LEDView(BRect(DISPLAY_X/5, DISPLAY_Y, DISPLAY_X*2/5-1, DISPLAY_Y+15), "Drive 8");
664 top->AddChild(LED[0]);
665 LED[1] = new LEDView(BRect(DISPLAY_X*2/5, DISPLAY_Y, DISPLAY_X*3/5-1, DISPLAY_Y+15), "Drive 9");
666 top->AddChild(LED[1]);
667 LED[2] = new LEDView(BRect(DISPLAY_X*3/5, DISPLAY_Y, DISPLAY_X*4/5-1, DISPLAY_Y+15), "Drive 10");
668 top->AddChild(LED[2]);
669 LED[3] = new LEDView(BRect(DISPLAY_X*4/5, DISPLAY_Y, DISPLAY_X-1, DISPLAY_Y+15), "Drive 11");
670 top->AddChild(LED[3]);
671
672 // Set pulse rate to 0.4 seconds for blinking drive LEDs
673 SetPulseRate(400000);
674 Unlock();
675 }
676
677
678 /*
679 * Closing the window quits Frodo
680 */
681
682 bool C64Window::QuitRequested(void)
683 {
684 be_app->PostMessage(B_QUIT_REQUESTED);
685 return false;
686 }
687
688
689 /*
690 * Handles redraw messages
691 */
692
693 void C64Window::MessageReceived(BMessage *msg)
694 {
695 BMessage *msg2;
696
697 switch (msg->what) {
698 case MSG_REDRAW: // Redraw bitmap
699 MessageQueue()->Lock();
700 while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
701 MessageQueue()->RemoveMessage(msg2);
702 delete msg2;
703 }
704 MessageQueue()->Unlock();
705 main_view->ChangeBitmap(TheBitmap[msg->FindInt32("bitmap")]);
706 Lock();
707 main_view->Draw(DisplayFrame);
708 Unlock();
709 break;
710
711 default:
712 BWindow::MessageReceived(msg);
713 }
714 }
715
716
717 /*
718 * Window connected/disconnected
719 */
720
721 void C64Window::DirectConnected(direct_buffer_info *info)
722 {
723 #if BIT_BANG
724 switch (info->buffer_state & B_DIRECT_MODE_MASK) {
725 case B_DIRECT_STOP:
726 // acquire_sem(drawing_sem);
727 break;
728 case B_DIRECT_MODIFY:
729 // acquire_sem(drawing_sem);
730 case B_DIRECT_START:
731 bits = ((uint8 *)info->bits + info->window_bounds.top * info->bytes_per_row + info->window_bounds.left * info->bits_per_pixel / 8);
732 bytes_per_row = info->bytes_per_row;
733 // release_sem(drawing_sem);
734 break;
735 }
736 #endif
737 }
738
739
740 /*
741 * Workspace activated/deactivated
742 */
743
744 void C64Screen::ScreenConnected(bool active)
745 {
746 if (active) {
747 if (first_connected) {
748 first_connected = false;
749
750 #if MGA_HACK
751 mga_clone_area = -1;
752
753 // Construct register area name
754 char mga_area_name[64];
755 int bus = 0, device = 13, function = 0;
756 sprintf(mga_area_name, "102B_0519_%02X%02X%02X regs", bus, device, function);
757
758 // Find MGA register area
759 area_id mga_area = find_area(mga_area_name);
760 if (mga_area > 0) {
761
762 // Clone area, remove write protection
763 volatile uint8 *mga_io;
764 mga_clone_area = clone_area("mga registers", (void **)&mga_io, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, mga_area);
765 if (mga_clone_area > 0) {
766 isa_io = mga_io + 0x1c00;
767 mga_ready = true;
768 }
769 }
770 #endif
771 }
772
773 #if MGA_HACK
774 if (mga_ready) {
775 CRTC_out(0x09, 1); // Enable double scan
776 int a = 4 * 640;
777 CRTC_out(0x0c, a >> 8); // Center screen vertically
778 CRTC_out(0x0d, a);
779 // defaults:
780 // total 0x67
781 // display end 0x4f
782 // blank start 0x4f
783 // blank end 2b
784 // sync start 0x53
785 // sync end 1f
786 CRTC_out(0x00, 0x3f); // Horizontal timing
787 CRTC_out(0x01, 0x2f);
788 CRTC_out(0x02, 0x2f);
789 CRTC_out(0x03, 0x83);
790 CRTC_out(0x04, 0x32);
791 CRTC_out(0x05, 0x1a);
792 }
793 #endif
794
795 FillRect(0, 0, 639, 479, 0); // Clear screen
796 the_display->TheC64->Resume();
797 Connected = true;
798 } else {
799 the_display->TheC64->Pause();
800 Connected = false;
801 }
802 BWindowScreen::ScreenConnected(active);
803 }
804
805
806 /*
807 * Simulate menu commands
808 */
809
810 void C64Screen::DispatchMessage(BMessage *msg, BHandler *handler)
811 {
812 switch (msg->what) {
813 case B_KEY_DOWN: {
814 uint32 mods = msg->FindInt32("modifiers");
815 if (mods & B_COMMAND_KEY) {
816 uint32 key = msg->FindInt32("raw_char");
817 switch (key) {
818 case 'p':
819 be_app->PostMessage(MSG_PREFS);
820 break;
821 case 'd':
822 be_app->PostMessage(MSG_NEXTDISK);
823 break;
824 case 'm':
825 be_app->PostMessage(MSG_SAM);
826 break;
827 }
828 }
829 BWindowScreen::DispatchMessage(msg, handler);
830 break;
831 }
832
833 default:
834 BWindowScreen::DispatchMessage(msg, handler);
835 }
836 }
837
838
839 /*
840 * Draw drive LEDs
841 */
842
843 void C64Screen::DrawLED(int i, int state)
844 {
845 int maxy;
846 if (ThePrefs.DoubleScan)
847 maxy = 480;
848 else
849 maxy = DISPLAY_Y;
850
851 switch (state) {
852 case LED_ON:
853 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 54);
854 break;
855 case LED_ERROR_ON:
856 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 44);
857 break;
858 }
859 }
860
861
862 /*
863 * Draw speedometer
864 */
865
866 static const int8 Digits[11][8] = { // Digit images
867 {0x3c, 0x66, 0x6e, 0x76, 0x66, 0x66, 0x3c, 0x00},
868 {0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00},
869 {0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00},
870 {0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00},
871 {0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00},
872 {0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00},
873 {0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00},
874 {0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00},
875 {0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00},
876 {0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00},
877 {0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00},
878 };
879
880 void C64Screen::DrawSpeedometer()
881 {
882 // Don't display speedometer if we're running at about 100%
883 if (Speed >= 50 && Speed <= 101)
884 return;
885
886 int maxx, maxy;
887 if (ThePrefs.DoubleScan) {
888 maxx = 640;
889 maxy = 480;
890 } else {
891 maxx = DISPLAY_X;
892 maxy = DISPLAY_Y;
893 }
894
895 char *s = SpeedoStr;
896 char c;
897 long xmod = CardInfo()->bytes_per_row;
898 uint8 *p = (uint8 *)CardInfo()->frame_buffer + maxx - 8*8 + (maxy-20) * xmod;
899 while ((c = *s++) != 0) {
900 if (c == ' ')
901 continue;
902 if (c == '%')
903 c = 10;
904 else
905 c -= '0';
906 uint8 *q = p;
907 for (int y=0; y<8; y++) {
908 uint8 data = Digits[c][y];
909 for (int x=0; x<8; x++) {
910 if (data & (1 << (7-x)))
911 q[x] = 255;
912 else
913 q[x] = 0;
914 }
915 q += xmod;
916 }
917 p += 8;
918 }
919 }
920
921
922 /*
923 * Fill rectangle
924 */
925
926 void C64Screen::FillRect(int x1, int y1, int x2, int y2, int color)
927 {
928 long xmod = CardInfo()->bytes_per_row;
929 uint8 *p = (uint8 *)CardInfo()->frame_buffer + y1 * xmod + x1;
930 int n = x2 - x1 + 1;
931 for(int y=y1; y<=y2; y++) {
932 #ifdef __POWERPC__
933 memset_nc(p, color, n);
934 #else
935 memset(p, color, n);
936 #endif
937 p += xmod;
938 }
939 }
940
941
942 /*
943 * Bitmap view constructor
944 */
945
946 BitmapView::BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW)
947 {
948 ChangeBitmap(bitmap);
949 }
950
951
952 /*
953 * Blit the bitmap
954 */
955
956 void BitmapView::Draw(BRect update)
957 {
958 if (the_bitmap != NULL)
959 DrawBitmapAsync(the_bitmap, update, update);
960 }
961
962
963 /*
964 * Receive special key-down events (main C64 keyboard handling is done in PollKeyboard)
965 */
966
967 void BitmapView::KeyDown(const char *bytes, int32 numBytes)
968 {
969 if (bytes[0] == B_FUNCTION_KEY || bytes[0] == '+' || bytes[0] == '-' || bytes[0] == '*' || bytes[0] == '/') {
970 BMessage *msg = Window()->CurrentMessage();
971 long key;
972 if (msg->FindInt32("key", &key) == B_NO_ERROR) {
973 switch (key) {
974
975 case B_F11_KEY: // F11: NMI (Restore)
976 be_app->PostMessage(MSG_NMI);
977 break;
978
979 case B_F12_KEY: // F12: Reset
980 be_app->PostMessage(MSG_RESET);
981 break;
982
983 case 0x3a: // '+' on keypad: Increase SkipFrames
984 ThePrefs.SkipFrames++;
985 break;
986
987 case 0x25: // '-' on keypad: Decrease SkipFrames
988 if (ThePrefs.SkipFrames > 1)
989 ThePrefs.SkipFrames--;
990 break;
991
992 case 0x24: // '*' on keypad: Toggle speed limiter
993 ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed;
994 break;
995
996 case 0x23: // '/' on keypad: Toggle processor-level 1541 emulation
997 be_app->PostMessage(MSG_TOGGLE_1541);
998 break;
999 }
1000 }
1001 }
1002 }
1003
1004
1005 /*
1006 * Change view bitmap
1007 */
1008
1009 void BitmapView::ChangeBitmap(BBitmap *bitmap)
1010 {
1011 the_bitmap = bitmap;
1012 }
1013
1014
1015 /*
1016 * Speedometer constructor
1017 */
1018
1019 SpeedoView::SpeedoView(BRect frame) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED)
1020 {
1021 speedostr[0] = 0;
1022 bounds = Bounds();
1023 SetViewColor(fill_gray);
1024 SetFont(be_plain_font);
1025 }
1026
1027
1028 /*
1029 * Draw speedometer
1030 */
1031
1032 void SpeedoView::Draw(BRect update)
1033 {
1034 // Draw bevelled border
1035 SetHighColor(shine_gray);
1036 StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0));
1037 StrokeLine(BPoint(bounds.right, 0));
1038 SetHighColor(shadow_gray);
1039 StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1));
1040
1041 // Draw text
1042 SetHighColor(0, 0, 0);
1043 DrawString(speedostr, BPoint(24, 12));
1044 }
1045
1046
1047 /*
1048 * Update speedometer at regular intervals
1049 */
1050
1051 void SpeedoView::Pulse(void)
1052 {
1053 Invalidate(BRect(1, 1, bounds.right-1, 15));
1054 }
1055
1056
1057 /*
1058 * Set new speedometer value
1059 */
1060
1061 void SpeedoView::SetValue(int speed)
1062 {
1063 sprintf(speedostr, "%d%%", speed);
1064 }
1065
1066
1067 /*
1068 * LED view constructor
1069 */
1070
1071 LEDView::LEDView(BRect frame, const char *label) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED)
1072 {
1073 current_state = 0;
1074 the_label = label;
1075 bounds = Bounds();
1076 SetViewColor(fill_gray);
1077 SetFont(be_plain_font);
1078 }
1079
1080
1081 /*
1082 * Draw drive LED
1083 */
1084
1085 void LEDView::Draw(BRect update)
1086 {
1087 // Draw bevelled border
1088 SetHighColor(shine_gray);
1089 StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0));
1090 StrokeLine(BPoint(bounds.right, 0));
1091 SetHighColor(shadow_gray);
1092 StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1));
1093
1094 // Draw label
1095 SetHighColor(0, 0, 0);
1096 SetLowColor(fill_gray);
1097 DrawString(the_label, BPoint(8, 12));
1098
1099 // Draw LED
1100 SetHighColor(shadow_gray);
1101 StrokeLine(BPoint(bounds.right-24, 12), BPoint(bounds.right-24, 4));
1102 StrokeLine(BPoint(bounds.right-8, 4));
1103 SetHighColor(shine_gray);
1104 StrokeLine(BPoint(bounds.right-23, 12), BPoint(bounds.right-8, 12));
1105 StrokeLine(BPoint(bounds.right-8, 5));
1106 DrawLED();
1107 }
1108
1109
1110 /*
1111 * Redraw just the LED
1112 */
1113
1114 void LEDView::DrawLED(void)
1115 {
1116 Window()->Lock();
1117 switch (current_state) {
1118 case LED_OFF:
1119 case LED_ERROR_OFF:
1120 SetHighColor(32, 32, 32);
1121 break;
1122 case LED_ON:
1123 SetHighColor(0, 240, 0);
1124 break;
1125 case LED_ERROR_ON:
1126 SetHighColor(240, 0, 0);
1127 break;
1128 }
1129 FillRect(BRect(bounds.right-23, 5, bounds.right-9, 11));
1130 Window()->Unlock();
1131 }
1132
1133
1134 /*
1135 * Set LED state
1136 */
1137
1138 void LEDView::SetState(int state)
1139 {
1140 if (state != current_state) {
1141 current_state = state;
1142 DrawLED();
1143 }
1144 }
1145
1146
1147 /*
1148 * Toggle red error LED
1149 */
1150
1151 void LEDView::Pulse(void)
1152 {
1153 switch (current_state) {
1154 case LED_ERROR_ON:
1155 current_state = LED_ERROR_OFF;
1156 DrawLED();
1157 break;
1158 case LED_ERROR_OFF:
1159 current_state = LED_ERROR_ON;
1160 DrawLED();
1161 break;
1162 }
1163 }
1164
1165
1166 /*
1167 * Show a requester
1168 */
1169
1170 long ShowRequester(char *str, char *button1, char *button2)
1171 {
1172 BAlert *the_alert;
1173
1174 the_alert = new BAlert("", str, button1, button2, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
1175 return the_alert->Go();
1176 }