Visual Computing Library  devel
Loading...
Searching...
No Matches
drawable_mesh.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_H
24#define VCL_BGFX_DRAWABLE_DRAWABLE_MESH_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 Box3d mBoundingBox;
52
53 mutable MeshRenderSettingsUniforms mMeshRenderSettingsUniforms;
54
55 Uniform mIdUniform = Uniform("u_meshId", bgfx::UniformType::Vec4);
56
57 // TODO: to be removed after shader benchmarks
58 SurfaceProgramsType mSurfaceProgramType = SurfaceProgramsType::UBER;
59
60protected:
62
63public:
64 DrawableMeshBGFX() = default;
65
66 DrawableMeshBGFX(const MeshType& mesh) :
67 AbstractDrawableMesh(mesh), MeshType(mesh)
68 {
69 updateBuffers();
70 }
71
72 DrawableMeshBGFX(MeshType&& mesh) :
73 AbstractDrawableMesh(mesh), MeshType(std::move(mesh))
74 {
75 updateBuffers();
76 }
77
80 MeshType(drawableMesh), mBoundingBox(drawableMesh.mBoundingBox),
81 mMeshRenderSettingsUniforms(
82 drawableMesh.mMeshRenderSettingsUniforms)
83 {
84 if constexpr (HasName<MeshType>) {
86 }
87 mMRB.update(*this);
88 }
89
91
92 ~DrawableMeshBGFX() = default;
93
95 {
96 swap(drawableMesh);
97 return *this;
98 }
99
100 void swap(DrawableMeshBGFX& other)
101 {
102 using std::swap;
103 AbstractDrawableMesh::swap(other);
104 MeshType::swap(other);
105 swap(mBoundingBox, other.mBoundingBox);
106 swap(mMRB, other.mMRB);
107 swap(mMeshRenderSettingsUniforms, other.mMeshRenderSettingsUniforms);
108 }
109
110 friend void swap(DrawableMeshBGFX& a, DrawableMeshBGFX& b) { a.swap(b); }
111
112 // TODO: to be removed after shader benchmarks
113 void setSurfaceProgramType(SurfaceProgramsType type)
114 {
115 if (type != mSurfaceProgramType) {
116 std::cerr << "Program Type changed: ";
117 switch (type) {
118 case SurfaceProgramsType::UBER: std::cerr << "UBER\n"; break;
119 case SurfaceProgramsType::SPLIT: std::cerr << "SPLITTED\n"; break;
120 case SurfaceProgramsType::UBER_WITH_STATIC_IF:
121 std::cerr << "UBER_WITH_STATIC_IF\n";
122 break;
123 }
124 mSurfaceProgramType = type;
125 }
126 }
127
128 // AbstractDrawableMesh implementation
129
130 void updateBuffers(
131 MRI::BuffersBitSet buffersToUpdate = MRI::BUFFERS_ALL) override
132 {
133 if constexpr (HasName<MeshType>) {
134 AbstractDrawableMesh::name() = MeshType::name();
135 }
136
138 if constexpr (vcl::HasBoundingBox<MeshType>) {
139 if (this->MeshType::boundingBox().isNull()) {
140 bbToInitialize = true;
141 }
142 else {
143 mBoundingBox =
144 this->MeshType::boundingBox().template cast<double>();
145 }
146 }
147
148 if (bbToInitialize) {
149 mBoundingBox = vcl::boundingBox(*this);
150 }
151
152 if constexpr (HasTransformMatrix<MeshType>) {
153 mBoundingBox.min() *=
154 MeshType::transformMatrix().template cast<double>();
155 mBoundingBox.max() *=
156 MeshType::transformMatrix().template cast<double>();
157 }
158
159 mMRB.update(*this, buffersToUpdate);
160 mMRS.setRenderCapabilityFrom(*this);
161 mMeshRenderSettingsUniforms.updateSettings(mMRS);
162 }
163
164 void setRenderSettings(const MeshRenderSettings& rs) override
165 {
166 AbstractDrawableMesh::setRenderSettings(rs);
167 mMeshRenderSettingsUniforms.updateSettings(rs);
168 }
169
170 uint vertexNumber() const override { return MeshType::vertexNumber(); }
171
172 uint faceNumber() const override
173 {
174 if constexpr (HasFaces<MeshType>)
175 return MeshType::faceNumber();
176 else
177 return 0;
178 }
179
180 uint edgeNumber() const override
181 {
182 if constexpr (HasEdges<MeshType>)
183 return MeshType::edgeNumber();
184 else
185 return 0;
186 }
187
188 vcl::Matrix44d transformMatrix() const override
189 {
190 if constexpr (HasTransformMatrix<MeshType>) {
191 return MeshType::transformMatrix().template cast<double>();
192 }
193 else {
195 }
196 }
197
198 std::vector<std::string> textures() const override
199 {
200 std::vector<std::string> txs;
201 if constexpr (HasTexturePaths<MeshType>) {
202 txs.reserve(MeshType::textureNumber());
203 for (const auto& tpath : MeshType::texturePaths()) {
204 txs.push_back(tpath);
205 }
206 }
207 return txs;
208 }
209
210 // DrawableObject implementation
211
212 void init() override {}
213
214 void draw(uint viewId) const override
215 {
216 using enum VertFragProgram;
217
218 ProgramManager& pm = Context::instance().programManager();
219
222
223 vcl::Matrix44f model = vcl::Matrix44f::Identity();
224
225 if constexpr (HasTransformMatrix<MeshType>) {
226 model = MeshType::transformMatrix().template cast<float>();
227 }
228
229 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
230 mMRB.bindTextures(); // Bind textures before vertex buffers!!
231 mMRB.bindVertexBuffers(mMRS);
232 mMRB.bindIndexBuffers(mMRS);
233 bindUniforms();
234
235 bgfx::setState(state);
236 bgfx::setTransform(model.data());
237
238 bgfx::submit(viewId, surfaceProgramSelector());
239 }
240
241 if (mMRS.isWireframe(MRI::Wireframe::VISIBLE)) {
242 mMRB.bindVertexBuffers(mMRS);
243 mMRB.bindIndexBuffers(mMRS, MRI::Buffers::WIREFRAME);
244 bindUniforms();
245
246 bgfx::setState(state | BGFX_STATE_PT_LINES);
247 bgfx::setTransform(model.data());
248
249 bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_WIREFRAME>());
250 }
251
252 if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
253 mMRB.bindVertexBuffers(mMRS);
254 mMRB.bindIndexBuffers(mMRS, MRI::Buffers::EDGES);
255 bindUniforms();
256
257 bgfx::setState(state | BGFX_STATE_PT_LINES);
258 bgfx::setTransform(model.data());
259
260 bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_EDGES>());
261 }
262
263 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
264 if (!Context::instance().supportsCompute()) {
265 // 1 px vertices
266 mMRB.bindVertexBuffers(mMRS);
267 bindUniforms();
268
269 bgfx::setState(state | BGFX_STATE_PT_POINTS);
270 bgfx::setTransform(model.data());
271
272 bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_POINTS>());
273 }
274 else {
275 // generate splats (quads) lazy
276 mMRB.computeQuadVertexBuffers(*this, viewId);
277
278 // render splats
279 mMRB.bindVertexQuadBuffer();
280 bindUniforms();
281
282 bgfx::setState(state);
283 bgfx::setTransform(model.data());
284
285 bgfx::submit(
286 viewId, pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE>());
287 }
288 }
289 }
290
291 void drawId(uint viewId, uint id) 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(id), 0.0f, 0.0f, 0.0f};
311
312 if (mMRS.isSurface(MRI::Surface::VISIBLE)) {
313 mMRB.bindTextures(); // Bind textures before vertex buffers!!
314 mMRB.bindVertexBuffers(mMRS);
315 mMRB.bindIndexBuffers(mMRS);
316 mIdUniform.bind(&idFloat);
317
318 bgfx::setState(state);
319 bgfx::setTransform(model.data());
320
321 bgfx::submit(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, pm.getProgram<DRAWABLE_MESH_WIREFRAME_ID>());
333 }
334
335 if (mMRS.isEdges(MRI::Edges::VISIBLE)) {
336 mMRB.bindVertexBuffers(mMRS);
337 mMRB.bindIndexBuffers(mMRS, MRI::Buffers::EDGES);
338 mIdUniform.bind(&idFloat);
339
340 bgfx::setState(state | BGFX_STATE_PT_LINES);
341 bgfx::setTransform(model.data());
342
343 bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_EDGES_ID>());
344 }
345
346 if (mMRS.isPoints(MRI::Points::VISIBLE)) {
347 if (!Context::instance().supportsCompute()) {
348 // 1 px vertices
349 mMRB.bindVertexBuffers(mMRS);
350 mIdUniform.bind(&idFloat);
351
352 bgfx::setState(state | BGFX_STATE_PT_POINTS);
353 bgfx::setTransform(model.data());
354
355 bgfx::submit(viewId, pm.getProgram<DRAWABLE_MESH_POINTS_ID>());
356 }
357 else {
358 // generate splats (quads) lazy
359 mMRB.computeQuadVertexBuffers(*this, viewId);
360
361 // render splats
362 mMRB.bindVertexQuadBuffer();
363 bindUniforms();
364 mIdUniform.bind(&idFloat);
365
366 bgfx::setState(state);
367 bgfx::setTransform(model.data());
368
369 bgfx::submit(
370 viewId, pm.getProgram<DRAWABLE_MESH_POINTS_INSTANCE_ID>());
371 }
372 }
373 }
374
375 Box3d boundingBox() const override { return mBoundingBox; }
376
377 std::shared_ptr<DrawableObject> clone() const& override
378 {
379 return std::make_shared<DrawableMeshBGFX>(*this);
380 }
381
382 std::shared_ptr<DrawableObject> clone() && override
383 {
384 return std::make_shared<DrawableMeshBGFX>(std::move(*this));
385 }
386
387 void setVisibility(bool vis) override
388 {
390 mMeshRenderSettingsUniforms.updateSettings(mMRS);
391 }
392
393 std::string& name() override { return MeshType::name(); }
394
395 const std::string& name() const override { return MeshType::name(); }
396
397protected:
398 void bindUniforms() const
399 {
400 mMeshRenderSettingsUniforms.bind();
401 mMRB.bindUniforms();
402 }
403
404 // TODO: change this function implementation after shader benchmarks
405 bgfx::ProgramHandle surfaceProgramSelector() const
406 {
407 using enum VertFragProgram;
408
409 ProgramManager& pm = Context::instance().programManager();
410
411 uint mul = 0;
412 uint off = 0;
413
414 {
415 using enum MeshRenderInfo::Surface;
416 if (mMRS.isSurface(SHADING_FLAT)) {
417 mul = 1;
418 }
419 if (mMRS.isSurface(SHADING_SMOOTH)) {
420 mul = 2;
421 }
422 if (mMRS.isSurface(COLOR_MESH)) {
423 off = 1;
424 }
425 if (mMRS.isSurface(COLOR_FACE)) {
426 off = 2;
427 }
428 if (mMRS.isSurface(COLOR_USER)) {
429 off = 3;
430 }
431 if (mMRS.isSurface(COLOR_VERTEX_TEX)) {
432 off = 4;
433 }
434 if (mMRS.isSurface(COLOR_WEDGE_TEX)) {
435 off = 5;
436 }
437 }
438
439 VertFragProgram p = static_cast<VertFragProgram>(6 * mul + off);
440
441 if (mSurfaceProgramType == SurfaceProgramsType::SPLIT) {
442 static const std::array<bgfx::ProgramHandle, 18>
443 surfaceProgramHandles = {
444 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX>(),
445 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH>(),
446 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE>(),
447 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER>(),
448 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX>(),
449 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE>(),
450 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX>(),
451 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH>(),
452 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE>(),
453 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER>(),
454 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX>(),
455 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE>(),
456 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX>(),
457 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH>(),
458 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE>(),
459 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER>(),
460 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX>(),
461 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE>()};
462
463 return surfaceProgramHandles[toUnderlying(p)];
464 }
465
466 if (mSurfaceProgramType == SurfaceProgramsType::UBER_WITH_STATIC_IF) {
467 static const std::array<bgfx::ProgramHandle, 18>
468 surfaceProgramHandles = {
469 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_VERTEX_SI>(),
470 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_MESH_SI>(),
471 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_FACE_SI>(),
472 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_COLOR_USER_SI>(),
473 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_VERTEX_SI>(),
474 pm.getProgram<DRAWABLE_MESH_SURFACE_NONE_TEX_WEDGE_SI>(),
475 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_VERTEX_SI>(),
476 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_MESH_SI>(),
477 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_FACE_SI>(),
478 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_COLOR_USER_SI>(),
479 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_VERTEX_SI>(),
480 pm.getProgram<DRAWABLE_MESH_SURFACE_FLAT_TEX_WEDGE_SI>(),
481 pm.getProgram<
482 DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_VERTEX_SI>(),
483 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_MESH_SI>(),
484 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_FACE_SI>(),
485 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_COLOR_USER_SI>(),
486 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_VERTEX_SI>(),
487 pm.getProgram<DRAWABLE_MESH_SURFACE_SMOOTH_TEX_WEDGE_SI>()};
488
489 return surfaceProgramHandles[toUnderlying(p)];
490 }
491
492 return pm.getProgram<DRAWABLE_MESH_SURFACE_UBER>();
493 }
494};
495
496} // namespace vcl
497
498#endif // VCL_BGFX_DRAWABLE_DRAWABLE_MESH_H
The AbstractDrawableMesh class is the base class for all the drawable meshes in the VCLib render syst...
Definition abstract_drawable_mesh.h:41
void setVisibility(bool vis)
This member function is used to set the visibility of the object.
Definition abstract_drawable_mesh.h:80
The BitSet class allows to treat an integral type as an array of booleans of a guaranteed size.
Definition bit_set.h:52
PointT & max()
Returns a reference to the maximum point of the box.
Definition box.h:104
PointT & min()
Returns a reference to the minimum point of the box.
Definition box.h:90
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.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.h:377
const std::string & name() const override
Returns the name of the object.
Definition drawable_mesh.h:395
Box3d boundingBox() const override
This member function is used to find a good camera position to render object. It should return the th...
Definition drawable_mesh.h:375
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.h:382
std::string & name() override
Returns a reference of the name of the object, that allows to modify it.
Definition drawable_mesh.h:393
void draw(uint viewId) const override
This member function must draw the object. It will be called at every frame.
Definition drawable_mesh.h:214
void drawId(uint viewId, uint id) const override
This member function should draw the object. It will be called on request when the renderer needs to ...
Definition drawable_mesh.h:291
void setVisibility(bool vis) override
This member function is used to set the visibility of the object.
Definition drawable_mesh.h:387
void init() override
This member function is called after the initialization of the Context. It must initialize and bind d...
Definition drawable_mesh.h:212
virtual const std::string & name() const
Returns the name of the object.
Definition drawable_object.h:164
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:147
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
Concept that is evaluated true if a Mesh has the BoundingBox component.
Definition mesh_requirements.h:53
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:1389
Concept that checks if a Mesh has the Name component.
Definition mesh_requirements.h:88
Concept that checks if a Mesh has the TexturePaths component.
Definition mesh_requirements.h:105
Concept that checks if a Mesh has the TransformMatrix component.
Definition mesh_requirements.h:114
auto boundingBox(const PointType &p)
Compute the bounding box of a single point.
Definition bounding_box.h:59