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