Mercurial > sdl-ios-xcode
view Xcode/TemplatesForProjectBuilder/SDL Custom Cocoa Application/MyController.m @ 2812:dc39c0b02f12
Finally got the right mojo for Apple's YUV texture format.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 01 Dec 2008 00:03:51 +0000 |
parents | d63e9f5944ae |
children |
line wrap: on
line source
// // 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 ]; }