1/* 2 * Copyright (c) 2002-2008 LWJGL Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'LWJGL' nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/** 34 * $Id$ 35 * 36 * @author elias_naur <elias_naur@users.sourceforge.net> 37 * @author Pelle Johnsen 38 * @author kappaOne <one.kappa@gmail.com> 39 * @version $Revision$ 40 */ 41 42#import <Cocoa/Cocoa.h> 43#include <jni.h> 44#include <jawt_md.h> 45#include "awt_tools.h" 46#include "org_lwjgl_opengl_MacOSXCanvasPeerInfo.h" 47#include "context.h" 48#include "common_tools.h" 49 50JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle 51(JNIEnv *env, jclass clazz, jobject lock_buffer_handle, jobject peer_info_handle, jobject window_handle, jboolean forceCALayer, jboolean autoResizable, jint x, jint y) { 52 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 53 54 MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); 55 AWTSurfaceLock *surface = (AWTSurfaceLock *)(*env)->GetDirectBufferAddress(env, lock_buffer_handle); 56 JAWT_MacOSXDrawingSurfaceInfo *macosx_dsi = (JAWT_MacOSXDrawingSurfaceInfo *)surface->dsi->platformInfo; 57 58 // force CALayer usage or check if CALayer is supported (i.e. on Java 5 and Java 6) 59 if(forceCALayer || (surface->awt.version & 0x80000000)) { //JAWT_MACOSX_USE_CALAYER) { 60 61 if (macosx_dsi != NULL) { 62 63 if (window_handle == NULL) { 64 window_handle = newJavaManagedByteBuffer(env, sizeof(MacOSXWindowInfo)); 65 if (window_handle == NULL) { 66 throwException(env, "Could not create handle buffer"); 67 } 68 } else if (peer_info->window_info->window != nil) { 69 return window_handle; 70 } 71 72 if (peer_info->isCALayer) { 73 [peer_info->glLayer release]; 74 } 75 76 peer_info->glLayer = [GLLayer new]; 77 78 peer_info->glLayer->macosx_dsi = macosx_dsi; 79 peer_info->window_info = (MacOSXWindowInfo *)(*env)->GetDirectBufferAddress(env, window_handle); 80 peer_info->glLayer->window_info = peer_info->window_info; 81 peer_info->glLayer->autoResizable = autoResizable; 82 83 /* we set bounds as requested w/ frame function */ 84 peer_info->glLayer.frame = CGRectMake(x, y, surface->dsi->bounds.width, surface->dsi->bounds.height); 85 86 [peer_info->glLayer performSelectorOnMainThread:@selector(createWindow:) withObject:peer_info->pixel_format waitUntilDone:YES]; 87 88 peer_info->isCALayer = true; 89 peer_info->isWindowed = true; 90 peer_info->parent = nil; 91 92 [pool release]; 93 return window_handle; 94 } 95 } 96 97 // no CALayer support, fallback to using legacy method of getting the NSView of an AWT Canvas 98 peer_info->parent = macosx_dsi->cocoaViewRef; 99 peer_info->isCALayer = false; 100 peer_info->isWindowed = true; 101 102 [pool release]; 103 return NULL; 104} 105 106JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nSetLayerPosition 107(JNIEnv *env, jclass clazz, jobject peer_info_handle, jint x, jint y) { 108 MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); 109 110 if (peer_info->glLayer != nil) { 111 NSPoint point = NSMakePoint(x, y); 112 NSValue *value = [NSValue valueWithPoint:point]; 113 [peer_info->glLayer performSelectorOnMainThread:@selector(updatePosition:) withObject:value waitUntilDone:NO]; 114 } 115} 116 117JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nSetLayerBounds 118(JNIEnv *env, jclass clazz, jobject peer_info_handle, jint x, jint y, jint width, jint height) { 119 MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); 120 121 if (peer_info->glLayer != nil) { 122 NSRect rect = NSMakeRect(x, y, width, height); 123 NSValue *value = [NSValue valueWithRect:rect]; 124 [peer_info->glLayer performSelectorOnMainThread:@selector(updateBounds:) withObject:value waitUntilDone:NO]; 125 } 126} 127 128@implementation GLLayer 129 130- (void) attachLayer { 131 self.asynchronous = YES; 132 self.needsDisplayOnBoundsChange = YES; 133 self.opaque = NO; 134 if (autoResizable) { 135 self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 136 } 137 else { 138 self.autoresizingMask = kCALayerNotSizable; 139 } 140 141 // get root layer of the AWT Canvas and add self to it 142 id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)macosx_dsi; 143 144 if (surfaceLayers.layer != self) { 145 surfaceLayers.layer = self; 146 } 147} 148 149- (void) removeLayer { 150 151 // clean up resources 152 glDeleteFramebuffersEXT(1, &fboID); 153 glDeleteRenderbuffersEXT(1, &imageRenderBufferID); 154 glDeleteRenderbuffersEXT(1, &depthRenderBufferID); 155 156 // finish any pending blits before destroying the offscreen window to prevent crashes 157 glFinish(); 158 159 // destroy offscreen Display window 160 [self destroyWindow]; 161 162 // remove self from root layer 163 [self removeFromSuperlayer]; 164} 165 166- (void)updatePosition:(NSValue*)value { 167 NSPoint point = [value pointValue]; 168 self.position = CGPointMake(point.x, point.y); 169} 170 171- (void)updateBounds:(NSValue*)value { 172 NSRect rect = [value rectValue]; 173 self.frame = CGRectMake(rect.origin.x, rect.origin.y, 174 rect.size.width, rect.size.height); 175} 176 177- (int) getWidth { 178 return canvasBounds.width; 179} 180 181- (int) getHeight { 182 return canvasBounds.height; 183} 184 185- (void) createWindow:(NSOpenGLPixelFormat*)pixel_format { 186 if (window_info->window != nil) { 187 [window_info->window close]; 188 } 189 190 window_info->display_rect = [[NSScreen mainScreen] frame]; 191 192 window_info->view = [[MacOSXOpenGLView alloc] initWithFrame:window_info->display_rect pixelFormat:pixel_format]; 193 194 window_info->window = [[MacOSXKeyableWindow alloc] initWithContentRect:window_info->display_rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 195 [window_info->window setContentView:window_info->view]; 196 197 [window_info->window orderOut:nil]; 198} 199 200- (void) destroyWindow { 201 if (window_info->window != nil) { 202 [window_info->view removeFromSuperviewWithoutNeedingDisplay]; 203 [window_info->window close]; 204 window_info->window = nil; 205 } 206} 207 208- (void) blitFrameBuffer { 209 210 // get the size of the CALayer/AWT Canvas 211 int width = self.bounds.size.width; 212 int height = self.bounds.size.height; 213 214 if (width != fboWidth || height != fboHeight) { 215 216 // store current fbo/renderbuffers for later deletion 217 int oldFboID = fboID; 218 int oldImageRenderBufferID = imageRenderBufferID; 219 int oldDepthRenderBufferID = depthRenderBufferID; 220 221 // create new fbo 222 int tempFBO; 223 glGenFramebuffersEXT(1, &tempFBO); 224 225 // create new render buffers 226 glGenRenderbuffersEXT(1, &imageRenderBufferID); 227 glGenRenderbuffersEXT(1, &depthRenderBufferID); 228 229 // switch to new fbo to attach render buffers 230 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tempFBO); 231 232 // initialize and attach image render buffer 233 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, imageRenderBufferID); 234 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height); 235 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, imageRenderBufferID); 236 237 // initialize and attach depth render buffer 238 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderBufferID); 239 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height); 240 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthRenderBufferID); 241 242 // clear garbage background on new fbo 243 glClearColor(0.0, 0.0, 0.0, 1.0); 244 glClear(GL_COLOR_BUFFER_BIT); 245 246 // blit frameBuffer to the new fbo 247 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 248 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tempFBO); 249 glBlitFramebufferEXT(0, 0, width, height, 250 0, 0, width, height, 251 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 252 GL_NEAREST); 253 254 glFinish(); // finish before using new fbo and resizing the window 255 256 // set new fbo and its sizes 257 fboID = tempFBO; 258 fboWidth = width; 259 fboHeight = height; 260 261 // set the size of the offscreen frame buffer window 262 window_info->display_rect = NSMakeRect(0, 0, width, height); 263 264 // clean up the old fbo and renderBuffers 265 glDeleteFramebuffersEXT(1, &oldFboID); 266 glDeleteRenderbuffersEXT(1, &oldImageRenderBufferID); 267 glDeleteRenderbuffersEXT(1, &oldDepthRenderBufferID); 268 } 269 else { 270 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 271 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboID); 272 273 glBlitFramebufferEXT(0, 0, width, height, 274 0, 0, width, height, 275 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 276 GL_NEAREST); 277 } 278 279 // restore default framebuffer 280 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 281} 282 283-(void)drawInCGLContext:(CGLContextObj)glContext 284 pixelFormat:(CGLPixelFormatObj)pixelFormat 285 forLayerTime:(CFTimeInterval)timeInterval 286 displayTime:(const CVTimeStamp *)timeStamp { 287 288 // set the current context 289 CGLSetCurrentContext(glContext); 290 291 // get the size of the CALayer/AWT Canvas 292 int width = self.bounds.size.width; 293 int height = self.bounds.size.height; 294 295 if (width != fboWidth || height != fboHeight) { 296 // clear garbage background before lwjgl fbo blit 297 glClearColor(0.0, 0.0, 0.0, 1.0); 298 glClear(GL_COLOR_BUFFER_BIT); 299 } 300 301 // read the LWJGL FBO and blit it into this CALayers FBO 302 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboID); 303 glBlitFramebufferEXT(0, 0, width, height, 304 0, 0, width, height, 305 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, 306 GL_NEAREST); 307 308 // call super to finalize the drawing - by default all it does is call glFlush() 309 [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; 310} 311 312-(BOOL)canDrawInCGLContext:(CGLContextObj)glContext 313 pixelFormat:(CGLPixelFormatObj)pixelFormat 314 forLayerTime:(CFTimeInterval)timeInterval 315 displayTime:(const CVTimeStamp *)timeStamp { 316 return YES; 317} 318 319- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { 320 CGLCreateContext(pixelFormat, [window_info->context CGLContextObj], &contextObject); 321 return contextObject; 322} 323 324- (void)releaseCGLContext:(CGLContextObj)glContext { 325 CGLClearDrawable(contextObject); 326 // disable releasing context due to nvidia crash bug when releasing shared contexts 327 //CGLDestroyContext(contextObject); 328} 329 330- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { 331 return CGLGetPixelFormat([window_info->context CGLContextObj]); 332} 333 334- (void)releaseCGLPixelFormat:(CGLPixelFormatObj)pixelFormat { 335 336} 337 338@end