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_ | 
