ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.20
Committed: 2001-10-14T18:00:44Z (22 years, 8 months ago) by jlachmann
Branch: MAIN
Changes since 1.19: +204 -57 lines
Log Message:
AmigaOS: added Video depth/resolution switching

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