1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "RenderAPI/BsVertexDeclaration.h"
4#include "Private/RTTI/BsVertexDeclarationRTTI.h"
5#include "Managers/BsHardwareBufferManager.h"
6#include "RenderAPI/BsRenderAPI.h"
7
8namespace bs
9{
10 VertexElement::VertexElement(UINT16 source, UINT32 offset,
11 VertexElementType theType, VertexElementSemantic semantic, UINT16 index, UINT32 instanceStepRate)
12 : mSource(source), mOffset(offset), mType(theType), mSemantic(semantic), mIndex(index)
13 , mInstanceStepRate(instanceStepRate)
14 {
15 }
16
17 UINT32 VertexElement::getSize(void) const
18 {
19 return getTypeSize(mType);
20 }
21
22 UINT32 VertexElement::getTypeSize(VertexElementType etype)
23 {
24 switch(etype)
25 {
26 case VET_COLOR:
27 case VET_COLOR_ABGR:
28 case VET_COLOR_ARGB:
29 return sizeof(RGBA);
30 case VET_UBYTE4_NORM:
31 return sizeof(UINT32);
32 case VET_FLOAT1:
33 return sizeof(float);
34 case VET_FLOAT2:
35 return sizeof(float) * 2;
36 case VET_FLOAT3:
37 return sizeof(float) * 3;
38 case VET_FLOAT4:
39 return sizeof(float) * 4;
40 case VET_USHORT1:
41 return sizeof(UINT16);
42 case VET_USHORT2:
43 return sizeof(UINT16) * 2;
44 case VET_USHORT4:
45 return sizeof(UINT16) * 4;
46 case VET_SHORT1:
47 return sizeof(INT16);
48 case VET_SHORT2:
49 return sizeof(INT16) * 2;
50 case VET_SHORT4:
51 return sizeof(INT16) * 4;
52 case VET_UINT1:
53 return sizeof(UINT32);
54 case VET_UINT2:
55 return sizeof(UINT32) * 2;
56 case VET_UINT3:
57 return sizeof(UINT32) * 3;
58 case VET_UINT4:
59 return sizeof(UINT32) * 4;
60 case VET_INT4:
61 return sizeof(INT32) * 4;
62 case VET_INT1:
63 return sizeof(INT32);
64 case VET_INT2:
65 return sizeof(INT32) * 2;
66 case VET_INT3:
67 return sizeof(INT32) * 3;
68 case VET_UBYTE4:
69 return sizeof(UINT8) * 4;
70 default:
71 break;
72 }
73
74 return 0;
75 }
76
77 unsigned short VertexElement::getTypeCount(VertexElementType etype)
78 {
79 switch (etype)
80 {
81 case VET_COLOR:
82 case VET_COLOR_ABGR:
83 case VET_COLOR_ARGB:
84 return 4;
85 case VET_FLOAT1:
86 case VET_SHORT1:
87 case VET_USHORT1:
88 case VET_INT1:
89 case VET_UINT1:
90 return 1;
91 case VET_FLOAT2:
92 case VET_SHORT2:
93 case VET_USHORT2:
94 case VET_INT2:
95 case VET_UINT2:
96 return 2;
97 case VET_FLOAT3:
98 case VET_INT3:
99 case VET_UINT3:
100 return 3;
101 case VET_FLOAT4:
102 case VET_SHORT4:
103 case VET_USHORT4:
104 case VET_INT4:
105 case VET_UINT4:
106 case VET_UBYTE4:
107 case VET_UBYTE4_NORM:
108 return 4;
109 default:
110 break;
111 }
112
113 BS_EXCEPT(InvalidParametersException, "Invalid type");
114 return 0;
115 }
116
117 VertexElementType VertexElement::getBestColorVertexElementType()
118 {
119 // Use the current render system to determine if possible
120 if (ct::RenderAPI::instancePtr() != nullptr)
121 {
122 return ct::RenderAPI::instance().getCapabilities(0).vertexColorType;
123 }
124 else
125 {
126 // We can't know the specific type right now, so pick a type based on platform
127#if BS_PLATFORM == BS_PLATFORM_WIN32
128 return VET_COLOR_ARGB; // prefer D3D format on Windows
129#else
130 return VET_COLOR_ABGR; // prefer GL format on everything else
131#endif
132
133 }
134 }
135
136 bool VertexElement::operator== (const VertexElement& rhs) const
137 {
138 if (mType != rhs.mType || mIndex != rhs.mIndex || mOffset != rhs.mOffset ||
139 mSemantic != rhs.mSemantic || mSource != rhs.mSource || mInstanceStepRate != rhs.mInstanceStepRate)
140 {
141 return false;
142 }
143 else
144 return true;
145 }
146
147 bool VertexElement::operator!= (const VertexElement& rhs) const
148 {
149 return !(*this == rhs);
150 }
151
152 size_t VertexElement::getHash(const VertexElement& element)
153 {
154 size_t hash = 0;
155 bs_hash_combine(hash, element.mType);
156 bs_hash_combine(hash, element.mIndex);
157 bs_hash_combine(hash, element.mOffset);
158 bs_hash_combine(hash, element.mSemantic);
159 bs_hash_combine(hash, element.mSource);
160 bs_hash_combine(hash, element.mInstanceStepRate);
161
162 return hash;
163 }
164
165 VertexDeclarationProperties::VertexDeclarationProperties(const Vector<VertexElement>& elements)
166 {
167 for (auto& elem : elements)
168 {
169 VertexElementType type = elem.getType();
170
171 if (elem.getType() == VET_COLOR)
172 type = VertexElement::getBestColorVertexElementType();
173
174 mElementList.push_back(VertexElement(elem.getStreamIdx(), elem.getOffset(), type, elem.getSemantic(),
175 elem.getSemanticIdx(), elem.getInstanceStepRate()));
176 }
177 }
178
179 bool VertexDeclarationProperties::operator== (const VertexDeclarationProperties& rhs) const
180 {
181 if (mElementList.size() != rhs.mElementList.size())
182 return false;
183
184 auto myIter = mElementList.begin();
185 auto theirIter = rhs.mElementList.begin();
186
187 for (; myIter != mElementList.end() && theirIter != rhs.mElementList.end(); ++myIter, ++theirIter)
188 {
189 if (!(*myIter == *theirIter))
190 return false;
191 }
192
193 return true;
194 }
195
196 bool VertexDeclarationProperties::operator!= (const VertexDeclarationProperties& rhs) const
197 {
198 return !(*this == rhs);
199 }
200
201 const VertexElement* VertexDeclarationProperties::getElement(UINT16 index) const
202 {
203 assert(index < mElementList.size() && "Index out of bounds");
204
205 auto iter = mElementList.begin();
206 for (UINT16 i = 0; i < index; ++i)
207 ++iter;
208
209 return &(*iter);
210
211 }
212
213 const VertexElement* VertexDeclarationProperties::findElementBySemantic(VertexElementSemantic sem, UINT16 index) const
214 {
215 for (auto& elem : mElementList)
216 {
217 if (elem.getSemantic() == sem && elem.getSemanticIdx() == index)
218 {
219 return &elem;
220 }
221 }
222
223 return nullptr;
224 }
225
226 Vector<VertexElement> VertexDeclarationProperties::findElementsBySource(UINT16 source) const
227 {
228 Vector<VertexElement> retList;
229 for (auto& elem : mElementList)
230 {
231 if (elem.getStreamIdx() == source)
232 retList.push_back(elem);
233 }
234
235 return retList;
236 }
237
238 UINT32 VertexDeclarationProperties::getVertexSize(UINT16 source) const
239 {
240 UINT32 size = 0;
241
242 for (auto& elem : mElementList)
243 {
244 if (elem.getStreamIdx() == source)
245 {
246 size += elem.getSize();
247 }
248 }
249
250 return size;
251 }
252
253 VertexDeclaration::VertexDeclaration(const Vector<VertexElement>& elements)
254 :mProperties(elements)
255 {
256
257 }
258
259 SPtr<ct::VertexDeclaration> VertexDeclaration::getCore() const
260 {
261 return std::static_pointer_cast<ct::VertexDeclaration>(mCoreSpecific);
262 }
263
264 SPtr<ct::CoreObject> VertexDeclaration::createCore() const
265 {
266 return ct::HardwareBufferManager::instance().createVertexDeclarationInternal(mProperties.mElementList);
267 }
268
269 SPtr<VertexDeclaration> VertexDeclaration::create(const SPtr<VertexDataDesc>& desc)
270 {
271 return HardwareBufferManager::instance().createVertexDeclaration(desc);
272 }
273
274 /************************************************************************/
275 /* SERIALIZATION */
276 /************************************************************************/
277 RTTITypeBase* VertexDeclaration::getRTTIStatic()
278 {
279 return VertexDeclarationRTTI::instance();
280 }
281
282 RTTITypeBase* VertexDeclaration::getRTTI() const
283 {
284 return getRTTIStatic();
285 }
286
287 String toString(const VertexElementSemantic& val)
288 {
289 switch (val)
290 {
291 case VES_POSITION:
292 return "POSITION";
293 case VES_BLEND_WEIGHTS:
294 return "BLEND_WEIGHTS";
295 case VES_BLEND_INDICES:
296 return "BLEND_INDICES";
297 case VES_NORMAL:
298 return "NORMAL";
299 case VES_COLOR:
300 return "COLOR";
301 case VES_TEXCOORD:
302 return "TEXCOORD";
303 case VES_BITANGENT:
304 return "BITANGENT";
305 case VES_TANGENT:
306 return "TANGENT";
307 case VES_POSITIONT:
308 return "POSITIONT";
309 case VES_PSIZE:
310 return "PSIZE";
311 }
312
313 return "";
314 }
315
316 namespace ct
317 {
318 UINT32 VertexDeclaration::NextFreeId = 0;
319
320 VertexDeclaration::VertexDeclaration(const Vector<VertexElement>& elements, GpuDeviceFlags deviceMask)
321 :mProperties(elements)
322 {
323
324 }
325
326 void VertexDeclaration::initialize()
327 {
328 mId = NextFreeId++;
329 CoreObject::initialize();
330 }
331
332 SPtr<VertexDeclaration> VertexDeclaration::create(const SPtr<VertexDataDesc>& desc, GpuDeviceFlags deviceMask)
333 {
334 return HardwareBufferManager::instance().createVertexDeclaration(desc, deviceMask);
335 }
336
337 bool VertexDeclaration::isCompatible(const SPtr<VertexDeclaration>& shaderDecl)
338 {
339 const Vector<VertexElement>& shaderElems = shaderDecl->getProperties().getElements();
340 const Vector<VertexElement>& bufferElems = getProperties().getElements();
341
342 for (auto shaderIter = shaderElems.begin(); shaderIter != shaderElems.end(); ++shaderIter)
343 {
344 const VertexElement* foundElement = nullptr;
345 for (auto bufferIter = bufferElems.begin(); bufferIter != bufferElems.end(); ++bufferIter)
346 {
347 if (shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getSemanticIdx() == bufferIter->getSemanticIdx())
348 {
349 foundElement = &(*bufferIter);
350 break;
351 }
352 }
353
354 if (foundElement == nullptr)
355 return false;
356 }
357
358 return true;
359 }
360
361 Vector<VertexElement> VertexDeclaration::getMissingElements(const SPtr<VertexDeclaration>& shaderDecl)
362 {
363 Vector<VertexElement> missingElements;
364
365 const Vector<VertexElement>& shaderElems = shaderDecl->getProperties().getElements();
366 const Vector<VertexElement>& bufferElems = getProperties().getElements();
367
368 for (auto shaderIter = shaderElems.begin(); shaderIter != shaderElems.end(); ++shaderIter)
369 {
370 const VertexElement* foundElement = nullptr;
371 for (auto bufferIter = bufferElems.begin(); bufferIter != bufferElems.end(); ++bufferIter)
372 {
373 if (shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getSemanticIdx() == bufferIter->getSemanticIdx())
374 {
375 foundElement = &(*bufferIter);
376 break;
377 }
378 }
379
380 if (foundElement == nullptr)
381 missingElements.push_back(*shaderIter);
382 }
383
384 return missingElements;
385 }
386 }
387}