b6d41ec969bec0d73db74ec9d46bae859b9e3f6d
[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 <Image_AlienPixMap.hxx>
26 #include <OpenGl_Aspects.hxx>
27 #include <OpenGl_Context.hxx>
28 #include <OpenGl_Element.hxx>
29 #include <OpenGl_GlCore20.hxx>
30 #include <OpenGl_GraphicDriver.hxx>
31 #include <OpenGl_ShaderManager.hxx>
32 #include <OpenGl_Workspace.hxx>
33 #include <OSD_Environment.hxx>
34 #include <OSD_File.hxx>
35 #include <Prs3d_Drawer.hxx>
36 #include <Prs3d_Presentation.hxx>
37 #include <Prs3d_Root.hxx>
38 #include <Prs3d_LineAspect.hxx>
39 #include <Prs3d_ShadingAspect.hxx>
40 #include <Select3D_SensitiveCurve.hxx>
41 #include <SelectMgr_EntityOwner.hxx>
42 #include <SelectMgr_Selection.hxx>
43 #include <TCollection_AsciiString.hxx>
44 #include <V3d_View.hxx>
45 #include <V3d_Viewer.hxx>
46 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
47 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
48 #include <OpenGl_Group.hxx>
49 #include <OSD_OpenFile.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();
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   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
158
159   // To test linking against OpenGl_Workspace and all aspect classes
160   const OpenGl_Aspects* aMA = theWorkspace->Aspects();
161   aMA->Aspect()->MarkerType();
162   OpenGl_Vec4 aColor = theWorkspace->InteriorColor();
163
164   aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID,
165                                           Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, false,
166                                           Handle(OpenGl_ShaderProgram)());
167   aCtx->SetColor4fv (aColor);
168
169   const OpenGl_Vec3 aVertArray[4] =
170   {
171     OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[2]),
172     OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[2]),
173     OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[5]),
174     OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[5]),
175   };
176   Handle(OpenGl_VertexBuffer) aVertBuffer = new OpenGl_VertexBuffer();
177   aVertBuffer->Init (aCtx, 3, 4, aVertArray[0].GetData());
178
179   // Finally draw something to make sure UserDraw really works
180   aVertBuffer->BindAttribute  (aCtx, Graphic3d_TOA_POS);
181   glDrawArrays(GL_LINE_LOOP, 0, aVertBuffer->GetElemsNb());
182   aVertBuffer->UnbindAttribute(aCtx, Graphic3d_TOA_POS);
183   aVertBuffer->Release (aCtx.get());
184 }
185
186 } // end of anonymous namespace
187
188 static Standard_Integer VUserDraw (Draw_Interpretor& di,
189                                     Standard_Integer argc,
190                                     const char ** argv)
191 {
192   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
193   if (aContext.IsNull())
194   {
195     di << argv[0] << "Call 'vinit' before!\n";
196     return 1;
197   }
198
199   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
200   if (aDriver.IsNull())
201   {
202     std::cerr << "Graphic driver not available.\n";
203     return 1;
204   }
205
206   if (argc > 2)
207   {
208     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
209     return 1;
210   }
211
212   TCollection_AsciiString aName (argv[1]);
213   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
214
215   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
216   VDisplayAISObject(aName, anIObj);
217
218   return 0;
219 }
220
221 //==============================================================================
222 //function : VFeedback
223 //purpose  :
224 //==============================================================================
225
226 static int VFeedback (Draw_Interpretor& theDI,
227                       Standard_Integer  /*theArgNb*/,
228                       const char**      /*theArgVec*/)
229 {
230 #if !defined(GL_ES_VERSION_2_0)
231   // get the active view
232   Handle(V3d_View) aView = ViewerTest::CurrentView();
233   if (aView.IsNull())
234   {
235     std::cerr << "No active view. Please call vinit.\n";
236     return 1;
237   }
238
239   unsigned int aBufferSize = 1024 * 1024;
240   for (;;)
241   {
242     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
243     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
244     {
245       // finito la commedia
246       std::cerr << "Can not allocate buffer - requested size ("
247                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
248                 << " MiB) is out of address space\n";
249       return 1;
250     }
251
252     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
253     if (aBuffer == NULL)
254     {
255       // finito la commedia
256       std::cerr << "Can not allocate buffer with size ("
257                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
258                 << " MiB)\n";
259       return 1;
260     }
261
262     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
263     glRenderMode (GL_FEEDBACK);
264
265     aView->Redraw();
266
267     GLint aResult = glRenderMode (GL_RENDER);
268     if (aResult < 0)
269     {
270       aBufferSize *= 2;
271
272       void* aPtr = aBuffer;
273       Standard::Free (aPtr);
274       aBuffer = NULL;
275       continue;
276     }
277
278     std::cout << "FeedBack result= " << aResult << "\n";
279     GLint aPntNb     = 0;
280     GLint aTriNb     = 0;
281     GLint aQuadsNb   = 0;
282     GLint aPolyNb    = 0;
283     GLint aNodesNb   = 0;
284     GLint aLinesNb   = 0;
285     GLint aBitmapsNb = 0;
286     GLint aPassThrNb = 0;
287     GLint aUnknownNb = 0;
288     const GLint NODE_VALUES = 2; // GL_2D
289     for (GLint anIter = 0; anIter < aResult;)
290     {
291         const GLfloat aPos = aBuffer[anIter];
292         switch ((GLint )aPos)
293         {
294           case GL_POINT_TOKEN:
295           {
296             ++aPntNb;
297             ++aNodesNb;
298             anIter += 1 + NODE_VALUES;
299             break;
300           }
301           case GL_LINE_RESET_TOKEN:
302           case GL_LINE_TOKEN:
303           {
304             ++aLinesNb;
305             aNodesNb += 2;
306             anIter += 1 + 2 * NODE_VALUES;
307             break;
308           }
309           case GL_POLYGON_TOKEN:
310           {
311             const GLint aCount = (GLint )aBuffer[++anIter];
312             aNodesNb += aCount;
313             anIter += aCount * NODE_VALUES + 1;
314             if (aCount == 3)
315             {
316               ++aTriNb;
317             }
318             else if (aCount == 4)
319             {
320               ++aQuadsNb;
321             }
322             else
323             {
324               ++aPolyNb;
325             }
326             break;
327           }
328           case GL_BITMAP_TOKEN:
329           case GL_DRAW_PIXEL_TOKEN:
330           case GL_COPY_PIXEL_TOKEN:
331           {
332             ++aBitmapsNb;
333             anIter += 1 + NODE_VALUES;
334             break;
335           }
336           case GL_PASS_THROUGH_TOKEN:
337           {
338             ++aPassThrNb;
339             anIter += 2; // header + value
340             break;
341           }
342           default:
343           {
344             ++anIter;
345             ++aUnknownNb;
346             break;
347           }
348        }
349     }
350     void* aPtr = aBuffer;
351     Standard::Free (aPtr);
352
353     // return statistics
354     theDI << "Total nodes:   " << aNodesNb   << "\n"
355           << "Points:        " << aPntNb     << "\n"
356           << "Line segments: " << aLinesNb   << "\n"
357           << "Triangles:     " << aTriNb     << "\n"
358           << "Quads:         " << aQuadsNb   << "\n"
359           << "Polygons:      " << aPolyNb    << "\n"
360           << "Bitmap tokens: " << aBitmapsNb << "\n"
361           << "Pass through:  " << aPassThrNb << "\n"
362           << "UNKNOWN:       " << aUnknownNb << "\n";
363
364     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
365     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
366     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
367     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
368           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
369           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
370     return 0;
371   }
372 #else
373   (void )theDI;
374   std::cout << "Command is unsupported on current platform.\n";
375   return 1;
376 #endif
377 }
378
379 //==============================================================================
380 //function : VImmediateFront
381 //purpose  :
382 //==============================================================================
383
384 static int VImmediateFront (Draw_Interpretor& /*theDI*/,
385                             Standard_Integer  theArgNb,
386                             const char**      theArgVec)
387 {
388   // get the context
389   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
390   if (aContextAIS.IsNull())
391   {
392     std::cerr << "No active view. Please call vinit.\n";
393     return 1;
394   }
395
396   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
397
398   if (aDriver.IsNull())
399   {
400     std::cerr << "Graphic driver not available.\n";
401     return 1;
402   }
403
404   if (theArgNb < 2)
405   {
406     std::cerr << "Wrong number of arguments.\n";
407     return 1;
408   }
409
410   ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
411
412   return 0;
413 }
414
415 //! Search the info from the key.
416 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
417                                            const TCollection_AsciiString& theKey)
418 {
419   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
420   {
421     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
422     {
423       return anIter.Value();
424     }
425   }
426   return TCollection_AsciiString();
427 }
428
429 //==============================================================================
430 //function : VGlInfo
431 //purpose  :
432 //==============================================================================
433
434 static int VGlInfo (Draw_Interpretor& theDI,
435                     Standard_Integer  theArgNb,
436                     const char**      theArgVec)
437 {
438   // get the active view
439   Handle(V3d_View) aView = ViewerTest::CurrentView();
440   if (aView.IsNull())
441   {
442     std::cerr << "No active view. Please call vinit.\n";
443     return 1;
444   }
445
446   Standard_Integer anArgIter = 1;
447   Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
448   if (theArgNb == 2)
449   {
450     TCollection_AsciiString aName (theArgVec[1]);
451     aName.LowerCase();
452     if (aName == "-short")
453     {
454       ++anArgIter;
455       anInfoLevel = Graphic3d_DiagnosticInfo_Short;
456     }
457     else if (aName == "-basic")
458     {
459       ++anArgIter;
460       anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
461     }
462     else if (aName == "-complete"
463           || aName == "-full")
464     {
465       ++anArgIter;
466       anInfoLevel = Graphic3d_DiagnosticInfo_Complete;
467     }
468   }
469
470   TColStd_IndexedDataMapOfStringString aDict;
471   if (anArgIter >= theArgNb)
472   {
473     aView->DiagnosticInformation (aDict, anInfoLevel);
474     TCollection_AsciiString aText;
475     for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aDict); aValueIter.More(); aValueIter.Next())
476     {
477       if (!aText.IsEmpty())
478       {
479         aText += "\n";
480       }
481       aText += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
482     }
483
484     theDI << "OpenGL info:\n"
485           << aText;
486     return 0;
487   }
488
489   const Standard_Boolean isList = theArgNb >= 3;
490   aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
491   for (; anArgIter < theArgNb; ++anArgIter)
492   {
493     TCollection_AsciiString aName (theArgVec[anArgIter]);
494     aName.UpperCase();
495     TCollection_AsciiString aValue;
496     if (aName.Search ("VENDOR") != -1)
497     {
498       aValue = searchInfo (aDict, "GLvendor");
499     }
500     else if (aName.Search ("RENDERER") != -1)
501     {
502       aValue = searchInfo (aDict, "GLdevice");
503     }
504     else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
505           || aName.Search ("GLSL") != -1)
506     {
507       aValue = searchInfo (aDict, "GLSLversion");
508     }
509     else if (aName.Search ("VERSION") != -1)
510     {
511       aValue = searchInfo (aDict, "GLversion");
512     }
513     else if (aName.Search ("EXTENSIONS") != -1)
514     {
515       aValue = searchInfo (aDict, "GLextensions");
516     }
517     else
518     {
519       std::cerr << "Unknown key '" << aName.ToCString() << "'\n";
520       return 1;
521     }
522
523     if (isList)
524     {
525       theDI << "{" << aValue << "} ";
526     }
527     else
528     {
529       theDI << aValue;
530     }
531   }
532
533   return 0;
534 }
535
536 //! Parse shader type argument.
537 static bool parseShaderTypeArg (Graphic3d_TypeOfShaderObject& theType,
538                                 const TCollection_AsciiString& theArg)
539 {
540   if (theArg == "-vertex"
541    || theArg == "-vert")
542   {
543     theType = Graphic3d_TOS_VERTEX;
544   }
545   else if (theArg == "-tessevaluation"
546         || theArg == "-tesseval"
547         || theArg == "-evaluation"
548         || theArg == "-eval")
549   {
550     theType = Graphic3d_TOS_TESS_EVALUATION;
551   }
552   else if (theArg == "-tesscontrol"
553         || theArg == "-tessctrl"
554         || theArg == "-control"
555         || theArg == "-ctrl")
556   {
557     theType = Graphic3d_TOS_TESS_CONTROL;
558   }
559   else if (theArg == "-geometry"
560         || theArg == "-geom")
561   {
562     theType = Graphic3d_TOS_GEOMETRY;
563   }
564   else if (theArg == "-fragment"
565         || theArg == "-frag")
566   {
567     theType = Graphic3d_TOS_FRAGMENT;
568   }
569   else if (theArg == "-compute"
570         || theArg == "-comp")
571   {
572     theType = Graphic3d_TOS_COMPUTE;
573   }
574   else
575   {
576     return false;
577   }
578   return true;
579 }
580
581 //==============================================================================
582 //function : VShaderProg
583 //purpose  : Sets the pair of vertex and fragment shaders for the object
584 //==============================================================================
585 static Standard_Integer VShaderProg (Draw_Interpretor& theDI,
586                                      Standard_Integer  theArgNb,
587                                      const char**      theArgVec)
588 {
589   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
590   if (aCtx.IsNull())
591   {
592     std::cout << "Error: no active view.\n";
593     return 1;
594   }
595   else if (theArgNb < 2)
596   {
597     std::cout << "Syntax error: lack of arguments\n";
598     return 1;
599   }
600
601   bool isExplicitShaderType = false;
602   Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
603   NCollection_Sequence<Handle(AIS_InteractiveObject)> aPrsList;
604   Graphic3d_GroupAspect aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
605   bool isSetGroupAspect = false;
606   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
607   {
608     TCollection_AsciiString anArg (theArgVec[anArgIter]);
609     anArg.LowerCase();
610     Graphic3d_TypeOfShaderObject aShaderTypeArg = Graphic3d_TypeOfShaderObject(-1);
611     if (!aProgram.IsNull()
612       && anArg == "-uniform"
613       && anArgIter + 2 < theArgNb)
614     {
615       TCollection_AsciiString aName = theArgVec[++anArgIter];
616       aProgram->PushVariableFloat (aName, float (Draw::Atof (theArgVec[++anArgIter])));
617     }
618     else if (anArg == "-list"
619           || ((anArg == "-update"
620             || anArg == "-dump"
621             || anArg == "-debug"
622             || anArg == "-reload"
623             || anArg == "-load")
624            && anArgIter + 1 < theArgNb))
625     {
626       Handle(OpenGl_Context) aGlCtx;
627       if (Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aCtx->CurrentViewer()->Driver()))
628       {
629         aGlCtx = aDriver->GetSharedContext();
630       }
631       if (aGlCtx.IsNull())
632       {
633         std::cout << "Error: no OpenGl_Context\n";
634         return 1;
635       }
636
637       if (anArg == "-list")
638       {
639         for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (aGlCtx->SharedResources()); aResIter.More(); aResIter.Next())
640         {
641           if (Handle(OpenGl_ShaderProgram) aResProg = Handle(OpenGl_ShaderProgram)::DownCast (aResIter.Value()))
642           {
643             theDI << aResProg->ResourceId() << " ";
644           }
645         }
646       }
647       else
648       {
649         TCollection_AsciiString aShaderName = theArgVec[++anArgIter];
650         Handle(OpenGl_ShaderProgram) aResProg;
651         if (!aGlCtx->GetResource (aShaderName, aResProg))
652         {
653           std::cout << "Syntax error: shader resource '" << aShaderName << "' is not found\n";
654           return 1;
655         }
656         if (aResProg->UpdateDebugDump (aGlCtx, "", false, anArg == "-dump"))
657         {
658           aCtx->UpdateCurrentViewer();
659         }
660       }
661       if (anArgIter + 1 < theArgNb)
662       {
663         std::cout << "Syntax error: wrong number of arguments\n";
664         return 1;
665       }
666       return 0;
667     }
668     else if (!aProgram.IsNull()
669           &&  aProgram->ShaderObjects().IsEmpty()
670           && (anArg == "-off"
671            || anArg ==  "off"))
672     {
673       aProgram.Nullify();
674     }
675     else if (!aProgram.IsNull()
676           &&  aProgram->ShaderObjects().IsEmpty()
677           && (anArg == "-phong"
678            || anArg ==  "phong"))
679     {
680       const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
681       if (aShadersRoot.IsEmpty())
682       {
683         std::cout << "Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
684                      "At least one should be defined to load Phong program.\n";
685         return 1;
686       }
687
688       const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
689       const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
690       if (!aSrcVert.IsEmpty()
691        && !OSD_File (aSrcVert).Exists())
692       {
693         std::cout << "Error: PhongShading.vs is not found\n";
694         return 1;
695       }
696       if (!aSrcFrag.IsEmpty()
697        && !OSD_File (aSrcFrag).Exists())
698       {
699         std::cout << "Error: PhongShading.fs is not found\n";
700         return 1;
701       }
702
703       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
704       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
705     }
706     else if (aPrsList.IsEmpty()
707           && anArg == "*")
708     {
709       //
710     }
711     else if (!isSetGroupAspect
712           &&  anArgIter + 1 < theArgNb
713           && (anArg == "-primtype"
714            || anArg == "-primitivetype"
715            || anArg == "-groupaspect"
716            || anArg == "-aspecttype"
717            || anArg == "-aspect"))
718     {
719       isSetGroupAspect = true;
720       TCollection_AsciiString aPrimTypeStr (theArgVec[++anArgIter]);
721       aPrimTypeStr.LowerCase();
722       if (aPrimTypeStr == "line")
723       {
724         aGroupAspect = Graphic3d_ASPECT_LINE;
725       }
726       else if (aPrimTypeStr == "tris"
727             || aPrimTypeStr == "triangles"
728             || aPrimTypeStr == "fill"
729             || aPrimTypeStr == "fillarea"
730             || aPrimTypeStr == "shading"
731             || aPrimTypeStr == "shade")
732       {
733         aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
734       }
735       else if (aPrimTypeStr == "text")
736       {
737         aGroupAspect = Graphic3d_ASPECT_TEXT;
738       }
739       else if (aPrimTypeStr == "marker"
740             || aPrimTypeStr == "point"
741             || aPrimTypeStr == "pnt")
742       {
743         aGroupAspect = Graphic3d_ASPECT_MARKER;
744       }
745       else
746       {
747         std::cerr << "Syntax error at '" << aPrimTypeStr << "'\n";
748         return 1;
749       }
750     }
751     else if (anArgIter + 1 < theArgNb
752          && !aProgram.IsNull()
753          &&  aProgram->Header().IsEmpty()
754          &&  (anArg == "-version"
755            || anArg == "-glslversion"
756            || anArg == "-header"
757            || anArg == "-glslheader"))
758     {
759       TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
760       if (aHeader.IsIntegerValue())
761       {
762         aHeader = TCollection_AsciiString ("#version ") + aHeader;
763       }
764       aProgram->SetHeader (aHeader);
765     }
766     else if (!anArg.StartsWith ("-")
767           && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
768     {
769       Handle(AIS_InteractiveObject) anIO = GetMapOfAIS().Find2 (theArgVec[anArgIter]);
770       if (anIO.IsNull())
771       {
772         std::cerr << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object\n";
773         return 1;
774       }
775       aPrsList.Append (anIO);
776     }
777     else if (!aProgram.IsNull()
778            && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
779             || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
780     {
781       TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
782       if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
783       {
784         aShaderPath = (theArgVec[++anArgIter]);
785         isExplicitShaderType = true;
786       }
787
788       const bool isSrcFile = OSD_File (aShaderPath).Exists();
789       Handle(Graphic3d_ShaderObject) aShader = isSrcFile
790                                              ? Graphic3d_ShaderObject::CreateFromFile  (Graphic3d_TOS_VERTEX, aShaderPath)
791                                              : Graphic3d_ShaderObject::CreateFromSource(Graphic3d_TOS_VERTEX, aShaderPath);
792       const TCollection_AsciiString& aShaderSrc = aShader->Source();
793
794       const bool hasVertPos   = aShaderSrc.Search ("gl_Position")  != -1;
795       const bool hasFragColor = aShaderSrc.Search ("occSetFragColor") != -1
796                              || aShaderSrc.Search ("occFragColor") != -1
797                              || aShaderSrc.Search ("gl_FragColor") != -1
798                              || aShaderSrc.Search ("gl_FragData")  != -1;
799       Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
800       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
801       {
802         if (hasVertPos
803         && !hasFragColor)
804         {
805           aShaderType = Graphic3d_TOS_VERTEX;
806         }
807         if (hasFragColor
808         && !hasVertPos)
809         {
810           aShaderType = Graphic3d_TOS_FRAGMENT;
811         }
812       }
813       if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
814       {
815         std::cerr << "Error: non-existing or invalid shader source\n";
816         return 1;
817       }
818
819       aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
820     }
821     else
822     {
823       std::cerr << "Syntax error at '" << anArg << "'\n";
824       return 1;
825     }
826   }
827
828   if (!aProgram.IsNull()
829     && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
830   {
831     aProgram->SetNbFragmentOutputs (2);
832     aProgram->SetWeightOitOutput (true);
833   }
834
835   ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
836   NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
837   const bool isGlobalList = aPrsList.IsEmpty();
838   for (;;)
839   {
840     Handle(AIS_InteractiveObject) anIO;
841     if (isGlobalList)
842     {
843       if (!aGlobalPrsIter.More())
844       {
845         break;
846       }
847       anIO = aGlobalPrsIter.Key1();
848       aGlobalPrsIter.Next();
849       if (anIO.IsNull())
850       {
851         continue;
852       }
853     }
854     else
855     {
856       if (!aPrsIter.More())
857       {
858         break;
859       }
860       anIO = aPrsIter.Value();
861       aPrsIter.Next();
862     }
863
864     if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
865     {
866       aCtx->Redisplay (anIO, Standard_False);
867     }
868     else
869     {
870       anIO->SynchronizeAspects();
871     }
872   }
873
874   aCtx->UpdateCurrentViewer();
875   return 0;
876 }
877
878 //! Print triplet of values.
879 template<class S, class T> static S& operator<< (S& theStream, const NCollection_Vec3<T>& theVec)
880 {
881   theStream << theVec[0] << " " << theVec[1] << " " << theVec[2];
882   return theStream;
883 }
884
885 //! Print 4 values.
886 template<class S, class T> static S& operator<< (S& theStream, const NCollection_Vec4<T>& theVec)
887 {
888   theStream << theVec[0] << " " << theVec[1] << " " << theVec[2] << " " << theVec[3];
889   return theStream;
890 }
891
892 //! Print fresnel model.
893 static const char* fresnelModelString (const Graphic3d_FresnelModel theModel)
894 {
895   switch (theModel)
896   {
897     case Graphic3d_FM_SCHLICK:    return "SCHLICK";
898     case Graphic3d_FM_CONSTANT:   return "CONSTANT";
899     case Graphic3d_FM_CONDUCTOR:  return "CONDUCTOR";
900     case Graphic3d_FM_DIELECTRIC: return "DIELECTRIC";
901   }
902   return "N/A";
903 }
904
905 //! Create a colored rectangle SVG element.
906 static TCollection_AsciiString formatSvgColoredRect (const Quantity_Color& theColor)
907 {
908   return TCollection_AsciiString()
909        + "<svg width='20px' height='20px'><rect width='20px' height='20px' fill='" + Quantity_Color::ColorToHex (theColor) + "' /></svg>";
910 }
911
912 //==============================================================================
913 //function : VListMaterials
914 //purpose  :
915 //==============================================================================
916 static Standard_Integer VListMaterials (Draw_Interpretor& theDI,
917                                         Standard_Integer  theArgNb,
918                                         const char**      theArgVec)
919 {
920   TCollection_AsciiString aDumpFile;
921   NCollection_Sequence<Graphic3d_NameOfMaterial> aMatList;
922   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
923   {
924     TCollection_AsciiString anArg (theArgVec[anArgIter]);
925     anArg.LowerCase();
926     Graphic3d_NameOfMaterial aMat = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter]);
927     if (aMat != Graphic3d_NOM_DEFAULT)
928     {
929       aMatList.Append (aMat);
930     }
931     else if (anArg == "*")
932     {
933       for (Standard_Integer aMatIter = 0; aMatIter < (Standard_Integer )Graphic3d_NOM_DEFAULT; ++aMatIter)
934       {
935         aMatList.Append ((Graphic3d_NameOfMaterial )aMatIter);
936       }
937     }
938     else if (aDumpFile.IsEmpty()
939           && (anArg.EndsWith (".obj")
940            || anArg.EndsWith (".mtl")
941            || anArg.EndsWith (".htm")
942            || anArg.EndsWith (".html")))
943     {
944       aDumpFile = theArgVec[anArgIter];
945     }
946     else
947     {
948       std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'\n";
949       return 1;
950     }
951   }
952   if (aMatList.IsEmpty())
953   {
954     if (aDumpFile.IsEmpty())
955     {
956       for (Standard_Integer aMatIter = 1; aMatIter <= Graphic3d_MaterialAspect::NumberOfMaterials(); ++aMatIter)
957       {
958         theDI << Graphic3d_MaterialAspect::MaterialName (aMatIter) << " ";
959       }
960       return 0;
961     }
962
963     for (Standard_Integer aMatIter = 0; aMatIter < (Standard_Integer )Graphic3d_NOM_DEFAULT; ++aMatIter)
964     {
965       aMatList.Append ((Graphic3d_NameOfMaterial )aMatIter);
966     }
967   }
968
969   // geometry for dumping
970   const Graphic3d_Vec3 aBoxVerts[8] =
971   {
972     Graphic3d_Vec3( 1, -1, -1),
973     Graphic3d_Vec3( 1, -1,  1),
974     Graphic3d_Vec3(-1, -1,  1),
975     Graphic3d_Vec3(-1, -1, -1),
976     Graphic3d_Vec3( 1,  1, -1),
977     Graphic3d_Vec3( 1,  1,  1),
978     Graphic3d_Vec3(-1,  1,  1),
979     Graphic3d_Vec3(-1,  1, -1)
980   };
981
982   const Graphic3d_Vec4i aBoxQuads[6] =
983   {
984     Graphic3d_Vec4i (1, 2, 3, 4),
985     Graphic3d_Vec4i (5, 8, 7, 6),
986     Graphic3d_Vec4i (1, 5, 6, 2),
987     Graphic3d_Vec4i (2, 6, 7, 3),
988     Graphic3d_Vec4i (3, 7, 8, 4),
989     Graphic3d_Vec4i (5, 1, 4, 8)
990   };
991
992   std::ofstream aMatFile, anObjFile, anHtmlFile;
993   if (aDumpFile.EndsWith (".obj")
994    || aDumpFile.EndsWith (".mtl"))
995   {
996     const TCollection_AsciiString aMatFilePath  = aDumpFile.SubString (1, aDumpFile.Length() - 3) + "mtl";
997     const TCollection_AsciiString anObjFilePath = aDumpFile.SubString (1, aDumpFile.Length() - 3) + "obj";
998
999     OSD_OpenStream (aMatFile,  aMatFilePath.ToCString(),  std::ios::out | std::ios::binary);
1000     if (!aMatFile.is_open())
1001     {
1002       std::cout << "Error: unable creating material file\n";
1003       return 0;
1004     }
1005     if (!aDumpFile.EndsWith (".mtl"))
1006     {
1007       OSD_OpenStream (anObjFile, anObjFilePath.ToCString(), std::ios::out | std::ios::binary);
1008       if (!anObjFile.is_open())
1009       {
1010         std::cout << "Error: unable creating OBJ file\n";
1011         return 0;
1012       }
1013
1014       TCollection_AsciiString anMtlName, aFolder;
1015       OSD_Path::FolderAndFileFromPath (aMatFilePath, aFolder, anMtlName);
1016       anObjFile << "mtllib " << anMtlName << "\n";
1017     }
1018   }
1019   else if (aDumpFile.EndsWith (".htm")
1020         || aDumpFile.EndsWith (".html"))
1021   {
1022     OSD_OpenStream (anHtmlFile, aDumpFile.ToCString(), std::ios::out | std::ios::binary);
1023     if (!anHtmlFile.is_open())
1024     {
1025       std::cout << "Error: unable creating HTML file\n";
1026       return 0;
1027     }
1028     anHtmlFile << "<html>\n"
1029                   "<head><title>OCCT Material table</title></head>\n"
1030                   "<body>\n"
1031                   "<table border='1'><tbody>\n"
1032                   "<tr>\n"
1033                   "<th rowspan='2'><div title='Material name.\n"
1034                                               "See also Graphic3d_NameOfMaterial enumeration'>"
1035                                    "Name</div></th>\n"
1036                   "<th rowspan='2'><div title='Material type: PHYSIC or ASPECT.\n"
1037                                               "ASPECT material does not define final colors, it is taken from Internal Color instead.\n"
1038                                               "See also Graphic3d_TypeOfMaterial enumeration'>"
1039                                    "Type</div></th>\n"
1040                   "<th colspan='5'><div title='Common material definition for Phong shading model'>"
1041                                    "Common</div></th>\n"
1042                   "<th rowspan='2'>Transparency</th>\n"
1043                   "<th rowspan='2'>Refraction Index</th>\n"
1044                   "<th colspan='9'><div title='BSDF (Bidirectional Scattering Distribution Function).\n"
1045                                               "Used for physically-based rendering (in path tracing engine).\n"
1046                                               "BSDF is represented as weighted mixture of basic BRDFs/BTDFs (Bidirectional Reflectance (Transmittance) Distribution Functions).\n"
1047                                               "See also Graphic3d_BSDF structure.'>"
1048                                    "BSDF</div></th>\n"
1049                   "</tr>\n"
1050                   "<tr>\n"
1051                   "<th>Ambient</th>\n"
1052                   "<th>Diffuse</th>\n"
1053                   "<th>Specular</th>\n"
1054                   "<th>Emissive</th>\n"
1055                   "<th>Shiness</th>\n"
1056                   "<th><div title='Weight of coat specular/glossy BRDF'>"
1057                        "Kc</div></th>\n"
1058                   "<th><div title='Weight of base diffuse BRDF'>"
1059                        "Kd</div></th>\n"
1060                   "<th><div title='Weight of base specular/glossy BRDF'>"
1061                        "Ks</div></th>\n"
1062                   "<th><div title='Weight of base specular/glossy BTDF'>"
1063                        "Kt</div></th>\n"
1064                   "<th><div title='Radiance emitted by the surface'>"
1065                        "Le</div></th>\n"
1066                   "<th><div title='Volume scattering color/density'>"
1067                        "Absorption</div></th>\n"
1068                   "<th><div title='Parameters of Fresnel reflectance of coat layer'>"
1069                        "FresnelCoat</div></th>\n"
1070                   "<th><div title='Parameters of Fresnel reflectance of base layer'>"
1071                        "FresnelBase</div></th>\n"
1072                   "</tr>\n";
1073   }
1074   else if (!aDumpFile.IsEmpty())
1075   {
1076     std::cout << "Syntax error: unknown output file format\n";
1077     return 1;
1078   }
1079
1080   Standard_Integer aMatIndex = 0, anX = 0, anY = 0;
1081   for (NCollection_Sequence<Graphic3d_NameOfMaterial>::Iterator aMatIter (aMatList); aMatIter.More(); aMatIter.Next(), ++aMatIndex)
1082   {
1083     Graphic3d_MaterialAspect aMat (aMatIter.Value());
1084     const TCollection_AsciiString aMatName = aMat.StringName();
1085     const Graphic3d_Vec3 anAmbient = aMat.ReflectionMode (Graphic3d_TOR_AMBIENT)
1086                                    ? (Graphic3d_Vec3 )aMat.AmbientColor()  * aMat.Ambient()
1087                                    : Graphic3d_Vec3 (0.0f);
1088     const Graphic3d_Vec3 aDiffuse  = aMat.ReflectionMode (Graphic3d_TOR_DIFFUSE)
1089                                    ? (Graphic3d_Vec3 )aMat.DiffuseColor()  * aMat.Diffuse()
1090                                    : Graphic3d_Vec3 (0.0f);
1091     const Graphic3d_Vec3 aSpecular = aMat.ReflectionMode (Graphic3d_TOR_SPECULAR)
1092                                    ? (Graphic3d_Vec3 )aMat.SpecularColor() * aMat.Specular()
1093                                    : Graphic3d_Vec3 (0.0f);
1094     const Graphic3d_Vec3 anEmission = aMat.ReflectionMode (Graphic3d_TOR_EMISSION)
1095                                    ? (Graphic3d_Vec3 )aMat.EmissiveColor() * aMat.Emissive()
1096                                    : Graphic3d_Vec3 (0.0f);
1097     const Standard_Real  aShiness  = aMat.Shininess() * 1000.0;
1098     if (aMatFile.is_open())
1099     {
1100       aMatFile << "newmtl " << aMatName << "\n";
1101       aMatFile << "Ka " << anAmbient << "\n";
1102       aMatFile << "Kd " << aDiffuse  << "\n";
1103       aMatFile << "Ks " << aSpecular << "\n";
1104       aMatFile << "Ns " << aShiness  << "\n";
1105       if (aMat.Transparency() >= 0.0001)
1106       {
1107         aMatFile << "Tr " << aMat.Transparency() << "\n";
1108       }
1109       aMatFile << "\n";
1110     }
1111     else if (anHtmlFile.is_open())
1112     {
1113       anHtmlFile << "<tr>\n";
1114       anHtmlFile << "<td>" << aMat.StringName() << "</td>\n";
1115       anHtmlFile << "<td>" << (aMat.MaterialType() == Graphic3d_MATERIAL_PHYSIC ? "PHYSIC" : "ASPECT")  << "</td>\n";
1116       anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anAmbient))  << anAmbient  << "</td>\n";
1117       anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aDiffuse))   << aDiffuse   << "</td>\n";
1118       anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aSpecular))  << aSpecular  << "</td>\n";
1119       anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anEmission)) << anEmission << "</td>\n";
1120       anHtmlFile << "<td>" << aMat.Shininess() << "</td>\n";
1121       anHtmlFile << "<td>" << aMat.Transparency() << "</td>\n";
1122       anHtmlFile << "<td>" << aMat.RefractionIndex() << "</td>\n";
1123       anHtmlFile << "<td>" << aMat.BSDF().Kc << "</td>\n";
1124       anHtmlFile << "<td>" << aMat.BSDF().Kd << "</td>\n";
1125       anHtmlFile << "<td>" << aMat.BSDF().Ks << "</td>\n";
1126       anHtmlFile << "<td>" << aMat.BSDF().Kt << "</td>\n";
1127       anHtmlFile << "<td>" << aMat.BSDF().Le << "</td>\n";
1128       anHtmlFile << "<td>" << aMat.BSDF().Absorption << "</td>\n";
1129       anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "</td>\n";
1130       anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "</td>\n";
1131       anHtmlFile << "</tr>\n";
1132     }
1133     else
1134     {
1135       theDI << aMat.StringName() << "\n";
1136       theDI << "  Common.Ambient:         " << anAmbient << "\n";
1137       theDI << "  Common.Diffuse:         " << aDiffuse  << "\n";
1138       theDI << "  Common.Specular:        " << aSpecular << "\n";
1139       theDI << "  Common.Emissive:        " << anEmission << "\n";
1140       theDI << "  Common.Shiness:         " << aMat.Shininess() << "\n";
1141       theDI << "  Common.Transparency:    " << aMat.Transparency() << "\n";
1142       theDI << "  RefractionIndex:        " << aMat.RefractionIndex() << "\n";
1143       theDI << "  BSDF.Kc:                " << aMat.BSDF().Kc << "\n";
1144       theDI << "  BSDF.Kd:                " << aMat.BSDF().Kd << "\n";
1145       theDI << "  BSDF.Ks:                " << aMat.BSDF().Ks << "\n";
1146       theDI << "  BSDF.Kt:                " << aMat.BSDF().Kt << "\n";
1147       theDI << "  BSDF.Le:                " << aMat.BSDF().Le << "\n";
1148       theDI << "  BSDF.Absorption:        " << aMat.BSDF().Absorption << "\n";
1149       theDI << "  BSDF.FresnelCoat:       " << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "\n";
1150       theDI << "  BSDF.FresnelBase:       " << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "\n";
1151     }
1152
1153     if (anObjFile.is_open())
1154     {
1155       anObjFile << "g " << aMatName << "\n";
1156       anObjFile << "usemtl " << aMatName << "\n";
1157       for (Standard_Integer aVertIter = 0; aVertIter < 8; ++aVertIter)
1158       {
1159         anObjFile << "v " << (aBoxVerts[aVertIter] + Graphic3d_Vec3 (3.0f * anX, -3.0f * anY, 0.0f)) << "\n";
1160       }
1161       anObjFile << "s off\n";
1162       for (Standard_Integer aFaceIter = 0; aFaceIter < 6; ++aFaceIter)
1163       {
1164         anObjFile << "f " << (aBoxQuads[aFaceIter] + Graphic3d_Vec4i (8 * aMatIndex)) << "\n";
1165       }
1166       anObjFile << "\n";
1167       if (++anX > 5)
1168       {
1169         anX = 0;
1170         ++anY;
1171       }
1172     }
1173   }
1174
1175   if (anHtmlFile.is_open())
1176   {
1177     anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
1178   }
1179   return 0;
1180 }
1181
1182 //==============================================================================
1183 //function : VListColors
1184 //purpose  :
1185 //==============================================================================
1186 static Standard_Integer VListColors (Draw_Interpretor& theDI,
1187                                      Standard_Integer  theArgNb,
1188                                      const char**      theArgVec)
1189 {
1190   TCollection_AsciiString aDumpFile;
1191   NCollection_Sequence<Quantity_NameOfColor> aColList;
1192   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
1193   {
1194     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1195     anArg.LowerCase();
1196     Quantity_NameOfColor aName;
1197     if (Quantity_Color::ColorFromName (theArgVec[anArgIter], aName))
1198     {
1199       aColList.Append (aName);
1200     }
1201     else if (anArg == "*")
1202     {
1203       for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1204       {
1205         aColList.Append ((Quantity_NameOfColor )aColIter);
1206       }
1207     }
1208     else if (aDumpFile.IsEmpty()
1209           && (anArg.EndsWith (".htm")
1210            || anArg.EndsWith (".html")))
1211     {
1212       aDumpFile = theArgVec[anArgIter];
1213     }
1214     else
1215     {
1216       std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'\n";
1217       return 1;
1218     }
1219   }
1220   if (aColList.IsEmpty())
1221   {
1222     if (aDumpFile.IsEmpty())
1223     {
1224       for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1225       {
1226         theDI << Quantity_Color::StringName (Quantity_NameOfColor (aColIter)) << " ";
1227       }
1228       return 0;
1229     }
1230
1231     for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1232     {
1233       aColList.Append ((Quantity_NameOfColor )aColIter);
1234     }
1235   }
1236
1237   std::ofstream anHtmlFile;
1238   TCollection_AsciiString aFileNameBase, aFolder;
1239   if (aDumpFile.EndsWith (".htm")
1240    || aDumpFile.EndsWith (".html"))
1241   {
1242     OSD_Path::FolderAndFileFromPath (aDumpFile, aFolder, aFileNameBase);
1243     aFileNameBase = aFileNameBase.SubString (1, aFileNameBase.Length() -  (aDumpFile.EndsWith (".htm") ? 4 : 5));
1244   }
1245   else if (!aDumpFile.IsEmpty())
1246   {
1247     std::cout << "Syntax error: unknown output file format\n";
1248     return 1;
1249   }
1250
1251   Standard_Integer aMaxNameLen = 1;
1252   for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next())
1253   {
1254     aMaxNameLen = Max (aMaxNameLen, TCollection_AsciiString (Quantity_Color::StringName (aColIter.Value())).Length());
1255   }
1256
1257   V3d_ImageDumpOptions anImgParams;
1258   anImgParams.Width  = 60;
1259   anImgParams.Height = 30;
1260   anImgParams.BufferType = Graphic3d_BT_RGB;
1261   anImgParams.StereoOptions  = V3d_SDO_MONO;
1262   anImgParams.ToAdjustAspect = Standard_True;
1263   Handle(V3d_View) aView;
1264   if (!aDumpFile.IsEmpty())
1265   {
1266     ViewerTest::ViewerInit (0, 0, anImgParams.Width, anImgParams.Height, "TmpDriver/TmpViewer/TmpView");
1267     aView = ViewerTest::CurrentView();
1268     aView->SetImmediateUpdate (false);
1269     aView->SetBgGradientStyle (Aspect_GFM_NONE, false);
1270   }
1271
1272   if (!aDumpFile.IsEmpty())
1273   {
1274     OSD_OpenStream (anHtmlFile, aDumpFile.ToCString(), std::ios::out | std::ios::binary);
1275     if (!anHtmlFile.is_open())
1276     {
1277       std::cout << "Error: unable creating HTML file\n";
1278       return 0;
1279     }
1280     anHtmlFile << "<html>\n"
1281                << "<head><title>OCCT Color table</title></head>\n"
1282                << "<body>\n"
1283                << "<table border='1'><tbody>\n"
1284                << "<tr>\n"
1285                << "<th>HTML</th>\n"
1286                << "<th>OCCT</th>\n"
1287                << "<th>Color name</th>\n"
1288                << "<th>sRGB hex</th>\n"
1289                << "<th>sRGB dec</th>\n"
1290                << "<th>RGB linear</th>\n"
1291                << "</tr>\n";
1292   }
1293
1294   Image_AlienPixMap anImg;
1295   Standard_Integer aColIndex = 0;
1296   for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next(), ++aColIndex)
1297   {
1298     Quantity_Color aCol (aColIter.Value());
1299     const TCollection_AsciiString aColName  = Quantity_Color::StringName (aColIter.Value());
1300     const TCollection_AsciiString anSRgbHex = Quantity_Color::ColorToHex (aCol);
1301     const Graphic3d_Vec3i anSRgbInt ((Graphic3d_Vec3 )aCol * 255.0f);
1302     if (anHtmlFile.is_open())
1303     {
1304       const TCollection_AsciiString anImgPath = aFileNameBase + "_" + aColName + ".png";
1305       if (!aView.IsNull())
1306       {
1307         aView->SetImmediateUpdate (false);
1308         aView->SetBackgroundColor (aCol);
1309         if (!aView->ToPixMap (anImg, anImgParams)
1310          || !anImg.Save (aFolder + anImgPath))
1311         {
1312           theDI << "Error: image dump failed\n";
1313           return 0;
1314         }
1315       }
1316
1317       anHtmlFile << "<tr>\n";
1318       anHtmlFile << "<td style='background-color:" << anSRgbHex << "'><pre>       </pre></td>\n";
1319       anHtmlFile << "<td><img src='" << (!aView.IsNull() ? anImgPath : "") << "'></img></td>\n";
1320       anHtmlFile << "<td style='text-align:left'>" << aColName << "</td>\n";
1321       anHtmlFile << "<td style='text-align:left'><pre>" << anSRgbHex << "</pre></td>\n";
1322       anHtmlFile << "<td style='text-align:left'>(" << anSRgbInt.r() << " " << anSRgbInt.g() << " " << anSRgbInt.b() << ")</td>\n";
1323       anHtmlFile << "<td style='text-align:left'>(" << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << ")</td>\n";
1324       anHtmlFile << "</tr>\n";
1325     }
1326     else
1327     {
1328       TCollection_AsciiString aColNameLong (aColName);
1329       aColNameLong.RightJustify (aMaxNameLen, ' ');
1330       theDI << aColNameLong << " [" << anSRgbHex << "]: " << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << "\n";
1331     }
1332   }
1333
1334   if (!aView.IsNull())
1335   {
1336     ViewerTest::RemoveView (aView);
1337   }
1338
1339   if (anHtmlFile.is_open())
1340   {
1341     anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
1342   }
1343   return 0;
1344 }
1345
1346 //=======================================================================
1347 //function : OpenGlCommands
1348 //purpose  :
1349 //=======================================================================
1350
1351 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
1352 {
1353   const char* aGroup ="Commands for low-level TKOpenGl features";
1354
1355   theCommands.Add("vuserdraw",
1356     "vuserdraw : name - simulates drawing with help of UserDraw",
1357     __FILE__, VUserDraw, aGroup);
1358   theCommands.Add("vfeedback",
1359     "vfeedback       : perform test GL feedback rendering",
1360     __FILE__, VFeedback, aGroup);
1361   theCommands.Add("vimmediatefront",
1362     "vimmediatefront : render immediate mode to front buffer or to back buffer",
1363     __FILE__, VImmediateFront, aGroup);
1364   theCommands.Add("vglinfo",
1365                 "vglinfo [-short|-basic|-complete]"
1366         "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
1367         "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
1368         "\n\t\t: print OpenGL info",
1369     __FILE__, VGlInfo, aGroup);
1370   theCommands.Add("vshader",
1371                   "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
1372                   "\n\t\t:   [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
1373                   "\n\t\t:   [-header VersionHeader]"
1374                   "\n\t\t:   [-tessControl TessControlShader -tesseval TessEvaluationShader]"
1375                   "\n\t\t:   [-uniform Name FloatValue]"
1376                   "\n\t\t: Assign custom GLSL program to presentation aspects."
1377                   "\nvshader [-list] [-dump] [-reload] ShaderId"
1378                   "\n\t\t:  -list   prints the list of registered GLSL programs"
1379                   "\n\t\t:  -dump   dumps specified GLSL program (for debugging)"
1380                   "\n\t\t:  -reload restores dump of specified GLSL program",
1381     __FILE__, VShaderProg, aGroup);
1382   theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
1383   theCommands.Add("vlistmaterials",
1384                   "vlistmaterials [*] [MaterialName1 [MaterialName2 [...]]] [dump.obj|dump.html]"
1385                   "\n\t\t: Without arguments, command prints the list of standard materials."
1386                   "\n\t\t: Otherwise, properties of specified materials will be printed"
1387                   "\n\t\t: or dumped into specified file."
1388                   "\n\t\t: * can be used to refer to complete list of standard materials.",
1389                   __FILE__, VListMaterials, aGroup);
1390   theCommands.Add("vlistcolors",
1391                   "vlistcolors [*] [ColorName1 [ColorName2 [...]]] [dump.html]"
1392                   "\n\t\t: Without arguments, command prints the list of standard colors."
1393                   "\n\t\t: Otherwise, properties of specified colors will be printed"
1394                   "\n\t\t: or dumped into specified file."
1395                   "\n\t\t: * can be used to refer to complete list of standard colors.",
1396                   __FILE__, VListColors, aGroup);
1397 }