ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_Be.h
Revision: 1.7
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.6: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * Display_Be.h - C64 graphics display, emulator window handling,
3     * Be specific stuff
4     *
5 cebix 1.7 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
6 cebix 1.1 *
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 cebix 1.4 #ifndef BIT_BANG
32 cebix 1.3 #define BIT_BANG 0
33 cebix 1.4 #endif
34     #ifndef MGA_HACK
35     #define MGA_HACK 0
36     #endif
37 cebix 1.3
38    
39 cebix 1.1 // 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 cebix 1.3 0x30, 8+0, 0, 0,0x30, -1, 7, 7,
96 cebix 1.1 -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 cebix 1.3 class C64Window : public BDirectWindow {
153 cebix 1.1 public:
154     C64Window();
155    
156     virtual bool QuitRequested(void);
157     virtual void MessageReceived(BMessage *msg);
158 cebix 1.3 virtual void DirectConnected(direct_buffer_info *info);
159 cebix 1.1
160     BBitmap *TheBitmap[2];
161     SpeedoView *Speedometer;
162     LEDView *LED[4];
163    
164 cebix 1.3 #if BIT_BANG
165     uint8 *bits;
166     int bytes_per_row;
167     #endif
168    
169 cebix 1.1 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 cebix 1.3 TheBitmap = new BBitmap(DisplayFrame, B_COLOR_8_BIT);
184     main_view = new BitmapView(Bounds(), TheBitmap);
185 cebix 1.1 AddChild(main_view);
186     main_view->MakeFocus();
187     Connected = false;
188 cebix 1.3 first_connected = true;
189     #if MGA_HACK
190     mga_ready = false;
191     #endif
192 cebix 1.1 Unlock();
193     }
194 cebix 1.3 ~C64Screen()
195     {
196     delete TheBitmap;
197     }
198 cebix 1.1
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 cebix 1.3 BBitmap *TheBitmap;
209 cebix 1.1
210     private:
211     C64Display *the_display;
212 cebix 1.3 BitmapView *main_view;
213     bool first_connected;
214 cebix 1.1 status_t error;
215 cebix 1.3
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 cebix 1.1 };
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 cebix 1.3 // 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 cebix 1.1 } else {
417    
418 cebix 1.3 #if !BIT_BANG
419 cebix 1.1 // Update C64 display
420     BMessage msg(MSG_REDRAW);
421     msg.AddInt32("bitmap", draw_bitmap);
422     the_window->PostMessage(&msg);
423     draw_bitmap ^= 1;
424 cebix 1.3 #endif
425 cebix 1.1
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 cebix 1.3 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 cebix 1.1 return (uint8 *)the_window->TheBitmap[draw_bitmap]->Bits();
466 cebix 1.3 #endif
467 cebix 1.1 }
468    
469    
470     /*
471     * Return number of bytes per row
472     */
473    
474     int C64Display::BitmapXMod(void)
475     {
476 cebix 1.3 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 cebix 1.1 return the_window->TheBitmap[draw_bitmap]->BytesPerRow();
486 cebix 1.3 #endif
487 cebix 1.1 }
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 cebix 1.3 C64Window::C64Window() : BDirectWindow(WindowFrame, "Frodo", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
619 cebix 1.1 {
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 cebix 1.3 int mbar_height = int(bar->Frame().bottom) + 1;
644 cebix 1.1
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 cebix 1.3 while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
705 cebix 1.1 MessageQueue()->RemoveMessage(msg2);
706 cebix 1.3 delete msg2;
707     }
708 cebix 1.1 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 cebix 1.3 * 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 cebix 1.1 * Workspace activated/deactivated
746     */
747    
748     void C64Screen::ScreenConnected(bool active)
749     {
750     if (active) {
751 cebix 1.3 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 cebix 1.1 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 cebix 1.3 int maxy;
850     if (ThePrefs.DoubleScan)
851     maxy = 480;
852     else
853     maxy = DISPLAY_Y;
854    
855 cebix 1.1 switch (state) {
856     case LED_ON:
857 cebix 1.3 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 54);
858 cebix 1.1 break;
859     case LED_ERROR_ON:
860 cebix 1.3 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 44);
861 cebix 1.1 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 cebix 1.3 if (Speed >= 50 && Speed <= 101)
888 cebix 1.1 return;
889    
890 cebix 1.3 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 cebix 1.1 char *s = SpeedoStr;
900     char c;
901     long xmod = CardInfo()->bytes_per_row;
902 cebix 1.3 uint8 *p = (uint8 *)CardInfo()->frame_buffer + maxx - 8*8 + (maxy-20) * xmod;
903     while ((c = *s++) != 0) {
904 cebix 1.1 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 cebix 1.3 #ifdef __POWERPC__
937 cebix 1.1 memset_nc(p, color, n);
938 cebix 1.3 #else
939     memset(p, color, n);
940     #endif
941 cebix 1.1 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 cebix 1.5 SetLowColor(fill_gray);
1029 cebix 1.1 SetFont(be_plain_font);
1030     }
1031    
1032    
1033     /*
1034     * Draw speedometer
1035     */
1036    
1037     void SpeedoView::Draw(BRect update)
1038     {
1039     // Draw bevelled border
1040     SetHighColor(shine_gray);
1041     StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0));
1042     StrokeLine(BPoint(bounds.right, 0));
1043     SetHighColor(shadow_gray);
1044     StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1));
1045    
1046     // Draw text
1047     SetHighColor(0, 0, 0);
1048     DrawString(speedostr, BPoint(24, 12));
1049     }
1050    
1051    
1052     /*
1053     * Update speedometer at regular intervals
1054     */
1055    
1056     void SpeedoView::Pulse(void)
1057     {
1058     Invalidate(BRect(1, 1, bounds.right-1, 15));
1059     }
1060    
1061    
1062     /*
1063     * Set new speedometer value
1064     */
1065    
1066     void SpeedoView::SetValue(int speed)
1067     {
1068     sprintf(speedostr, "%d%%", speed);
1069     }
1070    
1071    
1072     /*
1073     * LED view constructor
1074     */
1075    
1076     LEDView::LEDView(BRect frame, const char *label) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED)
1077     {
1078     current_state = 0;
1079     the_label = label;
1080     bounds = Bounds();
1081     SetViewColor(fill_gray);
1082     SetFont(be_plain_font);
1083     }
1084    
1085    
1086     /*
1087     * Draw drive LED
1088     */
1089    
1090     void LEDView::Draw(BRect update)
1091     {
1092     // Draw bevelled border
1093     SetHighColor(shine_gray);
1094     StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0));
1095     StrokeLine(BPoint(bounds.right, 0));
1096     SetHighColor(shadow_gray);
1097     StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1));
1098    
1099     // Draw label
1100     SetHighColor(0, 0, 0);
1101     SetLowColor(fill_gray);
1102     DrawString(the_label, BPoint(8, 12));
1103    
1104     // Draw LED
1105     SetHighColor(shadow_gray);
1106     StrokeLine(BPoint(bounds.right-24, 12), BPoint(bounds.right-24, 4));
1107     StrokeLine(BPoint(bounds.right-8, 4));
1108     SetHighColor(shine_gray);
1109     StrokeLine(BPoint(bounds.right-23, 12), BPoint(bounds.right-8, 12));
1110     StrokeLine(BPoint(bounds.right-8, 5));
1111     DrawLED();
1112     }
1113    
1114    
1115     /*
1116     * Redraw just the LED
1117     */
1118    
1119     void LEDView::DrawLED(void)
1120     {
1121     Window()->Lock();
1122     switch (current_state) {
1123     case LED_OFF:
1124     case LED_ERROR_OFF:
1125     SetHighColor(32, 32, 32);
1126     break;
1127     case LED_ON:
1128     SetHighColor(0, 240, 0);
1129     break;
1130     case LED_ERROR_ON:
1131     SetHighColor(240, 0, 0);
1132     break;
1133     }
1134     FillRect(BRect(bounds.right-23, 5, bounds.right-9, 11));
1135     Window()->Unlock();
1136     }
1137    
1138    
1139     /*
1140     * Set LED state
1141     */
1142    
1143     void LEDView::SetState(int state)
1144     {
1145     if (state != current_state) {
1146     current_state = state;
1147     DrawLED();
1148     }
1149     }
1150    
1151    
1152     /*
1153     * Toggle red error LED
1154     */
1155    
1156     void LEDView::Pulse(void)
1157     {
1158     switch (current_state) {
1159     case LED_ERROR_ON:
1160     current_state = LED_ERROR_OFF;
1161     DrawLED();
1162     break;
1163     case LED_ERROR_OFF:
1164     current_state = LED_ERROR_ON;
1165     DrawLED();
1166     break;
1167     }
1168     }
1169    
1170    
1171     /*
1172     * Show a requester
1173     */
1174    
1175     long ShowRequester(char *str, char *button1, char *button2)
1176     {
1177     BAlert *the_alert;
1178    
1179     the_alert = new BAlert("", str, button1, button2, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
1180     return the_alert->Go();
1181     }