~ubuntu-branches/ubuntu/lucid/basilisk2/lucid

« back to all changes in this revision

Viewing changes to src/MacOSX/video_macosx.mm

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2003-07-24 00:48:57 UTC
  • Revision ID: james.westby@ubuntu.com-20030724004857-vnv33v6vf7a7u0z6
Tags: upstream-0.9.20030722
ImportĀ upstreamĀ versionĀ 0.9.20030722

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  $Id: video_macosx.mm,v 1.10 2003/03/26 23:08:20 nigel Exp $
 
3
 *
 
4
 *  video_macosx.mm - Interface between Basilisk II and Cocoa windowing.
 
5
 *                    Based on video_amiga.cpp and video_x.cpp
 
6
 *
 
7
 *  Basilisk II (C) 1997-2003 Christian Bauer
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  (at your option) any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program; if not, write to the Free Software
 
21
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
22
 */
 
23
 
 
24
 
 
25
#include "sysdeps.h"
 
26
 
 
27
#ifdef HAVE_PTHREADS
 
28
# include <pthread.h>
 
29
#endif
 
30
 
 
31
#include <adb.h>
 
32
#include <cpu_emulation.h>
 
33
#include <main.h>
 
34
#include "macos_util_macosx.h"
 
35
#include <prefs.h>
 
36
#include <user_strings.h>
 
37
#include "video_macosx.h"
 
38
 
 
39
#define DEBUG 0
 
40
#define VERBOSE 0
 
41
#include "debug.h"
 
42
 
 
43
#ifdef NSBITMAP
 
44
#import <AppKit/NSBitmapImageRep.h>
 
45
#endif
 
46
 
 
47
#import <Foundation/NSString.h>                         // Needed for NSLog(@"")
 
48
#import "misc_macosx.h"                                         // WarningSheet() prototype
 
49
 
 
50
 
 
51
 
 
52
// Global variables
 
53
uint8           display_type = DISPLAY_WINDOW,  // These are used by PrefsEditor
 
54
                        frame_skip;     
 
55
uint16          init_width  = MIN_WIDTH,                // as well as this code
 
56
                        init_height = MIN_HEIGHT,
 
57
                        init_depth  = 32;
 
58
 
 
59
                EmulatorView    *output = nil;          // Set by [EmulatorView init]
 
60
                NSWindow                *the_win = nil;         // Set by [Emulator awakeFromNib]
 
61
 
 
62
static  BOOL                    singleDisplay = YES;
 
63
 
 
64
/*
 
65
 *  Utility functions
 
66
 */
 
67
 
 
68
static uint8
 
69
bits_from_depth(const video_depth depth)
 
70
{
 
71
        int bits = 1 << depth;
 
72
//      if (bits == 16)
 
73
//              bits = 15;
 
74
//      else if (bits == 32)
 
75
//              bits = 24;
 
76
        return bits;
 
77
}
 
78
 
 
79
static char *
 
80
colours_from_depth(const video_depth depth)
 
81
{
 
82
        switch ( depth )
 
83
        {
 
84
                case VDEPTH_1BIT : return "Monochrome";
 
85
                case VDEPTH_2BIT : return "4 colours";
 
86
                case VDEPTH_4BIT : return "16 colours";
 
87
                case VDEPTH_8BIT : return "256 colours";
 
88
                case VDEPTH_16BIT: return "Thousands of colours";
 
89
                case VDEPTH_32BIT: return "Millions of colours";
 
90
        }
 
91
 
 
92
        return "illegal colour depth";
 
93
}
 
94
 
 
95
static char *
 
96
colours_from_depth(const uint16 depth)
 
97
{
 
98
        return colours_from_depth(DepthModeForPixelDepth(depth) );
 
99
}
 
100
 
 
101
bool
 
102
parse_screen_prefs(const char *mode_str)
 
103
{
 
104
        if (sscanf(mode_str, "win/%hd/%hd/%hd",
 
105
                                &init_width, &init_height, &init_depth) == 3)
 
106
                display_type = DISPLAY_WINDOW;
 
107
        else if (sscanf(mode_str, "win/%hd/%hd", &init_width, &init_height) == 2)
 
108
                display_type  = DISPLAY_WINDOW;
 
109
        else if (strcmp(mode_str, "full") == 0)
 
110
                display_type = DISPLAY_SCREEN;
 
111
        else if (sscanf(mode_str, "full/%hd/%hd/%hd",
 
112
                                        &init_width, &init_height, &init_depth) == 3)
 
113
                display_type = DISPLAY_SCREEN;
 
114
        else if (sscanf(mode_str, "full/%hd/%hd", &init_width, &init_height) == 2)
 
115
                display_type = DISPLAY_SCREEN;
 
116
        else if (sscanf(mode_str, "opengl/%hd/%hd/%hd",
 
117
                                        &init_width, &init_height, &init_depth) == 3)
 
118
                display_type = DISPLAY_OPENGL;
 
119
        else if (sscanf(mode_str, "opengl/%hd/%hd", &init_width, &init_height) == 2)
 
120
                display_type = DISPLAY_OPENGL;
 
121
        else return false;
 
122
 
 
123
        return true;
 
124
}
 
125
 
 
126
// Supported video modes
 
127
static vector<video_mode> VideoModes;
 
128
 
 
129
 
 
130
// Add mode to list of supported modes
 
131
static void
 
132
add_mode(const uint16 width, const uint16 height,
 
133
                 const uint32 resolution_id, const uint32 bytes_per_row,
 
134
                 const uint32 user_data,
 
135
                 const video_depth depth)
 
