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:
ConditionalGrVertexWriter31         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>
IfGrVertexWriter41     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>
writeGrVertexWriter49     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>
writeGrVertexWriter61     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>
writeGrVertexWriter70     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         }
75         this->write(remainder...);
76     }
77 
78     template <typename T, typename... Args>
writeGrVertexWriter79     void write(const Conditional<T>& val, const Args&... remainder) {
80         if (val.fCondition) {
81             this->write(val.fValue);
82         }
83         this->write(remainder...);
84     }
85 
86     template <typename T, typename... Args>
writeGrVertexWriter87     void write(const Skip<T>& val, const Args&... remainder) {
88         fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
89         this->write(remainder...);
90     }
91 
92     template <typename... Args>
writeGrVertexWriter93     void write(const Sk4f& vector, const Args&... remainder) {
94         float buffer[4];
95         vector.store(buffer);
96         this->write<float, 4>(buffer);
97         this->write(remainder...);
98     }
99 
writeGrVertexWriter100     void write() {}
101 
102     /**
103      * Specialized utility for writing a four-vertices, with some data being replicated at each
104      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
105      * triangle strip.
106      *
107      * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
108      *
109      * - Four sets of data will be written
110      * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
111      *   in this order: left-top, left-bottom, right-top, right-bottom.
112      */
113     template <typename T>
114     struct TriStrip { T l, t, r, b; };
115 
TriStripFromRectGrVertexWriter116     static TriStrip<float> TriStripFromRect(const SkRect& r) {
117         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
118     }
119 
120     template <typename T>
121     struct TriFan { T l, t, r, b; };
122 
TriFanFromRectGrVertexWriter123     static TriFan<float> TriFanFromRect(const SkRect& r) {
124         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
125     }
126 
127     template <typename... Args>
writeQuadGrVertexWriter128     void writeQuad(const Args&... remainder) {
129         this->writeQuadVert<0>(remainder...);
130         this->writeQuadVert<1>(remainder...);
131         this->writeQuadVert<2>(remainder...);
132         this->writeQuadVert<3>(remainder...);
133     }
134 
135 private:
136     template <int corner, typename T, typename... Args>
writeQuadVertGrVertexWriter137     void writeQuadVert(const T& val, const Args&... remainder) {
138         this->writeQuadValue<corner>(val);
139         this->writeQuadVert<corner>(remainder...);
140     }
141 
142     template <int corner>
writeQuadVertGrVertexWriter143     void writeQuadVert() {}
144 
145     template <int corner, typename T>
writeQuadValueGrVertexWriter146     void writeQuadValue(const T& val) {
147         this->write(val);
148     }
149 
150     template <int corner, typename T>
writeQuadValueGrVertexWriter151     void writeQuadValue(const TriStrip<T>& r) {
152         switch (corner) {
153             case 0: this->write(r.l, r.t); break;
154             case 1: this->write(r.l, r.b); break;
155             case 2: this->write(r.r, r.t); break;
156             case 3: this->write(r.r, r.b); break;
157         }
158     }
159 
160     template <int corner, typename T>
writeQuadValueGrVertexWriter161     void writeQuadValue(const TriFan<T>& r) {
162         switch (corner) {
163         case 0: this->write(r.l, r.t); break;
164         case 1: this->write(r.l, r.b); break;
165         case 2: this->write(r.r, r.b); break;
166         case 3: this->write(r.r, r.t); break;
167         }
168     }
169 
170     template <int corner>
writeQuadValueGrVertexWriter171     void writeQuadValue(const GrQuad& q) {
172         this->write(q.point(corner));
173     }
174 };
175 
176 #endif
177