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