gl_view.mm 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. /*************************************************************************/
  2. /* gl_view.mm */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #import <QuartzCore/QuartzCore.h>
  30. #import <OpenGLES/EAGLDrawable.h>
  31. #include "os_iphone.h"
  32. #include "core/os/keyboard.h"
  33. #include "core/globals.h"
  34. #include "servers/audio_server.h"
  35. #import "gl_view.h"
  36. /*
  37. @interface GLView (private)
  38. - (id)initGLES;
  39. - (BOOL)createFramebuffer;
  40. - (void)destroyFramebuffer;
  41. @end
  42. */
  43. int gl_view_base_fb;
  44. static String keyboard_text;
  45. static GLView* _instance = NULL;
  46. static bool video_found_error = false;
  47. static bool video_playing = false;
  48. static float video_previous_volume = 0.0f;
  49. static CMTime video_current_time;
  50. void _show_keyboard(String p_existing) {
  51. keyboard_text = p_existing;
  52. printf("instance on show is %p\n", _instance);
  53. [_instance open_keyboard];
  54. };
  55. void _hide_keyboard() {
  56. printf("instance on hide is %p\n", _instance);
  57. [_instance hide_keyboard];
  58. keyboard_text = "";
  59. };
  60. /*
  61. bool _play_video(String p_path, float p_volume) {
  62. float player_volume = p_volume * AudioServer::get_singleton()->get_singleton()->get_stream_global_volume_scale();
  63. video_previous_volume = [[MPMusicPlayerController applicationMusicPlayer] volume];
  64. //[[MPMusicPlayerController applicationMusicPlayer] setVolume: player_volume];
  65. p_path = Globals::get_singleton()->globalize_path(p_path);
  66. NSString* file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease];
  67. NSURL *file_url = [NSURL fileURLWithPath:file_path];
  68. _instance.moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:file_url];
  69. _instance.moviePlayerController.controlStyle = MPMovieControlStyleNone;
  70. [_instance.moviePlayerController setScalingMode:MPMovieScalingModeAspectFit];
  71. //[_instance.moviePlayerController setScalingMode:MPMovieScalingModeAspectFill];
  72. [[NSNotificationCenter defaultCenter] addObserver:_instance
  73. selector:@selector(moviePlayBackDidFinish:)
  74. name:MPMoviePlayerPlaybackDidFinishNotification
  75. object:_instance.moviePlayerController];
  76. [_instance.moviePlayerController.view setFrame:_instance.bounds];
  77. _instance.moviePlayerController.view.userInteractionEnabled = NO;
  78. [_instance addSubview:_instance.moviePlayerController.view];
  79. [_instance.moviePlayerController play];
  80. video_playing = true;
  81. return true;
  82. }
  83. */
  84. bool _play_video(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
  85. p_path = Globals::get_singleton()->globalize_path(p_path);
  86. NSString* file_path = [[[NSString alloc] initWithUTF8String:p_path.utf8().get_data()] autorelease];
  87. //NSURL *file_url = [NSURL fileURLWithPath:file_path];
  88. _instance.avAsset = [AVAsset assetWithURL:[NSURL fileURLWithPath:file_path]];
  89. _instance.avPlayerItem =[[AVPlayerItem alloc]initWithAsset:_instance.avAsset];
  90. [_instance.avPlayerItem addObserver:_instance forKeyPath:@"status" options:0 context:nil];
  91. _instance.avPlayer = [[AVPlayer alloc]initWithPlayerItem:_instance.avPlayerItem];
  92. _instance.avPlayerLayer =[AVPlayerLayer playerLayerWithPlayer:_instance.avPlayer];
  93. [_instance.avPlayer addObserver:_instance forKeyPath:@"status" options:0 context:nil];
  94. [[NSNotificationCenter defaultCenter] addObserver:_instance
  95. selector:@selector(playerItemDidReachEnd:)
  96. name:AVPlayerItemDidPlayToEndTimeNotification
  97. object:[_instance.avPlayer currentItem]];
  98. [_instance.avPlayer addObserver:_instance forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:0];
  99. [_instance.avPlayerLayer setFrame:_instance.bounds];
  100. [_instance.layer addSublayer:_instance.avPlayerLayer];
  101. [_instance.avPlayer play];
  102. AVMediaSelectionGroup *audioGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic: AVMediaCharacteristicAudible];
  103. NSMutableArray *allAudioParams = [NSMutableArray array];
  104. for (id track in audioGroup.options)
  105. {
  106. NSString* language = [[track locale] localeIdentifier];
  107. NSLog(@"subtitle lang: %@", language);
  108. if ([language isEqualToString:[NSString stringWithUTF8String:p_audio_track.utf8()]])
  109. {
  110. AVMutableAudioMixInputParameters *audioInputParams = [AVMutableAudioMixInputParameters audioMixInputParameters];
  111. [audioInputParams setVolume:p_volume atTime:kCMTimeZero];
  112. [audioInputParams setTrackID:[track trackID]];
  113. [allAudioParams addObject:audioInputParams];
  114. AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
  115. [audioMix setInputParameters:allAudioParams];
  116. [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup: audioGroup];
  117. [_instance.avPlayer.currentItem setAudioMix:audioMix];
  118. break;
  119. }
  120. }
  121. AVMediaSelectionGroup *subtitlesGroup = [_instance.avAsset mediaSelectionGroupForMediaCharacteristic: AVMediaCharacteristicLegible];
  122. NSArray *useableTracks = [AVMediaSelectionGroup mediaSelectionOptionsFromArray:subtitlesGroup.options withoutMediaCharacteristics:[NSArray arrayWithObject:AVMediaCharacteristicContainsOnlyForcedSubtitles]];
  123. for (id track in useableTracks)
  124. {
  125. NSString* language = [[track locale] localeIdentifier];
  126. NSLog(@"subtitle lang: %@", language);
  127. if ([language isEqualToString:[NSString stringWithUTF8String:p_subtitle_track.utf8()]])
  128. {
  129. [_instance.avPlayer.currentItem selectMediaOption:track inMediaSelectionGroup: subtitlesGroup];
  130. break;
  131. }
  132. }
  133. video_playing = true;
  134. return true;
  135. }
  136. bool _is_video_playing() {
  137. //NSInteger playback_state = _instance.moviePlayerController.playbackState;
  138. //return video_playing || _instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying;
  139. //if (video_found_error)
  140. // return false;
  141. //return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
  142. return video_playing || (_instance.avPlayer.rate > 0 && !_instance.avPlayer.error);
  143. }
  144. void _pause_video() {
  145. //[_instance.moviePlayerController pause];
  146. video_current_time = _instance.avPlayer.currentTime;
  147. [_instance.avPlayer pause];
  148. video_playing = false;
  149. }
  150. void _focus_out_video() {
  151. printf("focus out pausing video\n");
  152. [_instance.avPlayer pause];
  153. };
  154. void _unpause_video() {
  155. [_instance.avPlayer play];
  156. video_playing = true;
  157. //video_current_time = kCMTimeZero;
  158. };
  159. void _stop_video() {
  160. //[_instance.moviePlayerController stop];
  161. //[_instance.moviePlayerController.view removeFromSuperview];
  162. //[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
  163. [_instance.avPlayer pause];
  164. [_instance.avPlayerLayer removeFromSuperlayer];
  165. _instance.avPlayer = nil;
  166. video_playing = false;
  167. }
  168. @implementation GLView
  169. @synthesize animationInterval;
  170. static const int max_touches = 8;
  171. static UITouch* touches[max_touches];
  172. static void init_touches() {
  173. for (int i=0; i<max_touches; i++) {
  174. touches[i] = NULL;
  175. };
  176. };
  177. static int get_touch_id(UITouch* p_touch) {
  178. int first = -1;
  179. for (int i=0; i<max_touches; i++) {
  180. if (first == -1 && touches[i] == NULL) {
  181. first = i;
  182. continue;
  183. };
  184. if (touches[i] == p_touch)
  185. return i;
  186. };
  187. if (first != -1) {
  188. touches[first] = p_touch;
  189. return first;
  190. };
  191. return -1;
  192. };
  193. static int remove_touch(UITouch* p_touch) {
  194. int remaining = 0;
  195. for (int i=0; i<max_touches; i++) {
  196. if (touches[i] == NULL)
  197. continue;
  198. if (touches[i] == p_touch)
  199. touches[i] = NULL;
  200. else
  201. ++remaining;
  202. };
  203. return remaining;
  204. };
  205. static int get_first_id(UITouch* p_touch) {
  206. for (int i=0; i<max_touches; i++) {
  207. if (touches[i] != NULL)
  208. return i;
  209. };
  210. return -1;
  211. };
  212. static void clear_touches() {
  213. for (int i=0; i<max_touches; i++) {
  214. touches[i] = NULL;
  215. };
  216. };
  217. // Implement this to override the default layer class (which is [CALayer class]).
  218. // We do this so that our view will be backed by a layer that is capable of OpenGL ES rendering.
  219. + (Class) layerClass
  220. {
  221. return [CAEAGLLayer class];
  222. }
  223. //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
  224. - (id)initWithCoder:(NSCoder*)coder
  225. {
  226. active = FALSE;
  227. if((self = [super initWithCoder:coder]))
  228. {
  229. self = [self initGLES];
  230. }
  231. return self;
  232. }
  233. -(id)initGLES
  234. {
  235. // Get our backing layer
  236. CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
  237. // Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color.
  238. eaglLayer.opaque = YES;
  239. eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
  240. [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,
  241. kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
  242. nil];
  243. // Create our EAGLContext, and if successful make it current and create our framebuffer.
  244. context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  245. if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer])
  246. {
  247. [self release];
  248. return nil;
  249. }
  250. // Default the animation interval to 1/60th of a second.
  251. animationInterval = 1.0 / 60.0;
  252. return self;
  253. }
  254. -(id<GLViewDelegate>)delegate
  255. {
  256. return delegate;
  257. }
  258. // Update the delegate, and if it needs a -setupView: call, set our internal flag so that it will be called.
  259. -(void)setDelegate:(id<GLViewDelegate>)d
  260. {
  261. delegate = d;
  262. delegateSetup = ![delegate respondsToSelector:@selector(setupView:)];
  263. }
  264. // If our view is resized, we'll be asked to layout subviews.
  265. // This is the perfect opportunity to also update the framebuffer so that it is
  266. // the same size as our display area.
  267. -(void)layoutSubviews
  268. {
  269. printf("HERE\n");
  270. [EAGLContext setCurrentContext:context];
  271. [self destroyFramebuffer];
  272. [self createFramebuffer];
  273. [self drawView];
  274. }
  275. - (BOOL)createFramebuffer
  276. {
  277. // Generate IDs for a framebuffer object and a color renderbuffer
  278. UIScreen* mainscr = [UIScreen mainScreen];
  279. printf("******** screen size %i, %i\n", (int)mainscr.currentMode.size.width, (int)mainscr.currentMode.size.height);
  280. if (mainscr.currentMode.size.width == 640 || mainscr.currentMode.size.width == 960) // modern iphone, can go to 640x960
  281. self.contentScaleFactor = 2.0;
  282. glGenFramebuffersOES(1, &viewFramebuffer);
  283. glGenRenderbuffersOES(1, &viewRenderbuffer);
  284. glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  285. glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  286. // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer)
  287. // allowing us to draw into a buffer that will later be rendered to screen whereever the layer is (which corresponds with our view).
  288. [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
  289. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
  290. glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  291. glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  292. // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer.
  293. glGenRenderbuffersOES(1, &depthRenderbuffer);
  294. glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
  295. glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
  296. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
  297. if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
  298. {
  299. NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
  300. return NO;
  301. }
  302. if (OS::get_singleton()) {
  303. OS::VideoMode vm;
  304. vm.fullscreen = true;
  305. vm.width = backingWidth;
  306. vm.height = backingHeight;
  307. vm.resizable = false;
  308. OS::get_singleton()->set_video_mode(vm);
  309. OSIPhone::get_singleton()->set_base_framebuffer(viewFramebuffer);
  310. };
  311. gl_view_base_fb = viewFramebuffer;
  312. return YES;
  313. }
  314. // Clean up any buffers we have allocated.
  315. - (void)destroyFramebuffer
  316. {
  317. glDeleteFramebuffersOES(1, &viewFramebuffer);
  318. viewFramebuffer = 0;
  319. glDeleteRenderbuffersOES(1, &viewRenderbuffer);
  320. viewRenderbuffer = 0;
  321. if(depthRenderbuffer)
  322. {
  323. glDeleteRenderbuffersOES(1, &depthRenderbuffer);
  324. depthRenderbuffer = 0;
  325. }
  326. }
  327. - (void)startAnimation
  328. {
  329. if (active)
  330. return;
  331. active = TRUE;
  332. printf("start animation!\n");
  333. #if USE_CADISPLAYLINK
  334. // Approximate frame rate
  335. // assumes device refreshes at 60 fps
  336. int frameInterval = (int) floor(animationInterval * 60.0f);
  337. displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
  338. [displayLink setFrameInterval:frameInterval];
  339. // Setup DisplayLink in main thread
  340. [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  341. #else
  342. animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
  343. #endif
  344. if (video_playing)
  345. {
  346. _unpause_video();
  347. }
  348. }
  349. - (void)stopAnimation
  350. {
  351. if (!active)
  352. return;
  353. active = FALSE;
  354. printf("******** stop animation!\n");
  355. #if USE_CADISPLAYLINK
  356. [displayLink invalidate];
  357. displayLink = nil;
  358. #else
  359. [animationTimer invalidate];
  360. animationTimer = nil;
  361. #endif
  362. clear_touches();
  363. if (video_playing)
  364. {
  365. // save position
  366. }
  367. }
  368. - (void)setAnimationInterval:(NSTimeInterval)interval
  369. {
  370. animationInterval = interval;
  371. #if USE_CADISPLAYLINK
  372. if(displayLink)
  373. #else
  374. if(animationTimer)
  375. #endif
  376. {
  377. [self stopAnimation];
  378. [self startAnimation];
  379. }
  380. }
  381. // Updates the OpenGL view when the timer fires
  382. - (void)drawView
  383. {
  384. #if USE_CADISPLAYLINK
  385. // Pause the CADisplayLink to avoid recursion
  386. [displayLink setPaused: YES];
  387. // Process all input events
  388. while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
  389. // We are good to go, resume the CADisplayLink
  390. [displayLink setPaused: NO];
  391. #endif
  392. if (!active) {
  393. printf("draw view not active!\n");
  394. return;
  395. };
  396. // Make sure that you are drawing to the current context
  397. [EAGLContext setCurrentContext:context];
  398. // If our drawing delegate needs to have the view setup, then call -setupView: and flag that it won't need to be called again.
  399. if(!delegateSetup)
  400. {
  401. [delegate setupView:self];
  402. delegateSetup = YES;
  403. }
  404. glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  405. [delegate drawView:self];
  406. glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  407. [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  408. #ifdef DEBUG_ENABLED
  409. GLenum err = glGetError();
  410. if(err)
  411. NSLog(@"%x error", err);
  412. #endif
  413. }
  414. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  415. {
  416. NSArray* tlist = [[event allTouches] allObjects];
  417. for (unsigned int i=0; i< [tlist count]; i++) {
  418. if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
  419. UITouch* touch = [tlist objectAtIndex:i];
  420. if (touch.phase != UITouchPhaseBegan)
  421. continue;
  422. int tid = get_touch_id(touch);
  423. ERR_FAIL_COND(tid == -1);
  424. CGPoint touchPoint = [touch locationInView:self];
  425. OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1, tid == 0);
  426. };
  427. };
  428. }
  429. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  430. {
  431. NSArray* tlist = [[event allTouches] allObjects];
  432. for (unsigned int i=0; i< [tlist count]; i++) {
  433. if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
  434. UITouch* touch = [tlist objectAtIndex:i];
  435. if (touch.phase != UITouchPhaseMoved)
  436. continue;
  437. int tid = get_touch_id(touch);
  438. ERR_FAIL_COND(tid == -1);
  439. int first = get_first_id(touch);
  440. CGPoint touchPoint = [touch locationInView:self];
  441. CGPoint prev_point = [touch previousLocationInView:self];
  442. OSIPhone::get_singleton()->mouse_move(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, first == tid);
  443. };
  444. };
  445. }
  446. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  447. {
  448. NSArray* tlist = [[event allTouches] allObjects];
  449. for (unsigned int i=0; i< [tlist count]; i++) {
  450. if ( [touches containsObject:[tlist objectAtIndex:i]] ) {
  451. UITouch* touch = [tlist objectAtIndex:i];
  452. if (touch.phase != UITouchPhaseEnded)
  453. continue;
  454. int tid = get_touch_id(touch);
  455. ERR_FAIL_COND(tid == -1);
  456. int rem = remove_touch(touch);
  457. CGPoint touchPoint = [touch locationInView:self];
  458. OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false, rem == 0);
  459. };
  460. };
  461. }
  462. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  463. OSIPhone::get_singleton()->touches_cancelled();
  464. clear_touches();
  465. };
  466. - (BOOL)canBecomeFirstResponder {
  467. return YES;
  468. };
  469. - (void)open_keyboard {
  470. //keyboard_text = p_existing;
  471. [self becomeFirstResponder];
  472. };
  473. - (void)hide_keyboard {
  474. //keyboard_text = p_existing;
  475. [self resignFirstResponder];
  476. };
  477. - (void)deleteBackward {
  478. if (keyboard_text.length())
  479. keyboard_text.erase(keyboard_text.length() - 1, 1);
  480. OSIPhone::get_singleton()->key(KEY_BACKSPACE, true);
  481. };
  482. - (BOOL)hasText {
  483. return keyboard_text.length() ? YES : NO;
  484. };
  485. - (void)insertText:(NSString *)p_text {
  486. String character;
  487. character.parse_utf8([p_text UTF8String]);
  488. keyboard_text = keyboard_text + character;
  489. OSIPhone::get_singleton()->key(character[0] == 10 ? KEY_ENTER : character[0] , true);
  490. printf("inserting text with character %i\n", character[0]);
  491. };
  492. - (void)audioRouteChangeListenerCallback:(NSNotification*)notification
  493. {
  494. printf("*********** route changed!%i\n");
  495. NSDictionary *interuptionDict = notification.userInfo;
  496. NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
  497. switch (routeChangeReason) {
  498. case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
  499. NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");
  500. NSLog(@"Headphone/Line plugged in");
  501. break;
  502. case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
  503. NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
  504. NSLog(@"Headphone/Line was pulled. Resuming video play....");
  505. if (_is_video_playing) {
  506. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  507. [_instance.avPlayer play]; // NOTE: change this line according your current player implementation
  508. NSLog(@"resumed play");
  509. });
  510. };
  511. break;
  512. case AVAudioSessionRouteChangeReasonCategoryChange:
  513. // called at start - also when other audio wants to play
  514. NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
  515. break;
  516. }
  517. }
  518. // When created via code however, we get initWithFrame
  519. -(id)initWithFrame:(CGRect)frame
  520. {
  521. self = [super initWithFrame:frame];
  522. _instance = self;
  523. printf("after init super %p\n", self);
  524. if(self != nil)
  525. {
  526. self = [self initGLES];
  527. printf("after init gles %p\n", self);
  528. }
  529. init_touches();
  530. self. multipleTouchEnabled = YES;
  531. printf("******** adding observer for sound routing changes\n");
  532. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)
  533. name:AVAudioSessionRouteChangeNotification
  534. object:nil];
  535. //self.autoresizesSubviews = YES;
  536. //[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
  537. return self;
  538. }
  539. // -(BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
  540. // return YES;
  541. // }
  542. // - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
  543. // return YES;
  544. // }
  545. // Stop animating and release resources when they are no longer needed.
  546. - (void)dealloc
  547. {
  548. [self stopAnimation];
  549. if([EAGLContext currentContext] == context)
  550. {
  551. [EAGLContext setCurrentContext:nil];
  552. }
  553. [context release];
  554. context = nil;
  555. [super dealloc];
  556. }
  557. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
  558. change:(NSDictionary *)change context:(void *)context {
  559. if (object == _instance.avPlayerItem && [keyPath isEqualToString:@"status"]) {
  560. if (_instance.avPlayerItem.status == AVPlayerStatusFailed || _instance.avPlayer.status == AVPlayerStatusFailed) {
  561. _stop_video();
  562. video_found_error = true;
  563. }
  564. if(_instance.avPlayer.status == AVPlayerStatusReadyToPlay &&
  565. _instance.avPlayerItem.status == AVPlayerItemStatusReadyToPlay &&
  566. CMTIME_COMPARE_INLINE(video_current_time, ==, kCMTimeZero)) {
  567. //NSLog(@"time: %@", video_current_time);
  568. [_instance.avPlayer seekToTime:video_current_time];
  569. video_current_time = kCMTimeZero;
  570. }
  571. }
  572. if (object == _instance.avPlayer && [keyPath isEqualToString:@"rate"]) {
  573. NSLog(@"Player playback rate changed: %.5f", _instance.avPlayer.rate);
  574. if (_is_video_playing() && _instance.avPlayer.rate == 0.0 && !_instance.avPlayer.error) {
  575. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  576. [_instance.avPlayer play]; // NOTE: change this line according your current player implementation
  577. NSLog(@"resumed play");
  578. });
  579. NSLog(@" . . . PAUSED (or just started)");
  580. }
  581. }
  582. }
  583. - (void)playerItemDidReachEnd:(NSNotification *)notification {
  584. _stop_video();
  585. }
  586. /*
  587. - (void)moviePlayBackDidFinish:(NSNotification*)notification {
  588. NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
  589. switch ([reason intValue]) {
  590. case MPMovieFinishReasonPlaybackEnded:
  591. //NSLog(@"Playback Ended");
  592. break;
  593. case MPMovieFinishReasonPlaybackError:
  594. //NSLog(@"Playback Error");
  595. video_found_error = true;
  596. break;
  597. case MPMovieFinishReasonUserExited:
  598. //NSLog(@"User Exited");
  599. video_found_error = true;
  600. break;
  601. default:
  602. //NSLog(@"Unsupported reason!");
  603. break;
  604. }
  605. MPMoviePlayerController *player = [notification object];
  606. [[NSNotificationCenter defaultCenter]
  607. removeObserver:self
  608. name:MPMoviePlayerPlaybackDidFinishNotification
  609. object:player];
  610. [_instance.moviePlayerController stop];
  611. [_instance.moviePlayerController.view removeFromSuperview];
  612. //[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
  613. video_playing = false;
  614. }
  615. */
  616. @end