|
1 |
|
2 /* |
|
3 * Copyright 2012 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 #include "SkSweepGradient.h" |
|
10 |
|
11 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, |
|
12 const Descriptor& desc) |
|
13 : SkGradientShaderBase(desc) |
|
14 , fCenter(SkPoint::Make(cx, cy)) |
|
15 { |
|
16 fPtsToUnit.setTranslate(-cx, -cy); |
|
17 |
|
18 // overwrite the tilemode to a canonical value (since sweep ignores it) |
|
19 fTileMode = SkShader::kClamp_TileMode; |
|
20 } |
|
21 |
|
22 SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap, |
|
23 SkMatrix* matrix, SkShader::TileMode* xy) const { |
|
24 if (bitmap) { |
|
25 this->getGradientTableBitmap(bitmap); |
|
26 } |
|
27 if (matrix) { |
|
28 *matrix = fPtsToUnit; |
|
29 } |
|
30 if (xy) { |
|
31 xy[0] = fTileMode; |
|
32 xy[1] = kClamp_TileMode; |
|
33 } |
|
34 return kSweep_BitmapType; |
|
35 } |
|
36 |
|
37 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const { |
|
38 if (info) { |
|
39 commonAsAGradient(info); |
|
40 info->fPoint[0] = fCenter; |
|
41 } |
|
42 return kSweep_GradientType; |
|
43 } |
|
44 |
|
45 SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer) |
|
46 : INHERITED(buffer), |
|
47 fCenter(buffer.readPoint()) { |
|
48 } |
|
49 |
|
50 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { |
|
51 this->INHERITED::flatten(buffer); |
|
52 buffer.writePoint(fCenter); |
|
53 } |
|
54 |
|
55 // returns angle in a circle [0..2PI) -> [0..255] |
|
56 static unsigned SkATan2_255(float y, float x) { |
|
57 // static const float g255Over2PI = 255 / (2 * SK_ScalarPI); |
|
58 static const float g255Over2PI = 40.584510488433314f; |
|
59 |
|
60 float result = sk_float_atan2(y, x); |
|
61 if (result < 0) { |
|
62 result += 2 * SK_ScalarPI; |
|
63 } |
|
64 SkASSERT(result >= 0); |
|
65 // since our value is always >= 0, we can cast to int, which is faster than |
|
66 // calling floorf() |
|
67 int ir = (int)(result * g255Over2PI); |
|
68 SkASSERT(ir >= 0 && ir <= 255); |
|
69 return ir; |
|
70 } |
|
71 |
|
72 void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, |
|
73 int count) { |
|
74 SkMatrix::MapXYProc proc = fDstToIndexProc; |
|
75 const SkMatrix& matrix = fDstToIndex; |
|
76 const SkPMColor* SK_RESTRICT cache = this->getCache32(); |
|
77 int toggle = init_dither_toggle(x, y); |
|
78 SkPoint srcPt; |
|
79 |
|
80 if (fDstToIndexClass != kPerspective_MatrixClass) { |
|
81 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, |
|
82 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
|
83 SkScalar dx, fx = srcPt.fX; |
|
84 SkScalar dy, fy = srcPt.fY; |
|
85 |
|
86 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
|
87 SkFixed storage[2]; |
|
88 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, |
|
89 &storage[0], &storage[1]); |
|
90 dx = SkFixedToScalar(storage[0]); |
|
91 dy = SkFixedToScalar(storage[1]); |
|
92 } else { |
|
93 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
|
94 dx = matrix.getScaleX(); |
|
95 dy = matrix.getSkewY(); |
|
96 } |
|
97 |
|
98 for (; count > 0; --count) { |
|
99 *dstC++ = cache[toggle + SkATan2_255(fy, fx)]; |
|
100 fx += dx; |
|
101 fy += dy; |
|
102 toggle = next_dither_toggle(toggle); |
|
103 } |
|
104 } else { // perspective case |
|
105 for (int stop = x + count; x < stop; x++) { |
|
106 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, |
|
107 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
|
108 *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)]; |
|
109 toggle = next_dither_toggle(toggle); |
|
110 } |
|
111 } |
|
112 } |
|
113 |
|
114 void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, |
|
115 int count) { |
|
116 SkMatrix::MapXYProc proc = fDstToIndexProc; |
|
117 const SkMatrix& matrix = fDstToIndex; |
|
118 const uint16_t* SK_RESTRICT cache = this->getCache16(); |
|
119 int toggle = init_dither_toggle16(x, y); |
|
120 SkPoint srcPt; |
|
121 |
|
122 if (fDstToIndexClass != kPerspective_MatrixClass) { |
|
123 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, |
|
124 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
|
125 SkScalar dx, fx = srcPt.fX; |
|
126 SkScalar dy, fy = srcPt.fY; |
|
127 |
|
128 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
|
129 SkFixed storage[2]; |
|
130 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, |
|
131 &storage[0], &storage[1]); |
|
132 dx = SkFixedToScalar(storage[0]); |
|
133 dy = SkFixedToScalar(storage[1]); |
|
134 } else { |
|
135 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
|
136 dx = matrix.getScaleX(); |
|
137 dy = matrix.getSkewY(); |
|
138 } |
|
139 |
|
140 for (; count > 0; --count) { |
|
141 int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits); |
|
142 *dstC++ = cache[toggle + index]; |
|
143 toggle = next_dither_toggle16(toggle); |
|
144 fx += dx; |
|
145 fy += dy; |
|
146 } |
|
147 } else { // perspective case |
|
148 for (int stop = x + count; x < stop; x++) { |
|
149 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, |
|
150 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
|
151 |
|
152 int index = SkATan2_255(srcPt.fY, srcPt.fX); |
|
153 index >>= (8 - kCache16Bits); |
|
154 *dstC++ = cache[toggle + index]; |
|
155 toggle = next_dither_toggle16(toggle); |
|
156 } |
|
157 } |
|
158 } |
|
159 |
|
160 ///////////////////////////////////////////////////////////////////// |
|
161 |
|
162 #if SK_SUPPORT_GPU |
|
163 |
|
164 #include "GrTBackendEffectFactory.h" |
|
165 |
|
166 class GrGLSweepGradient : public GrGLGradientEffect { |
|
167 public: |
|
168 |
|
169 GrGLSweepGradient(const GrBackendEffectFactory& factory, |
|
170 const GrDrawEffect&) : INHERITED (factory) { } |
|
171 virtual ~GrGLSweepGradient() { } |
|
172 |
|
173 virtual void emitCode(GrGLShaderBuilder*, |
|
174 const GrDrawEffect&, |
|
175 EffectKey, |
|
176 const char* outputColor, |
|
177 const char* inputColor, |
|
178 const TransformedCoordsArray&, |
|
179 const TextureSamplerArray&) SK_OVERRIDE; |
|
180 |
|
181 static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
|
182 return GenBaseGradientKey(drawEffect); |
|
183 } |
|
184 |
|
185 private: |
|
186 |
|
187 typedef GrGLGradientEffect INHERITED; |
|
188 |
|
189 }; |
|
190 |
|
191 ///////////////////////////////////////////////////////////////////// |
|
192 |
|
193 class GrSweepGradient : public GrGradientEffect { |
|
194 public: |
|
195 static GrEffectRef* Create(GrContext* ctx, |
|
196 const SkSweepGradient& shader, |
|
197 const SkMatrix& matrix) { |
|
198 AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix))); |
|
199 return CreateEffectRef(effect); |
|
200 } |
|
201 virtual ~GrSweepGradient() { } |
|
202 |
|
203 static const char* Name() { return "Sweep Gradient"; } |
|
204 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
|
205 return GrTBackendEffectFactory<GrSweepGradient>::getInstance(); |
|
206 } |
|
207 |
|
208 typedef GrGLSweepGradient GLEffect; |
|
209 |
|
210 private: |
|
211 GrSweepGradient(GrContext* ctx, |
|
212 const SkSweepGradient& shader, |
|
213 const SkMatrix& matrix) |
|
214 : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { } |
|
215 GR_DECLARE_EFFECT_TEST; |
|
216 |
|
217 typedef GrGradientEffect INHERITED; |
|
218 }; |
|
219 |
|
220 ///////////////////////////////////////////////////////////////////// |
|
221 |
|
222 GR_DEFINE_EFFECT_TEST(GrSweepGradient); |
|
223 |
|
224 GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random, |
|
225 GrContext* context, |
|
226 const GrDrawTargetCaps&, |
|
227 GrTexture**) { |
|
228 SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; |
|
229 |
|
230 SkColor colors[kMaxRandomGradientColors]; |
|
231 SkScalar stopsArray[kMaxRandomGradientColors]; |
|
232 SkScalar* stops = stopsArray; |
|
233 SkShader::TileMode tmIgnored; |
|
234 int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored); |
|
235 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY, |
|
236 colors, stops, colorCount)); |
|
237 SkPaint paint; |
|
238 return shader->asNewEffect(context, paint); |
|
239 } |
|
240 |
|
241 ///////////////////////////////////////////////////////////////////// |
|
242 |
|
243 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder, |
|
244 const GrDrawEffect&, |
|
245 EffectKey key, |
|
246 const char* outputColor, |
|
247 const char* inputColor, |
|
248 const TransformedCoordsArray& coords, |
|
249 const TextureSamplerArray& samplers) { |
|
250 this->emitUniforms(builder, key); |
|
251 SkString coords2D = builder->ensureFSCoords2D(coords, 0); |
|
252 const GrGLContextInfo ctxInfo = builder->ctxInfo(); |
|
253 SkString t; |
|
254 // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] |
|
255 // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int |
|
256 // thus must us -1.0 * %s.x to work correctly |
|
257 if (kIntel_GrGLVendor != ctxInfo.vendor()){ |
|
258 t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", |
|
259 coords2D.c_str(), coords2D.c_str()); |
|
260 } else { |
|
261 t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5", |
|
262 coords2D.c_str(), coords2D.c_str()); |
|
263 } |
|
264 this->emitColor(builder, t.c_str(), key, |
|
265 outputColor, inputColor, samplers); |
|
266 } |
|
267 |
|
268 ///////////////////////////////////////////////////////////////////// |
|
269 |
|
270 GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const { |
|
271 SkMatrix matrix; |
|
272 if (!this->getLocalMatrix().invert(&matrix)) { |
|
273 return NULL; |
|
274 } |
|
275 matrix.postConcat(fPtsToUnit); |
|
276 return GrSweepGradient::Create(context, *this, matrix); |
|
277 } |
|
278 |
|
279 #else |
|
280 |
|
281 GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const { |
|
282 SkDEBUGFAIL("Should not call in GPU-less build"); |
|
283 return NULL; |
|
284 } |
|
285 |
|
286 #endif |
|
287 |
|
288 #ifndef SK_IGNORE_TO_STRING |
|
289 void SkSweepGradient::toString(SkString* str) const { |
|
290 str->append("SkSweepGradient: ("); |
|
291 |
|
292 str->append("center: ("); |
|
293 str->appendScalar(fCenter.fX); |
|
294 str->append(", "); |
|
295 str->appendScalar(fCenter.fY); |
|
296 str->append(") "); |
|
297 |
|
298 this->INHERITED::toString(str); |
|
299 |
|
300 str->append(")"); |
|
301 } |
|
302 #endif |