From fc5994910dd841000e2a449ab72eae18bc052be2 Mon Sep 17 00:00:00 2001 From: Joshua Moerman Date: Sat, 8 Mar 2014 22:09:04 +0100 Subject: [PATCH] initial commit --- .gitignore | 4 + GLEssentials/Fractal-iOS.fsh | 22 + GLEssentials/Fractal-iOS.vsh | 18 + GLEssentials/Fractal.fsh | 26 + GLEssentials/Fractal.vsh | 18 + GLEssentials/Game.h | 14 + GLEssentials/Game.m | 123 ++++ GLEssentials/OSX/GLEssentials-Info.plist | 30 + .../OSX/GLEssentialsFullscreenWindow.h | 12 + .../OSX/GLEssentialsFullscreenWindow.m | 41 ++ GLEssentials/OSX/GLEssentialsGLView.h | 12 + GLEssentials/OSX/GLEssentialsGLView.m | 219 +++++++ .../OSX/GLEssentialsWindowController.h | 16 + .../OSX/GLEssentialsWindowController.m | 108 ++++ GLEssentials/OSX/MainMenu.xib | 588 ++++++++++++++++++ GLEssentials/OSX/main.m | 5 + GLEssentials/iOS/AppDelegate.h | 13 + GLEssentials/iOS/AppDelegate.m | 40 ++ GLEssentials/iOS/GLEssentials-Info.plist | 49 ++ GLEssentials/iOS/Main_iPad.storyboard | 26 + GLEssentials/iOS/Main_iPhone.storyboard | 26 + GLEssentials/iOS/ViewController.h | 12 + GLEssentials/iOS/ViewController.m | 90 +++ GLEssentials/iOS/main.m | 8 + OSXGLEssentials.xcodeproj/project.pbxproj | 254 ++++++++ README.md | 20 + Readme.txt | 32 + iOSGLEssentials.xcodeproj/project.pbxproj | 269 ++++++++ 28 files changed, 2095 insertions(+) create mode 100644 .gitignore create mode 100644 GLEssentials/Fractal-iOS.fsh create mode 100644 GLEssentials/Fractal-iOS.vsh create mode 100644 GLEssentials/Fractal.fsh create mode 100644 GLEssentials/Fractal.vsh create mode 100644 GLEssentials/Game.h create mode 100644 GLEssentials/Game.m create mode 100644 GLEssentials/OSX/GLEssentials-Info.plist create mode 100644 GLEssentials/OSX/GLEssentialsFullscreenWindow.h create mode 100644 GLEssentials/OSX/GLEssentialsFullscreenWindow.m create mode 100644 GLEssentials/OSX/GLEssentialsGLView.h create mode 100644 GLEssentials/OSX/GLEssentialsGLView.m create mode 100644 GLEssentials/OSX/GLEssentialsWindowController.h create mode 100644 GLEssentials/OSX/GLEssentialsWindowController.m create mode 100644 GLEssentials/OSX/MainMenu.xib create mode 100644 GLEssentials/OSX/main.m create mode 100644 GLEssentials/iOS/AppDelegate.h create mode 100644 GLEssentials/iOS/AppDelegate.m create mode 100644 GLEssentials/iOS/GLEssentials-Info.plist create mode 100644 GLEssentials/iOS/Main_iPad.storyboard create mode 100644 GLEssentials/iOS/Main_iPhone.storyboard create mode 100644 GLEssentials/iOS/ViewController.h create mode 100644 GLEssentials/iOS/ViewController.m create mode 100644 GLEssentials/iOS/main.m create mode 100644 OSXGLEssentials.xcodeproj/project.pbxproj create mode 100644 README.md create mode 100644 Readme.txt create mode 100755 iOSGLEssentials.xcodeproj/project.pbxproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b5da70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +*.xcworkspace +*.xcuser* + diff --git a/GLEssentials/Fractal-iOS.fsh b/GLEssentials/Fractal-iOS.fsh new file mode 100644 index 0000000..3cfb9e6 --- /dev/null +++ b/GLEssentials/Fractal-iOS.fsh @@ -0,0 +1,22 @@ +#version 100 + +varying highp vec2 pos; +varying highp vec2 start; + +void main(){ + + highp vec2 z = start; + + int i = 0; + for (i = 0; i < 7; i++) { + highp vec2 zsq = z*z; + if(zsq.x + zsq.y > 16.0) break; + + highp float t = zsq.x - zsq.y + pos.x; + z.y = 2.0*z.x*z.y + pos.y; + z.x = t; + } + + gl_FragColor = vec4(float(i) / 7.0); + gl_FragColor.bg = 0.5 * sin(z) + 0.5; +} diff --git a/GLEssentials/Fractal-iOS.vsh b/GLEssentials/Fractal-iOS.vsh new file mode 100644 index 0000000..fda0dde --- /dev/null +++ b/GLEssentials/Fractal-iOS.vsh @@ -0,0 +1,18 @@ +#version 100 + +uniform float rotation; + +attribute vec4 position; +attribute vec4 color; + +varying vec2 pos; +varying vec2 start; + +void main(){ + pos = position.xy; + pos.x -= 0.5; + + start = sqrt(1.0 + 0.01 * rotation) * 0.3 * sin(vec2(0.1, 0.1337) * rotation); + + gl_Position = position; +} diff --git a/GLEssentials/Fractal.fsh b/GLEssentials/Fractal.fsh new file mode 100644 index 0000000..d4ca0da --- /dev/null +++ b/GLEssentials/Fractal.fsh @@ -0,0 +1,26 @@ +#version 330 + +uniform float rotation; + +in vec2 pos; +in vec2 start; + +out vec4 fragColor; + +void main(){ + + vec2 z = start; + + int i = 0; + for (i = 0; i < 30; i++) { + vec2 zsq = z*z; + if(zsq.x + zsq.y > 16.0) break; + + float t = zsq.x - zsq.y + pos.x; + z.y = 2.0*z.x*z.y + pos.y; + z.x = t; + } + + fragColor = vec4(float(i) / 30.0); + fragColor.bg = 0.5 * sin(z) + 0.5; +} diff --git a/GLEssentials/Fractal.vsh b/GLEssentials/Fractal.vsh new file mode 100644 index 0000000..329f2d2 --- /dev/null +++ b/GLEssentials/Fractal.vsh @@ -0,0 +1,18 @@ +#version 330 + +uniform float rotation; + +in vec4 position; +in vec4 color; + +out vec2 pos; +out vec2 start; + +void main(){ + pos = position.xy; + pos.x -= 0.5; + + start = sqrt(1.0 + 0.01 * rotation) * 0.3 * sin(vec2(0.1, 0.1337) * rotation); + + gl_Position = position; +} diff --git a/GLEssentials/Game.h b/GLEssentials/Game.h new file mode 100644 index 0000000..49bb436 --- /dev/null +++ b/GLEssentials/Game.h @@ -0,0 +1,14 @@ +// +// Game.h +// iOSGLEssentials +// +// Created by Joshua Moerman on 08/03/14. +// +// + +@import Foundation; + +@interface Game : NSObject +- (void)update:(float)dt; +- (void)draw; +@end diff --git a/GLEssentials/Game.m b/GLEssentials/Game.m new file mode 100644 index 0000000..afc9dcf --- /dev/null +++ b/GLEssentials/Game.m @@ -0,0 +1,123 @@ +// +// Game.m +// iOSGLEssentials +// +// Created by Joshua Moerman on 08/03/14. +// +// + +#import "Game.h" +@import GLKit; + +#ifdef ESSENTIAL_GL_PRACTICES_IOS +#define glBindVertexArray glBindVertexArrayOES +#define glGenVertexArrays glGenVertexArraysOES +#define glDeleteVertexArrays glDeleteVertexArraysOES +#endif + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + + +#ifdef ESSENTIAL_GL_PRACTICES_IOS +NSString * file = @"Fractal-iOS"; +#else +NSString * file = @"Fractal"; +#endif + +const GLfloat quad[] = { + // x y z, r g b + 1, -1, 0, 1, 0, 0, + -1, -1, 0, 0, 1, 0, + 1, 1, 0, 0, 0, 1, + -1, 1, 0, 1, 1, 1 +}; + +static void check_shader(GLuint s){ + GLint logLength; + glGetShaderiv(s, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)malloc(logLength); + glGetShaderInfoLog(s, logLength, &logLength, log); + NSLog(@"Shader compile log:\n%s", log); + free(log); + } +} + +@implementation Game{ + float time; + GLuint program; + GLint uniform; + GLuint vao; + GLuint posBufferName; +} + +- (id)init{ + if(self = [super init]){ + time = 0; + program = glCreateProgram(); + + NSError * error = nil; + + NSString * vs = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:file ofType:@"vsh"] encoding:NSASCIIStringEncoding error:&error]; + NSString * fs = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:file ofType:@"fsh"] encoding:NSASCIIStringEncoding error:nil]; + + GLchar const * vs_cstr = [vs UTF8String]; + GLchar const * fs_cstr = [fs UTF8String]; + + GLuint v = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(v, 1, &vs_cstr, NULL); + glCompileShader(v); + check_shader(v); + + GLuint f = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(f, 1, &fs_cstr, NULL); + glCompileShader(f); + check_shader(f); + + glAttachShader(program, v); + glAttachShader(program, f); + + glBindAttribLocation(program, 0, "position"); + glBindAttribLocation(program, 1, "color"); + + glLinkProgram(program); + + uniform = glGetUniformLocation(program, "rotation"); + + glDetachShader(program, v); + glDeleteShader(v); + glDetachShader(program, f); + glDeleteShader(f); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &posBufferName); + glBindBuffer(GL_ARRAY_BUFFER, posBufferName); + glBufferData(GL_ARRAY_BUFFER, 4*6*4, quad, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*4, BUFFER_OFFSET(0)); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*4, BUFFER_OFFSET(3*4)); + } + return self; +} + +- (void)update:(float)dt{ + time += dt; +} + +- (void)draw{ + glClearColor(0.65f, 0.65f, 0.65f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(program); + glUniform1f(uniform, time); + glBindVertexArray(vao); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +@end diff --git a/GLEssentials/OSX/GLEssentials-Info.plist b/GLEssentials/OSX/GLEssentials-Info.plist new file mode 100644 index 0000000..31f116c --- /dev/null +++ b/GLEssentials/OSX/GLEssentials-Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.apple-samplecode.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.7 + CFBundleSignature + ???? + CFBundleVersion + Dan Omachi + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/GLEssentials/OSX/GLEssentialsFullscreenWindow.h b/GLEssentials/OSX/GLEssentialsFullscreenWindow.h new file mode 100644 index 0000000..7b06af0 --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsFullscreenWindow.h @@ -0,0 +1,12 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +@import Cocoa; + +@interface GLEssentialsFullscreenWindow : NSWindow +@end diff --git a/GLEssentials/OSX/GLEssentialsFullscreenWindow.m b/GLEssentials/OSX/GLEssentialsFullscreenWindow.m new file mode 100644 index 0000000..a1e5f79 --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsFullscreenWindow.m @@ -0,0 +1,41 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +#import "GLEssentialsFullscreenWindow.h" + +@implementation GLEssentialsFullscreenWindow + +- (id)init { + // Create a screen-sized window on the display you want to take over + // Initialize the window making it size of the screen and borderless + NSRect screenRect = [[NSScreen mainScreen] frame]; + if(self = [super initWithContentRect:screenRect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]){ + + self.level = NSMainMenuWindowLevel + 1; // Set the window level to be above the menu bar to cover everything else + self.opaque = YES; // Set opaque + self.hidesOnDeactivate = YES; // Hide this when user switches to another window (or app) + } + + return self; +} + +- (BOOL)canBecomeKeyWindow { + // Return yes so that this borderless window can receive input + return YES; +} + +- (void)keyDown:(NSEvent *)event { + // Implement keyDown since controller will not get [ESC] key event which + // the controller uses to kill fullscreen + [self.windowController keyDown:event]; +} + +@end diff --git a/GLEssentials/OSX/GLEssentialsGLView.h b/GLEssentials/OSX/GLEssentialsGLView.h new file mode 100644 index 0000000..9a72cc5 --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsGLView.h @@ -0,0 +1,12 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +@import AppKit; + +@interface GLEssentialsGLView : NSOpenGLView +@end diff --git a/GLEssentials/OSX/GLEssentialsGLView.m b/GLEssentials/OSX/GLEssentialsGLView.m new file mode 100644 index 0000000..9285756 --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsGLView.m @@ -0,0 +1,219 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +#import "GLEssentialsGLView.h" +#import "Game.h" + +@import GLKit; +@import QuartzCore; + +@interface GLEssentialsGLView (){ + CVDisplayLinkRef displayLink; + Game* game; +} +- (void) initGL; +@end + +@implementation GLEssentialsGLView + +- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime{ + // There is no autorelease pool when this method is called + // because it will be called from a background thread. + // It's important to create one or app can leak objects. + @autoreleasepool { + [self drawView]; + return kCVReturnSuccess; + } +} + +// This is the renderer output callback function +static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, + const CVTimeStamp* now, + const CVTimeStamp* outputTime, + CVOptionFlags flagsIn, + CVOptionFlags* flagsOut, + void* displayLinkContext) +{ + CVReturn result = [(__bridge GLEssentialsGLView*)displayLinkContext getFrameForTime:outputTime]; + return result; +} + +- (void) awakeFromNib{ + NSOpenGLPixelFormatAttribute attrs[] = { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAOpenGLProfile, + NSOpenGLProfileVersion3_2Core, + 0 + }; + + NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + assert(pf); + + NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; + assert(context); + +#ifdef DEBUG + // When we're using a CoreProfile context, crash if we call a legacy OpenGL function + // This will make it much more obvious where and when such a function call is made so + // that we can remove such calls. + // Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions + // but it would be more difficult to see where that function was called. + CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions); +#endif + + self.pixelFormat = pf; + self.openGLContext = context; + + // Opt-In to Retina resolution + self.wantsBestResolutionOpenGLSurface = YES; +} + +- (void) prepareOpenGL{ + [super prepareOpenGL]; + + // Make all the OpenGL calls to setup rendering + // and build the necessary rendering objects + [self initGL]; + + // Create a display link capable of being used with all active displays + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + + // Set the renderer output callback function + CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, (__bridge void *)(self)); + + // Set the display link for the current renderer + CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; + CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); + + // Activate the display link + CVDisplayLinkStart(displayLink); + + // Register to be notified when the window closes so we can stop the displaylink + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:[self window]]; +} + +- (void) windowWillClose:(NSNotification*)notification{ + // Stop the display link when the window is closing because default + // OpenGL render buffers will be destroyed. If display link continues to + // fire without renderbuffers, OpenGL draw calls will set errors. + + CVDisplayLinkStop(displayLink); +} + +- (void) initGL{ + // The reshape function may have changed the thread to which our OpenGL + // context is attached before prepareOpenGL and initGL are called. So call + // makeCurrentContext to ensure that our OpenGL context current to this + // thread (i.e. makeCurrentContext directs all OpenGL calls on this thread + // to [self openGLContext]) + [[self openGLContext] makeCurrentContext]; + + // Synchronize buffer swaps with vertical refresh rate + GLint swapInt = 1; + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + + // Init our renderer. Use 0 for the defaultFBO which is appropriate for + // OSX (but not iOS since iOS apps must create their own FBO) + game = [[Game alloc] init]; +} + +- (void) reshape{ + [super reshape]; + + // We draw on a secondary thread through the display link. However, when + // resizing the view, -drawRect is called on the main thread. + // Add a mutex around to avoid the threads accessing the context + // simultaneously when resizing. + CGLLockContext([self.openGLContext CGLContextObj]); + + // Get the view size in Points + NSRect viewRectPoints = self.bounds; + + // Rendering at retina resolutions will reduce aliasing, but at the potential + // cost of framerate and battery life due to the GPU needing to render more + // pixels. + + // Any calculations the renderer does which use pixel dimentions, must be + // in "retina" space. [NSView convertRectToBacking] converts point sizes + // to pixel sizes. Thus the renderer gets the size in pixels, not points, + // so that it can set it's viewport and perform and other pixel based + // calculations appropriately. + // viewRectPixels will be larger (2x) than viewRectPoints for retina displays. + // viewRectPixels will be the same as viewRectPoints for non-retina displays + NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints]; + + // If we do not want retina (why wouldn't you want it?). DO: + // Points:Pixels is always 1:1 when not supporting retina resolutions + // NSRect viewRectPixels = viewRectPoints; + + + // Set the new dimensions in our renderer + // [m_renderer resizeWithWidth:viewRectPixels.size.width AndHeight:viewRectPixels.size.height]; + + CGLUnlockContext([self.openGLContext CGLContextObj]); +} + + +- (void)renewGState{ + // Called whenever graphics state updated (such as window resize) + + // OpenGL rendering is not synchronous with other rendering on the OSX. + // Therefore, call disableScreenUpdatesUntilFlush so the window server + // doesn't render non-OpenGL content in the window asynchronously from + // OpenGL content, which could cause flickering. (non-OpenGL content + // includes the title bar and drawing done by the app with other APIs) + [[self window] disableScreenUpdatesUntilFlush]; + + [super renewGState]; +} + +- (void) drawRect: (NSRect) theRect{ + // Called during resize operations + // Avoid flickering during resize by drawiing + [self drawView]; +} + +- (void) drawView{ + [[self openGLContext] makeCurrentContext]; + + // We draw on a secondary thread through the display link + // When resizing the view, -reshape is called automatically on the main + // thread. Add a mutex around to avoid the threads accessing the context + // simultaneously when resizing + CGLLockContext([[self openGLContext] CGLContextObj]); + + NSRect viewRectPoints = self.bounds; + NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints]; + + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, viewRectPixels.size.width, viewRectPixels.size.height); + + [game update:1/60.0f]; + [game draw]; + + CGLFlushDrawable([[self openGLContext] CGLContextObj]); + CGLUnlockContext([[self openGLContext] CGLContextObj]); +} + +- (void) dealloc{ + // Stop the display link BEFORE releasing anything in the view + // otherwise the display link thread may call into the view and crash + // when it encounters something that has been release + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + + // Release the display link AFTER display link has been released + +} +@end diff --git a/GLEssentials/OSX/GLEssentialsWindowController.h b/GLEssentials/OSX/GLEssentialsWindowController.h new file mode 100644 index 0000000..00ca30c --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsWindowController.h @@ -0,0 +1,16 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +@import Cocoa; + +@class GLEssentialsGLView; +@interface GLEssentialsWindowController : NSWindowController { + IBOutlet GLEssentialsGLView *view; +} + +@end diff --git a/GLEssentials/OSX/GLEssentialsWindowController.m b/GLEssentials/OSX/GLEssentialsWindowController.m new file mode 100644 index 0000000..f67205e --- /dev/null +++ b/GLEssentials/OSX/GLEssentialsWindowController.m @@ -0,0 +1,108 @@ +// +// +// iOSGLEssentials +// +// Copied from the Apple GLEssentials +// +// + +#import "GLEssentialsWindowController.h" +#import "GLEssentialsFullscreenWindow.h" +#import "GLEssentialsGLView.h" + +@interface GLEssentialsWindowController () { + GLEssentialsFullscreenWindow *fullscreenWindow; // Fullscreen window + NSWindow* standardWindow; // Non-Fullscreen window (also the initial window) +} + +@end + + +@implementation GLEssentialsWindowController + +- (id)initWithWindow:(NSWindow *) window{ + if (self = [super initWithWindow:window]){ + fullscreenWindow = nil; + } + + return self; +} + +- (void)goFullscreen{ + if(fullscreenWindow){ + return; + } + + // Allocate a new fullscreen window + fullscreenWindow = [[GLEssentialsFullscreenWindow alloc] init]; + + // Resize the view to screensize + view.frame = fullscreenWindow.frame; + + // Set the view in the fullscreen window + fullscreenWindow.contentView = view; + + // keep a referene to the old window + standardWindow = self.window; + + // Hide non-fullscreen window so it doesn't show up when switching out + // of this app (i.e. with CMD-TAB) + [standardWindow orderOut:self]; + + // Set controller to the fullscreen window so that all input will go to + // this controller (self) + self.window = fullscreenWindow; + + // Show the window and make it the key window for input + [fullscreenWindow makeKeyAndOrderFront:self]; + +} + +- (void)goWindow{ + if(!fullscreenWindow){ + return; + } + + // Resize the view to the window size + view.frame = standardWindow.frame; + + // Set controller to the standard window so that all input will go to + // this controller (self) + self.window = standardWindow; + + // Set the content of the orginal window to the view + self.window.contentView = view; + + // Show the window and make it the key window for input + [[self window] makeKeyAndOrderFront:self]; + + // release fullscreenWindow + fullscreenWindow = nil; +} + + +- (void)keyDown:(NSEvent *)event{ + unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0]; + + switch (c){ + // Handle [ESC] key + case 27: + if(fullscreenWindow){ + [self goWindow]; + } + return; + // Have f key toggle fullscreen + case 'f': + if(fullscreenWindow){ + [self goWindow]; + } else { + [self goFullscreen]; + } + return; + } + + // Allow other character to be handled (or not and beep) + [super keyDown:event]; +} + +@end diff --git a/GLEssentials/OSX/MainMenu.xib b/GLEssentials/OSX/MainMenu.xib new file mode 100644 index 0000000..cd8f512 --- /dev/null +++ b/GLEssentials/OSX/MainMenu.xib @@ -0,0 +1,588 @@ + + + + 1060 + 12E55 + 4457.6 + 1187.39 + 626.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 4457.6 + + + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + OSXGLEssentials + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + OSXGLEssentials + + + + About OSXGLEssentialPractices + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide OSXGLEssentialPractices + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit OSXGLEssentialPractices + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + MacGLEssentialPractices Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{200, 200}, {320, 480}} + 1954021376 + OSXGLEssentialPractices + NSWindow + + + + + 1792 + + {320, 480} + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + YES + + + GLEssentialsGLView + + + GLEssentialsWindowController + + + + NO + + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + showHelp: + + + + 493 + + + + unhideAllApplications: + + + + 370 + + + + view + + + + hMc-Rf-8LH + + + + window + + + + z3B-S9-PsV + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + 56 + + + + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 236 + + + + + 129 + + + + + 143 + + + + + 131 + + + + + + + + 130 + + + + + 144 + + + + + 134 + + + + + 145 + + + + + 150 + + + + + 149 + + + + + 136 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + Menu Item - OSXGLEssentialPractices Help + + + 371 + + + + + + Window - OSXGLEssentialPractices + + + 372 + + + + + 494 + + + GL Essentials View + + + M8b-ga-iOS + + + GL Essentials Window Controller + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + com.apple.InterfaceBuilder.CocoaPlugin + + + GLEssentialsGLView + com.apple.InterfaceBuilder.CocoaPlugin + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + IBBuiltInLabel-Blue + + + + + + + + + + + GLEssentialsGLView + NSOpenGLView + + IBProjectSource + ./Classes/GLEssentialsGLView.h + + + + GLEssentialsWindowController + NSWindowController + + view + GLEssentialsGLView + + + view + + view + GLEssentialsGLView + + + + IBProjectSource + ./Classes/GLEssentialsWindowController.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + {11, 11} + {10, 3} + + + diff --git a/GLEssentials/OSX/main.m b/GLEssentials/OSX/main.m new file mode 100644 index 0000000..96c9dd6 --- /dev/null +++ b/GLEssentials/OSX/main.m @@ -0,0 +1,5 @@ +@import Cocoa; + +int main(int argc, char *argv[]){ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/GLEssentials/iOS/AppDelegate.h b/GLEssentials/iOS/AppDelegate.h new file mode 100644 index 0000000..2f29ade --- /dev/null +++ b/GLEssentials/iOS/AppDelegate.h @@ -0,0 +1,13 @@ +// +// AppDelegate.h +// temp +// +// Created by Joshua Moerman on 07/03/14. +// Copyright (c) 2014 Joshua Moerman. All rights reserved. +// + +@import UIKit; + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end diff --git a/GLEssentials/iOS/AppDelegate.m b/GLEssentials/iOS/AppDelegate.m new file mode 100644 index 0000000..bbbbb27 --- /dev/null +++ b/GLEssentials/iOS/AppDelegate.m @@ -0,0 +1,40 @@ +// +// AppDelegate.m +// temp +// +// Created by Joshua Moerman on 07/03/14. +// Copyright (c) 2014 Joshua Moerman. All rights reserved. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/GLEssentials/iOS/GLEssentials-Info.plist b/GLEssentials/iOS/GLEssentials-Info.plist new file mode 100644 index 0000000..f1a85bc --- /dev/null +++ b/GLEssentials/iOS/GLEssentials-Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.apple-samplecode.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.7 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main_iPhone + UIMainStoryboardFile~ipad + Main_iPad + UIRequiredDeviceCapabilities + + opengles-2 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/GLEssentials/iOS/Main_iPad.storyboard b/GLEssentials/iOS/Main_iPad.storyboard new file mode 100644 index 0000000..be77021 --- /dev/null +++ b/GLEssentials/iOS/Main_iPad.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GLEssentials/iOS/Main_iPhone.storyboard b/GLEssentials/iOS/Main_iPhone.storyboard new file mode 100644 index 0000000..5c0d8e3 --- /dev/null +++ b/GLEssentials/iOS/Main_iPhone.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GLEssentials/iOS/ViewController.h b/GLEssentials/iOS/ViewController.h new file mode 100644 index 0000000..d77dcb0 --- /dev/null +++ b/GLEssentials/iOS/ViewController.h @@ -0,0 +1,12 @@ +// +// ViewController.h +// temp +// +// Created by Joshua Moerman on 07/03/14. +// Copyright (c) 2014 Joshua Moerman. All rights reserved. +// + +@import GLKit; + +@interface ViewController : GLKViewController +@end diff --git a/GLEssentials/iOS/ViewController.m b/GLEssentials/iOS/ViewController.m new file mode 100644 index 0000000..07bd974 --- /dev/null +++ b/GLEssentials/iOS/ViewController.m @@ -0,0 +1,90 @@ +// +// ViewController.m +// temp +// +// Created by Joshua Moerman on 07/03/14. +// Copyright (c) 2014 Joshua Moerman. All rights reserved. +// + +#import "ViewController.h" +#import "Game.h" + +@interface ViewController () { + Game * game; +} + +@property (nonatomic) EAGLContext *context; +- (void)setupGL; +- (void)tearDownGL; +@end + +@implementation ViewController + +- (void)viewDidLoad{ + [super viewDidLoad]; + + // all devices supporting ios 5 also support ES 2.0 + // only a couple of devices support ES 3.0 + self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + assert(self.context); + + GLKView *view = (GLKView *)self.view; + view.context = self.context; + view.drawableDepthFormat = GLKViewDrawableDepthFormat24; + view.drawableMultisample = GLKViewDrawableMultisampleNone; + view.contentScaleFactor = 1.0; + + self.preferredFramesPerSecond = 60; + + [self setupGL]; +} + +- (void)dealloc{ + [self tearDownGL]; + + if ([EAGLContext currentContext] == self.context) { + [EAGLContext setCurrentContext:nil]; + } +} + +- (void)didReceiveMemoryWarning{ + [super didReceiveMemoryWarning]; + + if (self.isViewLoaded && (!self.view.window)) { + self.view = nil; + + [self tearDownGL]; + + if ([EAGLContext currentContext] == self.context) { + [EAGLContext setCurrentContext:nil]; + } + self.context = nil; + } + + // Dispose of any resources that can be recreated. +} + +- (void)setupGL{ + [EAGLContext setCurrentContext:self.context]; + game = [[Game alloc] init]; +} + +- (void)tearDownGL{ + [EAGLContext setCurrentContext:self.context]; + game = nil; +} + +#pragma mark - GLKView and GLKViewController delegate methods + +- (void)update{ + [game update:self.timeSinceLastUpdate]; +} + +- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{ + // If we drew on a different fbo in the meantime, do this + [((GLKView *) self.view) bindDrawable]; + + [game draw]; +} + +@end diff --git a/GLEssentials/iOS/main.m b/GLEssentials/iOS/main.m new file mode 100644 index 0000000..699495b --- /dev/null +++ b/GLEssentials/iOS/main.m @@ -0,0 +1,8 @@ +@import UIKit; +#import "AppDelegate.h" + +int main(int argc, char *argv[]){ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/OSXGLEssentials.xcodeproj/project.pbxproj b/OSXGLEssentials.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6256a57 --- /dev/null +++ b/OSXGLEssentials.xcodeproj/project.pbxproj @@ -0,0 +1,254 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4295A2CA18CB4E5100A58D8F /* GLEssentialsFullscreenWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2C318CB4E5100A58D8F /* GLEssentialsFullscreenWindow.m */; }; + 4295A2CB18CB4E5100A58D8F /* GLEssentialsGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2C518CB4E5100A58D8F /* GLEssentialsGLView.m */; }; + 4295A2CC18CB4E5100A58D8F /* GLEssentialsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2C718CB4E5100A58D8F /* GLEssentialsWindowController.m */; }; + 4295A2E018CB68A400A58D8F /* Game.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2DF18CB68A400A58D8F /* Game.m */; }; + 4295A2EB18CBB0F700A58D8F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2EA18CBB0F700A58D8F /* main.m */; }; + 4295A2F318CBB22800A58D8F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2F218CBB22800A58D8F /* MainMenu.xib */; }; + 4295A2F718CBBFF100A58D8F /* Fractal.vsh in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2F618CBBFF100A58D8F /* Fractal.vsh */; }; + 4295A2F918CBC00600A58D8F /* Fractal.fsh in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2F818CBC00500A58D8F /* Fractal.fsh */; }; + 4295A2FA18CBC15000A58D8F /* Fractal.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2F618CBBFF100A58D8F /* Fractal.vsh */; }; + 4295A2FB18CBC15000A58D8F /* Fractal.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2F818CBC00500A58D8F /* Fractal.fsh */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3A1598D311B9DDB0001E7AB5 /* OSXGLEssentials.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OSXGLEssentials.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4295A2C218CB4E5100A58D8F /* GLEssentialsFullscreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GLEssentialsFullscreenWindow.h; path = GLEssentials/OSX/GLEssentialsFullscreenWindow.h; sourceTree = ""; }; + 4295A2C318CB4E5100A58D8F /* GLEssentialsFullscreenWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GLEssentialsFullscreenWindow.m; path = GLEssentials/OSX/GLEssentialsFullscreenWindow.m; sourceTree = ""; }; + 4295A2C418CB4E5100A58D8F /* GLEssentialsGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GLEssentialsGLView.h; path = GLEssentials/OSX/GLEssentialsGLView.h; sourceTree = ""; }; + 4295A2C518CB4E5100A58D8F /* GLEssentialsGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GLEssentialsGLView.m; path = GLEssentials/OSX/GLEssentialsGLView.m; sourceTree = ""; }; + 4295A2C618CB4E5100A58D8F /* GLEssentialsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GLEssentialsWindowController.h; path = GLEssentials/OSX/GLEssentialsWindowController.h; sourceTree = ""; }; + 4295A2C718CB4E5100A58D8F /* GLEssentialsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GLEssentialsWindowController.m; path = GLEssentials/OSX/GLEssentialsWindowController.m; sourceTree = ""; }; + 4295A2DE18CB68A400A58D8F /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Game.h; path = GLEssentials/Game.h; sourceTree = ""; }; + 4295A2DF18CB68A400A58D8F /* Game.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Game.m; path = GLEssentials/Game.m; sourceTree = ""; }; + 4295A2EA18CBB0F700A58D8F /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = GLEssentials/OSX/main.m; sourceTree = ""; }; + 4295A2F018CBB1D200A58D8F /* GLEssentials-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GLEssentials-Info.plist"; path = "GLEssentials/OSX/GLEssentials-Info.plist"; sourceTree = ""; }; + 4295A2F218CBB22800A58D8F /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainMenu.xib; path = GLEssentials/OSX/MainMenu.xib; sourceTree = ""; }; + 4295A2F618CBBFF100A58D8F /* Fractal.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = Fractal.vsh; path = GLEssentials/Fractal.vsh; sourceTree = ""; }; + 4295A2F818CBC00500A58D8F /* Fractal.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = Fractal.fsh; path = GLEssentials/Fractal.fsh; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* GLEssentials */ = { + isa = PBXGroup; + children = ( + 4295A2DE18CB68A400A58D8F /* Game.h */, + 4295A2DF18CB68A400A58D8F /* Game.m */, + 4295A2F618CBBFF100A58D8F /* Fractal.vsh */, + 4295A2F818CBC00500A58D8F /* Fractal.fsh */, + 4295A2F418CBB24A00A58D8F /* OSX */, + 29B97315FDCFA39411CA2CEA /* Supporting Files */, + ); + name = GLEssentials; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 3A1598D311B9DDB0001E7AB5 /* OSXGLEssentials.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* OSXGLEssentials */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* GLEssentials */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = OSXGLEssentials; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4295A2F018CBB1D200A58D8F /* GLEssentials-Info.plist */, + 4295A2EA18CBB0F700A58D8F /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 4295A2F418CBB24A00A58D8F /* OSX */ = { + isa = PBXGroup; + children = ( + 4295A2C218CB4E5100A58D8F /* GLEssentialsFullscreenWindow.h */, + 4295A2C318CB4E5100A58D8F /* GLEssentialsFullscreenWindow.m */, + 4295A2C418CB4E5100A58D8F /* GLEssentialsGLView.h */, + 4295A2C518CB4E5100A58D8F /* GLEssentialsGLView.m */, + 4295A2C618CB4E5100A58D8F /* GLEssentialsWindowController.h */, + 4295A2C718CB4E5100A58D8F /* GLEssentialsWindowController.m */, + 4295A2F218CBB22800A58D8F /* MainMenu.xib */, + ); + name = OSX; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* OSXGLEssentials */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "OSXGLEssentials" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = OSXGLEssentials; + productInstallPath = "$(HOME)/Applications"; + productName = OSXGLEssentials; + productReference = 3A1598D311B9DDB0001E7AB5 /* OSXGLEssentials.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0450; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OSXGLEssentials" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* OSXGLEssentials */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* OSXGLEssentials */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4295A2FA18CBC15000A58D8F /* Fractal.vsh in Resources */, + 4295A2FB18CBC15000A58D8F /* Fractal.fsh in Resources */, + 4295A2F318CBB22800A58D8F /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4295A2F918CBC00600A58D8F /* Fractal.fsh in Sources */, + 4295A2EB18CBB0F700A58D8F /* main.m in Sources */, + 4295A2F718CBBFF100A58D8F /* Fractal.vsh in Sources */, + 4295A2CA18CB4E5100A58D8F /* GLEssentialsFullscreenWindow.m in Sources */, + 4295A2CC18CB4E5100A58D8F /* GLEssentialsWindowController.m in Sources */, + 4295A2E018CB68A400A58D8F /* Game.m in Sources */, + 4295A2CB18CB4E5100A58D8F /* GLEssentialsGLView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = "$(SRCROOT)/GLEssentials/OSX/GLEssentials-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = OSXGLEssentials; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = "$(SRCROOT)/GLEssentials/OSX/GLEssentials-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = OSXGLEssentials; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "OSXGLEssentials" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "OSXGLEssentials" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c1a7df --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# GLMinimals + +Very minimaal Xcode projects for OpenGL apps (both OSX and iOS). + +## Motivation + +I wanted a unified framework for OpenGL on both OSX and iOS without to much of a hassle (less is more). Just to play around easily and to see what the differences are between OSX and iOS. However, the sample code "GLEssentials" provided by Apple was very outdated, so I modernized it. + +## Changes include: + +* Converted to ARC +* Usage of obj-c modules +* Usage of GLKit (instead of doing everything by hand with EAGLayers and the like) +* Removed their basic glUtils (as such functionality is in GLKit anyways) +* Restructered project and a lot of simplifications +* Retina is supported by default + +## Where to plug in + +Just change Game.h and Game.mm to whatever you like. Note that everything in there is hardcoded and should not be regarded as example code. \ No newline at end of file diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..2f10fb6 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,32 @@ +GLEssentials + +================================================================================ +DESCRIPTION: + +This sample provides an example of some of the techniques described in the +"OpenGL Essential Design Practices" WWDC 2010 session. There are usages of +Vertex Buffer Objects (VBOs), Vertex Array Objects (VAOs), Framebuffer Objects +(FBO), and GLSL Program Objects. It creates a VAO and VBOs from model data +loaded in. It creates a texture for the model from image data and GLSL shaders +from source also loaded in. It also creates an FBO and texture to render a +reflection of the model. It uses an environment mapping GLSL program to apply +the reflection texture to a plane. This sample also demonstrates sharing of +OpenGL ES source code for iPhone OS and OpenGL source code for OS X. +Additionally, it implement fullscreen rendering, retina display support, and +demonstrates how to obtain and use an OpenGL 3.2 rendering context on OS X. + +================================================================================ +BUILD REQUIREMENTS: + +Mac version: Mac OS X v10.6 or later, Xcode 3.1 or later +iOS version: iOS SDK 4.0 or later + +================================================================================ +RUNTIME REQUIREMENTS: + +Mac version: Mac OS X v10.6 or later +Mac version: Mac OS X Lion or later to use OpenGL 3.2 +iOS version: iOS 4.0 or later (with OpenGL ES 2.0 support) + +================================================================================ +Copyright (C) 2010~2013 Apple Inc. All rights reserved. diff --git a/iOSGLEssentials.xcodeproj/project.pbxproj b/iOSGLEssentials.xcodeproj/project.pbxproj new file mode 100755 index 0000000..e3eb0f0 --- /dev/null +++ b/iOSGLEssentials.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4295A2AC18CA2C1200A58D8F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2A718CA2C1200A58D8F /* AppDelegate.m */; }; + 4295A2AD18CA2C1200A58D8F /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2A818CA2C1200A58D8F /* Main_iPad.storyboard */; }; + 4295A2AE18CA2C1200A58D8F /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2A918CA2C1200A58D8F /* Main_iPhone.storyboard */; }; + 4295A2AF18CA2C1200A58D8F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2AB18CA2C1200A58D8F /* ViewController.m */; }; + 4295A2DD18CB58B200A58D8F /* Game.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2DC18CB58B200A58D8F /* Game.m */; }; + 4295A2ED18CBB11900A58D8F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2EC18CBB11900A58D8F /* main.m */; }; + 4295A2EF18CBB1C800A58D8F /* GLEssentials-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2EE18CBB1C800A58D8F /* GLEssentials-Info.plist */; }; + 4295A2FE18CBC7D800A58D8F /* Fractal-iOS.fsh in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2FC18CBC7D800A58D8F /* Fractal-iOS.fsh */; }; + 4295A2FF18CBC7D800A58D8F /* Fractal-iOS.vsh in Sources */ = {isa = PBXBuildFile; fileRef = 4295A2FD18CBC7D800A58D8F /* Fractal-iOS.vsh */; }; + 4295A30018CBC81700A58D8F /* Fractal-iOS.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2FC18CBC7D800A58D8F /* Fractal-iOS.fsh */; }; + 4295A30118CBC81700A58D8F /* Fractal-iOS.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 4295A2FD18CBC7D800A58D8F /* Fractal-iOS.vsh */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 3A609E3811B9DB3300AA4C48 /* iOSGLEssentials.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSGLEssentials.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4295A2A618CA2C1200A58D8F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = GLEssentials/iOS/AppDelegate.h; sourceTree = ""; }; + 4295A2A718CA2C1200A58D8F /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = GLEssentials/iOS/AppDelegate.m; sourceTree = ""; }; + 4295A2A818CA2C1200A58D8F /* Main_iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main_iPad.storyboard; path = GLEssentials/iOS/Main_iPad.storyboard; sourceTree = ""; }; + 4295A2A918CA2C1200A58D8F /* Main_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main_iPhone.storyboard; path = GLEssentials/iOS/Main_iPhone.storyboard; sourceTree = ""; }; + 4295A2AA18CA2C1200A58D8F /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewController.h; path = GLEssentials/iOS/ViewController.h; sourceTree = ""; }; + 4295A2AB18CA2C1200A58D8F /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ViewController.m; path = GLEssentials/iOS/ViewController.m; sourceTree = ""; }; + 4295A2DB18CB58B200A58D8F /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Game.h; path = GLEssentials/Game.h; sourceTree = ""; }; + 4295A2DC18CB58B200A58D8F /* Game.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Game.m; path = GLEssentials/Game.m; sourceTree = ""; }; + 4295A2EC18CBB11900A58D8F /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = GLEssentials/iOS/main.m; sourceTree = ""; }; + 4295A2EE18CBB1C800A58D8F /* GLEssentials-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GLEssentials-Info.plist"; path = "GLEssentials/iOS/GLEssentials-Info.plist"; sourceTree = ""; }; + 4295A2FC18CBC7D800A58D8F /* Fractal-iOS.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = "Fractal-iOS.fsh"; path = "GLEssentials/Fractal-iOS.fsh"; sourceTree = ""; }; + 4295A2FD18CBC7D800A58D8F /* Fractal-iOS.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = "Fractal-iOS.vsh"; path = "GLEssentials/Fractal-iOS.vsh"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 3A609E3811B9DB3300AA4C48 /* iOSGLEssentials.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 4295A2A518CA2C0300A58D8F /* GLEssentials */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 4295A2A518CA2C0300A58D8F /* GLEssentials */ = { + isa = PBXGroup; + children = ( + 4295A2FC18CBC7D800A58D8F /* Fractal-iOS.fsh */, + 4295A2FD18CBC7D800A58D8F /* Fractal-iOS.vsh */, + 4295A2DB18CB58B200A58D8F /* Game.h */, + 4295A2DC18CB58B200A58D8F /* Game.m */, + 4295A2F518CBB26C00A58D8F /* iOS */, + 4295A2B018CA2C1600A58D8F /* Supporting Files */, + ); + name = GLEssentials; + sourceTree = ""; + }; + 4295A2B018CA2C1600A58D8F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4295A2EE18CBB1C800A58D8F /* GLEssentials-Info.plist */, + 4295A2EC18CBB11900A58D8F /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 4295A2F518CBB26C00A58D8F /* iOS */ = { + isa = PBXGroup; + children = ( + 4295A2A618CA2C1200A58D8F /* AppDelegate.h */, + 4295A2A718CA2C1200A58D8F /* AppDelegate.m */, + 4295A2A818CA2C1200A58D8F /* Main_iPad.storyboard */, + 4295A2A918CA2C1200A58D8F /* Main_iPhone.storyboard */, + 4295A2AA18CA2C1200A58D8F /* ViewController.h */, + 4295A2AB18CA2C1200A58D8F /* ViewController.m */, + ); + name = iOS; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* GLEssentials */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "GLEssentials" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GLEssentials; + productName = iOSGLEssentials; + productReference = 3A609E3811B9DB3300AA4C48 /* iOSGLEssentials.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0420; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "iOSGLEssentials" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* GLEssentials */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4295A30018CBC81700A58D8F /* Fractal-iOS.fsh in Resources */, + 4295A30118CBC81700A58D8F /* Fractal-iOS.vsh in Resources */, + 4295A2AE18CA2C1200A58D8F /* Main_iPhone.storyboard in Resources */, + 4295A2AD18CA2C1200A58D8F /* Main_iPad.storyboard in Resources */, + 4295A2EF18CBB1C800A58D8F /* GLEssentials-Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4295A2DD18CB58B200A58D8F /* Game.m in Sources */, + 4295A2FF18CBC7D800A58D8F /* Fractal-iOS.vsh in Sources */, + 4295A2AF18CA2C1200A58D8F /* ViewController.m in Sources */, + 4295A2FE18CBC7D800A58D8F /* Fractal-iOS.fsh in Sources */, + 4295A2ED18CBB11900A58D8F /* main.m in Sources */, + 4295A2AC18CA2C1200A58D8F /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = "$(SRCROOT)/GLEssentials/iOS/GLEssentials-Info.plist"; + PRODUCT_NAME = iOSGLEssentials; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + COPY_PHASE_STRIP = YES; + INFOPLIST_FILE = "$(SRCROOT)/GLEssentials/iOS/GLEssentials-Info.plist"; + PRODUCT_NAME = iOSGLEssentials; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = ESSENTIAL_GL_PRACTICES_IOS; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PREPROCESSOR_DEFINITIONS = ESSENTIAL_GL_PRACTICES_IOS; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "GLEssentials" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "iOSGLEssentials" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +}