/* * Copyright (c) 2002-2008 LWJGL Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'LWJGL' nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * $Id$ * * @author elias_naur * @author Pelle Johnsen * @author kappaOne * @version $Revision$ */ #import #include #include #include "awt_tools.h" #include "org_lwjgl_opengl_MacOSXCanvasPeerInfo.h" #include "context.h" #include "common_tools.h" JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nInitHandle (JNIEnv *env, jclass clazz, jobject lock_buffer_handle, jobject peer_info_handle, jobject window_handle, jboolean forceCALayer, jboolean autoResizable, jint x, jint y) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); AWTSurfaceLock *surface = (AWTSurfaceLock *)(*env)->GetDirectBufferAddress(env, lock_buffer_handle); JAWT_MacOSXDrawingSurfaceInfo *macosx_dsi = (JAWT_MacOSXDrawingSurfaceInfo *)surface->dsi->platformInfo; // force CALayer usage or check if CALayer is supported (i.e. on Java 5 and Java 6) if(forceCALayer || (surface->awt.version & 0x80000000)) { //JAWT_MACOSX_USE_CALAYER) { if (macosx_dsi != NULL) { if (window_handle == NULL) { window_handle = newJavaManagedByteBuffer(env, sizeof(MacOSXWindowInfo)); if (window_handle == NULL) { throwException(env, "Could not create handle buffer"); } } else if (peer_info->window_info->window != nil) { return window_handle; } if (peer_info->isCALayer) { [peer_info->glLayer release]; } peer_info->glLayer = [GLLayer new]; peer_info->glLayer->macosx_dsi = macosx_dsi; peer_info->window_info = (MacOSXWindowInfo *)(*env)->GetDirectBufferAddress(env, window_handle); peer_info->glLayer->window_info = peer_info->window_info; peer_info->glLayer->autoResizable = autoResizable; /* we set bounds as requested w/ frame function */ peer_info->glLayer.frame = CGRectMake(x, y, surface->dsi->bounds.width, surface->dsi->bounds.height); [peer_info->glLayer performSelectorOnMainThread:@selector(createWindow:) withObject:peer_info->pixel_format waitUntilDone:YES]; peer_info->isCALayer = true; peer_info->isWindowed = true; peer_info->parent = nil; [pool release]; return window_handle; } } // no CALayer support, fallback to using legacy method of getting the NSView of an AWT Canvas peer_info->parent = macosx_dsi->cocoaViewRef; peer_info->isCALayer = false; peer_info->isWindowed = true; [pool release]; return NULL; } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nSetLayerPosition (JNIEnv *env, jclass clazz, jobject peer_info_handle, jint x, jint y) { MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); if (peer_info->glLayer != nil) { NSPoint point = NSMakePoint(x, y); NSValue *value = [NSValue valueWithPoint:point]; [peer_info->glLayer performSelectorOnMainThread:@selector(updatePosition:) withObject:value waitUntilDone:NO]; } } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_MacOSXCanvasPeerInfo_nSetLayerBounds (JNIEnv *env, jclass clazz, jobject peer_info_handle, jint x, jint y, jint width, jint height) { MacOSXPeerInfo *peer_info = (MacOSXPeerInfo *)(*env)->GetDirectBufferAddress(env, peer_info_handle); if (peer_info->glLayer != nil) { NSRect rect = NSMakeRect(x, y, width, height); NSValue *value = [NSValue valueWithRect:rect]; [peer_info->glLayer performSelectorOnMainThread:@selector(updateBounds:) withObject:value waitUntilDone:NO]; } } @implementation GLLayer - (void) attachLayer { self.asynchronous = YES; self.needsDisplayOnBoundsChange = YES; self.opaque = NO; if (autoResizable) { self.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; } else { self.autoresizingMask = kCALayerNotSizable; } // get root layer of the AWT Canvas and add self to it id surfaceLayers = (id )macosx_dsi; if (surfaceLayers.layer != self) { surfaceLayers.layer = self; } } - (void) removeLayer { // clean up resources glDeleteFramebuffersEXT(1, &fboID); glDeleteRenderbuffersEXT(1, &imageRenderBufferID); glDeleteRenderbuffersEXT(1, &depthRenderBufferID); // finish any pending blits before destroying the offscreen window to prevent crashes glFinish(); // destroy offscreen Display window [self destroyWindow]; // remove self from root layer [self removeFromSuperlayer]; } - (void)updatePosition:(NSValue*)value { NSPoint point = [value pointValue]; self.position = CGPointMake(point.x, point.y); } - (void)updateBounds:(NSValue*)value { NSRect rect = [value rectValue]; self.frame = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } - (int) getWidth { return canvasBounds.width; } - (int) getHeight { return canvasBounds.height; } - (void) createWindow:(NSOpenGLPixelFormat*)pixel_format { if (window_info->window != nil) { [window_info->window close]; } window_info->display_rect = [[NSScreen mainScreen] frame]; window_info->view = [[MacOSXOpenGLView alloc] initWithFrame:window_info->display_rect pixelFormat:pixel_format]; window_info->window = [[MacOSXKeyableWindow alloc] initWithContentRect:window_info->display_rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; [window_info->window setContentView:window_info->view]; [window_info->window orderOut:nil]; } - (void) destroyWindow { if (window_info->window != nil) { [window_info->view removeFromSuperviewWithoutNeedingDisplay]; [window_info->window close]; window_info->window = nil; } } - (void) blitFrameBuffer { // get the size of the CALayer/AWT Canvas int width = self.bounds.size.width; int height = self.bounds.size.height; if (width != fboWidth || height != fboHeight) { // store current fbo/renderbuffers for later deletion int oldFboID = fboID; int oldImageRenderBufferID = imageRenderBufferID; int oldDepthRenderBufferID = depthRenderBufferID; // create new fbo int tempFBO; glGenFramebuffersEXT(1, &tempFBO); // create new render buffers glGenRenderbuffersEXT(1, &imageRenderBufferID); glGenRenderbuffersEXT(1, &depthRenderBufferID); // switch to new fbo to attach render buffers glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tempFBO); // initialize and attach image render buffer glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, imageRenderBufferID); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, imageRenderBufferID); // initialize and attach depth render buffer glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderBufferID); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthRenderBufferID); // clear garbage background on new fbo glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // blit frameBuffer to the new fbo glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tempFBO); glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); glFinish(); // finish before using new fbo and resizing the window // set new fbo and its sizes fboID = tempFBO; fboWidth = width; fboHeight = height; // set the size of the offscreen frame buffer window window_info->display_rect = NSMakeRect(0, 0, width, height); // clean up the old fbo and renderBuffers glDeleteFramebuffersEXT(1, &oldFboID); glDeleteRenderbuffersEXT(1, &oldImageRenderBufferID); glDeleteRenderbuffersEXT(1, &oldDepthRenderBufferID); } else { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboID); glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); } // restore default framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { // set the current context CGLSetCurrentContext(glContext); // get the size of the CALayer/AWT Canvas int width = self.bounds.size.width; int height = self.bounds.size.height; if (width != fboWidth || height != fboHeight) { // clear garbage background before lwjgl fbo blit glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } // read the LWJGL FBO and blit it into this CALayers FBO glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboID); glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); // call super to finalize the drawing - by default all it does is call glFlush() [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; } -(BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { return YES; } - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { CGLCreateContext(pixelFormat, [window_info->context CGLContextObj], &contextObject); return contextObject; } - (void)releaseCGLContext:(CGLContextObj)glContext { CGLClearDrawable(contextObject); // disable releasing context due to nvidia crash bug when releasing shared contexts //CGLDestroyContext(contextObject); } - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { return CGLGetPixelFormat([window_info->context CGLContextObj]); } - (void)releaseCGLPixelFormat:(CGLPixelFormatObj)pixelFormat { } @end