Visual Computing Library  devel
Loading...
Searching...
No Matches
drawable_mesh_bgfx.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
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/mesh/mesh_render_buffers.h>
31#include <vclib/bgfx/drawable/uniforms/mesh_render_settings_uniforms.h>
32
33#include <bgfx/bgfx.h>
34
35namespace vcl {
36
37template<MeshConcept MeshType>
38class DrawableMeshBGFX : public AbstractDrawableMesh, public MeshType
39{
40public:
41 // TODO: to be removed after shader benchmarks
42 enum class SurfaceProgramsType {
43 UBER,
44 SPLIT,
45 UBER_WITH_STATIC_IF,
46 };
47
48private:
49 using MRI = MeshRenderInfo;
50
51 mutable MeshRenderSettingsUniforms mMeshRenderSettingsUniforms;
52
53 Uniform mIdUniform = Uniform("u_meshId", bgfx::UniformType::Vec4);
54
55 // TODO: to be removed after shader benchmarks
56 SurfaceProgramsType mSurfaceProgramType = SurfaceProgramsType::UBER;
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 mMeshRenderSettingsUniforms.updateSettings(mMRS);
84 updateBuffers();
85 }
86
88
89 ~DrawableMeshBGFX() = default;
90
92 {
93 swap(drawableMesh);
94 return *this;
95 }
96
97 void swap(DrawableMeshBGFX& other)
98 {
99 using std::swap;
100 AbstractDrawableMesh::swap(other);
101 MeshType::swap(other);
102 swap(mMRB, other.mMRB);
103 swap(mMeshRenderSettingsUniforms, other.mMeshRenderSettingsUniforms);
104 }
105
106 friend void swap(DrawableMeshBGFX& a, DrawableMeshBGFX& b) { a.swap(b); }
107
109
110 // TODO: to be removed after shader benchmarks
111 void setSurfaceProgramType(SurfaceProgramsType type)
112 {
113 if (type != mSurfaceProgramType) {
114 std::cerr << "Program Type changed: ";
115 switch (type) {
116 case SurfaceProgramsType::UBER: std::cerr << "UBER\n"; break;
117 case SurfaceProgramsType::SPLIT: std::cerr << "SPLITTED\n"; break;
118 case SurfaceProgramsType::UBER_WITH_STATIC_IF:
119 std::cerr << "UBER_WITH_STATIC_IF\n";
120 break;
121 }
122 mSurfaceProgramType = type;
123 }
124 }
125
126 // AbstractDrawableMesh implementation
127
128 void updateBuffers(
129 MRI::BuffersBitSet buffersToUpdate = MRI::BUFFERS_ALL) override
130 {
131 if constexpr (HasName<MeshType>) {
132 AbstractDrawableMesh::name() = MeshType::name();
133 }
134
135 AbstractDrawableMesh::computeBoundingBox(
136 static_cast<const MeshType&>(*this));
137
138 mMRB.update(*this, buffersToUpdate);
139 mMRS.setRenderCapabilityFrom(*this);
140 setRenderSettings(mMRS);
141 }
142
143 void setRenderSettings(const MeshRenderSettings& rs) override
144 {
145 AbstractDrawableMesh::setRenderSettings(rs);
146 mMeshRenderSettingsUniforms.updateSettings(rs);
147 mMRB.updateEdgeSettings(rs);
148 mMRB.updateWireframeSettings(rs);
149 }
150
151 uint vertexNumber() const override { return MeshType::vertexNumber(); }
152
153 uint faceNumber() const override
154 {
155 if constexpr (HasFaces<MeshType>)
156 return MeshType::faceNumber();
157 else
158 return 0;
159 }
160
161 uint edgeNumber() const override
162 {
163 if constexpr (HasEdges<MeshType>)
164 return MeshType::edgeNumber();
165 else
166 return 0;
167 }
168
169 vcl::Matrix44d transformMatrix() const override
170 {
171 if constexpr (HasTransformMatrix<MeshType>) {
172 return MeshType::transformMatrix().template cast<double>();
173 }
174 else {
176 }
177 }
178
179 View<MatIt> materials() const override
180 {
181 if constexpr (HasMaterials<MeshType>) {
182 return MeshType::materials();
183 }
184 else {
185 return View<MatIt>();
186 }
187 }
188
189 const Image& textureImage(const std::string& path) const override
190 {
191 if constexpr (HasMaterials<MeshType>) {
192 return MeshType::textureImage(path);
193 }
194 else {
195 return AbstractDrawableMesh::textureImage(path);
196 }
197 }
198
199 // DrawableObject implementation
200
201 void init() override {}
202
203 void draw(const DrawObjectSettings& settings) const override
204 {
205 using enum VertFragProgram;
206
207 ProgramManager& pm = Context::instance().programManager();
208
211
212 vcl::Matrix44f model = vcl::Matrix44f::Identity();
213
214 if constexpr (HasTransformMatrix<MeshType>) {
215 model = MeshType::transformMatrix().template cast<float>();
216 }
217
218 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
219 for (uint i = 0; i < mMRB.triangleChunksNumber(); ++i) {
221 uint64_t materialState = mMRB.bindMaterials(mMRS, i, *this);
222 // Bind textures before vertex buffers!!
223 mMRB.bindTextures(mMRS, i, *this);
224 mMRB.bindVertexBuffers(mMRS);
225 mMRB.bindIndexBuffers(mMRS, i);
226
227 bindUniforms();
228
229 if (settings.pbrMode) {
231 }
232
233 bgfx::setState(surfaceState);
234 bgfx::setTransform(model.data());
235
236 if (settings.pbrMode) {
237 ProgramManager& pm = Context::instance().programManager();
238
239 bgfx::submit(
240 settings.viewId,
241 pm.getProgram<DRAWABLE_MESH_SURFACE_UBER_PBR>());
242 }
243 else {
244 bgfx::submit(settings.viewId, surfaceProgramSelector());
245 }
246 }
247 }
248
249 if (mMRS.isWireframe(MRI::Wireframe::VISIBLE)) {
250 bgfx::setTransform(model.data());
251
252 mMRB.drawWireframeLines(settings.viewId);
253 }
254
255 if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
256 bgfx::setTransform(model.data());
257
258 mMRB.drawEdgeLines(settings.viewId);
259 }
260
261 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
262 if (!Context::instance().supportsCompute()) {
263 // 1 px vertices
264 mMRB.bindVertexBuffers(mMRS);
265 bindUniforms();
266
267 bgfx::setState(state | BGFX_STATE_PT_POINTS);
268 bgfx::setTransform(model.data());
269
270 bgfx::submit(
271 settings.viewId, pm.getProgram<DRAWABLE_MESH_POINTS>());
272 }
273 else {
274 // generate splats (quads) lazy
275 mMRB.computeQuadVertexBuffers(*this, settings.viewId);
276
277 // render splats
278 mMRB.bindVertexQuadBuffer();
279 bindUniforms();
280
281 bgfx::setState(state);
282 bgfx::setTransform(model.data());
283
284 bgfx::submit(
285 settings.viewId,
286 pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE>());
287 }
288 }
289 }
290
291 void drawId(const DrawObjectSettings& settings) const override
292 {
293 using enum VertFragProgram;
294
295 ProgramManager& pm = Context::instance().programManager();
296
301 // write alpha as is
302
303 vcl::Matrix44f model = vcl::Matrix44f::Identity();
304
305 if constexpr (HasTransformMatrix<MeshType>) {
306 model = MeshType::transformMatrix().template cast<float>();
307 }
308
309 const std::array<float, 4> idFloat = {
310 Uniform::uintBitsToFloat(settings.objectId), 0.0f, 0.0f, 0.0f};
311
312 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
313 mMRB.bindVertexBuffers(mMRS);
314 mMRB.bindIndexBuffers(mMRS);
315 mIdUniform.bind(&idFloat);
316
317 bgfx::setState(state);
318 bgfx::setTransform(model.data());
319
320 bgfx::submit(
321 settings.viewId, pm.getProgram<DRAWABLE_MESH_SURFACE_ID>());
322 }
323
324 // if (mMRS.isWireframe(MRI::Wireframe::VISIBLE)) {
325 // mMRB.bindVertexBuffers(mMRS);
326 // mMRB.bindIndexBuffers(mMRS, MRI::Buffers::WIREFRAME);
327 // mIdUniform.bind(&idFloat);
328
329 // bgfx::setState(state | BGFX_STATE_PT_LINES);
330 // bgfx::setTransform(model.data());
331
332 // bgfx::submit(viewId,
333 // pm.getProgram<DRAWABLE_MESH_WIREFRAME_ID>());
334 // }
335
336 // if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
337 // mMRB.bindVertexBuffers(mMRS);
338 // mMRB.bindIndexBuffers(mMRS, MRI::Buffers::EDGES);
339 // mIdUniform.bind(&idFloat);
340
341 // bgfx::setState(state | BGFX_STATE_PT_LINES);
342 // bgfx::setTransform(model.data());
343
344 // bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_EDGES_ID>());
345 // }
346
347 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
348 if (!Context::instance().supportsCompute()) {
349 // 1 px vertices
350 mMRB.bindVertexBuffers(mMRS);
351 mIdUniform.bind(&idFloat);
352
353 bgfx::setState(state | BGFX_STATE_PT_POINTS);
354 bgfx::setTransform(model.data());
355
356 bgfx::submit(
357 settings.viewId, pm.getProgram<DRAWABLE_MESH_POINTS_ID>());
358 }
359 else {
360 // generate splats (quads) lazy
361 mMRB.computeQuadVertexBuffers(*this, settings.viewId);
362
363 // render splats
364 mMRB.bindVertexQuadBuffer();
365 bindUniforms();
366 mIdUniform.bind(&idFloat);
367
368 bgfx::setState(state);
369 bgfx::setTransform(model.data());
370
371 bgfx::submit(
372 settings.viewId,
373 pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE_ID>());
374 }
375 }
376 }
377
378 std::shared_ptr<DrawableObject> clone() const& override
379 {
380 return std::make_shared<DrawableMeshBGFX>(*this);
381 }
382
383 std::shared_ptr<DrawableObject> clone() && override
384 {
385 return std::make_shared<DrawableMeshBGFX>(std::move(*this));
386 }
387
388 void setVisibility(bool vis) override
389 {
391 mMeshRenderSettingsUniforms.updateSettings(mMRS);
392 }
393
394 std::string& name() override { return MeshType::name(); }
395
396 const std::string& name() const override { return MeshType::name(); }
397
398protected:
399 void bindUniforms() const
400 {
401 mMeshRenderSettingsUniforms.bind();
402 mMRB.bindUniforms();
403 }
404
405 // TODO: change this function implementation after shader benchmarks
406 bgfx::ProgramHandle surfaceProgramSelector() const
407 {
408 using enum VertFragProgram;
409
410 ProgramManager& pm = Context::instance().programManager();
411
412 uint mul = 0;
413 uint off = 0;
414
415 {
416 using enum MeshRenderInfo::Surface;
417 if (mMRS.isSurface(SHADING_FLAT)) {
418 mul = 1;
419 }
420 if (mMRS.isSurface(SHADING_SMOOTH)) {
421 mul = 2;
422 }
423 if (mMRS.isSurface(COLOR_MESH)) {
424 off = 1;
425 }
426 if (mMRS.isSurface(COLOR_FACE)) {
427 off = 2;
428 }
429 if (mMRS.isSurface(COLOR_USER)) {
430 off = 3;
431 }
432 if (mMRS.isSurface(COLOR_VERTEX_TEX)) {
433 off = 4;
434 }
435 if (mMRS.isSurface(COLOR_WEDGE_TEX)) {
436 off = 5;
437 }
438 }
439
440 VertFragProgram p = static_cast<VertFragProgram>(6 * mul + off);
441
442 if (mSurfaceProgramType == SurfaceProgramsType::SPLIT) {
443 static const std::array<bgfx::ProgramHandle, 18>
444 surfaceProgramHandles = {
445 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX>(),
446 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH>(),
447 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE>(),
448 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER>(),
449 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX>(),
450 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE>(),
451 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX>(),
452 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH>(),
453 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE>(),
454 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER>(),
455 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX>(),
456 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE>(),
457 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX>(),
458 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH>(),
459 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE>(),
460 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER>(),
461 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX>(),
462 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE>()};
463
464 return surfaceProgramHandles[toUnderlying(p)];
465 }
466
467 if (mSurfaceProgramType == SurfaceProgramsType::UBER_WITH_STATIC_IF) {
468 static const std::array<bgfx::ProgramHandle, 18>
469 surfaceProgramHandles = {
470 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX_SI>(),
471 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH_SI>(),
472 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE_SI>(),
473 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER_SI>(),
474 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX_SI>(),
475 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE_SI>(),
476 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX_SI>(),
477 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH_SI>(),
478 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE_SI>(),
479 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER_SI>(),
480 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX_SI>(),
481 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE_SI>(),
482 pm.getProgram<
483 DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX_SI>(),
484 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH_SI>(),
485 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE_SI>(),
486 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER_SI>(),
487 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX_SI>(),
488 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE_SI>()};
489
490 return surfaceProgramHandles[toUnderlying(p)];
491 }
492
493 return pm.getProgram<DRAWABLE_MESH_SURFACE_UBER>();
494 }
495};
496
497} // namespace vcl
498
499#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
void setVisibility(bool vis) override
This member function is used to set the visibility of the object.
Definition abstract_drawable_mesh.h:90
The BitSet class allows to treat an integral type as an array of booleans of a guaranteed size.
Definition bit_set.h:52
A class representing a box in N-dimensional space.
Definition box.h:46
Box()
The Empty constructor of a box, initializes a null box.
Definition box.h:65
static Context & instance(void *windowHandle=nullptr, void *displayHandle=nullptr)
Return the context instance.
Definition context.cpp:371
Definition drawable_mesh_bgfx.h:39
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:378
const std::string & name() const override
Returns the name of the object.
Definition drawable_mesh_bgfx.h:396
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:383
std::string & name() override
Returns a reference of the name of the object, that allows to modify it.
Definition drawable_mesh_bgfx.h:394
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:203
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:291
void setVisibility(bool vis) override
This member function is used to set the visibility of the object.
Definition drawable_mesh_bgfx.h:388
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:201
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
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
Definition mesh_render_settings_uniforms.h:34
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
The Uniform class wraps a bgfx::UniformHandle and provides a simple interface to set the uniform data...
Definition uniform.h:43
static float uintBitsToFloat(uint bits)
Utility function to reinterpret the bits of an unsigned integer as a float.
Definition uniform.h:155
void bind(const void *data) const
Sets the uniform data for the current shader program.
Definition uniform.h:144
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