blob: a7403ed785029fa507454a5e0945c1bb5e26a1c3 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/SkTemplates.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040012#include "src/gpu/GrColor.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040013#include "src/gpu/geometry/GrQuad.h"
Brian Osmanf9aabff2018-11-13 16:11:38 -050014#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 */
25struct GrVertexWriter {
Brian Osman4486d982018-11-15 15:56:04 -050026 void* fPtr;
27
Brian Osmancfec9d52018-11-20 11:39:15 -050028 template <typename T>
29 class Conditional {
30 public:
31 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>
41 static Conditional<T> If(bool condition, const T& value) {
42 return Conditional<T>(condition, value);
43 }
44
Brian Osmand2fa2eb2018-12-26 16:48:40 -050045 template <typename T>
46 struct Skip {};
47
Brian Osmanf9aabff2018-11-13 16:11:38 -050048 template <typename T, typename... Args>
49 void write(const T& val, const Args&... remainder) {
50 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050051 // 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, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050055 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>
61 void write(const T(&val)[N], const Args&... remainder) {
62 static_assert(std::is_pod<T>::value, "");
Brian Osman0dd43022018-11-16 15:53:26 -050063 static_assert(alignof(T) <= 4, "");
Brian Osmanf9aabff2018-11-13 16:11:38 -050064 memcpy(fPtr, val, N * sizeof(T));
65 fPtr = SkTAddOffset<void>(fPtr, N * sizeof(T));
66 this->write(remainder...);
67 }
68
Brian Osman5c8a6b32018-11-19 11:56:57 -050069 template <typename... Args>
70 void write(const GrVertexColor& color, const Args&... remainder) {
71 this->write(color.fColor[0]);
72 if (color.fWideColor) {
73 this->write(color.fColor[1]);
Brian Osman2715bf52019-12-06 14:38:47 -050074 this->write(color.fColor[2]);
75 this->write(color.fColor[3]);
Brian Osman5c8a6b32018-11-19 11:56:57 -050076 }
77 this->write(remainder...);
78 }
79
Brian Osmancfec9d52018-11-20 11:39:15 -050080 template <typename T, typename... Args>
81 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
Brian Osmand2fa2eb2018-12-26 16:48:40 -050088 template <typename T, typename... Args>
89 void write(const Skip<T>& val, const Args&... remainder) {
90 fPtr = SkTAddOffset<void>(fPtr, sizeof(T));
91 this->write(remainder...);
92 }
93
Michael Ludwigf995c052018-11-26 15:24:29 -050094 template <typename... Args>
95 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
Brian Osmanffd11f4a2020-03-30 09:57:53 -0400102 void writeRaw(const void* data, size_t size) {
103 memcpy(fPtr, data, size);
104 fPtr = SkTAddOffset<void>(fPtr, size);
105 }
106
Brian Osmanf9aabff2018-11-13 16:11:38 -0500107 void write() {}
108
Brian Osman4486d982018-11-15 15:56:04 -0500109 /**
110 * Specialized utility for writing a four-vertices, with some data being replicated at each
111 * vertex, and other data being the appropriate 2-components from an SkRect to construct a
112 * triangle strip.
113 *
114 * writeQuad(A, B, C, ...) is similar to write(A, B, C, ...), except that:
115 *
116 * - Four sets of data will be written
117 * - For any arguments of type TriStrip, a unique SkPoint will be written at each vertex,
118 * in this order: left-top, left-bottom, right-top, right-bottom.
119 */
Brian Osman0dd43022018-11-16 15:53:26 -0500120 template <typename T>
121 struct TriStrip { T l, t, r, b; };
122
123 static TriStrip<float> TriStripFromRect(const SkRect& r) {
124 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
125 }
Brian Osman4486d982018-11-15 15:56:04 -0500126
Robert Phillips6d3bc292020-04-06 10:29:28 -0400127 static TriStrip<uint16_t> TriStripFromUVs(const std::array<uint16_t, 4>& rect) {
128 return { rect[0], rect[1], rect[2], rect[3] };
129 }
130
Brian Osmancfec9d52018-11-20 11:39:15 -0500131 template <typename T>
132 struct TriFan { T l, t, r, b; };
133
134 static TriFan<float> TriFanFromRect(const SkRect& r) {
135 return { r.fLeft, r.fTop, r.fRight, r.fBottom };
136 }
137
Brian Osman4486d982018-11-15 15:56:04 -0500138 template <typename... Args>
139 void writeQuad(const Args&... remainder) {
140 this->writeQuadVert<0>(remainder...);
141 this->writeQuadVert<1>(remainder...);
142 this->writeQuadVert<2>(remainder...);
143 this->writeQuadVert<3>(remainder...);
144 }
145
146private:
147 template <int corner, typename T, typename... Args>
148 void writeQuadVert(const T& val, const Args&... remainder) {
149 this->writeQuadValue<corner>(val);
150 this->writeQuadVert<corner>(remainder...);
151 }
152
153 template <int corner>
154 void writeQuadVert() {}
155
156 template <int corner, typename T>
157 void writeQuadValue(const T& val) {
158 this->write(val);
159 }
160
Brian Osman0dd43022018-11-16 15:53:26 -0500161 template <int corner, typename T>
162 void writeQuadValue(const TriStrip<T>& r) {
Brian Osman4486d982018-11-15 15:56:04 -0500163 switch (corner) {
Brian Osman0dd43022018-11-16 15:53:26 -0500164 case 0: this->write(r.l, r.t); break;
165 case 1: this->write(r.l, r.b); break;
166 case 2: this->write(r.r, r.t); break;
167 case 3: this->write(r.r, r.b); break;
Brian Osman4486d982018-11-15 15:56:04 -0500168 }
169 }
Brian Osman0dd43022018-11-16 15:53:26 -0500170
Brian Osmancfec9d52018-11-20 11:39:15 -0500171 template <int corner, typename T>
172 void writeQuadValue(const TriFan<T>& r) {
173 switch (corner) {
174 case 0: this->write(r.l, r.t); break;
175 case 1: this->write(r.l, r.b); break;
176 case 2: this->write(r.r, r.b); break;
177 case 3: this->write(r.r, r.t); break;
178 }
179 }
180
Brian Osman0dd43022018-11-16 15:53:26 -0500181 template <int corner>
182 void writeQuadValue(const GrQuad& q) {
183 this->write(q.point(corner));
184 }
Brian Osmanf9aabff2018-11-13 16:11:38 -0500185};
186
187#endif