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

# User Rev Content
1 cebix 1.1 /*
2     * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff
3     *
4 cebix 1.12 * Basilisk II (C) 1997-2001 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <exec/types.h>
22     #include <intuition/intuition.h>
23     #include <graphics/rastport.h>
24     #include <graphics/gfx.h>
25 cebix 1.7 #include <cybergraphics/cybergraphics.h>
26 cebix 1.1 #include <dos/dostags.h>
27     #include <devices/timer.h>
28     #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 cebix 1.4 #include <proto/cybergraphics.h>
34 cebix 1.1
35     #include "sysdeps.h"
36 jlachmann 1.9 #include "cpu_emulation.h"
37 cebix 1.1 #include "main.h"
38     #include "adb.h"
39     #include "prefs.h"
40     #include "user_strings.h"
41     #include "video.h"
42    
43 cebix 1.4 #define DEBUG 0
44 cebix 1.1 #include "debug.h"
45    
46    
47     // Display types
48     enum {
49     DISPLAY_WINDOW,
50     DISPLAY_PIP,
51 cebix 1.6 DISPLAY_SCREEN_P96,
52     DISPLAY_SCREEN_CGFX
53 cebix 1.1 };
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 cebix 1.8 static UWORD *null_pointer = NULL; // Blank mouse pointer data
62     static UWORD *current_pointer = (UWORD *)-1; // Currently visible mouse pointer data
63 cebix 1.1 static LONG black_pen = -1, white_pen = -1;
64     static struct Process *periodic_proc = NULL; // Periodic process
65 jlachmann 1.20 static int window_width, window_height; // width and height for window display
66     static ULONG screen_mode_id; // mode ID for screen display
67 cebix 1.1
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 jlachmann 1.20 static bool video_open(const video_mode &mode);
94     static void video_close();
95 cebix 1.1 static void periodic_func(void);
96 jlachmann 1.20 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 cebix 1.1
101    
102     /*
103     * Initialization
104     */
105    
106 cebix 1.13
107 cebix 1.1 // 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 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
126 cebix 1.1 TAG_END
127     );
128     if (the_win == NULL) {
129 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
130 cebix 1.1 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 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
137 cebix 1.1 return false;
138     }
139    
140 cebix 1.13 // Add resolution and set VideoMonitor
141 cebix 1.1 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 cebix 1.2 P96PIP_ErrorCode, (ULONG)&error,
165 cebix 1.1 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 cebix 1.2 WA_Title, (ULONG)GetString(STR_WINDOW_TITLE),
176     WA_PubScreenName, (ULONG)"Workbench",
177 cebix 1.1 TAG_END
178     );
179     if (the_win == NULL || error) {
180 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
181 cebix 1.1 return false;
182     }
183    
184     // Find bitmap
185 cebix 1.2 p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END);
186 cebix 1.1
187 cebix 1.13 // Add resolution and set VideoMonitor
188 cebix 1.15 VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY);
189 jlachmann 1.20
190 cebix 1.1 return true;
191     }
192    
193 cebix 1.6 // Open Picasso96 screen
194     static bool init_screen_p96(ULONG mode_id)
195 cebix 1.1 {
196     // Set relative mouse mode
197     ADBSetRelMouseMode(true);
198    
199 cebix 1.6 // 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 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
210 cebix 1.6 return false;
211     }
212     break;
213     case 24:
214     case 32:
215     if (format != RGBFB_A8R8G8B8) {
216 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
217 cebix 1.6 return false;
218     }
219     break;
220     default:
221 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
222 cebix 1.6 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 cebix 1.16 ErrorAlert(STR_OPEN_SCREEN_ERR);
241 cebix 1.1 return false;
242     }
243    
244 cebix 1.6 // Open window
245     the_win = OpenWindowTags(NULL,
246     WA_Left, 0, WA_Top, 0,
247     WA_Width, width, WA_Height, height,
248 jlachmann 1.20 WA_SimpleRefresh, TRUE,
249 cebix 1.6 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 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
259 cebix 1.6 return false;
260     }
261    
262     ScreenToFront(the_screen);
263 cebix 1.13
264     // Add resolution and set VideoMonitor
265 cebix 1.6 VideoMonitor.mac_frame_base = p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY);
266 jlachmann 1.20
267 cebix 1.6 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 cebix 1.4
276 cebix 1.1 // Check if the mode is one we can handle
277 cebix 1.6 uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id);
278     uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id);
279 cebix 1.4
280 cebix 1.1 switch (depth) {
281     case 8:
282     break;
283     case 15:
284     case 16:
285 jlachmann 1.9 // !!! PIXFMT_RGB15 is correct !!!
286     if (format != PIXFMT_RGB15) {
287 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
288 cebix 1.1 return false;
289     }
290     break;
291     case 24:
292     case 32:
293 cebix 1.6 if (format != PIXFMT_ARGB32) {
294 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR);
295 cebix 1.1 return false;
296     }
297     break;
298     default:
299 cebix 1.16 ErrorAlert(STR_WRONG_SCREEN_DEPTH_ERR);
300 cebix 1.1 return false;
301     }
302    
303     // Yes, get width and height
304 cebix 1.6 uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id);
305     uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id);
306 cebix 1.4
307 cebix 1.1 // Open screen
308 cebix 1.6 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 cebix 1.1 if (the_screen == NULL) {
316 cebix 1.16 ErrorAlert(STR_OPEN_SCREEN_ERR);
317 cebix 1.1 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 jlachmann 1.20 WA_SimpleRefresh, TRUE,
325 cebix 1.1 WA_NoCareRefresh, TRUE,
326     WA_Borderless, TRUE,
327     WA_Activate, TRUE,
328     WA_RMBTrap, TRUE,
329     WA_ReportMouse, TRUE,
330 cebix 1.2 WA_CustomScreen, (ULONG)the_screen,
331 cebix 1.1 TAG_END
332     );
333     if (the_win == NULL) {
334 cebix 1.16 ErrorAlert(STR_OPEN_WINDOW_ERR);
335 cebix 1.1 return false;
336     }
337    
338     ScreenToFront(the_screen);
339 cebix 1.6 static UWORD ptr[] = { 0, 0, 0, 0 };
340     SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer
341 cebix 1.13
342     // Set VideoMonitor
343     ULONG frame_base;
344 cebix 1.6 APTR handle = LockBitMapTags(the_screen->RastPort.BitMap,
345 cebix 1.13 LBMI_BASEADDRESS, (ULONG)&frame_base,
346     TAG_END
347     );
348 cebix 1.6 UnLockBitMap(handle);
349 jlachmann 1.20
350 cebix 1.13 VideoMonitor.mac_frame_base = frame_base;
351 jlachmann 1.20
352 cebix 1.1 return true;
353     }
354    
355     bool VideoInit(bool classic)
356     {
357 jlachmann 1.20 int default_width, default_height, default_depth;
358    
359 cebix 1.8 // Allocate blank mouse pointer data
360     null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR);
361     if (null_pointer == NULL) {
362 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
363 cebix 1.8 return false;
364     }
365    
366 cebix 1.1 // 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 jlachmann 1.20
381     default_width = window_width = 512;
382     default_height = window_height = 384;
383    
384 cebix 1.1 if (mode_str) {
385 jlachmann 1.20 if (sscanf(mode_str, "win/%d/%d", &window_width, &window_height) == 2)
386 cebix 1.1 display_type = DISPLAY_WINDOW;
387 jlachmann 1.20 else if (sscanf(mode_str, "pip/%d/%d", &window_width, &window_height) == 2 && P96Base)
388 cebix 1.1 display_type = DISPLAY_PIP;
389 jlachmann 1.20 else if (sscanf(mode_str, "scr/%08lx", &screen_mode_id) == 1 && (CyberGfxBase || P96Base)) {
390     if (P96Base && p96GetModeIDAttr(screen_mode_id, P96IDA_ISP96))
391 cebix 1.6 display_type = DISPLAY_SCREEN_P96;
392 jlachmann 1.20 else if (CyberGfxBase && IsCyberModeID(screen_mode_id))
393 cebix 1.6 display_type = DISPLAY_SCREEN_CGFX;
394     else {
395 cebix 1.16 ErrorAlert(STR_NO_P96_MODE_ERR);
396 cebix 1.6 return false;
397     }
398     }
399 cebix 1.1 }
400    
401 jlachmann 1.20 // 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 cebix 1.1 // Open display
490     switch (display_type) {
491     case DISPLAY_WINDOW:
492 jlachmann 1.20 if (!init_window(mode.x, mode.y))
493 cebix 1.1 return false;
494     break;
495    
496     case DISPLAY_PIP:
497 jlachmann 1.20 if (!init_pip(mode.x, mode.y))
498 cebix 1.1 return false;
499     break;
500    
501 cebix 1.6 case DISPLAY_SCREEN_P96:
502 jlachmann 1.20 if (!init_screen_p96(ID))
503 cebix 1.6 return false;
504     break;
505    
506     case DISPLAY_SCREEN_CGFX:
507 jlachmann 1.20 if (!init_screen_cgfx(ID))
508 cebix 1.1 return false;
509     break;
510     }
511    
512     // Start periodic process
513     periodic_proc = CreateNewProcTags(
514 cebix 1.2 NP_Entry, (ULONG)periodic_func,
515     NP_Name, (ULONG)"Basilisk II IDCMP Handler",
516 cebix 1.1 NP_Priority, 0,
517     TAG_END
518     );
519     if (periodic_proc == NULL) {
520 cebix 1.16 ErrorAlert(STR_NO_MEM_ERR);
521 cebix 1.1 return false;
522     }
523 jlachmann 1.20
524 cebix 1.1 return true;
525     }
526    
527    
528 jlachmann 1.20 static void video_close()
529 cebix 1.1 {
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 jlachmann 1.20 the_win = NULL;
554 cebix 1.1 }
555     break;
556    
557     case DISPLAY_PIP:
558    
559     // Close PIP
560     if (the_win)
561     p96PIP_Close(the_win);
562     break;
563    
564 cebix 1.6 case DISPLAY_SCREEN_P96:
565 cebix 1.1
566     // Close window
567     if (the_win)
568 jlachmann 1.20 {
569 cebix 1.1 CloseWindow(the_win);
570 jlachmann 1.20 the_win = NULL;
571     }
572 cebix 1.1
573     // Close screen
574 cebix 1.4 if (the_screen) {
575 cebix 1.6 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 jlachmann 1.20 {
585 cebix 1.6 CloseWindow(the_win);
586 jlachmann 1.20 the_win = NULL;
587     }
588 cebix 1.4
589 cebix 1.6 // Close screen
590     if (the_screen) {
591     CloseScreen(the_screen);
592 cebix 1.4 the_screen = NULL;
593     }
594 cebix 1.1 break;
595     }
596 cebix 1.8
597     // Free mouse pointer
598     if (null_pointer) {
599     FreeMem(null_pointer, 12);
600     null_pointer = NULL;
601     }
602 cebix 1.1 }
603    
604    
605     /*
606 jlachmann 1.20 * Deinitialization
607     */
608    
609     void VideoExit(void)
610     {
611     video_close();
612     }
613    
614    
615     /*
616 cebix 1.1 * Set palette
617     */
618    
619 cebix 1.19 void video_set_palette(uint8 *pal, int num)
620 cebix 1.1 {
621 cebix 1.15 if ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
622     && !IsDirectMode(VideoMonitor.mode)) {
623 cebix 1.1
624     // Convert palette to 32 bits
625     ULONG table[2 + 256 * 3];
626 cebix 1.17 table[0] = num << 16;
627     table[num * 3 + 1] = 0;
628     for (int i=0; i<num; i++) {
629 cebix 1.1 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 cebix 1.14 * Switch video mode
642     */
643    
644     void video_switch_to_mode(const video_mode &mode)
645 cebix 1.19 {
646 jlachmann 1.20 // Close and reopen display
647     video_close();
648     if (!video_open(mode))
649     {
650     ErrorAlert(STR_OPEN_WINDOW_ERR);
651     QuitEmulator();
652     }
653 cebix 1.19 }
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 cebix 1.14 {
662     }
663    
664    
665     /*
666 cebix 1.1 * 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 cebix 1.6 ModifyIDCMP(the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | ((display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0));
691 cebix 1.1 }
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 cebix 1.13 the_win->BorderLeft, the_win->BorderTop, VideoMonitor.mode.x, VideoMonitor.mode.y);
724 cebix 1.1
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 cebix 1.7 if (display_type == DISPLAY_SCREEN_P96 || display_type == DISPLAY_SCREEN_CGFX)
749 cebix 1.1 ADBMouseMoved(mx, my);
750 cebix 1.8 else {
751 cebix 1.1 ADBMouseMoved(mx - the_win->BorderLeft, my - the_win->BorderTop);
752 cebix 1.8 if (mx < the_win->BorderLeft
753     || my < the_win->BorderTop
754 cebix 1.13 || mx >= the_win->BorderLeft + VideoMonitor.mode.x
755     || my >= the_win->BorderTop + VideoMonitor.mode.y) {
756 cebix 1.8 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 cebix 1.1 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 cebix 1.11 if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) ==
789     (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) {
790 jlachmann 1.9 SetInterruptFlag(INTFLAG_NMI);
791     TriggerInterrupt();
792     break;
793 cebix 1.10 }
794 jlachmann 1.9
795 cebix 1.1 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 jlachmann 1.20
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