ES2Renderer.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. #import "ES2Renderer.h"
  2. // uniform index
  3. enum {
  4. UNIFORM_MODELVIEWMATRIX,
  5. UNIFORM_TEXTURE,
  6. NUM_UNIFORMS
  7. };
  8. GLint uniforms[NUM_UNIFORMS];
  9. // attribute index
  10. enum {
  11. ATTRIB_VERTEX,
  12. ATTRIB_TEXTUREPOSITION,
  13. NUM_ATTRIBUTES
  14. };
  15. @interface ES2Renderer (PrivateMethods)
  16. - (BOOL)loadShaders;
  17. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
  18. - (BOOL)linkProgram:(GLuint)prog;
  19. - (BOOL)validateProgram:(GLuint)prog;
  20. @end
  21. @implementation ES2Renderer
  22. @synthesize outputTexture;
  23. @synthesize newFrameAvailableBlock;
  24. - (id)initWithSize:(CGSize)newSize;
  25. {
  26. if ((self = [super init]))
  27. {
  28. // Need to use a share group based on the GPUImage context to share textures with the 3-D scene
  29. context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[[GPUImageContext sharedImageProcessingContext] context] sharegroup]];
  30. if (!context || ![EAGLContext setCurrentContext:context] || ![self loadShaders])
  31. {
  32. [self release];
  33. return nil;
  34. }
  35. backingWidth = (int)newSize.width;
  36. backingHeight = (int)newSize.height;
  37. currentCalculatedMatrix = CATransform3DIdentity;
  38. currentCalculatedMatrix = CATransform3DScale(currentCalculatedMatrix, 0.5, 0.5 * (320.0/480.0), 0.5);
  39. glActiveTexture(GL_TEXTURE0);
  40. glGenTextures(1, &outputTexture);
  41. glBindTexture(GL_TEXTURE_2D, outputTexture);
  42. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  43. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  44. // This is necessary for non-power-of-two textures
  45. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  46. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  47. glBindTexture(GL_TEXTURE_2D, 0);
  48. glActiveTexture(GL_TEXTURE1);
  49. glGenFramebuffers(1, &defaultFramebuffer);
  50. glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
  51. glBindTexture(GL_TEXTURE_2D, outputTexture);
  52. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  53. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0);
  54. // GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  55. //
  56. // NSAssert(status == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", status);
  57. glBindTexture(GL_TEXTURE_2D, 0);
  58. videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
  59. videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
  60. inputFilter = [[GPUImageSepiaFilter alloc] init];
  61. textureOutput = [[GPUImageTextureOutput alloc] init];
  62. textureOutput.delegate = self;
  63. [videoCamera addTarget:inputFilter];
  64. [inputFilter addTarget:textureOutput];
  65. }
  66. return self;
  67. }
  68. - (void)renderByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation;
  69. {
  70. if (!newFrameAvailableBlock)
  71. {
  72. return;
  73. }
  74. static const GLfloat cubeVertices[] = {
  75. -1.0, -1.0, -1.0, // 0
  76. 1.0, 1.0, -1.0, // 2
  77. 1.0, -1.0, -1.0, // 1
  78. -1.0, -1.0, -1.0, // 0
  79. -1.0, 1.0, -1.0, // 3
  80. 1.0, 1.0, -1.0, // 2
  81. 1.0, -1.0, -1.0, // 1
  82. 1.0, 1.0, -1.0, // 2
  83. 1.0, 1.0, 1.0, // 6
  84. 1.0, 1.0, 1.0, // 6
  85. 1.0, -1.0, 1.0, // 5
  86. 1.0, -1.0, -1.0, // 1
  87. -1.0, -1.0, 1.0, // 4
  88. 1.0, -1.0, 1.0, // 5
  89. 1.0, 1.0, 1.0, // 6
  90. 1.0, 1.0, 1.0, // 6
  91. -1.0, 1.0, 1.0, // 7
  92. -1.0, -1.0, 1.0, // 4
  93. 1.0, 1.0, -1.0, // 2
  94. -1.0, 1.0, -1.0, // 3
  95. 1.0, 1.0, 1.0, // 6
  96. 1.0, 1.0, 1.0, // 6
  97. -1.0, 1.0, -1.0, // 3
  98. -1.0, 1.0, 1.0, // 7
  99. -1.0, -1.0, -1.0, // 0
  100. -1.0, 1.0, 1.0, // 7
  101. -1.0, 1.0, -1.0, // 3
  102. -1.0, -1.0, -1.0, // 0
  103. -1.0, -1.0, 1.0, // 4
  104. -1.0, 1.0, 1.0, // 7
  105. -1.0, -1.0, -1.0, // 0
  106. 1.0, -1.0, -1.0, // 1
  107. 1.0, -1.0, 1.0, // 5
  108. -1.0, -1.0, -1.0, // 0
  109. 1.0, -1.0, 1.0, // 5
  110. -1.0, -1.0, 1.0 // 4
  111. };
  112. const GLfloat cubeTexCoords[] = {
  113. 0.0, 0.0,
  114. 1.0, 1.0,
  115. 1.0, 0.0,
  116. 0.0, 0.0,
  117. 0.0, 1.0,
  118. 1.0, 1.0,
  119. 0.0, 0.0,
  120. 0.0, 1.0,
  121. 1.0, 1.0,
  122. 1.0, 1.0,
  123. 1.0, 0.0,
  124. 0.0, 0.0,
  125. 1.0, 0.0,
  126. 0.0, 0.0,
  127. 0.0, 1.0,
  128. 0.0, 1.0,
  129. 1.0, 1.0,
  130. 1.0, 0.0,
  131. 0.0, 1.0,
  132. 1.0, 1.0,
  133. 0.0, 0.0,
  134. 0.0, 0.0,
  135. 1.0, 1.0,
  136. 1.0, 0.0,
  137. 1.0, 0.0,
  138. 0.0, 1.0,
  139. 1.0, 1.0,
  140. 1.0, 0.0,
  141. 0.0, 0.0,
  142. 0.0, 1.0,
  143. 0.0, 1.0,
  144. 1.0, 1.0,
  145. 1.0, 0.0,
  146. 0.0, 1.0,
  147. 1.0, 0.0,
  148. 0.0, 0.0
  149. };
  150. [EAGLContext setCurrentContext:context];
  151. glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
  152. glEnable(GL_CULL_FACE);
  153. glCullFace(GL_BACK);
  154. glViewport(0, 0, backingWidth, backingHeight);
  155. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  156. glClear(GL_COLOR_BUFFER_BIT);
  157. glUseProgram(program);
  158. // Perform incremental rotation based on current angles in X and Y
  159. if ((xRotation != 0.0) || (yRotation != 0.0))
  160. {
  161. GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);
  162. CATransform3D temporaryMatrix = CATransform3DRotate(currentCalculatedMatrix, totalRotation * M_PI / 180.0,
  163. ((xRotation/totalRotation) * currentCalculatedMatrix.m12 + (yRotation/totalRotation) * currentCalculatedMatrix.m11),
  164. ((xRotation/totalRotation) * currentCalculatedMatrix.m22 + (yRotation/totalRotation) * currentCalculatedMatrix.m21),
  165. ((xRotation/totalRotation) * currentCalculatedMatrix.m32 + (yRotation/totalRotation) * currentCalculatedMatrix.m31));
  166. if ((temporaryMatrix.m11 >= -100.0) && (temporaryMatrix.m11 <= 100.0))
  167. currentCalculatedMatrix = temporaryMatrix;
  168. }
  169. else
  170. {
  171. }
  172. GLfloat currentModelViewMatrix[16];
  173. [self convert3DTransform:&currentCalculatedMatrix toMatrix:currentModelViewMatrix];
  174. glActiveTexture(GL_TEXTURE4);
  175. glBindTexture(GL_TEXTURE_2D, textureForCubeFace);
  176. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  177. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  178. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  179. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  180. // Update uniform value
  181. glUniform1i(uniforms[UNIFORM_TEXTURE], 4);
  182. glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWMATRIX], 1, 0, currentModelViewMatrix);
  183. // Update attribute values
  184. glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, cubeVertices);
  185. glEnableVertexAttribArray(ATTRIB_VERTEX);
  186. glVertexAttribPointer(ATTRIB_TEXTUREPOSITION, 2, GL_FLOAT, 0, 0, cubeTexCoords);
  187. glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITION);
  188. glDrawArrays(GL_TRIANGLES, 0, 36);
  189. // The flush is required at the end here to make sure the FBO texture is written to before passing it back to GPUImage
  190. glFlush();
  191. newFrameAvailableBlock();
  192. }
  193. - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
  194. {
  195. GLint status;
  196. const GLchar *source;
  197. source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
  198. if (!source)
  199. {
  200. NSLog(@"Failed to load vertex shader");
  201. return FALSE;
  202. }
  203. *shader = glCreateShader(type);
  204. glShaderSource(*shader, 1, &source, NULL);
  205. glCompileShader(*shader);
  206. #if defined(DEBUG)
  207. GLint logLength;
  208. glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
  209. if (logLength > 0)
  210. {
  211. GLchar *log = (GLchar *)malloc(logLength);
  212. glGetShaderInfoLog(*shader, logLength, &logLength, log);
  213. NSLog(@"Shader compile log:\n%s", log);
  214. free(log);
  215. }
  216. #endif
  217. glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
  218. if (status == 0)
  219. {
  220. glDeleteShader(*shader);
  221. return FALSE;
  222. }
  223. return TRUE;
  224. }
  225. - (BOOL)linkProgram:(GLuint)prog
  226. {
  227. GLint status;
  228. glLinkProgram(prog);
  229. #if defined(DEBUG)
  230. GLint logLength;
  231. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  232. if (logLength > 0)
  233. {
  234. GLchar *log = (GLchar *)malloc(logLength);
  235. glGetProgramInfoLog(prog, logLength, &logLength, log);
  236. NSLog(@"Program link log:\n%s", log);
  237. free(log);
  238. }
  239. #endif
  240. glGetProgramiv(prog, GL_LINK_STATUS, &status);
  241. if (status == 0)
  242. return FALSE;
  243. return TRUE;
  244. }
  245. - (BOOL)validateProgram:(GLuint)prog
  246. {
  247. GLint logLength, status;
  248. glValidateProgram(prog);
  249. glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
  250. if (logLength > 0)
  251. {
  252. GLchar *log = (GLchar *)malloc(logLength);
  253. glGetProgramInfoLog(prog, logLength, &logLength, log);
  254. NSLog(@"Program validate log:\n%s", log);
  255. free(log);
  256. }
  257. glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
  258. if (status == 0)
  259. return FALSE;
  260. return TRUE;
  261. }
  262. - (BOOL)loadShaders
  263. {
  264. GLuint vertShader, fragShader;
  265. NSString *vertShaderPathname, *fragShaderPathname;
  266. // Create shader program
  267. program = glCreateProgram();
  268. // Create and compile vertex shader
  269. vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
  270. if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
  271. {
  272. NSLog(@"Failed to compile vertex shader");
  273. return FALSE;
  274. }
  275. // Create and compile fragment shader
  276. fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
  277. if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname])
  278. {
  279. NSLog(@"Failed to compile fragment shader");
  280. return FALSE;
  281. }
  282. // Attach vertex shader to program
  283. glAttachShader(program, vertShader);
  284. // Attach fragment shader to program
  285. glAttachShader(program, fragShader);
  286. // Bind attribute locations
  287. // this needs to be done prior to linking
  288. glBindAttribLocation(program, ATTRIB_VERTEX, "position");
  289. glBindAttribLocation(program, ATTRIB_TEXTUREPOSITION, "inputTextureCoordinate");
  290. // Link program
  291. if (![self linkProgram:program])
  292. {
  293. NSLog(@"Failed to link program: %d", program);
  294. if (vertShader)
  295. {
  296. glDeleteShader(vertShader);
  297. vertShader = 0;
  298. }
  299. if (fragShader)
  300. {
  301. glDeleteShader(fragShader);
  302. fragShader = 0;
  303. }
  304. if (program)
  305. {
  306. glDeleteProgram(program);
  307. program = 0;
  308. }
  309. return FALSE;
  310. }
  311. // Get uniform locations
  312. uniforms[UNIFORM_MODELVIEWMATRIX] = glGetUniformLocation(program, "modelViewProjMatrix");
  313. uniforms[UNIFORM_TEXTURE] = glGetUniformLocation(program, "texture");
  314. // Release vertex and fragment shaders
  315. if (vertShader)
  316. glDeleteShader(vertShader);
  317. if (fragShader)
  318. glDeleteShader(fragShader);
  319. return TRUE;
  320. }
  321. - (void)dealloc
  322. {
  323. // Tear down GL
  324. if (defaultFramebuffer)
  325. {
  326. glDeleteFramebuffers(1, &defaultFramebuffer);
  327. defaultFramebuffer = 0;
  328. }
  329. if (colorRenderbuffer)
  330. {
  331. glDeleteRenderbuffers(1, &colorRenderbuffer);
  332. colorRenderbuffer = 0;
  333. }
  334. if (program)
  335. {
  336. glDeleteProgram(program);
  337. program = 0;
  338. }
  339. // Tear down context
  340. if ([EAGLContext currentContext] == context)
  341. [EAGLContext setCurrentContext:nil];
  342. [context release];
  343. context = nil;
  344. [super dealloc];
  345. }
  346. - (void)convert3DTransform:(CATransform3D *)transform3D toMatrix:(GLfloat *)matrix;
  347. {
  348. // struct CATransform3D
  349. // {
  350. // CGFloat m11, m12, m13, m14;
  351. // CGFloat m21, m22, m23, m24;
  352. // CGFloat m31, m32, m33, m34;
  353. // CGFloat m41, m42, m43, m44;
  354. // };
  355. matrix[0] = (GLfloat)transform3D->m11;
  356. matrix[1] = (GLfloat)transform3D->m12;
  357. matrix[2] = (GLfloat)transform3D->m13;
  358. matrix[3] = (GLfloat)transform3D->m14;
  359. matrix[4] = (GLfloat)transform3D->m21;
  360. matrix[5] = (GLfloat)transform3D->m22;
  361. matrix[6] = (GLfloat)transform3D->m23;
  362. matrix[7] = (GLfloat)transform3D->m24;
  363. matrix[8] = (GLfloat)transform3D->m31;
  364. matrix[9] = (GLfloat)transform3D->m32;
  365. matrix[10] = (GLfloat)transform3D->m33;
  366. matrix[11] = (GLfloat)transform3D->m34;
  367. matrix[12] = (GLfloat)transform3D->m41;
  368. matrix[13] = (GLfloat)transform3D->m42;
  369. matrix[14] = (GLfloat)transform3D->m43;
  370. matrix[15] = (GLfloat)transform3D->m44;
  371. }
  372. - (void)startCameraCapture;
  373. {
  374. [videoCamera startCameraCapture];
  375. }
  376. #pragma mark -
  377. #pragma mark GPUImageTextureOutputDelegate delegate method
  378. - (void)newFrameReadyFromTextureOutput:(GPUImageTextureOutput *)callbackTextureOutput;
  379. {
  380. // Rotation in response to touch events is handled on the main thread, so to be safe we dispatch this on the main queue as well
  381. // Nominally, I should create a dispatch queue just for the rendering within this application, but not today
  382. dispatch_async(dispatch_get_main_queue(), ^{
  383. textureForCubeFace = callbackTextureOutput.texture;
  384. [self renderByRotatingAroundX:0.0 rotatingAroundY:0.0];
  385. [callbackTextureOutput doneWithTexture];
  386. });
  387. }
  388. @end