diff options
-rw-r--r-- | SConscript | 8 | ||||
-rw-r--r-- | SDLMain.h | 11 | ||||
-rw-r--r-- | SDLMain.m | 384 | ||||
-rw-r--r-- | shader.cpp | 93 | ||||
-rw-r--r-- | shader.h | 54 | ||||
-rw-r--r-- | struct.h | 53 | ||||
-rw-r--r-- | texture.cpp | 19 | ||||
-rw-r--r-- | texture.h | 14 | ||||
-rw-r--r-- | texturesdl.cpp | 23 | ||||
-rw-r--r-- | texturesdl.h | 8 |
10 files changed, 667 insertions, 0 deletions
diff --git a/SConscript b/SConscript new file mode 100644 index 0000000..1aa29b7 --- /dev/null +++ b/SConscript @@ -0,0 +1,8 @@ +Import('env') + +sources = Glob('*.cpp') + +if env['PLATFORM'] == 'darwin': + sources.append('SDLMain.m') + +env.Library('wriggle', sources) diff --git a/SDLMain.h b/SDLMain.h new file mode 100644 index 0000000..4683df5 --- /dev/null +++ b/SDLMain.h @@ -0,0 +1,11 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser <dwaliss1@purdue.edu> + Non-NIB-Code & other changes: Max Horn <max@quendi.de> + + Feel free to customize this file to suit your needs +*/ + +#import <Cocoa/Cocoa.h> + +@interface SDLMain : NSObject +@end diff --git a/SDLMain.m b/SDLMain.m new file mode 100644 index 0000000..122fcc8 --- /dev/null +++ b/SDLMain.m @@ -0,0 +1,384 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser <dwaliss1@purdue.edu> + Non-NIB-Code & other changes: Max Horn <max@quendi.de> + + Feel free to customize this file to suit your needs +*/ + +#import <SDL/SDL.h> +#import "SDLMain.h" +#import <sys/param.h> /* for MAXPATHLEN */ +#import <unistd.h> + +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + +/* Use this flag to determine whether we use SDLMain.nib or not */ +#define SDL_USE_NIB_FILE 0 + +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ + +static int gArgc; +static char **gArgv; +static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} + +#if SDL_USE_NIB_FILE +/* A helper category for NSString */ +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end +#endif + +@interface SDLApplication : NSApplication +@end + +@implementation SDLApplication +/* Invoked from the Quit menu item */ +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} +@end + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + if (shouldChdir) + { + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } + +} + +#if SDL_USE_NIB_FILE + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; + if ([menuItem hasSubmenu]) + [self fixMenu:[menuItem submenu] withAppName:appName]; + } + [ aMenu sizeToFit ]; +} + +#else + +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; +} + +/* Replacement for NSApplicationMain */ +static void CustomApplicationMain (int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; + + /* Ensure the application object is initialised */ + [SDLApplication sharedApplication]; + +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + sdlMain = [[SDLMain alloc] init]; + [NSApp setDelegate:sdlMain]; + + /* Start the main event loop */ + [NSApp run]; + + [sdlMain release]; + [pool release]; +} + +#endif + + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + +#if SDL_USE_NIB_FILE + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; +#endif + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + /* Get middle part into buffer */ + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + /* Get last part into buffer */ + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + /* Build output string */ + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + + + +#ifdef main +# undef main +#endif + + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + +#if SDL_USE_NIB_FILE + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); +#else + CustomApplicationMain (argc, argv); +#endif + return 0; +} + diff --git a/shader.cpp b/shader.cpp new file mode 100644 index 0000000..a0509ff --- /dev/null +++ b/shader.cpp @@ -0,0 +1,93 @@ +#include <fstream> +#include <stdexcept> + +#include <boost/format.hpp> + +#include "shader.h" + +static void gl_check_error(const char *msg) { + GLenum error = glGetError(); + if(error != GL_NO_ERROR) { + throw(std::runtime_error((boost::format("%s:\n%s") % msg % gluErrorString(error)).str())); + } +} + +void GLBaseShader::shader_source(const char *filename) { + std::ifstream inf(filename, std::ios_base::in); + if(!inf.is_open()) { + throw(std::runtime_error((boost::format("Failed to load shader from file %s") % filename).str())); + } + inf.seekg(0, std::ios_base::end); + int length = inf.tellg(); + inf.seekg(0, std::ios_base::beg); + char *buffer = new char[length]; + inf.read(buffer, length); + inf.close(); + + glShaderSource(shader, 1, (const GLchar**)&buffer, &length); + gl_check_error("Failed to set shader source"); + delete[] buffer; + glCompileShader(shader); + int p; + glGetShaderiv(shader, GL_COMPILE_STATUS, &p); + if(p == 0) { + char log[0xffff]; + int size; + glGetShaderInfoLog(shader, 0xffff, &size, (GLchar*)&log); + throw(std::runtime_error((boost::format("Failed to compile shader:\n%s") % log).str())); + } +} + +void GLBaseShader::shader_source(std::string& filename) { + shader_source(filename.c_str()); +} + +GLBaseShader::GLBaseShader(GLenum type) { + shader = glCreateShader(type); +} + +GLBaseShader::~GLBaseShader() { + glDeleteShader(shader); +} + +/** + * GLShaderProgram + */ +GLShaderProgram::GLShaderProgram() { + program = glCreateProgram(); +} + +GLShaderProgram::~GLShaderProgram() { + glDeleteProgram(program); +} + +void GLShaderProgram::attach(GLBaseShader& shader) { + glAttachShader(program, shader.shader); + + gl_check_error("Failed to attach shader to program"); +} + +void GLShaderProgram::detach(GLBaseShader& shader) { + glDetachShader(program, shader.shader); + + gl_check_error("Failed to detach shader from program"); +} + +void GLShaderProgram::link() { + glLinkProgram(program); + + int p; + glGetProgramiv(program, GL_LINK_STATUS, &p); + if(p == 0) { + char log[0xffff]; + int size; + glGetProgramInfoLog(program, 0xffff, &size, (GLchar*)&log); + throw(std::runtime_error((boost::format("Failed to link program:\n%s") % log).str())); + } +} + +void GLShaderProgram::use() { + glUseProgram(program); + + gl_check_error("Failed to use program"); +} diff --git a/shader.h b/shader.h new file mode 100644 index 0000000..d4ad263 --- /dev/null +++ b/shader.h @@ -0,0 +1,54 @@ +#ifndef _SHADER_H_ +#define _SHADER_H_ + +#include <iostream> +#include <string> +#define GL_GLEXT_PROTOTYPES +#ifndef __APPLE__ +#include <GL/gl.h> +#include <GL/glu.h> +#else +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> +#endif + +class GLBaseShader { + friend class GLShaderProgram; + + protected: + void shader_source(const char *filename); + void shader_source(std::string& filename); + unsigned int shader; + public: + GLBaseShader(GLenum); + ~GLBaseShader(); +}; + +class GLVertexShader : public GLBaseShader { + public: + GLVertexShader() : GLBaseShader(GL_VERTEX_SHADER) {}; + GLVertexShader(const char *s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); }; + GLVertexShader(std::string& s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); }; +}; + +class GLFragmentShader : public GLBaseShader { + public: + GLFragmentShader() : GLBaseShader(GL_FRAGMENT_SHADER) {}; + GLFragmentShader(const char *s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); }; + GLFragmentShader(std::string& s) : GLBaseShader(GL_FRAGMENT_SHADER) { shader_source(s); }; +}; + +class GLShaderProgram { + protected: + unsigned int program; + public: + GLShaderProgram(); + ~GLShaderProgram(); + + void attach(GLBaseShader&); + void detach(GLBaseShader&); + void link(); + void use(); +}; + +#endif diff --git a/struct.h b/struct.h new file mode 100644 index 0000000..d08e66d --- /dev/null +++ b/struct.h @@ -0,0 +1,53 @@ +#ifndef STRUCT_H +#define STRUCT_H + +template<class A = void, class B = void, class C = void, class D = void, class E = void, class F = void> +struct Struct { + A a; + B b; + C c; + D d; + E e; + F f; +}; + +template<class A, class B, class C, class D, class E> +struct Struct<A, B, C, D, E, void> { + A a; + B b; + C c; + D d; + E e; +}; + +template<class A, class B, class C, class D> +struct Struct<A, B, C, D, void, void> { + A a; + B b; + C c; + D d; +}; + +template<class A, class B, class C> +struct Struct<A, B, C, void, void, void> { + A a; + B b; + C c; +}; + +template<class A, class B> +struct Struct<A, B, void, void, void, void> { + A a; + B b; +}; + +template<class A> +struct Struct<A, void, void, void, void, void> { + A a; +}; + +template<> +struct Struct<void, void, void, void, void, void> { +}; + +#endif diff --git a/texture.cpp b/texture.cpp new file mode 100644 index 0000000..c3575f2 --- /dev/null +++ b/texture.cpp @@ -0,0 +1,19 @@ +#include <SDL/SDL_opengl.h> +#include <stdexcept> +#include "texture.h" +#include <stdio.h> + +unsigned int Texture::tex() { + return texture; +} + +void Texture::build() { + if(!data) { + throw(std::runtime_error("No texture data")); + } + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, format, GL_UNSIGNED_BYTE, data); +} diff --git a/texture.h b/texture.h new file mode 100644 index 0000000..c88104f --- /dev/null +++ b/texture.h @@ -0,0 +1,14 @@ +#ifndef _TEXTURE_H_ +#define _TEXTURE_H_ +class Texture { + public: + unsigned int tex(); + protected: + void build(); + unsigned char* data; + unsigned int width; + unsigned int height; + unsigned int format; + unsigned int texture; +}; +#endif // _TEXTURE_H_ diff --git a/texturesdl.cpp b/texturesdl.cpp new file mode 100644 index 0000000..bab760b --- /dev/null +++ b/texturesdl.cpp @@ -0,0 +1,23 @@ +#include <stdexcept> +#include <SDL/SDL_image.h> +#include <SDL/SDL_opengl.h> +#include "texturesdl.h" + +TextureSDL::TextureSDL(const char* filename) { + SDL_Surface* image = IMG_Load(filename); + + width = image->w; + height = image->h; + + if(image->format->BytesPerPixel == 4) { + format = image->format->Bshift ? GL_RGBA : GL_BGRA; + } else { + format = image->format->Bshift ? GL_RGB : GL_BGR; + } + + data = (unsigned char*)image->pixels; + + build(); + + SDL_FreeSurface(image); +} diff --git a/texturesdl.h b/texturesdl.h new file mode 100644 index 0000000..6b2eff2 --- /dev/null +++ b/texturesdl.h @@ -0,0 +1,8 @@ +#ifndef _TEXTURESDL_H_ +#define _TEXTURESDL_H_ +#include "texture.h" +class TextureSDL : public Texture { + public: + TextureSDL(const char* filename); +}; +#endif // _TEXTURESDL_H_ |