0027813: Visualization - add method V3d_View::DiagnosticInformation() similar to...
[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_Workspace.hxx>
34 #include <OSD_Environment.hxx>
35 #include <OSD_File.hxx>
36 #include <Prs3d_Drawer.hxx>
37 #include <Prs3d_Presentation.hxx>
38 #include <Prs3d_Root.hxx>
39 #include <Prs3d_LineAspect.hxx>
40 #include <Prs3d_ShadingAspect.hxx>
41 #include <Select3D_SensitiveCurve.hxx>
42 #include <SelectMgr_EntityOwner.hxx>
43 #include <SelectMgr_Selection.hxx>
44 #include <TCollection_AsciiString.hxx>
45 #include <V3d_View.hxx>
46 #include <V3d_Viewer.hxx>
47 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
48 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
49 #include <OpenGl_Group.hxx>
50
51 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
52                                            const Handle(AIS_InteractiveObject)& theAISObj,
53                                            Standard_Boolean theReplaceIfExists = Standard_True);
54 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
55
56 namespace {
57
58 //=======================================================================
59 //function : VUserDraw
60 //purpose  : Checks availability and operation of UserDraw feature
61 //=======================================================================
62
63 class VUserDrawObj : public AIS_InteractiveObject
64 {
65 public:
66     // CASCADE RTTI
67     DEFINE_STANDARD_RTTI_INLINE(VUserDrawObj,AIS_InteractiveObject);
68
69     VUserDrawObj()
70     {
71       myCoords[0] = -10.;
72       myCoords[1] = -20.;
73       myCoords[2] = -30.;
74       myCoords[3] =  10.;
75       myCoords[4] =  20.;
76       myCoords[5] =  30.;
77     }
78
79 public:
80   class Element : public OpenGl_Element
81   {
82   private:
83     Handle(VUserDrawObj) myIObj;
84
85   public:
86     Element (const Handle(VUserDrawObj)& theIObj) : myIObj (theIObj) {}
87
88     virtual ~Element() {}
89
90     virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
91     {
92       if (!myIObj.IsNull())
93         myIObj->Render(theWorkspace);
94     }
95
96     virtual void Release (OpenGl_Context*)
97     {
98       //
99     }
100
101   public:
102     DEFINE_STANDARD_ALLOC
103   };
104
105 private:
106     // Virtual methods implementation
107     void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
108                   const Handle(Prs3d_Presentation)& thePresentation,
109                   const Standard_Integer theMode) Standard_OVERRIDE;
110
111     void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
112                            const Standard_Integer theMode) Standard_OVERRIDE;
113
114     // Called by VUserDrawElement
115     void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
116
117 private:
118     GLfloat myCoords[6];
119     friend class Element;
120 };
121
122 void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
123                            const Handle(Prs3d_Presentation)& thePrs,
124                            const Standard_Integer /*theMode*/)
125 {
126   thePrs->Clear();
127
128   Graphic3d_Vec4 aBndMin (myCoords[0], myCoords[1], myCoords[2], 1.0f);
129   Graphic3d_Vec4 aBndMax (myCoords[3], myCoords[4], myCoords[5], 1.0f);
130   Handle(OpenGl_Group) aGroup = Handle(OpenGl_Group)::DownCast (thePrs->NewGroup());
131   aGroup->SetMinMaxValues (aBndMin.x(), aBndMin.y(), aBndMin.z(),
132                            aBndMax.x(), aBndMax.y(), aBndMax.z());
133   aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
134   VUserDrawObj::Element* anElem = new VUserDrawObj::Element (this);
135   aGroup->AddElement(anElem);
136
137   // invalidate bounding box of the scene
138   thePrsMgr->StructureManager()->Update (thePrsMgr->StructureManager()->UpdateMode());
139 }
140
141 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
142                                      const Standard_Integer /*theMode*/)
143 {
144   Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner(this);
145   Handle(TColgp_HArray1OfPnt) aPnts = new TColgp_HArray1OfPnt(1, 5);
146   aPnts->SetValue(1, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
147   aPnts->SetValue(2, gp_Pnt(myCoords[3], myCoords[4], myCoords[2]));
148   aPnts->SetValue(3, gp_Pnt(myCoords[3], myCoords[4], myCoords[5]));
149   aPnts->SetValue(4, gp_Pnt(myCoords[0], myCoords[1], myCoords[5]));
150   aPnts->SetValue(5, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
151   Handle(Select3D_SensitiveCurve) aSensitive = new Select3D_SensitiveCurve(anEntityOwner, aPnts);
152   theSelection->Add(aSensitive);
153 }
154
155 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
156 {
157   // this sample does not use GLSL programs - make sure it is disabled
158   Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
159   aCtx->BindProgram (NULL);
160
161   // To test linking against OpenGl_Workspace and all aspect classes
162   const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker();
163   aMA->Aspect()->Type();
164   const OpenGl_AspectText* aTA = theWorkspace->AspectText();
165   aTA->Aspect()->Font();
166   OpenGl_Vec4 aColor = theWorkspace->LineColor();
167
168   // Finally draw something to make sure UserDraw really works
169   glPushAttrib(GL_ENABLE_BIT);
170   glDisable(GL_LIGHTING);
171   glColor4fv(aColor.GetData());
172   glBegin(GL_LINE_LOOP);
173   glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
174   glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
175   glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
176   glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
177   glEnd();
178   glPopAttrib();
179 }
180
181 } // end of anonymous namespace
182
183 static Standard_Integer VUserDraw (Draw_Interpretor& di,
184                                     Standard_Integer argc,
185                                     const char ** argv)
186 {
187   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
188   if (aContext.IsNull())
189   {
190     di << argv[0] << "Call 'vinit' before!\n";
191     return 1;
192   }
193
194   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
195   if (aDriver.IsNull())
196   {
197     std::cerr << "Graphic driver not available.\n";
198     return 1;
199   }
200
201   if (argc > 2)
202   {
203     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
204     return 1;
205   }
206
207   TCollection_AsciiString aName (argv[1]);
208   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
209
210   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
211   VDisplayAISObject(aName, anIObj);
212
213   return 0;
214 }
215
216 //==============================================================================
217 //function : VFeedback
218 //purpose  :
219 //==============================================================================
220
221 static int VFeedback (Draw_Interpretor& theDI,
222                       Standard_Integer  /*theArgNb*/,
223                       const char**      /*theArgVec*/)
224 {
225   // get the active view
226   Handle(V3d_View) aView = ViewerTest::CurrentView();
227   if (aView.IsNull())
228   {
229     std::cerr << "No active view. Please call vinit.\n";
230     return 1;
231   }
232
233   unsigned int aBufferSize = 1024 * 1024;
234   for (;;)
235   {
236     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
237     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
238     {
239       // finito la commedia
240       std::cerr << "Can not allocate buffer - requested size ("
241                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
242                 << " MiB) is out of address space\n";
243       return 1;
244     }
245
246     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
247     if (aBuffer == NULL)
248     {
249       // finito la commedia
250       std::cerr << "Can not allocate buffer with size ("
251                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
252                 << " MiB)\n";
253       return 1;
254     }
255
256     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
257     glRenderMode (GL_FEEDBACK);
258
259     aView->Redraw();
260
261     GLint aResult = glRenderMode (GL_RENDER);
262     if (aResult < 0)
263     {
264       aBufferSize *= 2;
265
266       void* aPtr = aBuffer;
267       Standard::Free (aPtr);
268       aBuffer = NULL;
269       continue;
270     }
271
272     std::cout << "FeedBack result= " << aResult << "\n";
273     GLint aPntNb     = 0;
274     GLint aTriNb     = 0;
275     GLint aQuadsNb   = 0;
276     GLint aPolyNb    = 0;
277     GLint aNodesNb   = 0;
278     GLint aLinesNb   = 0;
279     GLint aBitmapsNb = 0;
280     GLint aPassThrNb = 0;
281     GLint aUnknownNb = 0;
282     const GLint NODE_VALUES = 2; // GL_2D
283     for (GLint anIter = 0; anIter < aResult;)
284     {
285         const GLfloat aPos = aBuffer[anIter];
286         switch ((GLint )aPos)
287         {
288           case GL_POINT_TOKEN:
289           {
290             ++aPntNb;
291             ++aNodesNb;
292             anIter += 1 + NODE_VALUES;
293             break;
294           }
295           case GL_LINE_RESET_TOKEN:
296           case GL_LINE_TOKEN:
297           {
298             ++aLinesNb;
299             aNodesNb += 2;
300             anIter += 1 + 2 * NODE_VALUES;
301             break;
302           }
303           case GL_POLYGON_TOKEN:
304           {
305             const GLint aCount = (GLint )aBuffer[++anIter];
306             aNodesNb += aCount;
307             anIter += aCount * NODE_VALUES + 1;
308             if (aCount == 3)
309             {
310               ++aTriNb;
311             }
312             else if (aCount == 4)
313             {
314               ++aQuadsNb;
315             }
316             else
317             {
318               ++aPolyNb;
319             }
320             break;
321           }
322           case GL_BITMAP_TOKEN:
323           case GL_DRAW_PIXEL_TOKEN:
324           case GL_COPY_PIXEL_TOKEN:
325           {
326             ++aBitmapsNb;
327             anIter += 1 + NODE_VALUES;
328             break;
329           }
330           case GL_PASS_THROUGH_TOKEN:
331           {
332             ++aPassThrNb;
333             anIter += 2; // header + value
334             break;
335           }
336           default:
337           {
338             ++anIter;
339             ++aUnknownNb;
340             break;
341           }
342        }
343     }
344     void* aPtr = aBuffer;
345     Standard::Free (aPtr);
346
347     // return statistics
348     theDI << "Total nodes:   " << aNodesNb   << "\n"
349           << "Points:        " << aPntNb     << "\n"
350           << "Line segments: " << aLinesNb   << "\n"
351           << "Triangles:     " << aTriNb     << "\n"
352           << "Quads:         " << aQuadsNb   << "\n"
353           << "Polygons:      " << aPolyNb    << "\n"
354           << "Bitmap tokens: " << aBitmapsNb << "\n"
355           << "Pass through:  " << aPassThrNb << "\n"
356           << "UNKNOWN:       " << aUnknownNb << "\n";
357
358     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
359     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
360     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
361     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
362           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
363           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
364     return 0;
365   }
366 }
367
368 //==============================================================================
369 //function : VImmediateFront
370 //purpose  :
371 //==============================================================================
372
373 static int VImmediateFront (Draw_Interpretor& /*theDI*/,
374                             Standard_Integer  theArgNb,
375                             const char**      theArgVec)
376 {
377   // get the context
378   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
379   if (aContextAIS.IsNull())
380   {
381     std::cerr << "No active view. Please call vinit.\n";
382     return 1;
383   }
384
385   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
386
387   if (aDriver.IsNull())
388   {
389     std::cerr << "Graphic driver not available.\n";
390     return 1;
391   }
392
393   if (theArgNb < 2)
394   {
395     std::cerr << "Wrong number of arguments.\n";
396     return 1;
397   }
398
399   ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
400
401   return 0;
402 }
403
404 //! Search the info from the key.
405 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
406                                            const TCollection_AsciiString& theKey)
407 {
408   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
409   {
410     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
411     {
412       return anIter.Value();
413     }
414   }
415   return TCollection_AsciiString();
416 }
417
418 //==============================================================================
419 //function : VGlInfo
420 //purpose  :
421 //==============================================================================
422
423 static int VGlInfo (Draw_Interpretor& theDI,
424                     Standard_Integer  theArgNb,
425                     const char**      theArgVec)
426 {
427   // get the active view
428   Handle(V3d_View) aView = ViewerTest::CurrentView();
429   if (aView.IsNull())
430   {
431     std::cerr << "No active view. Please call vinit.\n";
432     return 1;
433   }
434
435   Standard_Integer anArgIter = 1;
436   Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
437   if (theArgNb == 2)
438   {
439     TCollection_AsciiString aName (theArgVec[1]);
440     aName.LowerCase();
441     if (aName == "-short")
442     {
443       ++anArgIter;
444       anInfoLevel = Graphic3d_DiagnosticInfo_Short;
445     }
446     else if (aName == "-basic")
447     {
448       ++anArgIter;
449       anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
450     }
451     else if (aName == "-complete"
452           || aName == "-full")
453     {
454       ++anArgIter;
455       anInfoLevel = Graphic3d_DiagnosticInfo_Complete;
456     }
457   }
458
459   TColStd_IndexedDataMapOfStringString aDict;
460   if (anArgIter >= theArgNb)
461   {
462     aView->DiagnosticInformation (aDict, anInfoLevel);
463     TCollection_AsciiString aText;
464     for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aDict); aValueIter.More(); aValueIter.Next())
465     {
466       if (!aText.IsEmpty())
467       {
468         aText += "\n";
469       }
470       aText += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
471     }
472
473     theDI << "OpenGL info:\n"
474           << aText;
475     return 0;
476   }
477
478   const Standard_Boolean isList = theArgNb >= 3;
479   aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
480   for (; anArgIter < theArgNb; ++anArgIter)
481   {
482     TCollection_AsciiString aName (theArgVec[anArgIter]);
483     aName.UpperCase();
484     TCollection_AsciiString aValue;
485     if (aName.Search ("VENDOR") != -1)
486     {
487       aValue = searchInfo (aDict, "GLvendor");
488     }
489     else if (aName.Search ("RENDERER") != -1)
490     {
491       aValue = searchInfo (aDict, "GLdevice");
492     }
493     else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
494           || aName.Search ("GLSL") != -1)
495     {
496       aValue = searchInfo (aDict, "GLSLversion");
497     }
498     else if (aName.Search ("VERSION") != -1)
499     {
500       aValue = searchInfo (aDict, "GLversion");
501     }
502     else if (aName.Search ("EXTENSIONS") != -1)
503     {
504       aValue = searchInfo (aDict, "GLextensions");
505     }
506     else
507     {
508       std::cerr << "Unknown key '" << aName.ToCString() << "'\n";
509       return 1;
510     }
511
512     if (isList)
513     {
514       theDI << "{" << aValue << "} ";
515     }
516     else
517     {
518       theDI << aValue;
519     }
520   }
521
522   return 0;
523 }
524
525
526 //==============================================================================
527 //function : VShaderProg
528 //purpose  : Sets the pair of vertex and fragment shaders for the object
529 //==============================================================================
530 static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
531                                      Standard_Integer  theArgNb,
532                                      const char**      theArgVec)
533 {
534   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
535   if (aCtx.IsNull())
536   {
537     std::cerr << "Use 'vinit' command before " << theArgVec[0] << "\n";
538     return 1;
539   }
540   else if (theArgNb < 2)
541   {
542     std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
543     return 1;
544   }
545
546   TCollection_AsciiString aLastArg (theArgVec[theArgNb - 1]);
547   aLastArg.UpperCase();
548   const Standard_Boolean toTurnOff = aLastArg == "OFF";
549   Standard_Integer       anArgsNb  = theArgNb - 1;
550   Handle(Graphic3d_ShaderProgram) aProgram;
551   if (!toTurnOff
552    && aLastArg == "PHONG")
553   {
554     aProgram = new Graphic3d_ShaderProgram (Graphic3d_ShaderProgram::ShaderName_Phong);
555   }
556   if (!toTurnOff
557    && aProgram.IsNull())
558   {
559     if (theArgNb < 3)
560     {
561       std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
562       return 1;
563     }
564
565     const TCollection_AsciiString aSrcVert = theArgVec[theArgNb - 2];
566     const TCollection_AsciiString aSrcFrag = theArgVec[theArgNb - 1];
567     if (!aSrcVert.IsEmpty()
568      && !OSD_File (aSrcVert).Exists())
569     {
570       std::cerr << "Non-existing vertex shader source\n";
571       return 1;
572     }
573     if (!aSrcFrag.IsEmpty()
574      && !OSD_File (aSrcFrag).Exists())
575     {
576       std::cerr << "Non-existing fragment shader source\n";
577       return 1;
578     }
579
580     aProgram = new Graphic3d_ShaderProgram();
581     aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
582     aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
583     anArgsNb = theArgNb - 2;
584   }
585
586   Handle(AIS_InteractiveObject) anIO;
587   if (anArgsNb <= 1
588    || *theArgVec[1] == '*')
589   {
590     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (GetMapOfAIS());
591           anIter.More(); anIter.Next())
592     {
593       anIO = Handle(AIS_InteractiveObject)::DownCast (anIter.Key1());
594       if (anIO.IsNull())
595       {
596         continue;
597       }
598
599       if (!anIO->Attributes()->HasOwnShadingAspect())
600       {
601         Handle(Prs3d_ShadingAspect) aNewAspect = new Prs3d_ShadingAspect();
602         *aNewAspect->Aspect() = *anIO->Attributes()->ShadingAspect()->Aspect();
603         aNewAspect->Aspect()->SetShaderProgram (aProgram);
604         anIO->Attributes()->SetShadingAspect (aNewAspect);
605         aCtx->Redisplay (anIO, Standard_False);
606       }
607       else
608       {
609         anIO->Attributes()->SetShaderProgram (aProgram, Graphic3d_ASPECT_FILL_AREA);
610         anIO->SynchronizeAspects();
611       }
612     }
613     aCtx->UpdateCurrentViewer();
614     return 0;
615   }
616
617   for (Standard_Integer anArgIter = 1; anArgIter < anArgsNb; ++anArgIter)
618   {
619     const TCollection_AsciiString aName (theArgVec[anArgIter]);
620     if (!GetMapOfAIS().IsBound2 (aName))
621     {
622       std::cerr << "Warning: " << aName.ToCString() << " is not displayed\n";
623       continue;
624     }
625     anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (aName));
626     if (anIO.IsNull())
627     {
628       std::cerr << "Warning: " << aName.ToCString() << " is not an AIS object\n";
629       continue;
630     }
631
632     if (!anIO->Attributes()->HasOwnShadingAspect())
633     {
634       Handle(Prs3d_ShadingAspect) aNewAspect = new Prs3d_ShadingAspect();
635       *aNewAspect->Aspect() = *anIO->Attributes()->ShadingAspect()->Aspect();
636       aNewAspect->Aspect()->SetShaderProgram (aProgram);
637       anIO->Attributes()->SetShadingAspect (aNewAspect);
638       aCtx->Redisplay (anIO, Standard_False);
639     }
640     else
641     {
642       anIO->Attributes()->SetShaderProgram (aProgram, Graphic3d_ASPECT_FILL_AREA);
643       anIO->SynchronizeAspects();
644     }
645   }
646
647   aCtx->UpdateCurrentViewer();
648   return 0;
649 }
650
651 //=======================================================================
652 //function : OpenGlCommands
653 //purpose  :
654 //=======================================================================
655
656 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
657 {
658   const char* aGroup ="Commands for low-level TKOpenGl features";
659
660   theCommands.Add("vuserdraw",
661     "vuserdraw : name - simulates drawing with help of UserDraw",
662     __FILE__, VUserDraw, aGroup);
663   theCommands.Add("vfeedback",
664     "vfeedback       : perform test GL feedback rendering",
665     __FILE__, VFeedback, aGroup);
666   theCommands.Add("vimmediatefront",
667     "vimmediatefront : render immediate mode to front buffer or to back buffer",
668     __FILE__, VImmediateFront, aGroup);
669   theCommands.Add("vglinfo",
670                 "vglinfo [-short|-basic|-complete]"
671         "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
672         "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
673         "\n\t\t: print OpenGL info",
674     __FILE__, VGlInfo, aGroup);
675   theCommands.Add("vshaderprog",
676             "   'vshaderprog [name] pathToVertexShader pathToFragmentShader'"
677     "\n\t\t: or 'vshaderprog [name] off'   to disable GLSL program"
678     "\n\t\t: or 'vshaderprog [name] phong' to enable per-pixel lighting calculations"
679     "\n\t\t: * might be used to specify all displayed objects",
680     __FILE__, VShaderProg, aGroup);
681 }