136
{
 
137
        vector<video_mode>::const_iterator      i,
 
138
                                                                                end = VideoModes.end();
 
139
 
 
140
        for (i = VideoModes.begin(); i != end; ++i)
 
141
                if ( i->x == width && i->y == height &&
 
142
                         i->bytes_per_row == bytes_per_row && i->depth == depth )
 
143
                {
 
144
                        D(NSLog(@"Duplicate mode (%hdx%hdx%ld, ID %02x, new ID %02x)\n",
 
145
                                                width, height, depth, i->resolution_id, resolution_id));
 
146
                        return;
 
147
                }
 
148
 
 
149
        video_mode mode;
 
150
 
 
151
        mode.x = width;
 
152
        mode.y = height;
 
153
        mode.resolution_id = resolution_id;
 
154
        mode.bytes_per_row = bytes_per_row;
 
155
        mode.user_data = user_data;
 
156
        mode.depth = depth;
 
157
 
 
158
        D(bug("Added video mode: w=%d  h=%d  d=%d(%d bits)\n",
 
159
                                width, height, depth, bits_from_depth(depth) ));
 
160
 
 
161
        VideoModes.push_back(mode);
 
162
}
 
163
 
 
164
// Add standard list of windowed modes for given color depth
 
165
static void add_standard_modes(const video_depth depth)
 
166
{
 
167
        D(bug("add_standard_modes: depth=%d(%d bits)\n",
 
168
                                                depth, bits_from_depth(depth) ));
 
169
 
 
170
        add_mode(512,  384,  0x80, TrivialBytesPerRow(512,  depth), 0, depth);
 
171
        add_mode(640,  480,  0x81, TrivialBytesPerRow(640,  depth), 0, depth);
 
172
        add_mode(800,  600,  0x82, TrivialBytesPerRow(800,  depth), 0, depth);
 
173
        add_mode(832,  624,  0x83, TrivialBytesPerRow(832,  depth), 0, depth);
 
174
        add_mode(1024, 768,  0x84, TrivialBytesPerRow(1024, depth), 0, depth);
 
175
        add_mode(1152, 768,  0x85, TrivialBytesPerRow(1152, depth), 0, depth);
 
176
        add_mode(1152, 870,  0x86, TrivialBytesPerRow(1152, depth), 0, depth);
 
177
        add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), 0, depth);
 
178
        add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), 0, depth);
 
179
}
 
180
 
 
181
// Helper function to get a 32bit int from a dictionary
 
182
static int32 getCFint32 (CFDictionaryRef dict, CFStringRef key)
 
183
{
 
184
        CFNumberRef     ref = (CFNumberRef) CFDictionaryGetValue(dict, key);
 
185
 
 
186
        if ( ref )
 
187
        {
 
188
                int32   val;
 
189
 
 
190
                if ( CFNumberGetValue(ref, kCFNumberSInt32Type, &val) )
 
191
                        return val;
 
192
                else
 
193
                        NSLog(@"getCFint32() - Failed to get the value %@", key);
 
194
        }
 
195
        else
 
196
                NSLog(@"getCFint32() - Failed to get a 32bit int for %@", key);
 
197
 
 
198
        return 0;
 
199
}
 
200
 
 
201
// Nasty hack. Under 10.1, CGDisplayAvailableModes() does not provide bytes per row,
 
202
// and the emulator doesn't like setting the bytes per row after the screen,
 
203
// so we use a lot of magic numbers here.
 
204
// This will probably fail on some video hardware.
 
205
// I have tested on my G4 PowerBook 400 and G3 PowerBook Series 292
 
206
 
 
207
static int
 
208
CGBytesPerRow(const uint16 width, const video_depth depth)
 
209
{
 
210
        if ( depth == VDEPTH_8BIT )
 
211
                switch ( width )
 
212
                {
 
213
                        case 640:
 
214
                        case 720:       return 768;
 
215
                        case 800:
 
216
                        case 896:       return 1024;
 
217
                        case 1152:      return 1280;
 
218
                }
 
219
 
 
220
        if ( width == 720  && depth == VDEPTH_16BIT)    return 1536;
 
221
        if ( width == 720  && depth == VDEPTH_32BIT)    return 3072;
 
222
        if ( width == 800  && depth == VDEPTH_16BIT)    return 1792;
 
223
        if ( width == 800  && depth == VDEPTH_32BIT)    return 3328;
 
224
 
 
225
        return TrivialBytesPerRow(width, depth);
 
226
}
 
227
 
 
228
static bool add_CGDirectDisplay_modes()
 
