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

# Content
1 /*
2 * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3 *
4 * Basilisk II (C) 1997-2002 Christian Bauer
5 *
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 #include <cybergraphics/cybergraphics.h>
26 #include <dos/dostags.h>
27 #include <devices/timer.h>
28 #define __USE_SYSBASE
29 #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 #include <proto/cybergraphics.h>
35 #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
41 #include "sysdeps.h"
42 #include "cpu_emulation.h"
43 #include "main.h"
44 #include "adb.h"
45 #include "prefs.h"
46 #include "user_strings.h"
47 #include "video.h"
48
49 #define DEBUG 0
50 #include "debug.h"
51
52
53 // Supported video modes
54 static vector<video_mode> VideoModes;
55
56 // Display types
57 enum {
58 DISPLAY_WINDOW,
59 DISPLAY_PIP,
60 DISPLAY_SCREEN_P96,
61 DISPLAY_SCREEN_CGFX
62 };
63
64 // Global variables
65 static int32 frame_skip;
66 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
70 extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp)
71
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 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
109
110 /*
111 * Display "driver" classes
112 */
113
114 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
128
129 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
141 class driver_pip : public driver_base {
142 public:
143 driver_pip(Amiga_monitor_desc &m, int width, int height);
144 ~driver_pip();
145
146 struct BitMap *get_bitmap() { return the_bitmap; };
147
148 private:
149 struct BitMap *the_bitmap;
150 };
151
152 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
157 void set_palette(uint8 *pal, int num);
158
159 private:
160 struct Screen *the_screen;
161 };
162
163 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
168 void set_palette(uint8 *pal, int num);
169
170 private:
171 struct Screen *the_screen;
172 };
173
174
175 static driver_base *drv = NULL; // Pointer to currently used driver object
176
177
178
179 // 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
189
190 /*
191 * Initialization
192 */
193
194
195 bool VideoInit(bool classic)
196 {
197 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
203 // Allocate blank mouse pointer data
204 null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
205 if (null_pointer == NULL) {
206 ErrorAlert(STR_NO_MEM_ERR);
207 return false;
208 }
209
210 // 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 default_width = window_width = 512;
223 default_height = window_height = 384;
224
225 if (mode_str) {
226 if (sscanf(mode_str, "win/%d/%d", &window_width, &window_height) == 2)
227 default_display_type = DISPLAY_WINDOW;
228 else if (sscanf(mode_str, "pip/%d/%d", &window_width, &window_height) == 2 && P96Base)
229 default_display_type = DISPLAY_PIP;
230 else if (sscanf(mode_str, "scr/%08lx", &screen_mode_id) == 1 && (CyberGfxBase || P96Base)) {
231 if (P96Base && p96GetModeIDAttr(screen_mode_id, P96IDA_ISP96))
232 default_display_type = DISPLAY_SCREEN_P96;
233 else if (CyberGfxBase && IsCyberModeID(screen_mode_id))
234 default_display_type = DISPLAY_SCREEN_CGFX;
235 else {
236 ErrorAlert(STR_NO_P96_MODE_ERR);
237 return false;
238 }
239 }
240 }
241
242 D(bug("default_display_type %d, window_width %d, window_height %d\n", default_display_type, window_width, window_height));
243
244 // Construct list of supported modes
245 switch (default_display_type) {
246 case DISPLAY_WINDOW:
247 default_width = window_width;
248 default_height = window_height;
249 default_depth = VDEPTH_1BIT;
250 add_modes(window_width, window_height, VDEPTH_1BIT);
251 break;
252
253 case DISPLAY_PIP:
254 default_depth = VDEPTH_16BIT;
255 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 if (handle == NULL)
266 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
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
292 for (unsigned d=VDEPTH_8BIT; d<=VDEPTH_32BIT; d++) {
293 ULONG mode_id = find_mode_for_depth(default_width, default_height, bits_from_depth(video_depth(d)));
294
295 if (is_valid_modeid(default_display_type, mode_id))
296 add_modes(default_width, default_height, video_depth(d));
297 }
298 break;
299 }
300
301 // video_init_depth_list();
302
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 bug(" %ld x %ld (ID %02lx), %ld colors\n", i->x, i->y, i->resolution_id, 1 << bits_from_depth(i->depth));
308 ++i;
309 }
310 #endif
311
312 D(bug("VideoInit/%ld: def_width=%ld def_height=%ld def_depth=%ld\n", \
313 __LINE__, default_width, default_height, default_depth));
314
315 // Find requested default mode and open display
316 if (VideoModes.size() == 1)
317 {
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 else {
330 // Find mode with specified dimensions
331 std::vector<video_mode>::const_iterator i, end = VideoModes.end();
332 for (i = VideoModes.begin(); i != end; ++i) {
333 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 }
346
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 }
356
357 return true;
358 }
359
360
361 bool Amiga_monitor_desc::video_open()
362 {
363 const video_mode &mode = get_current_mode();
364 ULONG depth_bits = bits_from_depth(mode.depth);
365 ULONG ID = find_mode_for_depth(mode.x, mode.y, depth_bits);
366
367 D(bug("video_open/%ld: width=%ld height=%ld depth=%ld ID=%08lx\n", __LINE__, mode.x, mode.y, depth_bits, ID));
368
369 if (ID == INVALID_ID) {
370 ErrorAlert(STR_NO_VIDEO_MODE_ERR);
371 return false;
372 }
373
374 // VideoMonitor.mode = mode;
375
376 D(bug("video_open/%ld: display_type=%ld\n", __LINE__, display_type));
377
378 // Open display
379 switch (display_type) {
380 case DISPLAY_WINDOW:
381 drv = new driver_window(*this, mode.x, mode.y);
382 break;
383
384 case DISPLAY_PIP:
385 drv = new driver_pip(*this, mode.x, mode.y);
386 break;
387
388 case DISPLAY_SCREEN_P96:
389 drv = new driver_screen_p96(*this, ID);
390 break;
391
392 case DISPLAY_SCREEN_CGFX:
393 drv = new driver_screen_cgfx(*this, ID);
394 break;
395 }
396
397 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 // Start periodic process
410 periodic_proc = CreateNewProcTags(
411 NP_Entry, (ULONG)periodic_func,
412 NP_Name, (ULONG)"Basilisk II IDCMP Handler",
413 NP_Priority, 0,
414 TAG_END
415 );
416
417 D(bug("video_open/%ld: periodic_proc=%08lx\n", __LINE__, periodic_proc));
418
419 if (periodic_proc == NULL) {
420 ErrorAlert(STR_NO_MEM_ERR);
421 return false;
422 }
423
424 return true;
425 }
426
427
428 void Amiga_monitor_desc::video_close()
429 {
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 delete drv;
438
439 // Free mouse pointer
440 if (null_pointer) {
441 FreeMem(null_pointer, 12);
442 null_pointer = NULL;
443 }
444 }
445
446
447 /*
448 * Deinitialization
449 */
450
451 void VideoExit(void)
452 {
453 // 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 }
458
459
460 /*
461 * Set palette
462 */
463
464 void Amiga_monitor_desc::set_palette(uint8 *pal, int num)
465 {
466 drv->set_palette(pal, num);
467 }
468
469
470 /*
471 * Switch video mode
472 */
473
474 void Amiga_monitor_desc::switch_to_current_mode()
475 {
476 // Close and reopen display
477 video_close();
478 if (!video_open()) {
479 ErrorAlert(STR_OPEN_WINDOW_ERR);
480 QuitEmulator();
481 }
482 }
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 {
491 }
492
493
494 /*
495 * 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 D(bug("periodic_func/%ld: \n", __LINE__));
515
516 // 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 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 }
524
525 D(bug("periodic_func/%ld: \n", __LINE__));
526
527 // Start 60Hz timer for window refresh
528 if (drv->monitor.display_type == DISPLAY_WINDOW) {
529 timer_port = CreateMsgPort();
530 if (timer_port) {
531 timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
532 if (timer_io) {
533 if (!OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
534 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 D(bug("periodic_func/%ld: \n", __LINE__));
545
546 // Main loop
547 for (;;) {
548 const video_mode &mode = drv->monitor.get_current_mode();
549
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 // D(bug("periodic_func/%ld: display_type=%ld the_win=%08lx\n", __LINE__, drv->monitor.display_type, drv->the_win));
557
558 if (sig & timer_mask) {
559 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
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 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 ADBMouseMoved(mx, my);
597 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 if (current_pointer) {
606 ClearPointer(drv->the_win);
607 current_pointer = NULL;
608 }
609 } else {
610 if (current_pointer != null_pointer) {
611 // Hide mouse pointer inside window
612 SetPointer(drv->the_win, null_pointer, 1, 16, 0, 0);
613 current_pointer = null_pointer;
614 }
615 }
616 break;
617 }
618 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 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
639 (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
640 SetInterruptFlag(INTFLAG_NMI);
641 TriggerInterrupt();
642 break;
643 }
644
645 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 D(bug("periodic_func/%ld: \n", __LINE__));
656
657 // 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 if (msg->IDCMPWindow == drv->the_win) {
674 Remove((struct Node *)msg);
675 ReplyMsg((struct Message *)msg);
676 }
677 msg = (struct IntuiMessage *)succ;
678 }
679 drv->the_win->UserPort = NULL;
680 ModifyIDCMP(drv->the_win, 0);
681 Permit();
682 DeleteMsgPort(win_port);
683
684 // Main task asked for termination, send signal
685 Forbid();
686 Signal(MainTask, SIGF_SINGLE);
687 }
688
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 // Add standard list of modes for given color depth
706 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 BIDTAG_DIPFMustNotHave, DIPF_IS_ECS | DIPF_IS_HAM | DIPF_IS_AA,
733 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 }
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 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 }
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 D(bug("check_modeid_p96: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
777
778 if (!p96GetModeIDAttr(mode_id, P96IDA_ISP96))
779 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 D(bug("check_modeid_cgfx: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
808
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 }
831
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