OLD | NEW |
---|---|
(Empty) | |
1 /* | |
robertphillips
2013/03/21 13:12:39
2013
jvanverth1
2013/03/21 18:42:18
Done.
| |
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 "GrOvalRenderer.h" | |
9 | |
10 #include "effects/GrCircleEdgeEffect.h" | |
11 #include "effects/GrEllipseEdgeEffect.h" | |
12 | |
13 #include "GrContext.h" | |
14 #include "GrDrawState.h" | |
15 #include "GrDrawTarget.h" | |
16 #include "GrPaint.h" | |
17 #include "SkStrokeRec.h" | |
18 | |
19 SK_DEFINE_INST_COUNT(GrOvalRenderer) | |
20 | |
21 namespace { | |
22 | |
23 struct CircleVertex { | |
24 GrPoint fPos; | |
25 GrPoint fCenter; | |
26 SkScalar fOuterRadius; | |
27 SkScalar fInnerRadius; | |
28 }; | |
29 | |
30 struct EllipseVertex { | |
31 GrPoint fPos; | |
32 GrPoint fCenter; | |
33 SkScalar fOuterXRadius; | |
34 SkScalar fOuterXYRatio; | |
35 SkScalar fInnerXRadius; | |
36 SkScalar fInnerXYRatio; | |
37 }; | |
38 | |
robertphillips
2013/03/21 13:12:39
circle_stays_circle
jvanverth1
2013/03/21 18:42:18
Done.
| |
39 inline bool circleStaysCircle(const SkMatrix& m) { | |
40 return m.isSimilarity(); | |
41 } | |
42 | |
43 } | |
44 | |
45 bool GrOvalRenderer::canDrawOval(const GrContext* context, const GrPaint& paint, | |
46 const GrRect& oval, bool* isCircle) const | |
47 { | |
48 GrAssert(isCircle != NULL); | |
49 | |
50 if (!paint.isAntiAlias()) { | |
51 return false; | |
52 } | |
53 | |
54 // we can draw circles | |
55 *isCircle = SkScalarNearlyEqual(oval.width(), oval.height()) | |
56 && circleStaysCircle(context->getMatrix()); | |
57 // and axis-aligned ellipses only | |
58 bool isAxisAlignedEllipse = context->getMatrix().rectStaysRect(); | |
59 | |
60 return *isCircle || isAxisAlignedEllipse; | |
61 | |
62 } | |
63 | |
64 void GrOvalRenderer::drawEllipse(GrDrawTarget* target, | |
65 const GrPaint& paint, | |
66 const GrRect& ellipse, | |
67 const SkStrokeRec& stroke) | |
68 { | |
69 GrDrawState* drawState = target->drawState(); | |
70 #ifdef SK_DEBUG | |
71 { | |
72 // we should have checked for this previously | |
73 bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect(); | |
74 SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse); | |
75 } | |
76 #endif | |
77 | |
robertphillips
2013/03/21 13:12:39
Do we even need "rt"?
jvanverth1
2013/03/21 18:42:18
Done.
| |
78 const GrRenderTarget* rt = drawState->getRenderTarget(); | |
79 if (NULL == rt) { | |
80 return; | |
81 } | |
82 | |
robertphillips
2013/03/21 13:12:39
&
jvanverth1
2013/03/21 18:42:18
Done.
| |
83 const SkMatrix vm = drawState->getViewMatrix(); | |
84 | |
85 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | |
86 if (!adcd.succeeded()) { | |
87 return; | |
88 } | |
89 | |
90 // position + edge | |
91 static const GrVertexAttrib kVertexAttribs[] = { | |
92 {kVec2f_GrVertexAttribType, 0}, | |
93 {kVec2f_GrVertexAttribType, sizeof(GrPoint)}, | |
94 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)} | |
95 }; | |
96 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); | |
97 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); | |
98 GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize()); | |
99 | |
100 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | |
101 if (!geo.succeeded()) { | |
102 GrPrintf("Failed to get space for vertices!\n"); | |
103 return; | |
104 } | |
105 | |
106 EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices()); | |
107 | |
108 GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY()); | |
109 vm.mapPoints(¢er, 1); | |
110 | |
111 SkStrokeRec::Style style = stroke.getStyle(); | |
112 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
113 enum { | |
114 // the edge effects share this stage with glyph rendering | |
115 // (kGlyphMaskStage in GrTextContext) && SW path rendering | |
116 // (kPathMaskStage in GrSWMaskHelper) | |
117 kEdgeEffectStage = GrPaint::kTotalStages, | |
118 }; | |
119 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | |
120 | |
121 GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); | |
122 static const int kEllipseCenterAttrIndex = 1; | |
123 static const int kEllipseEdgeAttrIndex = 2; | |
124 drawState->setEffect(kEdgeEffectStage, effect, | |
125 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); | |
126 | |
127 SkRect xformedRect; | |
128 vm.mapRect(&xformedRect, ellipse); | |
129 | |
130 SkScalar xRadius = SkScalarHalf(xformedRect.width()); | |
131 SkScalar yRadius = SkScalarHalf(xformedRect.height()); | |
132 SkScalar innerXRadius = 0.0f; | |
133 SkScalar innerRatio = 1.0f; | |
134 | |
135 if (SkStrokeRec::kFill_Style != style) { | |
136 SkScalar strokeWidth = stroke.getWidth(); | |
137 | |
138 // do (potentially) anisotropic mapping | |
139 SkVector scaledStroke; | |
140 scaledStroke.set(strokeWidth, strokeWidth); | |
141 vm.mapVectors(&scaledStroke, 1); | |
142 | |
143 if (SkScalarNearlyZero(scaledStroke.length())) { | |
144 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
145 } else { | |
146 scaledStroke.scale(0.5f); | |
147 } | |
148 | |
149 // this is legit only if scale & translation (which should be the case a t the moment) | |
150 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { | |
151 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
152 if (innerYRadius > SK_ScalarNearlyZero) { | |
153 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
154 innerRatio = innerXRadius/innerYRadius; | |
155 } | |
156 } | |
157 xRadius += scaledStroke.fX; | |
158 yRadius += scaledStroke.fY; | |
159 } | |
160 | |
161 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); | |
162 | |
163 for (int i = 0; i < 4; ++i) { | |
164 verts[i].fCenter = center; | |
165 verts[i].fOuterXRadius = xRadius + 0.5f; | |
166 verts[i].fOuterXYRatio = outerRatio; | |
167 verts[i].fInnerXRadius = innerXRadius - 0.5f; | |
168 verts[i].fInnerXYRatio = innerRatio; | |
169 } | |
170 | |
171 SkScalar L = -xRadius; | |
172 SkScalar R = +xRadius; | |
173 SkScalar T = -yRadius; | |
174 SkScalar B = +yRadius; | |
175 | |
176 // We've extended the outer x radius out half a pixel to antialias. | |
177 // Expand the drawn rect here so all the pixels will be captured. | |
178 L += center.fX - SK_ScalarHalf; | |
179 R += center.fX + SK_ScalarHalf; | |
180 T += center.fY - SK_ScalarHalf; | |
181 B += center.fY + SK_ScalarHalf; | |
182 | |
183 verts[0].fPos = SkPoint::Make(L, T); | |
184 verts[1].fPos = SkPoint::Make(R, T); | |
185 verts[2].fPos = SkPoint::Make(L, B); | |
186 verts[3].fPos = SkPoint::Make(R, B); | |
187 | |
188 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | |
189 } | |
190 | |
191 void GrOvalRenderer::drawCircle(GrDrawTarget* target, | |
192 const GrPaint& paint, | |
193 const GrRect& circle, | |
194 const SkStrokeRec& stroke) | |
195 { | |
196 GrDrawState* drawState = target->drawState(); | |
robertphillips
2013/03/21 13:12:39
Do we even need "rt"?
jvanverth1
2013/03/21 18:42:18
Done.
| |
197 const GrRenderTarget* rt = drawState->getRenderTarget(); | |
198 if (NULL == rt) { | |
199 return; | |
200 } | |
201 | |
202 SkScalar radius = SkScalarHalf(circle.width()); | |
203 | |
204 SkScalar strokeWidth = stroke.getWidth(); | |
205 SkStrokeRec::Style style = stroke.getStyle(); | |
206 | |
robertphillips
2013/03/21 13:12:39
&
jvanverth1
2013/03/21 18:42:18
Done.
| |
207 const SkMatrix vm = drawState->getViewMatrix(); | |
208 | |
209 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | |
210 if (!adcd.succeeded()) { | |
211 return; | |
212 } | |
213 | |
214 // position + edge | |
215 static const GrVertexAttrib kVertexAttribs[] = { | |
216 {kVec2f_GrVertexAttribType, 0}, | |
217 {kVec4f_GrVertexAttribType, sizeof(GrPoint)} | |
218 }; | |
219 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); | |
220 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); | |
221 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); | |
222 | |
223 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); | |
224 if (!geo.succeeded()) { | |
225 GrPrintf("Failed to get space for vertices!\n"); | |
226 return; | |
227 } | |
228 | |
229 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | |
230 | |
231 GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY()); | |
232 vm.mapPoints(¢er, 1); | |
233 | |
234 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
235 enum { | |
236 // the edge effects share this stage with glyph rendering | |
237 // (kGlyphMaskStage in GrTextContext) && SW path rendering | |
238 // (kPathMaskStage in GrSWMaskHelper) | |
239 kEdgeEffectStage = GrPaint::kTotalStages, | |
240 }; | |
241 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | |
242 | |
243 GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); | |
244 static const int kCircleEdgeAttrIndex = 1; | |
245 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref( ); | |
246 | |
247 radius = vm.mapRadius(radius); | |
248 | |
249 SkScalar innerRadius = 0.0f; | |
250 SkScalar outerRadius = radius; | |
251 SkScalar halfWidth = 0; | |
252 if (style != SkStrokeRec::kFill_Style) { | |
253 strokeWidth = vm.mapRadius(strokeWidth); | |
254 if (SkScalarNearlyZero(strokeWidth)) { | |
255 halfWidth = SK_ScalarHalf; | |
256 } else { | |
257 halfWidth = SkScalarHalf(strokeWidth); | |
258 } | |
259 | |
260 outerRadius += halfWidth; | |
261 if (isStroked) { | |
262 innerRadius = SkMaxScalar(0, radius - halfWidth); | |
263 } | |
264 } | |
265 | |
266 for (int i = 0; i < 4; ++i) { | |
267 verts[i].fCenter = center; | |
268 verts[i].fOuterRadius = outerRadius + 0.5f; | |
269 verts[i].fInnerRadius = innerRadius - 0.5f; | |
270 } | |
271 | |
272 SkScalar L = -outerRadius; | |
273 SkScalar R = +outerRadius; | |
274 SkScalar T = -outerRadius; | |
275 SkScalar B = +outerRadius; | |
276 | |
277 // We've extended the outer radius out half a pixel to antialias. | |
278 // Expand the drawn rect here so all the pixels will be captured. | |
279 L += center.fX - SK_ScalarHalf; | |
280 R += center.fX + SK_ScalarHalf; | |
281 T += center.fY - SK_ScalarHalf; | |
282 B += center.fY + SK_ScalarHalf; | |
283 | |
284 verts[0].fPos = SkPoint::Make(L, T); | |
285 verts[1].fPos = SkPoint::Make(R, T); | |
286 verts[2].fPos = SkPoint::Make(L, B); | |
287 verts[3].fPos = SkPoint::Make(R, B); | |
288 | |
289 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | |
290 } | |
OLD | NEW |