229
{
 
230
#define kMaxDisplays 8
 
231
        CGDirectDisplayID       displays[kMaxDisplays];
 
232
        CGDisplayErr            err;
 
233
        CGDisplayCount          n;
 
234
        int32                           oldRes = 0,
 
235
                                                res_id = 0x80;
 
236
 
 
237
 
 
238
        err = CGGetActiveDisplayList(kMaxDisplays, displays, &n);
 
239
        if ( err != CGDisplayNoErr )
 
240
                n = 1, displays[n] = kCGDirectMainDisplay;
 
241
 
 
242
        if ( n > 1 )
 
243
                singleDisplay = NO;
 
244
 
 
245
        for ( CGDisplayCount dc = 0; dc < n; ++dc )
 
246
        {
 
247
                CGDirectDisplayID       d = displays[dc];
 
248
                CFArrayRef                      m = CGDisplayAvailableModes(d);
 
249
 
 
250
                if ( ! m )                                      // Store the current display mode
 
251
                        add_mode(CGDisplayPixelsWide(d),
 
252
                                         CGDisplayPixelsHigh(d),
 
253
                                         res_id++, CGDisplayBytesPerRow(d),
 
254
                                         (const uint32) d,
 
255
                                         DepthModeForPixelDepth(CGDisplayBitsPerPixel(d)));
 
256
                else
 
257
                {
 
258
                        CFIndex  nModes = CFArrayGetCount(m);
 
259
 
 
260
                        for ( CFIndex mc = 0; mc < nModes; ++mc )
 
261
                        {
 
262
                                CFDictionaryRef modeSpec = (CFDictionaryRef)
 
263
                                                                                        CFArrayGetValueAtIndex(m, mc);
 
264
 
 
265
                                int32   bpp    = getCFint32(modeSpec, kCGDisplayBitsPerPixel);
 
266
                                int32   height = getCFint32(modeSpec, kCGDisplayHeight);
 
267
                                int32   width  = getCFint32(modeSpec, kCGDisplayWidth);
 
268
#ifdef MAC_OS_X_VERSION_10_2
 
269
                                int32   bytes  = getCFint32(modeSpec, kCGDisplayBytesPerRow);
 
270
#else
 
271
                                int32   bytes  = 0;
 
272
#endif
 
273
                                video_depth     depth = DepthModeForPixelDepth(bpp);
 
274
 
 
275
                                if ( ! bpp || ! height || ! width )
 
276
                                {
 
277
                                        NSLog(@"Could not get details of mode %d, display %d",
 
278
                                                        mc, dc);
 
279
                                        return false;
 
280
                                }
 
281
#if VERBOSE
 
282
                                else
 
283
                                        NSLog(@"Display %ld, spec = %@", d, modeSpec);
 
284
#endif
 
285
 
 
286
                                if ( ! bytes )
 
287
                                {
 
288
                                        NSLog(@"Could not get bytes per row, guessing");
 
289
                                        bytes = CGBytesPerRow(width, depth);
 
290
                                }
 
291
 
 
292
                                if ( ! oldRes )
 
293
                                        oldRes = width * height;
 
294
                                else
 
295
                                        if ( oldRes != width * height )
 
296
                                        {
 
297
                                                oldRes = width * height;
 
298
                                                ++res_id;
 
299
                                        }
 
300
 
 
301
                                add_mode(width, height, res_id, bytes, (const uint32) d, depth);
 
302
                        }
 
303
                }
 
304
        }
 
305
 
 
306
        return true;
 
307
}
 
308
 
 
309
#ifdef CG_USE_ALPHA
 
310
// memset() by long instead of byte
 
311
 
 
312
static void memsetl (long *buffer, long pattern, size_t length)
 
313
{
 
314
        long    *buf = (long *) buffer,
 
315
                        *end = buf + length/4;
 
316
 
 
317
        while ( ++buf < end )
 
318
                *buf = pattern;
 
319
}
 
320
 
 
321
// Sets the alpha channel in a image to full on, except for the corners
 
322
 
 
323
static void mask_buffer (void *buffer, size_t width, size_t size)
 
324
{
 
325
        long    *bufl = (long *) buffer;
 
326
        char    *bufc = (char *) buffer;
 
327
 
 
328
 
 
329
        memsetl(bufl, 0xFF000000, size);
 
330
 
 
331
 
 
332
        // Round upper-left corner
 
333
                                   *bufl = 0, *bufc+4 = 0;                                      // XXXXX
 
334
        bufc += width, *bufc++ = 0, *bufc++ = 0, *bufc++ = 0;   // XXX
 
335
        bufc += width, *bufc++ = 0, *bufc = 0;                                  // XX
 
336
        bufc += width, *bufc = 0;                                                               // X
 
337
        bufc += width, *bufc = 0;                                                               // X
 
338
 
 
339
 
 
340
        NSLog(@"Masked buffer");
 
341
}
 
342
#endif
 
343
 
 
344
// monitor_desc subclass for Mac OS X displays
 
345
 
 
346
class OSX_monitor : public monitor_desc
 
347
{
 
348
        public:
 
349
                OSX_monitor(const vector<video_mode>    &available_modes,
 
350
                                        video_depth                                     default_depth,
 
351
                                        uint32                                          default_id);
 
352
 
 
353
                virtual void set_palette(uint8 *pal, int num);
 
354
                virtual void switch_to_current_mode(void);
 
355
 
 
356
                                void set_mac_frame_buffer(const video_mode mode);
 
357
 
 
358
                                void video_close(void);
 
359
                                bool video_open (const video_mode &mode);
 
360
 
 
361
 
 
362
        private:
 
363
                bool init_opengl(const video_mode &mode);
 
364
                bool init_screen(      video_mode &mode);
 
365
                bool init_window(const video_mode &mode);
 
366
 
 
367
 
 
368
#ifdef CGIMAGEREF
 
369
                CGColorSpaceRef         colourSpace;
 
370
                uint8                           *colourTable;
 
371
                CGImageRef                      imageRef;
 
372
                CGDataProviderRef       provider;
 
373
                short                           x, y, bpp, depth, bpr;
 
374
#endif
 
375
#ifdef NSBITMAP
 
376
                NSBitmapImageRep        *bitmap;
 
377
#endif
 
378
                void                            *the_buffer;
 
379
 
 
380
 
 
381
                // These record changes we made in setting full screen mode,
 
382
                // so that we can set the display back as it was again.
 
383
                CGDirectDisplayID       theDisplay;
 
384
                CFDictionaryRef         originalMode,
 
385
                                                        newMode;
 
386
};
 
387
 
 
388
 
 
389
OSX_monitor :: OSX_monitor (const       vector<video_mode>      &available_modes,
 
390
                                                                        video_depth                     default_depth,
 
391
                                                                        uint32                          default_id)
 
392
                        : monitor_desc (available_modes, default_depth, default_id)
 
