1 // Created on: 2012-04-09
2 // Created by: Sergey ANIKIN
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
20 #include <ViewerTest.hxx>
22 #include <AIS_Drawer.hxx>
23 #include <AIS_InteractiveContext.hxx>
24 #include <AIS_InteractiveObject.hxx>
26 #include <Draw_Interpretor.hxx>
27 #include <Graphic3d_Group.hxx>
28 #include <Graphic3d_ShaderObject.hxx>
29 #include <Graphic3d_ShaderProgram.hxx>
30 #include <OpenGl_AspectFace.hxx>
31 #include <OpenGl_AspectLine.hxx>
32 #include <OpenGl_AspectMarker.hxx>
33 #include <OpenGl_AspectText.hxx>
34 #include <OpenGl_Context.hxx>
35 #include <OpenGl_Element.hxx>
36 #include <OpenGl_GlCore20.hxx>
37 #include <OpenGl_GraphicDriver.hxx>
38 #include <OpenGl_Workspace.hxx>
39 #include <OSD_Environment.hxx>
40 #include <OSD_File.hxx>
41 #include <Prs3d_Presentation.hxx>
42 #include <Prs3d_Root.hxx>
43 #include <Prs3d_ShadingAspect.hxx>
44 #include <Select3D_SensitiveCurve.hxx>
45 #include <SelectMgr_EntityOwner.hxx>
46 #include <SelectMgr_Selection.hxx>
47 #include <TCollection_AsciiString.hxx>
48 #include <V3d_View.hxx>
49 #include <V3d_Viewer.hxx>
50 #include <Visual3d_View.hxx>
51 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
52 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
54 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
55 const Handle(AIS_InteractiveObject)& theAISObj,
56 Standard_Boolean theReplaceIfExists = Standard_True);
57 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
59 //=======================================================================
60 //function : VUserDraw
61 //purpose : Checks availability and operation of UserDraw feature
62 //=======================================================================
63 DEFINE_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
65 class VUserDrawObj : public AIS_InteractiveObject
69 DEFINE_STANDARD_RTTI(VUserDrawObj);
82 class Element : public OpenGl_Element
85 Handle(VUserDrawObj) myIObj;
88 Element (const Handle(VUserDrawObj)& theIObj,
89 CALL_DEF_BOUNDS* theBounds)
93 myIObj->GetBounds(theBounds);
100 virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
102 if (!myIObj.IsNull())
103 myIObj->Render(theWorkspace);
106 virtual void Release (const Handle(OpenGl_Context)&)
112 DEFINE_STANDARD_ALLOC
116 // Virtual methods implementation
117 void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
118 const Handle(Prs3d_Presentation)& thePresentation,
119 const Standard_Integer theMode);
121 void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
122 const Standard_Integer theMode);
124 // Called by VUserDrawElement
125 void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
126 void GetBounds(CALL_DEF_BOUNDS* theBounds);
130 friend class Element;
132 IMPLEMENT_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
133 IMPLEMENT_STANDARD_RTTIEXT(VUserDrawObj, AIS_InteractiveObject)
135 void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& /*thePresentationManager*/,
136 const Handle(Prs3d_Presentation)& thePresentation,
137 const Standard_Integer /*theMode*/)
139 thePresentation->Clear();
141 Handle(Graphic3d_Group) aGrp = Prs3d_Root::CurrentGroup(thePresentation);
142 aGrp->UserDraw(this, Standard_True, Standard_True);
145 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
146 const Standard_Integer /*theMode*/)
148 Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner(this);
149 Handle(TColgp_HArray1OfPnt) aPnts = new TColgp_HArray1OfPnt(1, 5);
150 aPnts->SetValue(1, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
151 aPnts->SetValue(2, gp_Pnt(myCoords[3], myCoords[4], myCoords[2]));
152 aPnts->SetValue(3, gp_Pnt(myCoords[3], myCoords[4], myCoords[5]));
153 aPnts->SetValue(4, gp_Pnt(myCoords[0], myCoords[1], myCoords[5]));
154 aPnts->SetValue(5, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
155 Handle(Select3D_SensitiveCurve) aSensitive = new Select3D_SensitiveCurve(anEntityOwner, aPnts);
156 theSelection->Add(aSensitive);
159 void VUserDrawObj::GetBounds(CALL_DEF_BOUNDS* theBounds)
163 theBounds->XMin = myCoords[0];
164 theBounds->YMin = myCoords[1];
165 theBounds->ZMin = myCoords[2];
166 theBounds->XMax = myCoords[3];
167 theBounds->YMax = myCoords[4];
168 theBounds->ZMax = myCoords[5];
172 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
174 // To test linking against OpenGl_Workspace and all aspect classes
175 const OpenGl_AspectLine* aLA = theWorkspace->AspectLine(0);
176 const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker(0);
178 const OpenGl_AspectText* aTA = theWorkspace->AspectText(0);
180 TEL_COLOUR aColor = theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT ?
181 *(theWorkspace->HighlightColor) : aLA->Color();
183 // To test OpenGl_Window
184 //Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
186 // Finally draw something to make sure UserDraw really works
187 glPushAttrib(GL_ENABLE_BIT);
188 glDisable(GL_LIGHTING);
189 glColor4fv(aColor.rgb);
190 glBegin(GL_LINE_LOOP);
191 glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
192 glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
193 glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
194 glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
199 OpenGl_Element* VUserDrawCallback(const CALL_DEF_USERDRAW * theUserDraw)
201 Handle(VUserDrawObj) anIObj = (VUserDrawObj*)theUserDraw->Data;
204 std::cout << "VUserDrawCallback error: null object passed, the custom scene element will not be rendered" << std::endl;
207 return new VUserDrawObj::Element(anIObj, theUserDraw->Bounds);
210 static Standard_Integer VUserDraw (Draw_Interpretor& di,
211 Standard_Integer argc,
214 Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
215 if (aContext.IsNull())
217 di << argv[0] << "Call 'vinit' before!\n";
221 Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
222 if (aDriver.IsNull())
224 std::cerr << "Graphic driver not available.\n";
230 di << argv[0] << "Wrong number of arguments, only the object name expected\n";
234 TCollection_AsciiString aName (argv[1]);
235 VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
237 // register the custom element factory function
238 aDriver->UserDrawCallback() = VUserDrawCallback;
240 Handle(VUserDrawObj) anIObj = new VUserDrawObj();
241 VDisplayAISObject(aName, anIObj);
246 //==============================================================================
247 //function : VFeedback
249 //==============================================================================
251 static int VFeedback (Draw_Interpretor& theDI,
252 Standard_Integer /*theArgNb*/,
253 const char** /*theArgVec*/)
255 // get the active view
256 Handle(V3d_View) aView = ViewerTest::CurrentView();
259 std::cerr << "No active view. Please call vinit.\n";
263 unsigned int aBufferSize = 1024 * 1024;
266 size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
267 if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
269 // finito la commedia
270 std::cerr << "Can not allocate buffer - requested size ("
271 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
272 << " MiB) is out of address space\n";
276 GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
279 // finito la commedia
280 std::cerr << "Can not allocate buffer with size ("
281 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
286 glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
287 glRenderMode (GL_FEEDBACK);
291 GLint aResult = glRenderMode (GL_RENDER);
296 void* aPtr = aBuffer;
297 Standard::Free (aPtr);
302 std::cout << "FeedBack result= " << aResult << "\n";
309 GLint aBitmapsNb = 0;
310 GLint aPassThrNb = 0;
311 GLint aUnknownNb = 0;
312 const GLint NODE_VALUES = 2; // GL_2D
313 for (GLint anIter = 0; anIter < aResult;)
315 const GLfloat aPos = aBuffer[anIter];
316 switch ((GLint )aPos)
322 anIter += 1 + NODE_VALUES;
325 case GL_LINE_RESET_TOKEN:
330 anIter += 1 + 2 * NODE_VALUES;
333 case GL_POLYGON_TOKEN:
335 const GLint aCount = (GLint )aBuffer[++anIter];
337 anIter += aCount * NODE_VALUES + 1;
342 else if (aCount == 4)
352 case GL_BITMAP_TOKEN:
353 case GL_DRAW_PIXEL_TOKEN:
354 case GL_COPY_PIXEL_TOKEN:
357 anIter += 1 + NODE_VALUES;
360 case GL_PASS_THROUGH_TOKEN:
363 anIter += 2; // header + value
374 void* aPtr = aBuffer;
375 Standard::Free (aPtr);
378 theDI << "Total nodes: " << aNodesNb << "\n"
379 << "Points: " << aPntNb << "\n"
380 << "Line segments: " << aLinesNb << "\n"
381 << "Triangles: " << aTriNb << "\n"
382 << "Quads: " << aQuadsNb << "\n"
383 << "Polygons: " << aPolyNb << "\n"
384 << "Bitmap tokens: " << aBitmapsNb << "\n"
385 << "Pass through: " << aPassThrNb << "\n"
386 << "UNKNOWN: " << aUnknownNb << "\n";
388 double aLen2D = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
389 double aLen3D = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
390 double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
391 theDI << "Buffer size GL_2D: " << aLen2D * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
392 << "Buffer size GL_3D: " << aLen3D * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
393 << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
398 //==============================================================================
399 //function : VImmediateFront
401 //==============================================================================
403 static int VImmediateFront (Draw_Interpretor& /*theDI*/,
404 Standard_Integer theArgNb,
405 const char** theArgVec)
408 Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
409 if (aContextAIS.IsNull())
411 std::cerr << "No active view. Please call vinit.\n";
415 Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
417 if (aDriver.IsNull())
419 std::cerr << "Graphic driver not available.\n";
425 std::cerr << "Wrong number of arguments.\n";
429 Graphic3d_CView* aCView = (Graphic3d_CView* )(ViewerTest::CurrentView()->View()->CView());
430 aDriver->SetImmediateModeDrawToFront (*aCView, atoi(theArgVec[1]) != 0);
434 //==============================================================================
437 //==============================================================================
439 static int VGlInfo (Draw_Interpretor& theDI,
440 Standard_Integer theArgNb,
441 const char** theArgVec)
443 // get the active view
444 Handle(V3d_View) aView = ViewerTest::CurrentView();
447 std::cerr << "No active view. Please call vinit.\n";
453 Standard_CString aDebugInfo = OpenGl_Context::CheckExtension ((const char* )glGetString (GL_EXTENSIONS),
454 "GL_ARB_debug_output")
455 ? " GLdebug = ON\n" : "";
456 theDI << "OpenGL info:\n"
457 << " GLvendor = '" << (const char* )glGetString(GL_VENDOR) << "'\n"
458 << " GLdevice = '" << (const char* )glGetString(GL_RENDERER) << "'\n"
459 << " GLversion = '" << (const char* )glGetString(GL_VERSION) << "'\n"
460 << " GLSLversion = '" << (const char* )glGetString(GL_SHADING_LANGUAGE_VERSION) << "'\n"
465 const Standard_Boolean isList = theArgNb >= 3;
466 for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
468 TCollection_AsciiString aName (theArgVec[anIter]);
470 const char* aValue = NULL;
471 if (aName.Search ("VENDOR") != -1)
473 aValue = (const char* )glGetString (GL_VENDOR);
475 else if (aName.Search ("RENDERER") != -1)
477 aValue = (const char* )glGetString (GL_RENDERER);
479 else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
480 || aName.Search ("GLSL") != -1)
482 aValue = (const char* )glGetString (GL_SHADING_LANGUAGE_VERSION);
484 else if (aName.Search ("VERSION") != -1)
486 aValue = (const char* )glGetString (GL_VERSION);
488 else if (aName.Search ("EXTENSIONS") != -1)
490 aValue = (const char* )glGetString (GL_EXTENSIONS);
494 std::cerr << "Unknown key '" << aName.ToCString() << "'\n";
500 theDI << "{" << aValue << "} ";
512 //==============================================================================
513 //function : VShaderProg
514 //purpose : Sets the pair of vertex and fragment shaders for the object
515 //==============================================================================
516 static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
517 Standard_Integer theArgNb,
518 const char** theArgVec)
520 Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
523 std::cerr << "Use 'vinit' command before " << theArgVec[0] << "\n";
526 else if (theArgNb < 2)
528 std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
532 TCollection_AsciiString aLastArg (theArgVec[theArgNb - 1]);
533 aLastArg.UpperCase();
534 const Standard_Boolean toTurnOff = aLastArg == "OFF";
535 Standard_Integer anArgsNb = theArgNb - 1;
536 Handle(Graphic3d_ShaderProgram) aProgram;
538 && aLastArg == "PHONG")
540 aProgram = new Graphic3d_ShaderProgram (Graphic3d_ShaderProgram::ShaderName_Phong);
543 && aProgram.IsNull())
547 std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
551 const TCollection_AsciiString aSrcVert = theArgVec[theArgNb - 2];
552 const TCollection_AsciiString aSrcFrag = theArgVec[theArgNb - 1];
553 if (!aSrcVert.IsEmpty()
554 && !OSD_File (aSrcVert).Exists())
556 std::cerr << "Non-existing vertex shader source\n";
559 if (!aSrcFrag.IsEmpty()
560 && !OSD_File (aSrcFrag).Exists())
562 std::cerr << "Non-existing fragment shader source\n";
566 aProgram = new Graphic3d_ShaderProgram();
567 aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX, aSrcVert));
568 aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
569 anArgsNb = theArgNb - 2;
572 Handle(AIS_InteractiveObject) anIO;
574 || *theArgVec[1] == '*')
576 for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (GetMapOfAIS());
577 anIter.More(); anIter.Next())
579 anIO = Handle(AIS_InteractiveObject)::DownCast (anIter.Key1());
582 anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
583 aCtx->Redisplay (anIO, Standard_False);
586 aCtx->UpdateCurrentViewer();
590 for (Standard_Integer anArgIter = 1; anArgIter < anArgsNb; ++anArgIter)
592 const TCollection_AsciiString aName (theArgVec[anArgIter]);
593 if (!GetMapOfAIS().IsBound2 (aName))
595 std::cerr << "Warning: " << aName.ToCString() << " is not displayed\n";
598 anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (aName));
601 std::cerr << "Warning: " << aName.ToCString() << " is not an AIS object\n";
604 anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
605 aCtx->Redisplay (anIO, Standard_False);
608 aCtx->UpdateCurrentViewer();
612 //=======================================================================
613 //function : OpenGlCommands
615 //=======================================================================
617 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
619 const char* aGroup ="Commands for low-level TKOpenGl features";
621 theCommands.Add("vuserdraw",
622 "vuserdraw : name - simulates drawing with help of UserDraw",
623 __FILE__, VUserDraw, aGroup);
624 theCommands.Add("vfeedback",
625 "vfeedback : perform test GL feedback rendering",
626 __FILE__, VFeedback, aGroup);
627 theCommands.Add("vimmediatefront",
628 "vimmediatefront : render immediate mode to front buffer or to back buffer",
629 __FILE__, VImmediateFront, aGroup);
630 theCommands.Add("vglinfo",
631 "vglinfo [GL_VENDOR] [GL_RENDERER] [GL_VERSION] [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
633 __FILE__, VGlInfo, aGroup);
634 theCommands.Add("vshaderprog",
635 " 'vshaderprog [name] pathToVertexShader pathToFragmentShader'"
636 "\n\t\t: or 'vshaderprog [name] off' to disable GLSL program"
637 "\n\t\t: or 'vshaderprog [name] phong' to enable per-pixel lighting calculations"
638 "\n\t\t: * might be used to specify all displayed objects",
639 __FILE__, VShaderProg, aGroup);