352 lines
7.4 KiB
Plaintext
352 lines
7.4 KiB
Plaintext
//
|
|
// LLOpenGLView.m
|
|
// SecondLife
|
|
//
|
|
// Created by Geenz on 10/2/12.
|
|
//
|
|
//
|
|
|
|
#import "llopenglview-objc.h"
|
|
|
|
@implementation LLOpenGLView
|
|
|
|
- (void)viewDidMoveToWindow
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(windowResized:) name:NSWindowDidResizeNotification
|
|
object:[self window]];
|
|
}
|
|
|
|
- (void)windowResized:(NSNotification *)notification;
|
|
{
|
|
NSSize size = [[self window] frame].size;
|
|
|
|
mResizeCallback(size.width, size.height);
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync
|
|
{
|
|
|
|
[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];
|
|
}
|
|
|
|
- (void) registerResizeCallback:(ResizeCallback)callback
|
|
{
|
|
mResizeCallback = callback;
|
|
}
|
|
|
|
// 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
|
|
{
|
|
[super mouseDragged:theEvent];
|
|
}
|
|
|
|
- (void) scrollWheel:(NSEvent *)theEvent
|
|
{
|
|
[super scrollWheel:theEvent];
|
|
}
|
|
|
|
- (void) mouseDown:(NSEvent *)theEvent
|
|
{
|
|
[super mouseDown:theEvent];
|
|
}
|
|
|
|
- (void) mouseUp:(NSEvent *)theEvent
|
|
{
|
|
[super mouseUp:theEvent];
|
|
}
|
|
|
|
- (void) rightMouseDown:(NSEvent *)theEvent
|
|
{
|
|
[super rightMouseDown:theEvent];
|
|
}
|
|
|
|
- (void) rightMouseUp:(NSEvent *)theEvent
|
|
{
|
|
[super rightMouseUp:theEvent];
|
|
}
|
|
|
|
- (void) keyUp:(NSEvent *)theEvent
|
|
{
|
|
[super keyUp:theEvent];
|
|
}
|
|
|
|
- (void) keyDown:(NSEvent *)theEvent
|
|
{
|
|
[super keyDown:theEvent];
|
|
}
|
|
|
|
- (void) mouseMoved:(NSEvent *)theEvent
|
|
{
|
|
[super mouseMoved:theEvent];
|
|
}
|
|
|
|
- (void) flagsChanged:(NSEvent *)theEvent
|
|
{
|
|
[super flagsChanged:theEvent];
|
|
}
|
|
|
|
@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 {
|
|
mKeyDownCallback([theEvent keyCode], [theEvent modifierFlags]);
|
|
|
|
NSString *chars = [theEvent charactersIgnoringModifiers];
|
|
for (uint i = 0; i < [chars length]; i++)
|
|
{
|
|
mUnicodeCallback([chars characterAtIndex:i], [theEvent modifierFlags]);
|
|
}
|
|
|
|
// The viewer expects return to be submitted separately as a unicode character.
|
|
if ([theEvent keyCode] == 3 || [theEvent keyCode] == 13)
|
|
{
|
|
mUnicodeCallback([theEvent keyCode], [theEvent modifierFlags]);
|
|
}
|
|
}
|
|
|
|
- (void) keyUp:(NSEvent *)theEvent {
|
|
mKeyUpCallback([theEvent keyCode], [theEvent modifierFlags]);
|
|
}
|
|
|
|
- (void)flagsChanged:(NSEvent *)theEvent {
|
|
mModifiers = [theEvent modifierFlags];
|
|
}
|
|
|
|
- (void) mouseDown:(NSEvent *)theEvent
|
|
{
|
|
if ([theEvent clickCount] == 2)
|
|
{
|
|
mMouseDoubleClickCallback(mMousePos, [theEvent modifierFlags]);
|
|
} else if ([theEvent clickCount] == 1) {
|
|
mMouseDownCallback(mMousePos, [theEvent modifierFlags]);
|
|
}
|
|
}
|
|
|
|
- (void) mouseUp:(NSEvent *)theEvent
|
|
{
|
|
mMouseUpCallback(mMousePos, [theEvent modifierFlags]);
|
|
}
|
|
|
|
- (void) rightMouseDown:(NSEvent *)theEvent
|
|
{
|
|
mRightMouseDownCallback(mMousePos, [theEvent modifierFlags]);
|
|
}
|
|
|
|
- (void) rightMouseUp:(NSEvent *)theEvent
|
|
{
|
|
mRightMouseUpCallback(mMousePos, [theEvent modifierFlags]);
|
|
}
|
|
|
|
- (void)mouseMoved:(NSEvent *)theEvent {
|
|
float mouseDeltas[2] = {
|
|
[theEvent deltaX],
|
|
[theEvent deltaZ]
|
|
};
|
|
|
|
mDeltaUpdateCallback(mouseDeltas, 0);
|
|
|
|
NSPoint mPoint = [theEvent locationInWindow];
|
|
mMousePos[0] = mPoint.x;
|
|
mMousePos[1] = mPoint.y;
|
|
mMouseMovedCallback(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
|
|
{
|
|
float mouseDeltas[2] = {
|
|
[theEvent deltaX],
|
|
[theEvent deltaZ]
|
|
};
|
|
|
|
mDeltaUpdateCallback(mouseDeltas, 0);
|
|
|
|
NSPoint mPoint = [theEvent locationInWindow];
|
|
mMousePos[0] = mPoint.x;
|
|
mMousePos[1] = mPoint.y;
|
|
mMouseMovedCallback(mMousePos, 0);
|
|
}
|
|
|
|
- (void) scrollWheel:(NSEvent *)theEvent
|
|
{
|
|
mScrollWhellCallback(-[theEvent deltaY]);
|
|
}
|
|
|
|
- (void) mouseExited:(NSEvent *)theEvent
|
|
{
|
|
mMouseExitCallback();
|
|
}
|
|
|
|
- (void) registerKeyDownCallback:(KeyCallback)callback
|
|
{
|
|
mKeyDownCallback = callback;
|
|
}
|
|
|
|
- (void) registerKeyUpCallback:(KeyCallback)callback
|
|
{
|
|
mKeyUpCallback = callback;
|
|
}
|
|
|
|
- (void) registerUnicodeCallback:(UnicodeCallback)callback
|
|
{
|
|
mUnicodeCallback = callback;
|
|
}
|
|
|
|
- (void) registerModifierCallback:(ModifierCallback)callback
|
|
{
|
|
mModifierCallback = callback;
|
|
}
|
|
|
|
- (void) registerMouseDownCallback:(MouseCallback)callback
|
|
{
|
|
mMouseDownCallback = callback;
|
|
}
|
|
|
|
- (void) registerMouseUpCallback:(MouseCallback)callback
|
|
{
|
|
mMouseUpCallback = callback;
|
|
}
|
|
|
|
- (void) registerRightMouseDownCallback:(MouseCallback)callback
|
|
{
|
|
mRightMouseDownCallback = callback;
|
|
}
|
|
|
|
- (void) registerRightMouseUpCallback:(MouseCallback)callback
|
|
{
|
|
mRightMouseUpCallback = callback;
|
|
}
|
|
|
|
- (void) registerDoubleClickCallback:(MouseCallback)callback
|
|
{
|
|
mMouseDoubleClickCallback = callback;
|
|
}
|
|
|
|
- (void) registerMouseMovedCallback:(MouseCallback)callback
|
|
{
|
|
mMouseMovedCallback = callback;
|
|
}
|
|
|
|
- (void) registerScrollCallback:(ScrollWheelCallback)callback
|
|
{
|
|
mScrollWhellCallback = callback;
|
|
}
|
|
|
|
- (void) registerMouseExitCallback:(VoidCallback)callback
|
|
{
|
|
mMouseExitCallback = callback;
|
|
}
|
|
|
|
- (void) registerDeltaUpdateCallback:(MouseCallback)callback
|
|
{
|
|
mDeltaUpdateCallback = callback;
|
|
}
|
|
|
|
@end |