Engine²
Open-source game engine written in C++.
Loading...
Searching...
No Matches
VertexBufferLayout.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "utils/webgpu.hpp"
4
9
10namespace Graphic::Utils {
12 public:
13 VertexBufferLayout() = default;
14 ~VertexBufferLayout() override = default;
15
16 VertexBufferLayout &addVertexAttribute(wgpu::VertexFormat format, uint32_t offset, uint32_t shaderLocation)
17 {
18 wgpu::VertexAttribute attribute;
19 attribute.format = format;
20 attribute.offset = offset;
21 attribute.shaderLocation = shaderLocation;
22 this->vertexAttributes.push_back(attribute);
23 return *this;
24 }
25
27 {
28 this->arrayStride = stride;
29 return *this;
30 }
31
32 VertexBufferLayout &setStepMode(wgpu::VertexStepMode mode)
33 {
34 this->stepMode = mode;
35 return *this;
36 }
37
38 inline uint32_t getArrayStride() const { return this->arrayStride.value_or(_computeArrayStride()); }
39
40 inline wgpu::VertexStepMode getStepMode() const { return this->stepMode; }
41
42 inline const std::vector<wgpu::VertexAttribute> &getVertexAttributes() const { return this->vertexAttributes; }
43
44 std::vector<ValidationError> validate(void) const override
45 {
46 std::vector<ValidationError> errors;
47 if (!this->arrayStride.has_value())
48 {
49 errors.emplace_back("Array stride is not set (auto computation will be used)", "VertexBufferLayout",
51 }
52 if (auto duplicatedLocations = this->_getDuplicatedShaderLocation(); !duplicatedLocations.empty())
53 {
54 for (const auto &[i, j] : duplicatedLocations)
55 {
56 errors.emplace_back(
57 fmt::format("Shader location {} is duplicated between attributes at index {} and {}",
58 this->vertexAttributes[i].shaderLocation, i, j),
59 "VertexBufferLayout", ValidationError::Severity::Error);
60 }
61 }
62 if (auto overlappingAttribute = this->_getOverlappingVertexAttributes(); !overlappingAttribute.empty())
63 {
64 for (const auto &[i, j] : overlappingAttribute)
65 {
66 errors.emplace_back(
67 fmt::format("Attribute at index {} (format: {}, offset: {}, shaderLocation: {}) overlaps with "
68 "attribute at index {} (format: {}, offset: {}, shaderLocation: {})",
69
70 i, this->vertexAttributes[i].offset,
71 static_cast<uint32_t>(this->vertexAttributes[i].format),
72 this->vertexAttributes[i].shaderLocation, j,
73 static_cast<uint32_t>(this->vertexAttributes[j].format),
74 this->vertexAttributes[j].offset, this->vertexAttributes[j].shaderLocation),
75
76 "VertexBufferLayout", ValidationError::Severity::Error);
77 }
78 }
79 return errors;
80 }
81
82 private:
83 inline uint32_t _computeArrayStride() const
84 {
85 uint32_t maxEnd = 0;
86 for (const auto &attribute : this->vertexAttributes)
87 {
88 const uint32_t attributeEnd = attribute.offset + this->_getVertexFormatSize(attribute.format);
89 if (attributeEnd > maxEnd)
90 {
91 maxEnd = attributeEnd;
92 }
93 }
94 return maxEnd;
95 }
96
97 inline uint32_t _getVertexFormatSize(wgpu::VertexFormat format) const
98 {
99 switch (format)
100 {
101 case wgpu::VertexFormat::Uint8: return sizeof(uint8_t);
102 case wgpu::VertexFormat::Uint8x2: return 2 * sizeof(uint8_t);
103 case wgpu::VertexFormat::Uint8x4: return 4 * sizeof(uint8_t);
104 case wgpu::VertexFormat::Unorm8: return sizeof(uint8_t);
105 case wgpu::VertexFormat::Unorm8x2: return 2 * sizeof(uint8_t);
106 case wgpu::VertexFormat::Unorm8x4: return 4 * sizeof(uint8_t);
107 case wgpu::VertexFormat::Float32x2: return 2 * sizeof(float);
108 case wgpu::VertexFormat::Float32x3: return 3 * sizeof(float);
109 case wgpu::VertexFormat::Float32x4: return 4 * sizeof(float);
110 default: throw Exception::UnknownFormatType("Unknown vertex format");
111 }
112 }
113
114 inline std::vector<std::pair<uint64_t, uint64_t>> _getDuplicatedShaderLocation(void) const
115 {
116 std::vector<std::pair<uint64_t, uint64_t>> duplicatedIndices;
117 for (size_t i = 0; i < this->vertexAttributes.size(); i++)
118 {
119 for (size_t j = i + 1; j < this->vertexAttributes.size(); j++)
120 {
121 if (this->vertexAttributes[i].shaderLocation == this->vertexAttributes[j].shaderLocation)
122 {
123 duplicatedIndices.push_back(std::make_pair(i, j));
124 }
125 }
126 }
127 return duplicatedIndices;
128 }
129
130 inline std::vector<std::pair<uint64_t, uint64_t>> _getOverlappingVertexAttributes(void) const
131 {
132 std::vector<std::pair<uint64_t, uint64_t>> overlappingIndices;
133 for (size_t i = 0; i < this->vertexAttributes.size(); i++)
134 {
135 for (size_t j = i + 1; j < this->vertexAttributes.size(); j++)
136 {
137 if (this->_doVertexAttributeOverlap(this->vertexAttributes[i], this->vertexAttributes[j]))
138 {
139 overlappingIndices.push_back(std::make_pair(i, j));
140 }
141 }
142 }
143 return overlappingIndices;
144 }
145
146 inline bool _doVertexAttributeOverlap(const wgpu::VertexAttribute &firstAttribute,
147 const wgpu::VertexAttribute &secondAttribute) const
148 {
149 const uint32_t firstStart = firstAttribute.offset;
150 const uint32_t firstEnd = firstStart + this->_getVertexFormatSize(firstAttribute.format);
151 const uint32_t secondStart = secondAttribute.offset;
152 const uint32_t secondEnd = secondStart + this->_getVertexFormatSize(secondAttribute.format);
153 if ((firstStart < secondEnd) && (firstEnd > secondStart))
154 {
155 return true;
156 }
157 return false;
158 }
159
160 std::vector<wgpu::VertexAttribute> vertexAttributes;
161 std::optional<uint32_t> arrayStride;
162 wgpu::VertexStepMode stepMode = wgpu::VertexStepMode::Vertex;
163};
164} // namespace Graphic::Utils
Definition UnknownFormatType.hpp:7
Definition IValidable.hpp:26
std::vector< std::pair< uint64_t, uint64_t > > _getDuplicatedShaderLocation(void) const
Definition VertexBufferLayout.hpp:114
bool _doVertexAttributeOverlap(const wgpu::VertexAttribute &firstAttribute, const wgpu::VertexAttribute &secondAttribute) const
Definition VertexBufferLayout.hpp:146
VertexBufferLayout & setArrayStride(uint32_t stride)
Definition VertexBufferLayout.hpp:26
uint32_t getArrayStride() const
Definition VertexBufferLayout.hpp:38
const std::vector< wgpu::VertexAttribute > & getVertexAttributes() const
Definition VertexBufferLayout.hpp:42
~VertexBufferLayout() override=default
wgpu::VertexStepMode stepMode
Definition VertexBufferLayout.hpp:162
VertexBufferLayout & addVertexAttribute(wgpu::VertexFormat format, uint32_t offset, uint32_t shaderLocation)
Definition VertexBufferLayout.hpp:16
VertexBufferLayout & setStepMode(wgpu::VertexStepMode mode)
Definition VertexBufferLayout.hpp:32
std::vector< wgpu::VertexAttribute > vertexAttributes
Definition VertexBufferLayout.hpp:160
std::optional< uint32_t > arrayStride
Definition VertexBufferLayout.hpp:161
std::vector< std::pair< uint64_t, uint64_t > > _getOverlappingVertexAttributes(void) const
Definition VertexBufferLayout.hpp:130
uint32_t _computeArrayStride() const
Definition VertexBufferLayout.hpp:83
uint32_t _getVertexFormatSize(wgpu::VertexFormat format) const
Definition VertexBufferLayout.hpp:97
wgpu::VertexStepMode getStepMode() const
Definition VertexBufferLayout.hpp:40
std::vector< ValidationError > validate(void) const override
Definition VertexBufferLayout.hpp:44
Definition DefaultSampler.hpp:6
@ Warning
Definition IValidable.hpp:13
@ Error
Definition IValidable.hpp:14