393
{
 
394
#ifdef CGIMAGEREF
 
395
        colourSpace = nil;
 
396
        colourTable = (uint8 *) malloc(256 * 3);
 
397
        imageRef = nil;
 
398
        provider = nil;
 
399
#endif
 
400
#ifdef NSBITMAP
 
401
        bitmap = nil;
 
402
#endif
 
403
        newMode = originalMode = nil;
 
404
        the_buffer = NULL;
 
405
        theDisplay = nil;
 
406
};
 
407
 
 
408
// Should also have a destructor which does
 
409
//#ifdef CGIMAGEREF
 
410
//      free(colourTable);
 
411
//#endif
 
412
 
 
413
 
 
414
// Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
 
415
void
 
416
OSX_monitor::set_mac_frame_buffer(const video_mode mode)
 
417
{
 
418
#if !REAL_ADDRESSING && !DIRECT_ADDRESSING
 
419
        switch ( mode.depth )
 
420
        {
 
421
        //      case VDEPTH_15BIT:
 
422
                case VDEPTH_16BIT: MacFrameLayout = FLAYOUT_HOST_555; break;
 
423
        //      case VDEPTH_24BIT:
 
424
                case VDEPTH_32BIT: MacFrameLayout = FLAYOUT_HOST_888; break;
 
425
                default                  : MacFrameLayout = FLAYOUT_DIRECT;
 
426
        }
 
427
        set_mac_frame_base(MacFrameBaseMac);
 
428
 
 
429
        // Set variables used by UAE memory banking
 
430
        MacFrameBaseHost = (uint8 *) the_buffer;
 
431
        MacFrameSize = mode.bytes_per_row * mode.y;
 
432
        InitFrameBufferMapping();
 
433
#else
 
434
        set_mac_frame_base((unsigned int)Host2MacAddr((uint8 *)the_buffer));
 
435
#endif
 
436
        D(bug("mac_frame_base = %08x\n", get_mac_frame_base()));
 
437
}
 
438
 
 
439
static void
 
440
resizeWinBy(const short deltaX, const short deltaY)
 
441
{
 
442
        NSRect  rect = [the_win frame];
 
443
 
 
444
        D(bug("resizeWinBy(%d,%d) - ", deltaX, deltaY));
 
445
        D(bug("old x=%g, y=%g", rect.size.width, rect.size.height));
 
446
 
 
447
        rect.size.width  += deltaX;
 
448
        rect.size.height += deltaY;
 
449
 
 
450
        D(bug(", new x=%g, y=%g\n", rect.size.width, rect.size.height));
 
451
 
 
452
        [the_win setFrame: rect display: YES animate: YES];
 
453
        [the_win center];
 
454
        rect = [the_win frame];
 
455
}
 
456
 
 
457
void resizeWinTo(const uint16 newWidth, const uint16 newHeight)
 
458
{
 
459
        int             deltaX = newWidth  - [output width],
 
460
                        deltaY = newHeight - [output height];
 
461
 
 
462
        D(bug("resizeWinTo(%d,%d)\n", newWidth, newHeight));
 
463
 
 
464
        if ( deltaX || deltaY )
 
465
                resizeWinBy(deltaX, deltaY);
 
466
}
 
467
 
 
468
// Open window
 
469
bool
 
470
OSX_monitor::init_window(const video_mode &mode)
 
471
{
 
472
        D(bug("init_window: depth=%d(%d bits)\n",
 
473
                        mode.depth, bits_from_depth(mode.depth) ));
 
474
 
 
475
 
 
476
        // Set absolute mouse mode
 
477
        ADBSetRelMouseMode(false);
 
478
 
 
479
 
 
480
        // Is the window open?
 
481
        if ( ! the_win )
 
482
        {
 
483
                ErrorAlert(STR_OPEN_WINDOW_ERR);
 
484
                return false;
 
485
        }
 
486
        resizeWinTo(mode.x, mode.y);
 
487
 
 
488
 
 
489
        // Create frame buffer ("height + 2" for safety)
 
490
        int the_buffer_size = mode.bytes_per_row * (mode.y + 2);
 
491
 
 
492
        the_buffer = calloc(the_buffer_size, 1);
 
493
        if ( ! the_buffer )
 
494
        {
 
495
                NSLog(@"calloc(%d) failed", the_buffer_size);
 
496
                ErrorAlert(STR_NO_MEM_ERR);
 
497
                return false;
 
498
        }
 
499
        D(bug("the_buffer = %p\n", the_buffer));
 
500
 
 
501
 
 
502
        unsigned char *offsetBuffer = (unsigned char *) the_buffer;
 
503
        offsetBuffer += 1;              // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
 
504
 
 
505
#ifdef CGIMAGEREF
 
506
        switch ( mode.depth )
 
507
        {
 
508
                case VDEPTH_1BIT:       bpp = 1; break;
 
509
                case VDEPTH_2BIT:       bpp = 2; break;
 
510
                case VDEPTH_4BIT:       bpp = 4; break;
 
511
                case VDEPTH_8BIT:       bpp = 8; break;
 
512
                case VDEPTH_16BIT:      bpp = 5; break;
 
513
                case VDEPTH_32BIT:      bpp = 8; break;
 
514
        }
 
515
 
 
516
        x = mode.x, y = mode.y, depth = bits_from_depth(mode.depth), bpr = mode.bytes_per_row;
 
517
 
 
518
        colourSpace = CGColorSpaceCreateDeviceRGB();
 
519
 
 
520
        if ( mode.depth < VDEPTH_16BIT )
 
521
        {
 
522
                CGColorSpaceRef oldColourSpace = colourSpace;
 
523
 
 
524
                colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, colourTable);
 
525
 
 
526
                CGColorSpaceRelease(oldColourSpace);
 
527
        }
 
528
 
 
529
        if ( ! colourSpace )
 
