blob: 37df53ae70d8d547e7ea56afa6fdbdfb204330c9 [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +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 "GrAARectRenderer.h"
9#include "GrRefCnt.h"
10#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000011#include "gl/GrGLEffect.h"
12#include "GrTBackendEffectFactory.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000013
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000014SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000015
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000016class GrGLRectEffect;
17
18/**
19 * The output of this effect is a modulation of the input color and coverage
20 * for an arbitrarily oriented rect. The rect is specified as:
21 * Center of the rect
22 * Unit vector point down the height of the rect
23 * Half width + 0.5
24 * Half height + 0.5
25 * The center and vector are stored in a vec4 varying ("RectEdge") with the
26 * center in the xy components and the vector in the zw components.
27 * The munged width and height are stored in a vec2 varying ("WidthHeight")
28 * with the width in x and the height in y.
29 */
30class GrRectEffect : public GrEffect {
31public:
32 static GrEffectRef* Create() {
33 static SkAutoTUnref<GrEffectRef> gRectEffectRef(
34 CreateEffectRef(AutoEffectUnref(SkNEW(GrRectEffect))));
35 gRectEffectRef.get()->ref();
36 return gRectEffectRef;
37 }
38
39 virtual ~GrRectEffect() {}
40
41 static const char* Name() { return "RectEdge"; }
42
43 virtual void getConstantColorComponents(GrColor* color,
44 uint32_t* validFlags) const SK_OVERRIDE {
45 *validFlags = 0;
46 }
47
48 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
49 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
50 }
51
52 class GLEffect : public GrGLEffect {
53 public:
54 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
55 : INHERITED (factory) {}
56
57 virtual void emitCode(GrGLShaderBuilder* builder,
58 const GrDrawEffect& drawEffect,
59 EffectKey key,
60 const char* outputColor,
61 const char* inputColor,
62 const TextureSamplerArray& samplers) SK_OVERRIDE {
63 // setup the varying for the center point and the unit vector
64 // that points down the height of the rect
65 const char *vsRectEdgeName, *fsRectEdgeName;
66 builder->addVarying(kVec4f_GrSLType, "RectEdge",
67 &vsRectEdgeName, &fsRectEdgeName);
68 const SkString* attr0Name =
69 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
70 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
71
72 // setup the varying for width/2+.5 and height/2+.5
73 const char *vsWidthHeightName, *fsWidthHeightName;
74 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
75 &vsWidthHeightName, &fsWidthHeightName);
76 const SkString* attr1Name =
77 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
78 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
79
80 // TODO: compute these scale factors in the VS
81 // These scale factors adjust the coverage for < 1 pixel wide/high rects
82 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
83 fsWidthHeightName);
84 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
85 fsWidthHeightName);
86
87 // Compute the coverage for the rect's width
88 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
89 builder->fragmentPosition(), fsRectEdgeName);
90 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
91 fsRectEdgeName, fsRectEdgeName);
92 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
93 fsWidthHeightName);
94
95 // Compute the coverage for the rect's height and merge with the width
96 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
97 fsRectEdgeName);
98 builder->fsCodeAppendf(
99 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
100 fsWidthHeightName);
101
102 SkString modulate;
103 GrGLSLModulate4f(&modulate, inputColor, "coverage");
104 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
105 }
106
107 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
108 return 0;
109 }
110
111 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
112
113 private:
114 typedef GrGLEffect INHERITED;
115 };
116
117
118private:
119 GrRectEffect::GrRectEffect() : GrEffect() {
120 this->addVertexAttrib(kVec4f_GrSLType);
121 this->addVertexAttrib(kVec2f_GrSLType);
122 }
123
124 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
125
126 GR_DECLARE_EFFECT_TEST;
127
128 typedef GrEffect INHERITED;
129};
130
131
132GR_DEFINE_EFFECT_TEST(GrRectEffect);
133
134GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
135 GrContext* context,
136 const GrDrawTargetCaps&,
137 GrTexture* textures[]) {
138 return GrRectEffect::Create();
139}
140
141///////////////////////////////////////////////////////////////////////////////
142
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000143namespace {
144
jvanverth@google.com054ae992013-04-01 20:06:51 +0000145static void aa_rect_attributes(bool useCoverage, const GrVertexAttrib** attribs, int* count) {
146 static const GrVertexAttrib kCoverageAttribs[] = {
147 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
148 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
149 };
150 static const GrVertexAttrib kColorAttribs[] = {
151 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
152 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
153 };
154 *attribs = useCoverage ? kCoverageAttribs : kColorAttribs;
155 *count = 2;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000156}
157
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000158static void set_inset_fan(GrPoint* pts, size_t stride,
159 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000160 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
161 r.fRight - dx, r.fBottom - dy, stride);
162}
163
164};
165
166void GrAARectRenderer::reset() {
167 GrSafeSetNull(fAAFillRectIndexBuffer);
168 GrSafeSetNull(fAAStrokeRectIndexBuffer);
169}
170
robertphillips@google.com6d067302012-12-18 21:47:47 +0000171static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000172 0, 1, 5, 5, 4, 0,
173 1, 2, 6, 6, 5, 1,
174 2, 3, 7, 7, 6, 2,
175 3, 0, 4, 4, 7, 3,
176 4, 5, 6, 6, 7, 4,
177};
178
robertphillips@google.com6d067302012-12-18 21:47:47 +0000179static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
180static const int kVertsPerAAFillRect = 8;
181static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000182
183GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000184 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
185 sizeof(uint16_t) *
186 kNumAAFillRectsInIndexBuffer;
187
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000188 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000189 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000190 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000191 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
192 bool useTempData = (NULL == data);
193 if (useTempData) {
194 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
195 }
196 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
197 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
198 // the inner rect (for AA) and 2 for the inner rect.
199 int baseIdx = i * kIndicesPerAAFillRect;
200 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
201 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
202 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
203 }
204 }
205 if (useTempData) {
206 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
207 GrCrash("Can't get AA Fill Rect indices into buffer!");
208 }
209 SkDELETE_ARRAY(data);
210 } else {
211 fAAFillRectIndexBuffer->unlock();
212 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213 }
214 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000215
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000216 return fAAFillRectIndexBuffer;
217}
218
robertphillips@google.com6d067302012-12-18 21:47:47 +0000219static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000220 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
221 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
222 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
223 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
224
225 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
226 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
227 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
228 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
229
230 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
231 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
232 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
233 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
234};
235
236int GrAARectRenderer::aaStrokeRectIndexCount() {
237 return GR_ARRAY_COUNT(gStrokeAARectIdx);
238}
239
240GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
241 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000242 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000243 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
244 if (NULL != fAAStrokeRectIndexBuffer) {
245#if GR_DEBUG
246 bool updated =
247#endif
248 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
249 sizeof(gStrokeAARectIdx));
250 GR_DEBUGASSERT(updated);
251 }
252 }
253 return fAAStrokeRectIndexBuffer;
254}
255
256void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000257 GrDrawTarget* target,
258 const GrRect& devRect,
259 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000260 GrDrawState* drawState = target->drawState();
261
jvanverth@google.com054ae992013-04-01 20:06:51 +0000262 const GrVertexAttrib* attribs;
263 int attribCount;
264 aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
265 drawState->setVertexAttribs(attribs, attribCount);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000267 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268 if (!geo.succeeded()) {
269 GrPrintf("Failed to get space for vertices!\n");
270 return;
271 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000272
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000273 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
274 if (NULL == indexBuffer) {
275 GrPrintf("Failed to create index buffer!\n");
276 return;
277 }
278
279 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000280 size_t vsize = drawState->getVertexSize();
281 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000282
283 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
284 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
285
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000286 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
287 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000288
289 verts += sizeof(GrPoint);
290 for (int i = 0; i < 4; ++i) {
291 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
292 }
293
294 GrColor innerColor;
295 if (useVertexCoverage) {
296 innerColor = 0xffffffff;
297 } else {
298 innerColor = target->getDrawState().getColor();
299 }
300
301 verts += 4 * vsize;
302 for (int i = 0; i < 4; ++i) {
303 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
304 }
305
306 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000307 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
308 kVertsPerAAFillRect,
309 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000310 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000311}
312
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000313struct RectVertex {
314 GrPoint fPos;
315 GrPoint fCenter;
316 GrPoint fDir;
317 GrPoint fWidthHeight;
318};
319
320
321void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
322 GrDrawTarget* target,
323 const GrRect& rect,
324 const SkMatrix& combinedMatrix,
325 const GrRect& devRect,
326 bool useVertexCoverage) {
327 GrDrawState* drawState = target->drawState();
328
329 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
330 combinedMatrix.mapPoints(&center, 1);
331
332 // compute transformed (0, 1) vector
333 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
334 dir.normalize();
335
336 // compute transformed (width, 0) and (0, height) vectors
337 SkVector vec[2] = {
338 { combinedMatrix[SkMatrix::kMScaleX] * rect.width(),
339 combinedMatrix[SkMatrix::kMSkewY] * rect.width() },
340 { combinedMatrix[SkMatrix::kMSkewX] * rect.height(),
341 combinedMatrix[SkMatrix::kMScaleY] * rect.height() }
342 };
343
344 SkScalar newWidth = vec[0].length() / 2.0f + 0.5f;
345 SkScalar newHeight = vec[1].length() / 2.0f + 0.5f;
346
347 static const GrVertexAttrib kVertexAttribs[] = {
348 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
349 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
350 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
351 };
352 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
353 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
354
355 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
356 if (!geo.succeeded()) {
357 GrPrintf("Failed to get space for vertices!\n");
358 return;
359 }
360
361 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
362
363 enum {
364 // the edge effects share this stage with glyph rendering
365 // (kGlyphMaskStage in GrTextContext) && SW path rendering
366 // (kPathMaskStage in GrSWMaskHelper)
367 kEdgeEffectStage = GrPaint::kTotalStages,
368 };
369
370 GrEffectRef* effect = GrRectEffect::Create();
371 static const int kRectAttrIndex = 1;
372 static const int kWidthIndex = 2;
373 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
374
375 for (int i = 0; i < 4; ++i) {
376 verts[i].fCenter = center;
377 verts[i].fDir = dir;
378 verts[i].fWidthHeight.fX = newWidth;
379 verts[i].fWidthHeight.fY = newHeight;
380 }
381
382 SkRect devBounds = {
383 devRect.fLeft - SK_ScalarHalf,
384 devRect.fTop - SK_ScalarHalf,
385 devRect.fRight + SK_ScalarHalf,
386 devRect.fBottom + SK_ScalarHalf
387 };
388
389 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
390 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
391 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
392 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
393
394 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
395 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
396 target->resetIndexSource();
397}
398
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000399void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000400 GrDrawTarget* target,
401 const GrRect& devRect,
402 const GrVec& devStrokeSize,
403 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000404 GrDrawState* drawState = target->drawState();
405
bsalomon@google.com81712882012-11-01 17:12:34 +0000406 const SkScalar& dx = devStrokeSize.fX;
407 const SkScalar& dy = devStrokeSize.fY;
408 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
409 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000410
bsalomon@google.com81712882012-11-01 17:12:34 +0000411 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000412 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000413 SkScalar w = devRect.width() - dx;
414 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000415 spare = GrMin(w, h);
416 }
417
418 if (spare <= 0) {
419 GrRect r(devRect);
420 r.inset(-rx, -ry);
421 this->fillAARect(gpu, target, r, useVertexCoverage);
422 return;
423 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000424
jvanverth@google.com054ae992013-04-01 20:06:51 +0000425 const GrVertexAttrib* attribs;
426 int attribCount;
427 aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
428 drawState->setVertexAttribs(attribs, attribCount);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000429
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000430 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000431 if (!geo.succeeded()) {
432 GrPrintf("Failed to get space for vertices!\n");
433 return;
434 }
435 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
436 if (NULL == indexBuffer) {
437 GrPrintf("Failed to create index buffer!\n");
438 return;
439 }
440
441 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000442 size_t vsize = drawState->getVertexSize();
443 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000444
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000445 // We create vertices for four nested rectangles. There are two ramps from 0 to full
446 // coverage, one on the exterior of the stroke and the other on the interior.
447 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000448 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
449 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
450 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
451 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
452
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000453 set_inset_fan(fan0Pos, vsize, devRect,
454 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
455 set_inset_fan(fan1Pos, vsize, devRect,
456 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
457 set_inset_fan(fan2Pos, vsize, devRect,
458 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
459 set_inset_fan(fan3Pos, vsize, devRect,
460 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000462 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463 verts += sizeof(GrPoint);
464 for (int i = 0; i < 4; ++i) {
465 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
466 }
467
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000468 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000469 GrColor innerColor;
470 if (useVertexCoverage) {
471 innerColor = 0xffffffff;
472 } else {
473 innerColor = target->getDrawState().getColor();
474 }
475 verts += 4 * vsize;
476 for (int i = 0; i < 8; ++i) {
477 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
478 }
479
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000480 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000481 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000482 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000483 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
484 }
485
486 target->setIndexSourceToBuffer(indexBuffer);
487 target->drawIndexed(kTriangles_GrPrimitiveType,
488 0, 0, 16, aaStrokeRectIndexCount());
489}