diff options
Diffstat (limited to 'engine')
-rw-r--r-- | engine/SDLMain.h | 11 | ||||
-rw-r--r-- | engine/SDLMain.m | 384 | ||||
-rw-r--r-- | engine/application.cpp | 336 | ||||
-rw-r--r-- | engine/application.h | 45 | ||||
-rw-r--r-- | engine/bulletpattern.cpp | 43 | ||||
-rw-r--r-- | engine/bulletpattern.h | 17 | ||||
-rw-r--r-- | engine/config.h | 21 | ||||
-rw-r--r-- | engine/player.cpp | 49 | ||||
-rw-r--r-- | engine/player.h | 17 | ||||
-rw-r--r-- | engine/shader.cpp | 91 | ||||
-rw-r--r-- | engine/shader.h | 56 | ||||
-rw-r--r-- | engine/texture.cpp | 29 | ||||
-rw-r--r-- | engine/texture.h | 14 | ||||
-rw-r--r-- | engine/texturesdl.cpp | 17 | ||||
-rw-r--r-- | engine/texturesdl.h | 8 | ||||
-rw-r--r-- | engine/vector.cpp | 47 | ||||
-rw-r--r-- | engine/vector.h | 36 |
17 files changed, 1221 insertions, 0 deletions
diff --git a/engine/SDLMain.h b/engine/SDLMain.h new file mode 100644 index 0000000..4683df5 --- /dev/null +++ b/engine/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/engine/SDLMain.m b/engine/SDLMain.m new file mode 100644 index 0000000..122fcc8 --- /dev/null +++ b/engine/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/engine/application.cpp b/engine/application.cpp new file mode 100644 index 0000000..2ef8e79 --- /dev/null +++ b/engine/application.cpp @@ -0,0 +1,336 @@ +#include "application.h" + +#include "config.h" + +#include "texturesdl.h" + +#include <SDL/SDL_opengl.h> + +#include <iostream> +#include <stdexcept> + +#include <cmath> + +class BulletPattern1 : public BulletPattern { + unsigned int base; + public: + BulletPattern1(bool reverse, unsigned int base) { + num_bullets = 0; + color_r = 1; + color_g = 0; + color_b = 1; + bullets = new float[128]; + this->base = base; + + int j = 0; + for(float i = 0; i < M_PI; i += 0.1, j++) { + bullets[j*4] = 0.5 + sinf(!reverse ? M_PI_2 + i : M_PI - i + M_PI_2) * 0.09; + bullets[j*4 + 1] = 0.8 + cosf(M_PI_2 + i) * 0.1; + bullets[j*4 + 2] = sinf(!reverse ? M_PI_2 + i : M_PI - i + M_PI_2) / 15000.0; + bullets[j*4 + 3] = -0.0001; + } + }; + void update(unsigned int time, unsigned int step) { + if(num_bullets < 32 && base + num_bullets * 10 < time) { + num_bullets += time / 10 - num_bullets - base / 10; + if(num_bullets > 32) num_bullets = 32; + } + for(int i = 0; i < num_bullets; i++) { + bullets[i*4] += bullets[i*4 + 2] * step; + bullets[i*4 + 1] += bullets[i*4 + 3] * step; + } + } +}; + +class BulletPattern2 : public BulletPattern { + public: + BulletPattern2(unsigned int base) { + num_bullets = 0; + color_r = 0; + color_g = 1; + color_b = 0; + stride = sizeof(float); + bullets = new float[8*32*5]; + + int k = 0; + for(int j = 0; j < 8; j++) { + for(float i = 0; i < M_PI; i += 0.1, k++) { + bullets[k*5] = 0.5 + sinf(j % 2 ? M_PI_2 + i : M_PI - i + M_PI_2) * 0.09; + bullets[k*5 + 1] = 0.8 + cosf(M_PI_2 + i) * 0.1; + bullets[k*5 + 2] = sinf(j % 2 ? M_PI_2 + i : M_PI - i + M_PI_2) / 15000; + bullets[k*5 + 3] = -0.0001; + bullets[k*5 + 4] = base + j * 400 + i * 100; + } + } + + }; + void update(unsigned int time, unsigned int step) { + while(num_bullets < 256 && (unsigned int)(bullets[num_bullets*5 + 4]) < time) { + num_bullets++; + } + for(int i = 0; i < num_bullets; i++) { + bullets[i*5] += bullets[i*5 + 2] * step; + bullets[i*5 + 1] += bullets[i*5 + 3] * step; + } + } +}; + + +Application::Application() { + // Initialize SDL + if(SDL_Init(SDL_INIT_VIDEO)) { + throw(std::runtime_error("SDL initialization failed")); + } + // Fetch the video info + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + if(!info) { + throw(std::runtime_error("SDL info query failed")); + } + // The SDL mode-flags + int flags = SDL_OPENGL; // OpenGL in SDL + flags |= SDL_GL_DOUBLEBUFFER; // Double buffering + flags |= SDL_HWPALETTE; // Hardware palette + // Check for hardware surface aviability + if(info->hw_available) { + flags |= SDL_HWSURFACE; + } else { + flags |= SDL_SWSURFACE; + } + // Check for hardware blit ability + if(info->blit_hw) { + flags |= SDL_HWACCEL; + } + // Setup double buffering + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); + + // Get our surface + surface = SDL_SetVideoMode(Config::window_w, Config::window_h, 32, flags); + if(!surface) { + throw(std::runtime_error("Video mode set failed")); + } + + // Texturing + glEnable(GL_TEXTURE_2D); + // Blending + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + // Smooth shading + glShadeModel(GL_SMOOTH); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glEnable(GL_POINT_SPRITE); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + + glClearColor(0, 0, 0, 0); + glClearDepth(1); + + please_quit = false; +} + +Application::~Application() { + +} + +void Application::run() { + + elapsed = 0; + paused = false; + + font = new FTPixmapFont("fonts/VeraMono.ttf"); + font->FaceSize(12); + background = new TextureSDL("textures/background.png"); + texture = new TextureSDL("textures/shot1.png"); + shader = new GLShaderProgram(); + player = new Player(); + + patterns.push_back(new BulletPattern()); + for(int i = 0; i < 8; i++) { + patterns.push_back(new BulletPattern1(i % 2 == 1, 5000 + i * 400)); + } + patterns.push_back(new BulletPattern2(9000)); + + GLFragmentShader shader1("shaders/bullet_fragment.glsl"); + GLVertexShader shader2("shaders/bullet_vertex.glsl"); + shader->attach(shader1); + shader->attach(shader2); + shader->link(); + + lasttick = SDL_GetTicks(); + + while(1) { + SDL_Event event; + while(SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) { + break; + } else if(event.type == SDL_KEYDOWN) { + event_keypress(event.key.keysym.sym); + } + } + + if(please_quit) { + return; + } + + unsigned int tick = SDL_GetTicks(); + unsigned int step = tick - lasttick; + lasttick = tick; + + main_loop(tick, step); + + //SDL_Delay(10); + } +} + +void Application::main_loop(unsigned int tick, unsigned int step) { + if(!paused) { + elapsed += step; + for(std::vector<BulletPattern*>::iterator it = patterns.begin(); it < patterns.end(); it++) { + (*it)->update(elapsed, step); + } + + player->update(); + } + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glViewport(0, 0, Config::window_w, Config::window_h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + float xo = float(Config::window_w)/float(Config::window_h)/2.5 - 0.5; + glOrtho(-xo, 1 + xo, 0, 0.8, 0, 10); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, background->tex()); + glBegin(GL_QUADS); + glTexCoord2f(0, 1); + glVertex2f(-1.9/9.0, 0); + glTexCoord2f(0, 0); + glVertex2f(-1.9/9.0, 0.8); + glTexCoord2f(1, 0); + glVertex2f(10.9/9.0, 0.8); + glTexCoord2f(1, 1); + glVertex2f(10.9/9.0, 0); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glColor4f(1, 1, 0, 1); + + char s[0xff]; + + if(tick - lastframes >= 1000) { + fps = (float)frames * ((float)(tick - lastframes) / 1000.0f); + frames = 1; + lastframes = tick; + } else { + frames++; + } + snprintf(s, 0xff, "FPS: %.2f", fps); + glRasterPos2f(Config::fps_x, Config::fps_y); + font->Render(s); + + float v_x = Config::window_w * (Config::viewport_x + xo) / (1 + 2 * xo); + float v_y = Config::window_h * Config::viewport_y; + float v_w = Config::window_h * Config::viewport_w; + float v_h = Config::window_h * Config::viewport_h; + + glViewport( + v_x - Config::viewport_overscan, + v_y - Config::viewport_overscan, + v_w + Config::viewport_overscan * 2, + v_h + Config::viewport_overscan * 2); + glScissor(v_x, v_y, v_w, v_h); + glEnable(GL_SCISSOR_TEST); + + glClearColor(0.2, 0.2, 0.2, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45, (float)660 / (float)740, 1, 100); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + float f = elapsed * 0.0005; + + gluLookAt( + 5 * sinf(f), 1, 5 * cosf(f), + 0, 0, 0, + 5 * sinf(f), 2, 5 * cosf(f)); + + glBegin(GL_LINES); + for(int i = -10; i < 11; i++) { + if(i % 5 == 0) + glColor3f(1, 1, 1); + else + glColor3f(.5, .5, .5); + glVertex3f(i, 0, -10); + glVertex3f(i, 0, 10); + glVertex3f(-10, 0, i); + glVertex3f(10, 0, i); + } + glEnd(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho( + -float(Config::viewport_overscan) / float(v_w), + 1.0 + float(Config::viewport_overscan) / float(v_w), + -float(Config::viewport_overscan) / float(v_w), + Config::viewport_aspect + float(Config::viewport_overscan) / float(v_w), + 0, 10); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + + player->draw(); + + shader->use(); + glPointSize(32.0); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture->tex()); + + glColor4f(1, 0, 0, 1); + + for(std::vector<BulletPattern*>::iterator it = patterns.begin(); it < patterns.end(); it++) { + BulletPattern *bp = (*it); + glColor3f(bp->color_r, bp->color_g, bp->color_b); + bp->draw(); + } + + glUseProgram(0); + + glDisable(GL_SCISSOR_TEST); + + SDL_GL_SwapBuffers(); +} + +void Application::quit() { + please_quit = true; +} + +void Application::event_keypress(SDLKey key) { + switch(key) { + case SDLK_ESCAPE: + quit(); + break; + case SDLK_SPACE: + paused = !paused; + lasttick = SDL_GetTicks(); + break; + default: + break; + } +} diff --git a/engine/application.h b/engine/application.h new file mode 100644 index 0000000..4bf9251 --- /dev/null +++ b/engine/application.h @@ -0,0 +1,45 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +#include <SDL/SDL.h> +#include <FTGL/ftgl.h> +#include <vector> + +#include "bulletpattern.h" +#include "shader.h" +#include "texture.h" +#include "player.h" + +class Application { + private: + SDL_Surface *surface; + bool please_quit; + + bool paused; + unsigned int lasttick; + unsigned int elapsed; + unsigned int frames; + unsigned int lastframes; + float fps; + + FTFont* font; + Texture* background; + Texture* texture; + GLShaderProgram* shader; + Player *player; + + std::vector<BulletPattern*> patterns; + + public: + Application(); + ~Application(); + void run(); + void quit(); + + protected: + virtual void event_keypress(SDLKey key); + + void main_loop(unsigned int tick, unsigned int step); +}; + +#endif diff --git a/engine/bulletpattern.cpp b/engine/bulletpattern.cpp new file mode 100644 index 0000000..b4b5a31 --- /dev/null +++ b/engine/bulletpattern.cpp @@ -0,0 +1,43 @@ +#ifndef __APPLE__ +#include <GL/gl.h> +#else +#include <OpenGL/gl.h> +#endif +#include <cmath> +#include "bulletpattern.h" + +BulletPattern::BulletPattern() { + num_bullets = stride = color_g = color_b = 0; + color_r = 1; + bullets = new float[2048]; + + int k = 0; + + for(float i = 0; i < M_PI * 16; i += 0.1) { + bullets[k++] = 0.5 + cosf(i) * 0.05; + bullets[k++] = 0.5 + sinf(i) * 0.05; + bullets[k++] = cosf(i) / 10000.0; + bullets[k++] = sinf(i) / 10000.0; + } +} + +void BulletPattern::update(unsigned int time, unsigned int step) { + while(num_bullets < 503 && num_bullets * 4 < time) { + num_bullets++; + } + for(int i = 0; i < num_bullets; i++) { + bullets[i*4] += bullets[i*4 + 2] * step; + bullets[i*4 + 1] += bullets[i*4 + 3] * step; + } +} + +void BulletPattern::draw() { + glEnableClientState(GL_VERTEX_ARRAY); + + glVertexPointer(4, GL_FLOAT, 4 * sizeof(float) + stride, bullets); + + glDrawArrays(GL_POINTS, 0, num_bullets); + + glDisableClientState(GL_VERTEX_ARRAY); + +} diff --git a/engine/bulletpattern.h b/engine/bulletpattern.h new file mode 100644 index 0000000..092713e --- /dev/null +++ b/engine/bulletpattern.h @@ -0,0 +1,17 @@ +#ifndef BULLETPATTERN_H +#define BULLETPATTERN_H + +class BulletPattern { + protected: + float* bullets; + int num_bullets; + int stride; + public: + float color_r, color_g, color_b; + + BulletPattern(); + virtual void update(unsigned int time, unsigned int step); + void draw(); +}; + +#endif diff --git a/engine/config.h b/engine/config.h new file mode 100644 index 0000000..6884b1a --- /dev/null +++ b/engine/config.h @@ -0,0 +1,21 @@ +#ifndef CONFIG_H +#define CONFIG_H + +namespace Config { + const unsigned int window_w = 1280; + const unsigned int window_h = 800; + + const float viewport_x = 15.0 / 1080.0; + const float viewport_y = 15.0 / 1080.0; + const float viewport_w = 900.0 / 1080.0; + const float viewport_h = 1050.0 / 1080.0; + + const unsigned int viewport_overscan = 10; + + const float viewport_aspect = float(viewport_h) / float(viewport_w); + + const float fps_x = 0.0; + const float fps_y = 0.0; +}; + +#endif diff --git a/engine/player.cpp b/engine/player.cpp new file mode 100644 index 0000000..4a159ca --- /dev/null +++ b/engine/player.cpp @@ -0,0 +1,49 @@ +#ifndef __APPLE__ +#include <GL/gl.h> +#else +#include <OpenGL/gl.h> +#endif +#include <cmath> +#include <SDL/SDL.h> + +#include "player.h" +#include "texturesdl.h" +#include "config.h" + +Player::Player() { + x = 0.5; + y = 0.1; + move_factor = 0.005; + focus_factor = 0.5; + texture = new TextureSDL("textures/player.png"); +} + +void Player::draw() { + glPointSize(32.0); + + glColor4f(1, 1, 1, 1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture->tex()); + + glBegin(GL_POINTS); + glVertex2f(x, y); + glEnd(); + + glDisable(GL_TEXTURE_2D); +} + +void Player::update() { + Uint8 *keystate = SDL_GetKeyState(NULL); + float factor = move_factor * (SDL_GetModState() & KMOD_SHIFT ? focus_factor : 1); + + float x_speed = factor * keystate[SDLK_RIGHT] - factor * keystate[SDLK_LEFT]; + float y_speed = factor * keystate[SDLK_UP] - factor * keystate[SDLK_DOWN]; + + if(x_speed && y_speed) { + x_speed /= sqrtf(2); + y_speed /= sqrtf(2); + } + + x = fmaxf(fminf(x + x_speed, 1.0 - 0.018), 0.018); + y = fmaxf(fminf(y + y_speed, Config::viewport_aspect - 0.018), 0.018); +} diff --git a/engine/player.h b/engine/player.h new file mode 100644 index 0000000..41f1928 --- /dev/null +++ b/engine/player.h @@ -0,0 +1,17 @@ +#ifndef _PLAYER_H_ +#define _PLAYER_H_ + +#include "texture.h" + +class Player { + protected: + float x, y, move_factor, focus_factor; + Texture *texture; + + public: + Player(); + void draw(); + void update(); +}; + +#endif diff --git a/engine/shader.cpp b/engine/shader.cpp new file mode 100644 index 0000000..04aa031 --- /dev/null +++ b/engine/shader.cpp @@ -0,0 +1,91 @@ +#include <fstream> +#include "shader.h" + +bool GLBaseShader::shader_source(const char *filename) { + std::ifstream inf(filename, std::ios_base::in); + if(!inf.is_open()) { + std::cerr << "Failed to load shader " << filename << std::endl; + return false; + } + 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); + print_check_ogl_error(); + delete[] buffer; + glCompileShader(shader); + print_check_ogl_error(); + int p; + glGetShaderiv(shader, GL_COMPILE_STATUS, &p); + if(p == 0) { + std::cerr << "Failed to compile shader:" << std::endl; + char log[0xffff]; + int size; + glGetShaderInfoLog(shader, 0xffff, &size, (GLchar*)&log); + std::cerr << log << std::endl; + } + return shader; +} + +bool GLBaseShader::shader_source(std::string& filename) { + return shader_source(filename.c_str()); +} + +GLBaseShader::GLBaseShader(GLenum type) { + shader = glCreateShader(type); +} + +GLShaderProgram::GLShaderProgram() { + program = glCreateProgram(); +} + +bool GLShaderProgram::attach(GLBaseShader& shader) { + glAttachShader(program, shader.shader); + return !print_check_ogl_error(); +} + +bool GLShaderProgram::detach(GLBaseShader& shader) { + glDetachShader(program, shader.shader); + return !print_check_ogl_error(); +} + +bool GLShaderProgram::link() { + glLinkProgram(program); + bool error = print_check_ogl_error(); + int p; + glGetProgramiv(program, GL_LINK_STATUS, &p); + if(p == 0) { + std::cerr << "Failed to link program:" << std::endl; + char log[0xffff]; + int size; + glGetProgramInfoLog(program, 0xffff, &size, (GLchar*)&log); + printf(log); + } + return !error && p; +} + +bool GLShaderProgram::use() { + if(!glIsProgram(program)) program = glCreateProgram(); + glUseProgram(program); + return !print_check_ogl_error(); +} + +void GLShaderProgram::remove() { + glDeleteProgram(program); +} + +void print_ogl_error(GLenum error) { + unsigned char *buf = (unsigned char*)gluErrorString(error); + std::cerr << "OpenGL: " << buf << std::endl; +} + +bool print_check_ogl_error() { + GLenum error = glGetError(); + if(error != GL_NO_ERROR) + print_ogl_error(error); + return error != GL_NO_ERROR; +} diff --git a/engine/shader.h b/engine/shader.h new file mode 100644 index 0000000..012165a --- /dev/null +++ b/engine/shader.h @@ -0,0 +1,56 @@ +#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: + bool shader_source(const char *filename); + bool shader_source(std::string& filename); + unsigned int shader; + public: + GLBaseShader(GLenum); +}; + +class GLVertexShader : public GLBaseShader { + public: + GLVertexShader() : GLBaseShader(GL_VERTEX_SHADER) {}; + GLVertexShader(const char *s) : GLBaseShader(GL_VERTEX_SHADER) { shader_source(s); }; |