-
-
Save depthlove/586eac10c37d106b710e8a0141478f7f to your computer and use it in GitHub Desktop.
GPUImageFilter with custom shader up for five textures. Never thought I'd gonna make something like this.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <GPUImage/GPUImage.h> | |
#import "GPUImageFourInputFilter.h" | |
@interface GPUImageFiveInputFilter : GPUImageFourInputFilter | |
{ | |
GPUImageFramebuffer *fifthInputFramebuffer; | |
GLint filterFifthTextureCoordinateAttribute; | |
GLint filterInputTextureUniform5; | |
GPUImageRotationMode inputRotation5; | |
GLuint filterSourceTexture5; | |
CMTime fifthFrameTime; | |
BOOL hasSetFourthTexture, hasReceivedFifthFrame, fifthFrameWasVideo; | |
BOOL fifthFrameCheckDisabled; | |
} | |
- (void)disableFifthFrameCheck; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "GPUImageFiveInputFilter.h" | |
static NSString *const kGPUImageFiveInputTextureVertexShaderString = SHADER_STRING | |
( | |
attribute vec4 position; | |
attribute vec4 inputTextureCoordinate; | |
attribute vec4 inputTextureCoordinate2; | |
attribute vec4 inputTextureCoordinate3; | |
attribute vec4 inputTextureCoordinate4; | |
attribute vec4 inputTextureCoordinate5; | |
varying vec2 textureCoordinate; | |
varying vec2 textureCoordinate2; | |
varying vec2 textureCoordinate3; | |
varying vec2 textureCoordinate4; | |
varying vec2 textureCoordinate5; | |
void main() | |
{ | |
gl_Position = position; | |
textureCoordinate = inputTextureCoordinate.xy; | |
textureCoordinate2 = inputTextureCoordinate2.xy; | |
textureCoordinate3 = inputTextureCoordinate3.xy; | |
textureCoordinate4 = inputTextureCoordinate4.xy; | |
textureCoordinate5 = inputTextureCoordinate5.xy; | |
} | |
); | |
@implementation GPUImageFiveInputFilter | |
#pragma mark - | |
#pragma mark Initialization and teardown | |
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString; | |
{ | |
if (!(self = [self initWithVertexShaderFromString:kGPUImageFiveInputTextureVertexShaderString fragmentShaderFromString:fragmentShaderString])) | |
{ | |
return nil; | |
} | |
return self; | |
} | |
- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString; | |
{ | |
if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString])) | |
{ | |
return nil; | |
} | |
inputRotation5 = kGPUImageNoRotation; | |
hasSetFourthTexture = NO; | |
hasReceivedFifthFrame = NO; | |
fifthFrameWasVideo = NO; | |
fifthFrameCheckDisabled = NO; | |
fifthFrameTime = kCMTimeInvalid; | |
runSynchronouslyOnVideoProcessingQueue(^{ | |
[GPUImageContext useImageProcessingContext]; | |
filterFifthTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate5"]; | |
filterInputTextureUniform4 = [filterProgram uniformIndex:@"inputImageTexture5"]; // This does assume a name of "inputImageTexture5" for the fifth input texture in the fragment shader | |
glEnableVertexAttribArray(filterFifthTextureCoordinateAttribute); | |
}); | |
return self; | |
} | |
- (void)initializeAttributes; | |
{ | |
[super initializeAttributes]; | |
[filterProgram addAttribute:@"inputTextureCoordinate5"]; | |
} | |
- (void) disableFifthFrameCheck | |
{ | |
fourthFrameCheckDisabled = YES; | |
} | |
#pragma mark - | |
#pragma mark Rendering | |
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates; | |
{ | |
if (self.preventRendering) | |
{ | |
[firstInputFramebuffer unlock]; | |
[secondInputFramebuffer unlock]; | |
[thirdInputFramebuffer unlock]; | |
[fourthInputFramebuffer unlock]; | |
[fifthInputFramebuffer unlock]; | |
return; | |
} | |
[GPUImageContext setActiveShaderProgram:filterProgram]; | |
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO]; | |
[outputFramebuffer activateFramebuffer]; | |
if (usingNextFrameForImageCapture) | |
{ | |
[outputFramebuffer lock]; | |
} | |
[self setUniformsForProgramAtIndex:0]; | |
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glActiveTexture(GL_TEXTURE2); | |
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]); | |
glUniform1i(filterInputTextureUniform, 2); | |
glActiveTexture(GL_TEXTURE3); | |
glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]); | |
glUniform1i(filterInputTextureUniform2, 3); | |
glActiveTexture(GL_TEXTURE4); | |
glBindTexture(GL_TEXTURE_2D, [thirdInputFramebuffer texture]); | |
glUniform1i(filterInputTextureUniform3, 4); | |
glActiveTexture(GL_TEXTURE5); | |
glBindTexture(GL_TEXTURE_2D, [fourthInputFramebuffer texture]); | |
glUniform1i(filterInputTextureUniform4, 5); | |
glActiveTexture(GL_TEXTURE6); | |
glBindTexture(GL_TEXTURE_2D, [fifthInputFramebuffer texture]); | |
glUniform1i(filterInputTextureUniform5, 6); | |
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices); | |
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates); | |
glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation2]); | |
glVertexAttribPointer(filterThirdTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation3]); | |
glVertexAttribPointer(filterFourthTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation4]); | |
glVertexAttribPointer(filterFourthTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation5]); | |
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
[firstInputFramebuffer unlock]; | |
[secondInputFramebuffer unlock]; | |
[thirdInputFramebuffer unlock]; | |
[fourthInputFramebuffer unlock]; | |
[fifthInputFramebuffer unlock]; | |
if (usingNextFrameForImageCapture) | |
{ | |
dispatch_semaphore_signal(imageCaptureSemaphore); | |
} | |
} | |
#pragma mark - | |
#pragma mark GPUImageInput | |
- (NSInteger)nextAvailableTextureIndex; | |
{ | |
if(hasSetFourthTexture){ | |
return 4; | |
} | |
else if(hasSetThirdTexture){ | |
return 3; | |
} | |
else if (hasSetSecondTexture) | |
{ | |
return 2; | |
} | |
else if (hasSetFirstTexture) | |
{ | |
return 1; | |
} | |
else | |
{ | |
return 0; | |
} | |
} | |
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex; | |
{ | |
if (textureIndex == 0) | |
{ | |
firstInputFramebuffer = newInputFramebuffer; | |
hasSetFirstTexture = YES; | |
[firstInputFramebuffer lock]; | |
} | |
else if (textureIndex == 1) | |
{ | |
secondInputFramebuffer = newInputFramebuffer; | |
//hasSetSecondTexture = YES; | |
[secondInputFramebuffer lock]; | |
} | |
else if(textureIndex == 2){ | |
thirdInputFramebuffer = newInputFramebuffer; | |
[thirdInputFramebuffer lock]; | |
} | |
else if (textureIndex == 3) | |
{ | |
fourthInputFramebuffer = newInputFramebuffer; | |
[fourthInputFramebuffer lock]; | |
} | |
else if (textureIndex == 4) | |
{ | |
fifthInputFramebuffer = newInputFramebuffer; | |
[fifthInputFramebuffer lock]; | |
} | |
} | |
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex; | |
{ | |
if (textureIndex == 0) | |
{ | |
[super setInputSize:newSize atIndex:textureIndex]; | |
if (CGSizeEqualToSize(newSize, CGSizeZero)) | |
{ | |
hasSetFirstTexture = NO; | |
} | |
} | |
else if (textureIndex == 1) | |
{ | |
if (CGSizeEqualToSize(newSize, CGSizeZero)) | |
{ | |
hasSetSecondTexture = NO; | |
} | |
} | |
else if(textureIndex == 2) | |
{ | |
if (CGSizeEqualToSize(newSize, CGSizeZero)) { | |
hasSetThirdTexture = NO; | |
} | |
} | |
else if(textureIndex == 3) | |
{ | |
if (CGSizeEqualToSize(newSize, CGSizeZero)) { | |
hasSetFourthTexture = NO; | |
} | |
} | |
} | |
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex; | |
{ | |
if (textureIndex == 0) | |
{ | |
inputRotation = newInputRotation; | |
} | |
else if (textureIndex == 1) | |
{ | |
inputRotation2 = newInputRotation; | |
} | |
else if (textureIndex == 2) | |
{ | |
inputRotation3 = newInputRotation; | |
} | |
else if (textureIndex == 3) | |
{ | |
inputRotation4 = newInputRotation; | |
} | |
else | |
{ | |
inputRotation5 = newInputRotation; | |
} | |
} | |
- (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex; | |
{ | |
CGSize rotatedSize = sizeToRotate; | |
GPUImageRotationMode rotationToCheck; | |
if (textureIndex == 0) | |
{ | |
rotationToCheck = inputRotation; | |
} | |
else if (textureIndex == 1) | |
{ | |
rotationToCheck = inputRotation2; | |
} | |
else if (textureIndex == 2) | |
{ | |
rotationToCheck = inputRotation3; | |
} | |
else if (textureIndex == 3) | |
{ | |
rotationToCheck = inputRotation4; | |
} | |
else | |
{ | |
rotationToCheck = inputRotation5; | |
} | |
if (GPUImageRotationSwapsWidthAndHeight(rotationToCheck)) | |
{ | |
rotatedSize.width = sizeToRotate.height; | |
rotatedSize.height = sizeToRotate.width; | |
} | |
return rotatedSize; | |
} | |
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex; | |
{ | |
// You can set up infinite update loops, so this helps to short circuit them | |
if (hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame && hasReceivedFourthFrame && hasReceivedFifthFrame) | |
{ | |
return; | |
} | |
BOOL updatedMovieFrameOppositeStillImage = NO; | |
if (textureIndex == 0) | |
{ | |
hasReceivedFirstFrame = YES; | |
firstFrameTime = frameTime; | |
if (secondFrameCheckDisabled) | |
{ | |
hasReceivedSecondFrame = YES; | |
} | |
if (thirdFrameCheckDisabled) | |
{ | |
hasReceivedThirdFrame = YES; | |
} | |
if (fourthFrameCheckDisabled) { | |
hasReceivedFourthFrame = YES; | |
} | |
if (fifthFrameCheckDisabled) { | |
hasReceivedFifthFrame = YES; | |
} | |
if (!CMTIME_IS_INDEFINITE(frameTime)) | |
{ | |
if CMTIME_IS_INDEFINITE(secondFrameTime) | |
{ | |
updatedMovieFrameOppositeStillImage = YES; | |
} | |
} | |
} | |
else if (textureIndex == 1) | |
{ | |
hasReceivedSecondFrame = YES; | |
secondFrameTime = frameTime; | |
if (firstFrameCheckDisabled) | |
{ | |
hasReceivedFirstFrame = YES; | |
} | |
if (thirdFrameCheckDisabled) | |
{ | |
hasReceivedThirdFrame = YES; | |
} | |
if (fourthFrameCheckDisabled) { | |
hasReceivedFourthFrame = YES; | |
} | |
if (fifthFrameCheckDisabled) { | |
hasReceivedFifthFrame = YES; | |
} | |
if (!CMTIME_IS_INDEFINITE(frameTime)) | |
{ | |
if CMTIME_IS_INDEFINITE(firstFrameTime) | |
{ | |
updatedMovieFrameOppositeStillImage = YES; | |
} | |
} | |
} | |
else if(textureIndex == 2) | |
{ | |
hasReceivedThirdFrame = YES; | |
thirdFrameTime = frameTime; | |
if (firstFrameCheckDisabled) | |
{ | |
hasReceivedFirstFrame = YES; | |
} | |
if (secondFrameCheckDisabled) | |
{ | |
hasReceivedSecondFrame = YES; | |
} | |
if (fourthFrameCheckDisabled) { | |
hasReceivedFourthFrame = YES; | |
} | |
if (fifthFrameCheckDisabled) { | |
hasReceivedFifthFrame = YES; | |
} | |
if (!CMTIME_IS_INDEFINITE(frameTime)) | |
{ | |
if CMTIME_IS_INDEFINITE(firstFrameTime) | |
{ | |
updatedMovieFrameOppositeStillImage = YES; | |
} | |
} | |
}else | |
{ | |
hasReceivedFourthFrame = YES; | |
fourthFrameTime = frameTime; | |
if (firstFrameCheckDisabled) { | |
hasReceivedFirstFrame = YES; | |
} | |
if (secondFrameCheckDisabled) { | |
hasReceivedSecondFrame = YES; | |
} | |
if (thirdFrameCheckDisabled) { | |
hasReceivedThirdFrame = YES; | |
} | |
if (fifthFrameCheckDisabled) { | |
hasReceivedFifthFrame = YES; | |
} | |
if (!CMTIME_IS_INDEFINITE(frameTime)) | |
{ | |
if CMTIME_IS_INDEFINITE(firstFrameTime) | |
{ | |
updatedMovieFrameOppositeStillImage = YES; | |
} | |
} | |
} | |
if ((hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame && hasReceivedFourthFrame && hasReceivedFifthFrame) || updatedMovieFrameOppositeStillImage) | |
{ | |
static const GLfloat imageVertices[] = { | |
-1.0f, -1.0f, | |
1.0f, -1.0f, | |
-1.0f, 1.0f, | |
1.0f, 1.0f, | |
}; | |
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]]; | |
[self informTargetsAboutNewFrameAtTime:frameTime]; | |
hasReceivedFirstFrame = NO; | |
hasReceivedSecondFrame = NO; | |
hasReceivedThirdFrame = NO; | |
hasReceivedFourthFrame = NO; | |
hasReceivedFifthFrame = NO; | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment