Visual Computing Library  devel
Loading...
Searching...
No Matches
drawable_mesh_bgfx.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2026 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_BGFX_DRAWABLE_DRAWABLE_MESH_BGFX_H
24#define VCL_BGFX_DRAWABLE_DRAWABLE_MESH_BGFX_H
25
26#include <vclib/algorithms/mesh/stat/bounding_box.h>
27#include <vclib/render/drawable/abstract_drawable_mesh.h>
28
29#include <vclib/bgfx/context.h>
30#include <vclib/bgfx/drawable/drawable_environment.h>
31#include <vclib/bgfx/drawable/mesh/mesh_render_buffers.h>
32#include <vclib/bgfx/drawable/uniforms/mesh_render_settings_uniforms.h>
33
34#include <bgfx/bgfx.h>
35
36namespace vcl {
37
38template<MeshConcept MeshType>
39class DrawableMeshBGFX : public AbstractDrawableMesh, public MeshType
40{
41public:
42 // TODO: to be removed after shader benchmarks
43 enum class SurfaceProgramsType {
44 UBER,
45 SPLIT,
46 UBER_WITH_STATIC_IF,
47 };
48
49private:
50 using MRI = MeshRenderInfo;
51
52 // TODO: to be removed after shader benchmarks
53 SurfaceProgramsType mSurfaceProgramType = SurfaceProgramsType::UBER;
54
55 inline static const uint N_TEXTURE_TYPES =
56 toUnderlying(Material::TextureType::COUNT);
57
58protected:
60
61public:
62 DrawableMeshBGFX() = default;
63
64 DrawableMeshBGFX(const MeshType& mesh) :
65 AbstractDrawableMesh(mesh), MeshType(mesh)
66 {
67 updateBuffers();
68 }
69
70 DrawableMeshBGFX(MeshType&& mesh) :
71 AbstractDrawableMesh(mesh), MeshType(std::move(mesh))
72 {
73 updateBuffers();
74 }
75
78 MeshType(drawableMesh)
79 {
80 if constexpr (HasName<MeshType>) {
82 }
83 updateBuffers();
84 }
85
87
88 ~DrawableMeshBGFX() = default;
89
91 {
92 swap(drawableMesh);
93 return *this;
94 }
95
96 void swap(DrawableMeshBGFX& other)
97 {
98 using std::swap;
99 AbstractDrawableMesh::swap(other);
100 MeshType::swap(other);
101 swap(mSurfaceProgramType, other.mSurfaceProgramType);
102 swap(mMRB, other.mMRB);
103 }
104
105 friend void swap(DrawableMeshBGFX& a, DrawableMeshBGFX& b) { a.swap(b); }
106
108
109 // TODO: to be removed after shader benchmarks
110 void setSurfaceProgramType(SurfaceProgramsType type)
111 {
112 if (type != mSurfaceProgramType) {
113 std::cerr << "Program Type changed: ";
114 switch (type) {
115 case SurfaceProgramsType::UBER: std::cerr << "UBER\n"; break;
116 case SurfaceProgramsType::SPLIT: std::cerr << "SPLITTED\n"; break;
117 case SurfaceProgramsType::UBER_WITH_STATIC_IF:
118 std::cerr << "UBER_WITH_STATIC_IF\n";
119 break;
120 }
121 mSurfaceProgramType = type;
122 }
123 }
124
125 // AbstractDrawableMesh implementation
126
127 void updateBuffers(
128 MRI::BuffersBitSet buffersToUpdate = MRI::BUFFERS_ALL) override
129 {
130 if constexpr (HasName<MeshType>) {
131 AbstractDrawableMesh::name() = MeshType::name();
132 }
133
134 AbstractDrawableMesh::computeBoundingBox(
135 static_cast<const MeshType&>(*this));
136
137 mMRB.update(*this, buffersToUpdate);
138 mMRS.setRenderCapabilityFrom(*this);
139 setRenderSettings(mMRS);
140 }
141
142 void setRenderSettings(const MeshRenderSettings& rs) override
143 {
144 AbstractDrawableMesh::setRenderSettings(rs);
145 mMRB.updateEdgeSettings(rs);
146 mMRB.updateWireframeSettings(rs);
147 }
148
149 uint vertexCount() const override { return MeshType::vertexCount(); }
150
151 uint faceCount() const override
152 {
153 if constexpr (HasFaces<MeshType>)
154 return MeshType::faceCount();
155 else
156 return 0;
157 }
158
159 uint edgeCount() const override
160 {
161 if constexpr (HasEdges<MeshType>)
162 return MeshType::edgeCount();
163 else
164 return 0;
165 }
166
167 vcl::Matrix44d transformMatrix() const override
168 {
169 if constexpr (HasTransformMatrix<MeshType>) {
170 return MeshType::transformMatrix().template cast<double>();
171 }
172 else {
174 }
175 }
176
177 View<MatIt> materials() const override
178 {
179 if constexpr (HasMaterials<MeshType>) {
180 return MeshType::materials();
181 }
182 else {
183 return View<MatIt>();
184 }
185 }
186
187 const Image& textureImage(const std::string& path) const override
188 {
189 if constexpr (HasMaterials<MeshType>) {
190 return MeshType::textureImage(path);
191 }
192 else {
193 return AbstractDrawableMesh::textureImage(path);
194 }
195 }
196
197 // DrawableObject implementation
198
199 void init() override {}
200
201 void draw(const DrawObjectSettings& settings) const override
202 {
203 using enum VertFragProgram;
204
205 ProgramManager& pm = Context::instance().programManager();
206
209
210 vcl::Matrix44f model = vcl::Matrix44f::Identity();
211
212 if constexpr (HasTransformMatrix<MeshType>) {
213 model = MeshType::transformMatrix().template cast<float>();
214 }
215
216 DrawableMeshUniforms::setColor(*this);
217 MeshRenderSettingsUniforms::set(mMRS);
218
219 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
220 const PBRViewerSettings& pbrSettings = settings.pbrSettings;
221 const DrawableEnvironment* env = settings.environment;
222
223 bool iblEnabled = pbrSettings.imageBasedLighting &&
224 env != nullptr && env->canDraw();
225
226 for (uint i = 0; i < mMRB.triangleChunksNumber(); ++i) {
227 // Bind textures before vertex buffers!!
228
229 /* TEXTURES */
230 mMRB.bindTextures(mMRS, i, *this);
231 if (pbrSettings.pbrMode && iblEnabled) {
233 env->bindTexture(BRDF_LUT, VCL_MRB_TEXTURE5);
234 env->bindTexture(IRRADIANCE, VCL_MRB_CUBEMAP0);
235 env->bindTexture(SPECULAR, VCL_MRB_CUBEMAP1);
236 }
237
238 /* BUFFERS */
239 mMRB.bindVertexBuffers(mMRS);
240 mMRB.bindIndexBuffers(mMRS, i);
241
242 /* UNIFORMS */
243 DrawableMeshUniforms::setFirstChunkIndex(
244 mMRB.triangleChunk(i).startIndex);
247
248 bindUniforms();
249
250 bgfx::setTransform(model.data());
251
252 /* STATE */
254 if (pbrSettings.pbrMode) {
256 }
257
258 bgfx::setState(surfaceState);
259
260 /* SUBMIT */
261 if (pbrSettings.pbrMode) {
262 bgfx::submit(
263 settings.viewId,
264 pm.getProgram<DRAWABLE_MESH_SURFACE_UBER_PBR>());
265 }
266 else {
267 bgfx::submit(settings.viewId, surfaceProgramSelector());
268 }
269 }
270 }
271
272 if (mMRS.isWireframe(MRI::Wireframe::VISIBLE)) {
273 bgfx::setTransform(model.data());
274
275 mMRB.drawWireframeLines(settings.viewId);
276 }
277
278 if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
279 bgfx::setTransform(model.data());
280
281 mMRB.drawEdgeLines(settings.viewId);
282 }
283
284 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
285 if (!Context::instance().supportsCompute()) {
286 // 1 px vertices
287 mMRB.bindVertexBuffers(mMRS);
288 bindUniforms();
289
290 bgfx::setState(state | BGFX_STATE_PT_POINTS);
291 bgfx::setTransform(model.data());
292
293 bgfx::submit(
294 settings.viewId, pm.getProgram<DRAWABLE_MESH_POINTS>());
295 }
296 else {
297 // generate splats (quads) lazy
298 mMRB.computeQuadVertexBuffers(*this, settings.viewId);
299
300 // render splats
301 mMRB.bindVertexQuadBuffer();
302 bindUniforms();
303
304 bgfx::setState(state);
305 bgfx::setTransform(model.data());
306
307 bgfx::submit(
308 settings.viewId,
309 pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE>());
310 }
311 }
312 }
313
314 void drawId(const DrawObjectSettings& settings) const override
315 {
316 using enum VertFragProgram;
317
318 ProgramManager& pm = Context::instance().programManager();
319
324 // write alpha as is
325
326 vcl::Matrix44f model = vcl::Matrix44f::Identity();
327
328 if constexpr (HasTransformMatrix<MeshType>) {
329 model = MeshType::transformMatrix().template cast<float>();
330 }
331
332 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
333 mMRB.bindVertexBuffers(mMRS);
334 mMRB.bindIndexBuffers(mMRS);
335 DrawableMeshUniforms::setMeshId(settings.objectId);
336 DrawableMeshUniforms::setFirstChunkIndex(0);
337 bindUniforms();
338
339 bgfx::setState(state);
340 bgfx::setTransform(model.data());
341
342 bgfx::submit(
343 settings.viewId, pm.getProgram<DRAWABLE_MESH_SURFACE_ID>());
344 }
345
346 // if (mMRS.isWireframe(MRI::Wireframe::VISIBLE)) {
347 // mMRB.bindVertexBuffers(mMRS);
348 // mMRB.bindIndexBuffers(mMRS, MRI::Buffers::WIREFRAME);
349 // mIdUniform.bind(&idFloat);
350
351 // bgfx::setState(state | BGFX_STATE_PT_LINES);
352 // bgfx::setTransform(model.data());
353
354 // bgfx::submit(viewId,
355 // pm.getProgram<DRAWABLE_MESH_WIREFRAME_ID>());
356 // }
357
358 // if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
359 // mMRB.bindVertexBuffers(mMRS);
360 // mMRB.bindIndexBuffers(mMRS, MRI::Buffers::EDGES);
361 // mIdUniform.bind(&idFloat);
362
363 // bgfx::setState(state | BGFX_STATE_PT_LINES);
364 // bgfx::setTransform(model.data());
365
366 // bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_EDGES_ID>());
367 // }
368
369 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
370 if (!Context::instance().supportsCompute()) {
371 // 1 px vertices
372 mMRB.bindVertexBuffers(mMRS);
373
374 DrawableMeshUniforms::setMeshId(settings.objectId);
375 bindUniforms();
376
377 bgfx::setState(state | BGFX_STATE_PT_POINTS);
378 bgfx::setTransform(model.data());
379
380 bgfx::submit(
381 settings.viewId, pm.getProgram<DRAWABLE_MESH_POINTS_ID>());
382 }
383 else {
384 // generate splats (quads) lazy
385 mMRB.computeQuadVertexBuffers(*this, settings.viewId);
386
387 // render splats
388 mMRB.bindVertexQuadBuffer();
389 DrawableMeshUniforms::setMeshId(settings.objectId);
390 bindUniforms();
391
392 bgfx::setState(state);
393 bgfx::setTransform(model.data());
394
395 bgfx::submit(
396 settings.viewId,
397 pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE_ID>());
398 }
399 }
400 }
401
402 std::shared_ptr<DrawableObject> clone() const& override
403 {
404 return std::make_shared<DrawableMeshBGFX>(*this);
405 }
406
407 std::shared_ptr<DrawableObject> clone() && override
408 {
409 return std::make_shared<DrawableMeshBGFX>(std::move(*this));
410 }
411
412 std::string& name() override { return MeshType::name(); }
413
414 const std::string& name() const override { return MeshType::name(); }
415
416protected:
417 void bindUniforms() const
418 {
419 MeshRenderSettingsUniforms::bind();
420 DrawableMeshUniforms::bind();
421 }
422
432 uint chunkNumber,
433 bool imageBasedLighting) const
434 {
435 static const Material DEFAULT_MATERIAL;
436
438
439 std::array<bool, N_TEXTURE_TYPES> textureAvailable = {false};
440
441 if constexpr (!HasMaterials<MeshType>) {
442 // fallback to default material
443 MaterialUniforms::set(
445 isPerVertexColorAvailable(*this),
447 isPerVertexTangentAvailable(*this),
448 imageBasedLighting);
449 }
450 else {
451 using enum Material::AlphaMode;
452
453 uint materialId = mMRB.materialIndex(mMRS, chunkNumber);
454
455 if (materialId == UINT_NULL) {
456 // fallback to default material
457 MaterialUniforms::set(
459 isPerVertexColorAvailable(*this),
461 isPerVertexTangentAvailable(*this),
462 imageBasedLighting);
463 }
464 else {
466 mMRB.textureAvailableArray(*this, materialId);
467
468 MaterialUniforms::set(
469 MeshType::material(materialId),
470 isPerVertexColorAvailable(*this),
472 isPerVertexTangentAvailable(*this),
473 imageBasedLighting);
474
475 // set the state according to the material
476 if (!MeshType::material(materialId).doubleSided()) {
477 // backface culling
479 }
480 if (MeshType::material(materialId).alphaMode() == ALPHA_BLEND) {
482 }
483 }
484 }
485
486 MaterialUniforms::bind();
487 return state;
488 }
489
490 // TODO: change this function implementation after shader benchmarks
491 bgfx::ProgramHandle surfaceProgramSelector() const
492 {
493 using enum VertFragProgram;
494
495 ProgramManager& pm = Context::instance().programManager();
496
497 uint mul = 0;
498 uint off = 0;
499
500 {
501 using enum MeshRenderInfo::Surface;
502 if (mMRS.isSurface(SHADING_FLAT)) {
503 mul = 1;
504 }
505 if (mMRS.isSurface(SHADING_SMOOTH)) {
506 mul = 2;
507 }
508 if (mMRS.isSurface(COLOR_MESH)) {
509 off = 1;
510 }
511 if (mMRS.isSurface(COLOR_FACE)) {
512 off = 2;
513 }
514 if (mMRS.isSurface(COLOR_USER)) {
515 off = 3;
516 }
517 if (mMRS.isSurface(COLOR_VERTEX_TEX)) {
518 off = 4;
519 }
520 if (mMRS.isSurface(COLOR_WEDGE_TEX)) {
521 off = 5;
522 }
523 }
524
525 VertFragProgram p = static_cast<VertFragProgram>(6 * mul + off);
526
527 if (mSurfaceProgramType == SurfaceProgramsType::SPLIT) {
528 static const std::array<bgfx::ProgramHandle, 18>
529 surfaceProgramHandles = {
530 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX>(),
531 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH>(),
532 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE>(),
533 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER>(),
534 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX>(),
535 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE>(),
536 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX>(),
537 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH>(),
538 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE>(),
539 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER>(),
540 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX>(),
541 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE>(),
542 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX>(),
543 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH>(),
544 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE>(),
545 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER>(),
546 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX>(),
547 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE>()};
548
549 return surfaceProgramHandles[toUnderlying(p)];
550 }
551
552 if (mSurfaceProgramType == SurfaceProgramsType::UBER_WITH_STATIC_IF) {
553 static const std::array<bgfx::ProgramHandle, 18>
554 surfaceProgramHandles = {
555 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX_SI>(),
556 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH_SI>(),
557 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE_SI>(),
558 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER_SI>(),
559 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX_SI>(),
560 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE_SI>(),
561 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX_SI>(),
562 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH_SI>(),
563 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE_SI>(),
564 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER_SI>(),
565 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX_SI>(),
566 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE_SI>(),
567 pm.getProgram<
568 DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX_SI>(),
569 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH_SI>(),
570 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE_SI>(),
571 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER_SI>(),
572 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX_SI>(),
573 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE_SI>()};
574
575 return surfaceProgramHandles[toUnderlying(p)];
576 }
577
578 return pm.getProgram<DRAWABLE_MESH_SURFACE_UBER>();
579 }
580};
581
582} // namespace vcl
583
584#endif // VCL_BGFX_DRAWABLE_DRAWABLE_MESH_BGFX_H
The AbstractDrawableMesh class is the base class for all the drawable meshes in the VCLib render syst...
Definition abstract_drawable_mesh.h:41
Box3d boundingBox() const override
This member function is used to find a good camera position to render object. It should return the th...
Definition abstract_drawable_mesh.h:86
The BitSet class allows to treat an integral type as an array of booleans of a guaranteed size.
Definition bit_set.h:52
static Context & instance(void *windowHandle=nullptr, void *displayHandle=nullptr)
Return the context instance.
Definition context.cpp:371
A class representing an environment for PBR rendering.
Definition drawable_environment.h:46
TextureType
Types of environment textures managed by the DrawableEnvironment class.
Definition drawable_environment.h:114
Definition drawable_mesh_bgfx.h:40
std::shared_ptr< DrawableObject > clone() const &override
This member function is used to create a new copy of the DrawableObject. Each derived class must impl...
Definition drawable_mesh_bgfx.h:402
uint64_t updateAndBindMaterialUniforms(uint chunkNumber, bool imageBasedLighting) const
Sets and binds the material uniforms for the given triangle chunk, and returns the render state assoc...
Definition drawable_mesh_bgfx.h:431
const std::string & name() const override
Returns the name of the object.
Definition drawable_mesh_bgfx.h:414
std::shared_ptr< DrawableObject > clone() &&override
This member function is used to create a new DrawableObject that is a moved from the current one....
Definition drawable_mesh_bgfx.h:407
std::string & name() override
Returns a reference of the name of the object, that allows to modify it.
Definition drawable_mesh_bgfx.h:412
void draw(const DrawObjectSettings &settings) const override
This member function must draw the object. It will be called at every frame.
Definition drawable_mesh_bgfx.h:201
void drawId(const DrawObjectSettings &settings) const override
This member function should draw the object. It will be called on request when the renderer needs to ...
Definition drawable_mesh_bgfx.h:314
void init() override
This member function is called after the initialization of the Context. It must initialize and bind d...
Definition drawable_mesh_bgfx.h:199
virtual const std::string & name() const
Returns the name of the object.
Definition drawable_object.h:163
A class for representing and manipulating 2D images.
Definition image.h:48
Represents a Physically-Based Rendering (PBR) material.
Definition material.h:45
@ COUNT
Utility value to get the number of texture types.
AlphaMode
Defines the alpha rendering mode of the material.
Definition material.h:50
Definition matrix.h:34
The MeshRenderInfo class is a collection of rendering settings for a Mesh.
Definition mesh_render_info.h:61
Surface
List of possible settings for the surface primitive.
Definition mesh_render_info.h:148
The MeshRenderSettings class allows an easy management of render settings of a Mesh....
Definition mesh_render_settings.h:70
bool isPoints(MeshRenderInfo::Points p) const
Returns whether the given points option is set.
Definition mesh_render_settings.h:225
bool isSurface(MeshRenderInfo::Surface s) const
Returns whether the given surface option is set.
Definition mesh_render_settings.h:250
bool isWireframe(MeshRenderInfo::Wireframe w) const
Returns whether the given wireframe option is set.
Definition mesh_render_settings.h:270
bool isEdges(MeshRenderInfo::Edges e) const
Returns whether the given edges option is set.
Definition mesh_render_settings.h:295
Definition program_manager.h:36
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:41
Segment()
Default constructor. Creates a segment with endpoints at the origin.
Definition segment.h:66
HasEdges concepts is satisfied when at least one of its template types is (or inherits from) a vcl::m...
Definition edge_container.h:1064
HasFaces concepts is satisfied when at least one of its template types is (or inherits from) a vcl::m...
Definition face_container.h:1429
Concept that is evaluated true if a Mesh has the Materials component.
Definition mesh_requirements.h:88
Concept that checks if a Mesh has the Name component.
Definition mesh_requirements.h:96
Concept that checks if a Mesh has the TransformMatrix component.
Definition mesh_requirements.h:104
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:49
Definition pbr_viewer_settings.h:31