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 }