Mercurial > sdl-ios-xcode
diff Xcode/TemplatesForProjectBuilder/SDL Custom Cocoa Application/MyController.m @ 2207:d63e9f5944ae
Unpacked project archives to get individual file history in subversion
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 21 Jul 2007 17:09:01 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Xcode/TemplatesForProjectBuilder/SDL Custom Cocoa Application/MyController.m Sat Jul 21 17:09:01 2007 +0000 @@ -0,0 +1,506 @@ +// +// MyController.m +// SDL Custom Cocoa App +// +// Created by Darrell Walisser on Fri Jul 18 2003. +// Copyright (c) 2003 __MyCompanyName__. All rights reserved. +// + +#import "MyController.h" +#import "SDL.h" + +id gController; + +@implementation MyController + +- (id)init +{ + self = [ super init ]; + if (self) { + + _nSprites = 10; + _max_speed = 4; + _doFlip = 0; + _mem = NULL; + _screen = NULL; + _sprite_rects = NULL; + _positions = NULL; + _velocities = NULL; + _sprites_visible = 1; + _sprite_w = 0; + _sprite_h = 0; + _mouse_x = 0; + _mouse_y = 0; + } + + return self; +} + +- (void)setupCocoaWindow +{ + // If you want the close button to send SDL_Quit, + // you can attach the SDL_QuartzWindowDelegate to the window + [ _window setDelegate: + [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; + + // Make the window visible and the frontmost window + [ _window makeKeyAndOrderFront:nil ]; + + // Make the window accept passive motion events (when the button is released) + [ _window setAcceptsMouseMovedEvents:YES ]; +} + +- (void)setCocoaEnvironmentVariables +{ + // Export cocoa objects to environment + // SDL will use these when you call SDL_SetVideoMode + + // The window must be visible when you call SDL_SetVideoMode, + // and the view must lie completely within the window. + // + // The width and height passed to SDL_SetVideoMode should match + // the width/height of the view (the window can be any size) + // + // For resizing to work, you must set the appropriate + // attributes on the window and view. Then the SDL_RESIZABLE + // flag will be set automatically + // + // SDL will retain a reference to the window, and + // will release it when unsetting the video mode + // + // The view is not retained (the window object manages this). + // + char buffer[256]; + printf ("NSWindow=%p\n", _window); + sprintf (buffer, "%d", (int)_window); + setenv ("SDL_NSWindowPointer", buffer, 1); + + printf ("NSQuickDrawView=%p\n", _view); + sprintf (buffer, "%d", (int)_view); + setenv ("SDL_NSQuickDrawViewPointer", buffer, 1); + + // Also tell SDL to pass keyboard events to Cocoa + // In this case, Cocoa will get the event before SDL_PollEvent returns it + // Note that mouse events (button, motion) will always be passed, regardless of this setting + setenv ("SDL_ENABLEAPPEVENTS", "1", 1); +} + +- (void)printFlags:(Uint32)flags withName:(const char*)name +{ + printf ("%s", name); + + if (flags & SDL_SWSURFACE) + printf (" - SDL_SWSURFACE"); + if (flags & SDL_HWSURFACE) + printf (" - SDL_HWSURFACE"); + if (flags & SDL_ASYNCBLIT) + printf (" - SDL_ASYNCBLIT"); + if (flags & SDL_ANYFORMAT) + printf (" - SDL_ANYFORMAT"); + if (flags & SDL_HWPALETTE) + printf (" - SDL_HWPALETTE"); + if (flags & SDL_DOUBLEBUF) + printf (" - SDL_DOUBLEBUF"); + if (flags & SDL_FULLSCREEN) + printf (" - SDL_FULLSCREEN"); + if (flags & SDL_OPENGL) + printf (" - SDL_OPENGL"); + if (flags & SDL_OPENGLBLIT) + printf (" - SDL_OPENGLBLIT"); + if (flags & SDL_RESIZABLE) + printf (" - SDL_RESIZABLE"); + if (flags & SDL_NOFRAME) + printf (" - SDL_NOFRAME"); + + printf ("\n"); +} +// This is a way of telling whether or not to use hardware surfaces +// Note: this does nothing on Mac OS X at the moment - there is no +// hardware-accelerated blitting support. +- (Uint32)fastestFlags:(Uint32)flags :(int)width :(int)height :(int)bpp +{ + const SDL_VideoInfo *info; + + // Hardware acceleration is only used in fullscreen mode + flags |= SDL_FULLSCREEN; + + // Check for various video capabilities + info = SDL_GetVideoInfo(); + if ( info->blit_hw_CC && info->blit_fill ) { + // We use accelerated colorkeying and color filling + flags |= SDL_HWSURFACE; + } + // If we have enough video memory, and will use accelerated + // blits directly to it, then use page flipping. + if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { + + // Direct hardware blitting without double-buffering + // causes really bad flickering. + if ( info->video_mem*1024 > (height*width*bpp/8) ) { + flags |= SDL_DOUBLEBUF; + } else { + flags &= ~SDL_HWSURFACE; + } + } + + // Return the flags + return flags; +} + +- (int)loadSpriteFromFile:(const char*)file +{ + SDL_Surface *temp; + + // Load the sprite image + _sprite = SDL_LoadBMP (file); + if ( _sprite == NULL ) { + fprintf (stderr, "Couldn't load %s: %s", file, SDL_GetError ()); + return (-1); + } + + // Set transparent pixel as the pixel at (0,0) + if ( _sprite->format->palette ) { + SDL_SetColorKey (_sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL), + *(Uint8 *)_sprite->pixels); + } + + /* Convert sprite to video format */ + temp = SDL_DisplayFormat (_sprite); + SDL_FreeSurface (_sprite); + if ( temp == NULL ) { + fprintf(stderr, "Couldn't convert background: %s\n", + SDL_GetError ()); + return (-1); + } + _sprite = temp; + + // We're ready to roll. :) + return 0; +} + +- (void)allocSprites +{ + /* Allocate memory for the sprite info */ + _mem = (Uint8 *)malloc (4*sizeof(SDL_Rect)*_nSprites); + if ( _mem == NULL ) { + fprintf (stderr, "Out of memory!\n"); + exit (2); + } + + _sprite_rects = (SDL_Rect *)_mem; + _positions = _sprite_rects; + _sprite_rects += _nSprites; + _velocities = _sprite_rects; + _sprite_rects += _nSprites; + _sprite_w = _sprite->w; + _sprite_h = _sprite->h; +} + +- (void)freeSprites +{ + free (_mem); + _mem = NULL; +} + +- (void)initSprites +{ + // Give each sprite a random starting position and velocity + int i; + + srand(time(NULL)); + for ( i=0; i < _nSprites; ++i ) { + _positions[i].x = rand()%(_screen->w - _sprite->w); + _positions[i].y = rand()%(_screen->h - _sprite->h); + _positions[i].w = _sprite->w; + _positions[i].h = _sprite->h; + _velocities[i].x = 0; + _velocities[i].y = 0; + while ( ! _velocities[i].x && ! _velocities[i].y ) { + _velocities[i].x = (rand()%(_max_speed*2+1)) - _max_speed; + _velocities[i].y = (rand()%(_max_speed*2+1)) - _max_speed; + } + } +} + +- (void)moveSprites:(int)backgroundColor; +{ + int i, nupdates; + SDL_Rect area, *position, *velocity; + + nupdates = 0; + // Erase all the sprites if necessary + if ( _sprites_visible ) { + SDL_FillRect (_screen, NULL, backgroundColor); + } + + // Move the sprite, bounce at the wall, and draw + for ( i=0; i < _nSprites; ++i ) { + position = &_positions[i]; + velocity = &_velocities[i]; + position->x += velocity->x; + if ( (position->x < 0) || (position->x >= (_screen->w - _sprite_w)) ) { + velocity->x = -velocity->x; + position->x += velocity->x; + } + position->y += velocity->y; + if ( (position->y < 0) || (position->y >= (_screen->h - _sprite_w)) ) { + velocity->y = -velocity->y; + position->y += velocity->y; + } + + // Blit the sprite onto the screen + area = *position; + SDL_BlitSurface (_sprite, NULL, _screen, &area); + _sprite_rects[nupdates++] = area; + } + + // Update the screen! + if ( _doFlip ) { + SDL_Flip (_screen); + } else { + SDL_UpdateRects (_screen, nupdates, _sprite_rects); + } + + _sprites_visible = 1; +} + +- (int)run:(int)argc argv:(char*[])argv +{ + int width, height; + Uint8 video_bpp; + Uint32 videoflags; + Uint32 background; + int done; + SDL_Event event; + Uint32 then, now, frames; + + // Initialize SDL + if ( SDL_Init (SDL_INIT_VIDEO) < 0 ) { + fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError ()); + exit (1); + } + atexit(SDL_Quit); + + videoflags = SDL_SWSURFACE|SDL_ANYFORMAT; + width = 640; + height = 480; + video_bpp = 8; + while ( argc > 1 ) { + --argc; + if ( strcmp(argv[argc-1], "-width") == 0 ) { + width = atoi (argv[argc]); + --argc; + } else + if ( strcmp(argv[argc-1], "-height") == 0 ) { + height = atoi (argv[argc]); + --argc; + } else + if ( strcmp(argv[argc-1], "-bpp") == 0 ) { + video_bpp = atoi (argv[argc]); + videoflags &= ~SDL_ANYFORMAT; + --argc; + } else + if ( strcmp (argv[argc], "-fast") == 0 ) { + videoflags = [ self fastestFlags:videoflags :width :height :video_bpp ]; + } else + if ( strcmp (argv[argc], "-hw") == 0 ) { + videoflags ^= SDL_HWSURFACE; + } else + if ( strcmp (argv[argc], "-flip") == 0 ) { + videoflags ^= SDL_DOUBLEBUF; + } else + if ( strcmp (argv[argc], "-fullscreen") == 0 ) { + videoflags ^= SDL_FULLSCREEN; + } else + if ( isdigit(argv[argc][0]) ) { + _nSprites = atoi (argv[argc]); + } else { + fprintf (stderr, + "Usage: %s [-bpp N] [-hw] [-flip] [-fast] [-fullscreen] [numSprites]\n", + argv[0]); + exit (1); + } + } + + // The width/height passed to SDL_SetVideoMode should match the size of the NSView + width = [ _view frame ].size.width; + height = [ _view frame ].size.height; + videoflags &= ~SDL_FULLSCREEN; // this only for windowed mode + if ( [ _window styleMask ] & NSResizableWindowMask ) // enable resizable window + videoflags |= SDL_RESIZABLE; + [ self setupCocoaWindow ]; + [ self setCocoaEnvironmentVariables ]; + _mouse_x = width/2; + _mouse_y = width/2; + + // Set video mode + _screen = SDL_SetVideoMode (width, height, video_bpp, videoflags); + if ( ! _screen ) { + fprintf (stderr, "Couldn't set %dx%d video mode: %s\n", + width, height, SDL_GetError()); + exit (2); + } + + // Print out surface info + [ self printFlags:videoflags withName:"Requested flags: " ]; + [ self printFlags:_screen->flags withName:"Got flags: " ]; + + // Load the sprite + // The sprite is located in the Resources section of the .app bundle. + // SDL does not seem aware of bundle paths, so we must construct the path manually. + NSString* resource_path = [[NSBundle mainBundle] resourcePath]; + NSString* icon_path = [resource_path stringByAppendingString:@"/icon.bmp"]; + if ( [ self loadSpriteFromFile:[icon_path UTF8String] ] < 0 ) { + exit (1); + } + + [ self allocSprites ]; + [ self initSprites ]; + + background = SDL_MapRGB (_screen->format, 0x00, 0x00, 0x00); + + // Print out information about our surfaces + printf("Screen is at %d bits per pixel\n", _screen->format->BitsPerPixel); + if ( (_screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { + printf ("Screen is in video memory\n"); + } else { + printf ("Screen is in system memory\n"); + } + if ( (_screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) { + printf ("Screen has double-buffering enabled\n"); + } + if ( (_sprite->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { + printf ("Sprite is in video memory\n"); + } else { + printf ("Sprite is in system memory\n"); + } + + // Run a sample blit to trigger blit acceleration + { + SDL_Rect dst; + dst.x = 0; + dst.y = 0; + dst.w = _sprite->w; + dst.h = _sprite->h; + SDL_BlitSurface (_sprite, NULL, _screen, &dst); + SDL_FillRect (_screen, &dst, background); + } + if ( (_sprite->flags & SDL_HWACCEL) == SDL_HWACCEL ) { + printf("Sprite blit uses hardware acceleration\n"); + } + if ( (_sprite->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { + printf("Sprite blit uses RLE acceleration\n"); + } + + // Loop, blitting sprites and waiting for a keystroke + frames = 0; + then = SDL_GetTicks(); + done = 0; + _sprites_visible = 0; + while ( !done ) { + // Check for events + ++frames; + while ( SDL_PollEvent(&event) ) { + switch (event.type) { + + case SDL_VIDEORESIZE: + + // Recreate the video mode. Use the same bpp and flags + // that the original window was created with + _screen = SDL_SetVideoMode (event.resize.w, event.resize.h, + video_bpp, videoflags); + + // Clear screen and reinit sprite positions + SDL_FillRect (_screen, NULL, 0); + [ self initSprites ]; + break; + + case SDL_MOUSEMOTION: + + _velocities[_nSprites-1].x = 0; + _velocities[_nSprites-1].y = 0; + _positions[_nSprites-1].x = event.motion.x - _sprite->w/2; + _positions[_nSprites-1].y = event.motion.y - _sprite->h/2; + //printf ("motion: %d %d\n", event.motion.x, event.motion.y); + break; + + case SDL_MOUSEBUTTONDOWN: + + _velocities[_nSprites-1].x = 0; + _velocities[_nSprites-1].y = 0; + _positions[_nSprites-1].x = event.button.x; + _positions[_nSprites-1].y = event.button.y; + //printf ("button: %d %d\n", event.button.x, event.button.y); + break; + + case SDL_KEYDOWN: + + // Escape also quits the app + if (event.key.keysym.sym == SDLK_ESCAPE) + done = 1; + + // Control-W warps the cursor + if (event.key.keysym.sym == SDLK_w && + ( SDL_GetModState () & KMOD_LCTRL ) ) + SDL_WarpMouse (_screen->w/2, _screen->h/2); + + // Control-G toggles input grabbing + if (event.key.keysym.sym == SDLK_g && + ( SDL_GetModState () & KMOD_LCTRL ) ) + if ( SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF ) + SDL_WM_GrabInput (SDL_GRAB_ON); + else + SDL_WM_GrabInput (SDL_GRAB_OFF); + break; + + case SDL_QUIT: + done = 1; + break; + default: + break; + } + } + + // Draw sprites + [ self moveSprites:background ]; + + // Update fps counter every 100 frames + if ((frames % 100) == 0) { + now = SDL_GetTicks (); + [ _framesPerSecond setFloatValue:((float)frames*1000)/(now-then) ]; + frames = 0; + then = now; + } + } + [ self freeSprites ]; + SDL_FreeSurface (_sprite); + + SDL_Quit (); + return 0; +} + +- (IBAction)changeNumberOfSprites:(id)sender +{ + [ _numSprites setIntValue:[ sender intValue ] ]; + [ self freeSprites ]; + _nSprites = [ sender intValue ]; + [ self allocSprites ]; + [ self initSprites ]; + SDL_FillRect (_screen, NULL, 0); + SDL_Flip (_screen); +} + +- (IBAction)selectUpdateMode:(id)sender +{ + _doFlip = ![ sender selectedRow ]; // row is 0 or 1 +} + +@end + +int main(int argc, char *argv[]) +{ + // Hand off to instance of MyController + // This instance is created when SDLMain.nib is loaded, + // and the global variable is set in [SDLMain applicationDidFinishLaunching:] + return [ gController run:argc argv:argv ]; +} \ No newline at end of file