ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.26
Committed: 2004-01-12T15:29:22Z (20 years, 4 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-16, nigel-build-15
Changes since 1.25: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3     *
4 cebix 1.26 * Basilisk II (C) 1997-2004 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <exec/types.h>
22     #include <intuition/intuition.h>
23     #include <graphics/rastport.h>
24     #include <graphics/gfx.h>
25 cebix 1.7 #include <cybergraphics/cybergraphics.h>
26 cebix 1.1 #include <dos/dostags.h>
27     #include <devices/timer.h>
28 jlachmann 1.24 #define __USE_SYSBASE
29 cebix 1.1 #include <proto/exec.h>
30     #include <proto/dos.h>
31     #include <proto/intuition.h>
32     #include <proto/graphics.h>
33     #include <proto/Picasso96.h>
34 cebix 1.4 #include <proto/cybergraphics.h>
35 jlachmann 1.24 #include <inline/exec.h>
36     #include <inline/dos.h>
37     #include <inline/intuition.h>
38     #include <inline/Picasso96.h>
39     #include <inline/cybergraphics.h>
40 cebix 1.1
41     #include "sysdeps.h"
42 jlachmann 1.9 #include "cpu_emulation.h"
43 cebix 1.1 #include "main.h"
44     #include "adb.h"
45     #include "prefs.h"
46     #include "user_strings.h"
47     #include "video.h"
48    
49 cebix 1.4 #define DEBUG 0
50 cebix 1.1 #include "debug.h"
51    
52    
53 jlachmann 1.24 // Supported video modes
54     static vector<video_mode> VideoModes;
55    
56 cebix 1.1 // Display types
57     enum {
58     DISPLAY_WINDOW,
59     DISPLAY_PIP,
60 cebix 1.6 DISPLAY_SCREEN_P96,
61     DISPLAY_SCREEN_CGFX
62 cebix 1.1 };
63    
64     // Global variables
65     static int32 frame_skip;
66 jlachmann 1.24 static UWORD *null_pointer = NULL; // Blank mouse pointer data
67     static UWORD *current_pointer = (UWORD *)-1; // Currently visible mouse pointer data
68     static struct Process *periodic_proc = NULL; // Periodic process
69 cebix 1.1
70 jlachmann 1.24 extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp)
71 cebix 1.1
72    
73     // Amiga -> Mac raw keycode translation table
74     static const uint8 keycode2mac[0x80] = {
75     0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, 0x1a, // ` 1 2 3 4 5 6 7
76     0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x2a, 0xff, 0x52, // 8 9 0 - = \ inv 0
77     0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, // Q W E R T Y U I
78     0x1f, 0x23, 0x21, 0x1e, 0xff, 0x53, 0x54, 0x55, // O P [ ] inv 1 2 3
79     0x00, 0x01, 0x02, 0x03, 0x05, 0x04, 0x26, 0x28, // A S D F G H J K
80     0x25, 0x29, 0x27, 0x2a, 0xff, 0x56, 0x57, 0x58, // L ; ' # inv 4 5 6
81     0x32, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x2d, 0x2e, // < Z X C V B N M
82     0x2b, 0x2f, 0x2c, 0xff, 0x41, 0x59, 0x5b, 0x5c, // , . / inv . 7 8 9
83     0x31, 0x33, 0x30, 0x4c, 0x24, 0x35, 0x75, 0xff, // SPC BSP TAB ENT RET ESC DEL inv
84     0xff, 0xff, 0x4e, 0xff, 0x3e, 0x3d, 0x3c, 0x3b, // inv inv - inv CUP CDN CRT CLF
85     0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, 0x62, 0x64, // F1 F2 F3 F4 F5 F6 F7 F8
86     0x65, 0x6d, 0x47, 0x51, 0x4b, 0x43, 0x45, 0x72, // F9 F10 ( ) / * + HLP
87     0x38, 0x38, 0x39, 0x36, 0x3a, 0x3a, 0x37, 0x37, // SHL SHR CAP CTL ALL ALR AML AMR
88     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
89     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
90     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv
91     };
92    
93    
94 jlachmann 1.24 class Amiga_monitor_desc : public monitor_desc {
95     public:
96     Amiga_monitor_desc(const vector<video_mode> &available_modes, video_depth default_depth, uint32 default_id, int default_display_type)
97     : monitor_desc(available_modes, default_depth, default_id), display_type(default_display_type) {};
98     ~Amiga_monitor_desc() {};
99    
100     virtual void switch_to_current_mode(void);
101     virtual void set_palette(uint8 *pal, int num);
102    
103     bool video_open(void);
104     void video_close(void);
105     public:
106     int display_type; // See enum above
107     };
108 cebix 1.1
109    
110     /*
111 jlachmann 1.24 * Display "driver" classes
112 cebix 1.1 */
113    
114 jlachmann 1.24 class driver_base {
115     public:
116     driver_base(Amiga_monitor_desc &m);
117     virtual ~driver_base();
118    
119     virtual void set_palette(uint8 *pal, int num) {};
120     virtual struct BitMap *get_bitmap() { return NULL; };
121     public:
122     Amiga_monitor_desc &monitor; // Associated video monitor
123     const video_mode &mode; // Video mode handled by the driver
124     BOOL init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
125     struct Window *the_win;
126     };
127 cebix 1.13
128 cebix 1.1
129 jlachmann 1.24 class driver_window : public driver_base {
130     public:
131     driver_window(Amiga_monitor_desc &m, int width, int height);
132     ~driver_window();
133    
134     struct BitMap *get_bitmap() { return the_bitmap; };
135    
136     private:
137     LONG black_pen, white_pen;
138     struct BitMap *the_bitmap;
139     };
140 cebix 1.1
141 jlachmann 1.24 class driver_pip : public driver_base {
142     public:
143     driver_pip(Amiga_monitor_desc &m, int width, int height);
144     ~driver_pip();
145 cebix 1.1
146 jlachmann 1.24 struct BitMap *get_bitmap() { return the_bitmap; };
147 cebix 1.1
148 jlachmann 1.24 private:
149     struct BitMap *the_bitmap;
150     };
151 cebix 1.1
152 jlachmann 1.24 class driver_screen_p96 : public driver_base {
153     public:
154     driver_screen_p96(Amiga_monitor_desc &m, ULONG mode_id);
155     ~driver_screen_p96();
156 cebix 1.1
157 jlachmann 1.24 void set_palette(uint8 *pal, int num);
158 cebix 1.1
159 jlachmann 1.24 private:
160     struct Screen *the_screen;
161     };
162 cebix 1.1
163 jlachmann 1.24 class driver_screen_cgfx : public driver_base {
164     public:
165     driver_screen_cgfx(Amiga_monitor_desc &m, ULONG mode_id);
166     ~driver_screen_cgfx();
167 jlachmann 1.20
168 jlachmann 1.24 void set_palette(uint8 *pal, int num);
169 cebix 1.1
170 jlachmann 1.24 private:
171     struct Screen *the_screen;
172     };
173 cebix 1.1
174 cebix 1.6
175 jlachmann 1.24 static driver_base *drv = NULL; // Pointer to currently used driver object
176 cebix 1.6
177 cebix 1.1
178 cebix 1.6
179 jlachmann 1.24 // Prototypes
180     static void periodic_func(void);
181     static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth);
182     static void add_modes(uint32 width, uint32 height, video_depth depth);
183     static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth);
184     static ULONG bits_from_depth(video_depth depth);
185     static bool is_valid_modeid(int display_type, ULONG mode_id);
186     static bool check_modeid_p96(ULONG mode_id);
187     static bool check_modeid_cgfx(ULONG mode_id);
188 cebix 1.13
189 jlachmann 1.20
190 jlachmann 1.24 /*
191     * Initialization
192     */
193 cebix 1.1
194    
195     bool VideoInit(bool classic)
196     {
197 jlachmann 1.24 video_depth default_depth = VDEPTH_1BIT;
198     int default_width, default_height;
199     int default_display_type = DISPLAY_WINDOW;
200     int window_width, window_height; // width and height for window display
201     ULONG screen_mode_id; // mode ID for screen display
202 jlachmann 1.20
203 cebix 1.8 // Allocate blank mouse pointer data
204     null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
205     if (null_pointer == NULL) {
206 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
207 cebix 1.8 return false;
208     }
209    
210 cebix 1.1 // Read frame skip prefs
211     frame_skip = PrefsFindInt32("frameskip");
212     if (frame_skip == 0)
213     frame_skip = 1;
214    
215     // Get screen mode from preferences
216     const char *mode_str;
217     if (classic)
218     mode_str = "win/512/342";
219     else
220     mode_str = PrefsFindString("screen");
221    
222 jlachmann 1.20 default_width = window_width = 512;
223     default_height = window_height = 384;
224    
225 cebix 1.1 if (mode_str) {
226 jlachmann 1.20 if (sscanf(mode_str, "win/%d/%d", &window_width, &window_height) == 2)
227 jlachmann 1.24 default_display_type = DISPLAY_WINDOW;
228 jlachmann 1.20 else if (sscanf(mode_str, "pip/%d/%d", &window_width, &window_height) == 2 && P96Base)
229 jlachmann 1.24 default_display_type = DISPLAY_PIP;
230 jlachmann 1.20 else if (sscanf(mode_str, "scr/%08lx", &screen_mode_id) == 1 && (CyberGfxBase || P96Base)) {
231     if (P96Base && p96GetModeIDAttr(screen_mode_id, P96IDA_ISP96))
232 jlachmann 1.24 default_display_type = DISPLAY_SCREEN_P96;
233 jlachmann 1.20 else if (CyberGfxBase && IsCyberModeID(screen_mode_id))
234 jlachmann 1.24 default_display_type = DISPLAY_SCREEN_CGFX;
235 cebix 1.6 else {
236 cebix 1.16 ErrorAlert(STR_NO_P96_MODE_ERR);
237 cebix 1.6 return false;
238     }
239     }
240 cebix 1.1 }
241    
242 jlachmann 1.24 D(bug("default_display_type %d, window_width %d, window_height %d\n", default_display_type, window_width, window_height));
243 cebix 1.23
244 jlachmann 1.20 // Construct list of supported modes
245 jlachmann 1.24 switch (default_display_type) {
246 jlachmann 1.20 case DISPLAY_WINDOW:
247     default_width = window_width;
248     default_height = window_height;
249 jlachmann 1.24 default_depth = VDEPTH_1BIT;
250 jlachmann 1.20 add_modes(window_width, window_height, VDEPTH_1BIT);
251     break;
252    
253     case DISPLAY_PIP:
254     default_width = window_width;
255     default_height = window_height;
256 cebix 1.25 default_depth = VDEPTH_16BIT;
257 jlachmann 1.20 add_modes(window_width, window_height, VDEPTH_16BIT);
258     break;
259    
260     case DISPLAY_SCREEN_P96:
261     case DISPLAY_SCREEN_CGFX:
262     struct DimensionInfo dimInfo;
263     DisplayInfoHandle handle = FindDisplayInfo(screen_mode_id);
264    
265 cebix 1.23 if (handle == NULL)
266 jlachmann 1.20 return false;
267    
268     if (GetDisplayInfoData(handle, (UBYTE *) &dimInfo, sizeof(dimInfo), DTAG_DIMS, 0) <= 0)
269     return false;
270    
271     default_width = 1 + dimInfo.Nominal.MaxX - dimInfo.Nominal.MinX;
272     default_height = 1 + dimInfo.Nominal.MaxY - dimInfo.Nominal.MinY;
273 jlachmann 1.24
274 cebix 1.25 switch (dimInfo.MaxDepth) {
275     case 1:
276     default_depth = VDEPTH_1BIT;
277     break;
278     case 8:
279     default_depth = VDEPTH_8BIT;
280     break;
281     case 15:
282     case 16:
283     default_depth = VDEPTH_16BIT;
284     break;
285     case 24:
286     case 32:
287     default_depth = VDEPTH_32BIT;
288     break;
289     }
290 jlachmann 1.20
291 cebix 1.23 for (unsigned d=VDEPTH_8BIT; d<=VDEPTH_32BIT; d++) {
292 jlachmann 1.21 ULONG mode_id = find_mode_for_depth(default_width, default_height, bits_from_depth(video_depth(d)));
293    
294 jlachmann 1.24 if (is_valid_modeid(default_display_type, mode_id))
295 jlachmann 1.20 add_modes(default_width, default_height, video_depth(d));
296 cebix 1.23 }
297 jlachmann 1.20 break;
298     }
299    
300     #if DEBUG
301     bug("Available video modes:\n");
302     vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
303     while (i != end) {
304 jlachmann 1.24 bug(" %ld x %ld (ID %02lx), %ld colors\n", i->x, i->y, i->resolution_id, 1 << bits_from_depth(i->depth));
305 jlachmann 1.20 ++i;
306     }
307     #endif
308    
309 jlachmann 1.24 D(bug("VideoInit/%ld: def_width=%ld def_height=%ld def_depth=%ld\n", \
310     __LINE__, default_width, default_height, default_depth));
311 jlachmann 1.20
312     // Find requested default mode and open display
313 cebix 1.25 if (VideoModes.size() == 1) {
314 jlachmann 1.24 uint32 default_id ;
315    
316     // Create Amiga_monitor_desc for this (the only) display
317     default_id = VideoModes[0].resolution_id;
318     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
319     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
320     VideoMonitors.push_back(monitor);
321    
322     // Open display
323     return monitor->video_open();
324 cebix 1.25
325     } else {
326    
327 jlachmann 1.20 // Find mode with specified dimensions
328     std::vector<video_mode>::const_iterator i, end = VideoModes.end();
329 cebix 1.23 for (i = VideoModes.begin(); i != end; ++i) {
330 jlachmann 1.24 D(bug("VideoInit/%ld: w=%ld h=%ld d=%ld\n", __LINE__, i->x, i->y, bits_from_depth(i->depth)));
331 cebix 1.25 if (i->x == default_width && i->y == default_height && i->depth == default_depth) {
332 jlachmann 1.24 // Create Amiga_monitor_desc for this (the only) display
333     uint32 default_id = i->resolution_id;
334     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
335     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
336     VideoMonitors.push_back(monitor);
337    
338     // Open display
339     return monitor->video_open();
340 cebix 1.25 }
341 cebix 1.23 }
342 jlachmann 1.24
343     // Create Amiga_monitor_desc for this (the only) display
344     uint32 default_id = VideoModes[0].resolution_id;
345     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
346     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
347     VideoMonitors.push_back(monitor);
348    
349     // Open display
350     return monitor->video_open();
351 jlachmann 1.20 }
352    
353     return true;
354     }
355    
356    
357 jlachmann 1.24 bool Amiga_monitor_desc::video_open()
358 jlachmann 1.20 {
359 jlachmann 1.24 const video_mode &mode = get_current_mode();
360 jlachmann 1.20 ULONG depth_bits = bits_from_depth(mode.depth);
361     ULONG ID = find_mode_for_depth(mode.x, mode.y, depth_bits);
362    
363 jlachmann 1.24 D(bug("video_open/%ld: width=%ld height=%ld depth=%ld ID=%08lx\n", __LINE__, mode.x, mode.y, depth_bits, ID));
364 jlachmann 1.20
365 cebix 1.23 if (ID == INVALID_ID) {
366 jlachmann 1.20 ErrorAlert(STR_NO_VIDEO_MODE_ERR);
367     return false;
368 cebix 1.23 }
369 jlachmann 1.20
370 jlachmann 1.24 D(bug("video_open/%ld: display_type=%ld\n", __LINE__, display_type));
371 jlachmann 1.20
372 cebix 1.1 // Open display
373     switch (display_type) {
374     case DISPLAY_WINDOW:
375 jlachmann 1.24 drv = new driver_window(*this, mode.x, mode.y);
376 cebix 1.1 break;
377    
378     case DISPLAY_PIP:
379 jlachmann 1.24 drv = new driver_pip(*this, mode.x, mode.y);
380 cebix 1.1 break;
381    
382 cebix 1.6 case DISPLAY_SCREEN_P96:
383 jlachmann 1.24 drv = new driver_screen_p96(*this, ID);
384 cebix 1.6 break;
385    
386     case DISPLAY_SCREEN_CGFX:
387 jlachmann 1.24 drv = new driver_screen_cgfx(*this, ID);
388 cebix 1.1 break;
389     }
390    
391 jlachmann 1.24 D(bug("video_open/%ld: drv=%08lx\n", __LINE__, drv));
392    
393     if (drv == NULL)
394     return false;
395    
396     D(bug("video_open/%ld: init_ok=%ld\n", __LINE__, drv->init_ok));
397     if (!drv->init_ok) {
398     delete drv;
399     drv = NULL;
400     return false;
401     }
402    
403 cebix 1.1 // Start periodic process
404     periodic_proc = CreateNewProcTags(
405 cebix 1.2 NP_Entry, (ULONG)periodic_func,
406     NP_Name, (ULONG)"Basilisk II IDCMP Handler",
407 cebix 1.1 NP_Priority, 0,
408     TAG_END
409     );
410 jlachmann 1.24
411     D(bug("video_open/%ld: periodic_proc=%08lx\n", __LINE__, periodic_proc));
412    
413 cebix 1.1 if (periodic_proc == NULL) {
414 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
415 cebix 1.1 return false;
416     }
417 jlachmann 1.20
418 cebix 1.1 return true;
419     }
420    
421    
422 jlachmann 1.24 void Amiga_monitor_desc::video_close()
423 cebix 1.1 {
424     // Stop periodic process
425     if (periodic_proc) {
426     SetSignal(0, SIGF_SINGLE);
427     Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C);
428     Wait(SIGF_SINGLE);
429     }
430    
431 jlachmann 1.24 delete drv;
432 cebix 1.25 drv = NULL;
433 cebix 1.8
434     // Free mouse pointer
435     if (null_pointer) {
436     FreeMem(null_pointer, 12);
437     null_pointer = NULL;
438     }
439 cebix 1.1 }
440    
441    
442     /*
443 jlachmann 1.20 * Deinitialization
444     */
445    
446     void VideoExit(void)
447     {
448 jlachmann 1.24 // Close displays
449     vector<monitor_desc *>::iterator i, end = VideoMonitors.end();
450     for (i = VideoMonitors.begin(); i != end; ++i)
451     dynamic_cast<Amiga_monitor_desc *>(*i)->video_close();
452 jlachmann 1.20 }
453    
454    
455     /*
456 cebix 1.1 * Set palette
457     */
458    
459 jlachmann 1.24 void Amiga_monitor_desc::set_palette(uint8 *pal, int num)
460 cebix 1.1 {
461 jlachmann 1.24 drv->set_palette(pal, num);
462 cebix 1.1 }
463    
464    
465     /*
466 cebix 1.14 * Switch video mode
467     */
468    
469 jlachmann 1.24 void Amiga_monitor_desc::switch_to_current_mode()
470 cebix 1.19 {
471 jlachmann 1.20 // Close and reopen display
472     video_close();
473 jlachmann 1.24 if (!video_open()) {
474 jlachmann 1.20 ErrorAlert(STR_OPEN_WINDOW_ERR);
475     QuitEmulator();
476 cebix 1.23 }
477 cebix 1.19 }
478    
479    
480     /*
481     * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode)
482     */
483    
484     void VideoQuitFullScreen(void)
485 cebix 1.14 {
486     }
487    
488    
489     /*
490 cebix 1.1 * Video message handling (not neccessary under AmigaOS, handled by periodic_func())
491     */
492    
493     void VideoInterrupt(void)
494     {
495     }
496    
497    
498     /*
499     * Process for window refresh and message handling
500     */
501    
502     static __saveds void periodic_func(void)
503     {
504     struct MsgPort *timer_port = NULL;
505     struct timerequest *timer_io = NULL;
506     struct IntuiMessage *msg;
507     ULONG win_mask = 0, timer_mask = 0;
508    
509 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
510    
511 cebix 1.1 // Create message port for window and attach it
512     struct MsgPort *win_port = CreateMsgPort();
513     if (win_port) {
514     win_mask = 1 << win_port->mp_SigBit;
515 jlachmann 1.24 drv->the_win->UserPort = win_port;
516     ModifyIDCMP(drv->the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY |
517     ((drv->monitor.display_type == DISPLAY_SCREEN_P96 || drv->monitor.display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
518 cebix 1.1 }
519    
520 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
521    
522 cebix 1.1 // Start 60Hz timer for window refresh
523 jlachmann 1.24 if (drv->monitor.display_type == DISPLAY_WINDOW) {
524 cebix 1.1 timer_port = CreateMsgPort();
525     if (timer_port) {
526     timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
527     if (timer_io) {
528 jlachmann 1.24 if (!OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
529 cebix 1.1 timer_mask = 1 << timer_port->mp_SigBit;
530     timer_io->tr_node.io_Command = TR_ADDREQUEST;
531     timer_io->tr_time.tv_secs = 0;
532     timer_io->tr_time.tv_micro = 16667 * frame_skip;
533     SendIO((struct IORequest *)timer_io);
534     }
535     }
536     }
537     }
538    
539 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
540    
541 cebix 1.1 // Main loop
542     for (;;) {
543 jlachmann 1.24 const video_mode &mode = drv->monitor.get_current_mode();
544 cebix 1.1
545     // Wait for timer and/or window (CTRL_C is used for quitting the task)
546     ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C);
547    
548     if (sig & SIGBREAKF_CTRL_C)
549     break;
550    
551 jlachmann 1.24 // D(bug("periodic_func/%ld: display_type=%ld the_win=%08lx\n", __LINE__, drv->monitor.display_type, drv->the_win));
552    
553 cebix 1.1 if (sig & timer_mask) {
554 cebix 1.25 if (drv->get_bitmap()) {
555 jlachmann 1.24 // Timer tick, update display
556     BltTemplate(drv->get_bitmap()->Planes[0], 0,
557     drv->get_bitmap()->BytesPerRow, drv->the_win->RPort,
558     drv->the_win->BorderLeft, drv->the_win->BorderTop,
559     mode.x, mode.y);
560 cebix 1.25 }
561 cebix 1.1
562     // Restart timer
563     timer_io->tr_node.io_Command = TR_ADDREQUEST;
564     timer_io->tr_time.tv_secs = 0;
565     timer_io->tr_time.tv_micro = 16667 * frame_skip;
566     SendIO((struct IORequest *)timer_io);
567     }
568    
569     if (sig & win_mask) {
570    
571     // Handle window messages
572     while (msg = (struct IntuiMessage *)GetMsg(win_port)) {
573    
574     // Get data from message and reply
575     ULONG cl = msg->Class;
576     UWORD code = msg->Code;
577     UWORD qualifier = msg->Qualifier;
578     WORD mx = msg->MouseX;
579     WORD my = msg->MouseY;
580     ReplyMsg((struct Message *)msg);
581    
582     // Handle message according to class
583     switch (cl) {
584     case IDCMP_MOUSEMOVE:
585 cebix 1.25 switch (drv->monitor.display_type) {
586     case DISPLAY_SCREEN_P96:
587     case DISPLAY_SCREEN_CGFX:
588     // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx, my));
589     ADBMouseMoved(mx, my);
590     break;
591     default:
592     // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop));
593     ADBMouseMoved(mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop);
594     if (mx < drv->the_win->BorderLeft
595     || my < drv->the_win->BorderTop
596     || mx >= drv->the_win->BorderLeft + mode.x
597     || my >= drv->the_win->BorderTop + mode.y) {
598     if (current_pointer) {
599     ClearPointer(drv->the_win);
600     current_pointer = NULL;
601     }
602     } else {
603     if (current_pointer != null_pointer) {
604     // Hide mouse pointer inside window
605     SetPointer(drv->the_win, null_pointer, 1, 16, 0, 0);
606     current_pointer = null_pointer;
607     }
608 cebix 1.8 }
609 cebix 1.25 break;
610     }
611 cebix 1.1 break;
612    
613     case IDCMP_MOUSEBUTTONS:
614     if (code == SELECTDOWN)
615     ADBMouseDown(0);
616     else if (code == SELECTUP)
617     ADBMouseUp(0);
618     else if (code == MENUDOWN)
619     ADBMouseDown(1);
620     else if (code == MENUUP)
621     ADBMouseUp(1);
622     else if (code == MIDDLEDOWN)
623     ADBMouseDown(2);
624     else if (code == MIDDLEUP)
625     ADBMouseUp(2);
626     break;
627    
628     case IDCMP_RAWKEY:
629     if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS
630     break;
631 cebix 1.11 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
632     (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
633 jlachmann 1.9 SetInterruptFlag(INTFLAG_NMI);
634     TriggerInterrupt();
635     break;
636 cebix 1.10 }
637 jlachmann 1.9
638 cebix 1.1 if (code & IECODE_UP_PREFIX)
639     ADBKeyUp(keycode2mac[code & 0x7f]);
640     else
641     ADBKeyDown(keycode2mac[code & 0x7f]);
642     break;
643     }
644     }
645     }
646     }
647    
648 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
649    
650 cebix 1.1 // Stop timer
651     if (timer_io) {
652     if (!CheckIO((struct IORequest *)timer_io))
653     AbortIO((struct IORequest *)timer_io);
654     WaitIO((struct IORequest *)timer_io);
655     CloseDevice((struct IORequest *)timer_io);
656     DeleteIORequest(timer_io);
657     }
658     if (timer_port)
659     DeleteMsgPort(timer_port);
660    
661     // Remove port from window and delete it
662     Forbid();
663     msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head;
664     struct Node *succ;
665     while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
666 jlachmann 1.24 if (msg->IDCMPWindow == drv->the_win) {
667 cebix 1.1 Remove((struct Node *)msg);
668     ReplyMsg((struct Message *)msg);
669     }
670     msg = (struct IntuiMessage *)succ;
671     }
672 jlachmann 1.24 drv->the_win->UserPort = NULL;
673     ModifyIDCMP(drv->the_win, 0);
674 cebix 1.1 Permit();
675     DeleteMsgPort(win_port);
676    
677     // Main task asked for termination, send signal
678     Forbid();
679     Signal(MainTask, SIGF_SINGLE);
680     }
681 jlachmann 1.20
682    
683     // Add mode to list of supported modes
684     static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
685     {
686     video_mode mode;
687     mode.x = width;
688     mode.y = height;
689     mode.resolution_id = resolution_id;
690     mode.bytes_per_row = bytes_per_row;
691     mode.depth = depth;
692    
693     D(bug("Added video mode: w=%ld h=%ld d=%ld\n", width, height, depth));
694    
695     VideoModes.push_back(mode);
696     }
697    
698 cebix 1.23 // Add standard list of modes for given color depth
699 jlachmann 1.20 static void add_modes(uint32 width, uint32 height, video_depth depth)
700     {
701     D(bug("add_modes: w=%ld h=%ld d=%ld\n", width, height, depth));
702    
703     if (width >= 512 && height >= 384)
704     add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
705     if (width >= 640 && height >= 480)
706     add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
707     if (width >= 800 && height >= 600)
708     add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
709     if (width >= 1024 && height >= 768)
710     add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth);
711     if (width >= 1152 && height >= 870)
712     add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth);
713     if (width >= 1280 && height >= 1024)
714     add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth);
715     if (width >= 1600 && height >= 1200)
716     add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth);
717     }
718    
719    
720     static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth)
721     {
722     ULONG ID = BestModeID(BIDTAG_NominalWidth, width,
723     BIDTAG_NominalHeight, height,
724     BIDTAG_Depth, depth,
725 jlachmann 1.21 BIDTAG_DIPFMustNotHave, DIPF_IS_ECS | DIPF_IS_HAM | DIPF_IS_AA,
726 jlachmann 1.20 TAG_END);
727    
728     return ID;
729     }
730    
731    
732     static ULONG bits_from_depth(video_depth depth)
733     {
734     int bits = 1 << depth;
735     if (bits == 16)
736     bits = 15;
737     else if (bits == 32)
738     bits = 24;
739    
740     return bits;
741 jlachmann 1.21 }
742    
743    
744     static bool is_valid_modeid(int display_type, ULONG mode_id)
745     {
746     if (INVALID_ID == mode_id)
747     return false;
748    
749 cebix 1.23 switch (display_type) {
750     case DISPLAY_SCREEN_P96:
751     return check_modeid_p96(mode_id);
752     break;
753     case DISPLAY_SCREEN_CGFX:
754     return check_modeid_cgfx(mode_id);
755     break;
756     default:
757     return false;
758     break;
759     }
760 jlachmann 1.21 }
761    
762    
763     static bool check_modeid_p96(ULONG mode_id)
764     {
765     // Check if the mode is one we can handle
766     uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
767     uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT);
768    
769 cebix 1.23 D(bug("check_modeid_p96: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
770    
771 jlachmann 1.24 if (!p96GetModeIDAttr(mode_id, P96IDA_ISP96))
772 jlachmann 1.21 return false;
773    
774     switch (depth) {
775     case 8:
776     break;
777     case 15:
778     case 16:
779     if (format != RGBFB_R5G5B5)
780     return false;
781     break;
782     case 24:
783     case 32:
784     if (format != RGBFB_A8R8G8B8)
785     return false;
786     break;
787     default:
788     return false;
789     }
790    
791     return true;
792     }
793    
794    
795     static bool check_modeid_cgfx(ULONG mode_id)
796     {
797     uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
798     uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
799    
800 cebix 1.23 D(bug("check_modeid_cgfx: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
801 jlachmann 1.21
802     if (!IsCyberModeID(mode_id))
803     return false;
804    
805     switch (depth) {
806     case 8:
807     break;
808     case 15:
809     case 16:
810     if (format != PIXFMT_RGB15)
811     return false;
812     break;
813     case 24:
814     case 32:
815     if (format != PIXFMT_ARGB32)
816     return false;
817     break;
818     default:
819     return false;
820     }
821    
822     return true;
823 jlachmann 1.20 }
824 jlachmann 1.24
825    
826     driver_base::driver_base(Amiga_monitor_desc &m)
827     : monitor(m), mode(m.get_current_mode()), init_ok(false)
828     {
829     }
830    
831     driver_base::~driver_base()
832     {
833     }
834    
835    
836     // Open window
837     driver_window::driver_window(Amiga_monitor_desc &m, int width, int height)
838     : black_pen(-1), white_pen(-1), driver_base(m)
839     {
840 cebix 1.25 // Set absolute mouse mode
841 jlachmann 1.24 ADBSetRelMouseMode(false);
842    
843     // Open window
844     the_win = OpenWindowTags(NULL,
845     WA_Left, 0, WA_Top, 0,
846     WA_InnerWidth, width, WA_InnerHeight, height,
847     WA_SimpleRefresh, true,
848     WA_NoCareRefresh, true,
849     WA_Activate, true,
850     WA_RMBTrap, true,
851     WA_ReportMouse, true,
852     WA_DragBar, true,
853     WA_DepthGadget, true,
854     WA_SizeGadget, false,
855     WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
856     TAG_END
857     );
858     if (the_win == NULL) {
859     init_ok = false;
860     ErrorAlert(STR_OPEN_WINDOW_ERR);
861     return;
862     }
863    
864     // Create bitmap ("height + 2" for safety)
865     the_bitmap = AllocBitMap(width, height + 2, 1, BMF_CLEAR, NULL);
866     if (the_bitmap == NULL) {
867     init_ok = false;
868     ErrorAlert(STR_NO_MEM_ERR);
869     return;
870     }
871    
872     // Add resolution and set VideoMonitor
873     monitor.set_mac_frame_base((uint32)the_bitmap->Planes[0]);
874    
875     // Set FgPen and BgPen
876     black_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL);
877     white_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0xffffffff, 0xffffffff, 0xffffffff, NULL);
878     SetAPen(the_win->RPort, black_pen);
879     SetBPen(the_win->RPort, white_pen);
880     SetDrMd(the_win->RPort, JAM2);
881    
882     init_ok = true;
883     }
884    
885    
886     driver_window::~driver_window()
887     {
888     // Window mode, free bitmap
889     if (the_bitmap) {
890     WaitBlit();
891     FreeBitMap(the_bitmap);
892     }
893    
894     // Free pens and close window
895     if (the_win) {
896     ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen);
897     ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen);
898    
899     CloseWindow(the_win);
900     the_win = NULL;
901     }
902     }
903    
904    
905     // Open PIP (requires Picasso96)
906     driver_pip::driver_pip(Amiga_monitor_desc &m, int width, int height)
907     : driver_base(m)
908     {
909 cebix 1.25 // Set absolute mouse mode
910 jlachmann 1.24 ADBSetRelMouseMode(false);
911    
912 cebix 1.25 D(bug("driver_pip(%d,%d)\n", width, height));
913    
914 jlachmann 1.24 // Open window
915     ULONG error = 0;
916     the_win = p96PIP_OpenTags(
917     P96PIP_SourceFormat, RGBFB_R5G5B5,
918     P96PIP_SourceWidth, width,
919     P96PIP_SourceHeight, height,
920     P96PIP_ErrorCode, (ULONG)&error,
921 cebix 1.25 P96PIP_AllowCropping, true,
922 jlachmann 1.24 WA_Left, 0, WA_Top, 0,
923     WA_InnerWidth, width, WA_InnerHeight, height,
924     WA_SimpleRefresh, true,
925     WA_NoCareRefresh, true,
926     WA_Activate, true,
927     WA_RMBTrap, true,
928     WA_ReportMouse, true,
929     WA_DragBar, true,
930     WA_DepthGadget, true,
931     WA_SizeGadget, false,
932     WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
933     WA_PubScreenName, (ULONG)"Workbench",
934     TAG_END
935     );
936     if (the_win == NULL || error) {
937     init_ok = false;
938     ErrorAlert(STR_OPEN_WINDOW_ERR);
939     return;
940     }
941    
942     // Find bitmap
943     p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
944    
945     // Add resolution and set VideoMonitor
946     monitor.set_mac_frame_base(p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY));
947    
948     init_ok = true;
949     }
950    
951     driver_pip::~driver_pip()
952     {
953     // Close PIP
954     if (the_win)
955     p96PIP_Close(the_win);
956     }
957    
958    
959     // Open Picasso96 screen
960     driver_screen_p96::driver_screen_p96(Amiga_monitor_desc &m, ULONG mode_id)
961     : driver_base(m)
962     {
963 cebix 1.25 // Set relative mouse mode
964 jlachmann 1.24 ADBSetRelMouseMode(true);
965    
966     // Check if the mode is one we can handle
967     if (!check_modeid_p96(mode_id))
968     {
969     init_ok = false;
970     ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
971     return;
972     }
973    
974     // Yes, get width and height
975     uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
976     uint32 width = p96GetModeIDAttr(mode_id, P96IDA_WIDTH);
977     uint32 height = p96GetModeIDAttr(mode_id, P96IDA_HEIGHT);
978    
979     // Open screen
980     the_screen = p96OpenScreenTags(
981     P96SA_DisplayID, mode_id,
982     P96SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
983     P96SA_Quiet, true,
984     P96SA_NoMemory, true,
985     P96SA_NoSprite, true,
986     P96SA_Exclusive, true,
987     TAG_END
988     );
989     if (the_screen == NULL) {
990     ErrorAlert(STR_OPEN_SCREEN_ERR);
991     init_ok = false;
992     return;
993     }
994    
995     // Open window
996     the_win = OpenWindowTags(NULL,
997     WA_Left, 0, WA_Top, 0,
998     WA_Width, width, WA_Height, height,
999     WA_SimpleRefresh, true,
1000     WA_NoCareRefresh, true,
1001     WA_Borderless, true,
1002     WA_Activate, true,
1003     WA_RMBTrap, true,
1004     WA_ReportMouse, true,
1005     WA_CustomScreen, (ULONG)the_screen,
1006     TAG_END
1007     );
1008     if (the_win == NULL) {
1009     ErrorAlert(STR_OPEN_WINDOW_ERR);
1010     init_ok = false;
1011     return;
1012     }
1013    
1014     ScreenToFront(the_screen);
1015    
1016     // Add resolution and set VideoMonitor
1017     monitor.set_mac_frame_base(p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY));
1018    
1019     init_ok = true;
1020     }
1021    
1022    
1023     driver_screen_p96::~driver_screen_p96()
1024     {
1025     // Close window
1026     if (the_win)
1027     {
1028     CloseWindow(the_win);
1029     the_win = NULL;
1030     }
1031    
1032     // Close screen
1033     if (the_screen) {
1034     p96CloseScreen(the_screen);
1035     the_screen = NULL;
1036     }
1037     }
1038    
1039    
1040     void driver_screen_p96::set_palette(uint8 *pal, int num)
1041     {
1042     // Convert palette to 32 bits
1043     ULONG table[2 + 256 * 3];
1044     table[0] = num << 16;
1045     table[num * 3 + 1] = 0;
1046     for (int i=0; i<num; i++) {
1047     table[i*3+1] = pal[i*3] * 0x01010101;
1048     table[i*3+2] = pal[i*3+1] * 0x01010101;
1049     table[i*3+3] = pal[i*3+2] * 0x01010101;
1050     }
1051    
1052     // And load it
1053     LoadRGB32(&the_screen->ViewPort, table);
1054     }
1055    
1056    
1057     // Open CyberGraphX screen
1058     driver_screen_cgfx::driver_screen_cgfx(Amiga_monitor_desc &m, ULONG mode_id)
1059     : driver_base(m)
1060     {
1061     D(bug("driver_screen_cgfx/%ld: mode_id=%08lx\n", __LINE__, mode_id));
1062    
1063     // Set absolute mouse mode
1064     ADBSetRelMouseMode(true);
1065    
1066     // Check if the mode is one we can handle
1067     if (!check_modeid_cgfx(mode_id))
1068     {
1069     ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
1070     init_ok = false;
1071     return;
1072     }
1073    
1074     // Yes, get width and height
1075     uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
1076     uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
1077     uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
1078    
1079     // Open screen
1080     the_screen = OpenScreenTags(NULL,
1081     SA_DisplayID, mode_id,
1082     SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
1083     SA_Quiet, true,
1084     SA_Exclusive, true,
1085     TAG_END
1086     );
1087     if (the_screen == NULL) {
1088     ErrorAlert(STR_OPEN_SCREEN_ERR);
1089     init_ok = false;
1090     return;
1091     }
1092    
1093     // Open window
1094     the_win = OpenWindowTags(NULL,
1095     WA_Left, 0, WA_Top, 0,
1096     WA_Width, width, WA_Height, height,
1097     WA_SimpleRefresh, true,
1098     WA_NoCareRefresh, true,
1099     WA_Borderless, true,
1100     WA_Activate, true,
1101     WA_RMBTrap, true,
1102     WA_ReportMouse, true,
1103     WA_CustomScreen, (ULONG)the_screen,
1104     TAG_END
1105     );
1106     if (the_win == NULL) {
1107     ErrorAlert(STR_OPEN_WINDOW_ERR);
1108     init_ok = false;
1109     return;
1110     }
1111    
1112     ScreenToFront(the_screen);
1113     static UWORD ptr[] = { 0, 0, 0, 0 };
1114     SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
1115    
1116     // Set VideoMonitor
1117     ULONG frame_base;
1118     APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
1119     LBMI_BASEADDRESS, (ULONG)&frame_base,
1120     TAG_END
1121     );
1122     UnLockBitMap(handle);
1123    
1124     D(bug("driver_screen_cgfx/%ld: frame_base=%08lx\n", __LINE__, frame_base));
1125    
1126     monitor.set_mac_frame_base(frame_base);
1127    
1128     init_ok = true;
1129     }
1130    
1131    
1132     driver_screen_cgfx::~driver_screen_cgfx()
1133     {
1134     D(bug("~driver_screen_cgfx/%ld: \n", __LINE__));
1135    
1136     // Close window
1137     if (the_win)
1138     {
1139     CloseWindow(the_win);
1140     the_win = NULL;
1141     }
1142    
1143     // Close screen
1144     if (the_screen) {
1145     CloseScreen(the_screen);
1146     the_screen = NULL;
1147     }
1148     }
1149    
1150    
1151     void driver_screen_cgfx::set_palette(uint8 *pal, int num)
1152     {
1153     // Convert palette to 32 bits
1154     ULONG table[2 + 256 * 3];
1155     table[0] = num << 16;
1156     table[num * 3 + 1] = 0;
1157     for (int i=0; i<num; i++) {
1158     table[i*3+1] = pal[i*3] * 0x01010101;
1159     table[i*3+2] = pal[i*3+1] * 0x01010101;
1160     table[i*3+3] = pal[i*3+2] * 0x01010101;
1161     }
1162    
1163     // And load it
1164     LoadRGB32(&the_screen->ViewPort, table);
1165     }