michael@0: michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkRadialGradient.h" michael@0: #include "SkRadialGradient_Table.h" michael@0: michael@0: #define kSQRT_TABLE_BITS 11 michael@0: #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) michael@0: michael@0: #if 0 michael@0: michael@0: #include michael@0: michael@0: void SkRadialGradient_BuildTable() { michael@0: // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table michael@0: michael@0: FILE* file = ::fopen("SkRadialGradient_Table.h", "w"); michael@0: SkASSERT(file); michael@0: ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n"); michael@0: michael@0: for (int i = 0; i < kSQRT_TABLE_SIZE; i++) { michael@0: if ((i & 15) == 0) { michael@0: ::fprintf(file, "\t"); michael@0: } michael@0: michael@0: uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8); michael@0: michael@0: ::fprintf(file, "0x%02X", value); michael@0: if (i < kSQRT_TABLE_SIZE-1) { michael@0: ::fprintf(file, ", "); michael@0: } michael@0: if ((i & 15) == 15) { michael@0: ::fprintf(file, "\n"); michael@0: } michael@0: } michael@0: ::fprintf(file, "};\n"); michael@0: ::fclose(file); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: namespace { michael@0: michael@0: // GCC doesn't like using static functions as template arguments. So force these to be non-static. michael@0: inline SkFixed mirror_tileproc_nonstatic(SkFixed x) { michael@0: return mirror_tileproc(x); michael@0: } michael@0: michael@0: inline SkFixed repeat_tileproc_nonstatic(SkFixed x) { michael@0: return repeat_tileproc(x); michael@0: } michael@0: michael@0: void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, michael@0: SkMatrix* matrix) { michael@0: SkScalar inv = SkScalarInvert(radius); michael@0: michael@0: matrix->setTranslate(-center.fX, -center.fY); michael@0: matrix->postScale(inv, inv); michael@0: } michael@0: michael@0: typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx, michael@0: SkScalar sfy, SkScalar sdy, michael@0: uint16_t* dstC, const uint16_t* cache, michael@0: int toggle, int count); michael@0: michael@0: void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx, michael@0: SkScalar sfy, SkScalar sdy, michael@0: uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; michael@0: michael@0: /* knock these down so we can pin against +- 0x7FFF, which is an michael@0: immediate load, rather than 0xFFFF which is slower. This is a michael@0: compromise, since it reduces our precision, but that appears michael@0: to be visually OK. If we decide this is OK for all of our cases, michael@0: we could (it seems) put this scale-down into fDstToIndex, michael@0: to avoid having to do these extra shifts each time. michael@0: */ michael@0: SkFixed fx = SkScalarToFixed(sfx) >> 1; michael@0: SkFixed dx = SkScalarToFixed(sdx) >> 1; michael@0: SkFixed fy = SkScalarToFixed(sfy) >> 1; michael@0: SkFixed dy = SkScalarToFixed(sdy) >> 1; michael@0: // might perform this check for the other modes, michael@0: // but the win will be a smaller % of the total michael@0: if (dy == 0) { michael@0: fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: fy *= fy; michael@0: do { michael@0: unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS); michael@0: fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); michael@0: fx += dx; michael@0: *dstC++ = cache[toggle + michael@0: (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; michael@0: toggle = next_dither_toggle16(toggle); michael@0: } while (--count != 0); michael@0: } else { michael@0: do { michael@0: unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); michael@0: fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); michael@0: fx += dx; michael@0: fy += dy; michael@0: *dstC++ = cache[toggle + michael@0: (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; michael@0: toggle = next_dither_toggle16(toggle); michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: michael@0: template michael@0: void shadeSpan16_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: do { michael@0: const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); michael@0: const unsigned fi = TileProc(dist); michael@0: SkASSERT(fi <= 0xFFFF); michael@0: *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)]; michael@0: toggle = next_dither_toggle16(toggle); michael@0: fx += dx; michael@0: fy += dy; michael@0: } while (--count != 0); michael@0: } michael@0: michael@0: void shadeSpan16_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: shadeSpan16_radial(fx, dx, fy, dy, dstC, cache, toggle, count); michael@0: } michael@0: michael@0: void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: shadeSpan16_radial(fx, dx, fy, dy, dstC, cache, toggle, count); michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, michael@0: const Descriptor& desc) michael@0: : SkGradientShaderBase(desc), michael@0: fCenter(center), michael@0: fRadius(radius) michael@0: { michael@0: // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE michael@0: SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE); michael@0: michael@0: rad_to_unit_matrix(center, radius, &fPtsToUnit); michael@0: } michael@0: michael@0: void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam, michael@0: int count) { michael@0: SkASSERT(count > 0); michael@0: michael@0: uint16_t* SK_RESTRICT dstC = dstCParam; michael@0: michael@0: SkPoint srcPt; michael@0: SkMatrix::MapXYProc dstProc = fDstToIndexProc; michael@0: TileProc proc = fTileProc; michael@0: const uint16_t* SK_RESTRICT cache = this->getCache16(); michael@0: int toggle = init_dither_toggle16(x, y); michael@0: michael@0: if (fDstToIndexClass != kPerspective_MatrixClass) { michael@0: dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &srcPt); michael@0: michael@0: SkScalar sdx = fDstToIndex.getScaleX(); michael@0: SkScalar sdy = fDstToIndex.getSkewY(); michael@0: michael@0: if (fDstToIndexClass == kFixedStepInX_MatrixClass) { michael@0: SkFixed storage[2]; michael@0: (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), michael@0: &storage[0], &storage[1]); michael@0: sdx = SkFixedToScalar(storage[0]); michael@0: sdy = SkFixedToScalar(storage[1]); michael@0: } else { michael@0: SkASSERT(fDstToIndexClass == kLinear_MatrixClass); michael@0: } michael@0: michael@0: RadialShade16Proc shadeProc = shadeSpan16_radial_repeat; michael@0: if (SkShader::kClamp_TileMode == fTileMode) { michael@0: shadeProc = shadeSpan16_radial_clamp; michael@0: } else if (SkShader::kMirror_TileMode == fTileMode) { michael@0: shadeProc = shadeSpan16_radial_mirror; michael@0: } else { michael@0: SkASSERT(SkShader::kRepeat_TileMode == fTileMode); michael@0: } michael@0: (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, michael@0: cache, toggle, count); michael@0: } else { // perspective case michael@0: SkScalar dstX = SkIntToScalar(x); michael@0: SkScalar dstY = SkIntToScalar(y); michael@0: do { michael@0: dstProc(fDstToIndex, dstX, dstY, &srcPt); michael@0: unsigned fi = proc(SkScalarToFixed(srcPt.length())); michael@0: SkASSERT(fi <= 0xFFFF); michael@0: michael@0: int index = fi >> (16 - kCache16Bits); michael@0: *dstC++ = cache[toggle + index]; michael@0: toggle = next_dither_toggle16(toggle); michael@0: michael@0: dstX += SK_Scalar1; michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: michael@0: SkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap, michael@0: SkMatrix* matrix, SkShader::TileMode* xy) const { michael@0: if (bitmap) { michael@0: this->getGradientTableBitmap(bitmap); michael@0: } michael@0: if (matrix) { michael@0: matrix->setScale(SkIntToScalar(kCache32Count), michael@0: SkIntToScalar(kCache32Count)); michael@0: matrix->preConcat(fPtsToUnit); michael@0: } michael@0: if (xy) { michael@0: xy[0] = fTileMode; michael@0: xy[1] = kClamp_TileMode; michael@0: } michael@0: return kRadial_BitmapType; michael@0: } michael@0: michael@0: SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const { michael@0: if (info) { michael@0: commonAsAGradient(info); michael@0: info->fPoint[0] = fCenter; michael@0: info->fRadius[0] = fRadius; michael@0: } michael@0: return kRadial_GradientType; michael@0: } michael@0: michael@0: SkRadialGradient::SkRadialGradient(SkReadBuffer& buffer) michael@0: : INHERITED(buffer), michael@0: fCenter(buffer.readPoint()), michael@0: fRadius(buffer.readScalar()) { michael@0: } michael@0: michael@0: void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { michael@0: this->INHERITED::flatten(buffer); michael@0: buffer.writePoint(fCenter); michael@0: buffer.writeScalar(fRadius); michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { michael@0: // fast, overly-conservative test: checks unit square instead michael@0: // of unit circle michael@0: bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || michael@0: (fx <= -SK_FixedHalf && dx <= 0); michael@0: bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || michael@0: (fy <= -SK_FixedHalf && dy <= 0); michael@0: michael@0: return xClamped || yClamped; michael@0: } michael@0: michael@0: // Return true if (fx * fy) is always inside the unit circle michael@0: // SkPin32 is expensive, but so are all the SkFixedMul in this test, michael@0: // so it shouldn't be run if count is small. michael@0: inline bool no_need_for_radial_pin(int fx, int dx, michael@0: int fy, int dy, int count) { michael@0: SkASSERT(count > 0); michael@0: if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { michael@0: return false; michael@0: } michael@0: if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { michael@0: return false; michael@0: } michael@0: fx += (count - 1) * dx; michael@0: fy += (count - 1) * dy; michael@0: if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { michael@0: return false; michael@0: } michael@0: return fx*fx + fy*fy <= 0x7FFF*0x7FFF; michael@0: } michael@0: michael@0: #define UNPINNED_RADIAL_STEP \ michael@0: fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \ michael@0: *dstC++ = cache[toggle + \ michael@0: (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \ michael@0: toggle = next_dither_toggle(toggle); \ michael@0: fx += dx; \ michael@0: fy += dy; michael@0: michael@0: typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx, michael@0: SkScalar sfy, SkScalar sdy, michael@0: SkPMColor* dstC, const SkPMColor* cache, michael@0: int count, int toggle); michael@0: michael@0: // On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT michael@0: void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx, michael@0: SkScalar sfy, SkScalar sdy, michael@0: SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, michael@0: int count, int toggle) { michael@0: // Floating point seems to be slower than fixed point, michael@0: // even when we have float hardware. michael@0: const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; michael@0: SkFixed fx = SkScalarToFixed(sfx) >> 1; michael@0: SkFixed dx = SkScalarToFixed(sdx) >> 1; michael@0: SkFixed fy = SkScalarToFixed(sfy) >> 1; michael@0: SkFixed dy = SkScalarToFixed(sdy) >> 1; michael@0: if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) { michael@0: unsigned fi = SkGradientShaderBase::kCache32Count - 1; michael@0: sk_memset32_dither(dstC, michael@0: cache[toggle + fi], michael@0: cache[next_dither_toggle(toggle) + fi], michael@0: count); michael@0: } else if ((count > 4) && michael@0: no_need_for_radial_pin(fx, dx, fy, dy, count)) { michael@0: unsigned fi; michael@0: // 4x unroll appears to be no faster than 2x unroll on Linux michael@0: while (count > 1) { michael@0: UNPINNED_RADIAL_STEP; michael@0: UNPINNED_RADIAL_STEP; michael@0: count -= 2; michael@0: } michael@0: if (count) { michael@0: UNPINNED_RADIAL_STEP; michael@0: } michael@0: } else { michael@0: // Specializing for dy == 0 gains us 25% on Skia benchmarks michael@0: if (dy == 0) { michael@0: unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: yy *= yy; michael@0: do { michael@0: unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS); michael@0: fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); michael@0: *dstC++ = cache[toggle + (sqrt_table[fi] >> michael@0: SkGradientShaderBase::kSqrt32Shift)]; michael@0: toggle = next_dither_toggle(toggle); michael@0: fx += dx; michael@0: } while (--count != 0); michael@0: } else { michael@0: do { michael@0: unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); michael@0: fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); michael@0: fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); michael@0: *dstC++ = cache[toggle + (sqrt_table[fi] >> michael@0: SkGradientShaderBase::kSqrt32Shift)]; michael@0: toggle = next_dither_toggle(toggle); michael@0: fx += dx; michael@0: fy += dy; michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Unrolling this loop doesn't seem to help (when float); we're stalling to michael@0: // get the results of the sqrt (?), and don't have enough extra registers to michael@0: // have many in flight. michael@0: template michael@0: void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, michael@0: int count, int toggle) { michael@0: do { michael@0: const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); michael@0: const unsigned fi = TileProc(dist); michael@0: SkASSERT(fi <= 0xFFFF); michael@0: *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)]; michael@0: toggle = next_dither_toggle(toggle); michael@0: fx += dx; michael@0: fy += dy; michael@0: } while (--count != 0); michael@0: } michael@0: michael@0: void shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, michael@0: int count, int toggle) { michael@0: shadeSpan_radial(fx, dx, fy, dy, dstC, cache, count, toggle); michael@0: } michael@0: michael@0: void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, michael@0: SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, michael@0: int count, int toggle) { michael@0: shadeSpan_radial(fx, dx, fy, dy, dstC, cache, count, toggle); michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: void SkRadialGradient::shadeSpan(int x, int y, michael@0: SkPMColor* SK_RESTRICT dstC, int count) { michael@0: SkASSERT(count > 0); michael@0: michael@0: SkPoint srcPt; michael@0: SkMatrix::MapXYProc dstProc = fDstToIndexProc; michael@0: TileProc proc = fTileProc; michael@0: const SkPMColor* SK_RESTRICT cache = this->getCache32(); michael@0: int toggle = init_dither_toggle(x, y); michael@0: michael@0: if (fDstToIndexClass != kPerspective_MatrixClass) { michael@0: dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &srcPt); michael@0: SkScalar sdx = fDstToIndex.getScaleX(); michael@0: SkScalar sdy = fDstToIndex.getSkewY(); michael@0: michael@0: if (fDstToIndexClass == kFixedStepInX_MatrixClass) { michael@0: SkFixed storage[2]; michael@0: (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), michael@0: &storage[0], &storage[1]); michael@0: sdx = SkFixedToScalar(storage[0]); michael@0: sdy = SkFixedToScalar(storage[1]); michael@0: } else { michael@0: SkASSERT(fDstToIndexClass == kLinear_MatrixClass); michael@0: } michael@0: michael@0: RadialShadeProc shadeProc = shadeSpan_radial_repeat; michael@0: if (SkShader::kClamp_TileMode == fTileMode) { michael@0: shadeProc = shadeSpan_radial_clamp; michael@0: } else if (SkShader::kMirror_TileMode == fTileMode) { michael@0: shadeProc = shadeSpan_radial_mirror; michael@0: } else { michael@0: SkASSERT(SkShader::kRepeat_TileMode == fTileMode); michael@0: } michael@0: (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); michael@0: } else { // perspective case michael@0: SkScalar dstX = SkIntToScalar(x); michael@0: SkScalar dstY = SkIntToScalar(y); michael@0: do { michael@0: dstProc(fDstToIndex, dstX, dstY, &srcPt); michael@0: unsigned fi = proc(SkScalarToFixed(srcPt.length())); michael@0: SkASSERT(fi <= 0xFFFF); michael@0: *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift]; michael@0: dstX += SK_Scalar1; michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: #if SK_SUPPORT_GPU michael@0: michael@0: #include "GrTBackendEffectFactory.h" michael@0: michael@0: class GrGLRadialGradient : public GrGLGradientEffect { michael@0: public: michael@0: michael@0: GrGLRadialGradient(const GrBackendEffectFactory& factory, michael@0: const GrDrawEffect&) : INHERITED (factory) { } michael@0: virtual ~GrGLRadialGradient() { } michael@0: michael@0: virtual void emitCode(GrGLShaderBuilder*, michael@0: const GrDrawEffect&, michael@0: EffectKey, michael@0: const char* outputColor, michael@0: const char* inputColor, michael@0: const TransformedCoordsArray&, michael@0: const TextureSamplerArray&) SK_OVERRIDE; michael@0: michael@0: static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { michael@0: return GenBaseGradientKey(drawEffect); michael@0: } michael@0: michael@0: private: michael@0: michael@0: typedef GrGLGradientEffect INHERITED; michael@0: michael@0: }; michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: class GrRadialGradient : public GrGradientEffect { michael@0: public: michael@0: static GrEffectRef* Create(GrContext* ctx, michael@0: const SkRadialGradient& shader, michael@0: const SkMatrix& matrix, michael@0: SkShader::TileMode tm) { michael@0: AutoEffectUnref effect(SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm))); michael@0: return CreateEffectRef(effect); michael@0: } michael@0: michael@0: virtual ~GrRadialGradient() { } michael@0: michael@0: static const char* Name() { return "Radial Gradient"; } michael@0: virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { michael@0: return GrTBackendEffectFactory::getInstance(); michael@0: } michael@0: michael@0: typedef GrGLRadialGradient GLEffect; michael@0: michael@0: private: michael@0: GrRadialGradient(GrContext* ctx, michael@0: const SkRadialGradient& shader, michael@0: const SkMatrix& matrix, michael@0: SkShader::TileMode tm) michael@0: : INHERITED(ctx, shader, matrix, tm) { michael@0: } michael@0: michael@0: GR_DECLARE_EFFECT_TEST; michael@0: michael@0: typedef GrGradientEffect INHERITED; michael@0: }; michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: GR_DEFINE_EFFECT_TEST(GrRadialGradient); michael@0: michael@0: GrEffectRef* GrRadialGradient::TestCreate(SkRandom* random, michael@0: GrContext* context, michael@0: const GrDrawTargetCaps&, michael@0: GrTexture**) { michael@0: SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; michael@0: SkScalar radius = random->nextUScalar1(); michael@0: michael@0: SkColor colors[kMaxRandomGradientColors]; michael@0: SkScalar stopsArray[kMaxRandomGradientColors]; michael@0: SkScalar* stops = stopsArray; michael@0: SkShader::TileMode tm; michael@0: int colorCount = RandomGradientParams(random, colors, &stops, &tm); michael@0: SkAutoTUnref shader(SkGradientShader::CreateRadial(center, radius, michael@0: colors, stops, colorCount, michael@0: tm)); michael@0: SkPaint paint; michael@0: return shader->asNewEffect(context, paint); michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder, michael@0: const GrDrawEffect&, michael@0: EffectKey key, michael@0: const char* outputColor, michael@0: const char* inputColor, michael@0: const TransformedCoordsArray& coords, michael@0: const TextureSamplerArray& samplers) { michael@0: this->emitUniforms(builder, key); michael@0: SkString t("length("); michael@0: t.append(builder->ensureFSCoords2D(coords, 0)); michael@0: t.append(")"); michael@0: this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////////// michael@0: michael@0: GrEffectRef* SkRadialGradient::asNewEffect(GrContext* context, const SkPaint&) const { michael@0: SkASSERT(NULL != context); michael@0: michael@0: SkMatrix matrix; michael@0: if (!this->getLocalMatrix().invert(&matrix)) { michael@0: return NULL; michael@0: } michael@0: matrix.postConcat(fPtsToUnit); michael@0: return GrRadialGradient::Create(context, *this, matrix, fTileMode); michael@0: } michael@0: michael@0: #else michael@0: michael@0: GrEffectRef* SkRadialGradient::asNewEffect(GrContext*, const SkPaint&) const { michael@0: SkDEBUGFAIL("Should not call in GPU-less build"); michael@0: return NULL; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: #ifndef SK_IGNORE_TO_STRING michael@0: void SkRadialGradient::toString(SkString* str) const { michael@0: str->append("SkRadialGradient: ("); michael@0: michael@0: str->append("center: ("); michael@0: str->appendScalar(fCenter.fX); michael@0: str->append(", "); michael@0: str->appendScalar(fCenter.fY); michael@0: str->append(") radius: "); michael@0: str->appendScalar(fRadius); michael@0: str->append(" "); michael@0: michael@0: this->INHERITED::toString(str); michael@0: michael@0: str->append(")"); michael@0: } michael@0: #endif