glgraphics.macos.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include <AppKit/AppKit.h>
  2. #include <Carbon/Carbon.h>
  3. #include <OpenGL/gl.h>
  4. #include <OpenGL/OpenGL.h>
  5. #include <brl.mod/systemdefault.mod/system.h>
  6. enum{
  7. FLAGS_BACKBUFFER= 0x2,
  8. FLAGS_ALPHABUFFER= 0x4,
  9. FLAGS_DEPTHBUFFER= 0x8,
  10. FLAGS_STENCILBUFFER=0x10,
  11. FLAGS_ACCUMBUFFER= 0x20,
  12. FLAGS_FULLSCREEN= 0x80000000
  13. };
  14. enum{
  15. MODE_WIDGET= 1,
  16. MODE_WINDOW= 2,
  17. MODE_DISPLAY= 3
  18. };
  19. @interface BBGLWindow : NSWindow{
  20. }
  21. @end
  22. @implementation BBGLWindow
  23. -(void)sendEvent:(NSEvent*)event{
  24. bbSystemEmitOSEvent( event,[self contentView],&bbNullObject );
  25. switch( [event type] ){
  26. case NSKeyDown:case NSKeyUp:
  27. //prevent 'beeps'!
  28. return;
  29. }
  30. [super sendEvent:event];
  31. }
  32. -(BOOL)windowShouldClose:(id)sender{
  33. bbSystemEmitEvent( BBEVENT_APPTERMINATE,&bbNullObject,0,0,0,0,&bbNullObject );
  34. return NO;
  35. }
  36. - (BOOL)canBecomeKeyWindow{
  37. return YES;
  38. }
  39. @end
  40. typedef struct BBGLContext BBGLContext;
  41. struct BBGLContext{
  42. int mode,width,height,depth,hertz;
  43. BBInt64 flags;
  44. int sync;
  45. NSView *view;
  46. BBGLWindow *window;
  47. NSOpenGLContext *glContext;
  48. };
  49. static BBGLContext *_currentContext;
  50. static BBGLContext *_displayContext;
  51. static CFDictionaryRef oldDisplayMode;
  52. extern void bbFlushAutoreleasePool();
  53. void bbGLGraphicsClose( BBGLContext *context );
  54. void bbGLGraphicsGetSettings( BBGLContext *context,int *width,int *height,int *depth,int *hertz,BBInt64 *flags );
  55. void bbGLGraphicsSetGraphics( BBGLContext *context );
  56. static int _initAttrs( CGLPixelFormatAttribute attrs[16],BBInt64 flags ){
  57. int n=0;
  58. if( flags & FLAGS_BACKBUFFER ) attrs[n++]=kCGLPFADoubleBuffer;
  59. if( flags & FLAGS_ALPHABUFFER ){ attrs[n++]=kCGLPFAAlphaSize;attrs[n++]=1; }
  60. if( flags & FLAGS_DEPTHBUFFER ){ attrs[n++]=kCGLPFADepthSize;attrs[n++]=24; }
  61. if( flags & FLAGS_STENCILBUFFER ){ attrs[n++]=kCGLPFAStencilSize;attrs[n++]=1; }
  62. if( flags & FLAGS_ACCUMBUFFER ){ attrs[n++]=kCGLPFAAccumSize;attrs[n++]=1; }
  63. if( flags & FLAGS_FULLSCREEN ){
  64. attrs[n++]=kCGLPFAFullScreen;
  65. attrs[n++]=kCGLPFADisplayMask;
  66. attrs[n++]=CGDisplayIDToOpenGLDisplayMask( kCGDirectMainDisplay );
  67. }else{
  68. attrs[n++]=kCGLPFANoRecovery;
  69. }
  70. attrs[n]=0;
  71. return n;
  72. }
  73. static NSOpenGLContext *_sharedContext;
  74. static void _validateSize( BBGLContext *context ){
  75. NSRect rect;
  76. if( !context || context->mode!=MODE_WIDGET ) return;
  77. rect=[context->view bounds];
  78. if( rect.size.width==context->width && rect.size.height==context->height ) return;
  79. context->width=rect.size.width;
  80. context->height=rect.size.height;
  81. if( context->glContext ) [context->glContext update];
  82. }
  83. static void _validateContext( BBGLContext *context ){
  84. BBInt64 flags;
  85. NSOpenGLContext *shared;
  86. NSOpenGLContext *glContext;
  87. NSOpenGLPixelFormat *glFormat;
  88. CGLPixelFormatAttribute attrs[16];
  89. if( !context || context->glContext ) return;
  90. flags=context->flags;
  91. // if( context->mode==MODE_DISPLAY ) flags|=FLAGS_FULLSCREEN;
  92. _initAttrs( attrs,flags );
  93. glFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
  94. glContext=[[NSOpenGLContext alloc] initWithFormat:glFormat shareContext:_sharedContext];
  95. [glFormat release];
  96. if( !glContext ) bbExThrowCString( "Unable to create GL Context" );
  97. switch( context->mode ){
  98. case MODE_WIDGET:
  99. [glContext setView:context->view];
  100. break;
  101. case MODE_WINDOW:
  102. case MODE_DISPLAY:
  103. [glContext setView:[context->window contentView]];
  104. break;
  105. }
  106. context->glContext=glContext;
  107. }
  108. void bbGLGraphicsShareContexts(){
  109. NSOpenGLPixelFormat *glFormat;
  110. CGLPixelFormatAttribute attrs[16];
  111. if( _sharedContext ) return;
  112. _initAttrs( attrs,0 );
  113. glFormat=[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
  114. _sharedContext=[[NSOpenGLContext alloc] initWithFormat:glFormat shareContext:0];
  115. [glFormat release];
  116. }
  117. int bbGLGraphicsGraphicsModes( int *modes,int count ){
  118. int i=0,n=0,sz;
  119. CFArrayRef displayModeArray;
  120. displayModeArray = CGDisplayCopyAllDisplayModes(kCGDirectMainDisplay, NULL);
  121. sz=CFArrayGetCount( displayModeArray );
  122. while( i<sz && n<count ){
  123. CGDisplayModeRef displayMode;
  124. int width,height,depth,hertz;
  125. CFStringRef format;
  126. displayMode=(CGDisplayModeRef)CFArrayGetValueAtIndex( displayModeArray,i++ );
  127. format = CGDisplayModeCopyPixelEncoding(displayMode);
  128. width = CGDisplayModeGetWidth(displayMode);
  129. height = CGDisplayModeGetHeight(displayMode);
  130. hertz = (CGDisplayModeGetRefreshRate(displayMode) + 0.5);
  131. if (CFStringCompare(format, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
  132. depth = 32;
  133. } else if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
  134. depth = 16;
  135. } else if (CFStringCompare(format, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
  136. depth = 30;
  137. } else if (CFStringCompare(format, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
  138. depth = 8;
  139. } else {
  140. depth = 0;
  141. }
  142. CFRelease(format);
  143. if (hertz == 0) {
  144. CVDisplayLinkRef link = NULL;
  145. CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &link);
  146. if (link != NULL) {
  147. CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
  148. if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) {
  149. hertz = (long) ((time.timeScale / (double) time.timeValue) + 0.5);
  150. }
  151. }
  152. }
  153. *modes++=width;
  154. *modes++=height;
  155. *modes++=depth;
  156. *modes++=hertz;
  157. ++n;
  158. }
  159. return n;
  160. }
  161. BBGLContext *bbGLGraphicsAttachGraphics( NSView *view,BBInt64 flags ){
  162. NSRect rect;
  163. BBGLContext *context;
  164. rect=[view bounds];
  165. context=(BBGLContext*)malloc( sizeof(BBGLContext) );
  166. memset( context,0,sizeof(BBGLContext) );
  167. context->mode=MODE_WIDGET;
  168. context->width=rect.size.width;
  169. context->height=rect.size.height;
  170. context->flags=flags;
  171. context->sync=-1;
  172. context->view=view;
  173. return context;
  174. }
  175. BBGLContext *bbGLGraphicsCreateGraphics( int width,int height,int depth,int hertz,BBInt64 flags, int x, int y ){
  176. int mode;
  177. BBGLWindow *window=0;
  178. BBGLContext *context;
  179. int sysv=0;
  180. Gestalt( 'sysv',&sysv );
  181. if( depth ){
  182. CFDictionaryRef displayMode;
  183. CGCaptureAllDisplays();
  184. oldDisplayMode=CGDisplayCurrentMode( kCGDirectMainDisplay );
  185. CFRetain( (CFTypeRef)oldDisplayMode );
  186. if( !hertz ){
  187. displayMode=CGDisplayBestModeForParameters( kCGDirectMainDisplay,depth,width,height,0 );
  188. }else{
  189. displayMode=CGDisplayBestModeForParametersAndRefreshRate( kCGDirectMainDisplay,depth,width,height,hertz,0 );
  190. }
  191. if( CGDisplaySwitchToMode( kCGDirectMainDisplay,displayMode ) ){
  192. CFRelease( (CFTypeRef)oldDisplayMode );
  193. bbExThrowCString( "Unable to set display mode" );
  194. }
  195. HideMenuBar();
  196. window=[[NSWindow alloc]
  197. initWithContentRect:NSMakeRect( 0,0,width,height )
  198. styleMask:NSBorderlessWindowMask
  199. backing:NSBackingStoreBuffered
  200. defer:YES];
  201. [window setOpaque:YES];
  202. [window setBackgroundColor:[NSColor blackColor]];
  203. [window setLevel:CGShieldingWindowLevel()];
  204. [window makeKeyAndOrderFront:NSApp];
  205. mode=MODE_DISPLAY;
  206. }else{
  207. if (x < 0) x = 0;
  208. if (y < 0) y = 0;
  209. window=[[BBGLWindow alloc]
  210. initWithContentRect:NSMakeRect( x, y,width,height )
  211. styleMask:NSTitledWindowMask|NSClosableWindowMask
  212. backing:NSBackingStoreBuffered
  213. defer:YES];
  214. if( !window ) return 0;
  215. [window setDelegate:window];
  216. [window setAcceptsMouseMovedEvents:YES];
  217. char *p=bbStringToUTF8String(bbAppTitle);
  218. [window setTitle:[NSString stringWithUTF8String:p]];
  219. [window center];
  220. bbMemFree(p);
  221. [window makeKeyAndOrderFront:NSApp];
  222. mode=MODE_WINDOW;
  223. }
  224. context=(BBGLContext*)malloc( sizeof(BBGLContext) );
  225. memset( context,0,sizeof(BBGLContext) );
  226. context->mode=mode;
  227. context->width=width;
  228. context->height=height;
  229. context->depth=depth;
  230. context->hertz=hertz;
  231. context->flags=flags;
  232. context->sync=-1;
  233. context->window=window;
  234. if( mode==MODE_DISPLAY ) _displayContext=context;
  235. return context;
  236. }
  237. void bbGLGraphicsGetSettings( BBGLContext *context,int *width,int *height,int *depth,int *hertz, BBInt64 *flags ){
  238. _validateSize( context );
  239. *width=context->width;
  240. *height=context->height;
  241. *depth=context->depth;
  242. *hertz=context->hertz;
  243. *flags=context->flags;
  244. }
  245. void bbGLGraphicsClose( BBGLContext *context ){
  246. if( context==_currentContext ) bbGLGraphicsSetGraphics( 0 );
  247. [context->glContext clearDrawable];
  248. [context->glContext release];
  249. switch( context->mode ){
  250. case MODE_WINDOW:
  251. case MODE_DISPLAY:
  252. bbSystemViewClosed( [context->window contentView] );
  253. [context->window close];
  254. break;
  255. }
  256. if( context==_displayContext ){
  257. CGDisplaySwitchToMode( kCGDirectMainDisplay,oldDisplayMode );
  258. CFRelease( (CFTypeRef)oldDisplayMode );
  259. CGReleaseAllDisplays();
  260. CGDisplayShowCursor( kCGDirectMainDisplay );
  261. ShowMenuBar();
  262. _displayContext=0;
  263. }
  264. free( context );
  265. }
  266. void bbGLGraphicsSetGraphics( BBGLContext *context ){
  267. if( context ){
  268. _validateSize( context );
  269. _validateContext( context );
  270. [context->glContext makeCurrentContext];
  271. }else{
  272. [NSOpenGLContext clearCurrentContext];
  273. }
  274. _currentContext=context;
  275. }
  276. static int updated;
  277. void bbGLGraphicsFlip( int sync ){
  278. if( !_currentContext ) return;
  279. sync=sync ? 1 : 0;
  280. static int _sync=-1;
  281. if( sync!=_currentContext->sync ){
  282. _currentContext->sync=sync;
  283. [_currentContext->glContext setValues:(long*)&sync forParameter:kCGLCPSwapInterval];
  284. }
  285. [_currentContext->glContext flushBuffer];
  286. // update the context, at least once - mojave needs this or nothing is rendered.
  287. if (!updated) {
  288. updated = 1;
  289. [_currentContext->glContext update];
  290. }
  291. }