OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2014 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "GrDitherEffect.h" | |
9 | |
10 #include "gl/GrGLEffect.h" | |
11 #include "gl/GrGLSL.h" | |
12 #include "GrTBackendEffectFactory.h" | |
13 | |
14 #include "SkRect.h" | |
15 | |
16 ////////////////////////////////////////////////////////////////////////////// | |
17 | |
18 class GLDitherEffect; | |
19 | |
20 class DitherEffect : public GrEffect { | |
21 public: | |
22 static GrEffectRef* Create() { | |
23 return CreateEffectRef(AutoEffectUnref(SkNEW(DitherEffect))); | |
24 } | |
25 | |
26 virtual ~DitherEffect() {}; | |
27 static const char* Name() { return "Dither"; } | |
28 | |
29 typedef GLDitherEffect GLEffect; | |
30 | |
31 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE; | |
32 | |
33 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
34 return GrTBackendEffectFactory<DitherEffect>::getInstance(); | |
35 } | |
36 | |
37 private: | |
38 DitherEffect() { | |
39 this->setWillReadFragmentPosition(); | |
40 } | |
41 | |
42 // All dither effects are equal | |
43 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } | |
44 | |
45 GR_DECLARE_EFFECT_TEST; | |
46 | |
47 typedef GrEffect INHERITED; | |
48 }; | |
49 | |
50 void DitherEffect::getConstantColorComponents(GrColor* color, uint32_t* validFla gs) const { | |
51 *validFlags = 0; | |
52 } | |
53 | |
54 ////////////////////////////////////////////////////////////////////////////// | |
55 | |
56 GR_DEFINE_EFFECT_TEST(DitherEffect); | |
57 | |
58 GrEffectRef* DitherEffect::TestCreate(SkRandom*, | |
59 GrContext*, | |
60 const GrDrawTargetCaps&, | |
61 GrTexture*[]) { | |
62 return DitherEffect::Create(); | |
63 } | |
64 | |
65 ////////////////////////////////////////////////////////////////////////////// | |
66 | |
67 class GLDitherEffect : public GrGLEffect { | |
68 public: | |
69 GLDitherEffect(const GrBackendEffectFactory&, const GrDrawEffect&); | |
70 | |
71 virtual void emitCode(GrGLShaderBuilder* builder, | |
72 const GrDrawEffect& drawEffect, | |
73 EffectKey key, | |
74 const char* outputColor, | |
75 const char* inputColor, | |
76 const TransformedCoordsArray&, | |
77 const TextureSamplerArray&) SK_OVERRIDE; | |
78 | |
79 private: | |
80 typedef GrGLEffect INHERITED; | |
81 }; | |
82 | |
83 GLDitherEffect::GLDitherEffect(const GrBackendEffectFactory& factory, | |
84 const GrDrawEffect& drawEffect) | |
85 : INHERITED (factory) { | |
86 } | |
87 | |
88 void GLDitherEffect::emitCode(GrGLShaderBuilder* builder, | |
89 const GrDrawEffect& drawEffect, | |
90 EffectKey key, | |
91 const char* outputColor, | |
92 const char* inputColor, | |
93 const TransformedCoordsArray&, | |
94 const TextureSamplerArray& samplers) { | |
95 #if GR_DITHER_RANDOM | |
96 // Generate a random number based on the fragment position. For this | |
97 // random number generator, we use the "GLSL rand" function | |
98 // that seems to be floating around on the internet. It works under | |
99 // the assumption that sin(<big number>) oscillates with high frequency | |
100 // and sampling it will generate "randomness". Since we're using this | |
101 // for rendering and not cryptography it should be OK. | |
102 | |
103 // for each channel c: | |
104 // 1. Compute quantized colors [low, high] that c is between | |
105 // 2. Pick high by flipping a coin weighted by (c - low) | |
106 builder->fsCodeAppendf("\t\tfloat r = " | |
107 "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758. 5453);\n", | |
108 builder->fragmentPosition()); | |
109 | |
110 // For each channel, weight the neighboring pixel values based on thier | |
111 // distance from the input channel | |
112 static const char *kSuffixes[] = { "r", "g", "b" }; | |
113 static const int kNumSuffixes = SK_ARRAY_COUNT(kSuffixes); | |
114 for (int i = 0; i < kNumSuffixes; ++i) { | |
115 builder->fsCodeAppendf("\t\tfloat dithered_%s;\n", kSuffixes[i]); | |
116 builder->fsCodeAppendf("\t\t{\n"); | |
117 builder->fsCodeAppendf("\t\t\tfloat channel = 255.0f * %s.%s;\n", | |
118 inputColor, kSuffixes[i]); | |
119 builder->fsCodeAppendf("\t\t\tfloat low = floor(channel);\n"); | |
120 builder->fsCodeAppendf("\t\t\tfloat c = channel-low;\n"); | |
121 builder->fsCodeAppendf("\t\t\tfloat high = low + 1;\n"); | |
122 builder->fsCodeAppendf("\t\t\tfloat t = float(c > r);\n"); | |
123 builder->fsCodeAppendf("\t\t\tdithered_%s = (low*(1-t) + high*t)/255.0f; \n", kSuffixes[i]); | |
124 builder->fsCodeAppendf("\t\t}\n"); | |
125 } | |
126 | |
127 builder->fsCodeAppendf("\t\t%s = vec4(", outputColor); | |
128 for (int i = 0; i < kNumSuffixes; ++i) { | |
129 builder->fsCodeAppendf("dithered_%s%s", kSuffixes[i], (i < kNumSuffixes) ? ", " : ""); | |
130 } | |
131 builder->fsCodeAppendf("%s.a);\n", inputColor); | |
132 #else | |
133 builder->fsCodeAppendf("\t\tfloat dither[4] = float[4](\n"); | |
134 builder->fsCodeAppendf("\t\t\t0.000784314, 0.00235294, 0.00313725, 0.0015686 3);\n"); | |
135 builder->fsCodeAppendf("\t\tint x = int(%s.x + 0.5) & 1;\n", builder->fragme ntPosition()); | |
bsalomon
2014/06/12 19:59:54
ES2 doesn't have integer types. We may need to hav
| |
136 builder->fsCodeAppendf("\t\tint y = int(%s.y + 0.5) & 1;\n", builder->fragme ntPosition()); | |
137 builder->fsCodeAppendf("\t\tfloat d = dither[y*2+x];\n"); | |
138 builder->fsCodeAppendf("\t\t%s = vec4(d, d, d, 0) + %s;\n", | |
139 outputColor, inputColor); | |
140 #endif | |
141 } | |
142 | |
143 ////////////////////////////////////////////////////////////////////////////// | |
144 | |
145 GrEffectRef* GrDitherEffect::Create() { | |
146 return DitherEffect::Create(); | |
147 } | |
OLD | NEW |