blob: 3f498b332d3083ab7d3f5594bdb554450b9fd9a5 [file] [log] [blame]
tomhudson@google.com7fab52d2012-05-31 19:40:13 +00001/*
2 * Copyright 2012 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 "GrGradientEffects.h"
9#include "gl/GrGLProgramStage.h"
10#include "GrProgramStageFactory.h"
11
12/////////////////////////////////////////////////////////////////////
13
14class GrGLRadialGradient : public GrGLProgramStage {
15
16public:
17
18 GrGLRadialGradient(const GrProgramStageFactory& factory,
19 const GrCustomStage&) : INHERITED (factory) { }
20 virtual ~GrGLRadialGradient() { }
21
22 virtual void emitVS(GrGLShaderBuilder* state,
23 const char* vertexCoords) SK_OVERRIDE { }
24 virtual void emitFS(GrGLShaderBuilder* state,
25 const char* outputColor,
26 const char* inputColor,
27 const char* samplerName) SK_OVERRIDE;
28
29 static StageKey GenKey(const GrCustomStage& s) { return 0; }
30
31private:
32
33 typedef GrGLProgramStage INHERITED;
34
35};
36
37void GrGLRadialGradient::emitFS(GrGLShaderBuilder* state,
38 const char* outputColor,
39 const char* inputColor,
40 const char* samplerName) {
41 state->fSampleCoords.printf("vec2(length(%s.xy), 0.5)",
42 state->fSampleCoords.c_str());
43 state->fComplexCoord = true;
44
45 state->emitDefaultFetch(outputColor, samplerName);
46}
47
48
49/////////////////////////////////////////////////////////////////////
50
51
52GrRadialGradient::GrRadialGradient() {
53
54}
55
56GrRadialGradient::~GrRadialGradient() {
57
58}
59
60
61const GrProgramStageFactory& GrRadialGradient::getFactory() const {
62 return GrTProgramStageFactory<GrRadialGradient>::getInstance();
63}
64
65bool GrRadialGradient::isEqual(const GrCustomStage& sBase) const {
66 return true;
67}
68
69/////////////////////////////////////////////////////////////////////
70
71class GrGLRadial2Gradient : public GrGLProgramStage {
72
73public:
74
75 GrGLRadial2Gradient(const GrProgramStageFactory& factory,
76 const GrCustomStage&);
77 virtual ~GrGLRadial2Gradient() { }
78
79 virtual void setupVariables(GrGLShaderBuilder* state,
80 int stage) SK_OVERRIDE;
81 virtual void emitVS(GrGLShaderBuilder* state,
82 const char* vertexCoords) SK_OVERRIDE;
83 virtual void emitFS(GrGLShaderBuilder* state,
84 const char* outputColor,
85 const char* inputColor,
86 const char* samplerName) SK_OVERRIDE;
87 virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
88 virtual void setData(const GrGLInterface*,
89 const GrGLTexture&,
90 GrCustomStage*,
91 int stageNum) SK_OVERRIDE;
92
93 static StageKey GenKey(const GrCustomStage& s) {
94 return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
95 }
96
97protected:
98
99 const GrGLShaderVar* fParamVar;
100 GrGLint fParamLocation;
101
102 const char* fVSVaryingName;
103 const char* fFSVaryingName;
104
105 bool fIsDegenerate;
106
107 // @{
108 /// Values last uploaded as uniforms
109
110 GrScalar fCachedCenter;
111 GrScalar fCachedRadius;
112 SkBool8 fCachedPosRoot;
113
114 // @}
115
116private:
117
118 typedef GrGLProgramStage INHERITED;
119
120};
121
122GrGLRadial2Gradient::GrGLRadial2Gradient(
123 const GrProgramStageFactory& factory,
124 const GrCustomStage& baseData)
125 : INHERITED(factory)
126 , fParamVar(NULL)
127 , fVSVaryingName(NULL)
128 , fFSVaryingName(NULL)
129 , fCachedCenter(GR_ScalarMax)
130 , fCachedRadius(-GR_ScalarMax)
131 , fCachedPosRoot(0) {
132
133 const GrRadial2Gradient& data =
134 static_cast<const GrRadial2Gradient&>(baseData);
135 fIsDegenerate = data.isDegenerate();
136}
137
138void GrGLRadial2Gradient::setupVariables(GrGLShaderBuilder* state, int stage) {
139 fParamVar = &state->addUniform(
140 GrGLShaderBuilder::kBoth_VariableLifetime,
141 kFloat_GrSLType, "uRadial2Params", stage, 6);
142
143 fParamLocation = GrGLProgramStage::kUseUniform;
144
145 // For radial gradients without perspective we can pass the linear
146 // part of the quadratic as a varying.
147 if (state->fVaryingDims == state->fCoordDims) {
148 state->addVarying(kFloat_GrSLType, "Radial2BCoeff", stage,
149 &fVSVaryingName, &fFSVaryingName);
150 }
151}
152
153void GrGLRadial2Gradient::emitVS(GrGLShaderBuilder* state,
154 const char* vertexCoords) {
155 GrStringBuilder* code = &state->fVSCode;
156 GrStringBuilder p2;
157 GrStringBuilder p3;
158 fParamVar->appendArrayAccess(2, &p2);
159 fParamVar->appendArrayAccess(3, &p3);
160
161 // For radial gradients without perspective we can pass the linear
162 // part of the quadratic as a varying.
163 if (state->fVaryingDims == state->fCoordDims) {
164 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
165 code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
166 fVSVaryingName, p2.c_str(),
167 vertexCoords, p3.c_str());
168 }
169}
170
171void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* state,
172 const char* outputColor,
173 const char* inputColor,
174 const char* samplerName) {
175 GrStringBuilder* code = &state->fFSCode;
176 GrStringBuilder cName("c");
177 GrStringBuilder ac4Name("ac4");
178 GrStringBuilder rootName("root");
179 GrStringBuilder p0;
180 GrStringBuilder p1;
181 GrStringBuilder p2;
182 GrStringBuilder p3;
183 GrStringBuilder p4;
184 GrStringBuilder p5;
185 fParamVar->appendArrayAccess(0, &p0);
186 fParamVar->appendArrayAccess(1, &p1);
187 fParamVar->appendArrayAccess(2, &p2);
188 fParamVar->appendArrayAccess(3, &p3);
189 fParamVar->appendArrayAccess(4, &p4);
190 fParamVar->appendArrayAccess(5, &p5);
191
192 // If we we're able to interpolate the linear component,
193 // bVar is the varying; otherwise compute it
194 GrStringBuilder bVar;
195 if (state->fCoordDims == state->fVaryingDims) {
196 bVar = fFSVaryingName;
197 GrAssert(2 == state->fVaryingDims);
198 } else {
199 GrAssert(3 == state->fVaryingDims);
200 bVar = "b";
201 //bVar.appendS32(stageNum);
202 code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
203 bVar.c_str(), p2.c_str(),
204 state->fSampleCoords.c_str(), p3.c_str());
205 }
206
207 // c = (x^2)+(y^2) - params[4]
208 code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
209 cName.c_str(), state->fSampleCoords.c_str(),
210 state->fSampleCoords.c_str(),
211 p4.c_str());
212
213 // If we aren't degenerate, emit some extra code, and accept a slightly
214 // more complex coord.
215 if (fIsDegenerate) {
216
217 // ac4 = 4.0 * params[0] * c
218 code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
219 ac4Name.c_str(), p0.c_str(),
220 cName.c_str());
221
222 // root = sqrt(b^2-4ac)
223 // (abs to avoid exception due to fp precision)
224 code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
225 rootName.c_str(), bVar.c_str(), bVar.c_str(),
226 ac4Name.c_str());
227
228 // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
229 // y coord is 0.5 (texture is effectively 1D)
230 state->fSampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
231 bVar.c_str(), p5.c_str(),
232 rootName.c_str(), p1.c_str());
233 } else {
234 // x coord is: -c/b
235 // y coord is 0.5 (texture is effectively 1D)
236 state->fSampleCoords.printf("vec2((-%s / %s), 0.5)",
237 cName.c_str(), bVar.c_str());
238 }
239 state->fComplexCoord = true;
240
241 state->emitDefaultFetch(outputColor, samplerName);
242}
243
244void GrGLRadial2Gradient::initUniforms(const GrGLInterface* gl, int programID) {
245 GR_GL_CALL_RET(gl, fParamLocation,
246 GetUniformLocation(programID, fParamVar->getName().c_str()));
247}
248
249void GrGLRadial2Gradient::setData(const GrGLInterface* gl,
250 const GrGLTexture& texture,
251 GrCustomStage* baseData,
252 int stageNum) {
253 const GrRadial2Gradient* data =
254 static_cast<const GrRadial2Gradient*>(baseData);
255 GrAssert(data->isDegenerate() == fIsDegenerate);
256 GrScalar centerX1 = data->center();
257 GrScalar radius0 = data->radius();
258 if (fCachedCenter != centerX1 ||
259 fCachedRadius != radius0 ||
260 fCachedPosRoot != data->isPosRoot()) {
261
262 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
263
264 // When we're in the degenerate (linear) case, the second
265 // value will be INF but the program doesn't read it. (We
266 // use the same 6 uniforms even though we don't need them
267 // all in the linear case just to keep the code complexity
268 // down).
269 float values[6] = {
270 GrScalarToFloat(a),
271 1 / (2.f * GrScalarToFloat(a)),
272 GrScalarToFloat(centerX1),
273 GrScalarToFloat(radius0),
274 GrScalarToFloat(GrMul(radius0, radius0)),
275 data->isPosRoot() ? 1.f : -1.f
276 };
277
278 GR_GL_CALL(gl, Uniform1fv(fParamLocation, 6, values));
279 fCachedCenter = centerX1;
280 fCachedRadius = radius0;
281 fCachedPosRoot = data->isPosRoot();
282 }
283}
284
285
286/////////////////////////////////////////////////////////////////////
287
288GrRadial2Gradient::GrRadial2Gradient(GrScalar center,
289 GrScalar radius,
290 bool posRoot)
291 : fCenterX1 (center)
292 , fRadius0 (radius)
293 , fPosRoot (posRoot) {
294
295}
296
297GrRadial2Gradient::~GrRadial2Gradient() {
298
299}
300
301
302const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
303 return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
304}
305
306bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
307 const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
308 return (this->isDegenerate() == s.isDegenerate());
309}
310
311/////////////////////////////////////////////////////////////////////
312
313class GrGLSweepGradient : public GrGLProgramStage {
314
315public:
316
317 GrGLSweepGradient(const GrProgramStageFactory& factory,
318 const GrCustomStage&) : INHERITED (factory) { }
319 virtual ~GrGLSweepGradient() { }
320
321 virtual void emitVS(GrGLShaderBuilder* state,
322 const char* vertexCoords) SK_OVERRIDE { }
323 virtual void emitFS(GrGLShaderBuilder* state,
324 const char* outputColor,
325 const char* inputColor,
326 const char* samplerName) SK_OVERRIDE;
327
328 static StageKey GenKey(const GrCustomStage& s) { return 0; }
329
330private:
331
332 typedef GrGLProgramStage INHERITED;
333
334};
335
336void GrGLSweepGradient::emitFS(GrGLShaderBuilder* state,
337 const char* outputColor,
338 const char* inputColor,
339 const char* samplerName) {
340 state->fSampleCoords.printf(
341 "vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)",
342 state->fSampleCoords.c_str(), state->fSampleCoords.c_str());
343 state->fComplexCoord = true;
344
345 state->emitDefaultFetch(outputColor, samplerName);
346}
347
348/////////////////////////////////////////////////////////////////////
349
350GrSweepGradient::GrSweepGradient() {
351
352}
353
354GrSweepGradient::~GrSweepGradient() {
355
356}
357
358const GrProgramStageFactory& GrSweepGradient::getFactory() const {
359 return GrTProgramStageFactory<GrSweepGradient>::getInstance();
360}
361
362bool GrSweepGradient::isEqual(const GrCustomStage& sBase) const {
363 return true;
364}
365