1 | /* |
2 | * Copyright 2010 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 | #ifndef GrVertexWriter_DEFINED |
9 | #define GrVertexWriter_DEFINED |
10 | |
11 | #include "include/private/SkTemplates.h" |
12 | #include "src/gpu/GrColor.h" |
13 | #include "src/gpu/geometry/GrQuad.h" |
14 | #include <type_traits> |
15 | |
16 | /** |
17 | * Helper for writing vertex data to a buffer. Usage: |
18 | * GrVertexWriter vertices{target->makeVertexSpace(...)}; |
19 | * vertices.write(A0, B0, C0, ...); |
20 | * vertices.write(A1, B1, C1, ...); |
21 | * |
22 | * Supports any number of arguments. Each argument must be POD (plain old data), or an array |
23 | * thereof. |
24 | */ |
25 | struct GrVertexWriter { |
26 | void* fPtr; |
27 | |
28 | template <typename T> |
29 | class Conditional { |
30 | public: |
31 | explicit Conditional(bool condition, const T& value) |
32 | : fCondition(condition), fValue(value) {} |
33 | private: |
34 | friend struct GrVertexWriter; |
35 | |
36 | bool fCondition; |
37 | T fValue; |
38 | }; |
39 | |
40 | template <typename T> |
41 | static Conditional<T> If(bool condition, const T& value) { |
42 | return Conditional<T>(condition, value); |
43 | } |
44 | |
45 | template <typename T> |
46 | struct Skip {}; |
47 | |
48 | template <typename T, typename... Args> |
49 | void write(const T& val, const Args&... remainder) { |
50 | static_assert(std::is_pod<T>::value, "" ); |
51 | // This assert is barely related to what we're trying to check - that our vertex data |
52 | // matches our attribute layouts, where each attribute is aligned to four bytes. If this |
53 | // becomes a problem, just remove it. |
54 | static_assert(alignof(T) <= 4, "" ); |
55 | memcpy(fPtr, &val, sizeof(T)); |
56 | fPtr = SkTAddOffset<void>(fPtr, sizeof(T)); |
57 | this->write(remainder...); |
58 | } |
59 | |
60 | template <typename T, size_t N, typename... Args> |
61 | void write(const T(&val)[N], const Args&... remainder) { |
62 | static_assert(std::is_pod<T>::value, "" ); |
63 | static_assert(alignof(T) <= 4, "" ); |
64 | memcpy(fPtr, val, N * sizeof(T)); |
65 | fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T)); |
66 | this->write(remainder...); |
67 | } |
68 | |
69 | template <typename... Args> |
70 | void write(const GrVertexColor& color, const Args&... remainder) { |
71 | this->write(color.fColor[0]); |
72 | if (color.fWideColor) { |
73 | this->write(color.fColor[1]); |
74 | this->write(color.fColor[2]); |
75 | this->write(color.fColor[3]); |
76 | } |
77 | this->write(remainder...); |
78 | } |
79 | |
80 | template <typename T, typename... Args> |
81 | void write(const Conditional<T>& val, const Args&... remainder) { |
82 | if (val.fCondition) { |
83 | this->write(val.fValue); |
84 | } |
85 | this->write(remainder...); |
86 | } |
87 | |
88 | template <typename T, typename... Args> |
89 | void write(const Skip<T>& val, const Args&... remainder) { |
90 | fPtr = SkTAddOffset<void>(fPtr, sizeof(T)); |
91 | this->write(remainder...); |
92 | } |
93 | |
94 | template <typename... Args> |
95 | void write(const Sk4f& vector, const Args&... remainder) { |
96 | float buffer[4]; |
97 | vector.store(buffer); |
98 | this->write<float, 4>(buffer); |
99 | this->write(remainder...); |
100 | } |
101 | |
102 | void writeRaw(const void* data, size_t size) { |
103 | memcpy(fPtr, data, size); |
104 | fPtr = SkTAddOffset<void>(fPtr, size); |
105 | } |
106 | |
107 | void write() {} |
108 | |
109 | /** |
110 | * Specialized utility for writing a four-vertices, with some data being replicated at each |
111 | * vertex, and other data being the appropriate 2-components from an SkRect to construct a |
112 | * triangle strip. |
113 | * |
114 | * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that: |
115 | * |
116 | * - Four sets of data will be written |
117 | * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex, |
118 | * in this order: left-top, left-bottom, right-top, right-bottom. |
119 | */ |
120 | template <typename T> |
121 | struct TriStrip { T l, t, r, b; }; |
122 | |
123 | static TriStrip<float> TriStripFromRect(const SkRect& r) { |
124 | return { r.fLeft, r.fTop, r.fRight, r.fBottom }; |
125 | } |
126 | |
127 | static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) { |
128 | return { rect[0], rect[1], rect[2], rect[3] }; |
129 | } |
130 | |
131 | template <typename T> |
132 | struct TriFan { T l, t, r, b; }; |
133 | |
134 | static TriFan<float> TriFanFromRect(const SkRect& r) { |
135 | return { r.fLeft, r.fTop, r.fRight, r.fBottom }; |
136 | } |
137 | |
138 | template <typename... Args> |
139 | void writeQuad(const Args&... remainder) { |
140 | this->writeQuadVert<0>(remainder...); |
141 | this->writeQuadVert<1>(remainder...); |
142 | this->writeQuadVert<2>(remainder...); |
143 | this->writeQuadVert<3>(remainder...); |
144 | } |
145 | |
146 | private: |
147 | template <int corner, typename T, typename... Args> |
148 | void writeQuadVert(const T& val, const Args&... remainder) { |
149 | this->writeQuadValue<corner>(val); |
150 | this->writeQuadVert<corner>(remainder...); |
151 | } |
152 | |
153 | template <int corner> |
154 | void writeQuadVert() {} |
155 | |
156 | template <int corner, typename T> |
157 | void writeQuadValue(const T& val) { |
158 | this->write(val); |
159 | } |
160 | |
161 | template <int corner, typename T> |
162 | void writeQuadValue(const TriStrip<T>& r) { |
163 | switch (corner) { |
164 | case 0: this->write(r.l, r.t); break; |
165 | case 1: this->write(r.l, r.b); break; |
166 | case 2: this->write(r.r, r.t); break; |
167 | case 3: this->write(r.r, r.b); break; |
168 | } |
169 | } |
170 | |
171 | template <int corner, typename T> |
172 | void writeQuadValue(const TriFan<T>& r) { |
173 | switch (corner) { |
174 | case 0: this->write(r.l, r.t); break; |
175 | case 1: this->write(r.l, r.b); break; |
176 | case 2: this->write(r.r, r.b); break; |
177 | case 3: this->write(r.r, r.t); break; |
178 | } |
179 | } |
180 | |
181 | template <int corner> |
182 | void writeQuadValue(const GrQuad& q) { |
183 | this->write(q.point(corner)); |
184 | } |
185 | }; |
186 | |
187 | #endif |
188 | |