blob: b4e013a0a196535fad8e4fb763bbca6d6dff4ddb [file] [log] [blame]
rileya@google.com589708b2012-07-26 20:04:23 +00001
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
11SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const SkColor colors[],
12 const SkScalar pos[], int count, SkUnitMapper* mapper)
13: SkGradientShaderBase(colors, pos, count, SkShader::kClamp_TileMode, mapper),
14 fCenter(SkPoint::Make(cx, cy))
15{
16 fPtsToUnit.setTranslate(-cx, -cy);
17}
18
19SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap,
20 SkMatrix* matrix, SkShader::TileMode* xy) const {
21 if (bitmap) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000022 this->getGradientTableBitmap(bitmap);
rileya@google.com589708b2012-07-26 20:04:23 +000023 }
24 if (matrix) {
25 *matrix = fPtsToUnit;
26 }
27 if (xy) {
28 xy[0] = fTileMode;
29 xy[1] = kClamp_TileMode;
30 }
31 return kSweep_BitmapType;
32}
33
34SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
35 if (info) {
36 commonAsAGradient(info);
37 info->fPoint[0] = fCenter;
38 }
39 return kSweep_GradientType;
40}
41
rileya@google.com589708b2012-07-26 20:04:23 +000042SkSweepGradient::SkSweepGradient(SkFlattenableReadBuffer& buffer)
43 : INHERITED(buffer),
44 fCenter(buffer.readPoint()) {
45}
46
47void SkSweepGradient::flatten(SkFlattenableWriteBuffer& buffer) const {
48 this->INHERITED::flatten(buffer);
49 buffer.writePoint(fCenter);
50}
51
52#ifndef SK_SCALAR_IS_FLOAT
53#ifdef COMPUTE_SWEEP_TABLE
54#define PI 3.14159265
55static bool gSweepTableReady;
56static uint8_t gSweepTable[65];
57
58/* Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
59 We scale the results to [0..32]
60*/
61static const uint8_t* build_sweep_table() {
62 if (!gSweepTableReady) {
63 const int N = 65;
64 const double DENOM = N - 1;
65
66 for (int i = 0; i < N; i++)
67 {
68 double arg = i / DENOM;
69 double v = atan(arg);
70 int iv = (int)round(v * DENOM * 2 / PI);
71// printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
72 printf("%d, ", iv);
73 gSweepTable[i] = iv;
74 }
75 gSweepTableReady = true;
76 }
77 return gSweepTable;
78}
79#else
80static const uint8_t gSweepTable[] = {
81 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
82 10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
83 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
84 26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
85 32
86};
87static const uint8_t* build_sweep_table() { return gSweepTable; }
88#endif
89#endif
90
91// divide numer/denom, with a bias of 6bits. Assumes numer <= denom
92// and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
93// Same as (but faster than) SkFixedDiv(numer, denom) >> 10
94
95//unsigned div_64(int numer, int denom);
96#ifndef SK_SCALAR_IS_FLOAT
97static unsigned div_64(int numer, int denom) {
98 SkASSERT(numer <= denom);
99 SkASSERT(numer > 0);
100 SkASSERT(denom > 0);
101
102 int nbits = SkCLZ(numer);
103 int dbits = SkCLZ(denom);
104 int bits = 6 - nbits + dbits;
105 SkASSERT(bits <= 6);
106
107 if (bits < 0) { // detect underflow
108 return 0;
109 }
110
111 denom <<= dbits - 1;
112 numer <<= nbits - 1;
113
114 unsigned result = 0;
115
116 // do the first one
117 if ((numer -= denom) >= 0) {
118 result = 1;
119 } else {
120 numer += denom;
121 }
122
123 // Now fall into our switch statement if there are more bits to compute
124 if (bits > 0) {
125 // make room for the rest of the answer bits
126 result <<= bits;
127 switch (bits) {
128 case 6:
129 if ((numer = (numer << 1) - denom) >= 0)
130 result |= 32;
131 else
132 numer += denom;
133 case 5:
134 if ((numer = (numer << 1) - denom) >= 0)
135 result |= 16;
136 else
137 numer += denom;
138 case 4:
139 if ((numer = (numer << 1) - denom) >= 0)
140 result |= 8;
141 else
142 numer += denom;
143 case 3:
144 if ((numer = (numer << 1) - denom) >= 0)
145 result |= 4;
146 else
147 numer += denom;
148 case 2:
149 if ((numer = (numer << 1) - denom) >= 0)
150 result |= 2;
151 else
152 numer += denom;
153 case 1:
154 default: // not strictly need, but makes GCC make better ARM code
155 if ((numer = (numer << 1) - denom) >= 0)
156 result |= 1;
157 else
158 numer += denom;
159 }
160 }
161 return result;
162}
163#endif
164
165// Given x,y in the first quadrant, return 0..63 for the angle [0..90]
166#ifndef SK_SCALAR_IS_FLOAT
167static unsigned atan_0_90(SkFixed y, SkFixed x) {
168#ifdef SK_DEBUG
169 {
170 static bool gOnce;
171 if (!gOnce) {
172 gOnce = true;
173 SkASSERT(div_64(55, 55) == 64);
174 SkASSERT(div_64(128, 256) == 32);
175 SkASSERT(div_64(2326528, 4685824) == 31);
176 SkASSERT(div_64(753664, 5210112) == 9);
177 SkASSERT(div_64(229376, 4882432) == 3);
178 SkASSERT(div_64(2, 64) == 2);
179 SkASSERT(div_64(1, 64) == 1);
180 // test that we handle underflow correctly
181 SkASSERT(div_64(12345, 0x54321234) == 0);
182 }
183 }
184#endif
185
186 SkASSERT(y > 0 && x > 0);
187 const uint8_t* table = build_sweep_table();
188
189 unsigned result;
190 bool swap = (x < y);
191 if (swap) {
192 // first part of the atan(v) = PI/2 - atan(1/v) identity
193 // since our div_64 and table want v <= 1, where v = y/x
194 SkTSwap<SkFixed>(x, y);
195 }
196
197 result = div_64(y, x);
198
199#ifdef SK_DEBUG
200 {
201 unsigned result2 = SkDivBits(y, x, 6);
202 SkASSERT(result2 == result ||
203 (result == 1 && result2 == 0));
204 }
205#endif
206
207 SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
208 result = table[result];
209
210 if (swap) {
211 // complete the atan(v) = PI/2 - atan(1/v) identity
212 result = 64 - result;
213 // pin to 63
214 result -= result >> 6;
215 }
216
217 SkASSERT(result <= 63);
218 return result;
219}
220#endif
221
222// returns angle in a circle [0..2PI) -> [0..255]
223#ifdef SK_SCALAR_IS_FLOAT
224static unsigned SkATan2_255(float y, float x) {
225 // static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
226 static const float g255Over2PI = 40.584510488433314f;
227
228 float result = sk_float_atan2(y, x);
229 if (result < 0) {
230 result += 2 * SK_ScalarPI;
231 }
232 SkASSERT(result >= 0);
233 // since our value is always >= 0, we can cast to int, which is faster than
234 // calling floorf()
235 int ir = (int)(result * g255Over2PI);
236 SkASSERT(ir >= 0 && ir <= 255);
237 return ir;
238}
239#else
240static unsigned SkATan2_255(SkFixed y, SkFixed x) {
241 if (x == 0) {
242 if (y == 0) {
243 return 0;
244 }
245 return y < 0 ? 192 : 64;
246 }
247 if (y == 0) {
248 return x < 0 ? 128 : 0;
249 }
250
251 /* Find the right quadrant for x,y
252 Since atan_0_90 only handles the first quadrant, we rotate x,y
253 appropriately before calling it, and then add the right amount
254 to account for the real quadrant.
255 quadrant 0 : add 0 | x > 0 && y > 0
256 quadrant 1 : add 64 (90 degrees) | x < 0 && y > 0
257 quadrant 2 : add 128 (180 degrees) | x < 0 && y < 0
258 quadrant 3 : add 192 (270 degrees) | x > 0 && y < 0
259
260 map x<0 to (1 << 6)
261 map y<0 to (3 << 6)
262 add = map_x ^ map_y
263 */
264 int xsign = x >> 31;
265 int ysign = y >> 31;
266 int add = ((-xsign) ^ (ysign & 3)) << 6;
267
268#ifdef SK_DEBUG
269 if (0 == add)
270 SkASSERT(x > 0 && y > 0);
271 else if (64 == add)
272 SkASSERT(x < 0 && y > 0);
273 else if (128 == add)
274 SkASSERT(x < 0 && y < 0);
275 else if (192 == add)
276 SkASSERT(x > 0 && y < 0);
277 else
278 SkDEBUGFAIL("bad value for add");
279#endif
280
281 /* This ^ trick makes x, y positive, and the swap<> handles quadrants
282 where we need to rotate x,y by 90 or -90
283 */
284 x = (x ^ xsign) - xsign;
285 y = (y ^ ysign) - ysign;
286 if (add & 64) { // quads 1 or 3 need to swap x,y
287 SkTSwap<SkFixed>(x, y);
288 }
289
290 unsigned result = add + atan_0_90(y, x);
291 SkASSERT(result < 256);
292 return result;
293}
294#endif
295
296void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
297 int count) {
298 SkMatrix::MapXYProc proc = fDstToIndexProc;
299 const SkMatrix& matrix = fDstToIndex;
300 const SkPMColor* SK_RESTRICT cache = this->getCache32();
301 SkPoint srcPt;
302
303 if (fDstToIndexClass != kPerspective_MatrixClass) {
304 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
305 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
306 SkScalar dx, fx = srcPt.fX;
307 SkScalar dy, fy = srcPt.fY;
308
309 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
310 SkFixed storage[2];
311 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
312 &storage[0], &storage[1]);
313 dx = SkFixedToScalar(storage[0]);
314 dy = SkFixedToScalar(storage[1]);
315 } else {
316 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
317 dx = matrix.getScaleX();
318 dy = matrix.getSkewY();
319 }
320
321 for (; count > 0; --count) {
322 *dstC++ = cache[SkATan2_255(fy, fx)];
323 fx += dx;
324 fy += dy;
325 }
326 } else { // perspective case
327 for (int stop = x + count; x < stop; x++) {
328 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
329 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
330 *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
331 }
332 }
333}
334
335void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
336 int count) {
337 SkMatrix::MapXYProc proc = fDstToIndexProc;
338 const SkMatrix& matrix = fDstToIndex;
339 const uint16_t* SK_RESTRICT cache = this->getCache16();
340 int toggle = ((x ^ y) & 1) * kDitherStride16;
341 SkPoint srcPt;
342
343 if (fDstToIndexClass != kPerspective_MatrixClass) {
344 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
345 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
346 SkScalar dx, fx = srcPt.fX;
347 SkScalar dy, fy = srcPt.fY;
348
349 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
350 SkFixed storage[2];
351 (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
352 &storage[0], &storage[1]);
353 dx = SkFixedToScalar(storage[0]);
354 dy = SkFixedToScalar(storage[1]);
355 } else {
356 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
357 dx = matrix.getScaleX();
358 dy = matrix.getSkewY();
359 }
360
361 for (; count > 0; --count) {
362 int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
363 *dstC++ = cache[toggle + index];
364 toggle ^= kDitherStride16;
365 fx += dx;
366 fy += dy;
367 }
368 } else { // perspective case
369 for (int stop = x + count; x < stop; x++) {
370 proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
371 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
372
373 int index = SkATan2_255(srcPt.fY, srcPt.fX);
374 index >>= (8 - kCache16Bits);
375 *dstC++ = cache[toggle + index];
376 toggle ^= kDitherStride16;
377 }
378 }
379}
380
rileya@google.comd7cc6512012-07-27 14:00:39 +0000381/////////////////////////////////////////////////////////////////////
382
383class GrGLSweepGradient : public GrGLGradientStage {
rileya@google.comd7cc6512012-07-27 14:00:39 +0000384public:
385
386 GrGLSweepGradient(const GrProgramStageFactory& factory,
387 const GrCustomStage&) : INHERITED (factory) { }
388 virtual ~GrGLSweepGradient() { }
389
390 virtual void emitVS(GrGLShaderBuilder* builder,
391 const char* vertexCoords) SK_OVERRIDE { }
392 virtual void emitFS(GrGLShaderBuilder* builder,
393 const char* outputColor,
394 const char* inputColor,
395 const char* samplerName) SK_OVERRIDE;
396
397 static StageKey GenKey(const GrCustomStage& s) { return 0; }
398
399private:
400
401 typedef GrGLGradientStage INHERITED;
402
403};
404
rileya@google.com98e8b6d2012-07-31 20:38:06 +0000405/////////////////////////////////////////////////////////////////////
406
407class GrSweepGradient : public GrGradientEffect {
408public:
409
410 GrSweepGradient(GrContext* ctx,
411 const SkSweepGradient& shader,
412 GrSamplerState* sampler)
413 : INHERITED(ctx, shader, sampler) { }
414 virtual ~GrSweepGradient() { }
415
416 static const char* Name() { return "Sweep Gradient"; }
417 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE {
418 return GrTProgramStageFactory<GrSweepGradient>::getInstance();
419 }
420
421 typedef GrGLSweepGradient GLProgramStage;
422
423protected:
424
425 typedef GrGradientEffect INHERITED;
426};
427
428/////////////////////////////////////////////////////////////////////
429
rileya@google.comd7cc6512012-07-27 14:00:39 +0000430void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
431 const char* outputColor,
432 const char* inputColor,
433 const char* samplerName) {
434 SkString t;
435 t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
436 builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str());
437 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
438}
439
440/////////////////////////////////////////////////////////////////////
441
rileya@google.com98e8b6d2012-07-31 20:38:06 +0000442GrCustomStage* SkSweepGradient::asNewCustomStage(GrContext* context,
443 GrSamplerState* sampler) const {
444 sampler->matrix()->preConcat(fPtsToUnit);
445 sampler->textureParams()->setTileModeX(fTileMode);
446 sampler->textureParams()->setTileModeY(kClamp_TileMode);
447 sampler->textureParams()->setBilerp(true);
448 return SkNEW_ARGS(GrSweepGradient, (context, *this, sampler));
rileya@google.comd7cc6512012-07-27 14:00:39 +0000449}
450