/xbmc/visualizations/Goom/goom2k4-0/mac/StandAlone/AppController.m

http://github.com/xbmc/xbmc · Objective C · 438 lines · 286 code · 69 blank · 83 comment · 35 complexity · 43f362eca6efa14929fec14a8b182c20 MD5 · raw file

  1. #import "AppController.h"
  2. #import "GoomFXView.h"
  3. #include "src/goom.h"
  4. #import <OpenGL/OpenGL.h>
  5. @interface AppController (AnimationMethods)
  6. - (BOOL) isAnimating;
  7. - (void) startAnimation;
  8. - (void) stopAnimation;
  9. - (void) toggleAnimation;
  10. - (void) startAnimationTimer;
  11. - (void) stopAnimationTimer;
  12. - (void) animationTimerFired:(NSTimer *)timer;
  13. @end
  14. static float HowLong(AbsoluteTime * backUpTime)
  15. {
  16. AbsoluteTime absTime;
  17. Nanoseconds nanosec;
  18. absTime = SubAbsoluteFromAbsolute(UpTime(), *backUpTime);
  19. nanosec = AbsoluteToNanoseconds(absTime);
  20. //fprintf(stderr,"Time : %f\n", (float) UnsignedWideToUInt64( nanosec ) / 1000000000.0);
  21. //fprintf(stderr,"FPS : %f\n", (float) 1000000000.0f/UnsignedWideToUInt64( nanosec ));
  22. *backUpTime = UpTime();
  23. return (float) (1000000000.0f/UnsignedWideToUInt64( nanosec ));
  24. }
  25. static void logGLError(int line)
  26. {
  27. GLenum err = glGetError();
  28. char * code;
  29. if (err == GL_NO_ERROR) return;
  30. switch (err)
  31. {
  32. case GL_INVALID_ENUM:
  33. code = "GL_INVALID_ENUM";
  34. break;
  35. case GL_INVALID_VALUE:
  36. code = "GL_INVALID_VALUE";
  37. break;
  38. case GL_INVALID_OPERATION:
  39. code = "GL_INVALID_OPERATION";
  40. break;
  41. case GL_STACK_OVERFLOW:
  42. code = "GL_STACK_OVERFLOW";
  43. break;
  44. case GL_STACK_UNDERFLOW:
  45. code = "GL_STACK_UNDERFLOW";
  46. break;
  47. case GL_OUT_OF_MEMORY:
  48. code = "GL_OUT_OF_MEMORY";
  49. break;
  50. default:
  51. code = "Unknown Error";
  52. break;
  53. }
  54. fprintf(stderr,"iGoom OpenGL error : %s", code);
  55. }
  56. @implementation AppController
  57. -(void) awakeFromNib
  58. {
  59. PluginInfo * goomInfos;
  60. int i;
  61. goomInfos = [myGoom infos];
  62. for (i=0; i < goomInfos->nbParams; i++)
  63. {
  64. NSTabViewItem * item = [[[NSTabViewItem alloc] initWithIdentifier:nil] autorelease];
  65. [item setLabel:[NSString stringWithCString:goomInfos->params[i].name]];
  66. [item setView:[[[GoomFXView alloc] initWithFrame:[TabView contentRect] andFX:goomInfos->params[i]] autorelease]];
  67. [TabView addTabViewItem:item];
  68. // Create and load textures for the first time
  69. //[GLView loadTextures:GL_TRUE];
  70. }
  71. //[self goFullScreen:self];
  72. isAnimating = NO;
  73. lastFPS = 0.0f;
  74. backUpTime=UpTime();
  75. FrameRate = 0.028f; // ~35 FPS
  76. if ([GLView canBeHQ])
  77. {
  78. [HQButton setEnabled:YES];
  79. [QEWarning removeFromSuperview];
  80. }
  81. [self startAnimation];
  82. }
  83. // Action method wired up to fire when the user clicks the "Go FullScreen" button. We remain in this method until the user exits FullScreen mode.
  84. - (IBAction) goFullScreen:(id)sender
  85. {
  86. CFAbsoluteTime timeNow;
  87. CGLContextObj cglContext;
  88. CGDisplayErr err;
  89. long oldSwapInterval;
  90. long newSwapInterval;
  91. BOOL plugrunning = YES;
  92. long rendererID;
  93. // Pixel Format Attributes for the FullScreen NSOpenGLContext
  94. NSOpenGLPixelFormatAttribute attrs[] = {
  95. // Specify that we want a full-screen OpenGL context.
  96. NSOpenGLPFAFullScreen,
  97. // We may be on a multi-display system (and each screen may be driven by a different renderer),
  98. // so we need to specify which screen we want to take over.
  99. // For this demo, we'll specify the main screen.
  100. NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
  101. // Attributes Common to FullScreen and non-FullScreen
  102. NSOpenGLPFAColorSize, 24,
  103. NSOpenGLPFADepthSize, 16,
  104. NSOpenGLPFADoubleBuffer,
  105. NSOpenGLPFAAccelerated,
  106. 0
  107. };
  108. // Create the FullScreen NSOpenGLContext with the attributes listed above.
  109. NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
  110. if (pixelFormat == nil) {
  111. NSLog(@"Failed to create 1st pixelFormat, trying another format...");
  112. NSOpenGLPixelFormatAttribute attrs2[] = {
  113. NSOpenGLPFAFullScreen,
  114. NSOpenGLPFAScreenMask, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
  115. 0
  116. };
  117. // Create the FullScreen NSOpenGLContext with the attributes listed above.
  118. NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2];
  119. if (pixelFormat == nil) {
  120. NSLog(@"Failed to create 2nd pixelFormat, canceling full screen mode.");
  121. return;
  122. }
  123. }
  124. // Just as a diagnostic, report the renderer ID that this pixel format binds to.
  125. // CGLRenderers.h contains a list of known renderers and their corresponding RendererID codes.
  126. [pixelFormat getValues:&rendererID forAttribute:NSOpenGLPFARendererID forVirtualScreen:0];
  127. // Create an NSOpenGLContext with the FullScreen pixel format.
  128. // By specifying the non-FullScreen context as our "shareContext",
  129. // we automatically inherit all of the textures, display lists, and other OpenGL objects it has defined.
  130. fullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:[GLView openGLContext]];
  131. [pixelFormat release];
  132. pixelFormat = nil;
  133. if (fullScreenContext == nil) {
  134. NSLog(@"Failed to create fullScreenContext");
  135. return;
  136. }
  137. // Pause animation in the OpenGL view.
  138. // While we're in full-screen mode, we'll drive the animation actively instead of using a timer callback.
  139. if ([self isAnimating]) {
  140. [self stopAnimationTimer];
  141. }
  142. // Take control of the display where we're about to go FullScreen.
  143. err = CGCaptureAllDisplays();
  144. if (err != CGDisplayNoErr) {
  145. [fullScreenContext release];
  146. fullScreenContext = nil;
  147. return;
  148. }
  149. // Enter FullScreen mode and make our FullScreen context the active context for OpenGL commands.
  150. [fullScreenContext setFullScreen];
  151. [fullScreenContext makeCurrentContext];
  152. // Save the current swap interval so we can restore it later, and then set the new swap interval to lock us to the display's refresh rate.
  153. cglContext = CGLGetCurrentContext();
  154. CGLGetParameter(cglContext, kCGLCPSwapInterval, &oldSwapInterval);
  155. newSwapInterval = 1;
  156. CGLSetParameter(cglContext, kCGLCPSwapInterval, &newSwapInterval);
  157. // Tell the myGoom the dimensions of the area it's going to render to, so it can set up an appropriate viewport and viewing transformation.
  158. [myGoom setSize:NSMakeSize(CGDisplayPixelsWide(kCGDirectMainDisplay), CGDisplayPixelsHigh(kCGDirectMainDisplay))];
  159. // Now that we've got the screen, we enter a loop in which we alternately process input events and computer and render the next frame of our animation. The shift here is from a model in which we passively receive events handed to us by the AppKit to one in which we are actively driving event processing.
  160. timeBefore = CFAbsoluteTimeGetCurrent();
  161. stayInFullScreenMode = YES;
  162. while (stayInFullScreenMode) {
  163. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  164. // Check for and process input events.
  165. NSEvent *event;
  166. while (event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]) {
  167. switch ([event type]) {
  168. case NSLeftMouseDown:
  169. [self mouseDown:event];
  170. break;
  171. case NSLeftMouseUp:
  172. plugrunning = plugrunning?NO:YES;
  173. [self mouseUp:event];
  174. break;
  175. case NSRightMouseUp:
  176. plugrunning = plugrunning?NO:YES;
  177. break;
  178. case NSLeftMouseDragged:
  179. [self mouseDragged:event];
  180. break;
  181. case NSKeyDown:
  182. [self keyDown:event];
  183. break;
  184. default:
  185. break;
  186. }
  187. }
  188. // Render a frame, and swap the front and back buffers.
  189. timeNow = CFAbsoluteTimeGetCurrent();
  190. if ((timeNow-timeBefore) >= FrameRate)
  191. {
  192. timeBefore = timeNow;
  193. if (plugrunning==YES) {
  194. [myGoom render];
  195. [fullScreenContext flushBuffer];
  196. }
  197. }
  198. // Clean up any autoreleased objects that were created this time through the loop.
  199. [pool release];
  200. }
  201. // Clear the front and back framebuffers before switching out of FullScreen mode. (This is not strictly necessary, but avoids an untidy flash of garbage.)
  202. glClearColor(0.0, 0.0, 0.0, 0.0);
  203. glClear(GL_COLOR_BUFFER_BIT);
  204. [fullScreenContext flushBuffer];
  205. glClear(GL_COLOR_BUFFER_BIT);
  206. [fullScreenContext flushBuffer];
  207. // Restore the previously set swap interval.
  208. CGLSetParameter(cglContext, kCGLCPSwapInterval, &oldSwapInterval);
  209. // Exit fullscreen mode and release our FullScreen NSOpenGLContext.
  210. [NSOpenGLContext clearCurrentContext];
  211. [fullScreenContext clearDrawable];
  212. [fullScreenContext release];
  213. fullScreenContext = nil;
  214. // Release control of the display.
  215. CGReleaseAllDisplays();
  216. // Reset the size to the window size
  217. [myGoom setSize:[GLView frame].size];
  218. // Mark our view as needing drawing. (The animation has advanced while we were in FullScreen mode, so its current contents are stale.)
  219. [GLView setNeedsDisplay:YES];
  220. // Resume animation timer firings.
  221. if ([self isAnimating]) {
  222. [self startAnimationTimer];
  223. }
  224. }
  225. - (IBAction) setHighQuality:(id)sender
  226. {
  227. [myGoom setHighQuality:([sender state]==NSOnState)];
  228. }
  229. - (IBAction) setFrameRate:(id)sender
  230. {
  231. FrameRate = 1.0f/[sender floatValue];
  232. [self stopAnimation];
  233. [self startAnimation];
  234. }
  235. - (void) keyDown:(NSEvent *)event
  236. {
  237. unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
  238. switch (c) {
  239. // [Esc] exits FullScreen mode.
  240. case 27:
  241. stayInFullScreenMode = NO;
  242. break;
  243. // [space] toggles rotation of the globe.
  244. case 32:
  245. [self toggleAnimation];
  246. break;
  247. case 'l':
  248. case 'L':
  249. [myGoom setHighQuality:NO];
  250. break;
  251. case 'h':
  252. case 'H':
  253. [myGoom setHighQuality:YES];
  254. break;
  255. default:
  256. break;
  257. }
  258. }
  259. /*
  260. - (void)mouseDown:(NSEvent *)theEvent
  261. {
  262. BOOL wasAnimating = [self isAnimating];
  263. BOOL dragging = YES;
  264. NSPoint windowPoint;
  265. NSPoint lastWindowPoint = [theEvent locationInWindow];
  266. float dx, dy;
  267. if (wasAnimating) {
  268. [self stopAnimation];
  269. }
  270. while (dragging) {
  271. theEvent = [[GLView window] nextEventMatchingMask:NSLeftMouseUpMask | NSLeftMouseDraggedMask];
  272. windowPoint = [theEvent locationInWindow];
  273. switch ([theEvent type]) {
  274. case NSLeftMouseUp:
  275. dragging = NO;
  276. break;
  277. case NSLeftMouseDragged:
  278. dx = windowPoint.x - lastWindowPoint.x;
  279. dy = windowPoint.y - lastWindowPoint.y;
  280. lastWindowPoint = windowPoint;
  281. // Render a frame.
  282. if (fullScreenContext) {
  283. [myGoom render];
  284. [fullScreenContext flushBuffer];
  285. } else {
  286. [GLView display];
  287. }
  288. break;
  289. default:
  290. break;
  291. }
  292. }
  293. if (wasAnimating) {
  294. [self startAnimation];
  295. timeBefore = CFAbsoluteTimeGetCurrent();
  296. }
  297. }
  298. */
  299. - (BOOL) isInFullScreenMode
  300. {
  301. return fullScreenContext != nil;
  302. }
  303. @end
  304. @implementation AppController (AnimationMethods)
  305. - (BOOL) isAnimating
  306. {
  307. return isAnimating;
  308. }
  309. - (void) startAnimation
  310. {
  311. if (!isAnimating) {
  312. isAnimating = YES;
  313. if (![self isInFullScreenMode])
  314. {
  315. [self startAnimationTimer];
  316. }
  317. }
  318. }
  319. - (void) stopAnimation
  320. {
  321. if (isAnimating) {
  322. if (animationTimer != nil) {
  323. [self stopAnimationTimer];
  324. }
  325. isAnimating = NO;
  326. }
  327. }
  328. - (void) toggleAnimation
  329. {
  330. if ([self isAnimating]) [self stopAnimation];
  331. else [self startAnimation];
  332. }
  333. - (void) startAnimationTimer
  334. {
  335. if (animationTimer == nil) {
  336. animationTimer = [[NSTimer scheduledTimerWithTimeInterval:FrameRate target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES] retain];
  337. }
  338. }
  339. - (void) stopAnimationTimer
  340. {
  341. if (animationTimer != nil) {
  342. [animationTimer invalidate];
  343. [animationTimer release];
  344. animationTimer = nil;
  345. }
  346. }
  347. - (void) animationTimerFired:(NSTimer *)timer
  348. {
  349. lastFPS = (HowLong(&backUpTime) + lastFPS) * 0.5f;
  350. [FPSCounter setStringValue:[NSString stringWithFormat:@"%d/%d FPS",(int)lastFPS,(int)(1.0f/FrameRate)]];
  351. [GLView setNeedsDisplay:YES];
  352. }
  353. // TAB VIEW DELEGATE
  354. - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
  355. {
  356. NSRect frame = [PrefWin frame];
  357. float height;
  358. if(![[tabViewItem identifier] isEqual:@"maintab"]) height = ((GoomFXView*)[tabViewItem view])->height;
  359. else height = 356.0f;
  360. height += 20.0f;
  361. frame.origin.y -= height-frame.size.height;
  362. frame.size.height = height;
  363. [PrefWin setFrame:frame display:YES animate:YES];
  364. }
  365. @end