framework/Source/GPUImageMosaicFilter.m
//
//  GPUImageMosaicFilter.m


#import "GPUImageMosaicFilter.h"
#import "GPUImagePicture.h"

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kGPUImageMosaicFragmentShaderString = SHADER_STRING
(
 precision highp float;
 
 varying vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;
 
 uniform vec2 inputTileSize;
 uniform vec2 displayTileSize;
 uniform float numTiles;
 uniform int colorOn;
 
 void main()
 {
     vec2 xy = textureCoordinate;
     xy = xy - mod(xy, displayTileSize);
     
     vec4 lumcoeff = vec4(0.299,0.587,0.114,0.0);
     
     vec4 inputColor = texture2D(inputImageTexture2, xy);
     float lum = dot(inputColor,lumcoeff);
     lum = 1.0 - lum;
     
     float stepsize = 1.0 / numTiles;
     float lumStep = (lum - mod(lum, stepsize)) / stepsize; 
  
     float rowStep = 1.0 / inputTileSize.x;
     float x = mod(lumStep, rowStep);
     float y = floor(lumStep / rowStep);
     
     vec2 startCoord = vec2(float(x) *  inputTileSize.x, float(y) * inputTileSize.y);
     vec2 finalCoord = startCoord + ((textureCoordinate - xy) * (inputTileSize / displayTileSize));
     
     vec4 color = texture2D(inputImageTexture, finalCoord);   
     if (colorOn == 1) {
         color = color * inputColor;
     }
     gl_FragColor = color; 
     
 }  
);
#else
NSString *const kGPUImageMosaicFragmentShaderString = SHADER_STRING
(
 varying vec2 textureCoordinate;
 
 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;
 
 uniform vec2 inputTileSize;
 uniform vec2 displayTileSize;
 uniform float numTiles;
 uniform int colorOn;
 
 void main()
 {
     vec2 xy = textureCoordinate;
     xy = xy - mod(xy, displayTileSize);
     
     vec4 lumcoeff = vec4(0.299,0.587,0.114,0.0);
     
     vec4 inputColor = texture2D(inputImageTexture2, xy);
     float lum = dot(inputColor,lumcoeff);
     lum = 1.0 - lum;
     
     float stepsize = 1.0 / numTiles;
     float lumStep = (lum - mod(lum, stepsize)) / stepsize;
     
     float rowStep = 1.0 / inputTileSize.x;
     float x = mod(lumStep, rowStep);
     float y = floor(lumStep / rowStep);
     
     vec2 startCoord = vec2(float(x) *  inputTileSize.x, float(y) * inputTileSize.y);
     vec2 finalCoord = startCoord + ((textureCoordinate - xy) * (inputTileSize / displayTileSize));
     
     vec4 color = texture2D(inputImageTexture, finalCoord);
     if (colorOn == 1) {
         color = color * inputColor;
     }
     gl_FragColor = color;
 }
);
#endif

@implementation GPUImageMosaicFilter

@synthesize inputTileSize = _inputTileSize, numTiles = _numTiles, displayTileSize = _displayTileSize, colorOn = _colorOn;
@synthesize tileSet = _tileSet;

- (id)init;
{
    if (!(self = [super initWithFragmentShaderFromString:kGPUImageMosaicFragmentShaderString]))
    {
		return nil;
    }
    
    inputTileSizeUniform = [filterProgram uniformIndex:@"inputTileSize"];
    displayTileSizeUniform = [filterProgram uniformIndex:@"displayTileSize"];
    numTilesUniform = [filterProgram uniformIndex:@"numTiles"];
    colorOnUniform = [filterProgram uniformIndex:@"colorOn"];
    
    CGSize its = CGSizeMake(0.125, 0.125);
    CGSize dts = CGSizeMake(0.025, 0.025);
    [self setDisplayTileSize:dts];
    [self setInputTileSize:its];
    [self setNumTiles:64.0];
    [self setColorOn:YES];
    //[self setTileSet:@"squares.png"];
    return self;
}

- (void)setColorOn:(BOOL)yes
{
    glUniform1i(colorOnUniform, yes);
}

- (void)setNumTiles:(float)numTiles
{

    _numTiles = numTiles;
    [self setFloat:_numTiles forUniformName:@"numTiles"];
}

- (void)setInputTileSize:(CGSize)inputTileSize
{
    if (inputTileSize.width > 1.0) {
        _inputTileSize.width = 1.0;
    } 
    if (inputTileSize.height > 1.0) {
        _inputTileSize.height = 1.0;
    }
    if (inputTileSize.width < 0.0) {
        _inputTileSize.width = 0.0;
    }
    if (inputTileSize.height < 0.0) {
        _inputTileSize.height = 0.0;
    }
    
    
    _inputTileSize = inputTileSize;
    
    [self setSize:_inputTileSize forUniform:inputTileSizeUniform program:filterProgram];    
}

-(void)setDisplayTileSize:(CGSize)displayTileSize
{
    if (displayTileSize.width > 1.0) {
        _displayTileSize.width = 1.0;
    } 
    if (displayTileSize.height > 1.0) {
        _displayTileSize.height = 1.0;
    }
    if (displayTileSize.width < 0.0) {
        _displayTileSize.width = 0.0;
    }
    if (displayTileSize.height < 0.0) {
        _displayTileSize.height = 0.0;
    }
    
    
    _displayTileSize = displayTileSize;
    
    [self setSize:_displayTileSize forUniform:displayTileSizeUniform program:filterProgram];
}

-(void)setTileSet:(NSString *)tileSet
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
    UIImage *img = [UIImage imageNamed:tileSet];
#else
    NSImage *img = [NSImage imageNamed:tileSet];
#endif
    pic = [[GPUImagePicture alloc] initWithImage:img smoothlyScaleOutput:YES];
    [pic addTarget:self];
    [pic processImage];
}

@end
