1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/thirdparty/PGPhotoEditor/PGGrainTool.m
2015-10-01 19:19:52 +03:00

162 lines
5.4 KiB
Objective-C

#import "PGGrainTool.h"
@interface PGGrainTool ()
{
PGPhotoProcessPassParameter *_parameter;
}
@end
@implementation PGGrainTool
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_identifier = @"grain";
_type = PGPhotoToolTypeShader;
_order = 12;
_minimumValue = 0;
_maximumValue = 100;
_defaultValue = 0;
self.value = @(_defaultValue);
}
return self;
}
- (NSString *)title
{
return TGLocalized(@"PhotoEditor.GrainTool");
}
- (UIImage *)image
{
return [UIImage imageNamed:@"PhotoEditorGrainTool"];
}
- (bool)shouldBeSkipped
{
return (ABS(((NSNumber *)self.displayValue).floatValue - (float)self.defaultValue) < FLT_EPSILON);
}
- (NSArray *)parameters
{
if (!_parameters)
{
_parameter = [PGPhotoProcessPassParameter parameterWithName:@"grain" type:@"lowp float"];
_parameters = @[ _parameter,
[PGPhotoProcessPassParameter constWithName:@"permTexUnit" type:@"lowp float" value:@"1.0 / 256.0"],
[PGPhotoProcessPassParameter constWithName:@"permTexUnitHalf" type:@"lowp float" value:@"0.5 / 256.0"],
[PGPhotoProcessPassParameter constWithName:@"grainsize" type:@"lowp float" value:@"2.3"] ];
}
return _parameters;
}
- (void)updateParameters
{
NSNumber *value = (NSNumber *)self.displayValue;
CGFloat parameterValue = value.floatValue / 100.0f * 0.04f;
[_parameter setFloatValue:parameterValue];
}
- (NSString *)ancillaryShaderString
{
return PGShaderString
(
highp vec4 rnm(in highp vec2 tc) {
highp float noise = sin(dot(tc,vec2(12.9898,78.233))) * 43758.5453;
highp float noiseR = fract(noise)*2.0-1.0;
highp float noiseG = fract(noise*1.2154)*2.0-1.0;
highp float noiseB = fract(noise*1.3453)*2.0-1.0;
highp float noiseA = fract(noise*1.3647)*2.0-1.0;
return vec4(noiseR,noiseG,noiseB,noiseA);
}
highp float fade(in highp float t) {
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
highp float pnoise3D(in highp vec3 p)
{
highp vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;
highp vec3 pf = fract(p);
// Noise contributions from (x=0, y=0), z=0 and z=1
highp float perm00 = rnm(pi.xy).a ;
highp vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;
highp float n000 = dot(grad000, pf);
highp vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
highp float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));
// Noise contributions from (x=0, y=1), z=0 and z=1
highp float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a ;
highp vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;
highp float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));
highp vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
highp float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));
// Noise contributions from (x=1, y=0), z=0 and z=1
highp float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a ;
highp vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;
highp float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));
highp vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
highp float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));
// Noise contributions from (x=1, y=1), z=0 and z=1
highp float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a ;
highp vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;
highp float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));
highp vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;
highp float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));
// Blend contributions along x
highp vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));
// Blend contributions along y
highp vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));
// Blend contributions along z
highp float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));
return n_xyz;
}
lowp vec2 coordRot(in lowp vec2 tc, in lowp float angle)
{
lowp float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));
lowp float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));
rotX = rotX * 0.5 + 0.5;
rotY = rotY * 0.5 + 0.5;
return vec2(rotX,rotY);
}
);
}
- (NSString *)shaderString
{
return PGShaderString
(
if (abs(grain) > toolEpsilon) {
highp vec3 rotOffset = vec3(1.425, 3.892, 5.835);
highp vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);
highp vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));
lowp vec3 lumcoeff = vec3(0.299,0.587,0.114);
lowp float luminance = dot(result.rgb, lumcoeff);
lowp float lum = smoothstep(0.2, 0.0, luminance);
lum += luminance;
noise = mix(noise,vec3(0.0),pow(lum,4.0));
result.rgb = result.rgb + noise * grain;
}
);
}
@end