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-2002 Christian Bauer |
7 |
> |
* Basilisk II (C) 1997-2005 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 |
101 |
|
bool |
102 |
|
parse_screen_prefs(const char *mode_str) |
103 |
|
{ |
104 |
+ |
if ( ! mode_str ) |
105 |
+ |
{ |
106 |
+ |
// No screen pref was found. Supply a default: |
107 |
+ |
mode_str = "win/512/384"; |
108 |
+ |
} |
109 |
+ |
|
110 |
|
if (sscanf(mode_str, "win/%hd/%hd/%hd", |
111 |
|
&init_width, &init_height, &init_depth) == 3) |
112 |
|
display_type = DISPLAY_WINDOW; |
274 |
|
#ifdef MAC_OS_X_VERSION_10_2 |
275 |
|
int32 bytes = getCFint32(modeSpec, kCGDisplayBytesPerRow); |
276 |
|
#else |
277 |
< |
int32 bytes = 0; |
277 |
> |
int32 bytes = 0; |
278 |
|
#endif |
279 |
|
video_depth depth = DepthModeForPixelDepth(bpp); |
280 |
|
|
372 |
|
|
373 |
|
|
374 |
|
#ifdef CGIMAGEREF |
375 |
+ |
CGColorSpaceRef colourSpace; |
376 |
+ |
uint8 *colourTable; |
377 |
|
CGImageRef imageRef; |
378 |
+ |
CGDataProviderRef provider; |
379 |
+ |
short x, y, bpp, depth, bpr; |
380 |
|
#endif |
381 |
|
#ifdef NSBITMAP |
382 |
|
NSBitmapImageRep *bitmap; |
398 |
|
: monitor_desc (available_modes, default_depth, default_id) |
399 |
|
{ |
400 |
|
#ifdef CGIMAGEREF |
401 |
+ |
colourSpace = nil; |
402 |
+ |
colourTable = (uint8 *) malloc(256 * 3); |
403 |
|
imageRef = nil; |
404 |
+ |
provider = nil; |
405 |
|
#endif |
406 |
|
#ifdef NSBITMAP |
407 |
|
bitmap = nil; |
411 |
|
theDisplay = nil; |
412 |
|
}; |
413 |
|
|
414 |
+ |
// Should also have a destructor which does |
415 |
+ |
//#ifdef CGIMAGEREF |
416 |
+ |
// free(colourTable); |
417 |
+ |
//#endif |
418 |
+ |
|
419 |
|
|
420 |
|
// Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) |
421 |
|
void |
455 |
|
|
456 |
|
D(bug(", new x=%g, y=%g\n", rect.size.width, rect.size.height)); |
457 |
|
|
458 |
< |
[the_win setFrame: rect display: YES]; |
458 |
> |
[the_win setFrame: rect display: YES animate: YES]; |
459 |
> |
[the_win center]; |
460 |
|
rect = [the_win frame]; |
461 |
|
} |
462 |
|
|
475 |
|
bool |
476 |
|
OSX_monitor::init_window(const video_mode &mode) |
477 |
|
{ |
459 |
– |
#ifdef CGIMAGEREF |
460 |
– |
CGColorSpaceRef colourSpace; |
461 |
– |
CGDataProviderRef provider; |
462 |
– |
#endif |
463 |
– |
short bitsPer, samplesPer; // How big is each Pixel? |
464 |
– |
int the_buffer_size; |
465 |
– |
|
478 |
|
D(bug("init_window: depth=%d(%d bits)\n", |
479 |
|
mode.depth, bits_from_depth(mode.depth) )); |
480 |
|
|
483 |
|
ADBSetRelMouseMode(false); |
484 |
|
|
485 |
|
|
486 |
< |
// Open window |
486 |
> |
// Is the window open? |
487 |
|
if ( ! the_win ) |
488 |
|
{ |
489 |
|
ErrorAlert(STR_OPEN_WINDOW_ERR); |
493 |
|
|
494 |
|
|
495 |
|
// Create frame buffer ("height + 2" for safety) |
496 |
< |
the_buffer_size = mode.bytes_per_row * (mode.y + 2); |
496 |
> |
int the_buffer_size = mode.bytes_per_row * (mode.y + 2); |
497 |
> |
|
498 |
|
the_buffer = calloc(the_buffer_size, 1); |
499 |
|
if ( ! the_buffer ) |
500 |
|
{ |
505 |
|
D(bug("the_buffer = %p\n", the_buffer)); |
506 |
|
|
507 |
|
|
508 |
< |
if ( mode.depth == VDEPTH_1BIT ) |
509 |
< |
bitsPer = 1; |
497 |
< |
else |
498 |
< |
bitsPer = 8; |
499 |
< |
|
500 |
< |
if ( mode.depth == VDEPTH_32BIT ) |
501 |
< |
samplesPer = 3; |
502 |
< |
else |
503 |
< |
samplesPer = 1; |
508 |
> |
unsigned char *offsetBuffer = (unsigned char *) the_buffer; |
509 |
> |
offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB |
510 |
|
|
511 |
|
#ifdef CGIMAGEREF |
512 |
|
switch ( mode.depth ) |
513 |
|
{ |
514 |
< |
//case VDEPTH_1BIT: colourSpace = CGColorSpaceCreateDeviceMono(); break |
515 |
< |
case VDEPTH_8BIT: colourSpace = CGColorSpaceCreateDeviceGray(); break; |
516 |
< |
case VDEPTH_32BIT: colourSpace = CGColorSpaceCreateDeviceRGB(); break; |
517 |
< |
default: colourSpace = NULL; |
514 |
> |
case VDEPTH_1BIT: bpp = 1; break; |
515 |
> |
case VDEPTH_2BIT: bpp = 2; break; |
516 |
> |
case VDEPTH_4BIT: bpp = 4; break; |
517 |
> |
case VDEPTH_8BIT: bpp = 8; break; |
518 |
> |
case VDEPTH_16BIT: bpp = 5; break; |
519 |
> |
case VDEPTH_32BIT: bpp = 8; break; |
520 |
> |
} |
521 |
> |
|
522 |
> |
x = mode.x, y = mode.y, depth = bits_from_depth(mode.depth), bpr = mode.bytes_per_row; |
523 |
> |
|
524 |
> |
colourSpace = CGColorSpaceCreateDeviceRGB(); |
525 |
> |
|
526 |
> |
if ( mode.depth < VDEPTH_16BIT ) |
527 |
> |
{ |
528 |
> |
CGColorSpaceRef oldColourSpace = colourSpace; |
529 |
> |
|
530 |
> |
colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, colourTable); |
531 |
> |
|
532 |
> |
CGColorSpaceRelease(oldColourSpace); |
533 |
|
} |
534 |
|
|
535 |
|
if ( ! colourSpace ) |
545 |
|
ErrorAlert("Could not create CGDataProvider from buffer data"); |
546 |
|
return false; |
547 |
|
} |
548 |
< |
imageRef = CGImageCreate(mode.x, |
549 |
< |
mode.y, |
529 |
< |
bitsPer, |
530 |
< |
bits_from_depth(mode.depth), |
531 |
< |
mode.bytes_per_row, |
532 |
< |
colourSpace, |
548 |
> |
|
549 |
> |
imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace, |
550 |
|
#ifdef CG_USE_ALPHA |
551 |
|
kCGImageAlphaPremultipliedFirst, |
552 |
|
#else |
561 |
|
ErrorAlert("Could not create CGImage from CGDataProvider"); |
562 |
|
return false; |
563 |
|
} |
547 |
– |
CGDataProviderRelease(provider); |
548 |
– |
CGColorSpaceRelease(colourSpace); |
564 |
|
|
565 |
|
[output readyToDraw: imageRef |
566 |
< |
imageWidth: mode.x |
567 |
< |
imageHeight: mode.y]; |
566 |
> |
bitmap: offsetBuffer |
567 |
> |
imageWidth: x |
568 |
> |
imageHeight: y]; |
569 |
> |
|
570 |
|
|
571 |
|
#ifdef CG_USE_ALPHA |
572 |
< |
mask_buffer(the_buffer, mode.x, the_buffer_size); |
572 |
> |
mask_buffer(the_buffer, x, the_buffer_size); |
573 |
> |
|
574 |
> |
/* Create an image mask with this call? */ |
575 |
> |
//CG_EXTERN CGImageRef |
576 |
> |
//CGImageMaskCreate(size_t width, size_t height, size_t bitsPerComponent, |
577 |
> |
// size_t bitsPerPixel, size_t bytesPerRow, |
578 |
> |
// CGDataProviderRef provider, const float decode[], bool shouldInterpolate); |
579 |
|
#endif |
580 |
< |
#else |
581 |
< |
unsigned char *offsetBuffer = (unsigned char *) the_buffer; |
582 |
< |
offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB |
580 |
> |
|
581 |
> |
return true; |
582 |
> |
#endif |
583 |
> |
|
584 |
> |
|
585 |
> |
#ifndef CGIMAGEREF |
586 |
> |
short bitsPer, samplesPer; // How big is each Pixel? |
587 |
> |
|
588 |
> |
if ( mode.depth == VDEPTH_1BIT ) |
589 |
> |
bitsPer = 1; |
590 |
> |
else |
591 |
> |
bitsPer = 8; |
592 |
> |
|
593 |
> |
if ( mode.depth == VDEPTH_32BIT ) |
594 |
> |
samplesPer = 3; |
595 |
> |
else |
596 |
> |
samplesPer = 1; |
597 |
|
#endif |
598 |
|
|
599 |
+ |
|
600 |
|
#ifdef NSBITMAP |
601 |
|
bitmap = [NSBitmapImageRep alloc]; |
602 |
|
bitmap = [bitmap initWithBitmapDataPlanes: (unsigned char **) &offsetBuffer |
687 |
|
return false; |
688 |
|
} |
689 |
|
|
652 |
– |
// For mouse event processing: update screen height |
653 |
– |
[output startedFullScreen: theDisplay]; |
654 |
– |
|
690 |
|
the_buffer = CGDisplayBaseAddress(theDisplay); |
691 |
|
if ( ! the_buffer ) |
692 |
|
{ |
697 |
|
return false; |
698 |
|
} |
699 |
|
|
665 |
– |
D(NSLog(@"Starting full screen mode, height = %d", |
666 |
– |
CGDisplayPixelsHigh(theDisplay))); |
667 |
– |
|
668 |
– |
[output startedFullScreen: theDisplay]; // For mouse event processing |
669 |
– |
|
700 |
|
if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) ) |
701 |
|
{ |
702 |
|
D(bug("Bytes per row (%d) doesn't match current (%ld)\n", |
710 |
|
{ |
711 |
|
CGDisplayHideCursor(theDisplay); |
712 |
|
|
713 |
< |
// Send real mouse to emulated location |
684 |
< |
if ( CGDisplayMoveCursorToPoint(theDisplay, CGPointMake(15,15)) |
685 |
< |
!= CGDisplayNoErr ) |
686 |
< |
{ |
687 |
< |
video_close(); |
688 |
< |
ErrorSheet(@"Could move (jump) cursor on screen", the_win); |
689 |
< |
return false; |
690 |
< |
} |
713 |
> |
[output startedFullScreen: theDisplay]; |
714 |
|
|
715 |
|
// Send emulated mouse to current location |
716 |
< |
// [output performSelector: @selector(processMouseMove:) |
694 |
< |
// withObject: nil |
695 |
< |
// afterDelay: 7.0]; |
696 |
< |
// NNTimer *moveMouse = [[NNTimer new] retain]; |
697 |
< |
// [moveMouse perform: @selector(processMouseMove:) |
698 |
< |
// of: output |
699 |
< |
// after: 3 |
700 |
< |
// units: NNseconds]; |
716 |
> |
[output fullscreenMouseMove]; |
717 |
|
} |
718 |
|
else |
719 |
|
{ |
787 |
|
case DISPLAY_OPENGL: |
788 |
|
// Same as window depths and sizes? |
789 |
|
case DISPLAY_WINDOW: |
790 |
< |
//add_standard_modes(VDEPTH_1BIT); |
791 |
< |
//add_standard_modes(VDEPTH_8BIT); |
792 |
< |
//add_standard_modes(VDEPTH_16BIT); |
790 |
> |
#ifdef CGIMAGEREF |
791 |
> |
add_standard_modes(VDEPTH_1BIT); |
792 |
> |
add_standard_modes(VDEPTH_2BIT); |
793 |
> |
add_standard_modes(VDEPTH_4BIT); |
794 |
> |
add_standard_modes(VDEPTH_8BIT); |
795 |
> |
add_standard_modes(VDEPTH_16BIT); |
796 |
> |
#endif |
797 |
|
add_standard_modes(VDEPTH_32BIT); |
798 |
|
break; |
799 |
|
} |
868 |
|
// Free frame buffer stuff |
869 |
|
#ifdef CGIMAGEREF |
870 |
|
CGImageRelease(imageRef); |
871 |
+ |
CGColorSpaceRelease(colourSpace); |
872 |
+ |
CGDataProviderRelease(provider); |
873 |
|
#endif |
874 |
|
#ifdef NSBITMAP |
875 |
|
[bitmap release]; |
909 |
|
|
910 |
|
for (i = VideoMonitors.begin(); i != end; ++i) |
911 |
|
dynamic_cast<OSX_monitor *>(*i)->video_close(); |
912 |
+ |
|
913 |
+ |
VideoMonitors.clear(); |
914 |
+ |
VideoModes.clear(); |
915 |
|
} |
916 |
|
|
917 |
|
|
935 |
|
NSLog(@"Failed to set palette, error = %d", err); |
936 |
|
CGPaletteRelease(CGpal); |
937 |
|
} |
938 |
+ |
|
939 |
+ |
#ifdef CGIMAGEREF |
940 |
+ |
if ( display_type != DISPLAY_WINDOW ) |
941 |
+ |
return; |
942 |
+ |
|
943 |
+ |
// To change the palette, we have to regenerate |
944 |
+ |
// the CGImageRef with the new colour space. |
945 |
+ |
|
946 |
+ |
CGImageRef oldImageRef = imageRef; |
947 |
+ |
CGColorSpaceRef oldColourSpace = colourSpace; |
948 |
+ |
|
949 |
+ |
colourSpace = CGColorSpaceCreateDeviceRGB(); |
950 |
+ |
|
951 |
+ |
if ( depth < 16 ) |
952 |
+ |
{ |
953 |
+ |
CGColorSpaceRef tempColourSpace = colourSpace; |
954 |
+ |
|
955 |
+ |
colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, pal); |
956 |
+ |
CGColorSpaceRelease(tempColourSpace); |
957 |
+ |
} |
958 |
+ |
|
959 |
+ |
if ( ! colourSpace ) |
960 |
+ |
{ |
961 |
+ |
ErrorAlert("No valid colour space"); |
962 |
+ |
return; |
963 |
+ |
} |
964 |
+ |
|
965 |
+ |
imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace, |
966 |
+ |
#ifdef CG_USE_ALPHA |
967 |
+ |
kCGImageAlphaPremultipliedFirst, |
968 |
+ |
#else |
969 |
+ |
kCGImageAlphaNoneSkipFirst, |
970 |
+ |
#endif |
971 |
+ |
provider, |
972 |
+ |
NULL, // colourMap translation table |
973 |
+ |
NO, // shouldInterpolate colours? |
974 |
+ |
kCGRenderingIntentDefault); |
975 |
+ |
if ( ! imageRef ) |
976 |
+ |
{ |
977 |
+ |
ErrorAlert("Could not create CGImage from CGDataProvider"); |
978 |
+ |
return; |
979 |
+ |
} |
980 |
+ |
|
981 |
+ |
unsigned char *offsetBuffer = (unsigned char *) the_buffer; |
982 |
+ |
offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB |
983 |
+ |
|
984 |
+ |
[output readyToDraw: imageRef |
985 |
+ |
bitmap: offsetBuffer |
986 |
+ |
imageWidth: x |
987 |
+ |
imageHeight: y]; |
988 |
+ |
|
989 |
+ |
CGColorSpaceRelease(oldColourSpace); |
990 |
+ |
CGImageRelease(oldImageRef); |
991 |
+ |
#endif |
992 |
|
} |
993 |
|
|
994 |
|
|
1034 |
|
if ( ! failure && |
1035 |
|
! ( the_buffer = CGDisplayBaseAddress(theDisplay) ) ) |
1036 |
|
failure = "Could not get base address of screen"; |
1037 |
+ |
|
1038 |
+ |
} |
1039 |
+ |
#ifdef CGIMAGEREF |
1040 |
+ |
// Clean up the old CGImageRef stuff |
1041 |
+ |
else if ( display_type == DISPLAY_WINDOW && imageRef ) |
1042 |
+ |
{ |
1043 |
+ |
CGImageRef oldImageRef = imageRef; |
1044 |
+ |
CGColorSpaceRef oldColourSpace = colourSpace; |
1045 |
+ |
CGDataProviderRef oldProvider = provider; |
1046 |
+ |
void *oldBuffer = the_buffer; |
1047 |
+ |
|
1048 |
+ |
if ( video_open(mode) ) |
1049 |
+ |
{ |
1050 |
+ |
CGImageRelease(oldImageRef); |
1051 |
+ |
CGColorSpaceRelease(oldColourSpace); |
1052 |
+ |
CGDataProviderRelease(oldProvider); |
1053 |
+ |
free(oldBuffer); |
1054 |
+ |
} |
1055 |
|
else |
1056 |
< |
// Send emulated mouse to current location |
960 |
< |
[output processMouseMove: nil]; |
1056 |
> |
failure = "Could not video_open() requested mode"; |
1057 |
|
} |
1058 |
+ |
#endif |
1059 |
|
else if ( ! video_open(mode) ) |
1060 |
|
failure = "Could not video_open() requested mode"; |
1061 |
|
|
1062 |
+ |
if ( ! failure && display_type == DISPLAY_SCREEN ) |
1063 |
+ |
{ |
1064 |
+ |
// Whenever we change screen resolution, the MacOS mouse starts |
1065 |
+ |
// up in the top left corner. Send real mouse to that location |
1066 |
+ |
// if ( CGDisplayMoveCursorToPoint(theDisplay, CGPointMake(15,15)) |
1067 |
+ |
// == CGDisplayNoErr ) |
1068 |
+ |
// { |
1069 |
+ |
// |
1070 |
+ |
[output fullscreenMouseMove]; |
1071 |
+ |
// } |
1072 |
+ |
// else |
1073 |
+ |
// failure = "Could move (jump) cursor on screen"; |
1074 |
+ |
} |
1075 |
+ |
|
1076 |
|
if ( failure ) |
1077 |
|
{ |
1078 |
|
NSLog(@"In switch_to_current_mode():"); |
1111 |
|
void VideoRefresh(void) |
1112 |
|
{ |
1113 |
|
} |
1114 |
+ |
|
1115 |
+ |
|
1116 |
+ |
|
1117 |
+ |
// Deal with a memory access signal referring to the screen. |
1118 |
+ |
// For now, just ignore |
1119 |
+ |
bool Screen_fault_handler(char *a, char *b) |
1120 |
+ |
{ |
1121 |
+ |
// NSLog(@"Got a screen fault %lx %lx", a, b); |
1122 |
+ |
// [output setNeedsDisplay: YES]; |
1123 |
+ |
return YES; |
1124 |
+ |
} |