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