ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_Be.h
Revision: 1.4
Committed: 2003-07-09T15:57:06Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.3: +5 -1 lines
Log Message:
small BeOS cleanups

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