530
        {
 
531
                ErrorAlert("No valid colour space");
 
532
                return false;
 
533
        }
 
534
 
 
535
        provider = CGDataProviderCreateWithData(NULL, the_buffer,
 
536
                                                                                        the_buffer_size, NULL);
 
537
        if ( ! provider )
 
538
        {
 
539
                ErrorAlert("Could not create CGDataProvider from buffer data");
 
540
                return false;
 
541
        }
 
542
 
 
543
        imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace,
 
544
  #ifdef CG_USE_ALPHA
 
545
                                                         kCGImageAlphaPremultipliedFirst,
 
546
  #else
 
547
                                                         kCGImageAlphaNoneSkipFirst,
 
548
  #endif
 
549
                                                         provider,
 
550
                                                         NULL,  // colourMap translation table
 
551
                                                         NO,    // shouldInterpolate colours?
 
552
                                                         kCGRenderingIntentDefault);
 
553
        if ( ! imageRef )
 
554
        {
 
555
                ErrorAlert("Could not create CGImage from CGDataProvider");
 
556
                return false;
 
557
        }
 
558
 
 
559
        [output readyToDraw: imageRef
 
560
                                 bitmap: offsetBuffer
 
561
                         imageWidth: x
 
562
                        imageHeight: y];
 
563
 
 
564
 
 
565
  #ifdef CG_USE_ALPHA
 
566
        mask_buffer(the_buffer, x, the_buffer_size);
 
567
 
 
568
/* Create an image mask with this call? */
 
569
//CG_EXTERN CGImageRef
 
570
//CGImageMaskCreate(size_t width, size_t height, size_t bitsPerComponent,
 
571
//                                      size_t bitsPerPixel, size_t bytesPerRow,
 
572
//                                      CGDataProviderRef provider, const float decode[], bool shouldInterpolate);
 
573
  #endif
 
574
 
 
575
        return true;
 
576
#endif
 
577
 
 
578
 
 
579
#ifndef CGIMAGEREF
 
580
        short   bitsPer, samplesPer;    // How big is each Pixel?
 
581
 
 
582
        if ( mode.depth == VDEPTH_1BIT )
 
583
                bitsPer = 1;
 
584
        else
 
585
                bitsPer = 8;
 
586
 
 
587
        if ( mode.depth == VDEPTH_32BIT )
 
588
                samplesPer = 3;
 
589
        else
 
590
                samplesPer = 1;
 
591
#endif
 
592
 
 
593
 
 
594
#ifdef NSBITMAP
 
595
        bitmap = [NSBitmapImageRep alloc];
 
596
        bitmap = [bitmap initWithBitmapDataPlanes: (unsigned char **) &offsetBuffer
 
597
                                                                   pixelsWide: mode.x
 
598
                                                                   pixelsHigh: mode.y
 
599
                                                                bitsPerSample: bitsPer
 
600
                              samplesPerPixel: samplesPer
 
601
                                     hasAlpha: NO
 
602
                                                                         isPlanar: NO
 
603
                                                           colorSpaceName: NSCalibratedRGBColorSpace
 
604
                                                                  bytesPerRow: mode.bytes_per_row
 
605
                                                                 bitsPerPixel: bits_from_depth(mode.depth)];
 
606
 
 
607
    if ( ! bitmap )
 
608
        {
 
609
                ErrorAlert("Could not allocate an NSBitmapImageRep");
 
610
                return false;
 
611
        }
 
612
 
 
613
        [output readyToDraw: bitmap
 
614
                         imageWidth: mode.x
 
615
                        imageHeight: mode.y];
 
616
#endif
 
617
 
 
618
#ifdef CGDRAWBITMAP
 
619
        [output readyToDraw: offsetBuffer
 
620
                                  width: mode.x
 
621
                                 height: mode.y
 
622
                                        bps: bitsPer
 
623
                                        spp: samplesPer
 
624
                                        bpp: bits_from_depth(mode.depth)
 
625
                                        bpr: mode.bytes_per_row
 
626
                           isPlanar: NO
 
627
                           hasAlpha: NO];
 
628
#endif
 
629
 
 
630
        return true;
 
631
}
 
632
 
 
633
#import <AppKit/NSEvent.h>
 
634
#import <Carbon/Carbon.h>
 
635
#import "NNThread.h"
 
636
 
 
637
bool
 
638
OSX_monitor::init_screen(video_mode &mode)
 
639
{
 
640
        // Set absolute mouse mode
 
641
        ADBSetRelMouseMode(false);
 
642
 
 
643
        // Display stored by add_CGDirectDisplay_modes()
 
644
        theDisplay = (CGDirectDisplayID) mode.user_data;
 
645
 
 
646
        originalMode = CGDisplayCurrentMode(theDisplay);
 
647
        if ( ! originalMode )
 
648
        {
 
649
                ErrorSheet(@"Could not get current mode of display", the_win);
 
650
                return false;
 
651
        }
 
652
 
 
653
        D(NSLog(@"About to call CGDisplayBestModeForParameters()"));
 
654
        newMode = CGDisplayBestModeForParameters(theDisplay,
 
655
                                                                                         bits_from_depth(mode.depth),
 
656
                                                                                                        mode.x, mode.y, NULL);
 
657
        if ( ! newMode )
 
658
        {
 
659
                ErrorSheet(@"Could not find a matching screen mode", the_win);
 
660
                return false;
 
661
        }
 
662
 
 
663
//      This sometimes takes ages to return after the window is genied,
 
664
//      so for now we leave it onscreen
 
665
//      [the_win miniaturize: nil];
 
666
 
 
667
        D(NSLog(@"About to call CGDisplayCapture()"));
 
668
        if ( CGDisplayCapture(theDisplay) != CGDisplayNoErr )
 
669
        {
 
670
//              [the_win deminiaturize: nil];
 
671
                ErrorSheet(@"Could not capture display", the_win);
 
672
                return false;
 
673
        }
 
674
 
 
675
        D(NSLog(@"About to call CGDisplaySwitchToMode()"));
 
676
        if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr )
 
