BEGLView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright (C) 2018 Beijing Bytedance Network Technology Co., Ltd.
  2. #import "BEGLView.h"
  3. #import <UIKit/UIKit.h>
  4. #import <Masonry.h>
  5. #import <UIView+Toast.h>
  6. @interface BEGLView () {
  7. GLuint _displayTextureID;
  8. BOOL _shouldDeleteTextureID;
  9. GLuint _renderProgram;
  10. GLuint _renderLocation;
  11. GLuint _renderInputImageTexture;
  12. GLuint _renderTextureCoordinate;
  13. GLfloat vertex[8];
  14. unsigned char* saveTextureBuffer;
  15. GLuint _saveTexture;
  16. GLuint _frameBuffer;
  17. CGSize _savedSize;
  18. }
  19. @property (nonatomic, strong) CIContext *ciContext;
  20. @property (nonatomic, strong) EAGLContext *glContext;
  21. @property (nonatomic, assign) unsigned int screenWidth;
  22. @property (nonatomic, assign) unsigned int screenHeight;
  23. @property (nonatomic, strong) UIImageView *imageView;
  24. @end
  25. static float TEXTURE_FLIPPED[] = {0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,};
  26. static float CUBE[] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,};
  27. static float TEXTURE_RORATION_0[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,};
  28. #define TTF_STRINGIZE(x) #x
  29. #define TTF_STRINGIZE2(x) TTF_STRINGIZE(x)
  30. #define TTF_SHADER_STRING(text) @ TTF_STRINGIZE2(text)
  31. static NSString *const RENDER_VERTEX = TTF_SHADER_STRING
  32. (
  33. attribute vec4 position;
  34. attribute vec4 inputTextureCoordinate;
  35. varying vec2 textureCoordinate;
  36. void main(){
  37. float scale = 1.05;
  38. mat4 s = mat4(scale, 0.0, 0.0, 0.0,
  39. 0.0, scale, 0.0, 0.0,
  40. 0.0, 0.0, scale, 0.0,
  41. 0.0, 0.0, 0.0, 1.0);
  42. textureCoordinate = inputTextureCoordinate.xy;
  43. gl_Position = s * position;
  44. }
  45. );
  46. static NSString *const RENDER_FRAGMENT = TTF_SHADER_STRING
  47. (
  48. precision mediump float;
  49. varying highp vec2 textureCoordinate;
  50. uniform sampler2D inputImageTexture;
  51. void main()
  52. {
  53. gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
  54. }
  55. );
  56. @implementation BEGLView
  57. - (void)dealloc
  58. {
  59. //NSLog(@"%@", NSStringFromSelector(_cmd));
  60. free(saveTextureBuffer);
  61. glDeleteTextures(1, &_saveTexture);
  62. glDeleteFramebuffers(1, &_frameBuffer);
  63. }
  64. - (instancetype)initWithFrame:(CGRect)frame {
  65. self = [super initWithFrame:frame];
  66. if (self) {
  67. self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  68. self.ciContext = [CIContext contextWithEAGLContext:self.glContext];
  69. self.context = self.glContext;
  70. if ([EAGLContext currentContext] != self.glContext) {
  71. [EAGLContext setCurrentContext:self.glContext];
  72. }
  73. [self loadRenderShader];
  74. // CGFloat scale = [UIScreen mainScreen].scale;
  75. // UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
  76. // if (orientation == UIInterfaceOrientationPortrait
  77. // || orientation == UIInterfaceOrientationPortraitUpsideDown) {
  78. // _screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
  79. // _screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
  80. // } else {
  81. // _screenHeight = [UIScreen mainScreen].bounds.size.width * scale;
  82. // _screenWidth = [UIScreen mainScreen].bounds.size.height * scale;
  83. // }
  84. //
  85. // float ratio[2] = {1.0, 1.0};
  86. // [self calcVertex:_screenWidth height:_screenHeight ratios:ratio];
  87. //
  88. // for (int i = 0; i < 4; i ++){
  89. // vertex[i * 2] = CUBE[i * 2] / ratio[1];
  90. // vertex[i * 2 + 1] = CUBE[i * 2 + 1] / ratio[0];
  91. // }
  92. // saveTextureBuffer = malloc(_screenHeight * _screenWidth * 4);
  93. //
  94. // glGenTextures(1, &_saveTexture);
  95. // glGenFramebuffers(1, &_frameBuffer);
  96. //
  97. //// [CSToastManager setQueueEnabled:YES];
  98. }
  99. return self;
  100. }
  101. - (void)reloadDraw{
  102. CGFloat scale = [UIScreen mainScreen].scale;
  103. _screenWidth = self.f_width * scale;
  104. _screenHeight = self.f_heigh * scale;
  105. float ratio[2] = {1.0, 1.0};
  106. [self calcVertex:_screenWidth height:_screenHeight ratios:ratio];
  107. for (int i = 0; i < 4; i ++){
  108. vertex[i * 2] = CUBE[i * 2] / ratio[1];
  109. vertex[i * 2 + 1] = CUBE[i * 2 + 1] / ratio[0];
  110. }
  111. saveTextureBuffer = malloc(_screenHeight * _screenWidth * 4);
  112. glGenTextures(1, &_saveTexture);
  113. glGenFramebuffers(1, &_frameBuffer);
  114. //[CSToastManager setQueueEnabled:YES];
  115. }
  116. - (void)resetWidthAndHeight {
  117. // CGFloat scale = [UIScreen mainScreen].scale;
  118. // _screenWidth = [UIScreen mainScreen].bounds.size.width * scale;
  119. // _screenHeight = [UIScreen mainScreen].bounds.size.height * scale;
  120. CGFloat scale = [UIScreen mainScreen].scale;
  121. _screenWidth = self.f_width * scale;
  122. _screenHeight = self.f_heigh * scale;
  123. }
  124. /*
  125. * 将纹理绘制到屏幕上
  126. */
  127. - (void)renderWithTexture:(unsigned int)name
  128. size:(CGSize)size
  129. flipped:(BOOL)flipped
  130. applyingOrientation:(int)orientation
  131. savingCurrentTexture:(bool)enableSaving{
  132. if ([EAGLContext currentContext] != self.glContext) {
  133. [EAGLContext setCurrentContext:self.glContext];
  134. }
  135. if (!glIsTexture(name)) {
  136. return;
  137. }
  138. _displayTextureID = name;
  139. if (!self.window) {
  140. //glDeleteTextures(1, &_displayTextureID);
  141. _shouldDeleteTextureID = NO;
  142. return;
  143. }
  144. if (enableSaving) {
  145. [self textureToImage:name withBuffer:saveTextureBuffer Width:_screenWidth height:_screenHeight];
  146. CGDataProviderRef provider = CGDataProviderCreateWithData(
  147. NULL,
  148. saveTextureBuffer,
  149. _screenWidth * _screenHeight * 4,
  150. NULL);
  151. CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
  152. CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
  153. CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
  154. CGImageRef imageRef = CGImageCreate(_screenWidth,
  155. _screenHeight,
  156. 8,
  157. 4 * 8,
  158. 4 * _screenWidth,
  159. colorSpaceRef,
  160. bitmapInfo,
  161. provider,
  162. NULL,
  163. NO,
  164. renderingIntent);
  165. //free(buffer);
  166. UIImage *uiImage = [UIImage imageWithCGImage:imageRef];
  167. CGDataProviderRelease(provider);
  168. CGColorSpaceRelease(colorSpaceRef);
  169. CGImageRelease(imageRef);
  170. UIImageWriteToSavedPhotosAlbum(uiImage, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void*)self);
  171. }
  172. if (!_shouldDeleteTextureID){
  173. _shouldDeleteTextureID = YES;
  174. [self display];
  175. }
  176. }
  177. - (void) textureToImage:(GLuint)texture withBuffer:(unsigned char*)buffer Width:(int)rWidth height:(int)rHeight{
  178. glBindTexture(GL_TEXTURE_2D, _saveTexture);
  179. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rWidth, rHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  180. glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
  181. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _saveTexture, 0);
  182. glUseProgram(_renderProgram);
  183. glVertexAttribPointer(_renderLocation, 2, GL_FLOAT, false, 0, vertex);
  184. glEnableVertexAttribArray(_renderLocation);
  185. glVertexAttribPointer(_renderTextureCoordinate, 2, GL_FLOAT, false, 0, TEXTURE_RORATION_0);
  186. glEnableVertexAttribArray(_renderTextureCoordinate);
  187. glActiveTexture(GL_TEXTURE0);
  188. glBindTexture(GL_TEXTURE_2D, texture);
  189. glUniform1i(_renderInputImageTexture, 0);
  190. glViewport(0, 0, rWidth, rHeight);
  191. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  192. glDisableVertexAttribArray(_renderLocation);
  193. glDisableVertexAttribArray(_renderTextureCoordinate);
  194. glActiveTexture(GL_TEXTURE0);
  195. glBindTexture(GL_TEXTURE_2D, 0);
  196. glReadPixels(0, 0, rWidth, rHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
  197. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  198. [self checkGLError];
  199. }
  200. - (void)image:(UIImage*)image didFinishSavingWithError:(NSError*)error contextInfo:(void *)contextInfo{
  201. if (error){
  202. //NSLog(@"fail to save photo");
  203. }else {
  204. ////NSLog(@"image = %@, error = %@, contextInfo = %@", image, error, contextInfo);
  205. [self makeToast:NSLocalizedString(@"ablum_have_been_saved", nil) duration:(NSTimeInterval)(3.0) position:CSToastPositionCenter];
  206. }
  207. }
  208. - (void) calcVertex:(int)iWidth height:(int)iHeight ratios:(float *)retRatio{
  209. int outputWidth = iWidth;
  210. int outputHeight = iHeight;
  211. int imageHeight = 1280;
  212. int imageWidth = 720;
  213. float ratio1 = (float)outputWidth / imageWidth;
  214. float ratio2 = (float)outputHeight / imageHeight;
  215. float ratio = MIN(ratio1, ratio2);
  216. int imageNewHeight = round(imageHeight * ratio);
  217. int imageNewWidth = round(imageWidth * ratio);
  218. float ratioHeight = imageNewHeight / (float)outputHeight;
  219. float ratioWidth = imageNewWidth / (float)outputWidth;
  220. retRatio[0] = ratioWidth;
  221. retRatio[1] = ratioHeight;
  222. }
  223. - (void)drawRect:(CGRect)rect {
  224. [super drawRect:rect];
  225. CGSize size = self.bounds.size;
  226. if (!CGSizeEqualToSize(size, _savedSize)) {
  227. [self resetWidthAndHeight];
  228. _savedSize = size;
  229. }
  230. if (_shouldDeleteTextureID) {
  231. glClearColor(0.0, 0.0, 0.0, 0.0);
  232. glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
  233. glUseProgram(_renderProgram);
  234. glVertexAttribPointer(_renderLocation, 2, GL_FLOAT, false, 0, vertex);
  235. glEnableVertexAttribArray(_renderLocation);
  236. glVertexAttribPointer(_renderTextureCoordinate, 2, GL_FLOAT, false, 0, TEXTURE_FLIPPED);
  237. glEnableVertexAttribArray(_renderTextureCoordinate);
  238. glActiveTexture(GL_TEXTURE0);
  239. glBindTexture(GL_TEXTURE_2D, _displayTextureID);
  240. glUniform1i(_renderInputImageTexture, 0);
  241. glViewport(0, 0, _screenWidth, _screenHeight);
  242. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  243. glDisableVertexAttribArray(_renderLocation);
  244. glDisableVertexAttribArray(_renderTextureCoordinate);
  245. glActiveTexture(GL_TEXTURE0);
  246. glBindTexture(GL_TEXTURE_2D, 0);
  247. glUseProgram(0);
  248. glFlush();
  249. //glDeleteTextures(1, &_displayTextureID);
  250. _shouldDeleteTextureID = NO;
  251. }
  252. }
  253. /*
  254. * load resize shader
  255. */
  256. - (void) loadRenderShader{
  257. // GLuint vertexShader = [BERenderHelper compileShader:RENDER_VERTEX withType:GL_VERTEX_SHADER];
  258. // GLuint fragmentShader = [BERenderHelper compileShader:RENDER_FRAGMENT withType:GL_FRAGMENT_SHADER];
  259. //
  260. // _renderProgram = glCreateProgram();
  261. // glAttachShader(_renderProgram, vertexShader);
  262. // glAttachShader(_renderProgram, fragmentShader);
  263. // glLinkProgram(_renderProgram);
  264. //
  265. // GLint linkSuccess;
  266. // glGetProgramiv(_renderProgram, GL_LINK_STATUS, &linkSuccess);
  267. // if (linkSuccess == GL_FALSE){
  268. // //NSLog(@"BERenderHelper link shader error");
  269. // }
  270. //
  271. // glUseProgram(_renderProgram);
  272. // _renderLocation = glGetAttribLocation(_renderProgram, "position");
  273. // _renderTextureCoordinate = glGetAttribLocation(_renderProgram, "inputTextureCoordinate");
  274. // _renderInputImageTexture = glGetUniformLocation(_renderProgram, "inputImageTexture");
  275. //
  276. // if (vertexShader)
  277. // glDeleteShader(vertexShader);
  278. //
  279. // if (fragmentShader)
  280. // glDeleteShader(fragmentShader);
  281. }
  282. - (void)releaseContext {
  283. [EAGLContext setCurrentContext:nil];
  284. }
  285. #pragma mark - getter
  286. - (UIImageView*)imageView{
  287. if(!_imageView){
  288. _imageView = [[UIImageView alloc] init];
  289. }
  290. return _imageView;
  291. }
  292. - (void)checkGLError {
  293. int error = glGetError();
  294. if (error != GL_NO_ERROR) {
  295. //NSLog(@"%d", error);
  296. @throw [NSException exceptionWithName:@"GLError" reason:@"error " userInfo:nil];
  297. }
  298. }
  299. @end