Skip to content

Commit

Permalink
Added multifilter
Browse files Browse the repository at this point in the history
  • Loading branch information
GarthSnyder committed Mar 19, 2012
1 parent 4312b6b commit 03122c4
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 41 deletions.
2 changes: 1 addition & 1 deletion framework/GPUImage.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
Expand Down
2 changes: 1 addition & 1 deletion framework/Source/GPUImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
60 changes: 28 additions & 32 deletions framework/Source/GPUImage.m
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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
{
Expand Down
6 changes: 4 additions & 2 deletions framework/Source/GPUImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -39,7 +42,6 @@
- (void) draw;

// Still image processing convenience methods
- (UIImage *) outputAsUIImage;
- (UIImage *) imageByFilteringImage:(UIImage *)imageToFilter;

@end
5 changes: 0 additions & 5 deletions framework/Source/GPUImageFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
47 changes: 47 additions & 0 deletions framework/Source/GPUImageMultiFilter.h
Original file line number Diff line number Diff line change
@@ -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
138 changes: 138 additions & 0 deletions framework/Source/GPUImageMultiFilter.m
Original file line number Diff line number Diff line change
@@ -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.