Mercurial > sdl-ios-xcode
comparison 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 |
comparison
equal
deleted
inserted
replaced
2206:ca7d2227d630 | 2207:d63e9f5944ae |
---|---|
1 // | |
2 // MyController.m | |
3 // SDL Custom Cocoa App | |
4 // | |
5 // Created by Darrell Walisser on Fri Jul 18 2003. | |
6 // Copyright (c) 2003 __MyCompanyName__. All rights reserved. | |
7 // | |
8 | |
9 #import "MyController.h" | |
10 #import "SDL.h" | |
11 | |
12 id gController; | |
13 | |
14 @implementation MyController | |
15 | |
16 - (id)init | |
17 { | |
18 self = [ super init ]; | |
19 if (self) { | |
20 | |
21 _nSprites = 10; | |
22 _max_speed = 4; | |
23 _doFlip = 0; | |
24 _mem = NULL; | |
25 _screen = NULL; | |
26 _sprite_rects = NULL; | |
27 _positions = NULL; | |
28 _velocities = NULL; | |
29 _sprites_visible = 1; | |
30 _sprite_w = 0; | |
31 _sprite_h = 0; | |
32 _mouse_x = 0; | |
33 _mouse_y = 0; | |
34 } | |
35 | |
36 return self; | |
37 } | |
38 | |
39 - (void)setupCocoaWindow | |
40 { | |
41 // If you want the close button to send SDL_Quit, | |
42 // you can attach the SDL_QuartzWindowDelegate to the window | |
43 [ _window setDelegate: | |
44 [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; | |
45 | |
46 // Make the window visible and the frontmost window | |
47 [ _window makeKeyAndOrderFront:nil ]; | |
48 | |
49 // Make the window accept passive motion events (when the button is released) | |
50 [ _window setAcceptsMouseMovedEvents:YES ]; | |
51 } | |
52 | |
53 - (void)setCocoaEnvironmentVariables | |
54 { | |
55 // Export cocoa objects to environment | |
56 // SDL will use these when you call SDL_SetVideoMode | |
57 | |
58 // The window must be visible when you call SDL_SetVideoMode, | |
59 // and the view must lie completely within the window. | |
60 // | |
61 // The width and height passed to SDL_SetVideoMode should match | |
62 // the width/height of the view (the window can be any size) | |
63 // | |
64 // For resizing to work, you must set the appropriate | |
65 // attributes on the window and view. Then the SDL_RESIZABLE | |
66 // flag will be set automatically | |
67 // | |
68 // SDL will retain a reference to the window, and | |
69 // will release it when unsetting the video mode | |
70 // | |
71 // The view is not retained (the window object manages this). | |
72 // | |
73 char buffer[256]; | |
74 printf ("NSWindow=%p\n", _window); | |
75 sprintf (buffer, "%d", (int)_window); | |
76 setenv ("SDL_NSWindowPointer", buffer, 1); | |
77 | |
78 printf ("NSQuickDrawView=%p\n", _view); | |
79 sprintf (buffer, "%d", (int)_view); | |
80 setenv ("SDL_NSQuickDrawViewPointer", buffer, 1); | |
81 | |
82 // Also tell SDL to pass keyboard events to Cocoa | |
83 // In this case, Cocoa will get the event before SDL_PollEvent returns it | |
84 // Note that mouse events (button, motion) will always be passed, regardless of this setting | |
85 setenv ("SDL_ENABLEAPPEVENTS", "1", 1); | |
86 } | |
87 | |
88 - (void)printFlags:(Uint32)flags withName:(const char*)name | |
89 { | |
90 printf ("%s", name); | |
91 | |
92 if (flags & SDL_SWSURFACE) | |
93 printf (" - SDL_SWSURFACE"); | |
94 if (flags & SDL_HWSURFACE) | |
95 printf (" - SDL_HWSURFACE"); | |
96 if (flags & SDL_ASYNCBLIT) | |
97 printf (" - SDL_ASYNCBLIT"); | |
98 if (flags & SDL_ANYFORMAT) | |
99 printf (" - SDL_ANYFORMAT"); | |
100 if (flags & SDL_HWPALETTE) | |
101 printf (" - SDL_HWPALETTE"); | |
102 if (flags & SDL_DOUBLEBUF) | |
103 printf (" - SDL_DOUBLEBUF"); | |
104 if (flags & SDL_FULLSCREEN) | |
105 printf (" - SDL_FULLSCREEN"); | |
106 if (flags & SDL_OPENGL) | |
107 printf (" - SDL_OPENGL"); | |
108 if (flags & SDL_OPENGLBLIT) | |
109 printf (" - SDL_OPENGLBLIT"); | |
110 if (flags & SDL_RESIZABLE) | |
111 printf (" - SDL_RESIZABLE"); | |
112 if (flags & SDL_NOFRAME) | |
113 printf (" - SDL_NOFRAME"); | |
114 | |
115 printf ("\n"); | |
116 } | |
117 // This is a way of telling whether or not to use hardware surfaces | |
118 // Note: this does nothing on Mac OS X at the moment - there is no | |
119 // hardware-accelerated blitting support. | |
120 - (Uint32)fastestFlags:(Uint32)flags :(int)width :(int)height :(int)bpp | |
121 { | |
122 const SDL_VideoInfo *info; | |
123 | |
124 // Hardware acceleration is only used in fullscreen mode | |
125 flags |= SDL_FULLSCREEN; | |
126 | |
127 // Check for various video capabilities | |
128 info = SDL_GetVideoInfo(); | |
129 if ( info->blit_hw_CC && info->blit_fill ) { | |
130 // We use accelerated colorkeying and color filling | |
131 flags |= SDL_HWSURFACE; | |
132 } | |
133 // If we have enough video memory, and will use accelerated | |
134 // blits directly to it, then use page flipping. | |
135 if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { | |
136 | |
137 // Direct hardware blitting without double-buffering | |
138 // causes really bad flickering. | |
139 if ( info->video_mem*1024 > (height*width*bpp/8) ) { | |
140 flags |= SDL_DOUBLEBUF; | |
141 } else { | |
142 flags &= ~SDL_HWSURFACE; | |
143 } | |
144 } | |
145 | |
146 // Return the flags | |
147 return flags; | |
148 } | |
149 | |
150 - (int)loadSpriteFromFile:(const char*)file | |
151 { | |
152 SDL_Surface *temp; | |
153 | |
154 // Load the sprite image | |
155 _sprite = SDL_LoadBMP (file); | |
156 if ( _sprite == NULL ) { | |
157 fprintf (stderr, "Couldn't load %s: %s", file, SDL_GetError ()); | |
158 return (-1); | |
159 } | |
160 | |
161 // Set transparent pixel as the pixel at (0,0) | |
162 if ( _sprite->format->palette ) { | |
163 SDL_SetColorKey (_sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL), | |
164 *(Uint8 *)_sprite->pixels); | |
165 } | |
166 | |
167 /* Convert sprite to video format */ | |
168 temp = SDL_DisplayFormat (_sprite); | |
169 SDL_FreeSurface (_sprite); | |
170 if ( temp == NULL ) { | |
171 fprintf(stderr, "Couldn't convert background: %s\n", | |
172 SDL_GetError ()); | |
173 return (-1); | |
174 } | |
175 _sprite = temp; | |
176 | |
177 // We're ready to roll. :) | |
178 return 0; | |
179 } | |
180 | |
181 - (void)allocSprites | |
182 { | |
183 /* Allocate memory for the sprite info */ | |
184 _mem = (Uint8 *)malloc (4*sizeof(SDL_Rect)*_nSprites); | |
185 if ( _mem == NULL ) { | |
186 fprintf (stderr, "Out of memory!\n"); | |
187 exit (2); | |
188 } | |
189 | |
190 _sprite_rects = (SDL_Rect *)_mem; | |
191 _positions = _sprite_rects; | |
192 _sprite_rects += _nSprites; | |
193 _velocities = _sprite_rects; | |
194 _sprite_rects += _nSprites; | |
195 _sprite_w = _sprite->w; | |
196 _sprite_h = _sprite->h; | |
197 } | |
198 | |
199 - (void)freeSprites | |
200 { | |
201 free (_mem); | |
202 _mem = NULL; | |
203 } | |
204 | |
205 - (void)initSprites | |
206 { | |
207 // Give each sprite a random starting position and velocity | |
208 int i; | |
209 | |
210 srand(time(NULL)); | |
211 for ( i=0; i < _nSprites; ++i ) { | |
212 _positions[i].x = rand()%(_screen->w - _sprite->w); | |
213 _positions[i].y = rand()%(_screen->h - _sprite->h); | |
214 _positions[i].w = _sprite->w; | |
215 _positions[i].h = _sprite->h; | |
216 _velocities[i].x = 0; | |
217 _velocities[i].y = 0; | |
218 while ( ! _velocities[i].x && ! _velocities[i].y ) { | |
219 _velocities[i].x = (rand()%(_max_speed*2+1)) - _max_speed; | |
220 _velocities[i].y = (rand()%(_max_speed*2+1)) - _max_speed; | |
221 } | |
222 } | |
223 } | |
224 | |
225 - (void)moveSprites:(int)backgroundColor; | |
226 { | |
227 int i, nupdates; | |
228 SDL_Rect area, *position, *velocity; | |
229 | |
230 nupdates = 0; | |
231 // Erase all the sprites if necessary | |
232 if ( _sprites_visible ) { | |
233 SDL_FillRect (_screen, NULL, backgroundColor); | |
234 } | |
235 | |
236 // Move the sprite, bounce at the wall, and draw | |
237 for ( i=0; i < _nSprites; ++i ) { | |
238 position = &_positions[i]; | |
239 velocity = &_velocities[i]; | |
240 position->x += velocity->x; | |
241 if ( (position->x < 0) || (position->x >= (_screen->w - _sprite_w)) ) { | |
242 velocity->x = -velocity->x; | |
243 position->x += velocity->x; | |
244 } | |
245 position->y += velocity->y; | |
246 if ( (position->y < 0) || (position->y >= (_screen->h - _sprite_w)) ) { | |
247 velocity->y = -velocity->y; | |
248 position->y += velocity->y; | |
249 } | |
250 | |
251 // Blit the sprite onto the screen | |
252 area = *position; | |
253 SDL_BlitSurface (_sprite, NULL, _screen, &area); | |
254 _sprite_rects[nupdates++] = area; | |
255 } | |
256 | |
257 // Update the screen! | |
258 if ( _doFlip ) { | |
259 SDL_Flip (_screen); | |
260 } else { | |
261 SDL_UpdateRects (_screen, nupdates, _sprite_rects); | |
262 } | |
263 | |
264 _sprites_visible = 1; | |
265 } | |
266 | |
267 - (int)run:(int)argc argv:(char*[])argv | |
268 { | |
269 int width, height; | |
270 Uint8 video_bpp; | |
271 Uint32 videoflags; | |
272 Uint32 background; | |
273 int done; | |
274 SDL_Event event; | |
275 Uint32 then, now, frames; | |
276 | |
277 // Initialize SDL | |
278 if ( SDL_Init (SDL_INIT_VIDEO) < 0 ) { | |
279 fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError ()); | |
280 exit (1); | |
281 } | |
282 atexit(SDL_Quit); | |
283 | |
284 videoflags = SDL_SWSURFACE|SDL_ANYFORMAT; | |
285 width = 640; | |
286 height = 480; | |
287 video_bpp = 8; | |
288 while ( argc > 1 ) { | |
289 --argc; | |
290 if ( strcmp(argv[argc-1], "-width") == 0 ) { | |
291 width = atoi (argv[argc]); | |
292 --argc; | |
293 } else | |
294 if ( strcmp(argv[argc-1], "-height") == 0 ) { | |
295 height = atoi (argv[argc]); | |
296 --argc; | |
297 } else | |
298 if ( strcmp(argv[argc-1], "-bpp") == 0 ) { | |
299 video_bpp = atoi (argv[argc]); | |
300 videoflags &= ~SDL_ANYFORMAT; | |
301 --argc; | |
302 } else | |
303 if ( strcmp (argv[argc], "-fast") == 0 ) { | |
304 videoflags = [ self fastestFlags:videoflags :width :height :video_bpp ]; | |
305 } else | |
306 if ( strcmp (argv[argc], "-hw") == 0 ) { | |
307 videoflags ^= SDL_HWSURFACE; | |
308 } else | |
309 if ( strcmp (argv[argc], "-flip") == 0 ) { | |
310 videoflags ^= SDL_DOUBLEBUF; | |
311 } else | |
312 if ( strcmp (argv[argc], "-fullscreen") == 0 ) { | |
313 videoflags ^= SDL_FULLSCREEN; | |
314 } else | |
315 if ( isdigit(argv[argc][0]) ) { | |
316 _nSprites = atoi (argv[argc]); | |
317 } else { | |
318 fprintf (stderr, | |
319 "Usage: %s [-bpp N] [-hw] [-flip] [-fast] [-fullscreen] [numSprites]\n", | |
320 argv[0]); | |
321 exit (1); | |
322 } | |
323 } | |
324 | |
325 // The width/height passed to SDL_SetVideoMode should match the size of the NSView | |
326 width = [ _view frame ].size.width; | |
327 height = [ _view frame ].size.height; | |
328 videoflags &= ~SDL_FULLSCREEN; // this only for windowed mode | |
329 if ( [ _window styleMask ] & NSResizableWindowMask ) // enable resizable window | |
330 videoflags |= SDL_RESIZABLE; | |
331 [ self setupCocoaWindow ]; | |
332 [ self setCocoaEnvironmentVariables ]; | |
333 _mouse_x = width/2; | |
334 _mouse_y = width/2; | |
335 | |
336 // Set video mode | |
337 _screen = SDL_SetVideoMode (width, height, video_bpp, videoflags); | |
338 if ( ! _screen ) { | |
339 fprintf (stderr, "Couldn't set %dx%d video mode: %s\n", | |
340 width, height, SDL_GetError()); | |
341 exit (2); | |
342 } | |
343 | |
344 // Print out surface info | |
345 [ self printFlags:videoflags withName:"Requested flags: " ]; | |
346 [ self printFlags:_screen->flags withName:"Got flags: " ]; | |
347 | |
348 // Load the sprite | |
349 // The sprite is located in the Resources section of the .app bundle. | |
350 // SDL does not seem aware of bundle paths, so we must construct the path manually. | |
351 NSString* resource_path = [[NSBundle mainBundle] resourcePath]; | |
352 NSString* icon_path = [resource_path stringByAppendingString:@"/icon.bmp"]; | |
353 if ( [ self loadSpriteFromFile:[icon_path UTF8String] ] < 0 ) { | |
354 exit (1); | |
355 } | |
356 | |
357 [ self allocSprites ]; | |
358 [ self initSprites ]; | |
359 | |
360 background = SDL_MapRGB (_screen->format, 0x00, 0x00, 0x00); | |
361 | |
362 // Print out information about our surfaces | |
363 printf("Screen is at %d bits per pixel\n", _screen->format->BitsPerPixel); | |
364 if ( (_screen->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { | |
365 printf ("Screen is in video memory\n"); | |
366 } else { | |
367 printf ("Screen is in system memory\n"); | |
368 } | |
369 if ( (_screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) { | |
370 printf ("Screen has double-buffering enabled\n"); | |
371 } | |
372 if ( (_sprite->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { | |
373 printf ("Sprite is in video memory\n"); | |
374 } else { | |
375 printf ("Sprite is in system memory\n"); | |
376 } | |
377 | |
378 // Run a sample blit to trigger blit acceleration | |
379 { | |
380 SDL_Rect dst; | |
381 dst.x = 0; | |
382 dst.y = 0; | |
383 dst.w = _sprite->w; | |
384 dst.h = _sprite->h; | |
385 SDL_BlitSurface (_sprite, NULL, _screen, &dst); | |
386 SDL_FillRect (_screen, &dst, background); | |
387 } | |
388 if ( (_sprite->flags & SDL_HWACCEL) == SDL_HWACCEL ) { | |
389 printf("Sprite blit uses hardware acceleration\n"); | |
390 } | |
391 if ( (_sprite->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { | |
392 printf("Sprite blit uses RLE acceleration\n"); | |
393 } | |
394 | |
395 // Loop, blitting sprites and waiting for a keystroke | |
396 frames = 0; | |
397 then = SDL_GetTicks(); | |
398 done = 0; | |
399 _sprites_visible = 0; | |
400 while ( !done ) { | |
401 // Check for events | |
402 ++frames; | |
403 while ( SDL_PollEvent(&event) ) { | |
404 switch (event.type) { | |
405 | |
406 case SDL_VIDEORESIZE: | |
407 | |
408 // Recreate the video mode. Use the same bpp and flags | |
409 // that the original window was created with | |
410 _screen = SDL_SetVideoMode (event.resize.w, event.resize.h, | |
411 video_bpp, videoflags); | |
412 | |
413 // Clear screen and reinit sprite positions | |
414 SDL_FillRect (_screen, NULL, 0); | |
415 [ self initSprites ]; | |
416 break; | |
417 | |
418 case SDL_MOUSEMOTION: | |
419 | |
420 _velocities[_nSprites-1].x = 0; | |
421 _velocities[_nSprites-1].y = 0; | |
422 _positions[_nSprites-1].x = event.motion.x - _sprite->w/2; | |
423 _positions[_nSprites-1].y = event.motion.y - _sprite->h/2; | |
424 //printf ("motion: %d %d\n", event.motion.x, event.motion.y); | |
425 break; | |
426 | |
427 case SDL_MOUSEBUTTONDOWN: | |
428 | |
429 _velocities[_nSprites-1].x = 0; | |
430 _velocities[_nSprites-1].y = 0; | |
431 _positions[_nSprites-1].x = event.button.x; | |
432 _positions[_nSprites-1].y = event.button.y; | |
433 //printf ("button: %d %d\n", event.button.x, event.button.y); | |
434 break; | |
435 | |
436 case SDL_KEYDOWN: | |
437 | |
438 // Escape also quits the app | |
439 if (event.key.keysym.sym == SDLK_ESCAPE) | |
440 done = 1; | |
441 | |
442 // Control-W warps the cursor | |
443 if (event.key.keysym.sym == SDLK_w && | |
444 ( SDL_GetModState () & KMOD_LCTRL ) ) | |
445 SDL_WarpMouse (_screen->w/2, _screen->h/2); | |
446 | |
447 // Control-G toggles input grabbing | |
448 if (event.key.keysym.sym == SDLK_g && | |
449 ( SDL_GetModState () & KMOD_LCTRL ) ) | |
450 if ( SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF ) | |
451 SDL_WM_GrabInput (SDL_GRAB_ON); | |
452 else | |
453 SDL_WM_GrabInput (SDL_GRAB_OFF); | |
454 break; | |
455 | |
456 case SDL_QUIT: | |
457 done = 1; | |
458 break; | |
459 default: | |
460 break; | |
461 } | |
462 } | |
463 | |
464 // Draw sprites | |
465 [ self moveSprites:background ]; | |
466 | |
467 // Update fps counter every 100 frames | |
468 if ((frames % 100) == 0) { | |
469 now = SDL_GetTicks (); | |
470 [ _framesPerSecond setFloatValue:((float)frames*1000)/(now-then) ]; | |
471 frames = 0; | |
472 then = now; | |
473 } | |
474 } | |
475 [ self freeSprites ]; | |
476 SDL_FreeSurface (_sprite); | |
477 | |
478 SDL_Quit (); | |
479 return 0; | |
480 } | |
481 | |
482 - (IBAction)changeNumberOfSprites:(id)sender | |
483 { | |
484 [ _numSprites setIntValue:[ sender intValue ] ]; | |
485 [ self freeSprites ]; | |
486 _nSprites = [ sender intValue ]; | |
487 [ self allocSprites ]; | |
488 [ self initSprites ]; | |
489 SDL_FillRect (_screen, NULL, 0); | |
490 SDL_Flip (_screen); | |
491 } | |
492 | |
493 - (IBAction)selectUpdateMode:(id)sender | |
494 { | |
495 _doFlip = ![ sender selectedRow ]; // row is 0 or 1 | |
496 } | |
497 | |
498 @end | |
499 | |
500 int main(int argc, char *argv[]) | |
501 { | |
502 // Hand off to instance of MyController | |
503 // This instance is created when SDLMain.nib is loaded, | |
504 // and the global variable is set in [SDLMain applicationDidFinishLaunching:] | |
505 return [ gController run:argc argv:argv ]; | |
506 } |