PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Dependencies/GPUImage/Source/GPUImageToneCurveFilter.m

https://gitlab.com/Mr.Tomato/VideoEffects
Objective C | 621 lines | 479 code | 116 blank | 26 comment | 57 complexity | 2d3d95fbb354636ed40419c735c4967a MD5 | raw file
  1. #import "GPUImageToneCurveFilter.h"
  2. #pragma mark -
  3. #pragma mark GPUImageACVFile Helper
  4. // GPUImageACVFile
  5. //
  6. // ACV File format Parser
  7. // Please refer to http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577411_pgfId-1056330
  8. //
  9. @interface GPUImageACVFile : NSObject{
  10. short version;
  11. short totalCurves;
  12. NSArray *rgbCompositeCurvePoints;
  13. NSArray *redCurvePoints;
  14. NSArray *greenCurvePoints;
  15. NSArray *blueCurvePoints;
  16. }
  17. @property(strong,nonatomic) NSArray *rgbCompositeCurvePoints;
  18. @property(strong,nonatomic) NSArray *redCurvePoints;
  19. @property(strong,nonatomic) NSArray *greenCurvePoints;
  20. @property(strong,nonatomic) NSArray *blueCurvePoints;
  21. - (id) initWithACVFileData:(NSData*)data;
  22. unsigned short int16WithBytes(Byte* bytes);
  23. @end
  24. @implementation GPUImageACVFile
  25. @synthesize rgbCompositeCurvePoints, redCurvePoints, greenCurvePoints, blueCurvePoints;
  26. - (id) initWithACVFileData:(NSData *)data {
  27. self = [super init];
  28. if (self != nil)
  29. {
  30. if (data.length == 0)
  31. {
  32. NSLog(@"failed to init ACVFile with data:%@", data);
  33. return self;
  34. }
  35. Byte* rawBytes = (Byte*) [data bytes];
  36. version = int16WithBytes(rawBytes);
  37. rawBytes+=2;
  38. totalCurves = int16WithBytes(rawBytes);
  39. rawBytes+=2;
  40. NSMutableArray *curves = [NSMutableArray new];
  41. float pointRate = (1.0 / 255);
  42. // The following is the data for each curve specified by count above
  43. for (NSInteger x = 0; x<totalCurves; x++)
  44. {
  45. unsigned short pointCount = int16WithBytes(rawBytes);
  46. rawBytes+=2;
  47. NSMutableArray *points = [NSMutableArray new];
  48. // point count * 4
  49. // Curve points. Each curve point is a pair of short integers where
  50. // the first number is the output value (vertical coordinate on the
  51. // Curves dialog graph) and the second is the input value. All coordinates have range 0 to 255.
  52. for (NSInteger y = 0; y<pointCount; y++)
  53. {
  54. unsigned short y = int16WithBytes(rawBytes);
  55. rawBytes+=2;
  56. unsigned short x = int16WithBytes(rawBytes);
  57. rawBytes+=2;
  58. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  59. [points addObject:[NSValue valueWithCGSize:CGSizeMake(x * pointRate, y * pointRate)]];
  60. #else
  61. [points addObject:[NSValue valueWithSize:CGSizeMake(x * pointRate, y * pointRate)]];
  62. #endif
  63. }
  64. [curves addObject:points];
  65. }
  66. rgbCompositeCurvePoints = [curves objectAtIndex:0];
  67. redCurvePoints = [curves objectAtIndex:1];
  68. greenCurvePoints = [curves objectAtIndex:2];
  69. blueCurvePoints = [curves objectAtIndex:3];
  70. }
  71. return self;
  72. }
  73. unsigned short int16WithBytes(Byte* bytes) {
  74. uint16_t result;
  75. memcpy(&result, bytes, sizeof(result));
  76. return CFSwapInt16BigToHost(result);
  77. }
  78. @end
  79. #pragma mark -
  80. #pragma mark GPUImageToneCurveFilter Implementation
  81. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  82. NSString *const kGPUImageToneCurveFragmentShaderString = SHADER_STRING
  83. (
  84. varying highp vec2 textureCoordinate;
  85. uniform sampler2D inputImageTexture;
  86. uniform sampler2D toneCurveTexture;
  87. void main()
  88. {
  89. lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
  90. lowp float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r;
  91. lowp float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g;
  92. lowp float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b;
  93. gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);
  94. }
  95. );
  96. #else
  97. NSString *const kGPUImageToneCurveFragmentShaderString = SHADER_STRING
  98. (
  99. varying vec2 textureCoordinate;
  100. uniform sampler2D inputImageTexture;
  101. uniform sampler2D toneCurveTexture;
  102. void main()
  103. {
  104. vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
  105. float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r;
  106. float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g;
  107. float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b;
  108. gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);
  109. }
  110. );
  111. #endif
  112. @interface GPUImageToneCurveFilter()
  113. {
  114. GLint toneCurveTextureUniform;
  115. GLuint toneCurveTexture;
  116. GLubyte *toneCurveByteArray;
  117. NSArray *_redCurve, *_greenCurve, *_blueCurve, *_rgbCompositeCurve;
  118. }
  119. @end
  120. @implementation GPUImageToneCurveFilter
  121. @synthesize rgbCompositeControlPoints = _rgbCompositeControlPoints;
  122. @synthesize redControlPoints = _redControlPoints;
  123. @synthesize greenControlPoints = _greenControlPoints;
  124. @synthesize blueControlPoints = _blueControlPoints;
  125. #pragma mark -
  126. #pragma mark Initialization and teardown
  127. - (id)init;
  128. {
  129. if (!(self = [super initWithFragmentShaderFromString:kGPUImageToneCurveFragmentShaderString]))
  130. {
  131. return nil;
  132. }
  133. toneCurveTextureUniform = [filterProgram uniformIndex:@"toneCurveTexture"];
  134. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  135. NSArray *defaultCurve = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)], [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)], [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)], nil];
  136. #else
  137. NSArray *defaultCurve = [NSArray arrayWithObjects:[NSValue valueWithPoint:NSMakePoint(0.0, 0.0)], [NSValue valueWithPoint:NSMakePoint(0.5, 0.5)], [NSValue valueWithPoint:NSMakePoint(1.0, 1.0)], nil];
  138. #endif
  139. [self setRgbCompositeControlPoints:defaultCurve];
  140. [self setRedControlPoints:defaultCurve];
  141. [self setGreenControlPoints:defaultCurve];
  142. [self setBlueControlPoints:defaultCurve];
  143. return self;
  144. }
  145. // This pulls in Adobe ACV curve files to specify the tone curve
  146. - (id)initWithACVData:(NSData *)data {
  147. if (!(self = [super initWithFragmentShaderFromString:kGPUImageToneCurveFragmentShaderString]))
  148. {
  149. return nil;
  150. }
  151. toneCurveTextureUniform = [filterProgram uniformIndex:@"toneCurveTexture"];
  152. GPUImageACVFile *curve = [[GPUImageACVFile alloc] initWithACVFileData:data];
  153. [self setRgbCompositeControlPoints:curve.rgbCompositeCurvePoints];
  154. [self setRedControlPoints:curve.redCurvePoints];
  155. [self setGreenControlPoints:curve.greenCurvePoints];
  156. [self setBlueControlPoints:curve.blueCurvePoints];
  157. curve = nil;
  158. return self;
  159. }
  160. - (id)initWithACV:(NSString*)curveFilename
  161. {
  162. return [self initWithACVURL:[[NSBundle mainBundle] URLForResource:curveFilename
  163. withExtension:@"acv"]];
  164. }
  165. - (id)initWithACVURL:(NSURL*)curveFileURL
  166. {
  167. NSData* fileData = [NSData dataWithContentsOfURL:curveFileURL];
  168. return [self initWithACVData:fileData];
  169. }
  170. - (void)setPointsWithACV:(NSString*)curveFilename
  171. {
  172. [self setPointsWithACVURL:[[NSBundle mainBundle] URLForResource:curveFilename withExtension:@"acv"]];
  173. }
  174. - (void)setPointsWithACVURL:(NSURL*)curveFileURL
  175. {
  176. NSData* fileData = [NSData dataWithContentsOfURL:curveFileURL];
  177. GPUImageACVFile *curve = [[GPUImageACVFile alloc] initWithACVFileData:fileData];
  178. [self setRgbCompositeControlPoints:curve.rgbCompositeCurvePoints];
  179. [self setRedControlPoints:curve.redCurvePoints];
  180. [self setGreenControlPoints:curve.greenCurvePoints];
  181. [self setBlueControlPoints:curve.blueCurvePoints];
  182. curve = nil;
  183. }
  184. - (void)dealloc
  185. {
  186. runSynchronouslyOnVideoProcessingQueue(^{
  187. [GPUImageContext useImageProcessingContext];
  188. if (toneCurveTexture)
  189. {
  190. glDeleteTextures(1, &toneCurveTexture);
  191. toneCurveTexture = 0;
  192. free(toneCurveByteArray);
  193. }
  194. });
  195. }
  196. #pragma mark -
  197. #pragma mark Curve calculation
  198. - (NSArray *)getPreparedSplineCurve:(NSArray *)points
  199. {
  200. if (points && [points count] > 0)
  201. {
  202. // Sort the array.
  203. NSArray *sortedPoints = [points sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
  204. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  205. float x1 = [(NSValue *)a CGPointValue].x;
  206. float x2 = [(NSValue *)b CGPointValue].x;
  207. #else
  208. float x1 = [(NSValue *)a pointValue].x;
  209. float x2 = [(NSValue *)b pointValue].x;
  210. #endif
  211. return x1 > x2;
  212. }];
  213. // Convert from (0, 1) to (0, 255).
  214. NSMutableArray *convertedPoints = [NSMutableArray arrayWithCapacity:[sortedPoints count]];
  215. for (int i=0; i<[points count]; i++){
  216. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  217. CGPoint point = [[sortedPoints objectAtIndex:i] CGPointValue];
  218. #else
  219. NSPoint point = [[sortedPoints objectAtIndex:i] pointValue];
  220. #endif
  221. point.x = point.x * 255;
  222. point.y = point.y * 255;
  223. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  224. [convertedPoints addObject:[NSValue valueWithCGPoint:point]];
  225. #else
  226. [convertedPoints addObject:[NSValue valueWithPoint:point]];
  227. #endif
  228. }
  229. NSMutableArray *splinePoints = [self splineCurve:convertedPoints];
  230. // If we have a first point like (0.3, 0) we'll be missing some points at the beginning
  231. // that should be 0.
  232. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  233. CGPoint firstSplinePoint = [[splinePoints objectAtIndex:0] CGPointValue];
  234. #else
  235. NSPoint firstSplinePoint = [[splinePoints objectAtIndex:0] pointValue];
  236. #endif
  237. if (firstSplinePoint.x > 0) {
  238. for (int i=firstSplinePoint.x; i >= 0; i--) {
  239. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  240. CGPoint newCGPoint = CGPointMake(i, 0);
  241. [splinePoints insertObject:[NSValue valueWithCGPoint:newCGPoint] atIndex:0];
  242. #else
  243. NSPoint newNSPoint = NSMakePoint(i, 0);
  244. [splinePoints insertObject:[NSValue valueWithPoint:newNSPoint] atIndex:0];
  245. #endif
  246. }
  247. }
  248. // Insert points similarly at the end, if necessary.
  249. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  250. CGPoint lastSplinePoint = [[splinePoints lastObject] CGPointValue];
  251. if (lastSplinePoint.x < 255) {
  252. for (int i = lastSplinePoint.x + 1; i <= 255; i++) {
  253. CGPoint newCGPoint = CGPointMake(i, 255);
  254. [splinePoints addObject:[NSValue valueWithCGPoint:newCGPoint]];
  255. }
  256. }
  257. #else
  258. NSPoint lastSplinePoint = [[splinePoints lastObject] pointValue];
  259. if (lastSplinePoint.x < 255) {
  260. for (int i = lastSplinePoint.x + 1; i <= 255; i++) {
  261. NSPoint newNSPoint = NSMakePoint(i, 255);
  262. [splinePoints addObject:[NSValue valueWithPoint:newNSPoint]];
  263. }
  264. }
  265. #endif
  266. // Prepare the spline points.
  267. NSMutableArray *preparedSplinePoints = [NSMutableArray arrayWithCapacity:[splinePoints count]];
  268. for (int i=0; i<[splinePoints count]; i++)
  269. {
  270. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  271. CGPoint newPoint = [[splinePoints objectAtIndex:i] CGPointValue];
  272. #else
  273. NSPoint newPoint = [[splinePoints objectAtIndex:i] pointValue];
  274. #endif
  275. CGPoint origPoint = CGPointMake(newPoint.x, newPoint.x);
  276. float distance = sqrt(pow((origPoint.x - newPoint.x), 2.0) + pow((origPoint.y - newPoint.y), 2.0));
  277. if (origPoint.y > newPoint.y)
  278. {
  279. distance = -distance;
  280. }
  281. [preparedSplinePoints addObject:[NSNumber numberWithFloat:distance]];
  282. }
  283. return preparedSplinePoints;
  284. }
  285. return nil;
  286. }
  287. - (NSMutableArray *)splineCurve:(NSArray *)points
  288. {
  289. NSMutableArray *sdA = [self secondDerivative:points];
  290. // [points count] is equal to [sdA count]
  291. NSInteger n = [sdA count];
  292. if (n < 1)
  293. {
  294. return nil;
  295. }
  296. double sd[n];
  297. // From NSMutableArray to sd[n];
  298. for (int i=0; i<n; i++)
  299. {
  300. sd[i] = [[sdA objectAtIndex:i] doubleValue];
  301. }
  302. NSMutableArray *output = [NSMutableArray arrayWithCapacity:(n+1)];
  303. for(int i=0; i<n-1 ; i++)
  304. {
  305. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  306. CGPoint cur = [[points objectAtIndex:i] CGPointValue];
  307. CGPoint next = [[points objectAtIndex:(i+1)] CGPointValue];
  308. #else
  309. NSPoint cur = [[points objectAtIndex:i] pointValue];
  310. NSPoint next = [[points objectAtIndex:(i+1)] pointValue];
  311. #endif
  312. for(int x=cur.x;x<(int)next.x;x++)
  313. {
  314. double t = (double)(x-cur.x)/(next.x-cur.x);
  315. double a = 1-t;
  316. double b = t;
  317. double h = next.x-cur.x;
  318. double y= a*cur.y + b*next.y + (h*h/6)*( (a*a*a-a)*sd[i]+ (b*b*b-b)*sd[i+1] );
  319. if (y > 255.0)
  320. {
  321. y = 255.0;
  322. }
  323. else if (y < 0.0)
  324. {
  325. y = 0.0;
  326. }
  327. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  328. [output addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
  329. #else
  330. [output addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
  331. #endif
  332. }
  333. }
  334. // The above always misses the last point because the last point is the last next, so we approach but don't equal it.
  335. [output addObject:[points lastObject]];
  336. return output;
  337. }
  338. - (NSMutableArray *)secondDerivative:(NSArray *)points
  339. {
  340. const NSInteger n = [points count];
  341. if ((n <= 0) || (n == 1))
  342. {
  343. return nil;
  344. }
  345. double matrix[n][3];
  346. double result[n];
  347. matrix[0][1]=1;
  348. // What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.)
  349. matrix[0][0]=0;
  350. matrix[0][2]=0;
  351. for(int i=1;i<n-1;i++)
  352. {
  353. #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
  354. CGPoint P1 = [[points objectAtIndex:(i-1)] CGPointValue];
  355. CGPoint P2 = [[points objectAtIndex:i] CGPointValue];
  356. CGPoint P3 = [[points objectAtIndex:(i+1)] CGPointValue];
  357. #else
  358. NSPoint P1 = [[points objectAtIndex:(i-1)] pointValue];
  359. NSPoint P2 = [[points objectAtIndex:i] pointValue];
  360. NSPoint P3 = [[points objectAtIndex:(i+1)] pointValue];
  361. #endif
  362. matrix[i][0]=(double)(P2.x-P1.x)/6;
  363. matrix[i][1]=(double)(P3.x-P1.x)/3;
  364. matrix[i][2]=(double)(P3.x-P2.x)/6;
  365. result[i]=(double)(P3.y-P2.y)/(P3.x-P2.x) - (double)(P2.y-P1.y)/(P2.x-P1.x);
  366. }
  367. // What about result[0] and result[n-1]? Assuming 0 for now (Brad L.)
  368. result[0] = 0;
  369. result[n-1] = 0;
  370. matrix[n-1][1]=1;
  371. // What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.)
  372. matrix[n-1][0]=0;
  373. matrix[n-1][2]=0;
  374. // solving pass1 (up->down)
  375. for(int i=1;i<n;i++)
  376. {
  377. double k = matrix[i][0]/matrix[i-1][1];
  378. matrix[i][1] -= k*matrix[i-1][2];
  379. matrix[i][0] = 0;
  380. result[i] -= k*result[i-1];
  381. }
  382. // solving pass2 (down->up)
  383. for(NSInteger i=n-2;i>=0;i--)
  384. {
  385. double k = matrix[i][2]/matrix[i+1][1];
  386. matrix[i][1] -= k*matrix[i+1][0];
  387. matrix[i][2] = 0;
  388. result[i] -= k*result[i+1];
  389. }
  390. double y2[n];
  391. for(int i=0;i<n;i++) y2[i]=result[i]/matrix[i][1];
  392. NSMutableArray *output = [NSMutableArray arrayWithCapacity:n];
  393. for (int i=0;i<n;i++)
  394. {
  395. [output addObject:[NSNumber numberWithDouble:y2[i]]];
  396. }
  397. return output;
  398. }
  399. - (void)updateToneCurveTexture;
  400. {
  401. runSynchronouslyOnVideoProcessingQueue(^{
  402. [GPUImageContext useImageProcessingContext];
  403. if (!toneCurveTexture)
  404. {
  405. glActiveTexture(GL_TEXTURE3);
  406. glGenTextures(1, &toneCurveTexture);
  407. glBindTexture(GL_TEXTURE_2D, toneCurveTexture);
  408. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  409. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  410. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  411. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  412. toneCurveByteArray = calloc(256 * 4, sizeof(GLubyte));
  413. }
  414. else
  415. {
  416. glActiveTexture(GL_TEXTURE3);
  417. glBindTexture(GL_TEXTURE_2D, toneCurveTexture);
  418. }
  419. if ( ([_redCurve count] >= 256) && ([_greenCurve count] >= 256) && ([_blueCurve count] >= 256) && ([_rgbCompositeCurve count] >= 256))
  420. {
  421. for (unsigned int currentCurveIndex = 0; currentCurveIndex < 256; currentCurveIndex++)
  422. {
  423. // BGRA for upload to texture
  424. GLubyte b = fmin(fmax(currentCurveIndex + [[_blueCurve objectAtIndex:currentCurveIndex] floatValue], 0), 255);
  425. toneCurveByteArray[currentCurveIndex * 4] = fmin(fmax(b + [[_rgbCompositeCurve objectAtIndex:b] floatValue], 0), 255);
  426. GLubyte g = fmin(fmax(currentCurveIndex + [[_greenCurve objectAtIndex:currentCurveIndex] floatValue], 0), 255);
  427. toneCurveByteArray[currentCurveIndex * 4 + 1] = fmin(fmax(g + [[_rgbCompositeCurve objectAtIndex:g] floatValue], 0), 255);
  428. GLubyte r = fmin(fmax(currentCurveIndex + [[_redCurve objectAtIndex:currentCurveIndex] floatValue], 0), 255);
  429. toneCurveByteArray[currentCurveIndex * 4 + 2] = fmin(fmax(r + [[_rgbCompositeCurve objectAtIndex:r] floatValue], 0), 255);
  430. toneCurveByteArray[currentCurveIndex * 4 + 3] = 255;
  431. }
  432. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256 /*width*/, 1 /*height*/, 0, GL_BGRA, GL_UNSIGNED_BYTE, toneCurveByteArray);
  433. }
  434. });
  435. }
  436. #pragma mark -
  437. #pragma mark Rendering
  438. - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
  439. {
  440. if (self.preventRendering)
  441. {
  442. [firstInputFramebuffer unlock];
  443. return;
  444. }
  445. [GPUImageContext setActiveShaderProgram:filterProgram];
  446. outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
  447. [outputFramebuffer activateFramebuffer];
  448. if (usingNextFrameForImageCapture)
  449. {
  450. [outputFramebuffer lock];
  451. }
  452. glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
  453. glClear(GL_COLOR_BUFFER_BIT);
  454. glActiveTexture(GL_TEXTURE2);
  455. glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
  456. glUniform1i(filterInputTextureUniform, 2);
  457. glActiveTexture(GL_TEXTURE3);
  458. glBindTexture(GL_TEXTURE_2D, toneCurveTexture);
  459. glUniform1i(toneCurveTextureUniform, 3);
  460. glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
  461. glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
  462. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  463. [firstInputFramebuffer unlock];
  464. if (usingNextFrameForImageCapture)
  465. {
  466. dispatch_semaphore_signal(imageCaptureSemaphore);
  467. }
  468. }
  469. #pragma mark -
  470. #pragma mark Accessors
  471. - (void)setRGBControlPoints:(NSArray *)points
  472. {
  473. _redControlPoints = [points copy];
  474. _redCurve = [self getPreparedSplineCurve:_redControlPoints];
  475. _greenControlPoints = [points copy];
  476. _greenCurve = [self getPreparedSplineCurve:_greenControlPoints];
  477. _blueControlPoints = [points copy];
  478. _blueCurve = [self getPreparedSplineCurve:_blueControlPoints];
  479. [self updateToneCurveTexture];
  480. }
  481. - (void)setRgbCompositeControlPoints:(NSArray *)newValue
  482. {
  483. _rgbCompositeControlPoints = [newValue copy];
  484. _rgbCompositeCurve = [self getPreparedSplineCurve:_rgbCompositeControlPoints];
  485. [self updateToneCurveTexture];
  486. }
  487. - (void)setRedControlPoints:(NSArray *)newValue;
  488. {
  489. _redControlPoints = [newValue copy];
  490. _redCurve = [self getPreparedSplineCurve:_redControlPoints];
  491. [self updateToneCurveTexture];
  492. }
  493. - (void)setGreenControlPoints:(NSArray *)newValue
  494. {
  495. _greenControlPoints = [newValue copy];
  496. _greenCurve = [self getPreparedSplineCurve:_greenControlPoints];
  497. [self updateToneCurveTexture];
  498. }
  499. - (void)setBlueControlPoints:(NSArray *)newValue
  500. {
  501. _blueControlPoints = [newValue copy];
  502. _blueCurve = [self getPreparedSplineCurve:_blueControlPoints];
  503. [self updateToneCurveTexture];
  504. }
  505. @end