ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.24
Committed: 2002-06-23T08:27:05Z (22 years ago) by jlachmann
Branch: MAIN
Changes since 1.23: +578 -350 lines
Log Message:
Adapted to OO video scheme; Audio volume/muting/sample rate now settable

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3     *
4 cebix 1.22 * Basilisk II (C) 1997-2002 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 jlachmann 1.24 default_depth = VDEPTH_16BIT;
255 jlachmann 1.20 default_width = window_width;
256     default_height = window_height;
257     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     switch (dimInfo.MaxDepth)
275     {
276     case 1:
277     default_depth = VDEPTH_1BIT;
278     break;
279     case 8:
280     default_depth = VDEPTH_8BIT;
281     break;
282     case 15:
283     case 16:
284     default_depth = VDEPTH_16BIT;
285     break;
286     case 24:
287     case 32:
288     default_depth = VDEPTH_32BIT;
289     break;
290     }
291 jlachmann 1.20
292 cebix 1.23 for (unsigned d=VDEPTH_8BIT; d<=VDEPTH_32BIT; d++) {
293 jlachmann 1.21 ULONG mode_id = find_mode_for_depth(default_width, default_height, bits_from_depth(video_depth(d)));
294    
295 jlachmann 1.24 if (is_valid_modeid(default_display_type, mode_id))
296 jlachmann 1.20 add_modes(default_width, default_height, video_depth(d));
297 cebix 1.23 }
298 jlachmann 1.20 break;
299     }
300    
301 jlachmann 1.24 // video_init_depth_list();
302 jlachmann 1.20
303     #if DEBUG
304     bug("Available video modes:\n");
305     vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
306     while (i != end) {
307 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));
308 jlachmann 1.20 ++i;
309     }
310     #endif
311    
312 jlachmann 1.24 D(bug("VideoInit/%ld: def_width=%ld def_height=%ld def_depth=%ld\n", \
313     __LINE__, default_width, default_height, default_depth));
314 jlachmann 1.20
315     // Find requested default mode and open display
316     if (VideoModes.size() == 1)
317 jlachmann 1.24 {
318     uint32 default_id ;
319    
320     // Create Amiga_monitor_desc for this (the only) display
321     default_id = VideoModes[0].resolution_id;
322     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
323     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
324     VideoMonitors.push_back(monitor);
325    
326     // Open display
327     return monitor->video_open();
328     }
329 jlachmann 1.20 else {
330     // Find mode with specified dimensions
331     std::vector<video_mode>::const_iterator i, end = VideoModes.end();
332 cebix 1.23 for (i = VideoModes.begin(); i != end; ++i) {
333 jlachmann 1.24 D(bug("VideoInit/%ld: w=%ld h=%ld d=%ld\n", __LINE__, i->x, i->y, bits_from_depth(i->depth)));
334     if (i->x == default_width && i->y == default_height && i->depth == default_depth)
335     {
336     // Create Amiga_monitor_desc for this (the only) display
337     uint32 default_id = i->resolution_id;
338     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
339     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
340     VideoMonitors.push_back(monitor);
341    
342     // Open display
343     return monitor->video_open();
344     }
345 cebix 1.23 }
346 jlachmann 1.24
347     // Create Amiga_monitor_desc for this (the only) display
348     uint32 default_id = VideoModes[0].resolution_id;
349     D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id));
350     Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type);
351     VideoMonitors.push_back(monitor);
352    
353     // Open display
354     return monitor->video_open();
355 jlachmann 1.20 }
356    
357     return true;
358     }
359    
360    
361 jlachmann 1.24 bool Amiga_monitor_desc::video_open()
362 jlachmann 1.20 {
363 jlachmann 1.24 const video_mode &mode = get_current_mode();
364 jlachmann 1.20 ULONG depth_bits = bits_from_depth(mode.depth);
365     ULONG ID = find_mode_for_depth(mode.x, mode.y, depth_bits);
366    
367 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));
368 jlachmann 1.20
369 cebix 1.23 if (ID == INVALID_ID) {
370 jlachmann 1.20 ErrorAlert(STR_NO_VIDEO_MODE_ERR);
371     return false;
372 cebix 1.23 }
373 jlachmann 1.20
374 jlachmann 1.24 // VideoMonitor.mode = mode;
375    
376     D(bug("video_open/%ld: display_type=%ld\n", __LINE__, display_type));
377 jlachmann 1.20
378 cebix 1.1 // Open display
379     switch (display_type) {
380     case DISPLAY_WINDOW:
381 jlachmann 1.24 drv = new driver_window(*this, mode.x, mode.y);
382 cebix 1.1 break;
383    
384     case DISPLAY_PIP:
385 jlachmann 1.24 drv = new driver_pip(*this, mode.x, mode.y);
386 cebix 1.1 break;
387    
388 cebix 1.6 case DISPLAY_SCREEN_P96:
389 jlachmann 1.24 drv = new driver_screen_p96(*this, ID);
390 cebix 1.6 break;
391    
392     case DISPLAY_SCREEN_CGFX:
393 jlachmann 1.24 drv = new driver_screen_cgfx(*this, ID);
394 cebix 1.1 break;
395     }
396    
397 jlachmann 1.24 D(bug("video_open/%ld: drv=%08lx\n", __LINE__, drv));
398    
399     if (drv == NULL)
400     return false;
401    
402     D(bug("video_open/%ld: init_ok=%ld\n", __LINE__, drv->init_ok));
403     if (!drv->init_ok) {
404     delete drv;
405     drv = NULL;
406     return false;
407     }
408    
409 cebix 1.1 // Start periodic process
410     periodic_proc = CreateNewProcTags(
411 cebix 1.2 NP_Entry, (ULONG)periodic_func,
412     NP_Name, (ULONG)"Basilisk II IDCMP Handler",
413 cebix 1.1 NP_Priority, 0,
414     TAG_END
415     );
416 jlachmann 1.24
417     D(bug("video_open/%ld: periodic_proc=%08lx\n", __LINE__, periodic_proc));
418    
419 cebix 1.1 if (periodic_proc == NULL) {
420 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
421 cebix 1.1 return false;
422     }
423 jlachmann 1.20
424 cebix 1.1 return true;
425     }
426    
427    
428 jlachmann 1.24 void Amiga_monitor_desc::video_close()
429 cebix 1.1 {
430     // Stop periodic process
431     if (periodic_proc) {
432     SetSignal(0, SIGF_SINGLE);
433     Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C);
434     Wait(SIGF_SINGLE);
435     }
436    
437 jlachmann 1.24 delete drv;
438 cebix 1.8
439     // Free mouse pointer
440     if (null_pointer) {
441     FreeMem(null_pointer, 12);
442     null_pointer = NULL;
443     }
444 cebix 1.1 }
445    
446    
447     /*
448 jlachmann 1.20 * Deinitialization
449     */
450    
451     void VideoExit(void)
452     {
453 jlachmann 1.24 // Close displays
454     vector<monitor_desc *>::iterator i, end = VideoMonitors.end();
455     for (i = VideoMonitors.begin(); i != end; ++i)
456     dynamic_cast<Amiga_monitor_desc *>(*i)->video_close();
457 jlachmann 1.20 }
458    
459    
460     /*
461 cebix 1.1 * Set palette
462     */
463    
464 jlachmann 1.24 void Amiga_monitor_desc::set_palette(uint8 *pal, int num)
465 cebix 1.1 {
466 jlachmann 1.24 drv->set_palette(pal, num);
467 cebix 1.1 }
468    
469    
470     /*
471 cebix 1.14 * Switch video mode
472     */
473    
474 jlachmann 1.24 void Amiga_monitor_desc::switch_to_current_mode()
475 cebix 1.19 {
476 jlachmann 1.20 // Close and reopen display
477     video_close();
478 jlachmann 1.24 if (!video_open()) {
479 jlachmann 1.20 ErrorAlert(STR_OPEN_WINDOW_ERR);
480     QuitEmulator();
481 cebix 1.23 }
482 cebix 1.19 }
483    
484    
485     /*
486     * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode)
487     */
488    
489     void VideoQuitFullScreen(void)
490 cebix 1.14 {
491     }
492    
493    
494     /*
495 cebix 1.1 * Video message handling (not neccessary under AmigaOS, handled by periodic_func())
496     */
497    
498     void VideoInterrupt(void)
499     {
500     }
501    
502    
503     /*
504     * Process for window refresh and message handling
505     */
506    
507     static __saveds void periodic_func(void)
508     {
509     struct MsgPort *timer_port = NULL;
510     struct timerequest *timer_io = NULL;
511     struct IntuiMessage *msg;
512     ULONG win_mask = 0, timer_mask = 0;
513    
514 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
515    
516 cebix 1.1 // Create message port for window and attach it
517     struct MsgPort *win_port = CreateMsgPort();
518     if (win_port) {
519     win_mask = 1 << win_port->mp_SigBit;
520 jlachmann 1.24 drv->the_win->UserPort = win_port;
521     ModifyIDCMP(drv->the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY |
522     ((drv->monitor.display_type == DISPLAY_SCREEN_P96 || drv->monitor.display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
523 cebix 1.1 }
524    
525 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
526    
527 cebix 1.1 // Start 60Hz timer for window refresh
528 jlachmann 1.24 if (drv->monitor.display_type == DISPLAY_WINDOW) {
529 cebix 1.1 timer_port = CreateMsgPort();
530     if (timer_port) {
531     timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
532     if (timer_io) {
533 jlachmann 1.24 if (!OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
534 cebix 1.1 timer_mask = 1 << timer_port->mp_SigBit;
535     timer_io->tr_node.io_Command = TR_ADDREQUEST;
536     timer_io->tr_time.tv_secs = 0;
537     timer_io->tr_time.tv_micro = 16667 * frame_skip;
538     SendIO((struct IORequest *)timer_io);
539     }
540     }
541     }
542     }
543    
544 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
545    
546 cebix 1.1 // Main loop
547     for (;;) {
548 jlachmann 1.24 const video_mode &mode = drv->monitor.get_current_mode();
549 cebix 1.1
550     // Wait for timer and/or window (CTRL_C is used for quitting the task)
551     ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C);
552    
553     if (sig & SIGBREAKF_CTRL_C)
554     break;
555    
556 jlachmann 1.24 // D(bug("periodic_func/%ld: display_type=%ld the_win=%08lx\n", __LINE__, drv->monitor.display_type, drv->the_win));
557    
558 cebix 1.1 if (sig & timer_mask) {
559 jlachmann 1.24 if (drv->get_bitmap())
560     {
561     // Timer tick, update display
562     BltTemplate(drv->get_bitmap()->Planes[0], 0,
563     drv->get_bitmap()->BytesPerRow, drv->the_win->RPort,
564     drv->the_win->BorderLeft, drv->the_win->BorderTop,
565     mode.x, mode.y);
566     }
567 cebix 1.1
568     // Restart timer
569     timer_io->tr_node.io_Command = TR_ADDREQUEST;
570     timer_io->tr_time.tv_secs = 0;
571     timer_io->tr_time.tv_micro = 16667 * frame_skip;
572     SendIO((struct IORequest *)timer_io);
573     }
574    
575     if (sig & win_mask) {
576    
577     // Handle window messages
578     while (msg = (struct IntuiMessage *)GetMsg(win_port)) {
579    
580     // Get data from message and reply
581     ULONG cl = msg->Class;
582     UWORD code = msg->Code;
583     UWORD qualifier = msg->Qualifier;
584     WORD mx = msg->MouseX;
585     WORD my = msg->MouseY;
586     ReplyMsg((struct Message *)msg);
587    
588     // Handle message according to class
589     switch (cl) {
590     case IDCMP_MOUSEMOVE:
591 jlachmann 1.24 switch (drv->monitor.display_type)
592     {
593     case DISPLAY_SCREEN_P96:
594     case DISPLAY_SCREEN_CGFX:
595     // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx, my));
596 cebix 1.1 ADBMouseMoved(mx, my);
597 jlachmann 1.24 break;
598     default:
599     // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop));
600     ADBMouseMoved(mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop);
601     if (mx < drv->the_win->BorderLeft
602     || my < drv->the_win->BorderTop
603     || mx >= drv->the_win->BorderLeft + mode.x
604     || my >= drv->the_win->BorderTop + mode.y) {
605 cebix 1.8 if (current_pointer) {
606 jlachmann 1.24 ClearPointer(drv->the_win);
607 cebix 1.8 current_pointer = NULL;
608     }
609     } else {
610     if (current_pointer != null_pointer) {
611     // Hide mouse pointer inside window
612 jlachmann 1.24 SetPointer(drv->the_win, null_pointer, 1, 16, 0, 0);
613 cebix 1.8 current_pointer = null_pointer;
614     }
615     }
616 jlachmann 1.24 break;
617     }
618 cebix 1.1 break;
619    
620     case IDCMP_MOUSEBUTTONS:
621     if (code == SELECTDOWN)
622     ADBMouseDown(0);
623     else if (code == SELECTUP)
624     ADBMouseUp(0);
625     else if (code == MENUDOWN)
626     ADBMouseDown(1);
627     else if (code == MENUUP)
628     ADBMouseUp(1);
629     else if (code == MIDDLEDOWN)
630     ADBMouseDown(2);
631     else if (code == MIDDLEUP)
632     ADBMouseUp(2);
633     break;
634    
635     case IDCMP_RAWKEY:
636     if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS
637     break;
638 cebix 1.11 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
639     (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
640 jlachmann 1.9 SetInterruptFlag(INTFLAG_NMI);
641     TriggerInterrupt();
642     break;
643 cebix 1.10 }
644 jlachmann 1.9
645 cebix 1.1 if (code & IECODE_UP_PREFIX)
646     ADBKeyUp(keycode2mac[code & 0x7f]);
647     else
648     ADBKeyDown(keycode2mac[code & 0x7f]);
649     break;
650     }
651     }
652     }
653     }
654    
655 jlachmann 1.24 D(bug("periodic_func/%ld: \n", __LINE__));
656    
657 cebix 1.1 // Stop timer
658     if (timer_io) {
659     if (!CheckIO((struct IORequest *)timer_io))
660     AbortIO((struct IORequest *)timer_io);
661     WaitIO((struct IORequest *)timer_io);
662     CloseDevice((struct IORequest *)timer_io);
663     DeleteIORequest(timer_io);
664     }
665     if (timer_port)
666     DeleteMsgPort(timer_port);
667    
668     // Remove port from window and delete it
669     Forbid();
670     msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head;
671     struct Node *succ;
672     while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
673 jlachmann 1.24 if (msg->IDCMPWindow == drv->the_win) {
674 cebix 1.1 Remove((struct Node *)msg);
675     ReplyMsg((struct Message *)msg);
676     }
677     msg = (struct IntuiMessage *)succ;
678     }
679 jlachmann 1.24 drv->the_win->UserPort = NULL;
680     ModifyIDCMP(drv->the_win, 0);
681 cebix 1.1 Permit();
682     DeleteMsgPort(win_port);
683    
684     // Main task asked for termination, send signal
685     Forbid();
686     Signal(MainTask, SIGF_SINGLE);
687     }
688 jlachmann 1.20
689    
690     // Add mode to list of supported modes
691     static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
692     {
693     video_mode mode;
694     mode.x = width;
695     mode.y = height;
696     mode.resolution_id = resolution_id;
697     mode.bytes_per_row = bytes_per_row;
698     mode.depth = depth;
699    
700     D(bug("Added video mode: w=%ld h=%ld d=%ld\n", width, height, depth));
701    
702     VideoModes.push_back(mode);
703     }
704    
705 cebix 1.23 // Add standard list of modes for given color depth
706 jlachmann 1.20 static void add_modes(uint32 width, uint32 height, video_depth depth)
707     {
708     D(bug("add_modes: w=%ld h=%ld d=%ld\n", width, height, depth));
709    
710     if (width >= 512 && height >= 384)
711     add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
712     if (width >= 640 && height >= 480)
713     add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
714     if (width >= 800 && height >= 600)
715     add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
716     if (width >= 1024 && height >= 768)
717     add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth);
718     if (width >= 1152 && height >= 870)
719     add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth);
720     if (width >= 1280 && height >= 1024)
721     add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth);
722     if (width >= 1600 && height >= 1200)
723     add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth);
724     }
725    
726    
727     static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth)
728     {
729     ULONG ID = BestModeID(BIDTAG_NominalWidth, width,
730     BIDTAG_NominalHeight, height,
731     BIDTAG_Depth, depth,
732 jlachmann 1.21 BIDTAG_DIPFMustNotHave, DIPF_IS_ECS | DIPF_IS_HAM | DIPF_IS_AA,
733 jlachmann 1.20 TAG_END);
734    
735     return ID;
736     }
737    
738    
739     static ULONG bits_from_depth(video_depth depth)
740     {
741     int bits = 1 << depth;
742     if (bits == 16)
743     bits = 15;
744     else if (bits == 32)
745     bits = 24;
746    
747     return bits;
748 jlachmann 1.21 }
749    
750    
751     static bool is_valid_modeid(int display_type, ULONG mode_id)
752     {
753     if (INVALID_ID == mode_id)
754     return false;
755    
756 cebix 1.23 switch (display_type) {
757     case DISPLAY_SCREEN_P96:
758     return check_modeid_p96(mode_id);
759     break;
760     case DISPLAY_SCREEN_CGFX:
761     return check_modeid_cgfx(mode_id);
762     break;
763     default:
764     return false;
765     break;
766     }
767 jlachmann 1.21 }
768    
769    
770     static bool check_modeid_p96(ULONG mode_id)
771     {
772     // Check if the mode is one we can handle
773     uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
774     uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT);
775    
776 cebix 1.23 D(bug("check_modeid_p96: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
777    
778 jlachmann 1.24 if (!p96GetModeIDAttr(mode_id, P96IDA_ISP96))
779 jlachmann 1.21 return false;
780    
781     switch (depth) {
782     case 8:
783     break;
784     case 15:
785     case 16:
786     if (format != RGBFB_R5G5B5)
787     return false;
788     break;
789     case 24:
790     case 32:
791     if (format != RGBFB_A8R8G8B8)
792     return false;
793     break;
794     default:
795     return false;
796     }
797    
798     return true;
799     }
800    
801    
802     static bool check_modeid_cgfx(ULONG mode_id)
803     {
804     uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
805     uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
806    
807 cebix 1.23 D(bug("check_modeid_cgfx: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
808 jlachmann 1.21
809     if (!IsCyberModeID(mode_id))
810     return false;
811    
812     switch (depth) {
813     case 8:
814     break;
815     case 15:
816     case 16:
817     if (format != PIXFMT_RGB15)
818     return false;
819     break;
820     case 24:
821     case 32:
822     if (format != PIXFMT_ARGB32)
823     return false;
824     break;
825     default:
826     return false;
827     }
828    
829     return true;
830 jlachmann 1.20 }
831 jlachmann 1.24
832    
833     driver_base::driver_base(Amiga_monitor_desc &m)
834     : monitor(m), mode(m.get_current_mode()), init_ok(false)
835     {
836     }
837    
838     driver_base::~driver_base()
839     {
840     }
841    
842    
843     // Open window
844     driver_window::driver_window(Amiga_monitor_desc &m, int width, int height)
845     : black_pen(-1), white_pen(-1), driver_base(m)
846     {
847     // Set relative mouse mode
848     ADBSetRelMouseMode(false);
849    
850     // Open window
851     the_win = OpenWindowTags(NULL,
852     WA_Left, 0, WA_Top, 0,
853     WA_InnerWidth, width, WA_InnerHeight, height,
854     WA_SimpleRefresh, true,
855     WA_NoCareRefresh, true,
856     WA_Activate, true,
857     WA_RMBTrap, true,
858     WA_ReportMouse, true,
859     WA_DragBar, true,
860     WA_DepthGadget, true,
861     WA_SizeGadget, false,
862     WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
863     TAG_END
864     );
865     if (the_win == NULL) {
866     init_ok = false;
867     ErrorAlert(STR_OPEN_WINDOW_ERR);
868     return;
869     }
870    
871     // Create bitmap ("height + 2" for safety)
872     the_bitmap = AllocBitMap(width, height + 2, 1, BMF_CLEAR, NULL);
873     if (the_bitmap == NULL) {
874     init_ok = false;
875     ErrorAlert(STR_NO_MEM_ERR);
876     return;
877     }
878    
879     // Add resolution and set VideoMonitor
880     monitor.set_mac_frame_base((uint32)the_bitmap->Planes[0]);
881    
882     // Set FgPen and BgPen
883     black_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL);
884     white_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0xffffffff, 0xffffffff, 0xffffffff, NULL);
885     SetAPen(the_win->RPort, black_pen);
886     SetBPen(the_win->RPort, white_pen);
887     SetDrMd(the_win->RPort, JAM2);
888    
889     init_ok = true;
890     }
891    
892    
893     driver_window::~driver_window()
894     {
895     // Window mode, free bitmap
896     if (the_bitmap) {
897     WaitBlit();
898     FreeBitMap(the_bitmap);
899     }
900    
901     // Free pens and close window
902     if (the_win) {
903     ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen);
904     ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen);
905    
906     CloseWindow(the_win);
907     the_win = NULL;
908     }
909     }
910    
911    
912     // Open PIP (requires Picasso96)
913     driver_pip::driver_pip(Amiga_monitor_desc &m, int width, int height)
914     : driver_base(m)
915     {
916     // Set relative mouse mode
917     ADBSetRelMouseMode(false);
918    
919     // Open window
920     ULONG error = 0;
921     the_win = p96PIP_OpenTags(
922     P96PIP_SourceFormat, RGBFB_R5G5B5,
923     P96PIP_SourceWidth, width,
924     P96PIP_SourceHeight, height,
925     P96PIP_ErrorCode, (ULONG)&error,
926     WA_Left, 0, WA_Top, 0,
927     WA_InnerWidth, width, WA_InnerHeight, height,
928     WA_SimpleRefresh, true,
929     WA_NoCareRefresh, true,
930     WA_Activate, true,
931     WA_RMBTrap, true,
932     WA_ReportMouse, true,
933     WA_DragBar, true,
934     WA_DepthGadget, true,
935     WA_SizeGadget, false,
936     WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
937     WA_PubScreenName, (ULONG)"Workbench",
938     TAG_END
939     );
940     if (the_win == NULL || error) {
941     init_ok = false;
942     ErrorAlert(STR_OPEN_WINDOW_ERR);
943     return;
944     }
945    
946     // Find bitmap
947     p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
948    
949     // Add resolution and set VideoMonitor
950     monitor.set_mac_frame_base(p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY));
951    
952     init_ok = true;
953     }
954    
955     driver_pip::~driver_pip()
956     {
957     // Close PIP
958     if (the_win)
959     p96PIP_Close(the_win);
960     }
961    
962    
963     // Open Picasso96 screen
964     driver_screen_p96::driver_screen_p96(Amiga_monitor_desc &m, ULONG mode_id)
965     : driver_base(m)
966     {
967     // Set absolute mouse mode
968     ADBSetRelMouseMode(true);
969    
970     // Check if the mode is one we can handle
971     if (!check_modeid_p96(mode_id))
972     {
973     init_ok = false;
974     ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
975     return;
976     }
977    
978     // Yes, get width and height
979     uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
980     uint32 width = p96GetModeIDAttr(mode_id, P96IDA_WIDTH);
981     uint32 height = p96GetModeIDAttr(mode_id, P96IDA_HEIGHT);
982    
983     // Open screen
984     the_screen = p96OpenScreenTags(
985     P96SA_DisplayID, mode_id,
986     P96SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
987     P96SA_Quiet, true,
988     P96SA_NoMemory, true,
989     P96SA_NoSprite, true,
990     P96SA_Exclusive, true,
991     TAG_END
992     );
993     if (the_screen == NULL) {
994     ErrorAlert(STR_OPEN_SCREEN_ERR);
995     init_ok = false;
996     return;
997     }
998    
999     // Open window
1000     the_win = OpenWindowTags(NULL,
1001     WA_Left, 0, WA_Top, 0,
1002     WA_Width, width, WA_Height, height,
1003     WA_SimpleRefresh, true,
1004     WA_NoCareRefresh, true,
1005     WA_Borderless, true,
1006     WA_Activate, true,
1007     WA_RMBTrap, true,
1008     WA_ReportMouse, true,
1009     WA_CustomScreen, (ULONG)the_screen,
1010     TAG_END
1011     );
1012     if (the_win == NULL) {
1013     ErrorAlert(STR_OPEN_WINDOW_ERR);
1014     init_ok = false;
1015     return;
1016     }
1017    
1018     ScreenToFront(the_screen);
1019    
1020     // Add resolution and set VideoMonitor
1021     monitor.set_mac_frame_base(p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY));
1022    
1023     init_ok = true;
1024     }
1025    
1026    
1027     driver_screen_p96::~driver_screen_p96()
1028     {
1029     // Close window
1030     if (the_win)
1031     {
1032     CloseWindow(the_win);
1033     the_win = NULL;
1034     }
1035    
1036     // Close screen
1037     if (the_screen) {
1038     p96CloseScreen(the_screen);
1039     the_screen = NULL;
1040     }
1041     }
1042    
1043    
1044     void driver_screen_p96::set_palette(uint8 *pal, int num)
1045     {
1046     // Convert palette to 32 bits
1047     ULONG table[2 + 256 * 3];
1048     table[0] = num << 16;
1049     table[num * 3 + 1] = 0;
1050     for (int i=0; i<num; i++) {
1051     table[i*3+1] = pal[i*3] * 0x01010101;
1052     table[i*3+2] = pal[i*3+1] * 0x01010101;
1053     table[i*3+3] = pal[i*3+2] * 0x01010101;
1054     }
1055    
1056     // And load it
1057     LoadRGB32(&the_screen->ViewPort, table);
1058     }
1059    
1060    
1061     // Open CyberGraphX screen
1062     driver_screen_cgfx::driver_screen_cgfx(Amiga_monitor_desc &m, ULONG mode_id)
1063     : driver_base(m)
1064     {
1065     D(bug("driver_screen_cgfx/%ld: mode_id=%08lx\n", __LINE__, mode_id));
1066    
1067     // Set absolute mouse mode
1068     ADBSetRelMouseMode(true);
1069    
1070     // Check if the mode is one we can handle
1071     if (!check_modeid_cgfx(mode_id))
1072     {
1073     ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
1074     init_ok = false;
1075     return;
1076     }
1077    
1078     // Yes, get width and height
1079     uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
1080     uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
1081     uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
1082    
1083     // Open screen
1084     the_screen = OpenScreenTags(NULL,
1085     SA_DisplayID, mode_id,
1086     SA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
1087     SA_Quiet, true,
1088     SA_Exclusive, true,
1089     TAG_END
1090     );
1091     if (the_screen == NULL) {
1092     ErrorAlert(STR_OPEN_SCREEN_ERR);
1093     init_ok = false;
1094     return;
1095     }
1096    
1097     // Open window
1098     the_win = OpenWindowTags(NULL,
1099     WA_Left, 0, WA_Top, 0,
1100     WA_Width, width, WA_Height, height,
1101     WA_SimpleRefresh, true,
1102     WA_NoCareRefresh, true,
1103     WA_Borderless, true,
1104     WA_Activate, true,
1105     WA_RMBTrap, true,
1106     WA_ReportMouse, true,
1107     WA_CustomScreen, (ULONG)the_screen,
1108     TAG_END
1109     );
1110     if (the_win == NULL) {
1111     ErrorAlert(STR_OPEN_WINDOW_ERR);
1112     init_ok = false;
1113     return;
1114     }
1115    
1116     ScreenToFront(the_screen);
1117     static UWORD ptr[] = { 0, 0, 0, 0 };
1118     SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
1119    
1120     // Set VideoMonitor
1121     ULONG frame_base;
1122     APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
1123     LBMI_BASEADDRESS, (ULONG)&frame_base,
1124     TAG_END
1125     );
1126     UnLockBitMap(handle);
1127    
1128     D(bug("driver_screen_cgfx/%ld: frame_base=%08lx\n", __LINE__, frame_base));
1129    
1130     monitor.set_mac_frame_base(frame_base);
1131    
1132     init_ok = true;
1133     }
1134    
1135    
1136     driver_screen_cgfx::~driver_screen_cgfx()
1137     {
1138     D(bug("~driver_screen_cgfx/%ld: \n", __LINE__));
1139    
1140     // Close window
1141     if (the_win)
1142     {
1143     CloseWindow(the_win);
1144     the_win = NULL;
1145     }
1146    
1147     // Close screen
1148     if (the_screen) {
1149     CloseScreen(the_screen);
1150     the_screen = NULL;
1151     }
1152     }
1153    
1154    
1155     void driver_screen_cgfx::set_palette(uint8 *pal, int num)
1156     {
1157     // Convert palette to 32 bits
1158     ULONG table[2 + 256 * 3];
1159     table[0] = num << 16;
1160     table[num * 3 + 1] = 0;
1161     for (int i=0; i<num; i++) {
1162     table[i*3+1] = pal[i*3] * 0x01010101;
1163     table[i*3+2] = pal[i*3+1] * 0x01010101;
1164     table[i*3+3] = pal[i*3+2] * 0x01010101;
1165     }
1166    
1167     // And load it
1168     LoadRGB32(&the_screen->ViewPort, table);
1169     }
1170