• 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 "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             this->write(color.fColor[2]);
75             this->write(color.fColor[3]);
76         }
77         this->write(remainder...);
78     }
79 
80     template <typename T, typename... Args>
writeGrVertexWriter81     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>
writeGrVertexWriter89     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>
writeGrVertexWriter95     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 
writeGrVertexWriter102     void write() {}
103 
104     /**
105      * Specialized utility for writing a four-vertices, with some data being replicated at each
106      * vertex, and other data being the appropriate 2-components from an SkRect to construct a
107      * triangle strip.
108      *
109      * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
110      *
111      * - Four sets of data will be written
112      * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
113      *   in this order: left-top, left-bottom, right-top, right-bottom.
114      */
115     template <typename T>
116     struct TriStrip { T l, t, r, b; };
117 
TriStripFromRectGrVertexWriter118     static TriStrip<float> TriStripFromRect(const SkRect& r) {
119         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
120     }
121 
122     template <typename T>
123     struct TriFan { T l, t, r, b; };
124 
TriFanFromRectGrVertexWriter125     static TriFan<float> TriFanFromRect(const SkRect& r) {
126         return { r.fLeft, r.fTop, r.fRight, r.fBottom };
127     }
128 
129     template <typename... Args>
writeQuadGrVertexWriter130     void writeQuad(const Args&... remainder) {
131         this->writeQuadVert<0>(remainder...);
132         this->writeQuadVert<1>(remainder...);
133         this->writeQuadVert<2>(remainder...);
134         this->writeQuadVert<3>(remainder...);
135     }
136 
137 private:
138     template <int corner, typename T, typename... Args>
writeQuadVertGrVertexWriter139     void writeQuadVert(const T& val, const Args&... remainder) {
140         this->writeQuadValue<corner>(val);
141         this->writeQuadVert<corner>(remainder...);
142     }
143 
144     template <int corner>
writeQuadVertGrVertexWriter145     void writeQuadVert() {}
146 
147     template <int corner, typename T>
writeQuadValueGrVertexWriter148     void writeQuadValue(const T& val) {
149         this->write(val);
150     }
151 
152     template <int corner, typename T>
writeQuadValueGrVertexWriter153     void writeQuadValue(const TriStrip<T>& r) {
154         switch (corner) {
155             case 0: this->write(r.l, r.t); break;
156             case 1: this->write(r.l, r.b); break;
157             case 2: this->write(r.r, r.t); break;
158             case 3: this->write(r.r, r.b); break;
159         }
160     }
161 
162     template <int corner, typename T>
writeQuadValueGrVertexWriter163     void writeQuadValue(const TriFan<T>& r) {
164         switch (corner) {
165         case 0: this->write(r.l, r.t); break;
166         case 1: this->write(r.l, r.b); break;
167         case 2: this->write(r.r, r.b); break;
168         case 3: this->write(r.r, r.t); break;
169         }
170     }
171 
172     template <int corner>
writeQuadValueGrVertexWriter173     void writeQuadValue(const GrQuad& q) {
174         this->write(q.point(corner));
175     }
176 };
177 
178 #endif
179