0023227: New Draw Harness command to estimate current geometry complexity of OpenGL...
[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 <AIS_InteractiveObject.hxx>
27 #include <Draw.hxx>
28 #include <Draw_Interpretor.hxx>
29 #include <Graphic3d_Group.hxx>
30 #include <OpenGl_ArbVBO.hxx>
31 #include <OpenGl_AspectFace.hxx>
32 #include <OpenGl_AspectLine.hxx>
33 #include <OpenGl_AspectMarker.hxx>
34 #include <OpenGl_AspectText.hxx>
35 #include <OpenGl_Callback.hxx>
36 #include <OpenGl_Context.hxx>
37 #include <OpenGl_Element.hxx>
38 #include <OpenGl_ExtFBO.hxx>
39 #include <OpenGl_GlCore20.hxx>
40 #include <OpenGl_ResourceCleaner.hxx>
41 #include <OpenGl_ResourceTexture.hxx>
42 #include <OpenGl_ResourceVBO.hxx>
43 #include <OpenGl_Workspace.hxx>
44 #include <Prs3d_Presentation.hxx>
45 #include <Prs3d_Root.hxx>
46 #include <Select3D_SensitiveCurve.hxx>
47 #include <SelectMgr_EntityOwner.hxx>
48 #include <SelectMgr_Selection.hxx>
49 #include <TCollection_AsciiString.hxx>
50 #include <V3d_View.hxx>
51
52 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
53                                            const Handle(AIS_InteractiveObject)& theAISObj,
54                                            Standard_Boolean theReplaceIfExists = Standard_True);
55
56 //=======================================================================
57 //function : VUserDraw
58 //purpose  : Checks availability and operation of UserDraw feature
59 //=======================================================================
60 DEFINE_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
61
62 class VUserDrawObj : public AIS_InteractiveObject
63 {
64 public:
65     // CASCADE RTTI
66     DEFINE_STANDARD_RTTI(VUserDrawObj);
67
68     VUserDrawObj()
69     {
70       myCoords[0] = -10.;
71       myCoords[1] = -20.;
72       myCoords[2] = -30.;
73       myCoords[3] =  10.;
74       myCoords[4] =  20.;
75       myCoords[5] =  30.;
76     }
77
78 public:
79   class Element : public OpenGl_Element
80   {
81   private:
82     Handle(VUserDrawObj) myIObj;
83
84   public:
85     Element (const Handle(VUserDrawObj)& theIObj,
86              CALL_DEF_BOUNDS* theBounds)
87     : myIObj( theIObj )
88     {
89       if (!myIObj.IsNull())
90         myIObj->GetBounds(theBounds);
91     }
92
93     virtual ~Element ()
94     {
95     }
96
97     virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
98     {
99       if (!myIObj.IsNull())
100         myIObj->Render(theWorkspace);
101     }
102
103   public:
104     DEFINE_STANDARD_ALLOC
105   };
106
107 private:
108     // Virtual methods implementation
109     void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
110                   const Handle(Prs3d_Presentation)& thePresentation,
111                   const Standard_Integer theMode);
112
113     void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
114                            const Standard_Integer theMode);
115
116     // Called by VUserDrawElement
117     void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
118     void GetBounds(CALL_DEF_BOUNDS* theBounds);
119
120     GLfloat myCoords[6];
121
122     friend class Element;
123 };
124 IMPLEMENT_STANDARD_HANDLE(VUserDrawObj, AIS_InteractiveObject)
125 IMPLEMENT_STANDARD_RTTIEXT(VUserDrawObj, AIS_InteractiveObject)
126
127 void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
128                            const Handle(Prs3d_Presentation)& thePresentation,
129                            const Standard_Integer theMode)
130 {
131   thePresentation->Clear();
132
133   Handle(Graphic3d_Group) aGrp = Prs3d_Root::CurrentGroup(thePresentation);
134   aGrp->UserDraw(this, Standard_True, Standard_True);
135 }
136
137 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
138                                      const Standard_Integer theMode)
139 {
140   Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner(this);
141   Handle(TColgp_HArray1OfPnt) aPnts = new TColgp_HArray1OfPnt(1, 5);
142   aPnts->SetValue(1, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
143   aPnts->SetValue(2, gp_Pnt(myCoords[3], myCoords[4], myCoords[2]));
144   aPnts->SetValue(3, gp_Pnt(myCoords[3], myCoords[4], myCoords[5]));
145   aPnts->SetValue(4, gp_Pnt(myCoords[0], myCoords[1], myCoords[5]));
146   aPnts->SetValue(5, gp_Pnt(myCoords[0], myCoords[1], myCoords[2]));
147   Handle(Select3D_SensitiveCurve) aSensitive = new Select3D_SensitiveCurve(anEntityOwner, aPnts);
148   theSelection->Add(aSensitive);
149 }
150
151 void VUserDrawObj::GetBounds(CALL_DEF_BOUNDS* theBounds)
152 {
153   if (theBounds)
154   {
155     theBounds->XMin = myCoords[0];
156     theBounds->YMin = myCoords[1];
157     theBounds->ZMin = myCoords[2];
158     theBounds->XMax = myCoords[3];
159     theBounds->YMax = myCoords[4];
160     theBounds->ZMax = myCoords[5];
161   }
162 }
163
164 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
165 {
166   // To test linking against OpenGl_Workspace and all aspect classes
167   const OpenGl_AspectLine* aLA = theWorkspace->AspectLine(0);
168   const OpenGl_AspectFace* aFA = theWorkspace->AspectFace(0);
169   aFA->Context();
170   const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker(0);
171   aMA->Type();
172   const OpenGl_AspectText* aTA = theWorkspace->AspectText(0);
173   aTA->Font();
174   TEL_COLOUR aColor = theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT ?
175     *(theWorkspace->HighlightColor) : aLA->Color();
176
177   // To test OpenGl_Window
178   Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
179   GLCONTEXT aGlContext = theWorkspace->GetGContext();
180
181   // To link against OpenGl_Context and extensions
182   GLuint aVboId = -1, aTexId = -1;
183   if (aCtx->arbVBO)
184     aCtx->arbVBO->glGenBuffersARB(1, &aVboId);
185   glGenTextures(1, &aTexId);
186
187   // To link against OpenGl_ResourceCleaner, OpenGl_ResourceVBO, OpenGl_ResourceTexture
188   OpenGl_ResourceCleaner* aResCleaner = OpenGl_ResourceCleaner::GetInstance();
189   if (aVboId != (GLuint)-1)
190     aResCleaner->AddResource(aGlContext, new OpenGl_ResourceVBO(aVboId));
191   if (aTexId != (GLuint)-1)
192     aResCleaner->AddResource(aGlContext, new OpenGl_ResourceTexture(aTexId));
193
194   // Finally draw something to make sure UserDraw really works
195   glPushAttrib(GL_ENABLE_BIT);
196   glDisable(GL_LIGHTING);
197   glColor4fv(aColor.rgb);
198   glBegin(GL_LINE_LOOP);
199   glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
200   glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
201   glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
202   glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
203   glEnd();
204   glPopAttrib();
205 }
206
207
208
209 OpenGl_Element* VUserDrawCallback(const CALL_DEF_USERDRAW * theUserDraw)
210 {
211   Handle(VUserDrawObj) anIObj = (VUserDrawObj*)theUserDraw->Data;
212   if (anIObj.IsNull())
213   {
214     std::cout << "VUserDrawCallback error: null object passed, the custom scene element will not be rendered" << std::endl;
215   }
216
217   return new VUserDrawObj::Element(anIObj, theUserDraw->Bounds);
218 }
219
220 static Standard_Integer VUserDraw (Draw_Interpretor& di,
221                                     Standard_Integer argc,
222                                     const char ** argv)
223 {
224   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
225   if (aContext.IsNull())
226   {
227     di << argv[0] << "Call 'vinit' before!\n";
228     return 1;
229   }
230
231   if (argc > 2)
232   {
233     di << argv[0] << "Wrong number of arguments, only the object name expected\n";
234     return 1;
235   }
236
237   TCollection_AsciiString aName (argv[1]);
238   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
239
240   // register the custom element factory function
241   ::UserDrawCallback() = VUserDrawCallback;
242
243   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
244   VDisplayAISObject(aName, anIObj);
245
246   return 0;
247 }
248
249 //==============================================================================
250 //function : VFeedback
251 //purpose  :
252 //==============================================================================
253
254 static int VFeedback (Draw_Interpretor& theDI,
255                       Standard_Integer  theArgNb,
256                       const char**      theArgVec)
257 {
258   // get the active view
259   Handle(V3d_View) aView = ViewerTest::CurrentView();
260   if (aView.IsNull())
261   {
262     std::cerr << "No active view. Please call vinit.\n";
263     return 1;
264   }
265
266   unsigned int aBufferSize = 1024 * 1024;
267   for (;;)
268   {
269     size_t aBytes = (size_t )aBufferSize * sizeof(GLfloat);
270     if (aBytes / sizeof(GLfloat) != (size_t )aBufferSize)
271     {
272       // finito la commedia
273       std::cerr << "Can not allocate buffer - requested size ("
274                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
275                 << " MiB) is out of address space\n";
276       return 1;
277     }
278
279     GLfloat* aBuffer = (GLfloat* )Standard::Allocate (aBytes);
280     if (aBuffer == NULL)
281     {
282       // finito la commedia
283       std::cerr << "Can not allocate buffer with size ("
284                 << (double(aBufferSize / (1024 * 1024)) * double(sizeof(GLfloat)))
285                 << " MiB)\n";
286       return 1;
287     }
288
289     glFeedbackBuffer ((GLsizei )aBufferSize, GL_2D, aBuffer);
290     glRenderMode (GL_FEEDBACK);
291
292     aView->Redraw();
293
294     GLint aResult = glRenderMode (GL_RENDER);
295     if (aResult < 0)
296     {
297       aBufferSize *= 2;
298
299       void* aPtr = aBuffer;
300       Standard::Free (aPtr);
301       aBuffer = NULL;
302       continue;
303     }
304
305     std::cout << "FeedBack result= " << aResult << "\n";
306     GLint aPntNb     = 0;
307     GLint aTriNb     = 0;
308     GLint aQuadsNb   = 0;
309     GLint aPolyNb    = 0;
310     GLint aNodesNb   = 0;
311     GLint aLinesNb   = 0;
312     GLint aBitmapsNb = 0;
313     GLint aPassThrNb = 0;
314     GLint aUnknownNb = 0;
315     const GLint NODE_VALUES = 2; // GL_2D
316     for (GLint anIter = 0; anIter < aResult;)
317     {
318         const GLfloat aPos = aBuffer[anIter];
319         switch ((GLint )aPos)
320         {
321           case GL_POINT_TOKEN:
322           {
323             ++aPntNb;
324             ++aNodesNb;
325             anIter += 1 + NODE_VALUES;
326             break;
327           }
328           case GL_LINE_RESET_TOKEN:
329           case GL_LINE_TOKEN:
330           {
331             ++aLinesNb;
332             aNodesNb += 2;
333             anIter += 1 + 2 * NODE_VALUES;
334             break;
335           }
336           case GL_POLYGON_TOKEN:
337           {
338             const GLint aCount = (GLint )aBuffer[++anIter];
339             aNodesNb += aCount;
340             anIter += aCount * NODE_VALUES + 1;
341             if (aCount == 3)
342             {
343               ++aTriNb;
344             }
345             else if (aCount == 4)
346             {
347               ++aQuadsNb;
348             }
349             else
350             {
351               ++aPolyNb;
352             }
353             break;
354           }
355           case GL_BITMAP_TOKEN:
356           case GL_DRAW_PIXEL_TOKEN:
357           case GL_COPY_PIXEL_TOKEN:
358           {
359             ++aBitmapsNb;
360             anIter += 1 + NODE_VALUES;
361             break;
362           }
363           case GL_PASS_THROUGH_TOKEN:
364           {
365             ++aPassThrNb;
366             anIter += 2; // header + value
367             break;
368           }
369           default:
370           {
371             ++anIter;
372             ++aUnknownNb;
373             break;
374           }
375        }
376     }
377     void* aPtr = aBuffer;
378     Standard::Free (aPtr);
379
380     // return statistics
381     theDI << "Total nodes:   " << aNodesNb   << "\n"
382           << "Points:        " << aPntNb     << "\n"
383           << "Line segments: " << aLinesNb   << "\n"
384           << "Triangles:     " << aTriNb     << "\n"
385           << "Quads:         " << aQuadsNb   << "\n"
386           << "Polygons:      " << aPolyNb    << "\n"
387           << "Bitmap tokens: " << aBitmapsNb << "\n"
388           << "Pass through:  " << aPassThrNb << "\n"
389           << "UNKNOWN:       " << aUnknownNb << "\n";
390
391     double aLen2D      = double(aNodesNb * 2 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
392     double aLen3D      = double(aNodesNb * 3 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
393     double aLen3D_rgba = double(aNodesNb * 7 + aPntNb + aLinesNb * 2 + (aTriNb + aQuadsNb + aPolyNb) * 2 + aBitmapsNb + aPassThrNb);
394     theDI << "Buffer size GL_2D:       " << aLen2D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
395           << "Buffer size GL_3D:       " << aLen3D      * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n"
396           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
397     return 0;
398   }
399 }
400
401 //=======================================================================
402 //function : OpenGlCommands
403 //purpose  :
404 //=======================================================================
405
406 void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
407 {
408   const char* aGroup ="Commands for low-level TKOpenGl features";
409
410   theCommands.Add("vuserdraw",
411     "vuserdraw : name - simulates drawing with help of UserDraw",
412     __FILE__, VUserDraw, aGroup);
413   theCommands.Add("vfeedback",
414     "vfeedback       : perform test GL feedback rendering",
415     __FILE__, VFeedback, aGroup);
416 }