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

# 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.2 * Frodo (C) 1994-1997,2002-2003 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.3 #define BIT_BANG 0
32     #define MGA_HACK 1
33    
34    
35 cebix 1.1 // 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 cebix 1.3 0x30, 8+0, 0, 0,0x30, -1, 7, 7,
92 cebix 1.1 -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 cebix 1.3 class C64Window : public BDirectWindow {
149 cebix 1.1 public:
150     C64Window();
151    
152     virtual bool QuitRequested(void);
153     virtual void MessageReceived(BMessage *msg);
154 cebix 1.3 virtual void DirectConnected(direct_buffer_info *info);
155 cebix 1.1
156     BBitmap *TheBitmap[2];
157     SpeedoView *Speedometer;
158     LEDView *LED[4];
159    
160 cebix 1.3 #if BIT_BANG
161     uint8 *bits;
162     int bytes_per_row;
163     #endif
164    
165 cebix 1.1 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 cebix 1.3 TheBitmap = new BBitmap(DisplayFrame, B_COLOR_8_BIT);
180     main_view = new BitmapView(Bounds(), TheBitmap);
181 cebix 1.1 AddChild(main_view);
182     main_view->MakeFocus();
183     Connected = false;
184 cebix 1.3 first_connected = true;
185     #if MGA_HACK
186     mga_ready = false;
187     #endif
188 cebix 1.1 Unlock();
189     }
190 cebix 1.3 ~C64Screen()
191     {
192     delete TheBitmap;
193     }
194 cebix 1.1
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 cebix 1.3 BBitmap *TheBitmap;
205 cebix 1.1
206     private:
207     C64Display *the_display;
208 cebix 1.3 BitmapView *main_view;
209     bool first_connected;
210 cebix 1.1 status_t error;
211 cebix 1.3
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 cebix 1.1 };
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 cebix 1.3 // 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 cebix 1.1 } else {
413    
414 cebix 1.3 #if !BIT_BANG
415 cebix 1.1 // Update C64 display
416     BMessage msg(MSG_REDRAW);
417     msg.AddInt32("bitmap", draw_bitmap);
418     the_window->PostMessage(&msg);
419     draw_bitmap ^= 1;
420 cebix 1.3 #endif
421 cebix 1.1
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 cebix 1.3 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 cebix 1.1 return (uint8 *)the_window->TheBitmap[draw_bitmap]->Bits();
462 cebix 1.3 #endif
463 cebix 1.1 }
464    
465    
466     /*
467     * Return number of bytes per row
468     */
469    
470     int C64Display::BitmapXMod(void)
471     {
472 cebix 1.3 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 cebix 1.1 return the_window->TheBitmap[draw_bitmap]->BytesPerRow();
482 cebix 1.3 #endif
483 cebix 1.1 }
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 cebix 1.3 C64Window::C64Window() : BDirectWindow(WindowFrame, "Frodo", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
615 cebix 1.1 {
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 cebix 1.3 int mbar_height = int(bar->Frame().bottom) + 1;
640 cebix 1.1
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 cebix 1.3 while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
701 cebix 1.1 MessageQueue()->RemoveMessage(msg2);
702 cebix 1.3 delete msg2;
703     }
704 cebix 1.1 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 cebix 1.3 * 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 cebix 1.1 * Workspace activated/deactivated
742     */
743    
744     void C64Screen::ScreenConnected(bool active)
745     {
746     if (active) {
747 cebix 1.3 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 cebix 1.1 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 cebix 1.3 int maxy;
846     if (ThePrefs.DoubleScan)
847     maxy = 480;
848     else
849     maxy = DISPLAY_Y;
850    
851 cebix 1.1 switch (state) {
852     case LED_ON:
853 cebix 1.3 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 54);
854 cebix 1.1 break;
855     case LED_ERROR_ON:
856 cebix 1.3 FillRect(10+i*20, maxy-20, 20+i*20, maxy-12, 44);
857 cebix 1.1 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 cebix 1.3 if (Speed >= 50 && Speed <= 101)
884 cebix 1.1 return;
885    
886 cebix 1.3 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 cebix 1.1 char *s = SpeedoStr;
896     char c;
897     long xmod = CardInfo()->bytes_per_row;
898 cebix 1.3 uint8 *p = (uint8 *)CardInfo()->frame_buffer + maxx - 8*8 + (maxy-20) * xmod;
899     while ((c = *s++) != 0) {
900 cebix 1.1 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 cebix 1.3 #ifdef __POWERPC__
933 cebix 1.1 memset_nc(p, color, n);
934 cebix 1.3 #else
935     memset(p, color, n);
936     #endif
937 cebix 1.1 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     }