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