blob: c62eeb7d1ed5b3e22b2aface133addaf08c5e152 [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"
11
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000012SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000013
14namespace {
15
robertphillips@google.comca47aae2012-12-12 15:58:25 +000016static GrVertexLayout aa_rect_layout(bool useCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017 GrVertexLayout layout = 0;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000018 if (useCoverage) {
19 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
20 } else {
21 layout |= GrDrawTarget::kColor_VertexLayoutBit;
22 }
23 return layout;
24}
25
robertphillips@google.comca47aae2012-12-12 15:58:25 +000026static void set_inset_fan(GrPoint* pts, size_t stride,
27 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000028 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
29 r.fRight - dx, r.fBottom - dy, stride);
30}
31
32};
33
34void GrAARectRenderer::reset() {
35 GrSafeSetNull(fAAFillRectIndexBuffer);
36 GrSafeSetNull(fAAStrokeRectIndexBuffer);
37}
38
39const uint16_t GrAARectRenderer::gFillAARectIdx[] = {
40 0, 1, 5, 5, 4, 0,
41 1, 2, 6, 6, 5, 1,
42 2, 3, 7, 7, 6, 2,
43 3, 0, 4, 4, 7, 3,
44 4, 5, 6, 6, 7, 4,
45};
46
47int GrAARectRenderer::aaFillRectIndexCount() {
48 return GR_ARRAY_COUNT(gFillAARectIdx);
49}
50
51GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
52 if (NULL == fAAFillRectIndexBuffer) {
53 fAAFillRectIndexBuffer = gpu->createIndexBuffer(sizeof(gFillAARectIdx),
54 false);
55 if (NULL != fAAFillRectIndexBuffer) {
56#if GR_DEBUG
57 bool updated =
58#endif
59 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
60 sizeof(gFillAARectIdx));
61 GR_DEBUGASSERT(updated);
62 }
63 }
64 return fAAFillRectIndexBuffer;
65}
66
67const uint16_t GrAARectRenderer::gStrokeAARectIdx[] = {
68 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
69 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
70 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
71 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
72
73 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
74 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
75 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
76 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
77
78 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
79 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
80 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
81 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
82};
83
84int GrAARectRenderer::aaStrokeRectIndexCount() {
85 return GR_ARRAY_COUNT(gStrokeAARectIdx);
86}
87
88GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
89 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000090 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +000091 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
92 if (NULL != fAAStrokeRectIndexBuffer) {
93#if GR_DEBUG
94 bool updated =
95#endif
96 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
97 sizeof(gStrokeAARectIdx));
98 GR_DEBUGASSERT(updated);
99 }
100 }
101 return fAAStrokeRectIndexBuffer;
102}
103
104void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000105 GrDrawTarget* target,
106 const GrRect& devRect,
107 bool useVertexCoverage) {
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000108 GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000109
110 size_t vsize = GrDrawTarget::VertexSize(layout);
111
112 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
113 if (!geo.succeeded()) {
114 GrPrintf("Failed to get space for vertices!\n");
115 return;
116 }
117 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
118 if (NULL == indexBuffer) {
119 GrPrintf("Failed to create index buffer!\n");
120 return;
121 }
122
123 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
124
125 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
126 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
127
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000128 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
129 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000130
131 verts += sizeof(GrPoint);
132 for (int i = 0; i < 4; ++i) {
133 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
134 }
135
136 GrColor innerColor;
137 if (useVertexCoverage) {
138 innerColor = 0xffffffff;
139 } else {
140 innerColor = target->getDrawState().getColor();
141 }
142
143 verts += 4 * vsize;
144 for (int i = 0; i < 4; ++i) {
145 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
146 }
147
148 target->setIndexSourceToBuffer(indexBuffer);
149
150 target->drawIndexed(kTriangles_GrPrimitiveType, 0,
151 0, 8, this->aaFillRectIndexCount());
152}
153
154void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000155 GrDrawTarget* target,
156 const GrRect& devRect,
157 const GrVec& devStrokeSize,
158 bool useVertexCoverage) {
bsalomon@google.com81712882012-11-01 17:12:34 +0000159 const SkScalar& dx = devStrokeSize.fX;
160 const SkScalar& dy = devStrokeSize.fY;
161 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
162 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000163
bsalomon@google.com81712882012-11-01 17:12:34 +0000164 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000165 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000166 SkScalar w = devRect.width() - dx;
167 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000168 spare = GrMin(w, h);
169 }
170
171 if (spare <= 0) {
172 GrRect r(devRect);
173 r.inset(-rx, -ry);
174 this->fillAARect(gpu, target, r, useVertexCoverage);
175 return;
176 }
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000177 GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000178 size_t vsize = GrDrawTarget::VertexSize(layout);
179
180 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
181 if (!geo.succeeded()) {
182 GrPrintf("Failed to get space for vertices!\n");
183 return;
184 }
185 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
186 if (NULL == indexBuffer) {
187 GrPrintf("Failed to create index buffer!\n");
188 return;
189 }
190
191 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
192
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000193 // We create vertices for four nested rectangles. There are two ramps from 0 to full
194 // coverage, one on the exterior of the stroke and the other on the interior.
195 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000196 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
197 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
198 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
199 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
200
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000201 set_inset_fan(fan0Pos, vsize, devRect,
202 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
203 set_inset_fan(fan1Pos, vsize, devRect,
204 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
205 set_inset_fan(fan2Pos, vsize, devRect,
206 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
207 set_inset_fan(fan3Pos, vsize, devRect,
208 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000209
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000210 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000211 verts += sizeof(GrPoint);
212 for (int i = 0; i < 4; ++i) {
213 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
214 }
215
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000216 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000217 GrColor innerColor;
218 if (useVertexCoverage) {
219 innerColor = 0xffffffff;
220 } else {
221 innerColor = target->getDrawState().getColor();
222 }
223 verts += 4 * vsize;
224 for (int i = 0; i < 8; ++i) {
225 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
226 }
227
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000228 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000229 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000230 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000231 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
232 }
233
234 target->setIndexSourceToBuffer(indexBuffer);
235 target->drawIndexed(kTriangles_GrPrimitiveType,
236 0, 0, 16, aaStrokeRectIndexCount());
237}