677
        {
 
678
                CGDisplayRelease(theDisplay);
 
679
//              [the_win deminiaturize: nil];
 
680
                ErrorSheet(@"Could not switch to matching screen mode", the_win);
 
681
                return false;
 
682
        }
 
683
 
 
684
        the_buffer = CGDisplayBaseAddress(theDisplay);
 
685
        if ( ! the_buffer )
 
686
        {
 
687
                CGDisplaySwitchToMode(theDisplay, originalMode);
 
688
                CGDisplayRelease(theDisplay);
 
689
//              [the_win deminiaturize: nil];
 
690
                ErrorSheet(@"Could not get base address of screen", the_win);
 
691
                return false;
 
692
        }
 
693
 
 
694
        if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) )
 
695
        {
 
696
                D(bug("Bytes per row (%d) doesn't match current (%ld)\n",
 
697
                                mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay)));
 
698
                mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay);
 
699
        }
 
700
 
 
701
        HideMenuBar();
 
702
 
 
703
        if ( singleDisplay )
 
704
        {
 
705
                CGDisplayHideCursor(theDisplay);
 
706
 
 
707
                [output startedFullScreen: theDisplay];
 
708
 
 
709
                // Send emulated mouse to current location
 
710
                [output fullscreenMouseMove];
 
711
        }
 
712
        else
 
713
        {
 
714
                // Should set up something to hide the cursor when it enters theDisplay?
 
715
        }
 
716
 
 
717
        return true;
 
718
}
 
719
 
 
720
 
 
721
bool
 
722
OSX_monitor::init_opengl(const video_mode &mode)
 
723
{
 
724
        ErrorAlert("Sorry. OpenGL mode is not implemented yet");
 
725
        return false;
 
726
}
 
727
 
 
728
/*
 
729
 *  Initialization
 
730
 */
 
731
static bool
 
732
monitor_init(const video_mode &init_mode)
 
733
{
 
734
        OSX_monitor     *monitor;
 
735
        BOOL            success;
 
736
 
 
737
        monitor = new OSX_monitor(VideoModes, init_mode.depth,
 
738
                                                                                  init_mode.resolution_id);
 
739
        success = monitor->video_open(init_mode);
 
740
 
 
741
        if ( success )
 
742
        {
 
743
                monitor->set_mac_frame_buffer(init_mode);
 
744
                VideoMonitors.push_back(monitor);
 
745
                return YES;
 
746
        }
 
747
 
 
748
        return NO;
 
749
}
 
750
 
 
751
bool VideoInit(bool classic)
 
752
{
 
753
        // Read frame skip prefs
 
754
        frame_skip = PrefsFindInt32("frameskip");
 
755
        if (frame_skip == 0)
 
756
                frame_skip = 1;
 
757
 
 
758
        // Get screen mode from preferences
 
759
        const char *mode_str;
 
760
        if (classic)
 
761
                mode_str = "win/512/342";
 
762
        else
 
763
                mode_str = PrefsFindString("screen");
 
764
 
 
765
        // Determine display_type and init_width, height & depth
 
766
        parse_screen_prefs(mode_str);
 
767
 
 
768
        // Construct list of supported modes
 
769
        if (classic)
 
770
                add_mode(512, 342, 0x80, 64, 0, VDEPTH_1BIT);
 
771
        else
 
772
                switch ( display_type )
 
773
                {
 
774
                        case DISPLAY_SCREEN:
 
775
                                if ( ! add_CGDirectDisplay_modes() )
 
776
                                {
 
777
                                        ErrorAlert("Unable to get list of displays for full screen mode");
 
778
                                        return false;
 
779
                                }
 
780
                                break;
 
781
                        case DISPLAY_OPENGL:
 
782
                                // Same as window depths and sizes?
 
783
                        case DISPLAY_WINDOW:
 
784
#ifdef CGIMAGEREF
 
785
                                add_standard_modes(VDEPTH_1BIT);
 
786
                                add_standard_modes(VDEPTH_2BIT);
 
787
                                add_standard_modes(VDEPTH_4BIT);
 
788
                                add_standard_modes(VDEPTH_8BIT);
 
789
                                add_standard_modes(VDEPTH_16BIT);
 
790
#endif
 
791
                                add_standard_modes(VDEPTH_32BIT);
 
792
                                break;
 
793
                }
 
794
 
 
795
//      video_init_depth_list();                Now done in monitor_desc constructor?
 
796
 
 
797
#if DEBUG
 
798
        bug("Available video modes:\n");
 
799
        vector<video_mode>::const_iterator i, end = VideoModes.end();
 
800
        for (i = VideoModes.begin(); i != end; ++i)
 
801
                bug(" %dx%d (ID %02x), %s\n", i->x, i->y, i->resolution_id,
 
802
                                                                                colours_from_depth(i->depth));
 
803
#endif
 
804
 
 
805
        D(bug("VideoInit: width=%hd height=%hd depth=%d\n",
 
806
                                                init_width, init_height, init_depth));
 
807
 
 
808
        // Find requested default mode and open display
 
809
        if (VideoModes.size() > 0)
 
810
        {
 
811
                // Find mode with specified dimensions
 
812
                std::vector<video_mode>::const_iterator i, end = VideoModes.end();
 
813
                for (i = VideoModes.begin(); i != end; ++i)
 
814
                {
 
815
                        D(bug("VideoInit: w=%d h=%d d=%d\n",
 
816
                                        i->x, i->y, bits_from_depth(i->depth)));
 
817
                        if (i->x == init_width && i->y == init_height
 
818
                                        && bits_from_depth(i->depth) == init_depth)
 
819
                                return monitor_init(*i);
 
820
                }
 
821
        }
 
822
 
 
823
        char str[150];
 
824
        sprintf(str, "Cannot open selected video mode\r(%hd x %hd, %s).\r%s",
 
825
                        init_width, init_height,
 
826
                        colours_from_depth(init_depth), "Using lowest resolution");
 
827
        WarningAlert(str);
 
828
 
 
829
        return monitor_init(VideoModes[0]);
 
830
}
 
