1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4 
5   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6   All rights reserved.
7   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 #include "vtkOpenGLGlyph3DHelper.h"
15 
16 #include "vtkglVBOHelper.h"
17 
18 #include "vtkBitArray.h"
19 #include "vtkCamera.h"
20 #include "vtkDataObject.h"
21 #include "vtkHardwareSelector.h"
22 #include "vtkMath.h"
23 #include "vtkMatrix3x3.h"
24 #include "vtkMatrix4x4.h"
25 #include "vtkNew.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkOpenGLError.h"
28 #include "vtkOpenGLRenderWindow.h"
29 #include "vtkOpenGLRenderer.h"
30 #include "vtkOpenGLShaderCache.h"
31 #include "vtkProperty.h"
32 #include "vtkShader.h"
33 #include "vtkShaderProgram.h"
34 #include "vtkTransform.h"
35 
36 
37 #include "vtkglGlyph3DVSFragmentLit.h"
38 
39 using vtkgl::substitute;
40 
41 //-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkOpenGLGlyph3DHelper)42 vtkStandardNewMacro(vtkOpenGLGlyph3DHelper)
43 
44 //-----------------------------------------------------------------------------
45 vtkOpenGLGlyph3DHelper::vtkOpenGLGlyph3DHelper()
46 {
47   this->ModelTransformMatrix = NULL;
48   this->ModelNormalMatrix = NULL;
49   this->ModelColor = NULL;
50   this->UseFastPath = false;
51   this->UsingInstancing = false;
52 
53   // we always tell our triangle VAO to emulate to be safe
54   // this is because it seems that GLEW_ARB_vertex_array_object
55   // does not always handle the attributes for GLEW_ARB_instanced_arrays
56   this->Tris.vao.SetForceEmulation(true);
57 }
58 
59 //-----------------------------------------------------------------------------
GetShaderTemplate(std::string & VSSource,std::string & FSSource,std::string & GSSource,int lightComplexity,vtkRenderer * ren,vtkActor * actor)60 void vtkOpenGLGlyph3DHelper::GetShaderTemplate(std::string &VSSource,
61                                           std::string &FSSource,
62                                           std::string &GSSource,
63                                           int lightComplexity, vtkRenderer* ren, vtkActor *actor)
64 {
65   this->Superclass::GetShaderTemplate(VSSource,FSSource,GSSource,lightComplexity,ren,actor);
66 
67   VSSource = vtkglGlyph3DVSFragmentLit;
68 }
69 
ReplaceShaderValues(std::string & VSSource,std::string & FSSource,std::string & GSSource,int lightComplexity,vtkRenderer * ren,vtkActor * actor)70 void vtkOpenGLGlyph3DHelper::ReplaceShaderValues(std::string &VSSource,
71                                                  std::string &FSSource,
72                                                  std::string &GSSource,
73                                                  int lightComplexity,
74                                                  vtkRenderer* ren,
75                                                  vtkActor *actor)
76 {
77   if (lightComplexity > 0)
78     {
79     // we use vertex instead of vertexMC
80     substitute(VSSource,
81       "//VTK::PositionVC::Impl",
82       "vertexVC = MCVCMatrix * vertex;\n"
83       "  gl_Position = MCDCMatrix * vertex;\n");
84     }
85 
86   // deal with color
87   if (this->UsingInstancing)
88     {
89     substitute(VSSource,"//VTK::Color::Dec",
90                         "attribute vec4 glyphColor;\n"
91                         "varying vec4 vertexColor;");
92     }
93   else
94     {
95     substitute(VSSource,
96                "//VTK::Color::Dec",
97                "uniform vec4 glyphColor;\n"
98                "varying vec4 vertexColor;");
99     }
100   substitute(VSSource,"//VTK::Color::Impl",
101                       "vertexColor =  glyphColor;");
102 
103 
104   // crate the material/color property declarations, and VS implementation
105   // these are always defined
106   std::string colorDec =
107     "uniform float opacityUniform; // the fragment opacity\n"
108     "uniform vec3 ambientColorUniform; // intensity weighted color\n"
109     "uniform vec3 diffuseColorUniform; // intensity weighted color\n";
110   // add some if we have a backface property
111   if (actor->GetBackfaceProperty())
112     {
113     colorDec +=
114       "uniform float opacityUniformBF; // the fragment opacity\n"
115       "uniform vec3 ambientColorUniformBF; // intensity weighted color\n"
116       "uniform vec3 diffuseColorUniformBF; // intensity weighted color\n";
117     }
118   // add more for specular
119   if (lightComplexity)
120     {
121     colorDec +=
122       "uniform vec3 specularColorUniform; // intensity weighted color\n"
123       "uniform float specularPowerUniform;\n";
124     if (actor->GetBackfaceProperty())
125       {
126       colorDec +=
127         "uniform vec3 specularColorUniformBF; // intensity weighted color\n"
128         "uniform float specularPowerUniformBF;\n";
129       }
130     }
131   colorDec += "varying vec4 vertexColor;\n";
132   substitute(FSSource,"//VTK::Color::Dec", colorDec);
133 
134   // now handle the more complex fragment shader implementation
135   // the following are always defined variables.  We start
136   // by assiging a default value from the uniform
137   std::string colorImpl =
138     "vec3 ambientColor;\n"
139     "  vec3 diffuseColor;\n"
140     "  float opacity;\n";
141   if (lightComplexity)
142     {
143     colorImpl +=
144       "  vec3 specularColor;\n"
145       "  float specularPower;\n";
146     }
147   if (actor->GetBackfaceProperty())
148     {
149     if (lightComplexity)
150       {
151       colorImpl +=
152         "  if (int(gl_FrontFacing) == 0) {\n"
153         "    ambientColor = ambientColorUniformBF;\n"
154         "    diffuseColor = diffuseColorUniformBF;\n"
155         "    specularColor = specularColorUniformBF;\n"
156         "    specularPower = specularPowerUniformBF;\n"
157         "    opacity = opacityUniformBF; }\n"
158         "  else {\n"
159         "    ambientColor = ambientColorUniform;\n"
160         "    diffuseColor = diffuseColorUniform;\n"
161         "    specularColor = specularColorUniform;\n"
162         "    specularPower = specularPowerUniform;\n"
163         "    opacity = opacityUniform; }\n";
164       }
165     else
166       {
167       colorImpl +=
168         "  if (int(gl_FrontFacing) == 0) {\n"
169         "    ambientColor = ambientColorUniformBF;\n"
170         "    diffuseColor = diffuseColorUniformBF;\n"
171         "    opacity = opacityUniformBF; }\n"
172         "  else {\n"
173         "    ambientColor = ambientColorUniform;\n"
174         "    diffuseColor = diffuseColorUniform;\n"
175         "    opacity = opacityUniform; }\n";
176       }
177     }
178   else
179     {
180     colorImpl +=
181       "    ambientColor = ambientColorUniform;\n"
182       "    diffuseColor = diffuseColorUniform;\n"
183       "    opacity = opacityUniform;\n";
184     if (lightComplexity)
185       {
186       colorImpl +=
187         "    specularColor = specularColorUniform;\n"
188         "    specularPower = specularPowerUniform;\n";
189       }
190     }
191 
192   // now handle scalar coloring
193   if (this->ScalarMaterialMode == VTK_MATERIALMODE_AMBIENT ||
194         (this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT &&
195          actor->GetProperty()->GetAmbient() > actor->GetProperty()->GetDiffuse()))
196     {
197     substitute(FSSource,"//VTK::Color::Impl", colorImpl +
198                         "  ambientColor = vertexColor.rgb;\n"
199                         "  opacity = vertexColor.a;");
200     }
201   else if (this->ScalarMaterialMode == VTK_MATERIALMODE_DIFFUSE ||
202         (this->ScalarMaterialMode == VTK_MATERIALMODE_DEFAULT &&
203          actor->GetProperty()->GetAmbient() <= actor->GetProperty()->GetDiffuse()))
204     {
205     substitute(FSSource,"//VTK::Color::Impl", colorImpl +
206                         "  diffuseColor = vertexColor.rgb;\n"
207                         "  opacity = vertexColor.a;");
208     }
209   else
210     {
211     substitute(FSSource,"//VTK::Color::Impl", colorImpl +
212                         "  diffuseColor = vertexColor.rgb;\n"
213                         "  ambientColor = vertexColor.rgb;\n"
214                         "  opacity = vertexColor.a;");
215     }
216 
217   if (this->UsingInstancing)
218     {
219     substitute(VSSource,
220                        "//VTK::Glyph::Dec",
221                        "attribute mat4 GCMCMatrix;");
222     }
223   else
224     {
225     substitute(VSSource,
226                        "//VTK::Glyph::Dec",
227                        "uniform mat4 GCMCMatrix;");
228     }
229   substitute(VSSource,
230                      "//VTK::Glyph::Impl",
231                      "vec4 vertex = GCMCMatrix * vertexMC;\n");
232 
233   // new code for normal matrix if we have normals
234   if (this->Layout.NormalOffset)
235     {
236     if (this->UsingInstancing)
237       {
238       substitute(VSSource,
239                          "//VTK::Normal::Dec",
240                          "uniform mat3 normalMatrix;\n"
241                          "attribute vec3 normalMC;\n"
242                          "attribute mat3 glyphNormalMatrix;\n"
243                          "varying vec3 normalVCVarying;");
244       }
245     else
246       {
247       substitute(VSSource,
248                          "//VTK::Normal::Dec",
249                          "uniform mat3 normalMatrix;\n"
250                          "attribute vec3 normalMC;\n"
251                          "uniform mat3 glyphNormalMatrix;\n"
252                          "varying vec3 normalVCVarying;");
253       }
254     substitute(VSSource, "//VTK::Normal::Impl",
255       "normalVCVarying = normalMatrix * glyphNormalMatrix * normalMC;");
256     this->ShaderVariablesUsed.push_back("normalMatrix");
257     }
258 
259   // override one part of the clipping code
260   if (this->GetNumberOfClippingPlanes())
261     {
262     // add all the clipping planes
263     int numClipPlanes = this->GetNumberOfClippingPlanes();
264     if (numClipPlanes > 6)
265       {
266       vtkErrorMacro(<< "OpenGL has a limit of 6 clipping planes");
267       numClipPlanes = 6;
268       }
269 
270     substitute(VSSource,
271        "//VTK::Clip::Impl",
272        "for (int planeNum = 0; planeNum < numClipPlanes; planeNum++)\n"
273        "    {\n"
274        "    clipDistances[planeNum] = dot(clipPlanes[planeNum], vertex);\n"
275        "    }\n");
276     }
277 
278 
279   this->Superclass::ReplaceShaderValues(VSSource,FSSource,GSSource,
280                                         lightComplexity,ren,actor);
281 }
282 
283 //-----------------------------------------------------------------------------
~vtkOpenGLGlyph3DHelper()284 vtkOpenGLGlyph3DHelper::~vtkOpenGLGlyph3DHelper()
285 {
286 }
287 
GlyphRender(vtkRenderer * ren,vtkActor * actor,vtkIdType numPts,std::vector<unsigned char> & colors,std::vector<float> & matrices,std::vector<float> & normalMatrices,std::vector<vtkIdType> & pickIds,unsigned long pointMTime)288 void vtkOpenGLGlyph3DHelper::GlyphRender(vtkRenderer* ren, vtkActor* actor, vtkIdType numPts,
289       std::vector<unsigned char> &colors, std::vector<float> &matrices,
290       std::vector<float> &normalMatrices, std::vector<vtkIdType> &pickIds,
291       unsigned long pointMTime)
292 {
293   this->CurrentInput = this->GetInput();
294   this->UsingInstancing = false;
295 
296   vtkHardwareSelector* selector = ren->GetSelector();
297   bool selecting_points = selector && (selector->GetFieldAssociation() ==
298     vtkDataObject::FIELD_ASSOCIATION_POINTS);
299 
300 #if GL_ES_VERSION_2_0 != 1 || GL_ES_VERSION_3_0 == 1
301   if (actor->GetProperty()->GetRepresentation() == VTK_SURFACE &&
302       !selector &&
303       (vtkOpenGLRenderWindow::GetContextSupportsOpenGL32() ||
304         GLEW_ARB_instanced_arrays))
305     {
306     this->GlyphRenderInstances(ren, actor, numPts,
307       colors, matrices, normalMatrices, pointMTime);
308     return;
309     }
310 #endif
311 
312   bool primed = false;
313 
314   for (vtkIdType inPtId = 0; inPtId < numPts; inPtId++)
315     {
316     if (selecting_points)
317       {
318       selector->RenderAttributeId(pickIds[inPtId]);
319       }
320     if (!primed)
321       {
322       this->RenderPieceStart(ren,actor);
323       this->UpdateShader(this->Tris, ren, actor);
324       this->Tris.ibo.Bind();
325       primed = true;
326       }
327 
328     // handle the middle
329     vtkShaderProgram *program = this->Tris.Program;
330     vtkgl::VBOLayout &layout = this->Layout;
331 
332     // Apply the extra transform
333     program->SetUniformMatrix4x4("GCMCMatrix", &(matrices[inPtId*16]));
334 
335     // for lit shaders set normal matrix
336     if (this->LastLightComplexity > 0 && this->Layout.NormalOffset &&
337         !this->UsingInstancing)
338       {
339       program->SetUniformMatrix3x3("glyphNormalMatrix", &(normalMatrices[inPtId*9]));
340       }
341 
342     program->SetUniform4uc("glyphColor", &(colors[inPtId*4]));
343 
344     if (selector)
345       {
346       program->SetUniform3f("mapperIndex", selector->GetPropColorValue());
347       }
348 
349     // First we do the triangles, update the shader, set uniforms, etc.
350     if (actor->GetProperty()->GetRepresentation() == VTK_POINTS)
351       {
352       glDrawRangeElements(GL_POINTS, 0,
353                           static_cast<GLuint>(layout.VertexCount - 1),
354                           static_cast<GLsizei>(this->Tris.indexCount),
355                           GL_UNSIGNED_INT,
356                           reinterpret_cast<const GLvoid *>(NULL));
357       }
358     if (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME)
359       {
360       // TODO wireframe of triangles is not lit properly right now
361       // you either have to generate normals and send them down
362       // or use a geometry shader.
363       glMultiDrawElements(GL_LINE_LOOP,
364                         (GLsizei *)(&this->Tris.elementsArray[0]),
365                         GL_UNSIGNED_INT,
366                         reinterpret_cast<const GLvoid **>(&(this->Tris.offsetArray[0])),
367                         (GLsizei)this->Tris.offsetArray.size());
368       }
369     if (actor->GetProperty()->GetRepresentation() == VTK_SURFACE)
370       {
371       glDrawRangeElements(GL_TRIANGLES, 0,
372                           static_cast<GLuint>(layout.VertexCount - 1),
373                           static_cast<GLsizei>(this->Tris.indexCount),
374                           GL_UNSIGNED_INT,
375                           reinterpret_cast<const GLvoid *>(NULL));
376       }
377     }
378   if (primed)
379     {
380     this->Tris.ibo.Release();
381     this->RenderPieceFinish(ren,actor);
382     }
383 }
384 
385 //-----------------------------------------------------------------------------
SetCameraShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)386 void vtkOpenGLGlyph3DHelper::SetCameraShaderParameters(vtkgl::CellBO &cellBO,
387                                                     vtkRenderer* ren, vtkActor *actor)
388 {
389   // do the superclass and then reset a couple values
390   this->Superclass::SetCameraShaderParameters(cellBO,ren,actor);
391 
392   vtkShaderProgram *program = cellBO.Program;
393 
394   // Apply the extra transform
395   if (this->ModelTransformMatrix)
396     {
397     program->SetUniformMatrix4x4("GCMCMatrix", this->ModelTransformMatrix);
398     }
399 
400   // for lit shaders set normal matrix
401   if (this->LastLightComplexity > 0 && this->ModelNormalMatrix &&
402      this->Layout.NormalOffset && !this->UsingInstancing)
403     {
404     program->SetUniformMatrix3x3("glyphNormalMatrix", this->ModelNormalMatrix);
405     }
406 }
407 
408 //-----------------------------------------------------------------------------
SetPropertyShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)409 void vtkOpenGLGlyph3DHelper::SetPropertyShaderParameters(vtkgl::CellBO &cellBO,
410                                                          vtkRenderer *ren, vtkActor *actor)
411 {
412   // do the superclass and then reset a couple values
413   this->Superclass::SetPropertyShaderParameters(cellBO,ren,actor);
414 
415   vtkShaderProgram *program = cellBO.Program;
416 
417   if (this->ModelColor)
418     {
419     program->SetUniform4uc("glyphColor", this->ModelColor);
420     }
421 }
422 
423 //-----------------------------------------------------------------------------
SetMapperShaderParameters(vtkgl::CellBO & cellBO,vtkRenderer * ren,vtkActor * actor)424 void vtkOpenGLGlyph3DHelper::SetMapperShaderParameters(vtkgl::CellBO &cellBO,
425                                                          vtkRenderer *ren, vtkActor *actor)
426 {
427   this->Superclass::SetMapperShaderParameters(cellBO,ren,actor);
428 
429   vtkHardwareSelector* selector = ren->GetSelector();
430   if (selector && selector->GetCurrentPass() == vtkHardwareSelector::ID_LOW24)
431     {
432     cellBO.Program->SetUniform3f("mapperIndex", selector->GetPropColorValue());
433     }
434 }
435 
436 #if GL_ES_VERSION_2_0 != 1 || GL_ES_VERSION_3_0 == 1
GlyphRenderInstances(vtkRenderer * ren,vtkActor * actor,vtkIdType numPts,std::vector<unsigned char> & colors,std::vector<float> & matrices,std::vector<float> & normalMatrices,unsigned long pointMTime)437 void vtkOpenGLGlyph3DHelper::GlyphRenderInstances(
438     vtkRenderer* ren, vtkActor* actor, vtkIdType numPts,
439     std::vector<unsigned char> &colors, std::vector<float> &matrices,
440     std::vector<float> &normalMatrices,
441     unsigned long pointMTime)
442 {
443   this->UsingInstancing = true;
444   this->RenderPieceStart(ren,actor);
445   this->UpdateShader(this->Tris, ren, actor);
446 
447   // do the superclass and then reset a couple values
448   if (this->Tris.indexCount &&   // we have points and one of
449       (this->VBOBuildTime > this->InstanceBuffersLoadTime ||
450       this->Tris.ShaderSourceTime > this->InstanceBuffersLoadTime ||
451       pointMTime > this->InstanceBuffersLoadTime.GetMTime()))
452     {
453     this->Tris.vao.Bind();
454     // add 3 new BOs?
455     this->MatrixBuffer.Bind();
456     this->MatrixBuffer.Upload(matrices, vtkgl::BufferObject::ArrayBuffer);
457     if (!this->Tris.vao.AddAttributeMatrixWithDivisor(this->Tris.Program, this->MatrixBuffer,
458         "GCMCMatrix", 0, 16*sizeof(float), VTK_FLOAT, 4, false, 1))
459       {
460       vtkErrorMacro(<< "Error setting 'GCMCMatrix' in shader VAO.");
461       }
462     this->MatrixBuffer.Release();
463 
464     if (this->Layout.NormalOffset && this->LastLightComplexity > 0)
465       {
466       this->NormalMatrixBuffer.Bind();
467       this->NormalMatrixBuffer.Upload(normalMatrices, vtkgl::BufferObject::ArrayBuffer);
468       if (!this->Tris.vao.AddAttributeMatrixWithDivisor(this->Tris.Program, this->NormalMatrixBuffer,
469             "glyphNormalMatrix", 0, 9*sizeof(float), VTK_FLOAT, 3, false, 1))
470         {
471         vtkErrorMacro(<< "Error setting 'glyphNormalMatrix' in shader VAO.");
472         }
473       this->NormalMatrixBuffer.Release();
474       }
475 
476     this->ColorBuffer.Bind();
477     this->ColorBuffer.Upload(colors, vtkgl::BufferObject::ArrayBuffer);
478     if (!this->Tris.vao.AddAttributeArrayWithDivisor(this->Tris.Program, this->ColorBuffer,
479           "glyphColor", 0, 4*sizeof(unsigned char), VTK_UNSIGNED_CHAR, 4, true, 1, false))
480       {
481       vtkErrorMacro(<< "Error setting 'diffuse color' in shader VAO.");
482       }
483     this->ColorBuffer.Release();
484 
485     this->InstanceBuffersLoadTime.Modified();
486     }
487 
488   this->Tris.ibo.Bind();
489 #if GL_ES_VERSION_3_0 == 1
490   glDrawElementsInstanced(GL_TRIANGLES,
491                         static_cast<GLsizei>(this->Tris.indexCount),
492                         GL_UNSIGNED_INT,
493                         reinterpret_cast<const GLvoid *>(NULL),
494                         numPts);
495 #else
496   if (vtkOpenGLRenderWindow::GetContextSupportsOpenGL32())
497     {
498     glDrawElementsInstanced(GL_TRIANGLES,
499                           static_cast<GLsizei>(this->Tris.indexCount),
500                           GL_UNSIGNED_INT,
501                           reinterpret_cast<const GLvoid *>(NULL),
502                           numPts);
503     }
504   else if (GLEW_ARB_instanced_arrays)
505     {
506     glDrawElementsInstancedARB(GL_TRIANGLES,
507                           static_cast<GLsizei>(this->Tris.indexCount),
508                           GL_UNSIGNED_INT,
509                           reinterpret_cast<const GLvoid *>(NULL),
510                           numPts);
511     }
512 #endif
513   vtkOpenGLCheckErrorMacro("failed after Render");
514 
515   this->Tris.ibo.Release();
516   this->RenderPieceFinish(ren, actor);
517 }
518 #endif
519 
520 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)521 void vtkOpenGLGlyph3DHelper::PrintSelf(ostream& os, vtkIndent indent)
522 {
523   this->Superclass::PrintSelf(os, indent);
524 }
525