Permalink
Browse files

Added multifilter

  • Loading branch information...
1 parent 4312b6b commit 03122c43aa614d77a4408ffa55e1ee4f57982ac5 @GarthSnyder committed Mar 19, 2012
@@ -246,7 +246,7 @@
CE72156215169911005A2227 /* GPUImageRenderbuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageRenderbuffer.m; path = Source/GPUImageRenderbuffer.m; sourceTree = SOURCE_ROOT; };
CEE1F7CB1511932700385B6C /* GPUImageProtocols.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPUImageProtocols.h; path = Source/GPUImageProtocols.h; sourceTree = SOURCE_ROOT; };
CEE1F7CD1511944100385B6C /* GPUImageUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GPUImageUtils.c; path = Source/GPUImageUtils.c; sourceTree = SOURCE_ROOT; };
- CEE1F7CF15119A0200385B6C /* GPUImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImage.h; path = Source/GPUImage.h; sourceTree = SOURCE_ROOT; };
+ CEE1F7CF15119A0200385B6C /* GPUImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImage.h; path = Source/GPUImage.h; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
CEE1F7D015119A0200385B6C /* GPUImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImage.m; path = Source/GPUImage.m; sourceTree = SOURCE_ROOT; };
CEE1F7E91512BA1C00385B6C /* GPUImageProgram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageProgram.h; path = Source/GPUImageProgram.h; sourceTree = SOURCE_ROOT; };
CEE1F7EA1512BA1C00385B6C /* GPUImageProgram.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageProgram.m; path = Source/GPUImageProgram.m; sourceTree = SOURCE_ROOT; };
@@ -43,7 +43,7 @@
@property (nonatomic) BOOL generateMipmap;
-// Let the texture manage this! Not part of the general API.
+// Generally NOT necessary to access this directly
@property (strong, nonatomic) GPUImageBuffer *backingStore;
- (void) bindAsFramebuffer;
@@ -1,14 +1,7 @@
-// Created by Garth Snyder on 3/14/12.
-
#import "GPUImage.h"
#import "GPUImageTextureBuffer.h"
#import "GPUImageRenderbuffer.h"
-@interface GPUImage ()
-{
- BOOL _renderbufferRequested;
-}
-
@end
@implementation GPUImage
@@ -98,16 +91,12 @@ - (void) setGenerateMipmap:(BOOL)gen
- (void) adoptParametersFrom:(GPUImage *)other
{
- GLsize newSize = self.size;
- if (!newSize.width || !newSize.height) {
- newSize = other.size;
- self.size = newSize;
+ if (!self.size.width || !self.size.height) {
+ self.size = other.size;
}
-
if (!self.baseFormat) {
self.baseFormat = other.baseFormat;
}
-
if (!self.pixType) {
self.pixType = other.pixType;
}
@@ -143,41 +132,42 @@ - (void) adoptParametersFrom:(GPUImage *)other
- (BOOL) render
{
- NSAssert([parents count] == 1, @"Textures should have only one parent.");
-
- if ([[parents anyObject] isKindOfClass:[GPUImage class]]) {
- GPUImage *parent = [parents anyObject];
- NSAssert(![self parentRequiresConversion:parent],
+ if ([parent isKindOfClass:[GPUImage class]]) {
+ GPUImage *gpuParent = parent;
+ NSAssert(![self parentRequiresConversion:gpuParent],
@"Automatic texture size and format conversions are not yet supported.");
self.backingStore = parent.backingStore;
[self setTextureParams];
}
if (!self.useRenderbuffer && self.generateMipmap) {
GPUImageTextureBuffer *store = (GPUImageTextureBuffer *)self.backingStore;
- [store generateMipmap];
+ [store generateMipmap]; // Optimized out if already done
}
timeLastChanged = GPUImageGetCurrentTimestamp();
return YES;
}
-// Is there anything about the parent texture that makes it impossible for us
+// Is there anything about the parent GPUImage that makes it impossible for us
// to share the parent's backing texture?
-- (BOOL) parentRequiresConversion:(GPUImage *)parent
+- (BOOL) parentRequiresConversion:(GPUImage *)gp
{
- return ((self.useRenderbuffer != parent.useRenderbuffer)
- || (self.size.width != parent.size.width)
- || (self.size.height != parent.size.height)
- || (self.baseFormat != parent.baseFormat)
- || (!self.useRenderbuffer && (self.pixType != parent.pixType)));
+ return ((self.useRenderbuffer != gp.useRenderbuffer)
+ || (self.size.width != gp.size.width)
+ || (self.size.height != gp.size.height)
+ || (self.baseFormat != gp.baseFormat)
+ || (!self.useRenderbuffer && (self.pixType != gp.pixType)));
}
+// Propagate configuration parameters for textures through to the OpenGL
+// wrapper layer.
+
- (void) setTextureParams
{
- GPUImageTextureBuffer *store = (GPUImageTextureBuffer *)self.backingStore;
- if (self.useRenderbuffer || !store) {
+ if (self.useRenderbuffer || !self.backingStore) {
return;
}
+ GPUImageTextureBuffer *store = (GPUImageTextureBuffer *)self.backingStore;
[store bind];
if (self.magFilter > 0) {
store.magFilter = self.magFilter;
@@ -200,8 +190,8 @@ - (void) bindAsFramebuffer
return;
}
// We're going to have to create the backing store. Must know at least
- // size and base format.
- NSAssert(self.size.width && self.size.height && self.baseFormat,
+ // size and base format, or for layer-based renderbuffers, the layer id.
+ NSAssert(self.layer || (self.size.width && self.size.height && self.baseFormat),
@"Cannot bindAsFramebuffer without at least size and base format.");
if (self.useRenderbuffer) {
if (self.layer) {
@@ -223,9 +213,15 @@ - (void) bindAsFramebuffer
[self.backingStore bindAsFramebuffer];
}
-- (GLuint *) getRawContents;
+- (GLuint *) getRawContents
+{
+ return [self.backingStore rawDataFromFramebuffer];
+}
-- (CGImageRef) getCGImage;
+- (CGImageRef) getCGImage
+{
+ return [self.backingStore CGImageFromFramebuffer];
+}
- (UIImage *) getUIImage
{
@@ -3,7 +3,10 @@
#import "GPUImage.h"
#import <UIKit/UIKit.h>
-@interface GPUImageFilter : GPUImageElement
+// A GPUImageFilter is a GPUImage that uses an OpenGL program to transform
+// its input image.
+
+@interface GPUImageFilter : GPUImage
{
NSMutableArray *programs;
NSMutableArray *outputTextures;
@@ -39,7 +42,6 @@
- (void) draw;
// Still image processing convenience methods
-- (UIImage *) outputAsUIImage;
- (UIImage *) imageByFilteringImage:(UIImage *)imageToFilter;
@end
@@ -121,11 +121,6 @@ - (void) draw
#pragma mark -
#pragma mark Still image convenience methods
-- (UIImage *) outputAsUIImage
-{
- return [self.outputTexture textureAsUIImage];
-}
-
- (UIImage *) imageByFilteringImage:(UIImage *)imageToFilter
{
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:imageToFilter];
@@ -0,0 +1,47 @@
+#import "GPUImageElement.h"
+#import "GPUImageProgram.h"
+#import "GPUImage.h"
+#import <UIKit/UIKit.h>
+
+// A GPUImageFilter is a GPUImage that uses an OpenGL program to transform
+// its input image.
+
+@interface GPUImageFilter : GPUImage
+{
+ NSMutableArray *programs;
+ NSMutableArray *outputTextures;
+}
+
+// These property names are conventional. If there are multiple program stages,
+// these textures denote the first input and the very last output.
+// More complex filters may use additional input and output textures if
+// desired; they can also ignore the standard input and output textures
+// with no ill effects if they wish.
+
+@property (strong, nonatomic) GPUImage *inputTexture;
+@property (strong, nonatomic) GPUImage *outputTexture;
+
+// Override to automatically set up a framework for >1 program in series
++ (int) numberOfFilterPrograms;
+
+// Convenience methods for subclasses
+@property (readonly, nonatomic) GPUImageProgram *program;
+@property (readonly, nonatomic) GPUImageProgram *programOne;
+@property (readonly, nonatomic) GPUImageProgram *programTwo;
+@property (readonly, nonatomic) GPUImageProgram *programThree;
+
+// If you are not using the standard inputTexture, you'll want to override
+// render in your subclass to set the proper size of the output texture.
+// Then call [super render]. The default implementation sets the size
+// from inputTexture if a size has not already been set.
+
+- (BOOL) render;
+
+// Called as part of render; override if you don't want std triangulation
+
+- (void) draw;
+
+// Still image processing convenience methods
+- (UIImage *) imageByFilteringImage:(UIImage *)imageToFilter;
+
+@end
@@ -0,0 +1,138 @@
+#import "GPUImageFilter.h"
+#import "GPUImagePicture.h"
+
+@interface GPUImageFilter
+- (GPUImageProgram *) filterProgramAtIndex:(int)n;
+@end
+
+@implementation GPUImageFilter
+
+@dynamic inputTexture;
+
+#pragma mark -
+#pragma mark Basic setup and utility
+
++ (int) numberOfFilterPrograms
+{
+ return 1;
+}
+
+- (id) init
+{
+ if (self = [super init]) {
+ filterPrograms = [NSMutableArray array];
+ int nFilters = [[self class] numberOfFilterPrograms];
+ GPUImage *texture = nil;
+ for (int i = 0; i < nFilters; i++) {
+ GPUImageProgram *newProgram = [GPUImageProgram program];
+ if (texture) {
+ [newProgram setValue:texture forKey:@"inputTexture"];
+ }
+ [filterPrograms addObject:newProgram];
+ texture = [GPUImage texture];
+ [outputTextures addObject:texture];
+ }
+ [[outputTextures lastObject] deriveFrom:self];
+ }
+ return self;
+}
+
+- (GPUImageProgram *)filterProgram {
+ return [self filterProgramAtIndex:0];
+}
+
+- (GPUImageProgram *)filterProgramOne {
+ return [self filterProgramAtIndex:0];
+}
+
+- (GPUImageProgram *)filterProgramTwo {
+ return [self filterProgramAtIndex:1];
+}
+
+- (GPUImageProgram *)filterProgramThree {
+ return [self filterProgramAtIndex:2];
+}
+
+- (GPUImageProgram *)filterProgramAtIndex:(int)n {
+ return [filterPrograms objectAtIndex:n];
+}
+
+- (GPUImage *)outputTexture {
+ return [outputTextures lastObject];
+}
+
+- (void) setOutputTexture:(GPUImage *)texture
+{
+ GPUImage *oldOutput = [outputTextures lastObject];
+ [outputTextures removeLastObject];
+ [oldOutput undoDerivationFrom:self];
+ [outputTextures addObject:texture];
+ [texture deriveFrom:self];
+}
+
+#pragma mark -
+#pragma mark Rendering and drawing
+
+- (BOOL) render
+{
+ // This is called via the update method in GPUImageElement, and is
+ // ultimately instigated by whoever downstream from us is pulling our
+ // product textures. By this point, all of our parent objects have been
+ // made current, so we just need to set up our rendering environment
+ // and draw.
+
+ for (int i = 0; i < [filterPrograms count]; i++) {
+ GPUImageProgram *program = [filterPrograms objectAtIndex:i];
+ GPUImage *output = [outputTextures objectAtIndex:i];
+ if (program.inputTexture) {
+ [output takeUnknownParametersFrom:program.inputTexture];
+ }
+ if (![program use] || ![output bindAsFramebuffer]) {
+ return NO;
+ }
+ [self draw];
+ }
+ self.timeLastChanged = GPUImageGetCurrentTimestamp();
+ return YES;
+}
+
+- (void) draw
+{
+ static const GLfloat squareVertices[] = {
+ -1.0, -1.0,
+ 1.0, -1.0,
+ -1.0, 1.0,
+ 1.0, 1.0,
+ };
+
+ static const GLfloat squareTextureCoordinates[] = {
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ };
+
+ // TODO: Work out attrib management
+ glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, squareVertices);
+ glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, squareTextureCoordinates);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+#pragma mark -
+#pragma mark Still image convenience methods
+
+- (UIImage *) imageByFilteringImage:(UIImage *)imageToFilter
+{
+ GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:imageToFilter];
+ [self.inputTexture deriveFrom:stillImageSource.outputTexture];
+ [self.outputTexture update];
+ [self.inputTexture underiveFrom:stillImageSource.outputTexture];
+ return [self.outputTexture textureAsUIImage];
+}
+
+#pragma mark -
+#pragma mark Attribute and uniform processing
+
+// TODO: Handle attribs and uniforms on behalf of program
+
+@end

0 comments on commit 03122c4

Please sign in to comment.