Skip to content

Instantly share code, notes, and snippets.

@georgmay
Created December 13, 2014 05:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save georgmay/eaef1449bc7941f99b78 to your computer and use it in GitHub Desktop.
Save georgmay/eaef1449bc7941f99b78 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.
#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
#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