blob: de4c78f9109654dc789df187ce5657ff91a93925 [file] [log] [blame]
Brian Osmanf9aabff2018-11-13 16:11:38 -05001/*
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
Brian Osman0dd43022018-11-16 15:53:26 -050011#include "GrQuad.h"
Brian Osmanf9aabff2018-11-13 16:11:38 -050012#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 */
24struct GrVertexWriter {
Brian Osman4486d982018-11-15 15:56:04 -050025 void* fPtr;
26
Brian Osmancfec9d52018-11-20 11:39:15 -050027 template <typename T>
28 class Conditional {
29 public:
30 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>
40 static Conditional<T> If(bool condition, const T& value) {
41 return Conditional<T>(condition, value);
42 }
43
Brian Osmand2fa2eb2018-12-26 16:48:40 -050044 template <typename T>
45 struct Skip {};
46
Brian Osmanf9aabff2018-11-13 16:11:38 -050047 template <typename T, typename... Args>
48 void write(const T& val, const Args&... remainder) {
49 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050050 // 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, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050054 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>
60 void write(const T(&val)[N], const Args&... remainder) {
61 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050062 static_assert(alignof(T) <= 4, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050063 memcpy(fPtr, val, N * sizeof(T));
64 fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T));
65 this->write(remainder...);
66 }
67
Brian Osman5c8a6b32018-11-19 11:56:57 -050068 template <typename... Args>
69 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
Brian Osmancfec9d52018-11-20 11:39:15 -050077 template <typename T, typename... Args>
78 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
Brian Osmand2fa2eb2018-12-26 16:48:40 -050085 template <typename T, typename... Args>
86 void write(const Skip<T>& val, const Args&... remainder) {
87 fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
88 this->write(remainder...);
89 }
90
Michael Ludwigf995c052018-11-26 15:24:29 -050091 template <typename... Args>
92 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
Brian Osmanf9aabff2018-11-13 16:11:38 -050099 void write() {}
100
Brian Osman4486d982018-11-15 15:56:04 -0500101 /**
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 */
Brian Osman0dd43022018-11-16 15:53:26 -0500112 template <typename T>
113 struct TriStrip { T l, t, r, b; };
114
115 static TriStrip<float> TriStripFromRect(const SkRect& r) {
116 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
117 }
Brian Osman4486d982018-11-15 15:56:04 -0500118
Brian Osmancfec9d52018-11-20 11:39:15 -0500119 template <typename T>
120 struct TriFan { T l, t, r, b; };
121
122 static TriFan<float> TriFanFromRect(const SkRect& r) {
123 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
124 }
125
Brian Osman4486d982018-11-15 15:56:04 -0500126 template <typename... Args>
127 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
134private:
135 template <int corner, typename T, typename... Args>
136 void writeQuadVert(const T& val, const Args&... remainder) {
137 this->writeQuadValue<corner>(val);
138 this->writeQuadVert<corner>(remainder...);
139 }
140
141 template <int corner>
142 void writeQuadVert() {}
143
144 template <int corner, typename T>
145 void writeQuadValue(const T& val) {
146 this->write(val);
147 }
148
Brian Osman0dd43022018-11-16 15:53:26 -0500149 template <int corner, typename T>
150 void writeQuadValue(const TriStrip<T>& r) {
Brian Osman4486d982018-11-15 15:56:04 -0500151 switch (corner) {
Brian Osman0dd43022018-11-16 15:53:26 -0500152 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;
Brian Osman4486d982018-11-15 15:56:04 -0500156 }
157 }
Brian Osman0dd43022018-11-16 15:53:26 -0500158
Brian Osmancfec9d52018-11-20 11:39:15 -0500159 template <int corner, typename T>
160 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
Brian Osman0dd43022018-11-16 15:53:26 -0500169 template <int corner>
170 void writeQuadValue(const GrQuad& q) {
171 this->write(q.point(corner));
172 }
Brian Osmanf9aabff2018-11-13 16:11:38 -0500173};
174
175#endif