ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/video_amiga.cpp
Revision: 1.23
Committed: 2002-03-10T20:17:14Z (22 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.22: +26 -31 lines
Log Message:
minor cleanups

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 #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 D(bug("display_type %d, window_width %d, window_height %d\n", display_type, window_width, window_height));
368
369 // Construct list of supported modes
370 switch (display_type) {
371 case DISPLAY_WINDOW:
372 default_width = window_width;
373 default_height = window_height;
374 default_depth = 1;
375 add_modes(window_width, window_height, VDEPTH_1BIT);
376 break;
377
378 case DISPLAY_PIP:
379 default_depth = 16;
380 default_width = window_width;
381 default_height = window_height;
382 add_modes(window_width, window_height, VDEPTH_16BIT);
383 break;
384
385 case DISPLAY_SCREEN_P96:
386 case DISPLAY_SCREEN_CGFX:
387 struct DimensionInfo dimInfo;
388 DisplayInfoHandle handle = FindDisplayInfo(screen_mode_id);
389
390 if (handle == NULL)
391 return false;
392
393 if (GetDisplayInfoData(handle, (UBYTE *) &dimInfo, sizeof(dimInfo), DTAG_DIMS, 0) <= 0)
394 return false;
395
396 default_width = 1 + dimInfo.Nominal.MaxX - dimInfo.Nominal.MinX;
397 default_height = 1 + dimInfo.Nominal.MaxY - dimInfo.Nominal.MinY;
398 default_depth = dimInfo.MaxDepth;
399
400 for (unsigned d=VDEPTH_8BIT; d<=VDEPTH_32BIT; d++) {
401 ULONG mode_id = find_mode_for_depth(default_width, default_height, bits_from_depth(video_depth(d)));
402
403 if (is_valid_modeid(display_type, mode_id))
404 add_modes(default_width, default_height, video_depth(d));
405 }
406 break;
407 }
408
409 video_init_depth_list();
410
411 #if DEBUG
412 bug("Available video modes:\n");
413 vector<video_mode>::const_iterator i = VideoModes.begin(), end = VideoModes.end();
414 while (i != end) {
415 bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits_from_depth(i->depth));
416 ++i;
417 }
418 #endif
419
420 D(bug("VideoInit: def_width=%ld def_height=%ld def_depth=%ld\n", default_width, default_height, default_depth));
421
422 // Find requested default mode and open display
423 if (VideoModes.size() == 1)
424 return video_open(VideoModes[0]);
425 else {
426 // Find mode with specified dimensions
427 std::vector<video_mode>::const_iterator i, end = VideoModes.end();
428 for (i = VideoModes.begin(); i != end; ++i) {
429 D(bug("VideoInit: w=%ld h=%ld d=%ld\n", i->x, i->y, bits_from_depth(i->depth)));
430 if (i->x == default_width && i->y == default_height && bits_from_depth(i->depth) == default_depth)
431 return video_open(*i);
432 }
433 return video_open(VideoModes[0]);
434 }
435
436 return true;
437 }
438
439
440 static bool video_open(const video_mode &mode)
441 {
442 ULONG depth_bits = bits_from_depth(mode.depth);
443 ULONG ID = find_mode_for_depth(mode.x, mode.y, depth_bits);
444
445 D(bug("video_open: width=%ld height=%ld depth=%ld ID=%08lx\n", mode.x, mode.y, depth_bits, ID));
446
447 if (ID == INVALID_ID) {
448 ErrorAlert(STR_NO_VIDEO_MODE_ERR);
449 return false;
450 }
451
452 VideoMonitor.mode = mode;
453
454 // Open display
455 switch (display_type) {
456 case DISPLAY_WINDOW:
457 if (!init_window(mode.x, mode.y))
458 return false;
459 break;
460
461 case DISPLAY_PIP:
462 if (!init_pip(mode.x, mode.y))
463 return false;
464 break;
465
466 case DISPLAY_SCREEN_P96:
467 if (!init_screen_p96(ID))
468 return false;
469 break;
470
471 case DISPLAY_SCREEN_CGFX:
472 if (!init_screen_cgfx(ID))
473 return false;
474 break;
475 }
476
477 // Start periodic process
478 periodic_proc = CreateNewProcTags(
479 NP_Entry, (ULONG)periodic_func,
480 NP_Name, (ULONG)"Basilisk II IDCMP Handler",
481 NP_Priority, 0,
482 TAG_END
483 );
484 if (periodic_proc == NULL) {
485 ErrorAlert(STR_NO_MEM_ERR);
486 return false;
487 }
488
489 return true;
490 }
491
492
493 static void video_close()
494 {
495 // Stop periodic process
496 if (periodic_proc) {
497 SetSignal(0, SIGF_SINGLE);
498 Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C);
499 Wait(SIGF_SINGLE);
500 }
501
502 switch (display_type) {
503
504 case DISPLAY_WINDOW:
505
506 // Window mode, free bitmap
507 if (the_bitmap) {
508 WaitBlit();
509 FreeBitMap(the_bitmap);
510 }
511
512 // Free pens and close window
513 if (the_win) {
514 ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen);
515 ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen);
516
517 CloseWindow(the_win);
518 the_win = NULL;
519 }
520 break;
521
522 case DISPLAY_PIP:
523
524 // Close PIP
525 if (the_win)
526 p96PIP_Close(the_win);
527 break;
528
529 case DISPLAY_SCREEN_P96:
530
531 // Close window
532 if (the_win)
533 {
534 CloseWindow(the_win);
535 the_win = NULL;
536 }
537
538 // Close screen
539 if (the_screen) {
540 p96CloseScreen(the_screen);
541 the_screen = NULL;
542 }
543 break;
544
545 case DISPLAY_SCREEN_CGFX:
546
547 // Close window
548 if (the_win)
549 {
550 CloseWindow(the_win);
551 the_win = NULL;
552 }
553
554 // Close screen
555 if (the_screen) {
556 CloseScreen(the_screen);
557 the_screen = NULL;
558 }
559 break;
560 }
561
562 // Free mouse pointer
563 if (null_pointer) {
564 FreeMem(null_pointer, 12);
565 null_pointer = NULL;
566 }
567 }
568
569
570 /*
571 * Deinitialization
572 */
573
574 void VideoExit(void)
575 {
576 video_close();
577 }
578
579
580 /*
581 * Set palette
582 */
583
584 void video_set_palette(uint8 *pal, int num)
585 {
586 if ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
587 && !IsDirectMode(VideoMonitor.mode)) {
588
589 // Convert palette to 32 bits
590 ULONG table[2 + 256 * 3];
591 table[0] = num << 16;
592 table[num * 3 + 1] = 0;
593 for (int i=0; i<num; i++) {
594 table[i*3+1] = pal[i*3] * 0x01010101;
595 table[i*3+2] = pal[i*3+1] * 0x01010101;
596 table[i*3+3] = pal[i*3+2] * 0x01010101;
597 }
598
599 // And load it
600 LoadRGB32(&the_screen->ViewPort, table);
601 }
602 }
603
604
605 /*
606 * Switch video mode
607 */
608
609 void video_switch_to_mode(const video_mode &mode)
610 {
611 // Close and reopen display
612 video_close();
613 if (!video_open(mode)) {
614 ErrorAlert(STR_OPEN_WINDOW_ERR);
615 QuitEmulator();
616 }
617 }
618
619
620 /*
621 * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode)
622 */
623
624 void VideoQuitFullScreen(void)
625 {
626 }
627
628
629 /*
630 * Video message handling (not neccessary under AmigaOS, handled by periodic_func())
631 */
632
633 void VideoInterrupt(void)
634 {
635 }
636
637
638 /*
639 * Process for window refresh and message handling
640 */
641
642 static __saveds void periodic_func(void)
643 {
644 struct MsgPort *timer_port = NULL;
645 struct timerequest *timer_io = NULL;
646 struct IntuiMessage *msg;
647 ULONG win_mask = 0, timer_mask = 0;
648
649 // Create message port for window and attach it
650 struct MsgPort *win_port = CreateMsgPort();
651 if (win_port) {
652 win_mask = 1 << win_port->mp_SigBit;
653 the_win->UserPort = win_port;
654 ModifyIDCMP(the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
655 }
656
657 // Start 60Hz timer for window refresh
658 if (display_type == DISPLAY_WINDOW) {
659 timer_port = CreateMsgPort();
660 if (timer_port) {
661 timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest));
662 if (timer_io) {
663 if (!OpenDevice((UBYTE *)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) {
664 timer_mask = 1 << timer_port->mp_SigBit;
665 timer_io->tr_node.io_Command = TR_ADDREQUEST;
666 timer_io->tr_time.tv_secs = 0;
667 timer_io->tr_time.tv_micro = 16667 * frame_skip;
668 SendIO((struct IORequest *)timer_io);
669 }
670 }
671 }
672 }
673
674 // Main loop
675 for (;;) {
676
677 // Wait for timer and/or window (CTRL_C is used for quitting the task)
678 ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C);
679
680 if (sig & SIGBREAKF_CTRL_C)
681 break;
682
683 if (sig & timer_mask) {
684
685 // Timer tick, update display
686 BltTemplate(the_bitmap->Planes[0], 0, the_bitmap->BytesPerRow, the_win->RPort,
687 the_win->BorderLeft, the_win->BorderTop, VideoMonitor.mode.x, VideoMonitor.mode.y);
688
689 // Restart timer
690 timer_io->tr_node.io_Command = TR_ADDREQUEST;
691 timer_io->tr_time.tv_secs = 0;
692 timer_io->tr_time.tv_micro = 16667 * frame_skip;
693 SendIO((struct IORequest *)timer_io);
694 }
695
696 if (sig & win_mask) {
697
698 // Handle window messages
699 while (msg = (struct IntuiMessage *)GetMsg(win_port)) {
700
701 // Get data from message and reply
702 ULONG cl = msg->Class;
703 UWORD code = msg->Code;
704 UWORD qualifier = msg->Qualifier;
705 WORD mx = msg->MouseX;
706 WORD my = msg->MouseY;
707 ReplyMsg((struct Message *)msg);
708
709 // Handle message according to class
710 switch (cl) {
711 case IDCMP_MOUSEMOVE:
712 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
713 ADBMouseMoved(mx, my);
714 else {
715 ADBMouseMoved(mx - the_win->BorderLeft, my - the_win->BorderTop);
716 if (mx < the_win->BorderLeft
717 || my < the_win->BorderTop
718 || mx >= the_win->BorderLeft + VideoMonitor.mode.x
719 || my >= the_win->BorderTop + VideoMonitor.mode.y) {
720 if (current_pointer) {
721 ClearPointer(the_win);
722 current_pointer = NULL;
723 }
724 } else {
725 if (current_pointer != null_pointer) {
726 // Hide mouse pointer inside window
727 SetPointer(the_win, null_pointer, 1, 16, 0, 0);
728 current_pointer = null_pointer;
729 }
730 }
731 }
732 break;
733
734 case IDCMP_MOUSEBUTTONS:
735 if (code == SELECTDOWN)
736 ADBMouseDown(0);
737 else if (code == SELECTUP)
738 ADBMouseUp(0);
739 else if (code == MENUDOWN)
740 ADBMouseDown(1);
741 else if (code == MENUUP)
742 ADBMouseUp(1);
743 else if (code == MIDDLEDOWN)
744 ADBMouseDown(2);
745 else if (code == MIDDLEUP)
746 ADBMouseUp(2);
747 break;
748
749 case IDCMP_RAWKEY:
750 if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS
751 break;
752 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
753 (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
754 SetInterruptFlag(INTFLAG_NMI);
755 TriggerInterrupt();
756 break;
757 }
758
759 if (code & IECODE_UP_PREFIX)
760 ADBKeyUp(keycode2mac[code & 0x7f]);
761 else
762 ADBKeyDown(keycode2mac[code & 0x7f]);
763 break;
764 }
765 }
766 }
767 }
768
769 // Stop timer
770 if (timer_io) {
771 if (!CheckIO((struct IORequest *)timer_io))
772 AbortIO((struct IORequest *)timer_io);
773 WaitIO((struct IORequest *)timer_io);
774 CloseDevice((struct IORequest *)timer_io);
775 DeleteIORequest(timer_io);
776 }
777 if (timer_port)
778 DeleteMsgPort(timer_port);
779
780 // Remove port from window and delete it
781 Forbid();
782 msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head;
783 struct Node *succ;
784 while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
785 if (msg->IDCMPWindow == the_win) {
786 Remove((struct Node *)msg);
787 ReplyMsg((struct Message *)msg);
788 }
789 msg = (struct IntuiMessage *)succ;
790 }
791 the_win->UserPort = NULL;
792 ModifyIDCMP(the_win, 0);
793 Permit();
794 DeleteMsgPort(win_port);
795
796 // Main task asked for termination, send signal
797 Forbid();
798 Signal(MainTask, SIGF_SINGLE);
799 }
800
801
802 // Add mode to list of supported modes
803 static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth)
804 {
805 video_mode mode;
806 mode.x = width;
807 mode.y = height;
808 mode.resolution_id = resolution_id;
809 mode.bytes_per_row = bytes_per_row;
810 mode.depth = depth;
811
812 D(bug("Added video mode: w=%ld h=%ld d=%ld\n", width, height, depth));
813
814 VideoModes.push_back(mode);
815 }
816
817 // Add standard list of modes for given color depth
818 static void add_modes(uint32 width, uint32 height, video_depth depth)
819 {
820 D(bug("add_modes: w=%ld h=%ld d=%ld\n", width, height, depth));
821
822 if (width >= 512 && height >= 384)
823 add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth);
824 if (width >= 640 && height >= 480)
825 add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth);
826 if (width >= 800 && height >= 600)
827 add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth);
828 if (width >= 1024 && height >= 768)
829 add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth);
830 if (width >= 1152 && height >= 870)
831 add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth);
832 if (width >= 1280 && height >= 1024)
833 add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth);
834 if (width >= 1600 && height >= 1200)
835 add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth);
836 }
837
838
839 static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth)
840 {
841 ULONG ID = BestModeID(BIDTAG_NominalWidth, width,
842 BIDTAG_NominalHeight, height,
843 BIDTAG_Depth, depth,
844 BIDTAG_DIPFMustNotHave, DIPF_IS_ECS | DIPF_IS_HAM | DIPF_IS_AA,
845 TAG_END);
846
847 return ID;
848 }
849
850
851 static ULONG bits_from_depth(video_depth depth)
852 {
853 int bits = 1 << depth;
854 if (bits == 16)
855 bits = 15;
856 else if (bits == 32)
857 bits = 24;
858
859 return bits;
860 }
861
862
863 static bool is_valid_modeid(int display_type, ULONG mode_id)
864 {
865 if (INVALID_ID == mode_id)
866 return false;
867
868 switch (display_type) {
869 case DISPLAY_SCREEN_P96:
870 return check_modeid_p96(mode_id);
871 break;
872 case DISPLAY_SCREEN_CGFX:
873 return check_modeid_cgfx(mode_id);
874 break;
875 default:
876 return false;
877 break;
878 }
879 }
880
881
882 static bool check_modeid_p96(ULONG mode_id)
883 {
884 // Check if the mode is one we can handle
885 uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH);
886 uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT);
887
888 D(bug("check_modeid_p96: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
889
890 if (!p96GetModeIDAttr(screen_mode_id, P96IDA_ISP96))
891 return false;
892
893 switch (depth) {
894 case 8:
895 break;
896 case 15:
897 case 16:
898 if (format != RGBFB_R5G5B5)
899 return false;
900 break;
901 case 24:
902 case 32:
903 if (format != RGBFB_A8R8G8B8)
904 return false;
905 break;
906 default:
907 return false;
908 }
909
910 return true;
911 }
912
913
914 static bool check_modeid_cgfx(ULONG mode_id)
915 {
916 uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
917 uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
918
919 D(bug("check_modeid_cgfx: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format));
920
921 if (!IsCyberModeID(mode_id))
922 return false;
923
924 switch (depth) {
925 case 8:
926 break;
927 case 15:
928 case 16:
929 if (format != PIXFMT_RGB15)
930 return false;
931 break;
932 case 24:
933 case 32:
934 if (format != PIXFMT_ARGB32)
935 return false;
936 break;
937 default:
938 return false;
939 }
940
941 return true;
942 }