|
1 |
|
2 /* |
|
3 * Copyright 2012 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 #include "GrGLPath.h" |
|
10 #include "GrGpuGL.h" |
|
11 |
|
12 #define GPUGL static_cast<GrGpuGL*>(this->getGpu()) |
|
13 |
|
14 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) |
|
15 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(GPUGL->glInterface(), R, X) |
|
16 |
|
17 namespace { |
|
18 inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) { |
|
19 static const GrGLubyte gTable[] = { |
|
20 GR_GL_MOVE_TO, |
|
21 GR_GL_LINE_TO, |
|
22 GR_GL_QUADRATIC_CURVE_TO, |
|
23 0xFF, // conic |
|
24 GR_GL_CUBIC_CURVE_TO, |
|
25 GR_GL_CLOSE_PATH, |
|
26 }; |
|
27 GR_STATIC_ASSERT(0 == SkPath::kMove_Verb); |
|
28 GR_STATIC_ASSERT(1 == SkPath::kLine_Verb); |
|
29 GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb); |
|
30 GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb); |
|
31 GR_STATIC_ASSERT(5 == SkPath::kClose_Verb); |
|
32 |
|
33 SkASSERT(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable)); |
|
34 return gTable[verb]; |
|
35 } |
|
36 |
|
37 #ifdef SK_DEBUG |
|
38 inline int num_pts(SkPath::Verb verb) { |
|
39 static const int gTable[] = { |
|
40 1, // move |
|
41 1, // line |
|
42 2, // quad |
|
43 2, // conic |
|
44 3, // cubic |
|
45 0, // close |
|
46 }; |
|
47 GR_STATIC_ASSERT(0 == SkPath::kMove_Verb); |
|
48 GR_STATIC_ASSERT(1 == SkPath::kLine_Verb); |
|
49 GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb); |
|
50 GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb); |
|
51 GR_STATIC_ASSERT(5 == SkPath::kClose_Verb); |
|
52 |
|
53 SkASSERT(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable)); |
|
54 return gTable[verb]; |
|
55 } |
|
56 #endif |
|
57 |
|
58 inline GrGLenum join_to_gl_join(SkPaint::Join join) { |
|
59 static GrGLenum gSkJoinsToGrGLJoins[] = { |
|
60 GR_GL_MITER_REVERT, |
|
61 GR_GL_ROUND, |
|
62 GR_GL_BEVEL |
|
63 }; |
|
64 return gSkJoinsToGrGLJoins[join]; |
|
65 GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join); |
|
66 GR_STATIC_ASSERT(1 == SkPaint::kRound_Join); |
|
67 GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join); |
|
68 GR_STATIC_ASSERT(GR_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount); |
|
69 } |
|
70 |
|
71 inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) { |
|
72 static GrGLenum gSkCapsToGrGLCaps[] = { |
|
73 GR_GL_FLAT, |
|
74 GR_GL_ROUND, |
|
75 GR_GL_SQUARE |
|
76 }; |
|
77 return gSkCapsToGrGLCaps[cap]; |
|
78 GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap); |
|
79 GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap); |
|
80 GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap); |
|
81 GR_STATIC_ASSERT(GR_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount); |
|
82 } |
|
83 |
|
84 } |
|
85 |
|
86 static const bool kIsWrapped = false; // The constructor creates the GL path object. |
|
87 |
|
88 GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke) |
|
89 : INHERITED(gpu, kIsWrapped, path, stroke) { |
|
90 SkASSERT(!path.isEmpty()); |
|
91 |
|
92 GL_CALL_RET(fPathID, GenPaths(1)); |
|
93 |
|
94 SkSTArray<16, GrGLubyte, true> pathCommands; |
|
95 SkSTArray<16, SkPoint, true> pathPoints; |
|
96 |
|
97 int verbCnt = fSkPath.countVerbs(); |
|
98 int pointCnt = fSkPath.countPoints(); |
|
99 pathCommands.resize_back(verbCnt); |
|
100 pathPoints.resize_back(pointCnt); |
|
101 |
|
102 // TODO: Direct access to path points since we could pass them on directly. |
|
103 fSkPath.getPoints(&pathPoints[0], pointCnt); |
|
104 fSkPath.getVerbs(&pathCommands[0], verbCnt); |
|
105 |
|
106 SkDEBUGCODE(int numPts = 0); |
|
107 for (int i = 0; i < verbCnt; ++i) { |
|
108 SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]); |
|
109 pathCommands[i] = verb_to_gl_path_cmd(v); |
|
110 SkDEBUGCODE(numPts += num_pts(v)); |
|
111 } |
|
112 SkASSERT(pathPoints.count() == numPts); |
|
113 |
|
114 GL_CALL(PathCommands(fPathID, |
|
115 verbCnt, &pathCommands[0], |
|
116 2 * pointCnt, GR_GL_FLOAT, &pathPoints[0])); |
|
117 |
|
118 if (stroke.needToApply()) { |
|
119 GL_CALL(PathParameterf(fPathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth()))); |
|
120 GL_CALL(PathParameterf(fPathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter()))); |
|
121 GrGLenum join = join_to_gl_join(stroke.getJoin()); |
|
122 GL_CALL(PathParameteri(fPathID, GR_GL_PATH_JOIN_STYLE, join)); |
|
123 GrGLenum cap = cap_to_gl_cap(stroke.getCap()); |
|
124 GL_CALL(PathParameteri(fPathID, GR_GL_PATH_INITIAL_END_CAP, cap)); |
|
125 GL_CALL(PathParameteri(fPathID, GR_GL_PATH_TERMINAL_END_CAP, cap)); |
|
126 |
|
127 // FIXME: try to account for stroking, without rasterizing the stroke. |
|
128 fBounds.outset(SkScalarToFloat(stroke.getWidth()), SkScalarToFloat(stroke.getWidth())); |
|
129 } |
|
130 } |
|
131 |
|
132 GrGLPath::~GrGLPath() { |
|
133 this->release(); |
|
134 } |
|
135 |
|
136 void GrGLPath::onRelease() { |
|
137 if (0 != fPathID && !this->isWrapped()) { |
|
138 GL_CALL(DeletePaths(fPathID, 1)); |
|
139 fPathID = 0; |
|
140 } |
|
141 |
|
142 INHERITED::onRelease(); |
|
143 } |
|
144 |
|
145 void GrGLPath::onAbandon() { |
|
146 fPathID = 0; |
|
147 |
|
148 INHERITED::onAbandon(); |
|
149 } |