0023525: Disappearing of highlight in screenshot
[occt.git] / src / ViewerTest / ViewerTest_OpenGlCommands.cxx
1 // Created on: 2012-04-09
2 // Created by: Sergey ANIKIN
3 // Copyright (c) 2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <ViewerTest.hxx>
25
26 #include <Aspect_GraphicDevice.hxx>
27 #include <AIS_InteractiveContext.hxx>
28 #include <AIS_InteractiveObject.hxx>
29 #include <Draw.hxx>
30 #include <Draw_Interpretor.hxx>
31 #include <Graphic3d_Group.hxx>
32 #include <OpenGl_ArbVBO.hxx>
33 #include <OpenGl_AspectFace.hxx>
34 #include <OpenGl_AspectLine.hxx>
35 #include <OpenGl_AspectMarker.hxx>
36 #include <OpenGl_AspectText.hxx>
37 #include <OpenGl_Context.hxx>
38 #include <OpenGl_Element.hxx>
39 #include <OpenGl_ExtFBO.hxx>
40 #include <OpenGl_GlCore20.hxx>
41 #include <OpenGl_GraphicDriver.hxx>
42 #include <OpenGl_Workspace.hxx>
43 #include <Prs3d_Presentation.hxx>
44 #include <Prs3d_Root.hxx>
45 #include <Select3D_SensitiveCurve.hxx>
46 #include <SelectMgr_EntityOwner.hxx>
47 #include <SelectMgr_Selection.hxx>
48 #include <V3d_Viewer.hxx>
49 #include <TCollection_AsciiString.hxx>
50 #include <V3d_View.hxx>
51 #include <Visual3d_View.hxx>
52
53 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
54                                            const Handle(AIS_InteractiveObject)& theAISObj,
55                                            Standard_Boolean theReplaceIfExists = Standard_True);
56
57 //=======================================================================
58 //function : VUserDraw
59 //purpose  : Checks availability and operation of UserDraw feature
60 //=======================================================================
61 DEFINE_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
62
63 class VUserDrawObj : public AIS_InteractiveObject
64 {
65 public:
66     // CASCADE RTTI
67     DEFINE_STANDARD_RTTI(VUserDrawObj);
68
69     VUserDrawObj()
70     {
71       myCoords[0] = -10.;
72       myCoords[1] = -20.;
73       myCoords[2] = -30.;
74       myCoords[3] =  10.;
75       myCoords[4] =  20.;
76       myCoords[5] =  30.;
77     }
78
79 public:
80   class Element : public OpenGl_Element
81   {
82   private:
83     Handle(VUserDrawObj) myIObj;
84
85   public:
86     Element (const Handle(VUserDrawObj)& theIObj,
87              CALL_DEF_BOUNDS* theBounds)
88     : myIObj( theIObj )
89     {
90       if (!myIObj.IsNull())
91         myIObj->GetBounds(theBounds);
92     }
93
94     virtual ~Element ()
95     {
96     }
97
98     virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
99     {
100       if (!myIObj.IsNull())
101         myIObj->Render(theWorkspace);
102     }
103
104     virtual void Release (const Handle(OpenGl_Context)& theGlCtx)
105     {
106       //
107     }
108
109   public:
110     DEFINE_STANDARD_ALLOC
111   };
112
113 private:
114     // Virtual methods implementation
115     void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
116                   const Handle(Prs3d_Presentation)& thePresentation,
117                   const Standard_Integer theMode);
118
119     void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
120                            const Standard_Integer theMode);
121
122     // Called by VUserDrawElement
123     void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
124     void GetBounds(CALL_DEF_BOUNDS* theBounds);
125
126     GLfloat myCoords[6];
127
128     friend class Element;
129 };
130 IMPLEMENT_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
131 IMPLEMENT_STANDARD_RTTIEXT(VUserDrawObj, AIS_InteractiveObject)
132
133 void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
134                            const Handle(Prs3d_Presentation)& thePresentation,
135                            const Standard_Integer theMode)
136 {
137   thePresentation->Clear();
138
139   Handle(Graphic3d_Group) aGrp = Prs3d_Root::CurrentGroup(thePresentation);
140   aGrp->UserDraw(this, Standard_True, Standard_True);
141 }
142
143 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
144                                      const Standard_Integer theMode)
145 {
146   Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner(this);
147   Handle(TColgp_HArray1OfPnt) aPnts = new TColgp_HArray1OfPnt(1, 5);
148   aPnts->SetValue(1, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
149   aPnts->SetValue(2, gp_Pnt(myCoords[3], myCoords[4], myCoords[2]));
150   aPnts->SetValue(3, gp_Pnt(myCoords[3], myCoords[4], myCoords[5]));
151   aPnts->SetValue(4, gp_Pnt(myCoords[0], myCoords[1], myCoords[5]));
152   aPnts->SetValue(5, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
153   Handle(Select3D_SensitiveCurve) aSensitive = new Select3D_SensitiveCurve(anEntityOwner, aPnts);
154   theSelection->Add(aSensitive);
155 }
156
157 void VUserDrawObj::GetBounds(CALL_DEF_BOUNDS* theBounds)
158 {
159   if (theBounds)
160   {
161     theBounds->XMin = myCoords[0];
162     theBounds->YMin = myCoords[1];
163     theBounds->ZMin = myCoords[2];
164     theBounds->XMax = myCoords[3];
165     theBounds->YMax = myCoords[4];
166     theBounds->ZMax = myCoords[5];
167   }
168 }
169
170 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
171 {
172   // To test linking against OpenGl_Workspace and all aspect classes
173   const OpenGl_AspectLine* aLA = theWorkspace->AspectLine(0);
174   const OpenGl_AspectFace* aFA = theWorkspace->AspectFace(0);
175   const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker(0);
176   aMA->Type();
177   const OpenGl_AspectText* aTA = theWorkspace->AspectText(0);
178   aTA->Font();
179   TEL_COLOUR aColor = theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT ?
180     *(theWorkspace->HighlightColor) : aLA->Color();
181
182   // To test OpenGl_Window
183   //Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
184
185   // Finally draw something to make sure UserDraw really works
186   glPushAttrib(GL_ENABLE_BIT);
187   glDisable(GL_LIGHTING);
188   glColor4fv(aColor.rgb);
189   glBegin(GL_LINE_LOOP);
190   glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
191   glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
192   glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
193   glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
194   glEnd();
195   glPopAttrib();
196 }
197
198 OpenGl_Element* VUserDrawCallback(const CALL_DEF_USERDRAW * theUserDraw)
199 {
200   Handle(VUserDrawObj) anIObj = (VUserDrawObj*)theUserDraw->Data;
201   if (anIObj.IsNull())
202   {
203     std::cout << "VUserDrawCallback error: null object passed, the custom scene element will not be rendered" << std::endl;
204   }
205
206   return new VUserDrawObj::Element(anIObj, theUserDraw->Bounds);
207 }
208
209 static Standard_Integer VUserDraw (Draw_Interpretor& di,
210                                     Standard_Integer argc,
211                                     const char ** argv)
212 {
213   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
214   if (aContext.IsNull())
215   {
216     di << argv[0] << "Call 'vinit' before!\n";
217     return 1;
218   }
219
220   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Device()->GraphicDriver());
221   if (aDriver.IsNull())
222   {
223     std::cerr << "Graphic driver not available.\n";
224     return 1;
225   }
226
227   if (argc > 2)
228   {
229     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
230     return 1;
231   }
232
233   TCollection_AsciiString aName (argv[1]);
234   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
235
236   // register the custom element factory function
237   aDriver->UserDrawCallback() = VUserDrawCallback;
238
239   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
240   VDisplayAISObject(aName, anIObj);
241
242   return 0;
243 }
244
245 //==============================================================================
246 //function : VFeedback
247 //purpose  :
248 //==============================================================================
249
250 static int VFeedback (Draw_Interpretor& theDI,
251                       Standard_Integer  theArgNb,
252                       const char**      theArgVec)
253 {
254   // get the active view
255   Handle(V3d_View) aView = ViewerTest::CurrentView();
256   if (aView.IsNull())
257   {
258     std::cerr << "No active view. Please call vinit.\n";
259     return 1;
260   }
261
262   unsigned int aBufferSize = 1024 * 1024;
263   for (;;)
264   {
265     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
266     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
267     {
268       // finito la commedia
269       std::cerr << "Can not allocate buffer - requested size ("
270                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
271                 << " MiB) is out of address space\n";
272       return 1;
273     }
274
275     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
276     if (aBuffer == NULL)
277     {
278       // finito la commedia
279       std::cerr << "Can not allocate buffer with size ("
280                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
281                 << " MiB)\n";
282       return 1;
283     }
284
285     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
286     glRenderMode (GL_FEEDBACK);
287
288     aView->Redraw();
289
290     GLint aResult = glRenderMode (GL_RENDER);
291     if (aResult < 0)
292     {
293       aBufferSize *= 2;
294
295       void* aPtr = aBuffer;
296       Standard::Free (aPtr);
297       aBuffer = NULL;
298       continue;
299     }
300
301     std::cout << "FeedBack result= " << aResult << "\n";
302     GLint aPntNb     = 0;
303     GLint aTriNb     = 0;
304     GLint aQuadsNb   = 0;
305     GLint aPolyNb    = 0;
306     GLint aNodesNb   = 0;
307     GLint aLinesNb   = 0;
308     GLint aBitmapsNb = 0;
309     GLint aPassThrNb = 0;
310     GLint aUnknownNb = 0;
311     const GLint NODE_VALUES = 2; // GL_2D
312     for (GLint anIter = 0; anIter < aResult;)
313     {
314         const GLfloat aPos = aBuffer[anIter];
315         switch ((GLint )aPos)
316         {
317           case GL_POINT_TOKEN:
318           {
319             ++aPntNb;
320             ++aNodesNb;
321             anIter += 1 + NODE_VALUES;
322             break;
323           }
324           case GL_LINE_RESET_TOKEN:
325           case GL_LINE_TOKEN:
326           {
327             ++aLinesNb;
328             aNodesNb += 2;
329             anIter += 1 + 2 * NODE_VALUES;
330             break;
331           }
332           case GL_POLYGON_TOKEN:
333           {
334             const GLint aCount = (GLint )aBuffer[++anIter];
335             aNodesNb += aCount;
336             anIter += aCount * NODE_VALUES + 1;
337             if (aCount == 3)
338             {
339               ++aTriNb;
340             }
341             else if (aCount == 4)
342             {
343               ++aQuadsNb;
344             }
345             else
346             {
347               ++aPolyNb;
348             }
349             break;
350           }
351           case GL_BITMAP_TOKEN:
352           case GL_DRAW_PIXEL_TOKEN:
353           case GL_COPY_PIXEL_TOKEN:
354           {
355             ++aBitmapsNb;
356             anIter += 1 + NODE_VALUES;
357             break;
358           }
359           case GL_PASS_THROUGH_TOKEN:
360           {
361             ++aPassThrNb;
362             anIter += 2; // header + value
363             break;
364           }
365           default:
366           {
367             ++anIter;
368             ++aUnknownNb;
369             break;
370           }
371        }
372     }
373     void* aPtr = aBuffer;
374     Standard::Free (aPtr);
375
376     // return statistics
377     theDI << "Total nodes:   " << aNodesNb   << "\n"
378           << "Points:        " << aPntNb     << "\n"
379           << "Line segments: " << aLinesNb   << "\n"
380           << "Triangles:     " << aTriNb     << "\n"
381           << "Quads:         " << aQuadsNb   << "\n"
382           << "Polygons:      " << aPolyNb    << "\n"
383           << "Bitmap tokens: " << aBitmapsNb << "\n"
384           << "Pass through:  " << aPassThrNb << "\n"
385           << "UNKNOWN:       " << aUnknownNb << "\n";
386
387     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
388     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
389     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
390     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
391           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
392           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
393     return 0;
394   }
395 }
396
397 //==============================================================================
398 //function : VImmediateFront
399 //purpose  :
400 //==============================================================================
401
402 static int VImmediateFront (Draw_Interpretor& theDI,
403                             Standard_Integer  theArgNb,
404                             const char**      theArgVec)
405 {
406   // get the context
407   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
408   if (aContextAIS.IsNull())
409   {
410     std::cerr << "No active view. Please call vinit.\n";
411     return 1;
412   }
413
414   Handle(Graphic3d_GraphicDriver) aDriver =
415          Handle(Graphic3d_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Device()->GraphicDriver());
416   if (aDriver.IsNull())
417   {
418     std::cerr << "Graphic driver not available.\n";
419     return 1;
420   }
421
422   if (theArgNb < 2)
423   {
424     //theDI << "VBO: " << aDriver->ToUseVBO() << "\n";
425     //return 0;
426     std::cerr << "Wrong number of arguments.\n";
427     return 1;
428   }
429
430   Graphic3d_CView* aCView = (Graphic3d_CView* )(ViewerTest::CurrentView()->View()->CView());
431   aDriver->SetImmediateModeDrawToFront (*aCView, atoi(theArgVec[1]) != 0);
432   return 0;
433 }
434
435 //=======================================================================
436 //function : OpenGlCommands
437 //purpose  :
438 //=======================================================================
439
440 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
441 {
442   const char* aGroup ="Commands for low-level TKOpenGl features";
443
444   theCommands.Add("vuserdraw",
445     "vuserdraw : name - simulates drawing with help of UserDraw",
446     __FILE__, VUserDraw, aGroup);
447   theCommands.Add("vfeedback",
448     "vfeedback       : perform test GL feedback rendering",
449     __FILE__, VFeedback, aGroup);
450   theCommands.Add("vimmediatefront",
451     "vimmediatefront : render immediate mode to front buffer or to back buffer",
452     __FILE__, VImmediateFront, aGroup);
453
454 }