EAGLView.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*
  2. Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company.
  3. Copyright (C) 2009 Id Software, Inc.
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #import <QuartzCore/QuartzCore.h>
  17. #import <OpenGLES/EAGLDrawable.h>
  18. #import "EAGLView.h"
  19. #import "doomAppDelegate.h"
  20. #include "doomiphone.h"
  21. #include <pthread.h>
  22. EAGLView *eaglview;
  23. EAGLContext *context;
  24. @implementation EAGLView
  25. // You must implement this method
  26. + (Class)layerClass {
  27. return [CAEAGLLayer class];
  28. }
  29. float screenResolutionScale = 1.0f;
  30. CAEAGLLayer *eaglLayer;
  31. //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
  32. - (id)initWithCoder:(NSCoder*)coder {
  33. self = [super initWithCoder:coder];
  34. eaglview = self;
  35. // allow multiple touch events
  36. self.multipleTouchEnabled = true;
  37. // Double the resolution on iPhone 4.
  38. if ( [[UIScreen mainScreen] respondsToSelector:@selector(scale)] &&
  39. [self respondsToSelector:@selector(setContentScaleFactor:)] ) {
  40. screenResolutionScale = [UIScreen mainScreen].scale;
  41. // set scaling factor
  42. [self setContentScaleFactor:[UIScreen mainScreen].scale];
  43. }
  44. // Get the layer
  45. eaglLayer = (CAEAGLLayer *)self.layer;
  46. // set opaque so UIKit doesn't try to blend it over other layers
  47. eaglLayer.opaque = YES;
  48. // set it to no-backing-retained so it can do ast pageflips instead
  49. // of update copies, and go to 565 bit depth for higher performance.
  50. eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
  51. [NSNumber numberWithBool:NO],
  52. kEAGLDrawablePropertyRetainedBacking,
  53. kEAGLColorFormatRGB565,
  54. /* kEAGLColorFormatRGBA8, */
  55. kEAGLDrawablePropertyColorFormat,
  56. nil];
  57. context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  58. assert( context );
  59. if ( ![EAGLContext setCurrentContext:context]) {
  60. [self release];
  61. return nil;
  62. }
  63. glGenFramebuffersOES(1, &mViewFramebuffer);
  64. glGenRenderbuffersOES(1, &mViewRenderbuffer);
  65. glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer);
  66. glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer);
  67. [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  68. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mViewRenderbuffer);
  69. // the backing sizes should be the same as the screen
  70. glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  71. glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  72. displaywidth = backingHeight;
  73. displayheight = backingWidth;
  74. glGenRenderbuffersOES(1, &mDepthRenderbuffer);
  75. glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer);
  76. glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
  77. glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer);
  78. // the framebuffer will stay constant
  79. glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer);
  80. glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer);
  81. if ( glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) != GL_FRAMEBUFFER_COMPLETE_OES ) {
  82. printf( "Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES( GL_FRAMEBUFFER_OES ) );
  83. assert( 0 );
  84. }
  85. return self;
  86. }
  87. - (void) handleTouches:(UIEvent*)event {
  88. int touchCount = 0;
  89. static int previousTouchCount;
  90. static int touchRover;
  91. int touchThisSequence[MAX_TOUCHES];
  92. memset( touchThisSequence, 0, sizeof( touchThisSequence ) );
  93. NSSet *touches = [event allTouches];
  94. // printf( "count: %i\n", [touches count] );
  95. // lock the game out temporarily
  96. pthread_mutex_lock( &eventMutex );
  97. for (UITouch *myTouch in touches)
  98. {
  99. CGPoint touchLocation = [myTouch locationInView:nil];
  100. // Scale Touches with the screen resolution.
  101. touchLocation.x *= screenResolutionScale;
  102. touchLocation.y *= screenResolutionScale;
  103. // handle landscape mode and flipping
  104. int x, y;
  105. if ( revLand->value ) {
  106. x = touchLocation.y;
  107. y = ( displayheight - 1 ) - touchLocation.x;
  108. } else {
  109. x = ( displaywidth - 1) - touchLocation.y;
  110. y = touchLocation.x;
  111. }
  112. // printf( "%i, %i\n", x, y );
  113. touchCount++;
  114. touch_t *t2;
  115. // find which one it is closest to
  116. int minDist = 64 * 64; // allow up to 64 unit moves to be drags
  117. int minIndex = -1;
  118. for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) {
  119. t2 = &sysTouches[i];
  120. if ( !t2->down ) {
  121. continue;
  122. }
  123. int dist = ( t2->x - x ) * ( t2->x - x ) + ( t2->y - y ) * ( t2->y - y );
  124. if ( dist < minDist ) {
  125. minDist = dist;
  126. minIndex = i;
  127. }
  128. }
  129. if ( minIndex != -1 ) {
  130. // reuse a touch
  131. sysTouches[minIndex].x = x;
  132. sysTouches[minIndex].y = y;
  133. if (myTouch.phase == UITouchPhaseEnded) {
  134. // if this was released before the game got to see it,
  135. // make it a special case
  136. if ( sysTouches[minIndex].stateCount == 1 ) {
  137. // leave it in the down state with a special count
  138. sysTouches[minIndex].stateCount = -1;
  139. // printf( "Tap release touch on a reuse\n" );
  140. } else {
  141. sysTouches[minIndex].down = false;
  142. sysTouches[minIndex].stateCount = 1;
  143. // printf( "Release touch on a reuse\n" );
  144. }
  145. } else {
  146. if (myTouch.phase == UITouchPhaseBegan) {
  147. sysTouches[minIndex].stateCount = 1;
  148. sysTouches[minIndex].controlOwner = NULL;
  149. // printf( "Begin touch on a reuse\n" );
  150. } else {
  151. // printf( "Drag touch on a reuse\n" );
  152. }
  153. sysTouches[minIndex].down = true;
  154. }
  155. touchThisSequence[minIndex] = true;
  156. } else {
  157. if ( myTouch.phase != UITouchPhaseBegan ) {
  158. printf( "Non-local touch wasn't a begin\n" );
  159. } else {
  160. // allocate a new one
  161. // grab the next rover spot
  162. // don't just use first-not-down, because that might
  163. // cause the release to be missed by the game code.
  164. int i, j;
  165. for ( j = 0 ; j < MAX_TOUCHES ; j++ ) {
  166. i = touchRover;
  167. t2 = &sysTouches[i];
  168. touchRover = ( touchRover + 1 ) % MAX_TOUCHES;
  169. if ( !t2->down ) {
  170. break;
  171. }
  172. }
  173. if ( j == MAX_TOUCHES ) {
  174. printf( "MAX_TOUCHES, clearing everything!\n" );
  175. memset( sysTouches, 0, sizeof( sysTouches ) );
  176. continue;
  177. }
  178. // printf( "new touch down\n" );
  179. t2->x = x;
  180. t2->y = y;
  181. t2->down = true;
  182. t2->controlOwner = NULL;
  183. t2->stateCount = 1;
  184. touchThisSequence[i] = true;
  185. }
  186. }
  187. }
  188. // Change any active touches to released if they weren't
  189. // in the touch set. This will happen if we forced a break because
  190. // a "moved" event was so large that it was very likely a release and
  191. // press of a different finger that happened to be in the same frame.
  192. for ( int i = 0 ; i < MAX_TOUCHES ; i++ ) {
  193. if ( sysTouches[i].down && !touchThisSequence[i] ) {
  194. printf( "clearing touch %i\n", i );
  195. sysTouches[i].down = false;
  196. sysTouches[i].stateCount = 0;
  197. touchCount--;
  198. }
  199. }
  200. // toggle the console with four touches
  201. if ( touchCount == 4 && previousTouchCount != 4 ) {
  202. touchCount = 0; // won't get the releases, because the text field will eat them
  203. if ( textField == nil ) {
  204. // do this before starting the textField, which
  205. // takes a long time
  206. // iphoneActivateConsole();
  207. textField = [UITextField alloc];
  208. [textField initWithFrame:CGRectMake( 0, 0, 20, 20 ) ];
  209. [self addSubview:textField];
  210. [textField release];
  211. textField.hidden = true;
  212. textField.delegate = self;
  213. textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
  214. textField.autocorrectionType = UITextAutocorrectionTypeNo;
  215. [textField becomeFirstResponder];
  216. } else {
  217. }
  218. }
  219. // the game is free to copy the touches now
  220. pthread_mutex_unlock( &eventMutex );
  221. previousTouchCount = touchCount;
  222. }
  223. - (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
  224. // printf( "touchesBegan\n" );
  225. [self handleTouches:event];
  226. }
  227. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  228. // printf( "touchesMoved\n" );
  229. [self handleTouches:event];
  230. }
  231. - (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
  232. // printf( "touchesEnded\n" );
  233. [self handleTouches:event];
  234. }
  235. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  236. // printf( "touchesCancelled\n" );
  237. [self handleTouches:event];
  238. }
  239. @end
  240. @implementation EAGLView (UITextFieldDelegate)
  241. char consoleCommand[1024];
  242. - (BOOL)textFieldShouldReturn:(UITextField *)_textField
  243. {
  244. if ( eaglview->textField == nil ) {
  245. return YES;
  246. }
  247. // we can't just execute this, because we are running in another
  248. // thread, so fetch the line and the game will catch it next time
  249. // around
  250. // lock the game out temporarily
  251. pthread_mutex_lock( &eventMutex );
  252. const char *line = [ eaglview->textField.text UTF8String ];
  253. strncpy( consoleCommand, line, sizeof(consoleCommand)-1 );
  254. eaglview->textField.text = [ NSString stringWithUTF8String: "" ];
  255. // put it away
  256. [textField resignFirstResponder];
  257. [textField removeFromSuperview];
  258. textField = nil;
  259. // lock the game out temporarily
  260. pthread_mutex_unlock( &eventMutex );
  261. return YES;
  262. }
  263. @end
  264. const char * SysIPhoneGetConsoleTextField() {
  265. if ( eaglview->textField == nil ) {
  266. return "";
  267. }
  268. return [ eaglview->textField.text UTF8String ];
  269. }
  270. void SysIPhoneSetConsoleTextField( const char * str) {
  271. assert( eaglview->textField != nil );
  272. eaglview->textField.text = [ NSString stringWithUTF8String: str ];
  273. }
  274. void SysIPhoneSwapBuffers() {
  275. glBindRenderbufferOES(GL_RENDERBUFFER_OES, eaglview->mViewRenderbuffer);
  276. // present the renderbuffer for display
  277. [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  278. }
  279. void SysIPhoneOpenURL( const char *url ) {
  280. Com_Printf( "OpenURL char *: %s\n", url );
  281. NSString *nss = [NSString stringWithCString: url encoding: NSASCIIStringEncoding];
  282. [[UIApplication sharedApplication] openURL:[NSURL URLWithString: nss]];
  283. }
  284. void SysIPhoneSetUIKitOrientation( int isLandscapeRight ) {
  285. if ( isLandscapeRight ) {
  286. [UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
  287. } else {
  288. [UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
  289. }
  290. }