0031189: Draw Harness, ViewerTest - send messages to Message::DefaultMessenger()
[occt.git] / src / ViewerTest / ViewerTest_OpenGlCommands.cxx
CommitLineData
6aca4d39 1// Created on: 2012-04-09
3946774d 2// Created by: Sergey ANIKIN
6aca4d39 3// Copyright (c) 2012-2014 OPEN CASCADE SAS
3946774d 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
3946774d 6//
d5f74e42 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
973c2be1 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.
3946774d 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
3946774d 15
3946774d 16#include <ViewerTest.hxx>
17
5e27df78 18#include <AIS_InteractiveContext.hxx>
3946774d 19#include <AIS_InteractiveObject.hxx>
20#include <Draw.hxx>
21#include <Draw_Interpretor.hxx>
22#include <Graphic3d_Group.hxx>
392ac980 23#include <Graphic3d_ShaderObject.hxx>
24#include <Graphic3d_ShaderProgram.hxx>
59ee34ef 25#include <Image_AlienPixMap.hxx>
bf5f0ca2 26#include <OpenGl_Aspects.hxx>
3946774d 27#include <OpenGl_Context.hxx>
28#include <OpenGl_Element.hxx>
3946774d 29#include <OpenGl_GlCore20.hxx>
5e27df78 30#include <OpenGl_GraphicDriver.hxx>
8613985b 31#include <OpenGl_ShaderManager.hxx>
3946774d 32#include <OpenGl_Workspace.hxx>
392ac980 33#include <OSD_Environment.hxx>
34#include <OSD_File.hxx>
67312b79 35#include <OSD_OpenFile.hxx>
6262338c 36#include <Prs3d_Drawer.hxx>
3946774d 37#include <Prs3d_Presentation.hxx>
38#include <Prs3d_Root.hxx>
2831708b 39#include <Prs3d_LineAspect.hxx>
392ac980 40#include <Prs3d_ShadingAspect.hxx>
3946774d 41#include <Select3D_SensitiveCurve.hxx>
42#include <SelectMgr_EntityOwner.hxx>
43#include <SelectMgr_Selection.hxx>
44#include <TCollection_AsciiString.hxx>
3c4153af 45#include <V3d_View.hxx>
392ac980 46#include <V3d_Viewer.hxx>
392ac980 47#include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
48#include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
92efcf78 49#include <OpenGl_Group.hxx>
59ee34ef 50#include <OSD_OpenFile.hxx>
3946774d 51
52extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
53 const Handle(AIS_InteractiveObject)& theAISObj,
54 Standard_Boolean theReplaceIfExists = Standard_True);
392ac980 55extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
3946774d 56
c04c30b3 57namespace {
58
3946774d 59//=======================================================================
60//function : VUserDraw
61//purpose : Checks availability and operation of UserDraw feature
62//=======================================================================
3946774d 63
64class VUserDrawObj : public AIS_InteractiveObject
65{
66public:
67 // CASCADE RTTI
92efcf78 68 DEFINE_STANDARD_RTTI_INLINE(VUserDrawObj,AIS_InteractiveObject);
3946774d 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
80public:
81 class Element : public OpenGl_Element
82 {
83 private:
84 Handle(VUserDrawObj) myIObj;
85
86 public:
a521d90d 87 Element (const Handle(VUserDrawObj)& theIObj) : myIObj (theIObj) {}
3946774d 88
a521d90d 89 virtual ~Element() {}
3946774d 90
91 virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
92 {
93 if (!myIObj.IsNull())
94 myIObj->Render(theWorkspace);
95 }
96
10b9c7df 97 virtual void Release (OpenGl_Context*)
5e27df78 98 {
99 //
100 }
101
3946774d 102 public:
103 DEFINE_STANDARD_ALLOC
104 };
105
106private:
107 // Virtual methods implementation
108 void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
109 const Handle(Prs3d_Presentation)& thePresentation,
79104795 110 const Standard_Integer theMode) Standard_OVERRIDE;
3946774d 111
112 void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
79104795 113 const Standard_Integer theMode) Standard_OVERRIDE;
3946774d 114
115 // Called by VUserDrawElement
116 void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
3946774d 117
a521d90d 118private:
3946774d 119 GLfloat myCoords[6];
3946774d 120 friend class Element;
121};
ec357c5c 122
a521d90d 123void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
124 const Handle(Prs3d_Presentation)& thePrs,
35e08fe8 125 const Standard_Integer /*theMode*/)
3946774d 126{
a521d90d 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());
2831708b 134 aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
a521d90d 135 VUserDrawObj::Element* anElem = new VUserDrawObj::Element (this);
136 aGroup->AddElement(anElem);
137
138 // invalidate bounding box of the scene
cfece3ef 139 thePrsMgr->StructureManager()->Update();
3946774d 140}
141
142void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
35e08fe8 143 const Standard_Integer /*theMode*/)
3946774d 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
3946774d 156void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
157{
1136702b 158 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
a521d90d 159
3946774d 160 // To test linking against OpenGl_Workspace and all aspect classes
bf5f0ca2 161 const OpenGl_Aspects* aMA = theWorkspace->Aspects();
162 aMA->Aspect()->MarkerType();
163 OpenGl_Vec4 aColor = theWorkspace->InteriorColor();
3946774d 164
c40eb6b9 165 aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID,
166 Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, false,
167 Handle(OpenGl_ShaderProgram)());
1136702b 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
3946774d 180 // Finally draw something to make sure UserDraw really works
1136702b 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());
3946774d 185}
186
c04c30b3 187} // end of anonymous namespace
188
23fe70ec 189static Standard_Integer VUserDraw (Draw_Interpretor& ,
3946774d 190 Standard_Integer argc,
191 const char ** argv)
192{
193 Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
194 if (aContext.IsNull())
195 {
23fe70ec 196 Message::SendFail ("Error: no active viewer");
3946774d 197 return 1;
198 }
199
dc3fe572 200 Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
5e27df78 201 if (aDriver.IsNull())
202 {
23fe70ec 203 Message::SendFail ("Error: Graphic driver not available.");
5e27df78 204 return 1;
205 }
206
3946774d 207 if (argc > 2)
208 {
23fe70ec 209 Message::SendFail ("Syntax error: wrong number of arguments");
3946774d 210 return 1;
211 }
212
213 TCollection_AsciiString aName (argv[1]);
214 VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
215
3946774d 216 Handle(VUserDrawObj) anIObj = new VUserDrawObj();
217 VDisplayAISObject(aName, anIObj);
218
219 return 0;
220}
221
3c4153af 222//==============================================================================
223//function : VFeedback
224//purpose :
225//==============================================================================
226
227static int VFeedback (Draw_Interpretor& theDI,
35e08fe8 228 Standard_Integer /*theArgNb*/,
229 const char** /*theArgVec*/)
3c4153af 230{
1ce0716b 231#if !defined(GL_ES_VERSION_2_0)
3c4153af 232 // get the active view
233 Handle(V3d_View) aView = ViewerTest::CurrentView();
234 if (aView.IsNull())
235 {
23fe70ec 236 Message::SendFail ("Error: no active viewer");
3c4153af 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
23fe70ec 247 Message::SendFail() << "Can not allocate buffer - requested size ("
248 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
249 << " MiB) is out of address space";
3c4153af 250 return 1;
251 }
252
253 GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
254 if (aBuffer == NULL)
255 {
256 // finito la commedia
23fe70ec 257 Message::SendFail() << "Can not allocate buffer with size ("
258 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
259 << " MiB)";
3c4153af 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 }
1ce0716b 373#else
374 (void )theDI;
375 std::cout << "Command is unsupported on current platform.\n";
376 return 1;
377#endif
3c4153af 378}
379
1981cb22 380//==============================================================================
381//function : VImmediateFront
382//purpose :
383//==============================================================================
384
35e08fe8 385static int VImmediateFront (Draw_Interpretor& /*theDI*/,
1981cb22 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 {
23fe70ec 393 Message::SendFail ("Error: no active viewer");
1981cb22 394 return 1;
395 }
396
dc3fe572 397 Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
1981cb22 398 if (aDriver.IsNull())
399 {
23fe70ec 400 Message::SendFail ("Error: graphic driver not available.");
1981cb22 401 return 1;
402 }
403
404 if (theArgNb < 2)
405 {
23fe70ec 406 Message::SendFail ("Syntax error: wrong number of arguments.");
1981cb22 407 return 1;
408 }
409
c357e426 410 ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
411
1981cb22 412 return 0;
413}
414
26d9c835 415//! Search the info from the key.
416inline 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
dac04bfa 429//==============================================================================
430//function : VGlInfo
431//purpose :
432//==============================================================================
433
434static 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 {
23fe70ec 442 Message::SendFail ("No active viewer");
dac04bfa 443 return 1;
444 }
445
26d9c835 446 Standard_Integer anArgIter = 1;
447 Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
448 if (theArgNb == 2)
dac04bfa 449 {
26d9c835 450 TCollection_AsciiString aName (theArgVec[1]);
451 aName.LowerCase();
452 if (aName == "-short")
4e1523ef 453 {
26d9c835 454 ++anArgIter;
455 anInfoLevel = Graphic3d_DiagnosticInfo_Short;
456 }
457 else if (aName == "-basic")
458 {
459 ++anArgIter;
460 anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
4e1523ef 461 }
26d9c835 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
dac04bfa 484 theDI << "OpenGL info:\n"
26d9c835 485 << aText;
dac04bfa 486 return 0;
487 }
488
489 const Standard_Boolean isList = theArgNb >= 3;
26d9c835 490 aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
491 for (; anArgIter < theArgNb; ++anArgIter)
dac04bfa 492 {
26d9c835 493 TCollection_AsciiString aName (theArgVec[anArgIter]);
dac04bfa 494 aName.UpperCase();
26d9c835 495 TCollection_AsciiString aValue;
dac04bfa 496 if (aName.Search ("VENDOR") != -1)
497 {
26d9c835 498 aValue = searchInfo (aDict, "GLvendor");
dac04bfa 499 }
500 else if (aName.Search ("RENDERER") != -1)
501 {
26d9c835 502 aValue = searchInfo (aDict, "GLdevice");
dac04bfa 503 }
504 else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
505 || aName.Search ("GLSL") != -1)
506 {
26d9c835 507 aValue = searchInfo (aDict, "GLSLversion");
dac04bfa 508 }
509 else if (aName.Search ("VERSION") != -1)
510 {
26d9c835 511 aValue = searchInfo (aDict, "GLversion");
dac04bfa 512 }
513 else if (aName.Search ("EXTENSIONS") != -1)
514 {
26d9c835 515 aValue = searchInfo (aDict, "GLextensions");
dac04bfa 516 }
517 else
518 {
23fe70ec 519 Message::SendFail() << "Syntax error: unknown key '" << aName.ToCString() << "'";
dac04bfa 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
8e0a2b19 536//! Parse shader type argument.
537static 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}
392ac980 580
581//==============================================================================
582//function : VShaderProg
583//purpose : Sets the pair of vertex and fragment shaders for the object
584//==============================================================================
d95f5ce1 585static Standard_Integer VShaderProg (Draw_Interpretor& theDI,
392ac980 586 Standard_Integer theArgNb,
587 const char** theArgVec)
588{
589 Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
590 if (aCtx.IsNull())
591 {
23fe70ec 592 Message::SendFail ("Error: no active viewer");
392ac980 593 return 1;
594 }
595 else if (theArgNb < 2)
596 {
23fe70ec 597 Message::SendFail ("Syntax error: lack of arguments");
392ac980 598 return 1;
599 }
600
8e0a2b19 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)
392ac980 607 {
8e0a2b19 608 TCollection_AsciiString anArg (theArgVec[anArgIter]);
609 anArg.LowerCase();
610 Graphic3d_TypeOfShaderObject aShaderTypeArg = Graphic3d_TypeOfShaderObject(-1);
0dab5817 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))
d95f5ce1 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 {
23fe70ec 633 Message::SendFail ("Error: no OpenGl_Context");
d95f5ce1 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 {
23fe70ec 653 Message::SendFail() << "Syntax error: shader resource '" << aShaderName << "' is not found";
d95f5ce1 654 return 1;
655 }
656 if (aResProg->UpdateDebugDump (aGlCtx, "", false, anArg == "-dump"))
657 {
658 aCtx->UpdateCurrentViewer();
659 }
660 }
661 if (anArgIter + 1 < theArgNb)
662 {
23fe70ec 663 Message::SendFail ("Syntax error: wrong number of arguments");
d95f5ce1 664 return 1;
665 }
666 return 0;
667 }
668 else if (!aProgram.IsNull()
669 && aProgram->ShaderObjects().IsEmpty()
670 && (anArg == "-off"
671 || anArg == "off"))
8e0a2b19 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 {
23fe70ec 683 Message::SendFail("Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
684 "At least one should be defined to load Phong program.");
8e0a2b19 685 return 1;
686 }
ee5befae 687
8e0a2b19 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 {
23fe70ec 693 Message::SendFail ("Error: PhongShading.vs is not found");
8e0a2b19 694 return 1;
695 }
696 if (!aSrcFrag.IsEmpty()
697 && !OSD_File (aSrcFrag).Exists())
698 {
23fe70ec 699 Message::SendFail ("Error: PhongShading.fs is not found");
8e0a2b19 700 return 1;
701 }
ee5befae 702
8e0a2b19 703 aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX, aSrcVert));
704 aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
ee5befae 705 }
8e0a2b19 706 else if (aPrsList.IsEmpty()
707 && anArg == "*")
ee5befae 708 {
8e0a2b19 709 //
392ac980 710 }
8e0a2b19 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 {
23fe70ec 747 Message::SendFail() << "Syntax error at '" << aPrimTypeStr << "'";
8e0a2b19 748 return 1;
749 }
392ac980 750 }
8e0a2b19 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"))
392ac980 758 {
8e0a2b19 759 TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
760 if (aHeader.IsIntegerValue())
761 {
762 aHeader = TCollection_AsciiString ("#version ") + aHeader;
763 }
764 aProgram->SetHeader (aHeader);
cc8cbabe 765 }
8e0a2b19 766 else if (!anArg.StartsWith ("-")
767 && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
cc8cbabe 768 {
8f521168 769 Handle(AIS_InteractiveObject) anIO = GetMapOfAIS().Find2 (theArgVec[anArgIter]);
8e0a2b19 770 if (anIO.IsNull())
771 {
23fe70ec 772 Message::SendFail() << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object";
8e0a2b19 773 return 1;
774 }
775 aPrsList.Append (anIO);
392ac980 776 }
8e0a2b19 777 else if (!aProgram.IsNull()
778 && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
779 || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
392ac980 780 {
8e0a2b19 781 TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
782 if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
392ac980 783 {
8e0a2b19 784 aShaderPath = (theArgVec[++anArgIter]);
785 isExplicitShaderType = true;
fb66bb28 786 }
787
8e0a2b19 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;
b17e5bae 795 const bool hasFragColor = aShaderSrc.Search ("occSetFragColor") != -1
796 || aShaderSrc.Search ("occFragColor") != -1
8e0a2b19 797 || aShaderSrc.Search ("gl_FragColor") != -1
798 || aShaderSrc.Search ("gl_FragData") != -1;
799 Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
800 if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
fb66bb28 801 {
8e0a2b19 802 if (hasVertPos
803 && !hasFragColor)
804 {
805 aShaderType = Graphic3d_TOS_VERTEX;
806 }
807 if (hasFragColor
808 && !hasVertPos)
809 {
810 aShaderType = Graphic3d_TOS_FRAGMENT;
811 }
392ac980 812 }
8e0a2b19 813 if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
fb66bb28 814 {
23fe70ec 815 Message::SendFail() << "Error: non-existing or invalid shader source";
8e0a2b19 816 return 1;
fb66bb28 817 }
8e0a2b19 818
819 aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
820 }
821 else
822 {
23fe70ec 823 Message::SendFail() << "Syntax error at '" << anArg << "'";
8e0a2b19 824 return 1;
392ac980 825 }
392ac980 826 }
827
b17e5bae 828 if (!aProgram.IsNull()
829 && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
830 {
831 aProgram->SetNbFragmentOutputs (2);
832 aProgram->SetWeightOitOutput (true);
833 }
834
8e0a2b19 835 ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
836 NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
837 const bool isGlobalList = aPrsList.IsEmpty();
838 for (;;)
392ac980 839 {
8e0a2b19 840 Handle(AIS_InteractiveObject) anIO;
841 if (isGlobalList)
392ac980 842 {
8e0a2b19 843 if (!aGlobalPrsIter.More())
844 {
845 break;
846 }
8f521168 847 anIO = aGlobalPrsIter.Key1();
8e0a2b19 848 aGlobalPrsIter.Next();
849 if (anIO.IsNull())
850 {
851 continue;
852 }
392ac980 853 }
8e0a2b19 854 else
392ac980 855 {
8e0a2b19 856 if (!aPrsIter.More())
857 {
858 break;
859 }
860 anIO = aPrsIter.Value();
861 aPrsIter.Next();
392ac980 862 }
fb66bb28 863
8e0a2b19 864 if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
fb66bb28 865 {
fb66bb28 866 aCtx->Redisplay (anIO, Standard_False);
867 }
868 else
869 {
fb66bb28 870 anIO->SynchronizeAspects();
871 }
392ac980 872 }
873
874 aCtx->UpdateCurrentViewer();
875 return 0;
876}
877
59ee34ef 878//! Print triplet of values.
879template<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.
886template<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.
893static 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.
906static 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//==============================================================================
916static 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 {
23fe70ec 948 Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
59ee34ef 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 {
23fe70ec 1002 Message::SendFail ("Error: unable creating material file");
59ee34ef 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 {
23fe70ec 1010 Message::SendFail ("Error: unable creating OBJ file");
59ee34ef 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 {
23fe70ec 1025 Message::SendFail ("Error: unable creating HTML file");
59ee34ef 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"
59ee34ef 1040 "<th rowspan='2'>Transparency</th>\n"
67312b79 1041 "<th colspan='5'><div title='PBR Metallic-Roughness'>"
1042 "PBR Metallic-Roughness</div></th>\n"
1043 "<th colspan='5'><div title='Common material definition for Phong shading model'>"
1044 "Common (Blinn-Phong)</div></th>\n"
1045 "<th colspan='10'><div title='BSDF (Bidirectional Scattering Distribution Function).\n"
59ee34ef 1046 "Used for physically-based rendering (in path tracing engine).\n"
1047 "BSDF is represented as weighted mixture of basic BRDFs/BTDFs (Bidirectional Reflectance (Transmittance) Distribution Functions).\n"
1048 "See also Graphic3d_BSDF structure.'>"
67312b79 1049 "BSDF (Bidirectional Scattering Distribution Function)</div></th>\n"
59ee34ef 1050 "</tr>\n"
1051 "<tr>\n"
67312b79 1052 "<th>Color</th>\n"
1053 "<th>Metallic</th>\n"
1054 "<th>Roughness</th>\n"
1055 "<th>Emission</th>\n"
1056 "<th><div title='Index of refraction'>"
1057 "IOR</div></th>\n"
59ee34ef 1058 "<th>Ambient</th>\n"
1059 "<th>Diffuse</th>\n"
1060 "<th>Specular</th>\n"
1061 "<th>Emissive</th>\n"
1062 "<th>Shiness</th>\n"
1063 "<th><div title='Weight of coat specular/glossy BRDF'>"
1064 "Kc</div></th>\n"
1065 "<th><div title='Weight of base diffuse BRDF'>"
1066 "Kd</div></th>\n"
1067 "<th><div title='Weight of base specular/glossy BRDF'>"
1068 "Ks</div></th>\n"
1069 "<th><div title='Weight of base specular/glossy BTDF'>"
1070 "Kt</div></th>\n"
1071 "<th><div title='Radiance emitted by the surface'>"
1072 "Le</div></th>\n"
1073 "<th><div title='Volume scattering color/density'>"
1074 "Absorption</div></th>\n"
1075 "<th><div title='Parameters of Fresnel reflectance of coat layer'>"
1076 "FresnelCoat</div></th>\n"
1077 "<th><div title='Parameters of Fresnel reflectance of base layer'>"
1078 "FresnelBase</div></th>\n"
67312b79 1079 "<th>Refraction Index</th>\n"
59ee34ef 1080 "</tr>\n";
1081 }
1082 else if (!aDumpFile.IsEmpty())
1083 {
23fe70ec 1084 Message::SendFail ("Syntax error: unknown output file format");
59ee34ef 1085 return 1;
1086 }
1087
1088 Standard_Integer aMatIndex = 0, anX = 0, anY = 0;
1089 for (NCollection_Sequence<Graphic3d_NameOfMaterial>::Iterator aMatIter (aMatList); aMatIter.More(); aMatIter.Next(), ++aMatIndex)
1090 {
1091 Graphic3d_MaterialAspect aMat (aMatIter.Value());
1092 const TCollection_AsciiString aMatName = aMat.StringName();
61168418 1093 const Graphic3d_Vec3 anAmbient = (Graphic3d_Vec3 )aMat.AmbientColor();
1094 const Graphic3d_Vec3 aDiffuse = (Graphic3d_Vec3 )aMat.DiffuseColor();
1095 const Graphic3d_Vec3 aSpecular = (Graphic3d_Vec3 )aMat.SpecularColor();
1096 const Graphic3d_Vec3 anEmission = (Graphic3d_Vec3 )aMat.EmissiveColor();
59ee34ef 1097 const Standard_Real aShiness = aMat.Shininess() * 1000.0;
1098 if (aMatFile.is_open())
1099 {
1100 aMatFile << "newmtl " << aMatName << "\n";
ba00aab7 1101 aMatFile << "Ka " << Quantity_Color::Convert_LinearRGB_To_sRGB (anAmbient) << "\n";
1102 aMatFile << "Kd " << Quantity_Color::Convert_LinearRGB_To_sRGB (aDiffuse) << "\n";
1103 aMatFile << "Ks " << Quantity_Color::Convert_LinearRGB_To_sRGB (aSpecular) << "\n";
59ee34ef 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";
67312b79 1116 anHtmlFile << "<td>" << aMat.Transparency() << "</td>\n";
1117 anHtmlFile << "<td>" << formatSvgColoredRect (aMat.PBRMaterial().Color().GetRGB()) << (Graphic3d_Vec3 )aMat.PBRMaterial().Color().GetRGB() << "</td>\n";
1118 anHtmlFile << "<td>" << aMat.PBRMaterial().Metallic() << "</td>\n";
1119 anHtmlFile << "<td>" << aMat.PBRMaterial().NormalizedRoughness() << "</td>\n";
1120 anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aMat.PBRMaterial().Emission())) << aMat.PBRMaterial().Emission() << "</td>\n";
1121 anHtmlFile << "<td>" << aMat.PBRMaterial().IOR() << "</td>\n";
59ee34ef 1122 anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anAmbient)) << anAmbient << "</td>\n";
1123 anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aDiffuse)) << aDiffuse << "</td>\n";
1124 anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aSpecular)) << aSpecular << "</td>\n";
1125 anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anEmission)) << anEmission << "</td>\n";
1126 anHtmlFile << "<td>" << aMat.Shininess() << "</td>\n";
59ee34ef 1127 anHtmlFile << "<td>" << aMat.BSDF().Kc << "</td>\n";
1128 anHtmlFile << "<td>" << aMat.BSDF().Kd << "</td>\n";
1129 anHtmlFile << "<td>" << aMat.BSDF().Ks << "</td>\n";
1130 anHtmlFile << "<td>" << aMat.BSDF().Kt << "</td>\n";
1131 anHtmlFile << "<td>" << aMat.BSDF().Le << "</td>\n";
1132 anHtmlFile << "<td>" << aMat.BSDF().Absorption << "</td>\n";
1133 anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "</td>\n";
1134 anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "</td>\n";
67312b79 1135 anHtmlFile << "<td>" << aMat.RefractionIndex() << "</td>\n";
59ee34ef 1136 anHtmlFile << "</tr>\n";
1137 }
1138 else
1139 {
1140 theDI << aMat.StringName() << "\n";
67312b79 1141 theDI << " Transparency: " << aMat.Transparency() << "\n";
1142 theDI << " PBR.BaseColor: " << (Graphic3d_Vec3 )aMat.PBRMaterial().Color().GetRGB() << "\n";
1143 theDI << " PBR.Metallic: " << aMat.PBRMaterial().Metallic() << "\n";
1144 theDI << " PBR.Roughness: " << aMat.PBRMaterial().NormalizedRoughness() << "\n";
1145 theDI << " PBR.Emission: " << aMat.PBRMaterial().Emission() << "\n";
1146 theDI << " PBR.IOR: " << aMat.PBRMaterial().IOR() << "\n";
59ee34ef 1147 theDI << " Common.Ambient: " << anAmbient << "\n";
1148 theDI << " Common.Diffuse: " << aDiffuse << "\n";
1149 theDI << " Common.Specular: " << aSpecular << "\n";
1150 theDI << " Common.Emissive: " << anEmission << "\n";
1151 theDI << " Common.Shiness: " << aMat.Shininess() << "\n";
59ee34ef 1152 theDI << " BSDF.Kc: " << aMat.BSDF().Kc << "\n";
1153 theDI << " BSDF.Kd: " << aMat.BSDF().Kd << "\n";
1154 theDI << " BSDF.Ks: " << aMat.BSDF().Ks << "\n";
1155 theDI << " BSDF.Kt: " << aMat.BSDF().Kt << "\n";
1156 theDI << " BSDF.Le: " << aMat.BSDF().Le << "\n";
1157 theDI << " BSDF.Absorption: " << aMat.BSDF().Absorption << "\n";
1158 theDI << " BSDF.FresnelCoat: " << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "\n";
1159 theDI << " BSDF.FresnelBase: " << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "\n";
67312b79 1160 theDI << " RefractionIndex: " << aMat.RefractionIndex() << "\n";
59ee34ef 1161 }
1162
1163 if (anObjFile.is_open())
1164 {
1165 anObjFile << "g " << aMatName << "\n";
1166 anObjFile << "usemtl " << aMatName << "\n";
1167 for (Standard_Integer aVertIter = 0; aVertIter < 8; ++aVertIter)
1168 {
1169 anObjFile << "v " << (aBoxVerts[aVertIter] + Graphic3d_Vec3 (3.0f * anX, -3.0f * anY, 0.0f)) << "\n";
1170 }
1171 anObjFile << "s off\n";
1172 for (Standard_Integer aFaceIter = 0; aFaceIter < 6; ++aFaceIter)
1173 {
1174 anObjFile << "f " << (aBoxQuads[aFaceIter] + Graphic3d_Vec4i (8 * aMatIndex)) << "\n";
1175 }
1176 anObjFile << "\n";
1177 if (++anX > 5)
1178 {
1179 anX = 0;
1180 ++anY;
1181 }
1182 }
1183 }
1184
1185 if (anHtmlFile.is_open())
1186 {
1187 anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
1188 }
1189 return 0;
1190}
1191
1192//==============================================================================
1193//function : VListColors
1194//purpose :
1195//==============================================================================
1196static Standard_Integer VListColors (Draw_Interpretor& theDI,
1197 Standard_Integer theArgNb,
1198 const char** theArgVec)
1199{
1200 TCollection_AsciiString aDumpFile;
1201 NCollection_Sequence<Quantity_NameOfColor> aColList;
1202 for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
1203 {
1204 TCollection_AsciiString anArg (theArgVec[anArgIter]);
1205 anArg.LowerCase();
1206 Quantity_NameOfColor aName;
1207 if (Quantity_Color::ColorFromName (theArgVec[anArgIter], aName))
1208 {
1209 aColList.Append (aName);
1210 }
1211 else if (anArg == "*")
1212 {
1213 for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1214 {
1215 aColList.Append ((Quantity_NameOfColor )aColIter);
1216 }
1217 }
1218 else if (aDumpFile.IsEmpty()
1219 && (anArg.EndsWith (".htm")
1220 || anArg.EndsWith (".html")))
1221 {
1222 aDumpFile = theArgVec[anArgIter];
1223 }
1224 else
1225 {
23fe70ec 1226 Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
59ee34ef 1227 return 1;
1228 }
1229 }
1230 if (aColList.IsEmpty())
1231 {
1232 if (aDumpFile.IsEmpty())
1233 {
1234 for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1235 {
1236 theDI << Quantity_Color::StringName (Quantity_NameOfColor (aColIter)) << " ";
1237 }
1238 return 0;
1239 }
1240
1241 for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
1242 {
1243 aColList.Append ((Quantity_NameOfColor )aColIter);
1244 }
1245 }
1246
1247 std::ofstream anHtmlFile;
1248 TCollection_AsciiString aFileNameBase, aFolder;
1249 if (aDumpFile.EndsWith (".htm")
1250 || aDumpFile.EndsWith (".html"))
1251 {
1252 OSD_Path::FolderAndFileFromPath (aDumpFile, aFolder, aFileNameBase);
1253 aFileNameBase = aFileNameBase.SubString (1, aFileNameBase.Length() - (aDumpFile.EndsWith (".htm") ? 4 : 5));
1254 }
1255 else if (!aDumpFile.IsEmpty())
1256 {
23fe70ec 1257 Message::SendFail ("Syntax error: unknown output file format");
59ee34ef 1258 return 1;
1259 }
1260
1261 Standard_Integer aMaxNameLen = 1;
1262 for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next())
1263 {
1264 aMaxNameLen = Max (aMaxNameLen, TCollection_AsciiString (Quantity_Color::StringName (aColIter.Value())).Length());
1265 }
1266
1267 V3d_ImageDumpOptions anImgParams;
1268 anImgParams.Width = 60;
1269 anImgParams.Height = 30;
1270 anImgParams.BufferType = Graphic3d_BT_RGB;
1271 anImgParams.StereoOptions = V3d_SDO_MONO;
1272 anImgParams.ToAdjustAspect = Standard_True;
1273 Handle(V3d_View) aView;
1274 if (!aDumpFile.IsEmpty())
1275 {
1276 ViewerTest::ViewerInit (0, 0, anImgParams.Width, anImgParams.Height, "TmpDriver/TmpViewer/TmpView");
1277 aView = ViewerTest::CurrentView();
1278 aView->SetImmediateUpdate (false);
1279 aView->SetBgGradientStyle (Aspect_GFM_NONE, false);
1280 }
1281
1282 if (!aDumpFile.IsEmpty())
1283 {
1284 OSD_OpenStream (anHtmlFile, aDumpFile.ToCString(), std::ios::out | std::ios::binary);
1285 if (!anHtmlFile.is_open())
1286 {
23fe70ec 1287 Message::SendFail ("Error: unable creating HTML file");
59ee34ef 1288 return 0;
1289 }
1290 anHtmlFile << "<html>\n"
1291 << "<head><title>OCCT Color table</title></head>\n"
1292 << "<body>\n"
1293 << "<table border='1'><tbody>\n"
1294 << "<tr>\n"
1295 << "<th>HTML</th>\n"
1296 << "<th>OCCT</th>\n"
1297 << "<th>Color name</th>\n"
1298 << "<th>sRGB hex</th>\n"
1299 << "<th>sRGB dec</th>\n"
1300 << "<th>RGB linear</th>\n"
1301 << "</tr>\n";
1302 }
1303
1304 Image_AlienPixMap anImg;
1305 Standard_Integer aColIndex = 0;
1306 for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next(), ++aColIndex)
1307 {
1308 Quantity_Color aCol (aColIter.Value());
1309 const TCollection_AsciiString aColName = Quantity_Color::StringName (aColIter.Value());
1310 const TCollection_AsciiString anSRgbHex = Quantity_Color::ColorToHex (aCol);
1311 const Graphic3d_Vec3i anSRgbInt ((Graphic3d_Vec3 )aCol * 255.0f);
1312 if (anHtmlFile.is_open())
1313 {
1314 const TCollection_AsciiString anImgPath = aFileNameBase + "_" + aColName + ".png";
1315 if (!aView.IsNull())
1316 {
1317 aView->SetImmediateUpdate (false);
1318 aView->SetBackgroundColor (aCol);
1319 if (!aView->ToPixMap (anImg, anImgParams)
1320 || !anImg.Save (aFolder + anImgPath))
1321 {
1322 theDI << "Error: image dump failed\n";
1323 return 0;
1324 }
1325 }
1326
1327 anHtmlFile << "<tr>\n";
1328 anHtmlFile << "<td style='background-color:" << anSRgbHex << "'><pre> </pre></td>\n";
1329 anHtmlFile << "<td><img src='" << (!aView.IsNull() ? anImgPath : "") << "'></img></td>\n";
1330 anHtmlFile << "<td style='text-align:left'>" << aColName << "</td>\n";
1331 anHtmlFile << "<td style='text-align:left'><pre>" << anSRgbHex << "</pre></td>\n";
1332 anHtmlFile << "<td style='text-align:left'>(" << anSRgbInt.r() << " " << anSRgbInt.g() << " " << anSRgbInt.b() << ")</td>\n";
1333 anHtmlFile << "<td style='text-align:left'>(" << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << ")</td>\n";
1334 anHtmlFile << "</tr>\n";
1335 }
1336 else
1337 {
1338 TCollection_AsciiString aColNameLong (aColName);
1339 aColNameLong.RightJustify (aMaxNameLen, ' ');
1340 theDI << aColNameLong << " [" << anSRgbHex << "]: " << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << "\n";
1341 }
1342 }
1343
1344 if (!aView.IsNull())
1345 {
1346 ViewerTest::RemoveView (aView);
1347 }
1348
1349 if (anHtmlFile.is_open())
1350 {
1351 anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
1352 }
1353 return 0;
1354}
1355
67312b79 1356//==============================================================================
1357//function : envlutWriteToFile
1358//purpose :
1359//==============================================================================
1360static std::string envLutWriteToFile (Standard_ShortReal theValue)
1361{
1362 std::stringstream aStream;
1363 aStream << theValue;
1364 if (aStream.str().length() == 1)
1365 {
1366 aStream << '.';
1367 }
1368 aStream << 'f';
1369 return aStream.str();
1370}
1371
1372//==============================================================================
1373//function : VGenEnvLUT
1374//purpose :
1375//==============================================================================
1376static Standard_Integer VGenEnvLUT (Draw_Interpretor&,
1377 Standard_Integer theArgNb,
1378 const char** theArgVec)
1379{
1380 Standard_Integer aTableSize = -1;
1381 Standard_Integer aNbSamples = -1;
1382 TCollection_AsciiString aFilePath = Graphic3d_TextureRoot::TexturesFolder() + "/Textures_EnvLUT.pxx";
1383
1384 for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
1385 {
1386 TCollection_AsciiString anArg(theArgVec[anArgIter]);
1387 anArg.LowerCase();
1388
1389 if (anArg == "-size"
1390 || anArg == "-s")
1391 {
1392 if (anArgIter + 1 >= theArgNb)
1393 {
23fe70ec 1394 Message::SendFail ("Syntax error: size of PBR environment look up table is undefined");
67312b79 1395 return 1;
1396 }
1397
1398 aTableSize = Draw::Atoi(theArgVec[++anArgIter]);
1399
1400 if (aTableSize < 16)
1401 {
23fe70ec 1402 Message::SendFail ("Error: size of PBR environment look up table must be greater or equal 16");
67312b79 1403 return 1;
1404 }
1405 }
1406 else if (anArg == "-nbsamples"
1407 || anArg == "-samples")
1408 {
1409 if (anArgIter + 1 >= theArgNb)
1410 {
23fe70ec 1411 Message::SendFail ("Syntax error: number of samples to generate PBR environment look up table is undefined");
67312b79 1412 return 1;
1413 }
1414
1415 aNbSamples = Draw::Atoi(theArgVec[++anArgIter]);
1416
1417 if (aNbSamples < 1)
1418 {
23fe70ec 1419 Message::SendFail ("Syntax error: number of samples to generate PBR environment look up table must be greater than 1");
67312b79 1420 return 1;
1421 }
1422 }
1423 else
1424 {
23fe70ec 1425 Message::SendFail() << "Syntax error: unknown argument " << anArg;
67312b79 1426 return 1;
1427 }
1428 }
1429
1430 if (aTableSize < 0)
1431 {
1432 aTableSize = 128;
1433 }
1434
1435 if (aNbSamples < 0)
1436 {
1437 aNbSamples = 1024;
1438 }
1439
1440 std::ofstream aFile;
1441
1442 OSD_OpenStream (aFile, aFilePath, std::ios::out | std::ios::binary);
1443
1444 if (!aFile.good())
1445 {
23fe70ec 1446 Message::SendFail() << "Error: unable to write to " << aFilePath;
67312b79 1447 return 1;
1448 }
1449
1450 aFile << "//this file has been generated by vgenenvlut draw command\n";
1451 aFile << "static unsigned int Textures_EnvLUTSize = " << aTableSize << ";\n\n";
1452 aFile << "static float Textures_EnvLUT[] =\n";
1453 aFile << "{\n";
1454
1455 Handle(Image_PixMap) aPixMap = new Image_PixMap();
1456 aPixMap->InitZero (Image_Format_RGF, aTableSize, aTableSize);
1457 Graphic3d_PBRMaterial::GenerateEnvLUT (aPixMap, aNbSamples);
1458
1459 const Standard_Integer aNumbersInRow = 5;
1460 Standard_Integer aCounter = 0;
1461
1462 for (int y = 0; y < aTableSize - 1; ++y)
1463 {
1464 aCounter = 0;
1465 for (int x = 0; x < aTableSize; ++x)
1466 {
1467 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(aTableSize - 1 - y, x).x()) << ",";
1468 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(aTableSize - 1 - y, x).y()) << ",";
1469 if (++aCounter % aNumbersInRow == 0)
1470 {
1471 aFile << "\n";
1472 }
1473 else if (x != aTableSize - 1)
1474 {
1475 aFile << " ";
1476 }
1477 }
1478 aFile << "\n";
1479 if (aTableSize % aNumbersInRow != 0)
1480 {
1481 aFile << "\n";
1482 }
1483 }
1484
1485 aCounter = 0;
1486 for (int x = 0; x < aTableSize - 1; ++x)
1487 {
1488 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(0, x).x()) << ",";
1489 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(0, x).y()) << ",";
1490 if (++aCounter % aNumbersInRow == 0)
1491 {
1492 aFile << "\n";
1493 }
1494 else
1495 {
1496 aFile << " ";
1497 }
1498 }
1499
1500 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(0, aTableSize - 1).x()) << ",";
1501 aFile << envLutWriteToFile (aPixMap->Value<Graphic3d_Vec3>(0, aTableSize - 1).y()) << "\n";
1502
1503 aFile << "};";
1504 aFile.close();
1505
1506 return 0;
1507}
1508
3946774d 1509//=======================================================================
1510//function : OpenGlCommands
1511//purpose :
1512//=======================================================================
1513
1514void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
1515{
1516 const char* aGroup ="Commands for low-level TKOpenGl features";
1517
1518 theCommands.Add("vuserdraw",
1519 "vuserdraw : name - simulates drawing with help of UserDraw",
1520 __FILE__, VUserDraw, aGroup);
3c4153af 1521 theCommands.Add("vfeedback",
1522 "vfeedback : perform test GL feedback rendering",
1523 __FILE__, VFeedback, aGroup);
1981cb22 1524 theCommands.Add("vimmediatefront",
1525 "vimmediatefront : render immediate mode to front buffer or to back buffer",
1526 __FILE__, VImmediateFront, aGroup);
dac04bfa 1527 theCommands.Add("vglinfo",
26d9c835 1528 "vglinfo [-short|-basic|-complete]"
1529 "\n\t\t: [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
1530 "\n\t\t: [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
1531 "\n\t\t: print OpenGL info",
dac04bfa 1532 __FILE__, VGlInfo, aGroup);
8e0a2b19 1533 theCommands.Add("vshader",
1534 "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
1535 "\n\t\t: [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
1536 "\n\t\t: [-header VersionHeader]"
1537 "\n\t\t: [-tessControl TessControlShader -tesseval TessEvaluationShader]"
0dab5817 1538 "\n\t\t: [-uniform Name FloatValue]"
d95f5ce1 1539 "\n\t\t: Assign custom GLSL program to presentation aspects."
1540 "\nvshader [-list] [-dump] [-reload] ShaderId"
1541 "\n\t\t: -list prints the list of registered GLSL programs"
1542 "\n\t\t: -dump dumps specified GLSL program (for debugging)"
1543 "\n\t\t: -reload restores dump of specified GLSL program",
392ac980 1544 __FILE__, VShaderProg, aGroup);
8e0a2b19 1545 theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
59ee34ef 1546 theCommands.Add("vlistmaterials",
1547 "vlistmaterials [*] [MaterialName1 [MaterialName2 [...]]] [dump.obj|dump.html]"
1548 "\n\t\t: Without arguments, command prints the list of standard materials."
1549 "\n\t\t: Otherwise, properties of specified materials will be printed"
1550 "\n\t\t: or dumped into specified file."
1551 "\n\t\t: * can be used to refer to complete list of standard materials.",
1552 __FILE__, VListMaterials, aGroup);
1553 theCommands.Add("vlistcolors",
1554 "vlistcolors [*] [ColorName1 [ColorName2 [...]]] [dump.html]"
1555 "\n\t\t: Without arguments, command prints the list of standard colors."
1556 "\n\t\t: Otherwise, properties of specified colors will be printed"
1557 "\n\t\t: or dumped into specified file."
1558 "\n\t\t: * can be used to refer to complete list of standard colors.",
1559 __FILE__, VListColors, aGroup);
67312b79 1560 theCommands.Add("vgenenvlut",
1561 "vgenenvlut [-size size = 128] [-nbsamples nbsamples = 1024]"
1562 "\n\t\t: Generates PBR environment look up table."
1563 "\n\t\t: Saves it as C++ source file which is expected to be included in code."
1564 "\n\t\t: The path where result will be located is 'Graphic3d_TextureRoot::TexturesFolder()'."
1565 "\n\t\t: -size size of one side of resulted square table"
1566 "\n\t\t: -nbsamples number of samples used in Monte-Carlo integration",
1567 __FILE__, VGenEnvLUT, aGroup);
3946774d 1568}