|
1 /* |
|
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 "GrAARectRenderer.h" |
|
9 #include "GrGpu.h" |
|
10 #include "gl/GrGLEffect.h" |
|
11 #include "gl/GrGLVertexEffect.h" |
|
12 #include "GrTBackendEffectFactory.h" |
|
13 #include "SkColorPriv.h" |
|
14 #include "effects/GrVertexEffect.h" |
|
15 |
|
16 /////////////////////////////////////////////////////////////////////////////// |
|
17 class GrGLAlignedRectEffect; |
|
18 |
|
19 // Axis Aligned special case |
|
20 class GrAlignedRectEffect : public GrVertexEffect { |
|
21 public: |
|
22 static GrEffectRef* Create() { |
|
23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ()); |
|
24 gAlignedRectEffect->ref(); |
|
25 return gAlignedRectEffect; |
|
26 } |
|
27 |
|
28 virtual ~GrAlignedRectEffect() {} |
|
29 |
|
30 static const char* Name() { return "AlignedRectEdge"; } |
|
31 |
|
32 virtual void getConstantColorComponents(GrColor* color, |
|
33 uint32_t* validFlags) const SK_OVERRIDE { |
|
34 *validFlags = 0; |
|
35 } |
|
36 |
|
37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
|
38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance(); |
|
39 } |
|
40 |
|
41 class GLEffect : public GrGLVertexEffect { |
|
42 public: |
|
43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
|
44 : INHERITED (factory) {} |
|
45 |
|
46 virtual void emitCode(GrGLFullShaderBuilder* builder, |
|
47 const GrDrawEffect& drawEffect, |
|
48 EffectKey key, |
|
49 const char* outputColor, |
|
50 const char* inputColor, |
|
51 const TransformedCoordsArray&, |
|
52 const TextureSamplerArray& samplers) SK_OVERRIDE { |
|
53 // setup the varying for the Axis aligned rect effect |
|
54 // xy -> interpolated offset |
|
55 // zw -> w/2+0.5, h/2+0.5 |
|
56 const char *vsRectName, *fsRectName; |
|
57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName); |
|
58 const SkString* attr0Name = |
|
59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
|
60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str()); |
|
61 |
|
62 // TODO: compute all these offsets, spans, and scales in the VS |
|
63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName); |
|
64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName); |
|
65 builder->fsCodeAppend("\tfloat outset = 0.5;\n"); |
|
66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects |
|
67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. |
|
68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n"); |
|
69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n"); |
|
70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum |
|
71 // value of coverage that is used. In other words it is the coverage that is |
|
72 // used in the interior of the rect after the ramp. |
|
73 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n"); |
|
74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n"); |
|
75 |
|
76 // Compute the coverage for the rect's width |
|
77 builder->fsCodeAppendf( |
|
78 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName, |
|
79 fsRectName); |
|
80 // Compute the coverage for the rect's height and merge with the width |
|
81 builder->fsCodeAppendf( |
|
82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n", |
|
83 fsRectName, fsRectName); |
|
84 |
|
85 |
|
86 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, |
|
87 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str()); |
|
88 } |
|
89 |
|
90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
|
91 return 0; |
|
92 } |
|
93 |
|
94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} |
|
95 |
|
96 private: |
|
97 typedef GrGLVertexEffect INHERITED; |
|
98 }; |
|
99 |
|
100 |
|
101 private: |
|
102 GrAlignedRectEffect() : GrVertexEffect() { |
|
103 this->addVertexAttrib(kVec4f_GrSLType); |
|
104 } |
|
105 |
|
106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } |
|
107 |
|
108 GR_DECLARE_EFFECT_TEST; |
|
109 |
|
110 typedef GrVertexEffect INHERITED; |
|
111 }; |
|
112 |
|
113 |
|
114 GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect); |
|
115 |
|
116 GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random, |
|
117 GrContext* context, |
|
118 const GrDrawTargetCaps&, |
|
119 GrTexture* textures[]) { |
|
120 return GrAlignedRectEffect::Create(); |
|
121 } |
|
122 |
|
123 /////////////////////////////////////////////////////////////////////////////// |
|
124 class GrGLRectEffect; |
|
125 |
|
126 /** |
|
127 * The output of this effect is a modulation of the input color and coverage |
|
128 * for an arbitrarily oriented rect. The rect is specified as: |
|
129 * Center of the rect |
|
130 * Unit vector point down the height of the rect |
|
131 * Half width + 0.5 |
|
132 * Half height + 0.5 |
|
133 * The center and vector are stored in a vec4 varying ("RectEdge") with the |
|
134 * center in the xy components and the vector in the zw components. |
|
135 * The munged width and height are stored in a vec2 varying ("WidthHeight") |
|
136 * with the width in x and the height in y. |
|
137 */ |
|
138 class GrRectEffect : public GrVertexEffect { |
|
139 public: |
|
140 static GrEffectRef* Create() { |
|
141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ()); |
|
142 gRectEffect->ref(); |
|
143 return gRectEffect; |
|
144 } |
|
145 |
|
146 virtual ~GrRectEffect() {} |
|
147 |
|
148 static const char* Name() { return "RectEdge"; } |
|
149 |
|
150 virtual void getConstantColorComponents(GrColor* color, |
|
151 uint32_t* validFlags) const SK_OVERRIDE { |
|
152 *validFlags = 0; |
|
153 } |
|
154 |
|
155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
|
156 return GrTBackendEffectFactory<GrRectEffect>::getInstance(); |
|
157 } |
|
158 |
|
159 class GLEffect : public GrGLVertexEffect { |
|
160 public: |
|
161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
|
162 : INHERITED (factory) {} |
|
163 |
|
164 virtual void emitCode(GrGLFullShaderBuilder* builder, |
|
165 const GrDrawEffect& drawEffect, |
|
166 EffectKey key, |
|
167 const char* outputColor, |
|
168 const char* inputColor, |
|
169 const TransformedCoordsArray&, |
|
170 const TextureSamplerArray& samplers) SK_OVERRIDE { |
|
171 // setup the varying for the center point and the unit vector |
|
172 // that points down the height of the rect |
|
173 const char *vsRectEdgeName, *fsRectEdgeName; |
|
174 builder->addVarying(kVec4f_GrSLType, "RectEdge", |
|
175 &vsRectEdgeName, &fsRectEdgeName); |
|
176 const SkString* attr0Name = |
|
177 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
|
178 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str()); |
|
179 |
|
180 // setup the varying for width/2+.5 and height/2+.5 |
|
181 const char *vsWidthHeightName, *fsWidthHeightName; |
|
182 builder->addVarying(kVec2f_GrSLType, "WidthHeight", |
|
183 &vsWidthHeightName, &fsWidthHeightName); |
|
184 const SkString* attr1Name = |
|
185 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]); |
|
186 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str()); |
|
187 |
|
188 // TODO: compute all these offsets, spans, and scales in the VS |
|
189 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName); |
|
190 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName); |
|
191 builder->fsCodeAppend("\tfloat outset = 0.5;\n"); |
|
192 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects |
|
193 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. |
|
194 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n"); |
|
195 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n"); |
|
196 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum |
|
197 // value of coverage that is used. In other words it is the coverage that is |
|
198 // used in the interior of the rect after the ramp. |
|
199 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n"); |
|
200 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n"); |
|
201 |
|
202 // Compute the coverage for the rect's width |
|
203 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n", |
|
204 builder->fragmentPosition(), fsRectEdgeName); |
|
205 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n", |
|
206 fsRectEdgeName, fsRectEdgeName); |
|
207 builder->fsCodeAppendf( |
|
208 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n", |
|
209 fsWidthHeightName); |
|
210 |
|
211 // Compute the coverage for the rect's height and merge with the width |
|
212 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n", |
|
213 fsRectEdgeName); |
|
214 builder->fsCodeAppendf( |
|
215 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n", |
|
216 fsWidthHeightName); |
|
217 |
|
218 |
|
219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, |
|
220 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str()); |
|
221 } |
|
222 |
|
223 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
|
224 return 0; |
|
225 } |
|
226 |
|
227 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} |
|
228 |
|
229 private: |
|
230 typedef GrGLVertexEffect INHERITED; |
|
231 }; |
|
232 |
|
233 |
|
234 private: |
|
235 GrRectEffect() : GrVertexEffect() { |
|
236 this->addVertexAttrib(kVec4f_GrSLType); |
|
237 this->addVertexAttrib(kVec2f_GrSLType); |
|
238 this->setWillReadFragmentPosition(); |
|
239 } |
|
240 |
|
241 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } |
|
242 |
|
243 GR_DECLARE_EFFECT_TEST; |
|
244 |
|
245 typedef GrVertexEffect INHERITED; |
|
246 }; |
|
247 |
|
248 |
|
249 GR_DEFINE_EFFECT_TEST(GrRectEffect); |
|
250 |
|
251 GrEffectRef* GrRectEffect::TestCreate(SkRandom* random, |
|
252 GrContext* context, |
|
253 const GrDrawTargetCaps&, |
|
254 GrTexture* textures[]) { |
|
255 return GrRectEffect::Create(); |
|
256 } |
|
257 |
|
258 /////////////////////////////////////////////////////////////////////////////// |
|
259 |
|
260 namespace { |
|
261 |
|
262 extern const GrVertexAttrib gAARectCoverageAttribs[] = { |
|
263 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, |
|
264 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding}, |
|
265 }; |
|
266 |
|
267 extern const GrVertexAttrib gAARectColorAttribs[] = { |
|
268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, |
|
269 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding}, |
|
270 }; |
|
271 |
|
272 static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) { |
|
273 if (useCoverage) { |
|
274 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs)); |
|
275 } else { |
|
276 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs)); |
|
277 } |
|
278 } |
|
279 |
|
280 static void set_inset_fan(GrPoint* pts, size_t stride, |
|
281 const SkRect& r, SkScalar dx, SkScalar dy) { |
|
282 pts->setRectFan(r.fLeft + dx, r.fTop + dy, |
|
283 r.fRight - dx, r.fBottom - dy, stride); |
|
284 } |
|
285 |
|
286 }; |
|
287 |
|
288 void GrAARectRenderer::reset() { |
|
289 SkSafeSetNull(fAAFillRectIndexBuffer); |
|
290 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer); |
|
291 SkSafeSetNull(fAABevelStrokeRectIndexBuffer); |
|
292 } |
|
293 |
|
294 static const uint16_t gFillAARectIdx[] = { |
|
295 0, 1, 5, 5, 4, 0, |
|
296 1, 2, 6, 6, 5, 1, |
|
297 2, 3, 7, 7, 6, 2, |
|
298 3, 0, 4, 4, 7, 3, |
|
299 4, 5, 6, 6, 7, 4, |
|
300 }; |
|
301 |
|
302 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx); |
|
303 static const int kVertsPerAAFillRect = 8; |
|
304 static const int kNumAAFillRectsInIndexBuffer = 256; |
|
305 |
|
306 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) { |
|
307 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect * |
|
308 sizeof(uint16_t) * |
|
309 kNumAAFillRectsInIndexBuffer; |
|
310 |
|
311 if (NULL == fAAFillRectIndexBuffer) { |
|
312 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false); |
|
313 if (NULL != fAAFillRectIndexBuffer) { |
|
314 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock(); |
|
315 bool useTempData = (NULL == data); |
|
316 if (useTempData) { |
|
317 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect); |
|
318 } |
|
319 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) { |
|
320 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around |
|
321 // the inner rect (for AA) and 2 for the inner rect. |
|
322 int baseIdx = i * kIndicesPerAAFillRect; |
|
323 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect); |
|
324 for (int j = 0; j < kIndicesPerAAFillRect; ++j) { |
|
325 data[baseIdx+j] = baseVert + gFillAARectIdx[j]; |
|
326 } |
|
327 } |
|
328 if (useTempData) { |
|
329 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) { |
|
330 GrCrash("Can't get AA Fill Rect indices into buffer!"); |
|
331 } |
|
332 SkDELETE_ARRAY(data); |
|
333 } else { |
|
334 fAAFillRectIndexBuffer->unlock(); |
|
335 } |
|
336 } |
|
337 } |
|
338 |
|
339 return fAAFillRectIndexBuffer; |
|
340 } |
|
341 |
|
342 static const uint16_t gMiterStrokeAARectIdx[] = { |
|
343 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, |
|
344 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, |
|
345 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, |
|
346 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, |
|
347 |
|
348 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, |
|
349 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, |
|
350 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, |
|
351 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, |
|
352 |
|
353 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, |
|
354 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, |
|
355 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, |
|
356 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, |
|
357 }; |
|
358 |
|
359 /** |
|
360 * As in miter-stroke, index = a + b, and a is the current index, b is the shift |
|
361 * from the first index. The index layout: |
|
362 * outer AA line: 0~3, 4~7 |
|
363 * outer edge: 8~11, 12~15 |
|
364 * inner edge: 16~19 |
|
365 * inner AA line: 20~23 |
|
366 * Following comes a bevel-stroke rect and its indices: |
|
367 * |
|
368 * 4 7 |
|
369 * ********************************* |
|
370 * * ______________________________ * |
|
371 * * / 12 15 \ * |
|
372 * * / \ * |
|
373 * 0 * |8 16_____________________19 11 | * 3 |
|
374 * * | | | | * |
|
375 * * | | **************** | | * |
|
376 * * | | * 20 23 * | | * |
|
377 * * | | * * | | * |
|
378 * * | | * 21 22 * | | * |
|
379 * * | | **************** | | * |
|
380 * * | |____________________| | * |
|
381 * 1 * |9 17 18 10| * 2 |
|
382 * * \ / * |
|
383 * * \13 __________________________14/ * |
|
384 * * * |
|
385 * ********************************** |
|
386 * 5 6 |
|
387 */ |
|
388 static const uint16_t gBevelStrokeAARectIdx[] = { |
|
389 // Draw outer AA, from outer AA line to outer edge, shift is 0. |
|
390 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0, |
|
391 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0, |
|
392 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0, |
|
393 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0, |
|
394 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0, |
|
395 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0, |
|
396 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0, |
|
397 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0, |
|
398 |
|
399 // Draw the stroke, from outer edge to inner edge, shift is 8. |
|
400 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8, |
|
401 1 + 8, 5 + 8, 9 + 8, |
|
402 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8, |
|
403 6 + 8, 2 + 8, 10 + 8, |
|
404 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8, |
|
405 3 + 8, 7 + 8, 11 + 8, |
|
406 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8, |
|
407 4 + 8, 0 + 8, 8 + 8, |
|
408 |
|
409 // Draw the inner AA, from inner edge to inner AA line, shift is 16. |
|
410 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16, |
|
411 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16, |
|
412 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16, |
|
413 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16, |
|
414 }; |
|
415 |
|
416 int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) { |
|
417 return miterStroke ? GR_ARRAY_COUNT(gMiterStrokeAARectIdx) : |
|
418 GR_ARRAY_COUNT(gBevelStrokeAARectIdx); |
|
419 } |
|
420 |
|
421 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) { |
|
422 if (miterStroke) { |
|
423 if (NULL == fAAMiterStrokeRectIndexBuffer) { |
|
424 fAAMiterStrokeRectIndexBuffer = |
|
425 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false); |
|
426 if (NULL != fAAMiterStrokeRectIndexBuffer) { |
|
427 #ifdef SK_DEBUG |
|
428 bool updated = |
|
429 #endif |
|
430 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx, |
|
431 sizeof(gMiterStrokeAARectIdx)); |
|
432 GR_DEBUGASSERT(updated); |
|
433 } |
|
434 } |
|
435 return fAAMiterStrokeRectIndexBuffer; |
|
436 } else { |
|
437 if (NULL == fAABevelStrokeRectIndexBuffer) { |
|
438 fAABevelStrokeRectIndexBuffer = |
|
439 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false); |
|
440 if (NULL != fAABevelStrokeRectIndexBuffer) { |
|
441 #ifdef SK_DEBUG |
|
442 bool updated = |
|
443 #endif |
|
444 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx, |
|
445 sizeof(gBevelStrokeAARectIdx)); |
|
446 GR_DEBUGASSERT(updated); |
|
447 } |
|
448 } |
|
449 return fAABevelStrokeRectIndexBuffer; |
|
450 } |
|
451 } |
|
452 |
|
453 void GrAARectRenderer::geometryFillAARect(GrGpu* gpu, |
|
454 GrDrawTarget* target, |
|
455 const SkRect& rect, |
|
456 const SkMatrix& combinedMatrix, |
|
457 const SkRect& devRect, |
|
458 bool useVertexCoverage) { |
|
459 GrDrawState* drawState = target->drawState(); |
|
460 |
|
461 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); |
|
462 |
|
463 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0); |
|
464 if (!geo.succeeded()) { |
|
465 GrPrintf("Failed to get space for vertices!\n"); |
|
466 return; |
|
467 } |
|
468 |
|
469 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu); |
|
470 if (NULL == indexBuffer) { |
|
471 GrPrintf("Failed to create index buffer!\n"); |
|
472 return; |
|
473 } |
|
474 |
|
475 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); |
|
476 size_t vsize = drawState->getVertexSize(); |
|
477 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize); |
|
478 |
|
479 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); |
|
480 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); |
|
481 |
|
482 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1); |
|
483 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height()); |
|
484 |
|
485 if (combinedMatrix.rectStaysRect()) { |
|
486 // Temporarily #if'ed out. We don't want to pass in the devRect but |
|
487 // right now it is computed in GrContext::apply_aa_to_rect and we don't |
|
488 // want to throw away the work |
|
489 #if 0 |
|
490 SkRect devRect; |
|
491 combinedMatrix.mapRect(&devRect, rect); |
|
492 #endif |
|
493 |
|
494 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf); |
|
495 set_inset_fan(fan1Pos, vsize, devRect, inset, inset); |
|
496 } else { |
|
497 // compute transformed (1, 0) and (0, 1) vectors |
|
498 SkVector vec[2] = { |
|
499 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, |
|
500 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } |
|
501 }; |
|
502 |
|
503 vec[0].normalize(); |
|
504 vec[0].scale(SK_ScalarHalf); |
|
505 vec[1].normalize(); |
|
506 vec[1].scale(SK_ScalarHalf); |
|
507 |
|
508 // create the rotated rect |
|
509 fan0Pos->setRectFan(rect.fLeft, rect.fTop, |
|
510 rect.fRight, rect.fBottom, vsize); |
|
511 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4); |
|
512 |
|
513 // Now create the inset points and then outset the original |
|
514 // rotated points |
|
515 |
|
516 // TL |
|
517 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) = |
|
518 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1]; |
|
519 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1]; |
|
520 // BL |
|
521 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) = |
|
522 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1]; |
|
523 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1]; |
|
524 // BR |
|
525 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) = |
|
526 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1]; |
|
527 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1]; |
|
528 // TR |
|
529 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) = |
|
530 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1]; |
|
531 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1]; |
|
532 } |
|
533 |
|
534 verts += sizeof(GrPoint); |
|
535 for (int i = 0; i < 4; ++i) { |
|
536 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; |
|
537 } |
|
538 |
|
539 int scale; |
|
540 if (inset < SK_ScalarHalf) { |
|
541 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); |
|
542 SkASSERT(scale >= 0 && scale <= 255); |
|
543 } else { |
|
544 scale = 0xff; |
|
545 } |
|
546 |
|
547 GrColor innerColor; |
|
548 if (useVertexCoverage) { |
|
549 innerColor = GrColorPackRGBA(scale, scale, scale, scale); |
|
550 } else { |
|
551 if (0xff == scale) { |
|
552 innerColor = target->getDrawState().getColor(); |
|
553 } else { |
|
554 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); |
|
555 } |
|
556 } |
|
557 |
|
558 verts += 4 * vsize; |
|
559 for (int i = 0; i < 4; ++i) { |
|
560 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; |
|
561 } |
|
562 |
|
563 target->setIndexSourceToBuffer(indexBuffer); |
|
564 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, |
|
565 kVertsPerAAFillRect, |
|
566 kIndicesPerAAFillRect); |
|
567 target->resetIndexSource(); |
|
568 } |
|
569 |
|
570 namespace { |
|
571 |
|
572 // Rotated |
|
573 struct RectVertex { |
|
574 GrPoint fPos; |
|
575 GrPoint fCenter; |
|
576 GrPoint fDir; |
|
577 GrPoint fWidthHeight; |
|
578 }; |
|
579 |
|
580 // Rotated |
|
581 extern const GrVertexAttrib gAARectVertexAttribs[] = { |
|
582 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, |
|
583 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, |
|
584 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding } |
|
585 }; |
|
586 |
|
587 // Axis Aligned |
|
588 struct AARectVertex { |
|
589 GrPoint fPos; |
|
590 GrPoint fOffset; |
|
591 GrPoint fWidthHeight; |
|
592 }; |
|
593 |
|
594 // Axis Aligned |
|
595 extern const GrVertexAttrib gAAAARectVertexAttribs[] = { |
|
596 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, |
|
597 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, |
|
598 }; |
|
599 |
|
600 }; |
|
601 |
|
602 void GrAARectRenderer::shaderFillAARect(GrGpu* gpu, |
|
603 GrDrawTarget* target, |
|
604 const SkRect& rect, |
|
605 const SkMatrix& combinedMatrix) { |
|
606 GrDrawState* drawState = target->drawState(); |
|
607 |
|
608 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); |
|
609 combinedMatrix.mapPoints(¢er, 1); |
|
610 |
|
611 // compute transformed (0, 1) vector |
|
612 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }; |
|
613 dir.normalize(); |
|
614 |
|
615 // compute transformed (width, 0) and (0, height) vectors |
|
616 SkVector vec[2] = { |
|
617 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] }, |
|
618 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] } |
|
619 }; |
|
620 |
|
621 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf; |
|
622 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf; |
|
623 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs)); |
|
624 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize()); |
|
625 |
|
626 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
|
627 if (!geo.succeeded()) { |
|
628 GrPrintf("Failed to get space for vertices!\n"); |
|
629 return; |
|
630 } |
|
631 |
|
632 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices()); |
|
633 |
|
634 GrEffectRef* effect = GrRectEffect::Create(); |
|
635 static const int kRectAttrIndex = 1; |
|
636 static const int kWidthIndex = 2; |
|
637 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref(); |
|
638 |
|
639 for (int i = 0; i < 4; ++i) { |
|
640 verts[i].fCenter = center; |
|
641 verts[i].fDir = dir; |
|
642 verts[i].fWidthHeight.fX = newWidth; |
|
643 verts[i].fWidthHeight.fY = newHeight; |
|
644 } |
|
645 |
|
646 SkRect devRect; |
|
647 combinedMatrix.mapRect(&devRect, rect); |
|
648 |
|
649 SkRect devBounds = { |
|
650 devRect.fLeft - SK_ScalarHalf, |
|
651 devRect.fTop - SK_ScalarHalf, |
|
652 devRect.fRight + SK_ScalarHalf, |
|
653 devRect.fBottom + SK_ScalarHalf |
|
654 }; |
|
655 |
|
656 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); |
|
657 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); |
|
658 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); |
|
659 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); |
|
660 |
|
661 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); |
|
662 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); |
|
663 target->resetIndexSource(); |
|
664 } |
|
665 |
|
666 void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu, |
|
667 GrDrawTarget* target, |
|
668 const SkRect& rect, |
|
669 const SkMatrix& combinedMatrix) { |
|
670 GrDrawState* drawState = target->drawState(); |
|
671 SkASSERT(combinedMatrix.rectStaysRect()); |
|
672 |
|
673 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs)); |
|
674 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize()); |
|
675 |
|
676 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); |
|
677 if (!geo.succeeded()) { |
|
678 GrPrintf("Failed to get space for vertices!\n"); |
|
679 return; |
|
680 } |
|
681 |
|
682 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices()); |
|
683 |
|
684 GrEffectRef* effect = GrAlignedRectEffect::Create(); |
|
685 static const int kOffsetIndex = 1; |
|
686 drawState->addCoverageEffect(effect, kOffsetIndex)->unref(); |
|
687 |
|
688 SkRect devRect; |
|
689 combinedMatrix.mapRect(&devRect, rect); |
|
690 |
|
691 SkRect devBounds = { |
|
692 devRect.fLeft - SK_ScalarHalf, |
|
693 devRect.fTop - SK_ScalarHalf, |
|
694 devRect.fRight + SK_ScalarHalf, |
|
695 devRect.fBottom + SK_ScalarHalf |
|
696 }; |
|
697 |
|
698 GrPoint widthHeight = { |
|
699 SkScalarHalf(devRect.width()) + SK_ScalarHalf, |
|
700 SkScalarHalf(devRect.height()) + SK_ScalarHalf |
|
701 }; |
|
702 |
|
703 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); |
|
704 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY); |
|
705 verts[0].fWidthHeight = widthHeight; |
|
706 |
|
707 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); |
|
708 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY); |
|
709 verts[1].fWidthHeight = widthHeight; |
|
710 |
|
711 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); |
|
712 verts[2].fOffset = widthHeight; |
|
713 verts[2].fWidthHeight = widthHeight; |
|
714 |
|
715 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); |
|
716 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY); |
|
717 verts[3].fWidthHeight = widthHeight; |
|
718 |
|
719 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); |
|
720 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); |
|
721 target->resetIndexSource(); |
|
722 } |
|
723 |
|
724 void GrAARectRenderer::strokeAARect(GrGpu* gpu, |
|
725 GrDrawTarget* target, |
|
726 const SkRect& rect, |
|
727 const SkMatrix& combinedMatrix, |
|
728 const SkRect& devRect, |
|
729 const SkStrokeRec* stroke, |
|
730 bool useVertexCoverage) { |
|
731 GrVec devStrokeSize; |
|
732 SkScalar width = stroke->getWidth(); |
|
733 if (width > 0) { |
|
734 devStrokeSize.set(width, width); |
|
735 combinedMatrix.mapVectors(&devStrokeSize, 1); |
|
736 devStrokeSize.setAbs(devStrokeSize); |
|
737 } else { |
|
738 devStrokeSize.set(SK_Scalar1, SK_Scalar1); |
|
739 } |
|
740 |
|
741 const SkScalar dx = devStrokeSize.fX; |
|
742 const SkScalar dy = devStrokeSize.fY; |
|
743 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); |
|
744 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); |
|
745 |
|
746 // Temporarily #if'ed out. We don't want to pass in the devRect but |
|
747 // right now it is computed in GrContext::apply_aa_to_rect and we don't |
|
748 // want to throw away the work |
|
749 #if 0 |
|
750 SkRect devRect; |
|
751 combinedMatrix.mapRect(&devRect, rect); |
|
752 #endif |
|
753 |
|
754 SkScalar spare; |
|
755 { |
|
756 SkScalar w = devRect.width() - dx; |
|
757 SkScalar h = devRect.height() - dy; |
|
758 spare = GrMin(w, h); |
|
759 } |
|
760 |
|
761 SkRect devOutside(devRect); |
|
762 devOutside.outset(rx, ry); |
|
763 |
|
764 bool miterStroke = true; |
|
765 // small miter limit means right angles show bevel... |
|
766 if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) { |
|
767 miterStroke = false; |
|
768 } |
|
769 |
|
770 if (spare <= 0 && miterStroke) { |
|
771 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), |
|
772 devOutside, useVertexCoverage); |
|
773 return; |
|
774 } |
|
775 |
|
776 SkRect devInside(devRect); |
|
777 devInside.inset(rx, ry); |
|
778 |
|
779 SkRect devOutsideAssist(devRect); |
|
780 |
|
781 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) |
|
782 // to draw the outer of the rect. Because there are 8 vertices on the outer |
|
783 // edge, while vertex number of inner edge is 4, the same as miter-stroke. |
|
784 if (!miterStroke) { |
|
785 devOutside.inset(0, ry); |
|
786 devOutsideAssist.outset(0, ry); |
|
787 } |
|
788 |
|
789 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, |
|
790 devInside, useVertexCoverage, miterStroke); |
|
791 } |
|
792 |
|
793 void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu, |
|
794 GrDrawTarget* target, |
|
795 const SkRect& devOutside, |
|
796 const SkRect& devOutsideAssist, |
|
797 const SkRect& devInside, |
|
798 bool useVertexCoverage, |
|
799 bool miterStroke) { |
|
800 GrDrawState* drawState = target->drawState(); |
|
801 |
|
802 set_aa_rect_vertex_attributes(drawState, useVertexCoverage); |
|
803 |
|
804 int innerVertexNum = 4; |
|
805 int outerVertexNum = miterStroke ? 4 : 8; |
|
806 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; |
|
807 |
|
808 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0); |
|
809 if (!geo.succeeded()) { |
|
810 GrPrintf("Failed to get space for vertices!\n"); |
|
811 return; |
|
812 } |
|
813 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke); |
|
814 if (NULL == indexBuffer) { |
|
815 GrPrintf("Failed to create index buffer!\n"); |
|
816 return; |
|
817 } |
|
818 |
|
819 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); |
|
820 size_t vsize = drawState->getVertexSize(); |
|
821 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize); |
|
822 |
|
823 // We create vertices for four nested rectangles. There are two ramps from 0 to full |
|
824 // coverage, one on the exterior of the stroke and the other on the interior. |
|
825 // The following pointers refer to the four rects, from outermost to innermost. |
|
826 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); |
|
827 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + outerVertexNum * vsize); |
|
828 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 2 * outerVertexNum * vsize); |
|
829 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize); |
|
830 |
|
831 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX |
|
832 // TODO: this only really works if the X & Y margins are the same all around |
|
833 // the rect |
|
834 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight); |
|
835 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); |
|
836 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); |
|
837 if (miterStroke) { |
|
838 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom); |
|
839 } else { |
|
840 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom); |
|
841 } |
|
842 SkASSERT(inset >= 0); |
|
843 #else |
|
844 SkScalar inset = SK_ScalarHalf; |
|
845 #endif |
|
846 |
|
847 if (miterStroke) { |
|
848 // outermost |
|
849 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
|
850 // inner two |
|
851 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); |
|
852 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); |
|
853 // innermost |
|
854 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); |
|
855 } else { |
|
856 GrPoint* fan0AssistPos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); |
|
857 GrPoint* fan1AssistPos = reinterpret_cast<GrPoint*>(verts + (outerVertexNum + 4) * vsize); |
|
858 // outermost |
|
859 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf); |
|
860 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf); |
|
861 // outer one of the inner two |
|
862 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset); |
|
863 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset); |
|
864 // inner one of the inner two |
|
865 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset); |
|
866 // innermost |
|
867 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf); |
|
868 } |
|
869 |
|
870 // The outermost rect has 0 coverage |
|
871 verts += sizeof(GrPoint); |
|
872 for (int i = 0; i < outerVertexNum; ++i) { |
|
873 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; |
|
874 } |
|
875 |
|
876 int scale; |
|
877 if (inset < SK_ScalarHalf) { |
|
878 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); |
|
879 SkASSERT(scale >= 0 && scale <= 255); |
|
880 } else { |
|
881 scale = 0xff; |
|
882 } |
|
883 |
|
884 // The inner two rects have full coverage |
|
885 GrColor innerColor; |
|
886 if (useVertexCoverage) { |
|
887 innerColor = GrColorPackRGBA(scale, scale, scale, scale); |
|
888 } else { |
|
889 if (0xff == scale) { |
|
890 innerColor = target->getDrawState().getColor(); |
|
891 } else { |
|
892 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale); |
|
893 } |
|
894 } |
|
895 |
|
896 verts += outerVertexNum * vsize; |
|
897 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { |
|
898 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; |
|
899 } |
|
900 |
|
901 // The innermost rect has 0 coverage |
|
902 verts += (outerVertexNum + innerVertexNum) * vsize; |
|
903 for (int i = 0; i < innerVertexNum; ++i) { |
|
904 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; |
|
905 } |
|
906 |
|
907 target->setIndexSourceToBuffer(indexBuffer); |
|
908 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, |
|
909 totalVertexNum, aaStrokeRectIndexCount(miterStroke)); |
|
910 } |
|
911 |
|
912 void GrAARectRenderer::fillAANestedRects(GrGpu* gpu, |
|
913 GrDrawTarget* target, |
|
914 const SkRect rects[2], |
|
915 const SkMatrix& combinedMatrix, |
|
916 bool useVertexCoverage) { |
|
917 SkASSERT(combinedMatrix.rectStaysRect()); |
|
918 SkASSERT(!rects[1].isEmpty()); |
|
919 |
|
920 SkRect devOutside, devOutsideAssist, devInside; |
|
921 combinedMatrix.mapRect(&devOutside, rects[0]); |
|
922 // can't call mapRect for devInside since it calls sort |
|
923 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); |
|
924 |
|
925 if (devInside.isEmpty()) { |
|
926 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage); |
|
927 return; |
|
928 } |
|
929 |
|
930 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, |
|
931 devInside, useVertexCoverage, true); |
|
932 } |