831
 
 
832
 
 
833
// Open display for specified mode
 
834
bool
 
835
OSX_monitor::video_open(const video_mode &mode)
 
836
{
 
837
        D(bug("video_open: width=%d  height=%d  depth=%d  bytes_per_row=%d\n",
 
838
                        mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row));
 
839
 
 
840
        // Open display
 
841
        switch ( display_type )
 
842
        {
 
843
                case DISPLAY_WINDOW:    return init_window(mode);
 
844
                case DISPLAY_SCREEN:    return init_screen((video_mode &)mode);
 
845
                case DISPLAY_OPENGL:    return init_opengl(mode);
 
846
        }
 
847
 
 
848
        return false;
 
849
}
 
850
 
 
851
 
 
852
void
 
853
OSX_monitor::video_close()
 
854
{
 
855
        D(bug("video_close()\n"));
 
856
 
 
857
        switch ( display_type ) {
 
858
                case DISPLAY_WINDOW:
 
859
                        // Stop redraw thread
 
860
                        [output disableDrawing];
 
861
 
 
862
                        // Free frame buffer stuff
 
863
#ifdef CGIMAGEREF
 
864
                        CGImageRelease(imageRef);
 
865
                        CGColorSpaceRelease(colourSpace);
 
866
                        CGDataProviderRelease(provider);
 
867
#endif
 
868
#ifdef NSBITMAP
 
869
                        [bitmap release];
 
870
#endif
 
871
                        free(the_buffer);
 
872
 
 
873
                        break;
 
874
 
 
875
                case DISPLAY_SCREEN:
 
876
                        if ( theDisplay && originalMode )
 
877
                        {
 
878
                                if ( singleDisplay )
 
879
                                        CGDisplayShowCursor(theDisplay);
 
880
                                ShowMenuBar();
 
881
                                CGDisplaySwitchToMode(theDisplay, originalMode);
 
882
                                CGDisplayRelease(theDisplay);
 
883
                                //[the_win deminiaturize: nil];
 
884
                        }
 
885
                        break;
 
886
 
 
887
                case DISPLAY_OPENGL:
 
888
                        break;
 
889
        }
 
890
}
 
891
 
 
892
 
 
893
/*
 
894
 *  Deinitialization
 
895
 */
 
896
 
 
897
void VideoExit(void)
 
898
{
 
899
        // Close displays
 
900
        vector<monitor_desc *>::iterator        i, end;
 
901
 
 
902
        end = VideoMonitors.end();
 
903
 
 
904
        for (i = VideoMonitors.begin(); i != end; ++i)
 
905
                dynamic_cast<OSX_monitor *>(*i)->video_close();
 
906
 
 
907
        VideoMonitors.clear();
 
908
        VideoModes.clear();
 
909
}
 
910
 
 
911
 
 
912
/*
 
913
 *  Set palette
 
914
 */
 
915
 
 
916
void
 
917
OSX_monitor::set_palette(uint8 *pal, int num)
 
918
{
 
919
        if ( [output isFullScreen] && CGDisplayCanSetPalette(theDisplay)
 
920
                                                                && ! IsDirectMode(get_current_mode()) )
 
921
        {
 
922
                CGDirectPaletteRef      CGpal;
 
923
                CGDisplayErr            err;
 
924
 
 
925
 
 
926
                CGpal = CGPaletteCreateWithByteSamples((CGDeviceByteColor *)pal, num);
 
927
                err   = CGDisplaySetPalette(theDisplay, CGpal);
 
928
                if ( err != noErr )
 
929
                        NSLog(@"Failed to set palette, error = %d", err);
 
930
                CGPaletteRelease(CGpal);
 
931
        }
 
932
 
 
933
#ifdef CGIMAGEREF
 
934
        if ( display_type != DISPLAY_WINDOW )
 
935
                return;
 
936
 
 
937
        // To change the palette, we have to regenerate
 
938
        // the CGImageRef with the new colour space.
 
939
 
 
940
        CGImageRef                      oldImageRef = imageRef;
 
941
        CGColorSpaceRef         oldColourSpace = colourSpace;
 
942
 
 
943
        colourSpace = CGColorSpaceCreateDeviceRGB();
 
944
 
 
945
        if ( depth < 16 )
 
946
        {
 
947
                CGColorSpaceRef         tempColourSpace = colourSpace;
 
948
 
 
949
                colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, pal);
 
950
                CGColorSpaceRelease(tempColourSpace);
 
951
        }
 
952
 
 
953
        if ( ! colourSpace )
 
954
        {
 
955
                ErrorAlert("No valid colour space");
 
956
                return;
 
957
        }
 
958
 
 
959
        imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace,
 
960
  #ifdef CG_USE_ALPHA
 
961
                                                         kCGImageAlphaPremultipliedFirst,
 
962
  #else
 
963
                                                         kCGImageAlphaNoneSkipFirst,
 
964
  #endif
 
965
                                                         provider,
 
966
                                                         NULL,  // colourMap translation table
 
