0029074: Visualization, TKOpenGl - support Geometry Shader definition
[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   // this sample does not use GLSL programs - make sure it is disabled
159   Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
160   aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
161   aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
162
163   // To test linking against OpenGl_Workspace and all aspect classes
164   const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker();
165   aMA->Aspect()->Type();
166   const OpenGl_AspectText* aTA = theWorkspace->AspectText();
167   aTA->Aspect()->Font();
168   OpenGl_Vec4 aColor = theWorkspace->LineColor();
169
170 #if !defined(GL_ES_VERSION_2_0)
171   // Finally draw something to make sure UserDraw really works
172   glPushAttrib(GL_ENABLE_BIT);
173   glDisable(GL_LIGHTING);
174   glColor4fv(aColor.GetData());
175   glBegin(GL_LINE_LOOP);
176   glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
177   glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
178   glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
179   glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
180   glEnd();
181   glPopAttrib();
182 #endif
183 }
184
185 } // end of anonymous namespace
186
187 static Standard_Integer VUserDraw (Draw_Interpretor& di,
188                                     Standard_Integer argc,
189                                     const char ** argv)
190 {
191   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
192   if (aContext.IsNull())
193   {
194     di << argv[0] << "Call 'vinit' before!\n";
195     return 1;
196   }
197
198   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
199   if (aDriver.IsNull())
200   {
201     std::cerr << "Graphic driver not available.\n";
202     return 1;
203   }
204
205   if (argc > 2)
206   {
207     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
208     return 1;
209   }
210
211   TCollection_AsciiString aName (argv[1]);
212   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
213
214   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
215   VDisplayAISObject(aName, anIObj);
216
217   return 0;
218 }
219
220 //==============================================================================
221 //function : VFeedback
222 //purpose  :
223 //==============================================================================
224
225 static int VFeedback (Draw_Interpretor& theDI,
226                       Standard_Integer  /*theArgNb*/,
227                       const char**      /*theArgVec*/)
228 {
229 #if !defined(GL_ES_VERSION_2_0)
230   // get the active view
231   Handle(V3d_View) aView = ViewerTest::CurrentView();
232   if (aView.IsNull())
233   {
234     std::cerr << "No active view. Please call vinit.\n";
235     return 1;
236   }
237
238   unsigned int aBufferSize = 1024 * 1024;
239   for (;;)
240   {
241     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
242     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
243     {
244       // finito la commedia
245       std::cerr << "Can not allocate buffer - requested size ("
246                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
247                 << " MiB) is out of address space\n";
248       return 1;
249     }
250
251     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
252     if (aBuffer == NULL)
253     {
254       // finito la commedia
255       std::cerr << "Can not allocate buffer with size ("
256                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
257                 << " MiB)\n";
258       return 1;
259     }
260
261     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
262     glRenderMode (GL_FEEDBACK);
263
264     aView->Redraw();
265
266     GLint aResult = glRenderMode (GL_RENDER);
267     if (aResult < 0)
268     {
269       aBufferSize *= 2;
270
271       void* aPtr = aBuffer;
272       Standard::Free (aPtr);
273       aBuffer = NULL;
274       continue;
275     }
276
277     std::cout << "FeedBack result= " << aResult << "\n";
278     GLint aPntNb     = 0;
279     GLint aTriNb     = 0;
280     GLint aQuadsNb   = 0;
281     GLint aPolyNb    = 0;
282     GLint aNodesNb   = 0;
283     GLint aLinesNb   = 0;
284     GLint aBitmapsNb = 0;
285     GLint aPassThrNb = 0;
286     GLint aUnknownNb = 0;
287     const GLint NODE_VALUES = 2; // GL_2D
288     for (GLint anIter = 0; anIter < aResult;)
289     {
290         const GLfloat aPos = aBuffer[anIter];
291         switch ((GLint )aPos)
292         {
293           case GL_POINT_TOKEN:
294           {
295             ++aPntNb;
296             ++aNodesNb;
297             anIter += 1 + NODE_VALUES;
298             break;
299           }
300           case GL_LINE_RESET_TOKEN:
301           case GL_LINE_TOKEN:
302           {
303             ++aLinesNb;
304             aNodesNb += 2;
305             anIter += 1 + 2 * NODE_VALUES;
306             break;
307           }
308           case GL_POLYGON_TOKEN:
309           {
310             const GLint aCount = (GLint )aBuffer[++anIter];
311             aNodesNb += aCount;
312             anIter += aCount * NODE_VALUES + 1;
313             if (aCount == 3)
314             {
315               ++aTriNb;
316             }
317             else if (aCount == 4)
318             {
319               ++aQuadsNb;
320             }
321             else
322             {
323               ++aPolyNb;
324             }
325             break;
326           }
327           case GL_BITMAP_TOKEN:
328           case GL_DRAW_PIXEL_TOKEN:
329           case GL_COPY_PIXEL_TOKEN:
330           {
331             ++aBitmapsNb;
332             anIter += 1 + NODE_VALUES;
333             break;
334           }
335           case GL_PASS_THROUGH_TOKEN:
336           {
337             ++aPassThrNb;
338             anIter += 2; // header + value
339             break;
340           }
341           default:
342           {
343             ++anIter;
344             ++aUnknownNb;
345             break;
346           }
347        }
348     }
349     void* aPtr = aBuffer;
350     Standard::Free (aPtr);
351
352     // return statistics
353     theDI << "Total nodes:   " << aNodesNb   << "\n"
354           << "Points:        " << aPntNb     << "\n"
355           << "Line segments: " << aLinesNb   << "\n"
356           << "Triangles:     " << aTriNb     << "\n"
357           << "Quads:         " << aQuadsNb   << "\n"
358           << "Polygons:      " << aPolyNb    << "\n"
359           << "Bitmap tokens: " << aBitmapsNb << "\n"
360           << "Pass through:  " << aPassThrNb << "\n"
361           << "UNKNOWN:       " << aUnknownNb << "\n";
362
363     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
364     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
365     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
366     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
367           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
368           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
369     return 0;
370   }
371 #else
372   (void )theDI;
373   std::cout << "Command is unsupported on current platform.\n";
374   return 1;
375 #endif
376 }
377
378 //==============================================================================
379 //function : VImmediateFront
380 //purpose  :
381 //==============================================================================
382
383 static int VImmediateFront (Draw_Interpretor& /*theDI*/,
384                             Standard_Integer  theArgNb,
385                             const char**      theArgVec)
386 {
387   // get the context
388   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
389   if (aContextAIS.IsNull())
390   {
391     std::cerr << "No active view. Please call vinit.\n";
392     return 1;
393   }
394
395   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
396
397   if (aDriver.IsNull())
398   {
399     std::cerr << "Graphic driver not available.\n";
400     return 1;
401   }
402
403   if (theArgNb < 2)
404   {
405     std::cerr << "Wrong number of arguments.\n";
406     return 1;
407   }
408
409   ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
410
411   return 0;
412 }
413
414 //! Search the info from the key.
415 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
416                                            const TCollection_AsciiString& theKey)
417 {
418   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
419   {
420     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
421     {
422       return anIter.Value();
423     }
424   }
425   return TCollection_AsciiString();
426 }
427
428 //==============================================================================
429 //function : VGlInfo
430 //purpose  :
431 //==============================================================================
432
433 static int VGlInfo (Draw_Interpretor& theDI,
434                     Standard_Integer  theArgNb,
435                     const char**      theArgVec)
436 {
437   // get the active view
438   Handle(V3d_View) aView = ViewerTest::CurrentView();
439   if (aView.IsNull())
440   {
441     std::cerr << "No active view. Please call vinit.\n";
442     return 1;
443   }
444
445   Standard_Integer anArgIter = 1;
446   Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
447   if (theArgNb == 2)
448   {
449     TCollection_AsciiString aName (theArgVec[1]);
450     aName.LowerCase();
451     if (aName == "-short")
452     {
453       ++anArgIter;
454       anInfoLevel = Graphic3d_DiagnosticInfo_Short;
455     }
456     else if (aName == "-basic")
457     {
458       ++anArgIter;
459       anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
460     }
461     else if (aName == "-complete"
462           || aName == "-full")
463     {
464       ++anArgIter;
465       anInfoLevel = Graphic3d_DiagnosticInfo_Complete;
466     }
467   }
468
469   TColStd_IndexedDataMapOfStringString aDict;
470   if (anArgIter >= theArgNb)
471   {
472     aView->DiagnosticInformation (aDict, anInfoLevel);
473     TCollection_AsciiString aText;
474     for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aDict); aValueIter.More(); aValueIter.Next())
475     {
476       if (!aText.IsEmpty())
477       {
478         aText += "\n";
479       }
480       aText += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
481     }
482
483     theDI << "OpenGL info:\n"
484           << aText;
485     return 0;
486   }
487
488   const Standard_Boolean isList = theArgNb >= 3;
489   aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
490   for (; anArgIter < theArgNb; ++anArgIter)
491   {
492     TCollection_AsciiString aName (theArgVec[anArgIter]);
493     aName.UpperCase();
494     TCollection_AsciiString aValue;
495     if (aName.Search ("VENDOR") != -1)
496     {
497       aValue = searchInfo (aDict, "GLvendor");
498     }
499     else if (aName.Search ("RENDERER") != -1)
500     {
501       aValue = searchInfo (aDict, "GLdevice");
502     }
503     else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
504           || aName.Search ("GLSL") != -1)
505     {
506       aValue = searchInfo (aDict, "GLSLversion");
507     }
508     else if (aName.Search ("VERSION") != -1)
509     {
510       aValue = searchInfo (aDict, "GLversion");
511     }
512     else if (aName.Search ("EXTENSIONS") != -1)
513     {
514       aValue = searchInfo (aDict, "GLextensions");
515     }
516     else
517     {
518       std::cerr << "Unknown key '" << aName.ToCString() << "'\n";
519       return 1;
520     }
521
522     if (isList)
523     {
524       theDI << "{" << aValue << "} ";
525     }
526     else
527     {
528       theDI << aValue;
529     }
530   }
531
532   return 0;
533 }
534
535 //! Parse shader type argument.
536 static bool parseShaderTypeArg (Graphic3d_TypeOfShaderObject& theType,
537                                 const TCollection_AsciiString& theArg)
538 {
539   if (theArg == "-vertex"
540    || theArg == "-vert")
541   {
542     theType = Graphic3d_TOS_VERTEX;
543   }
544   else if (theArg == "-tessevaluation"
545         || theArg == "-tesseval"
546         || theArg == "-evaluation"
547         || theArg == "-eval")
548   {
549     theType = Graphic3d_TOS_TESS_EVALUATION;
550   }
551   else if (theArg == "-tesscontrol"
552         || theArg == "-tessctrl"
553         || theArg == "-control"
554         || theArg == "-ctrl")
555   {
556     theType = Graphic3d_TOS_TESS_CONTROL;
557   }
558   else if (theArg == "-geometry"
559         || theArg == "-geom")
560   {
561     theType = Graphic3d_TOS_GEOMETRY;
562   }
563   else if (theArg == "-fragment"
564         || theArg == "-frag")
565   {
566     theType = Graphic3d_TOS_FRAGMENT;
567   }
568   else if (theArg == "-compute"
569         || theArg == "-comp")
570   {
571     theType = Graphic3d_TOS_COMPUTE;
572   }
573   else
574   {
575     return false;
576   }
577   return true;
578 }
579
580 //==============================================================================
581 //function : VShaderProg
582 //purpose  : Sets the pair of vertex and fragment shaders for the object
583 //==============================================================================
584 static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
585                                      Standard_Integer  theArgNb,
586                                      const char**      theArgVec)
587 {
588   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
589   if (aCtx.IsNull())
590   {
591     std::cout << "Error: no active view.\n";
592     return 1;
593   }
594   else if (theArgNb < 2)
595   {
596     std::cout << "Syntax error: lack of arguments\n";
597     return 1;
598   }
599
600   bool isExplicitShaderType = false;
601   Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
602   NCollection_Sequence<Handle(AIS_InteractiveObject)> aPrsList;
603   Graphic3d_GroupAspect aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
604   bool isSetGroupAspect = false;
605   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
606   {
607     TCollection_AsciiString anArg (theArgVec[anArgIter]);
608     anArg.LowerCase();
609     Graphic3d_TypeOfShaderObject aShaderTypeArg = Graphic3d_TypeOfShaderObject(-1);
610     if (!aProgram.IsNull()
611      &&  aProgram->ShaderObjects().IsEmpty()
612      && (anArg == "-off"
613       || anArg ==  "off"))
614     {
615       aProgram.Nullify();
616     }
617     else if (!aProgram.IsNull()
618           &&  aProgram->ShaderObjects().IsEmpty()
619           && (anArg == "-phong"
620            || anArg ==  "phong"))
621     {
622       const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
623       if (aShadersRoot.IsEmpty())
624       {
625         std::cout << "Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
626                      "At least one should be defined to load Phong program.\n";
627         return 1;
628       }
629
630       const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
631       const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
632       if (!aSrcVert.IsEmpty()
633        && !OSD_File (aSrcVert).Exists())
634       {
635         std::cout << "Error: PhongShading.vs is not found\n";
636         return 1;
637       }
638       if (!aSrcFrag.IsEmpty()
639        && !OSD_File (aSrcFrag).Exists())
640       {
641         std::cout << "Error: PhongShading.fs is not found\n";
642         return 1;
643       }
644
645       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
646       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
647     }
648     else if (aPrsList.IsEmpty()
649           && anArg == "*")
650     {
651       //
652     }
653     else if (!isSetGroupAspect
654           &&  anArgIter + 1 < theArgNb
655           && (anArg == "-primtype"
656            || anArg == "-primitivetype"
657            || anArg == "-groupaspect"
658            || anArg == "-aspecttype"
659            || anArg == "-aspect"))
660     {
661       isSetGroupAspect = true;
662       TCollection_AsciiString aPrimTypeStr (theArgVec[++anArgIter]);
663       aPrimTypeStr.LowerCase();
664       if (aPrimTypeStr == "line")
665       {
666         aGroupAspect = Graphic3d_ASPECT_LINE;
667       }
668       else if (aPrimTypeStr == "tris"
669             || aPrimTypeStr == "triangles"
670             || aPrimTypeStr == "fill"
671             || aPrimTypeStr == "fillarea"
672             || aPrimTypeStr == "shading"
673             || aPrimTypeStr == "shade")
674       {
675         aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
676       }
677       else if (aPrimTypeStr == "text")
678       {
679         aGroupAspect = Graphic3d_ASPECT_TEXT;
680       }
681       else if (aPrimTypeStr == "marker"
682             || aPrimTypeStr == "point"
683             || aPrimTypeStr == "pnt")
684       {
685         aGroupAspect = Graphic3d_ASPECT_MARKER;
686       }
687       else
688       {
689         std::cerr << "Syntax error at '" << aPrimTypeStr << "'\n";
690         return 1;
691       }
692     }
693     else if (anArgIter + 1 < theArgNb
694          && !aProgram.IsNull()
695          &&  aProgram->Header().IsEmpty()
696          &&  (anArg == "-version"
697            || anArg == "-glslversion"
698            || anArg == "-header"
699            || anArg == "-glslheader"))
700     {
701       TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
702       if (aHeader.IsIntegerValue())
703       {
704         aHeader = TCollection_AsciiString ("#version ") + aHeader;
705       }
706       aProgram->SetHeader (aHeader);
707     }
708     else if (!anArg.StartsWith ("-")
709           && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
710     {
711       Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (theArgVec[anArgIter]));
712       if (anIO.IsNull())
713       {
714         std::cerr << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object\n";
715         return 1;
716       }
717       aPrsList.Append (anIO);
718     }
719     else if (!aProgram.IsNull()
720            && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
721             || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
722     {
723       TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
724       if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
725       {
726         aShaderPath = (theArgVec[++anArgIter]);
727         isExplicitShaderType = true;
728       }
729
730       const bool isSrcFile = OSD_File (aShaderPath).Exists();
731       Handle(Graphic3d_ShaderObject) aShader = isSrcFile
732                                              ? Graphic3d_ShaderObject::CreateFromFile  (Graphic3d_TOS_VERTEX, aShaderPath)
733                                              : Graphic3d_ShaderObject::CreateFromSource(Graphic3d_TOS_VERTEX, aShaderPath);
734       const TCollection_AsciiString& aShaderSrc = aShader->Source();
735
736       const bool hasVertPos   = aShaderSrc.Search ("gl_Position")  != -1;
737       const bool hasFragColor = aShaderSrc.Search ("occFragColor") != -1
738                              || aShaderSrc.Search ("gl_FragColor") != -1
739                              || aShaderSrc.Search ("gl_FragData")  != -1;
740       Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
741       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
742       {
743         if (hasVertPos
744         && !hasFragColor)
745         {
746           aShaderType = Graphic3d_TOS_VERTEX;
747         }
748         if (hasFragColor
749         && !hasVertPos)
750         {
751           aShaderType = Graphic3d_TOS_FRAGMENT;
752         }
753       }
754       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
755       {
756         std::cerr << "Error: non-existing or invalid shader source\n";
757         return 1;
758       }
759
760       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
761     }
762     else
763     {
764       std::cerr << "Syntax error at '" << anArg << "'\n";
765       return 1;
766     }
767   }
768
769   ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
770   NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
771   const bool isGlobalList = aPrsList.IsEmpty();
772   for (;;)
773   {
774     Handle(AIS_InteractiveObject) anIO;
775     if (isGlobalList)
776     {
777       if (!aGlobalPrsIter.More())
778       {
779         break;
780       }
781       anIO = Handle(AIS_InteractiveObject)::DownCast (aGlobalPrsIter.Key1());
782       aGlobalPrsIter.Next();
783       if (anIO.IsNull())
784       {
785         continue;
786       }
787     }
788     else
789     {
790       if (!aPrsIter.More())
791       {
792         break;
793       }
794       anIO = aPrsIter.Value();
795       aPrsIter.Next();
796     }
797
798     if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
799     {
800       aCtx->Redisplay (anIO, Standard_False);
801     }
802     else
803     {
804       anIO->SynchronizeAspects();
805     }
806   }
807
808   aCtx->UpdateCurrentViewer();
809   return 0;
810 }
811
812 //=======================================================================
813 //function : OpenGlCommands
814 //purpose  :
815 //=======================================================================
816
817 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
818 {
819   const char* aGroup ="Commands for low-level TKOpenGl features";
820
821   theCommands.Add("vuserdraw",
822     "vuserdraw : name - simulates drawing with help of UserDraw",
823     __FILE__, VUserDraw, aGroup);
824   theCommands.Add("vfeedback",
825     "vfeedback       : perform test GL feedback rendering",
826     __FILE__, VFeedback, aGroup);
827   theCommands.Add("vimmediatefront",
828     "vimmediatefront : render immediate mode to front buffer or to back buffer",
829     __FILE__, VImmediateFront, aGroup);
830   theCommands.Add("vglinfo",
831                 "vglinfo [-short|-basic|-complete]"
832         "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
833         "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
834         "\n\t\t: print OpenGL info",
835     __FILE__, VGlInfo, aGroup);
836   theCommands.Add("vshader",
837                   "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
838                   "\n\t\t:   [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
839                   "\n\t\t:   [-header VersionHeader]"
840                   "\n\t\t:   [-tessControl TessControlShader -tesseval TessEvaluationShader]"
841                   "\n\t\t: Assign custom GLSL program to presentation aspects.",
842     __FILE__, VShaderProg, aGroup);
843   theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
844 }