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