967
                                                         NO,    // shouldInterpolate colours?
 
968
                                                         kCGRenderingIntentDefault);
 
969
        if ( ! imageRef )
 
970
        {
 
971
                ErrorAlert("Could not create CGImage from CGDataProvider");
 
972
                return;
 
973
        }
 
974
 
 
975
        unsigned char *offsetBuffer = (unsigned char *) the_buffer;
 
976
        offsetBuffer += 1;              // OS X NSBitmaps are RGBA, but Basilisk generates ARGB
 
977
 
 
978
        [output readyToDraw: imageRef
 
979
                                 bitmap: offsetBuffer
 
980
                         imageWidth: x
 
981
                        imageHeight: y];
 
982
 
 
983
        CGColorSpaceRelease(oldColourSpace);
 
984
        CGImageRelease(oldImageRef);
 
985
#endif
 
986
}
 
987
 
 
988
 
 
989
/*
 
990
 *  Switch video mode
 
991
 */
 
992
 
 
993
void
 
994
OSX_monitor::switch_to_current_mode(void)
 
995
{
 
996
        video_mode      mode = get_current_mode();
 
997
        char            *failure = NULL;
 
998
 
 
999
 
 
1000
        D(bug("switch_to_current_mode(): width=%d  height=%d  depth=%d  bytes_per_row=%d\n", mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row));
 
1001
        
 
1002
        if ( display_type == DISPLAY_SCREEN && originalMode )
 
1003
        {
 
1004
                D(NSLog(@"About to call CGDisplayBestModeForParameters()"));
 
1005
                newMode = CGDisplayBestModeForParameters(theDisplay,
 
1006
                                                                                                 bits_from_depth(mode.depth),
 
1007
                                                                                                                mode.x, mode.y, NULL);
 
1008
                if ( ! newMode )
 
1009
                        failure = "Could not find a matching screen mode";
 
1010
                else
 
1011
                {
 
1012
                        D(NSLog(@"About to call CGDisplaySwitchToMode()"));
 
1013
                        if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr )
 
1014
                                failure = "Could not switch to matching screen mode";
 
1015
                }
 
1016
 
 
1017
                // For mouse event processing: update screen height
 
1018
                [output startedFullScreen: theDisplay];
 
1019
 
 
1020
                if ( ! failure &&
 
1021
                        mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) )
 
1022
                {
 
1023
                        D(bug("Bytes per row (%d) doesn't match current (%ld)\n",
 
1024
                                        mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay)));
 
1025
                        mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay);
 
1026
                }
 
1027
 
 
1028
                if ( ! failure &&
 
1029
                         ! ( the_buffer = CGDisplayBaseAddress(theDisplay) ) )
 
1030
                        failure = "Could not get base address of screen";
 
1031
 
 
1032
        }
 
1033
        // Clean up the old CGImageRef stuff
 
1034
        else if ( display_type == DISPLAY_WINDOW && imageRef )
 
1035
        {
 
1036
                CGImageRef                      oldImageRef             = imageRef;
 
1037
                CGColorSpaceRef         oldColourSpace  = colourSpace;
 
1038
                CGDataProviderRef       oldProvider             = provider;
 
1039
                void                            *oldBuffer              = the_buffer;
 
1040
 
 
1041
                if ( video_open(mode) )
 
1042
                {
 
1043
                        CGImageRelease(oldImageRef);
 
1044
                        CGColorSpaceRelease(oldColourSpace);
 
1045
                        CGDataProviderRelease(oldProvider);
 
1046
                        free(oldBuffer);
 
1047
                }
 
1048
                else
 
1049
                        failure = "Could not video_open() requested mode";
 
1050
        }
 
1051
        else if ( ! video_open(mode) )
 
1052
                failure = "Could not video_open() requested mode";
 
1053
 
 
1054
        if ( ! failure && display_type == DISPLAY_SCREEN )
 
1055
        {
 
1056
                // Whenever we change screen resolution, the MacOS mouse starts
 
1057
                // up in the top left corner. Send real mouse to that location
 
1058
//              if ( CGDisplayMoveCursorToPoint(theDisplay, CGPointMake(15,15))
 
1059
//                                                                                                              == CGDisplayNoErr )
 
1060
//              {
 
1061
                        // 
 
1062
                        [output fullscreenMouseMove];
 
1063
//              }
 
1064
//              else
 
1065
//                      failure = "Could move (jump) cursor on screen";
 
1066
        }
 
1067
 
 
1068
        if ( failure )
 
1069
        {
 
1070
                NSLog(@"In switch_to_current_mode():");
 
1071
                NSLog(@"%s.", failure);
 
1072
                video_close();
 
1073
                if ( display_type == DISPLAY_SCREEN )
 
1074
                        ErrorAlert("Cannot switch screen to selected video mode");
 
1075
                else
 
1076
                        ErrorAlert(STR_OPEN_WINDOW_ERR);
 
1077
                QuitEmulator();
 
1078
        }
 
1079
        else
 
1080
                set_mac_frame_buffer(mode);
 
1081
}
 
1082
 
 
1083
/*
 
1084
 *  Close down full-screen mode
 
1085
 *      (if bringing up error alerts is unsafe while in full-screen mode)
 
1086
 */
 
1087
 
 
1088
void VideoQuitFullScreen(void)
 
1089
{
 
1090
}
 
1091
 
 
1092
 
 
1093
/*
 
1094
 *  Mac VBL interrupt
 
1095
 */
 
1096
 
 
1097
void VideoInterrupt(void)
 
1098
{
 
1099
}
 
1100
 
 
1101
 
 
1102
// This function is called on non-threaded platforms from a timer interrupt
 
1103
void VideoRefresh(void)
 
1104
{
 
1105
}