GLVis  v4.2
Accurate and flexible finite element visualization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
renderer.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-443271.
4 //
5 // This file is part of the GLVis visualization tool and library. For more
6 // information and source code availability see https://glvis.org.
7 //
8 // GLVis is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "renderer.hpp"
13 
14 namespace gl3
15 {
16 
17 // Beginning in OpenGL 3.0, there were two changes in texture format support:
18 // - The older single-channel internal format GL_ALPHA was deprecated in favor
19 // of GL_RED
20 // - New sized internal formats were introduced, e.g. GL_RGBA32F defines a 4-
21 // channel texture with each channel holding a 32-bit floating point value
22 //
23 // An additional complication is introduced with OpenGL ES 3/WebGL 2 - the
24 // unsized formats like GL_RED and GL_RGBA no longer support floating-point
25 // data being passed in, so use of the sized internal formats is obligatory in
26 // WebGL 2.
28 {
29 #ifdef __EMSCRIPTEN__
30  const std::string versionString
31  = reinterpret_cast<const char*>(glGetString(GL_VERSION));
32  if (versionString.find("OpenGL ES 3.0") != std::string::npos)
33  {
34  return false;
35  }
36  else
37  {
38  return true;
39  }
40 #else
41  return !GLEW_VERSION_3_0;
42 #endif
43 }
44 
45 void MeshRenderer::setAntialiasing(bool aa_status)
46 {
47  if (msaa_enable != aa_status)
48  {
49  msaa_enable = aa_status;
50  if (msaa_enable)
51  {
52  if (!feat_use_fbo_antialias)
53  {
54  glEnable(GL_MULTISAMPLE);
55  glEnable(GL_LINE_SMOOTH);
56  device->enableBlend();
57  }
58  device->setLineWidth(line_w_aa);
59  }
60  else
61  {
62  if (!feat_use_fbo_antialias)
63  {
64  glDisable(GL_MULTISAMPLE);
65  glDisable(GL_LINE_SMOOTH);
66  device->disableBlend();
67  }
68  device->setLineWidth(line_w);
69  }
70  }
71 }
72 
74 {
75  line_w = w;
76  if (device && !msaa_enable)
77  {
78  device->setLineWidth(line_w);
79  }
80 }
81 
83 {
84  line_w_aa = w;
85  if (device && msaa_enable)
86  {
87  device->setLineWidth(line_w_aa);
88  }
89 }
90 
91 void MeshRenderer::init()
92 {
93 #ifdef __EMSCRIPTEN__
94  const std::string versionString
95  = reinterpret_cast<const char*>(glGetString(GL_VERSION));
96  bool is_webgl2 = (versionString.find("OpenGL ES 3.0") != std::string::npos);
97  feat_use_fbo_antialias = is_webgl2;
98  if (feat_use_fbo_antialias)
99  {
100  glGetIntegerv(GL_MAX_SAMPLES, &msaa_samples);
101  }
102 #else
103  // TODO: we could also support ARB_framebuffer_object
104  feat_use_fbo_antialias = GLEW_VERSION_3_0;
105  glGetIntegerv(GL_MAX_SAMPLES, &msaa_samples);
106 #endif
107 }
108 
110 {
111  // elements containing opaque objects should be rendered first
112  RenderQueue sorted_queue = queue;
113  std::stable_partition(sorted_queue.begin(), sorted_queue.end(),
114  [](RenderQueue::value_type& renderPair)
115  {
116  return !renderPair.first.contains_translucent;
117  });
118  RenderBufHandle renderBufs[2];
119  FBOHandle msaaFb;
120  if (feat_use_fbo_antialias && msaa_enable)
121  {
122  GLuint colorBuf, depthBuf;
123  glGenRenderbuffers(1, &colorBuf);
124  glGenRenderbuffers(1, &depthBuf);
125  renderBufs[0] = RenderBufHandle(colorBuf);
126  renderBufs[1] = RenderBufHandle(depthBuf);
127 
128  GLuint fbo;
129  glGenFramebuffers(1, &fbo);
130 
131  int vp[4];
132  device->getViewport(vp);
133  int width = vp[2];
134  int height = vp[3];
135  glBindRenderbuffer(GL_RENDERBUFFER, colorBuf);
136  glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples,
137  GL_RGBA8, width, height);
138  glBindRenderbuffer(GL_RENDERBUFFER, depthBuf);
139  glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_samples,
140  GL_DEPTH_COMPONENT24, width, height);
141  glBindRenderbuffer(GL_RENDERBUFFER, 0);
142 
143  glBindFramebuffer(GL_FRAMEBUFFER, fbo);
144  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
145  GL_RENDERBUFFER, colorBuf);
146  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
147  GL_RENDERBUFFER, depthBuf);
148 
149  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
150  {
151  cerr << "Unable to create multisampled renderbuffer." << flush;
152  glDeleteFramebuffers(1, &fbo);
153  glBindFramebuffer(GL_FRAMEBUFFER, 0);
154  }
155  else
156  {
157  msaaFb = FBOHandle(fbo);
158  }
159 #ifndef __EMSCRIPTEN__
160  glEnable(GL_MULTISAMPLE);
161 #endif
162  }
163  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
164  for (auto& q_elem : sorted_queue)
165  {
166  const RenderParams& params = q_elem.first;
167  device->setTransformMatrices(params.model_view.mtx, params.projection.mtx);
168  device->setMaterial(params.mesh_material);
169  device->setNumLights(params.num_pt_lights);
170  for (int i = 0; i < params.num_pt_lights; i++)
171  {
172  device->setPointLight(i, params.lights[i]);
173  }
174  device->setAmbientLight(params.light_amb_scene);
175  device->setStaticColor(params.static_color);
176  device->setClipPlaneUse(params.use_clip_plane);
177  device->setClipPlaneEqn(params.clip_plane_eqn);
178  // aggregate buffers with common parameters
179  std::vector<int> tex_bufs, no_tex_bufs;
180  std::vector<TextBuffer*> text_bufs;
181  GlDrawable* curr_drawable = q_elem.second;
182  for (int i = 0; i < NUM_LAYOUTS; i++)
183  {
184  for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++)
185  {
186  if (curr_drawable->buffers[i][j])
187  {
189  {
190  tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle());
191  }
192  else
193  {
194  no_tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle());
195  }
196  }
197  if (curr_drawable->indexed_buffers[i][j])
198  {
200  {
201  tex_bufs.emplace_back(curr_drawable->indexed_buffers[i][j].get()->getHandle());
202  }
203  else
204  {
205  no_tex_bufs.emplace_back(
206  curr_drawable->indexed_buffers[i][j].get()->getHandle());
207  }
208  }
209  }
210  }
211  text_bufs.emplace_back(&curr_drawable->text_buffer);
212  if (params.contains_translucent)
213  {
214  device->enableBlend();
215  }
216  else
217  {
218  device->enableDepthWrite();
219  }
220  device->attachTexture(GLDevice::SAMPLER_COLOR, color_tex);
221  device->attachTexture(GLDevice::SAMPLER_ALPHA, alpha_tex);
222  for (auto buf : tex_bufs)
223  {
224  device->drawDeviceBuffer(buf);
225  }
226  device->detachTexture(GLDevice::SAMPLER_COLOR);
227  device->detachTexture(GLDevice::SAMPLER_ALPHA);
228  for (auto buf : no_tex_bufs)
229  {
230  device->drawDeviceBuffer(buf);
231  }
232  if (!params.contains_translucent)
233  {
234  device->enableBlend();
235  device->disableDepthWrite();
236  }
237  device->attachTexture(1, font_tex);
238  device->setNumLights(0);
239  for (TextBuffer* buf : text_bufs)
240  {
241  device->drawDeviceBuffer(*buf);
242  }
243  device->enableDepthWrite();
244  if (feat_use_fbo_antialias || !msaa_enable) { device->disableBlend(); }
245  }
246  if (feat_use_fbo_antialias && msaa_enable && msaaFb)
247  {
248  device->enableBlend();
249  int vp[4];
250  device->getViewport(vp);
251  int width = vp[2];
252  int height = vp[3];
253  GLuint colorBufId;
254  glGenRenderbuffers(1, &colorBufId);
255  RenderBufHandle colorBuf(colorBufId);
256 
257  GLuint fboId;
258  glGenFramebuffers(1, &fboId);
259  FBOHandle resolveFb(fboId);
260 
261  glBindRenderbuffer(GL_RENDERBUFFER, colorBuf);
262  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
263  glBindRenderbuffer(GL_RENDERBUFFER, 0);
264 
265  glBindFramebuffer(GL_FRAMEBUFFER, resolveFb);
266  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
267  GL_RENDERBUFFER, colorBuf);
268 
269  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
270  {
271  cerr << "Unable to create resolve renderbuffer." << endl;
272  glBindFramebuffer(GL_FRAMEBUFFER, 0);
273  }
274 
275  // bind our draw framebuffer and blit the multisampled image
276  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFb);
277  glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFb);
278  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
279  glBlitFramebuffer(0, 0, width, height,
280  0, 0, width, height,
281  GL_COLOR_BUFFER_BIT,
282  GL_NEAREST);
283 #ifndef __EMSCRIPTEN__
284  glDisable(GL_MULTISAMPLE);
285 #endif
286  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
287  glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb);
288  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
289  glBlitFramebuffer(0, 0, width, height,
290  0, 0, width, height,
291  GL_COLOR_BUFFER_BIT,
292  GL_LINEAR);
293  device->disableBlend();
294  }
295 }
296 
298 {
299  CaptureBuffer cbuf;
300  device->initXfbMode();
301  for (auto& q_elem : queue)
302  {
303  const RenderParams& params = q_elem.first;
304  device->setTransformMatrices(params.model_view.mtx, params.projection.mtx);
305  device->setMaterial(params.mesh_material);
306  device->setNumLights(params.num_pt_lights);
307  for (int i = 0; i < params.num_pt_lights; i++)
308  {
309  device->setPointLight(i, params.lights[i]);
310  }
311  device->setAmbientLight(params.light_amb_scene);
312  device->setStaticColor(params.static_color);
313  device->setClipPlaneUse(params.use_clip_plane);
314  device->setClipPlaneEqn(params.clip_plane_eqn);
315  // aggregate buffers with common parameters
316  std::vector<int> tex_bufs, no_tex_bufs;
317  std::vector<TextBuffer*> text_bufs;
318  GlDrawable* curr_drawable = q_elem.second;
319  for (int i = 0; i < NUM_LAYOUTS; i++)
320  {
321  for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++)
322  {
323  if (curr_drawable->buffers[i][j])
324  {
326  {
327  tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle());
328  }
329  else
330  {
331  no_tex_bufs.emplace_back(curr_drawable->buffers[i][j].get()->getHandle());
332  }
333  }
334  if (curr_drawable->indexed_buffers[i][j])
335  {
337  {
338  tex_bufs.emplace_back(curr_drawable->indexed_buffers[i][j].get()->getHandle());
339  }
340  else
341  {
342  no_tex_bufs.emplace_back(
343  curr_drawable->indexed_buffers[i][j].get()->getHandle());
344  }
345  }
346  }
347  }
348  text_bufs.emplace_back(&curr_drawable->text_buffer);
349 
350  device->attachTexture(GLDevice::SAMPLER_COLOR, color_tex);
351  device->attachTexture(GLDevice::SAMPLER_ALPHA, alpha_tex);
352  for (auto buf : tex_bufs)
353  {
354  device->captureXfbBuffer(*palette, cbuf, buf);
355  }
356  device->detachTexture(GLDevice::SAMPLER_COLOR);
357  device->detachTexture(GLDevice::SAMPLER_ALPHA);
358  for (auto buf : no_tex_bufs)
359  {
360  device->captureXfbBuffer(*palette, cbuf, buf);
361  }
362  if (!params.contains_translucent)
363  {
364  device->enableBlend();
365  device->disableDepthWrite();
366  }
367  device->attachTexture(1, font_tex);
368  device->setNumLights(0);
369  for (TextBuffer* buf : text_bufs)
370  {
371  device->captureXfbBuffer(cbuf, *buf);
372  }
373  }
374  device->exitXfbMode();
375  return cbuf;
376 }
377 
379 {
380  for (int i = 0; i < NUM_LAYOUTS; i++)
381  {
382  for (size_t j = 0; j < GlDrawable::NUM_SHAPES; j++)
383  {
384  if (buf->buffers[i][j])
385  {
386  device->bufferToDevice((array_layout) i, *(buf->buffers[i][j].get()));
387  }
388  if (buf->indexed_buffers[i][j])
389  {
390  device->bufferToDevice((array_layout) i, *(buf->indexed_buffers[i][j].get()));
391  }
392  }
393  }
394  device->bufferToDevice(buf->text_buffer);
395 }
396 
398 {
399  // enable depth testing
400  glDepthFunc(GL_LEQUAL);
401  glEnable(GL_DEPTH_TEST);
402  // enable polygon offset to expose mesh lines
403  glPolygonOffset(1,1);
404  glEnable(GL_POLYGON_OFFSET_FILL);
405  // use "over" blending equation
406  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
407  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
408  // generate a white default texture modulation with default texture will just
409  // pass through input color
410  GLuint default_texture;
411  glGenTextures(1, &default_texture);
412  glBindTexture(GL_TEXTURE_2D, default_texture);
413  int black_color = 0xFFFFFFFF;
414  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
415  &black_color);
416  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
417  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
418  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
419  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
420 
421  passthrough_texture = TextureHandle(default_texture);
422 }
423 
424 void GLDevice::setViewport(GLsizei w, GLsizei h)
425 {
426  vp_width = w;
427  vp_height = h;
428  glViewport(0, 0, w, h);
429 }
430 
431 void GLDevice::getViewport(GLint (&vp)[4])
432 {
433  vp[0] = vp[1] = 0;
434  vp[2] = vp_width;
435  vp[3] = vp_height;
436 }
437 
438 void GLDevice::setTransformMatrices(glm::mat4 model_view, glm::mat4 projection)
439 {
440  model_view_mtx = model_view;
441  proj_mtx = projection;
442 }
443 
445 {
446  for (const auto& entry : t_buf)
447  {
448  glm::vec3 raster = glm::project(
449  glm::vec3(entry.rx, entry.ry, entry.rz),
451  proj_mtx,
452  glm::vec4(0, 0, vp_width, vp_height));
453  capture.text.emplace_back(raster, glm::make_vec4(static_color.data()),
454  entry.text);
455  }
456 }
457 
458 }
glm::mat4 proj_mtx
Definition: renderer.hpp:103
glm::mat4 model_view_mtx
Definition: renderer.hpp:102
GlMatrix projection
Definition: renderer.hpp:41
virtual void setTransformMatrices(glm::mat4 model_view, glm::mat4 projection)
Definition: renderer.cpp:438
Handle< rboCleanup > RenderBufHandle
Definition: types.hpp:115
TextureHandle passthrough_texture
Definition: renderer.hpp:108
void render(const RenderQueue &queued)
Definition: renderer.cpp:109
void setLineWidth(float w)
Definition: renderer.cpp:73
std::array< float, 4 > light_amb_scene
Definition: renderer.hpp:47
vector< FeedbackText > text
Definition: renderer.hpp:93
std::array< Light, LIGHTS_MAX > lights
Definition: renderer.hpp:46
array_layout
Definition: types.hpp:170
CaptureBuffer capture(const RenderQueue &queued)
Definition: renderer.cpp:297
std::array< float, 4 > static_color
Definition: renderer.hpp:105
static bool useLegacyTextureFmts()
Definition: renderer.cpp:27
Handle< texCleanup > TextureHandle
Definition: types.hpp:113
glm::mat4 mtx
Definition: types.hpp:121
void buffer(GlDrawable *buf)
Definition: renderer.cpp:378
void getViewport(GLint(&vp)[4])
Definition: renderer.cpp:431
static const int SAMPLER_ALPHA
Definition: renderer.hpp:121
static const int SAMPLER_COLOR
Definition: renderer.hpp:120
virtual void captureXfbBuffer(PaletteState &pal, CaptureBuffer &capture, int hnd)=0
vector< pair< RenderParams, GlDrawable * > > RenderQueue
Definition: renderer.hpp:58
bool contains_translucent
Definition: renderer.hpp:55
void setLineWidthMS(float w)
Definition: renderer.cpp:82
std::array< float, 4 > static_color
Definition: renderer.hpp:48
void setAntialiasing(bool aa_status)
Definition: renderer.cpp:45
GlMatrix model_view
Definition: renderer.hpp:40
Material mesh_material
Definition: renderer.hpp:44
virtual void init()
Definition: renderer.cpp:397
std::array< double, 4 > clip_plane_eqn
Definition: renderer.hpp:52
void setViewport(GLsizei w, GLsizei h)
Definition: renderer.cpp:424
Handle< fboCleanup > FBOHandle
Definition: types.hpp:114