0029570: Visualization, Graphic3d_Aspect - merge Graphic3d_Group aspects
[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 (anArg == "-list"
610      || ((anArg == "-update"
611        || anArg == "-dump"
612        || anArg == "-debug"
613        || anArg == "-reload"
614        || anArg == "-load")
615       && anArgIter + 1 < theArgNb))
616     {
617       Handle(OpenGl_Context) aGlCtx;
618       if (Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aCtx->CurrentViewer()->Driver()))
619       {
620         aGlCtx = aDriver->GetSharedContext();
621       }
622       if (aGlCtx.IsNull())
623       {
624         std::cout << "Error: no OpenGl_Context\n";
625         return 1;
626       }
627
628       if (anArg == "-list")
629       {
630         for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (aGlCtx->SharedResources()); aResIter.More(); aResIter.Next())
631         {
632           if (Handle(OpenGl_ShaderProgram) aResProg = Handle(OpenGl_ShaderProgram)::DownCast (aResIter.Value()))
633           {
634             theDI << aResProg->ResourceId() << " ";
635           }
636         }
637       }
638       else
639       {
640         TCollection_AsciiString aShaderName = theArgVec[++anArgIter];
641         Handle(OpenGl_ShaderProgram) aResProg;
642         if (!aGlCtx->GetResource (aShaderName, aResProg))
643         {
644           std::cout << "Syntax error: shader resource '" << aShaderName << "' is not found\n";
645           return 1;
646         }
647         if (aResProg->UpdateDebugDump (aGlCtx, "", false, anArg == "-dump"))
648         {
649           aCtx->UpdateCurrentViewer();
650         }
651       }
652       if (anArgIter + 1 < theArgNb)
653       {
654         std::cout << "Syntax error: wrong number of arguments\n";
655         return 1;
656       }
657       return 0;
658     }
659     else if (!aProgram.IsNull()
660           &&  aProgram->ShaderObjects().IsEmpty()
661           && (anArg == "-off"
662            || anArg ==  "off"))
663     {
664       aProgram.Nullify();
665     }
666     else if (!aProgram.IsNull()
667           &&  aProgram->ShaderObjects().IsEmpty()
668           && (anArg == "-phong"
669            || anArg ==  "phong"))
670     {
671       const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
672       if (aShadersRoot.IsEmpty())
673       {
674         std::cout << "Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
675                      "At least one should be defined to load Phong program.\n";
676         return 1;
677       }
678
679       const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
680       const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
681       if (!aSrcVert.IsEmpty()
682        && !OSD_File (aSrcVert).Exists())
683       {
684         std::cout << "Error: PhongShading.vs is not found\n";
685         return 1;
686       }
687       if (!aSrcFrag.IsEmpty()
688        && !OSD_File (aSrcFrag).Exists())
689       {
690         std::cout << "Error: PhongShading.fs is not found\n";
691         return 1;
692       }
693
694       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
695       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
696     }
697     else if (aPrsList.IsEmpty()
698           && anArg == "*")
699     {
700       //
701     }
702     else if (!isSetGroupAspect
703           &&  anArgIter + 1 < theArgNb
704           && (anArg == "-primtype"
705            || anArg == "-primitivetype"
706            || anArg == "-groupaspect"
707            || anArg == "-aspecttype"
708            || anArg == "-aspect"))
709     {
710       isSetGroupAspect = true;
711       TCollection_AsciiString aPrimTypeStr (theArgVec[++anArgIter]);
712       aPrimTypeStr.LowerCase();
713       if (aPrimTypeStr == "line")
714       {
715         aGroupAspect = Graphic3d_ASPECT_LINE;
716       }
717       else if (aPrimTypeStr == "tris"
718             || aPrimTypeStr == "triangles"
719             || aPrimTypeStr == "fill"
720             || aPrimTypeStr == "fillarea"
721             || aPrimTypeStr == "shading"
722             || aPrimTypeStr == "shade")
723       {
724         aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
725       }
726       else if (aPrimTypeStr == "text")
727       {
728         aGroupAspect = Graphic3d_ASPECT_TEXT;
729       }
730       else if (aPrimTypeStr == "marker"
731             || aPrimTypeStr == "point"
732             || aPrimTypeStr == "pnt")
733       {
734         aGroupAspect = Graphic3d_ASPECT_MARKER;
735       }
736       else
737       {
738         std::cerr << "Syntax error at '" << aPrimTypeStr << "'\n";
739         return 1;
740       }
741     }
742     else if (anArgIter + 1 < theArgNb
743          && !aProgram.IsNull()
744          &&  aProgram->Header().IsEmpty()
745          &&  (anArg == "-version"
746            || anArg == "-glslversion"
747            || anArg == "-header"
748            || anArg == "-glslheader"))
749     {
750       TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
751       if (aHeader.IsIntegerValue())
752       {
753         aHeader = TCollection_AsciiString ("#version ") + aHeader;
754       }
755       aProgram->SetHeader (aHeader);
756     }
757     else if (!anArg.StartsWith ("-")
758           && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
759     {
760       Handle(AIS_InteractiveObject) anIO = GetMapOfAIS().Find2 (theArgVec[anArgIter]);
761       if (anIO.IsNull())
762       {
763         std::cerr << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object\n";
764         return 1;
765       }
766       aPrsList.Append (anIO);
767     }
768     else if (!aProgram.IsNull()
769            && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
770             || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
771     {
772       TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
773       if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
774       {
775         aShaderPath = (theArgVec[++anArgIter]);
776         isExplicitShaderType = true;
777       }
778
779       const bool isSrcFile = OSD_File (aShaderPath).Exists();
780       Handle(Graphic3d_ShaderObject) aShader = isSrcFile
781                                              ? Graphic3d_ShaderObject::CreateFromFile  (Graphic3d_TOS_VERTEX, aShaderPath)
782                                              : Graphic3d_ShaderObject::CreateFromSource(Graphic3d_TOS_VERTEX, aShaderPath);
783       const TCollection_AsciiString& aShaderSrc = aShader->Source();
784
785       const bool hasVertPos   = aShaderSrc.Search ("gl_Position")  != -1;
786       const bool hasFragColor = aShaderSrc.Search ("occSetFragColor") != -1
787                              || aShaderSrc.Search ("occFragColor") != -1
788                              || aShaderSrc.Search ("gl_FragColor") != -1
789                              || aShaderSrc.Search ("gl_FragData")  != -1;
790       Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
791       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
792       {
793         if (hasVertPos
794         && !hasFragColor)
795         {
796           aShaderType = Graphic3d_TOS_VERTEX;
797         }
798         if (hasFragColor
799         && !hasVertPos)
800         {
801           aShaderType = Graphic3d_TOS_FRAGMENT;
802         }
803       }
804       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
805       {
806         std::cerr << "Error: non-existing or invalid shader source\n";
807         return 1;
808       }
809
810       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
811     }
812     else
813     {
814       std::cerr << "Syntax error at '" << anArg << "'\n";
815       return 1;
816     }
817   }
818
819   if (!aProgram.IsNull()
820     && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
821   {
822     aProgram->SetNbFragmentOutputs (2);
823     aProgram->SetWeightOitOutput (true);
824   }
825
826   ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
827   NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
828   const bool isGlobalList = aPrsList.IsEmpty();
829   for (;;)
830   {
831     Handle(AIS_InteractiveObject) anIO;
832     if (isGlobalList)
833     {
834       if (!aGlobalPrsIter.More())
835       {
836         break;
837       }
838       anIO = aGlobalPrsIter.Key1();
839       aGlobalPrsIter.Next();
840       if (anIO.IsNull())
841       {
842         continue;
843       }
844     }
845     else
846     {
847       if (!aPrsIter.More())
848       {
849         break;
850       }
851       anIO = aPrsIter.Value();
852       aPrsIter.Next();
853     }
854
855     if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
856     {
857       aCtx->Redisplay (anIO, Standard_False);
858     }
859     else
860     {
861       anIO->SynchronizeAspects();
862     }
863   }
864
865   aCtx->UpdateCurrentViewer();
866   return 0;
867 }
868
869 //=======================================================================
870 //function : OpenGlCommands
871 //purpose  :
872 //=======================================================================
873
874 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
875 {
876   const char* aGroup ="Commands for low-level TKOpenGl features";
877
878   theCommands.Add("vuserdraw",
879     "vuserdraw : name - simulates drawing with help of UserDraw",
880     __FILE__, VUserDraw, aGroup);
881   theCommands.Add("vfeedback",
882     "vfeedback       : perform test GL feedback rendering",
883     __FILE__, VFeedback, aGroup);
884   theCommands.Add("vimmediatefront",
885     "vimmediatefront : render immediate mode to front buffer or to back buffer",
886     __FILE__, VImmediateFront, aGroup);
887   theCommands.Add("vglinfo",
888                 "vglinfo [-short|-basic|-complete]"
889         "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
890         "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
891         "\n\t\t: print OpenGL info",
892     __FILE__, VGlInfo, aGroup);
893   theCommands.Add("vshader",
894                   "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
895                   "\n\t\t:   [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
896                   "\n\t\t:   [-header VersionHeader]"
897                   "\n\t\t:   [-tessControl TessControlShader -tesseval TessEvaluationShader]"
898                   "\n\t\t: Assign custom GLSL program to presentation aspects."
899                   "\nvshader [-list] [-dump] [-reload] ShaderId"
900                   "\n\t\t:  -list   prints the list of registered GLSL programs"
901                   "\n\t\t:  -dump   dumps specified GLSL program (for debugging)"
902                   "\n\t\t:  -reload restores dump of specified GLSL program",
903     __FILE__, VShaderProg, aGroup);
904   theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
905 }