ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.21
Committed: 2001-10-16T17:27:52Z (22 years, 8 months ago) by jlachmann
Branch: MAIN
Changes since 1.20: +102 -51 lines
Log Message:
AmigaOS: Improved video mode switching - more strict error checking

File Contents

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