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