0029337: Visualization, TKOpenGl - visual artifacts on Intel Broadwell GPU
[occt.git] / src / ViewerTest / ViewerTest_OpenGlCommands.cxx
1 // Created on: 2012-04-09
2 // Created by: Sergey ANIKIN
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <ViewerTest.hxx>
17
18 #include <AIS_InteractiveContext.hxx>
19 #include <AIS_InteractiveObject.hxx>
20 #include <Draw.hxx>
21 #include <Draw_Interpretor.hxx>
22 #include <Graphic3d_Group.hxx>
23 #include <Graphic3d_ShaderObject.hxx>
24 #include <Graphic3d_ShaderProgram.hxx>
25 #include <OpenGl_AspectFace.hxx>
26 #include <OpenGl_AspectLine.hxx>
27 #include <OpenGl_AspectMarker.hxx>
28 #include <OpenGl_AspectText.hxx>
29 #include <OpenGl_Context.hxx>
30 #include <OpenGl_Element.hxx>
31 #include <OpenGl_GlCore20.hxx>
32 #include <OpenGl_GraphicDriver.hxx>
33 #include <OpenGl_ShaderManager.hxx>
34 #include <OpenGl_Workspace.hxx>
35 #include <OSD_Environment.hxx>
36 #include <OSD_File.hxx>
37 #include <Prs3d_Drawer.hxx>
38 #include <Prs3d_Presentation.hxx>
39 #include <Prs3d_Root.hxx>
40 #include <Prs3d_LineAspect.hxx>
41 #include <Prs3d_ShadingAspect.hxx>
42 #include <Select3D_SensitiveCurve.hxx>
43 #include <SelectMgr_EntityOwner.hxx>
44 #include <SelectMgr_Selection.hxx>
45 #include <TCollection_AsciiString.hxx>
46 #include <V3d_View.hxx>
47 #include <V3d_Viewer.hxx>
48 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
49 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
50 #include <OpenGl_Group.hxx>
51
52 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
53                                            const Handle(AIS_InteractiveObject)& theAISObj,
54                                            Standard_Boolean theReplaceIfExists = Standard_True);
55 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
56
57 namespace {
58
59 //=======================================================================
60 //function : VUserDraw
61 //purpose  : Checks availability and operation of UserDraw feature
62 //=======================================================================
63
64 class VUserDrawObj : public AIS_InteractiveObject
65 {
66 public:
67     // CASCADE RTTI
68     DEFINE_STANDARD_RTTI_INLINE(VUserDrawObj,AIS_InteractiveObject);
69
70     VUserDrawObj()
71     {
72       myCoords[0] = -10.;
73       myCoords[1] = -20.;
74       myCoords[2] = -30.;
75       myCoords[3] =  10.;
76       myCoords[4] =  20.;
77       myCoords[5] =  30.;
78     }
79
80 public:
81   class Element : public OpenGl_Element
82   {
83   private:
84     Handle(VUserDrawObj) myIObj;
85
86   public:
87     Element (const Handle(VUserDrawObj)& theIObj) : myIObj (theIObj) {}
88
89     virtual ~Element() {}
90
91     virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
92     {
93       if (!myIObj.IsNull())
94         myIObj->Render(theWorkspace);
95     }
96
97     virtual void Release (OpenGl_Context*)
98     {
99       //
100     }
101
102   public:
103     DEFINE_STANDARD_ALLOC
104   };
105
106 private:
107     // Virtual methods implementation
108     void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
109                   const Handle(Prs3d_Presentation)& thePresentation,
110                   const Standard_Integer theMode) Standard_OVERRIDE;
111
112     void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
113                            const Standard_Integer theMode) Standard_OVERRIDE;
114
115     // Called by VUserDrawElement
116     void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
117
118 private:
119     GLfloat myCoords[6];
120     friend class Element;
121 };
122
123 void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
124                            const Handle(Prs3d_Presentation)& thePrs,
125                            const Standard_Integer /*theMode*/)
126 {
127   thePrs->Clear();
128
129   Graphic3d_Vec4 aBndMin (myCoords[0], myCoords[1], myCoords[2], 1.0f);
130   Graphic3d_Vec4 aBndMax (myCoords[3], myCoords[4], myCoords[5], 1.0f);
131   Handle(OpenGl_Group) aGroup = Handle(OpenGl_Group)::DownCast (thePrs->NewGroup());
132   aGroup->SetMinMaxValues (aBndMin.x(), aBndMin.y(), aBndMin.z(),
133                            aBndMax.x(), aBndMax.y(), aBndMax.z());
134   aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
135   VUserDrawObj::Element* anElem = new VUserDrawObj::Element (this);
136   aGroup->AddElement(anElem);
137
138   // invalidate bounding box of the scene
139   thePrsMgr->StructureManager()->Update();
140 }
141
142 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
143                                      const Standard_Integer /*theMode*/)
144 {
145   Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner(this);
146   Handle(TColgp_HArray1OfPnt) aPnts = new TColgp_HArray1OfPnt(1, 5);
147   aPnts->SetValue(1, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
148   aPnts->SetValue(2, gp_Pnt(myCoords[3], myCoords[4], myCoords[2]));
149   aPnts->SetValue(3, gp_Pnt(myCoords[3], myCoords[4], myCoords[5]));
150   aPnts->SetValue(4, gp_Pnt(myCoords[0], myCoords[1], myCoords[5]));
151   aPnts->SetValue(5, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
152   Handle(Select3D_SensitiveCurve) aSensitive = new Select3D_SensitiveCurve(anEntityOwner, aPnts);
153   theSelection->Add(aSensitive);
154 }
155
156 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
157 {
158   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
159
160   // To test linking against OpenGl_Workspace and all aspect classes
161   const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker();
162   aMA->Aspect()->Type();
163   const OpenGl_AspectText* aTA = theWorkspace->AspectText();
164   aTA->Aspect()->Font();
165   OpenGl_Vec4 aColor = theWorkspace->LineColor();
166
167   aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), false, false, false, Handle(OpenGl_ShaderProgram)());
168   aCtx->SetColor4fv (aColor);
169
170   const OpenGl_Vec3 aVertArray[4] =
171   {
172     OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[2]),
173     OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[2]),
174     OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[5]),
175     OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[5]),
176   };
177   Handle(OpenGl_VertexBuffer) aVertBuffer = new OpenGl_VertexBuffer();
178   aVertBuffer->Init (aCtx, 3, 4, aVertArray[0].GetData());
179
180   // Finally draw something to make sure UserDraw really works
181   aVertBuffer->BindAttribute  (aCtx, Graphic3d_TOA_POS);
182   glDrawArrays(GL_LINE_LOOP, 0, aVertBuffer->GetElemsNb());
183   aVertBuffer->UnbindAttribute(aCtx, Graphic3d_TOA_POS);
184   aVertBuffer->Release (aCtx.get());
185 }
186
187 } // end of anonymous namespace
188
189 static Standard_Integer VUserDraw (Draw_Interpretor& di,
190                                     Standard_Integer argc,
191                                     const char ** argv)
192 {
193   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
194   if (aContext.IsNull())
195   {
196     di << argv[0] << "Call 'vinit' before!\n";
197     return 1;
198   }
199
200   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
201   if (aDriver.IsNull())
202   {
203     std::cerr << "Graphic driver not available.\n";
204     return 1;
205   }
206
207   if (argc > 2)
208   {
209     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
210     return 1;
211   }
212
213   TCollection_AsciiString aName (argv[1]);
214   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
215
216   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
217   VDisplayAISObject(aName, anIObj);
218
219   return 0;
220 }
221
222 //==============================================================================
223 //function : VFeedback
224 //purpose  :
225 //==============================================================================
226
227 static int VFeedback (Draw_Interpretor& theDI,
228                       Standard_Integer  /*theArgNb*/,
229                       const char**      /*theArgVec*/)
230 {
231 #if !defined(GL_ES_VERSION_2_0)
232   // get the active view
233   Handle(V3d_View) aView = ViewerTest::CurrentView();
234   if (aView.IsNull())
235   {
236     std::cerr << "No active view. Please call vinit.\n";
237     return 1;
238   }
239
240   unsigned int aBufferSize = 1024 * 1024;
241   for (;;)
242   {
243     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
244     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
245     {
246       // finito la commedia
247       std::cerr << "Can not allocate buffer - requested size ("
248                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
249                 << " MiB) is out of address space\n";
250       return 1;
251     }
252
253     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
254     if (aBuffer == NULL)
255     {
256       // finito la commedia
257       std::cerr << "Can not allocate buffer with size ("
258                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
259                 << " MiB)\n";
260       return 1;
261     }
262
263     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
264     glRenderMode (GL_FEEDBACK);
265
266     aView->Redraw();
267
268     GLint aResult = glRenderMode (GL_RENDER);
269     if (aResult < 0)
270     {
271       aBufferSize *= 2;
272
273       void* aPtr = aBuffer;
274       Standard::Free (aPtr);
275       aBuffer = NULL;
276       continue;
277     }
278
279     std::cout << "FeedBack result= " << aResult << "\n";
280     GLint aPntNb     = 0;
281     GLint aTriNb     = 0;
282     GLint aQuadsNb   = 0;
283     GLint aPolyNb    = 0;
284     GLint aNodesNb   = 0;
285     GLint aLinesNb   = 0;
286     GLint aBitmapsNb = 0;
287     GLint aPassThrNb = 0;
288     GLint aUnknownNb = 0;
289     const GLint NODE_VALUES = 2; // GL_2D
290     for (GLint anIter = 0; anIter < aResult;)
291     {
292         const GLfloat aPos = aBuffer[anIter];
293         switch ((GLint )aPos)
294         {
295           case GL_POINT_TOKEN:
296           {
297             ++aPntNb;
298             ++aNodesNb;
299             anIter += 1 + NODE_VALUES;
300             break;
301           }
302           case GL_LINE_RESET_TOKEN:
303           case GL_LINE_TOKEN:
304           {
305             ++aLinesNb;
306             aNodesNb += 2;
307             anIter += 1 + 2 * NODE_VALUES;
308             break;
309           }
310           case GL_POLYGON_TOKEN:
311           {
312             const GLint aCount = (GLint )aBuffer[++anIter];
313             aNodesNb += aCount;
314             anIter += aCount * NODE_VALUES + 1;
315             if (aCount == 3)
316             {
317               ++aTriNb;
318             }
319             else if (aCount == 4)
320             {
321               ++aQuadsNb;
322             }
323             else
324             {
325               ++aPolyNb;
326             }
327             break;
328           }
329           case GL_BITMAP_TOKEN:
330           case GL_DRAW_PIXEL_TOKEN:
331           case GL_COPY_PIXEL_TOKEN:
332           {
333             ++aBitmapsNb;
334             anIter += 1 + NODE_VALUES;
335             break;
336           }
337           case GL_PASS_THROUGH_TOKEN:
338           {
339             ++aPassThrNb;
340             anIter += 2; // header + value
341             break;
342           }
343           default:
344           {
345             ++anIter;
346             ++aUnknownNb;
347             break;
348           }
349        }
350     }
351     void* aPtr = aBuffer;
352     Standard::Free (aPtr);
353
354     // return statistics
355     theDI << "Total nodes:   " << aNodesNb   << "\n"
356           << "Points:        " << aPntNb     << "\n"
357           << "Line segments: " << aLinesNb   << "\n"
358           << "Triangles:     " << aTriNb     << "\n"
359           << "Quads:         " << aQuadsNb   << "\n"
360           << "Polygons:      " << aPolyNb    << "\n"
361           << "Bitmap tokens: " << aBitmapsNb << "\n"
362           << "Pass through:  " << aPassThrNb << "\n"
363           << "UNKNOWN:       " << aUnknownNb << "\n";
364
365     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
366     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
367     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
368     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
369           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
370           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
371     return 0;
372   }
373 #else
374   (void )theDI;
375   std::cout << "Command is unsupported on current platform.\n";
376   return 1;
377 #endif
378 }
379
380 //==============================================================================
381 //function : VImmediateFront
382 //purpose  :
383 //==============================================================================
384
385 static int VImmediateFront (Draw_Interpretor& /*theDI*/,
386                             Standard_Integer  theArgNb,
387                             const char**      theArgVec)
388 {
389   // get the context
390   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
391   if (aContextAIS.IsNull())
392   {
393     std::cerr << "No active view. Please call vinit.\n";
394     return 1;
395   }
396
397   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
398
399   if (aDriver.IsNull())
400   {
401     std::cerr << "Graphic driver not available.\n";
402     return 1;
403   }
404
405   if (theArgNb < 2)
406   {
407     std::cerr << "Wrong number of arguments.\n";
408     return 1;
409   }
410
411   ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
412
413   return 0;
414 }
415
416 //! Search the info from the key.
417 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
418                                            const TCollection_AsciiString& theKey)
419 {
420   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
421   {
422     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
423     {
424       return anIter.Value();
425     }
426   }
427   return TCollection_AsciiString();
428 }
429
430 //==============================================================================
431 //function : VGlInfo
432 //purpose  :
433 //==============================================================================
434
435 static int VGlInfo (Draw_Interpretor& theDI,
436                     Standard_Integer  theArgNb,
437                     const char**      theArgVec)
438 {
439   // get the active view
440   Handle(V3d_View) aView = ViewerTest::CurrentView();
441   if (aView.IsNull())
442   {
443     std::cerr << "No active view. Please call vinit.\n";
444     return 1;
445   }
446
447   Standard_Integer anArgIter = 1;
448   Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
449   if (theArgNb == 2)
450   {
451     TCollection_AsciiString aName (theArgVec[1]);
452     aName.LowerCase();
453     if (aName == "-short")
454     {
455       ++anArgIter;
456       anInfoLevel = Graphic3d_DiagnosticInfo_Short;
457     }
458     else if (aName == "-basic")
459     {
460       ++anArgIter;
461       anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
462     }
463     else if (aName == "-complete"
464           || aName == "-full")
465     {
466       ++anArgIter;
467       anInfoLevel = Graphic3d_DiagnosticInfo_Complete;
468     }
469   }
470
471   TColStd_IndexedDataMapOfStringString aDict;
472   if (anArgIter >= theArgNb)
473   {
474     aView->DiagnosticInformation (aDict, anInfoLevel);
475     TCollection_AsciiString aText;
476     for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aDict); aValueIter.More(); aValueIter.Next())
477     {
478       if (!aText.IsEmpty())
479       {
480         aText += "\n";
481       }
482       aText += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
483     }
484
485     theDI << "OpenGL info:\n"
486           << aText;
487     return 0;
488   }
489
490   const Standard_Boolean isList = theArgNb >= 3;
491   aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
492   for (; anArgIter < theArgNb; ++anArgIter)
493   {
494     TCollection_AsciiString aName (theArgVec[anArgIter]);
495     aName.UpperCase();
496     TCollection_AsciiString aValue;
497     if (aName.Search ("VENDOR") != -1)
498     {
499       aValue = searchInfo (aDict, "GLvendor");
500     }
501     else if (aName.Search ("RENDERER") != -1)
502     {
503       aValue = searchInfo (aDict, "GLdevice");
504     }
505     else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
506           || aName.Search ("GLSL") != -1)
507     {
508       aValue = searchInfo (aDict, "GLSLversion");
509     }
510     else if (aName.Search ("VERSION") != -1)
511     {
512       aValue = searchInfo (aDict, "GLversion");
513     }
514     else if (aName.Search ("EXTENSIONS") != -1)
515     {
516       aValue = searchInfo (aDict, "GLextensions");
517     }
518     else
519     {
520       std::cerr << "Unknown key '" << aName.ToCString() << "'\n";
521       return 1;
522     }
523
524     if (isList)
525     {
526       theDI << "{" << aValue << "} ";
527     }
528     else
529     {
530       theDI << aValue;
531     }
532   }
533
534   return 0;
535 }
536
537 //! Parse shader type argument.
538 static bool parseShaderTypeArg (Graphic3d_TypeOfShaderObject& theType,
539                                 const TCollection_AsciiString& theArg)
540 {
541   if (theArg == "-vertex"
542    || theArg == "-vert")
543   {
544     theType = Graphic3d_TOS_VERTEX;
545   }
546   else if (theArg == "-tessevaluation"
547         || theArg == "-tesseval"
548         || theArg == "-evaluation"
549         || theArg == "-eval")
550   {
551     theType = Graphic3d_TOS_TESS_EVALUATION;
552   }
553   else if (theArg == "-tesscontrol"
554         || theArg == "-tessctrl"
555         || theArg == "-control"
556         || theArg == "-ctrl")
557   {
558     theType = Graphic3d_TOS_TESS_CONTROL;
559   }
560   else if (theArg == "-geometry"
561         || theArg == "-geom")
562   {
563     theType = Graphic3d_TOS_GEOMETRY;
564   }
565   else if (theArg == "-fragment"
566         || theArg == "-frag")
567   {
568     theType = Graphic3d_TOS_FRAGMENT;
569   }
570   else if (theArg == "-compute"
571         || theArg == "-comp")
572   {
573     theType = Graphic3d_TOS_COMPUTE;
574   }
575   else
576   {
577     return false;
578   }
579   return true;
580 }
581
582 //==============================================================================
583 //function : VShaderProg
584 //purpose  : Sets the pair of vertex and fragment shaders for the object
585 //==============================================================================
586 static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
587                                      Standard_Integer  theArgNb,
588                                      const char**      theArgVec)
589 {
590   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
591   if (aCtx.IsNull())
592   {
593     std::cout << "Error: no active view.\n";
594     return 1;
595   }
596   else if (theArgNb < 2)
597   {
598     std::cout << "Syntax error: lack of arguments\n";
599     return 1;
600   }
601
602   bool isExplicitShaderType = false;
603   Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
604   NCollection_Sequence<Handle(AIS_InteractiveObject)> aPrsList;
605   Graphic3d_GroupAspect aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
606   bool isSetGroupAspect = false;
607   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
608   {
609     TCollection_AsciiString anArg (theArgVec[anArgIter]);
610     anArg.LowerCase();
611     Graphic3d_TypeOfShaderObject aShaderTypeArg = Graphic3d_TypeOfShaderObject(-1);
612     if (!aProgram.IsNull()
613      &&  aProgram->ShaderObjects().IsEmpty()
614      && (anArg == "-off"
615       || anArg ==  "off"))
616     {
617       aProgram.Nullify();
618     }
619     else if (!aProgram.IsNull()
620           &&  aProgram->ShaderObjects().IsEmpty()
621           && (anArg == "-phong"
622            || anArg ==  "phong"))
623     {
624       const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
625       if (aShadersRoot.IsEmpty())
626       {
627         std::cout << "Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
628                      "At least one should be defined to load Phong program.\n";
629         return 1;
630       }
631
632       const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
633       const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
634       if (!aSrcVert.IsEmpty()
635        && !OSD_File (aSrcVert).Exists())
636       {
637         std::cout << "Error: PhongShading.vs is not found\n";
638         return 1;
639       }
640       if (!aSrcFrag.IsEmpty()
641        && !OSD_File (aSrcFrag).Exists())
642       {
643         std::cout << "Error: PhongShading.fs is not found\n";
644         return 1;
645       }
646
647       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
648       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
649     }
650     else if (aPrsList.IsEmpty()
651           && anArg == "*")
652     {
653       //
654     }
655     else if (!isSetGroupAspect
656           &&  anArgIter + 1 < theArgNb
657           && (anArg == "-primtype"
658            || anArg == "-primitivetype"
659            || anArg == "-groupaspect"
660            || anArg == "-aspecttype"
661            || anArg == "-aspect"))
662     {
663       isSetGroupAspect = true;
664       TCollection_AsciiString aPrimTypeStr (theArgVec[++anArgIter]);
665       aPrimTypeStr.LowerCase();
666       if (aPrimTypeStr == "line")
667       {
668         aGroupAspect = Graphic3d_ASPECT_LINE;
669       }
670       else if (aPrimTypeStr == "tris"
671             || aPrimTypeStr == "triangles"
672             || aPrimTypeStr == "fill"
673             || aPrimTypeStr == "fillarea"
674             || aPrimTypeStr == "shading"
675             || aPrimTypeStr == "shade")
676       {
677         aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
678       }
679       else if (aPrimTypeStr == "text")
680       {
681         aGroupAspect = Graphic3d_ASPECT_TEXT;
682       }
683       else if (aPrimTypeStr == "marker"
684             || aPrimTypeStr == "point"
685             || aPrimTypeStr == "pnt")
686       {
687         aGroupAspect = Graphic3d_ASPECT_MARKER;
688       }
689       else
690       {
691         std::cerr << "Syntax error at '" << aPrimTypeStr << "'\n";
692         return 1;
693       }
694     }
695     else if (anArgIter + 1 < theArgNb
696          && !aProgram.IsNull()
697          &&  aProgram->Header().IsEmpty()
698          &&  (anArg == "-version"
699            || anArg == "-glslversion"
700            || anArg == "-header"
701            || anArg == "-glslheader"))
702     {
703       TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
704       if (aHeader.IsIntegerValue())
705       {
706         aHeader = TCollection_AsciiString ("#version ") + aHeader;
707       }
708       aProgram->SetHeader (aHeader);
709     }
710     else if (!anArg.StartsWith ("-")
711           && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
712     {
713       Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (theArgVec[anArgIter]));
714       if (anIO.IsNull())
715       {
716         std::cerr << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object\n";
717         return 1;
718       }
719       aPrsList.Append (anIO);
720     }
721     else if (!aProgram.IsNull()
722            && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
723             || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
724     {
725       TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
726       if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
727       {
728         aShaderPath = (theArgVec[++anArgIter]);
729         isExplicitShaderType = true;
730       }
731
732       const bool isSrcFile = OSD_File (aShaderPath).Exists();
733       Handle(Graphic3d_ShaderObject) aShader = isSrcFile
734                                              ? Graphic3d_ShaderObject::CreateFromFile  (Graphic3d_TOS_VERTEX, aShaderPath)
735                                              : Graphic3d_ShaderObject::CreateFromSource(Graphic3d_TOS_VERTEX, aShaderPath);
736       const TCollection_AsciiString& aShaderSrc = aShader->Source();
737
738       const bool hasVertPos   = aShaderSrc.Search ("gl_Position")  != -1;
739       const bool hasFragColor = aShaderSrc.Search ("occSetFragColor") != -1
740                              || aShaderSrc.Search ("occFragColor") != -1
741                              || aShaderSrc.Search ("gl_FragColor") != -1
742                              || aShaderSrc.Search ("gl_FragData")  != -1;
743       Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
744       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
745       {
746         if (hasVertPos
747         && !hasFragColor)
748         {
749           aShaderType = Graphic3d_TOS_VERTEX;
750         }
751         if (hasFragColor
752         && !hasVertPos)
753         {
754           aShaderType = Graphic3d_TOS_FRAGMENT;
755         }
756       }
757       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
758       {
759         std::cerr << "Error: non-existing or invalid shader source\n";
760         return 1;
761       }
762
763       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
764     }
765     else
766     {
767       std::cerr << "Syntax error at '" << anArg << "'\n";
768       return 1;
769     }
770   }
771
772   if (!aProgram.IsNull()
773     && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
774   {
775     aProgram->SetNbFragmentOutputs (2);
776     aProgram->SetWeightOitOutput (true);
777   }
778
779   ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
780   NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
781   const bool isGlobalList = aPrsList.IsEmpty();
782   for (;;)
783   {
784     Handle(AIS_InteractiveObject) anIO;
785     if (isGlobalList)
786     {
787       if (!aGlobalPrsIter.More())
788       {
789         break;
790       }
791       anIO = Handle(AIS_InteractiveObject)::DownCast (aGlobalPrsIter.Key1());
792       aGlobalPrsIter.Next();
793       if (anIO.IsNull())
794       {
795         continue;
796       }
797     }
798     else
799     {
800       if (!aPrsIter.More())
801       {
802         break;
803       }
804       anIO = aPrsIter.Value();
805       aPrsIter.Next();
806     }
807
808     if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
809     {
810       aCtx->Redisplay (anIO, Standard_False);
811     }
812     else
813     {
814       anIO->SynchronizeAspects();
815     }
816   }
817
818   aCtx->UpdateCurrentViewer();
819   return 0;
820 }
821
822 //=======================================================================
823 //function : OpenGlCommands
824 //purpose  :
825 //=======================================================================
826
827 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
828 {
829   const char* aGroup ="Commands for low-level TKOpenGl features";
830
831   theCommands.Add("vuserdraw",
832     "vuserdraw : name - simulates drawing with help of UserDraw",
833     __FILE__, VUserDraw, aGroup);
834   theCommands.Add("vfeedback",
835     "vfeedback       : perform test GL feedback rendering",
836     __FILE__, VFeedback, aGroup);
837   theCommands.Add("vimmediatefront",
838     "vimmediatefront : render immediate mode to front buffer or to back buffer",
839     __FILE__, VImmediateFront, aGroup);
840   theCommands.Add("vglinfo",
841                 "vglinfo [-short|-basic|-complete]"
842         "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
843         "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
844         "\n\t\t: print OpenGL info",
845     __FILE__, VGlInfo, aGroup);
846   theCommands.Add("vshader",
847                   "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
848                   "\n\t\t:   [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
849                   "\n\t\t:   [-header VersionHeader]"
850                   "\n\t\t:   [-tessControl TessControlShader -tesseval TessEvaluationShader]"
851                   "\n\t\t: Assign custom GLSL program to presentation aspects.",
852     __FILE__, VShaderProg, aGroup);
853   theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
854 }