1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/gradients/SkSweepGradient.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,302 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkSweepGradient.h" 1.13 + 1.14 +SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, 1.15 + const Descriptor& desc) 1.16 + : SkGradientShaderBase(desc) 1.17 + , fCenter(SkPoint::Make(cx, cy)) 1.18 +{ 1.19 + fPtsToUnit.setTranslate(-cx, -cy); 1.20 + 1.21 + // overwrite the tilemode to a canonical value (since sweep ignores it) 1.22 + fTileMode = SkShader::kClamp_TileMode; 1.23 +} 1.24 + 1.25 +SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap, 1.26 + SkMatrix* matrix, SkShader::TileMode* xy) const { 1.27 + if (bitmap) { 1.28 + this->getGradientTableBitmap(bitmap); 1.29 + } 1.30 + if (matrix) { 1.31 + *matrix = fPtsToUnit; 1.32 + } 1.33 + if (xy) { 1.34 + xy[0] = fTileMode; 1.35 + xy[1] = kClamp_TileMode; 1.36 + } 1.37 + return kSweep_BitmapType; 1.38 +} 1.39 + 1.40 +SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const { 1.41 + if (info) { 1.42 + commonAsAGradient(info); 1.43 + info->fPoint[0] = fCenter; 1.44 + } 1.45 + return kSweep_GradientType; 1.46 +} 1.47 + 1.48 +SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer) 1.49 + : INHERITED(buffer), 1.50 + fCenter(buffer.readPoint()) { 1.51 +} 1.52 + 1.53 +void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { 1.54 + this->INHERITED::flatten(buffer); 1.55 + buffer.writePoint(fCenter); 1.56 +} 1.57 + 1.58 +// returns angle in a circle [0..2PI) -> [0..255] 1.59 +static unsigned SkATan2_255(float y, float x) { 1.60 + // static const float g255Over2PI = 255 / (2 * SK_ScalarPI); 1.61 + static const float g255Over2PI = 40.584510488433314f; 1.62 + 1.63 + float result = sk_float_atan2(y, x); 1.64 + if (result < 0) { 1.65 + result += 2 * SK_ScalarPI; 1.66 + } 1.67 + SkASSERT(result >= 0); 1.68 + // since our value is always >= 0, we can cast to int, which is faster than 1.69 + // calling floorf() 1.70 + int ir = (int)(result * g255Over2PI); 1.71 + SkASSERT(ir >= 0 && ir <= 255); 1.72 + return ir; 1.73 +} 1.74 + 1.75 +void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 1.76 + int count) { 1.77 + SkMatrix::MapXYProc proc = fDstToIndexProc; 1.78 + const SkMatrix& matrix = fDstToIndex; 1.79 + const SkPMColor* SK_RESTRICT cache = this->getCache32(); 1.80 + int toggle = init_dither_toggle(x, y); 1.81 + SkPoint srcPt; 1.82 + 1.83 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.84 + proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 1.85 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.86 + SkScalar dx, fx = srcPt.fX; 1.87 + SkScalar dy, fy = srcPt.fY; 1.88 + 1.89 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.90 + SkFixed storage[2]; 1.91 + (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, 1.92 + &storage[0], &storage[1]); 1.93 + dx = SkFixedToScalar(storage[0]); 1.94 + dy = SkFixedToScalar(storage[1]); 1.95 + } else { 1.96 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.97 + dx = matrix.getScaleX(); 1.98 + dy = matrix.getSkewY(); 1.99 + } 1.100 + 1.101 + for (; count > 0; --count) { 1.102 + *dstC++ = cache[toggle + SkATan2_255(fy, fx)]; 1.103 + fx += dx; 1.104 + fy += dy; 1.105 + toggle = next_dither_toggle(toggle); 1.106 + } 1.107 + } else { // perspective case 1.108 + for (int stop = x + count; x < stop; x++) { 1.109 + proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 1.110 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.111 + *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)]; 1.112 + toggle = next_dither_toggle(toggle); 1.113 + } 1.114 + } 1.115 +} 1.116 + 1.117 +void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, 1.118 + int count) { 1.119 + SkMatrix::MapXYProc proc = fDstToIndexProc; 1.120 + const SkMatrix& matrix = fDstToIndex; 1.121 + const uint16_t* SK_RESTRICT cache = this->getCache16(); 1.122 + int toggle = init_dither_toggle16(x, y); 1.123 + SkPoint srcPt; 1.124 + 1.125 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.126 + proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 1.127 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.128 + SkScalar dx, fx = srcPt.fX; 1.129 + SkScalar dy, fy = srcPt.fY; 1.130 + 1.131 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.132 + SkFixed storage[2]; 1.133 + (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf, 1.134 + &storage[0], &storage[1]); 1.135 + dx = SkFixedToScalar(storage[0]); 1.136 + dy = SkFixedToScalar(storage[1]); 1.137 + } else { 1.138 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.139 + dx = matrix.getScaleX(); 1.140 + dy = matrix.getSkewY(); 1.141 + } 1.142 + 1.143 + for (; count > 0; --count) { 1.144 + int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits); 1.145 + *dstC++ = cache[toggle + index]; 1.146 + toggle = next_dither_toggle16(toggle); 1.147 + fx += dx; 1.148 + fy += dy; 1.149 + } 1.150 + } else { // perspective case 1.151 + for (int stop = x + count; x < stop; x++) { 1.152 + proc(matrix, SkIntToScalar(x) + SK_ScalarHalf, 1.153 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.154 + 1.155 + int index = SkATan2_255(srcPt.fY, srcPt.fX); 1.156 + index >>= (8 - kCache16Bits); 1.157 + *dstC++ = cache[toggle + index]; 1.158 + toggle = next_dither_toggle16(toggle); 1.159 + } 1.160 + } 1.161 +} 1.162 + 1.163 +///////////////////////////////////////////////////////////////////// 1.164 + 1.165 +#if SK_SUPPORT_GPU 1.166 + 1.167 +#include "GrTBackendEffectFactory.h" 1.168 + 1.169 +class GrGLSweepGradient : public GrGLGradientEffect { 1.170 +public: 1.171 + 1.172 + GrGLSweepGradient(const GrBackendEffectFactory& factory, 1.173 + const GrDrawEffect&) : INHERITED (factory) { } 1.174 + virtual ~GrGLSweepGradient() { } 1.175 + 1.176 + virtual void emitCode(GrGLShaderBuilder*, 1.177 + const GrDrawEffect&, 1.178 + EffectKey, 1.179 + const char* outputColor, 1.180 + const char* inputColor, 1.181 + const TransformedCoordsArray&, 1.182 + const TextureSamplerArray&) SK_OVERRIDE; 1.183 + 1.184 + static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 1.185 + return GenBaseGradientKey(drawEffect); 1.186 + } 1.187 + 1.188 +private: 1.189 + 1.190 + typedef GrGLGradientEffect INHERITED; 1.191 + 1.192 +}; 1.193 + 1.194 +///////////////////////////////////////////////////////////////////// 1.195 + 1.196 +class GrSweepGradient : public GrGradientEffect { 1.197 +public: 1.198 + static GrEffectRef* Create(GrContext* ctx, 1.199 + const SkSweepGradient& shader, 1.200 + const SkMatrix& matrix) { 1.201 + AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix))); 1.202 + return CreateEffectRef(effect); 1.203 + } 1.204 + virtual ~GrSweepGradient() { } 1.205 + 1.206 + static const char* Name() { return "Sweep Gradient"; } 1.207 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 1.208 + return GrTBackendEffectFactory<GrSweepGradient>::getInstance(); 1.209 + } 1.210 + 1.211 + typedef GrGLSweepGradient GLEffect; 1.212 + 1.213 +private: 1.214 + GrSweepGradient(GrContext* ctx, 1.215 + const SkSweepGradient& shader, 1.216 + const SkMatrix& matrix) 1.217 + : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { } 1.218 + GR_DECLARE_EFFECT_TEST; 1.219 + 1.220 + typedef GrGradientEffect INHERITED; 1.221 +}; 1.222 + 1.223 +///////////////////////////////////////////////////////////////////// 1.224 + 1.225 +GR_DEFINE_EFFECT_TEST(GrSweepGradient); 1.226 + 1.227 +GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random, 1.228 + GrContext* context, 1.229 + const GrDrawTargetCaps&, 1.230 + GrTexture**) { 1.231 + SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; 1.232 + 1.233 + SkColor colors[kMaxRandomGradientColors]; 1.234 + SkScalar stopsArray[kMaxRandomGradientColors]; 1.235 + SkScalar* stops = stopsArray; 1.236 + SkShader::TileMode tmIgnored; 1.237 + int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored); 1.238 + SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY, 1.239 + colors, stops, colorCount)); 1.240 + SkPaint paint; 1.241 + return shader->asNewEffect(context, paint); 1.242 +} 1.243 + 1.244 +///////////////////////////////////////////////////////////////////// 1.245 + 1.246 +void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder, 1.247 + const GrDrawEffect&, 1.248 + EffectKey key, 1.249 + const char* outputColor, 1.250 + const char* inputColor, 1.251 + const TransformedCoordsArray& coords, 1.252 + const TextureSamplerArray& samplers) { 1.253 + this->emitUniforms(builder, key); 1.254 + SkString coords2D = builder->ensureFSCoords2D(coords, 0); 1.255 + const GrGLContextInfo ctxInfo = builder->ctxInfo(); 1.256 + SkString t; 1.257 + // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] 1.258 + // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int 1.259 + // thus must us -1.0 * %s.x to work correctly 1.260 + if (kIntel_GrGLVendor != ctxInfo.vendor()){ 1.261 + t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", 1.262 + coords2D.c_str(), coords2D.c_str()); 1.263 + } else { 1.264 + t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5", 1.265 + coords2D.c_str(), coords2D.c_str()); 1.266 + } 1.267 + this->emitColor(builder, t.c_str(), key, 1.268 + outputColor, inputColor, samplers); 1.269 +} 1.270 + 1.271 +///////////////////////////////////////////////////////////////////// 1.272 + 1.273 +GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const { 1.274 + SkMatrix matrix; 1.275 + if (!this->getLocalMatrix().invert(&matrix)) { 1.276 + return NULL; 1.277 + } 1.278 + matrix.postConcat(fPtsToUnit); 1.279 + return GrSweepGradient::Create(context, *this, matrix); 1.280 +} 1.281 + 1.282 +#else 1.283 + 1.284 +GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const { 1.285 + SkDEBUGFAIL("Should not call in GPU-less build"); 1.286 + return NULL; 1.287 +} 1.288 + 1.289 +#endif 1.290 + 1.291 +#ifndef SK_IGNORE_TO_STRING 1.292 +void SkSweepGradient::toString(SkString* str) const { 1.293 + str->append("SkSweepGradient: ("); 1.294 + 1.295 + str->append("center: ("); 1.296 + str->appendScalar(fCenter.fX); 1.297 + str->append(", "); 1.298 + str->appendScalar(fCenter.fY); 1.299 + str->append(") "); 1.300 + 1.301 + this->INHERITED::toString(str); 1.302 + 1.303 + str->append(")"); 1.304 +} 1.305 +#endif