GLVis  v4.2
Accurate and flexible finite element visualization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
renderer_ff.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_ff.hpp"
13 #include "attr_traits.hpp"
14 #include "../aux_vis.hpp"
15 
16 namespace gl3
17 {
18 
19 template<typename TVtx>
20 void setupFFVertexArray(TVtx* buffer)
21 {
22  static_assert(AttrCoord<TVtx>::exists,
23  "Invalid vertex type, requires at least TVtx::coord to be present.");
27  glClientActiveTexture(GL_TEXTURE0);
29  glClientActiveTexture(GL_TEXTURE1);
31 }
32 
33 template<typename TVtx>
35 {
39  glClientActiveTexture(GL_TEXTURE0);
41  glClientActiveTexture(GL_TEXTURE1);
43 }
44 
45 template<typename TVtx>
46 void FFGLDevice::bufferFFDeviceImpl(const VertexBuffer<TVtx>& buf)
47 {
48  glNewList(disp_lists[buf.getHandle()].list, GL_COMPILE);
49  setupFFVertexArray((TVtx*)buf.getData());
50  glDrawArrays(buf.getShape(), 0, buf.count());
51  glEndList();
52  clearFFVertexArray<TVtx>();
53 }
54 
55 template<typename TVtx>
56 void FFGLDevice::bufferFFDeviceImpl(const IndexedVertexBuffer<TVtx>& buf)
57 {
58  glNewList(disp_lists[buf.getHandle()].list, GL_COMPILE);
59  setupFFVertexArray((TVtx*)buf.getData());
60  glDrawElements(buf.getShape(), buf.getIndices().size(), GL_UNSIGNED_INT,
61  buf.getIndices().data());
62  glEndList();
63  clearFFVertexArray<TVtx>();
64 }
65 
67 {
69  // Fixed-function pipeline parameters
70  glEnable(GL_NORMALIZE);
71  glShadeModel(GL_SMOOTH);
72  glEnable(GL_COLOR_MATERIAL);
73  glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
74  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
75  // Texturing is set up such that the output color is computed as follows:
76  // - color_out.rgb = color_in.rgb * tex0.rgb
77  // - color_out.a = tex1.a
78  // Texture unit 0 should contain the color palette, while texture unit 1
79  // contains either the transparency alpha channel, or the font texture
80  glActiveTexture(GL_TEXTURE0);
81  glEnable(GL_TEXTURE_2D);
82  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
83  glActiveTexture(GL_TEXTURE1);
84  glEnable(GL_TEXTURE_2D);
85  // With a GL_ALPHA format texture loaded, GL_MODULATE will pass through the
86  // fragment rgb value.
87  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
88 }
89 
90 void FFGLDevice::setTransformMatrices(glm::mat4 model_view,
91  glm::mat4 projection)
92 {
93  GLDevice::setTransformMatrices(model_view, projection);
94  glMatrixMode(GL_MODELVIEW);
95  glLoadMatrixf(glm::value_ptr(model_view));
96  glMatrixMode(GL_PROJECTION);
97  glLoadMatrixf(glm::value_ptr(projection));
98 }
99 
101 {
102  if (i == 0)
103  {
104  glDisable(GL_LIGHTING);
105  return;
106  }
107  glEnable(GL_LIGHTING);
108  for (int light_id = 0; light_id < i; light_id++)
109  {
110  glEnable(GL_LIGHT0 + light_id);
111  }
112  for (int light_id = i; light_id < LIGHTS_MAX; light_id++)
113  {
114  glDisable(GL_LIGHT0 + light_id);
115  }
116 }
117 
119 {
120  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat.diffuse.data());
121  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat.ambient.data());
122  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat.specular.data());
123  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat.shininess);
124 
125  GLfloat memis[] = { 0.0, 0.0, 0.0, 1.0 };
126  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, memis);
127 }
128 
130 {
131  glMatrixMode(GL_MODELVIEW);
132  glPushMatrix();
133  glLoadIdentity();
134  glLightfv(GL_LIGHT0 + i, GL_POSITION, lt.position.data());
135 
136  GLfloat lambi[] = { 0.0, 0.0, 0.0, 1.0 };
137  glLightfv(GL_LIGHT0 + i, GL_AMBIENT, lambi);
138 
139  glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lt.diffuse.data());
140  glLightfv(GL_LIGHT0 + i, GL_SPECULAR, lt.specular.data());
141  glPopMatrix();
142 }
143 
144 void FFGLDevice::setAmbientLight(const std::array<float, 4>& amb)
145 {
146  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &amb[0]);
147 }
148 
150 {
151  if (enable) { glEnable(GL_CLIP_PLANE0); }
152  else { glDisable(GL_CLIP_PLANE0); }
153 }
154 
155 void FFGLDevice::setClipPlaneEqn(const std::array<double, 4>& eqn)
156 {
157  glClipPlane(GL_CLIP_PLANE0, eqn.data());
158 }
159 
161 {
162  if (buf.getHandle() == 0)
163  {
164  if (buf.count() == 0) { return; }
165  GLuint new_hnd = glGenLists(1);
166  buf.setHandle(disp_lists.size());
167  disp_lists.emplace_back(DispListData_{new_hnd, buf.getShape(), buf.count(), layout});
168  }
169  else
170  {
171  disp_lists[buf.getHandle()].count = buf.count();
172  }
173 
174  switch (layout)
175  {
176  case Vertex::layout:
177  bufferFFDeviceImpl(static_cast<const VertexBuffer<Vertex>&>(buf));
178  break;
179  case VertexColor::layout:
180  bufferFFDeviceImpl(static_cast<const VertexBuffer<VertexColor>&>(buf));
181  break;
182  case VertexTex::layout:
183  bufferFFDeviceImpl(static_cast<const VertexBuffer<VertexTex>&>(buf));
184  break;
185  case VertexNorm::layout:
186  bufferFFDeviceImpl(static_cast<const VertexBuffer<VertexNorm>&>(buf));
187  break;
189  bufferFFDeviceImpl(static_cast<const VertexBuffer<VertexNormColor>&>(buf));
190  break;
192  bufferFFDeviceImpl(static_cast<const VertexBuffer<VertexNormTex>&>(buf));
193  break;
194  default:
195  cerr << "WARNING: Unhandled vertex layout " << layout << endl;
196  }
197 }
198 
200 {
201  if (buf.getHandle() == 0)
202  {
203  if (buf.count() == 0) { return; }
204  GLuint new_hnd = glGenLists(1);
205  buf.setHandle(disp_lists.size());
206  disp_lists.emplace_back(DispListData_{new_hnd, buf.getShape(), buf.getIndices().size(), layout});
207  }
208  else
209  {
210  disp_lists[buf.getHandle()].count = buf.getIndices().size();
211  }
212 
213  switch (layout)
214  {
215  case Vertex::layout:
216  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<Vertex>&>(buf));
217  break;
218  case VertexColor::layout:
219  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<VertexColor>&>(buf));
220  break;
221  case VertexTex::layout:
222  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<VertexTex>&>(buf));
223  break;
224  case VertexNorm::layout:
225  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<VertexNorm>&>(buf));
226  break;
228  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<VertexNormColor>&>
229  (buf));
230  break;
232  bufferFFDeviceImpl(static_cast<const IndexedVertexBuffer<VertexNormTex>&>(buf));
233  break;
234  default:
235  cerr << "WARNING: Unhandled vertex layout " << layout << endl;
236  }
237 }
238 
240 {
241  // we can't really do anything here can only compute offset matrix at draw
242 }
243 
245 {
246  if (hnd == 0) { return; }
247  if (disp_lists[hnd].count == 0) { return; }
248  if (disp_lists[hnd].layout == Vertex::layout
249  || disp_lists[hnd].layout == VertexNorm::layout)
250  {
251  glColor4fv(static_color.data());
252  }
253  else
254  {
255  glColor4f(1.f, 1.f, 1.f, 1.f);
256  }
257  if (!( disp_lists[hnd].layout == VertexNorm::layout
258  || disp_lists[hnd].layout == VertexNormColor::layout
259  || disp_lists[hnd].layout == VertexNormTex::layout))
260  {
261  glNormal3f(0.f, 0.f, 1.f);
262  }
263  glCallList(disp_lists[hnd].list);
264  // reset texturing parameters
265  // glMultiTexCoord2f(GL_TEXTURE0, 0.f, 0.f);
266  // glMultiTexCoord2f(GL_TEXTURE1, 0.f, 0.f);
267 }
268 
270 {
271  glColor4fv(static_color.data());
272  glNormal3f(0.f, 0.f, 1.f);
273  glMultiTexCoord2f(GL_TEXTURE0, 0.f, 0.f);
274  float tex_w = GetFont()->getAtlasWidth();
275  float tex_h = GetFont()->getAtlasHeight();
276  // Model-view transform:
277  // - scale bounding boxes to relative clip-space/NDC coords
278  // - add z-offset of -0.005 to reduce text hiding by mesh
279  glMatrixMode(GL_MODELVIEW);
280  glPushMatrix();
281  glLoadIdentity();
282  glScalef(2.f / vp_width, 2.f / vp_height, 0.f);
283  glTranslatef(0.f, 0.f, -0.005);
284  glMatrixMode(GL_PROJECTION);
285  for (const TextBuffer::Entry& e : buf)
286  {
287  glm::vec4 pos(e.rx, e.ry, e.rz, 1.0);
288  // transform text starting position into NDC
289  pos = model_view_mtx * pos;
290  pos = proj_mtx * pos;
291  pos = pos / pos.w;
292  // Projection transform:
293  // - add starting offset in NDC
294  glPushMatrix();
295  glLoadIdentity();
296  glTranslatef(pos.x, pos.y, pos.z);
297  float pen_x = e.ox, pen_y = e.oy;
298  char prev_c = '\0';
299  for (char c : e.text)
300  {
301  const GlVisFont::glyph &g = GetFont()->GetTexChar(c);
302  pen_x += GetFont()->GetKerning(prev_c, c);
303  // note: subtract 1 to account for the padding in the texture glyphs
304  float cur_x = pen_x + g.bear_x - 1;
305  float cur_y = -pen_y - g.bear_y - 1;
306  pen_x += g.adv_x;
307  pen_y += g.adv_y;
308  if (!g.w || !g.h)
309  {
310  continue;
311  }
312  glBegin(GL_TRIANGLE_STRIP);
313  glMultiTexCoord2f(GL_TEXTURE1, g.tex_x, 0);
314  glVertex2f(cur_x, -cur_y);
315  glMultiTexCoord2f(GL_TEXTURE1, g.tex_x + g.w / tex_w, 0);
316  glVertex2f(cur_x + g.w, -cur_y);
317  glMultiTexCoord2f(GL_TEXTURE1, g.tex_x, g.h / tex_h);
318  glVertex2f(cur_x, -cur_y - g.h);
319  glMultiTexCoord2f(GL_TEXTURE1, g.tex_x + g.w / tex_w, g.h / tex_h);
320  glVertex2f(cur_x + g.w, -cur_y - g.h);
321  glEnd();
322  }
323  glPopMatrix();
324  }
325  glMatrixMode(GL_MODELVIEW);
326  glPopMatrix();
327 }
328 
330  int hnd)
331 {
332  if (hnd == 0) { return; }
333  if (disp_lists[hnd].count == 0) { return; }
334  GLenum fbType;
335  int fbStride;
336  if (disp_lists[hnd].layout == VertexTex::layout
337  || disp_lists[hnd].layout == VertexNormTex::layout)
338  {
339  //capture texture values too
340  // [ X Y Z ] [ R G B A ] [ U V - - ]
341  fbType = GL_3D_COLOR_TEXTURE;
342  fbStride = 11;
343  }
344  else
345  {
346  // only capture pos and color
347  // [ X Y Z ] [ R G B A ]
348  fbType = GL_3D_COLOR;
349  fbStride = 7;
350  }
351  // compute feedback buffer size
352  int sizebuf = 0;
353  if (disp_lists[hnd].shape == GL_LINES)
354  {
355  // for each line: LINE_TOKEN [Vtx] [Vtx]
356  sizebuf = (disp_lists[hnd].count / 2) + disp_lists[hnd].count * fbStride;
357  }
358  else if (disp_lists[hnd].shape == GL_TRIANGLES)
359  {
360  // for each tri: POLY_TOKEN 3 [Vtx] [Vtx] [Vtx]
361  // NOTE: when clip plane is enabled, we might get two triangles
362  // or a quad for an input triangle. However, the other clipped
363  // triangles get discarded, so this *should* be enough space.
364  sizebuf = (disp_lists[hnd].count / 3) * (2 + fbStride * 4);
365  }
366  else
367  {
368  std::cerr << "Warning: unhandled primitive type in FFPrinter::preDraw()" <<
369  std::endl;
370  return;
371  }
372  // allocate feedback buffer
373  vector<float> xfb_buf;
374  xfb_buf.resize(sizebuf);
375  glFeedbackBuffer(sizebuf, fbType, xfb_buf.data());
376  // draw with feedback capture
377  glRenderMode(GL_FEEDBACK);
378  drawDeviceBuffer(hnd);
379 #ifndef GLVIS_DEBUG
380  glRenderMode(GL_RENDER);
381 #else
382  if (glRenderMode(GL_RENDER) < 0)
383  {
384  std::cerr << "Warning: feedback data exceeded available buffer size" <<
385  std::endl;
386  }
387 #endif
388  size_t tok_idx = 0;
389  // process feedback buffer
390  while (tok_idx < xfb_buf.size())
391  {
392  switch ((GLuint)xfb_buf[tok_idx])
393  {
394  case GL_LINE_TOKEN:
395  case GL_LINE_RESET_TOKEN:
396  {
397  tok_idx++;
398  glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]),
399  coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]);
400  glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]),
401  color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]);
402  if (fbStride == 11)
403  {
404  // get texture
405  pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0));
406  pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1));
407  }
408  cbuf.lines.emplace_back(coord0, color0);
409  cbuf.lines.emplace_back(coord1, color1);
410  tok_idx += fbStride * 2;
411  }
412  break;
413  case GL_POLYGON_TOKEN:
414  {
415  int n = xfb_buf[tok_idx + 1];
416  tok_idx += 2;
417  // get vertex 0, 1
418  glm::vec3 coord0 = glm::make_vec3(&xfb_buf[tok_idx]),
419  coord1 = glm::make_vec3(&xfb_buf[tok_idx + fbStride]);
420  glm::vec4 color0 = glm::make_vec4(&xfb_buf[tok_idx + 3]),
421  color1 = glm::make_vec4(&xfb_buf[tok_idx + 3 + fbStride]);
422  if (fbStride == 11)
423  {
424  // get texture
425  pal.GetColorFromVal(xfb_buf[tok_idx + 7], glm::value_ptr(color0));
426  pal.GetColorFromVal(xfb_buf[tok_idx + 7 + fbStride], glm::value_ptr(color1));
427  }
428  // decompose polygon into n-2 triangles [0 1 2] [0 2 3] ...
429  for (int i = 0; i < n-2; i++)
430  {
431  // get last vertex of current triangle
432  int vtxStart = fbStride * (2 + 3*i);
433  glm::vec3 coord2 = glm::make_vec3(&xfb_buf[tok_idx + vtxStart]);
434  glm::vec4 color2 = glm::make_vec4(&xfb_buf[tok_idx + 3 + vtxStart]);
435  if (fbStride == 11)
436  {
437  pal.GetColorFromVal(xfb_buf[tok_idx + 7 + vtxStart], glm::value_ptr(color2));
438  }
439  cbuf.triangles.emplace_back(coord0, color0);
440  cbuf.triangles.emplace_back(coord1, color1);
441  cbuf.triangles.emplace_back(coord2, color2);
442  // last vertex becomes second vertex of next triangle
443  coord1 = coord2;
444  color1 = color2;
445  }
446  tok_idx += n * fbStride;
447  }
448  break;
449  case GL_POINT_TOKEN:
450  case GL_BITMAP_TOKEN:
451  case GL_DRAW_PIXEL_TOKEN:
452  case GL_COPY_PIXEL_TOKEN:
453  default:
454  // commands containing the token + a single vertex ignore for now
455  tok_idx += 1 + fbStride;
456  break;
457  }
458  }
459 }
460 
461 }
glm::mat4 proj_mtx
Definition: renderer.hpp:103
void setupFFVertexArray(TVtx *buffer)
Definition: renderer_ff.cpp:20
int32_t bear_y
Definition: font.hpp:32
static void clearLegacy()
Definition: attr_traits.hpp:27
glm::mat4 model_view_mtx
Definition: renderer.hpp:102
virtual void setTransformMatrices(glm::mat4 model_view, glm::mat4 projection)
Definition: renderer.cpp:438
int32_t bear_x
Definition: font.hpp:32
float shininess
Definition: material.hpp:21
virtual size_t count() const =0
Gets the number of vertices contained in the buffer.
static const int layout
Definition: types.hpp:227
static const int layout
Definition: types.hpp:211
static void setupLegacy(void *)
Definition: attr_traits.hpp:25
float adv_x
Definition: font.hpp:33
std::array< float, 4 > position
Definition: material.hpp:26
std::array< float, 4 > diffuse
Definition: material.hpp:19
void bufferToDevice(array_layout layout, IVertexBuffer &buf) override
void GetColorFromVal(double val, float *rgba)
Definition: palettes.cpp:7785
static const int layout
Definition: types.hpp:235
static const int layout
Definition: types.hpp:219
std::array< float, 4 > ambient
Definition: material.hpp:18
void setTransformMatrices(glm::mat4 model_view, glm::mat4 projection) override
Definition: renderer_ff.cpp:90
void setClipPlaneEqn(const std::array< double, 4 > &eqn) override
float GetKerning(char cprev, char c)
Definition: font.hpp:82
std::array< float, 4 > specular
Definition: material.hpp:20
void setPointLight(int i, Light lt) override
array_layout
Definition: types.hpp:170
std::array< float, 4 > diffuse
Definition: material.hpp:27
void drawDeviceBuffer(int hnd) override
std::array< float, 4 > static_color
Definition: renderer.hpp:105
void setNumLights(int i) override
static const int layout
Definition: types.hpp:244
void setMaterial(Material mat) override
void setHandle(int dev_hnd)
Definition: types.hpp:449
void captureXfbBuffer(PaletteState &pal, CaptureBuffer &cbuf, int hnd) override
float getAtlasHeight()
Definition: font.hpp:105
int getHandle() const
Definition: types.hpp:448
GlVisFont * GetFont()
Definition: aux_vis.cpp:1678
const int LIGHTS_MAX
Definition: renderer.hpp:30
std::array< float, 4 > specular
Definition: material.hpp:28
virtual const std::vector< int > & getIndices() const =0
virtual GLenum getShape() const =0
Gets the primitive type contained by the vertex buffer.
void init() override
Definition: renderer_ff.cpp:66
uint32_t h
Definition: font.hpp:31
const glyph & GetTexChar(char c) const
Definition: font.hpp:54
static const int layout
Definition: types.hpp:253
float tex_x
Definition: font.hpp:34
void setAmbientLight(const std::array< float, 4 > &amb) override
vector< FeedbackVertex > lines
Definition: renderer.hpp:91
float adv_y
Definition: font.hpp:33
vector< FeedbackVertex > triangles
Definition: renderer.hpp:92
void clearFFVertexArray()
Definition: renderer_ff.cpp:34
uint32_t w
Definition: font.hpp:31
virtual void init()
Definition: renderer.cpp:397
void setClipPlaneUse(bool enable) override
float getAtlasWidth()
Definition: font.hpp:103