summaryrefslogtreecommitdiff
path: root/indra/llwindow/llopenglview-objc.mm
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow/llopenglview-objc.mm')
-rw-r--r--indra/llwindow/llopenglview-objc.mm473
1 files changed, 473 insertions, 0 deletions
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
new file mode 100644
index 0000000000..b79b7b3fa5
--- /dev/null
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -0,0 +1,473 @@
+//
+// LLOpenGLView.m
+// SecondLife
+//
+// Created by Geenz on 10/2/12.
+//
+//
+
+#import "llopenglview-objc.h"
+
+@implementation NSScreen (PointConversion)
+
++ (NSScreen *)currentScreenForMouseLocation
+{
+ NSPoint mouseLocation = [NSEvent mouseLocation];
+
+ NSEnumerator *screenEnumerator = [[NSScreen screens] objectEnumerator];
+ NSScreen *screen;
+ while ((screen = [screenEnumerator nextObject]) && !NSMouseInRect(mouseLocation, screen.frame, NO))
+ ;
+
+ return screen;
+}
+
+- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint
+{
+ float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x));
+ float normalizedY = aPoint.y - self.frame.origin.y;
+
+ return NSMakePoint(normalizedX, normalizedY);
+}
+
+- (NSPoint)flipPoint:(NSPoint)aPoint
+{
+ return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+}
+
+@end
+
+@implementation LLOpenGLView
+
+- (void)viewDidMoveToWindow
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowResized:) name:NSWindowDidResizeNotification
+ object:[self window]];
+}
+
+- (void)windowResized:(NSNotification *)notification;
+{
+ NSSize size = [self frame].size;
+
+ callResize(size.width, size.height);
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (id) init
+{
+ //[self registerForDraggedTypes:[NSArray arrayWithObjects:NSURLPboardType, NSFilenamesPboardType, nil]];
+ return [self initWithFrame:[self bounds] withSamples:2 andVsync:TRUE];
+}
+
+- (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync
+{
+ [self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]];
+ [self initWithFrame:frame];
+
+ // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6.
+ // Any specialized pixel formats, i.e. a core profile pixel format, should be initialized through rebuildContextWithFormat.
+ // 10.7 and 10.8 don't really care if we're defining a profile or not. If we don't explicitly request a core or legacy profile, it'll always assume a legacy profile (for compatibility reasons).
+ NSOpenGLPixelFormatAttribute attrs[] = {
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAClosestPolicy,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFASampleBuffers, (samples > 0 ? 1 : 0),
+ NSOpenGLPFASamples, samples,
+ NSOpenGLPFAStencilSize, 8,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ NSOpenGLPFAColorSize, 24,
+ 0
+ };
+
+ NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease];
+
+ if (pixelFormat == nil)
+ {
+ NSLog(@"Failed to create pixel format!", nil);
+ return nil;
+ }
+
+ NSOpenGLContext *glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
+
+ if (glContext == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return nil;
+ }
+
+ [self setPixelFormat:pixelFormat];
+
+ [self setOpenGLContext:glContext];
+
+ [glContext setView:self];
+
+ [glContext makeCurrentContext];
+
+ if (vsync)
+ {
+ [glContext setValues:(const GLint*)1 forParameter:NSOpenGLCPSwapInterval];
+ } else {
+ [glContext setValues:(const GLint*)0 forParameter:NSOpenGLCPSwapInterval];
+ }
+
+ return self;
+}
+
+- (BOOL) rebuildContext
+{
+ return [self rebuildContextWithFormat:[self pixelFormat]];
+}
+
+- (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format
+{
+ NSOpenGLContext *ctx = [self openGLContext];
+
+ [ctx clearDrawable];
+ [ctx initWithFormat:format shareContext:nil];
+
+ if (ctx == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return false;
+ }
+
+ [self setOpenGLContext:ctx];
+ [ctx setView:self];
+ [ctx makeCurrentContext];
+ return true;
+}
+
+- (CGLContextObj)getCGLContextObj
+{
+ NSOpenGLContext *ctx = [self openGLContext];
+ return (CGLContextObj)[ctx CGLContextObj];
+}
+
+- (CGLPixelFormatObj*)getCGLPixelFormatObj
+{
+ NSOpenGLPixelFormat *fmt = [self pixelFormat];
+ return (CGLPixelFormatObj*)[fmt CGLPixelFormatObj];
+}
+
+// Various events can be intercepted by our view, thus not reaching our window.
+// Intercept these events, and pass them to the window as needed. - Geenz
+
+- (void) mouseDragged:(NSEvent *)theEvent
+{
+ [_window mouseDragged:theEvent];
+}
+
+- (void) scrollWheel:(NSEvent *)theEvent
+{
+ [_window scrollWheel:theEvent];
+}
+
+- (void) mouseDown:(NSEvent *)theEvent
+{
+ [_window mouseDown:theEvent];
+}
+
+- (void) mouseUp:(NSEvent *)theEvent
+{
+ [_window mouseUp:theEvent];
+}
+
+- (void) rightMouseDown:(NSEvent *)theEvent
+{
+ [_window rightMouseDown:theEvent];
+}
+
+- (void) rightMouseUp:(NSEvent *)theEvent
+{
+ [_window rightMouseUp:theEvent];
+}
+
+- (void) otherMouseDown:(NSEvent *)theEvent
+{
+ [_window otherMouseDown:theEvent];
+}
+
+- (void) otherMouseUp:(NSEvent *)theEvent
+{
+ [_window otherMouseUp:theEvent];
+}
+
+- (void) keyUp:(NSEvent *)theEvent
+{
+ [_window keyUp:theEvent];
+}
+
+- (void) keyDown:(NSEvent *)theEvent
+{
+ [_window keyDown:theEvent];
+}
+
+- (void) mouseMoved:(NSEvent *)theEvent
+{
+ [_window mouseMoved:theEvent];
+}
+
+- (void) flagsChanged:(NSEvent *)theEvent
+{
+ [_window flagsChanged:theEvent];
+}
+
+- (void) mouseExited:(NSEvent *)theEvent
+{
+ [_window mouseExited:theEvent];
+}
+
+- (BOOL) becomeFirstResponder
+{
+ return [_window becomeFirstResponder];
+}
+
+- (BOOL) resignFirstResponder
+{
+ return [_window resignFirstResponder];
+}
+
+- (NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender
+{
+ NSPasteboard *pboard;
+ NSDragOperation sourceDragMask;
+
+ sourceDragMask = [sender draggingSourceOperationMask];
+
+ pboard = [sender draggingPasteboard];
+
+ if ([[pboard types] containsObject:NSURLPboardType])
+ {
+ if (sourceDragMask & NSDragOperationLink) {
+ NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0];
+ mLastDraggedUrl = [[fileUrl absoluteString] UTF8String];
+ return NSDragOperationLink;
+ }
+ }
+ return NSDragOperationNone;
+}
+
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ callHandleDragUpdated(mLastDraggedUrl);
+
+ return NSDragOperationLink;
+}
+
+- (void) draggingExited:(id<NSDraggingInfo>)sender
+{
+ callHandleDragExited(mLastDraggedUrl);
+}
+
+- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
+{
+ return YES;
+}
+
+- (BOOL) performDragOperation:(id<NSDraggingInfo>)sender
+{
+ callHandleDragDropped(mLastDraggedUrl);
+ return true;
+}
+
+@end
+
+// We use a custom NSWindow for our event handling.
+// Why not an NSWindowController you may ask?
+// Answer: this is easier.
+
+@implementation LLNSWindow
+
+- (id) init
+{
+
+ return self;
+}
+
+- (void) keyDown:(NSEvent *)theEvent
+{
+ uint keycode = [theEvent keyCode];
+
+ switch (keycode) {
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ callKeyDown(keycode, mModifiers);
+ break;
+
+ default:
+ callKeyDown(keycode, mModifiers);
+ NSString *chars = [theEvent characters];
+ for (uint i = 0; i < [chars length]; i++) {
+ // Enter and Return are special cases.
+ unichar returntest = [chars characterAtIndex:i];
+ if ((returntest == NSCarriageReturnCharacter || returntest == NSEnterCharacter) &&
+ !([theEvent modifierFlags] & NSCommandKeyMask) &&
+ !([theEvent modifierFlags] & NSAlternateKeyMask) &&
+ !([theEvent modifierFlags] & NSControlKeyMask))
+ {
+ callUnicodeCallback(13, 0);
+ } else {
+ // The command key being pressed is also a special case.
+ // Control + <character> produces an ASCII control character code.
+ // Command + <character> produces just the character's code.
+ // Check to see if the command key is pressed, then filter through the different character ranges that are relevant to control characters, and subtract the appropriate range.
+ if ([theEvent modifierFlags] & NSCommandKeyMask)
+ {
+ if (returntest >= 64 && returntest <= 95)
+ {
+ callUnicodeCallback(returntest - 63, mModifiers);
+ } else if (returntest >= 97 && returntest <= 122)
+ {
+ callUnicodeCallback(returntest - 96, mModifiers);
+ }
+ } else {
+ callUnicodeCallback(returntest, mModifiers);
+ }
+ }
+ }
+ break;
+ }
+}
+
+- (void) keyUp:(NSEvent *)theEvent {
+ callKeyUp([theEvent keyCode], mModifiers);
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent {
+ mModifiers = [theEvent modifierFlags];
+}
+
+- (void) mouseDown:(NSEvent *)theEvent
+{
+ if ([theEvent clickCount] >= 2)
+ {
+ callDoubleClick(mMousePos, mModifiers);
+ } else if ([theEvent clickCount] == 1) {
+ callLeftMouseDown(mMousePos, mModifiers);
+ }
+}
+
+- (void) mouseUp:(NSEvent *)theEvent
+{
+ callLeftMouseUp(mMousePos, mModifiers);
+}
+
+- (void) rightMouseDown:(NSEvent *)theEvent
+{
+ callRightMouseDown(mMousePos, mModifiers);
+}
+
+- (void) rightMouseUp:(NSEvent *)theEvent
+{
+ callRightMouseUp(mMousePos, mModifiers);
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+ float mouseDeltas[2] = {
+ [theEvent deltaX],
+ [theEvent deltaY]
+ };
+
+ callDeltaUpdate(mouseDeltas, 0);
+
+ NSPoint mPoint = [theEvent locationInWindow];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseMoved(mMousePos, 0);
+}
+
+// NSWindow doesn't trigger mouseMoved when the mouse is being clicked and dragged.
+// Use mouseDragged for situations like this to trigger our movement callback instead.
+
+- (void) mouseDragged:(NSEvent *)theEvent
+{
+ // Trust the deltas supplied by NSEvent.
+ // The old CoreGraphics APIs we previously relied on are now flagged as obsolete.
+ // NSEvent isn't obsolete, and provides us with the correct deltas.
+ float mouseDeltas[2] = {
+ [theEvent deltaX],
+ [theEvent deltaY]
+ };
+
+ callDeltaUpdate(mouseDeltas, 0);
+
+ NSPoint mPoint = [theEvent locationInWindow];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseMoved(mMousePos, 0);
+}
+
+- (void) otherMouseDown:(NSEvent *)theEvent
+{
+ callMiddleMouseDown(mMousePos, mModifiers);
+}
+
+- (void) otherMouseUp:(NSEvent *)theEvent
+{
+ callMiddleMouseUp(mMousePos, mModifiers);
+}
+
+- (void) otherMouseDragged:(NSEvent *)theEvent
+{
+
+}
+
+- (void) scrollWheel:(NSEvent *)theEvent
+{
+ callScrollMoved(-[theEvent deltaY]);
+}
+
+- (void) mouseExited:(NSEvent *)theEvent
+{
+ callMouseExit();
+}
+
+
+
+- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view
+{
+ NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation];
+ if(currentScreen)
+ {
+ NSPoint windowPoint = [view convertPoint:point toView:nil];
+ NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
+ NSPoint flippedScreenPoint = [currentScreen flipPoint:screenPoint];
+ flippedScreenPoint.y += [currentScreen frame].origin.y;
+
+ return flippedScreenPoint;
+ }
+
+ return NSZeroPoint;
+}
+
+- (NSPoint)flipPoint:(NSPoint)aPoint
+{
+ return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+}
+
+- (BOOL) becomeFirstResponder
+{
+ NSLog(@"Window gained focus!");
+ callFocus();
+ return true;
+}
+
+- (BOOL) resignFirstResponder
+{
+ NSLog(@"Window lost focus!");
+ callFocus();
+ return true;
+}
+
+@end