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