0026029: Visualization - Poor performance of connected objects
[occt.git] / src / OpenGl / OpenGl_Group.cxx
1 // Created on: 2011-08-01
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_Group.hxx>
17
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_Flipper.hxx>
20 #include <OpenGl_PrimitiveArray.hxx>
21 #include <OpenGl_StencilTest.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <OpenGl_Text.hxx>
24 #include <OpenGl_Workspace.hxx>
25
26 #include <Graphic3d_ArrayOfPrimitives.hxx>
27 #include <Graphic3d_CUserDraw.hxx>
28 #include <Graphic3d_GroupDefinitionError.hxx>
29
30 IMPLEMENT_STANDARD_HANDLE (OpenGl_Group, Graphic3d_Group)
31 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Group, Graphic3d_Group)
32
33 // =======================================================================
34 // function : OpenGl_Group
35 // purpose  :
36 // =======================================================================
37 OpenGl_Group::OpenGl_Group (const Handle(Graphic3d_Structure)& theStruct)
38 : Graphic3d_Group (theStruct),
39   myAspectLine(NULL),
40   myAspectFace(NULL),
41   myAspectMarker(NULL),
42   myAspectText(NULL),
43   myFirst(NULL),
44   myLast(NULL),
45   myIsRaytracable (Standard_False)
46 {
47   Handle(OpenGl_Structure) aStruct = Handle(OpenGl_Structure)::DownCast (myStructure->CStructure());
48   if (aStruct == NULL)
49   {
50     Graphic3d_GroupDefinitionError::Raise ("OpenGl_Group should be created by OpenGl_Structure!");
51   }
52 }
53
54 // =======================================================================
55 // function : ~OpenGl_Group
56 // purpose  :
57 // =======================================================================
58 OpenGl_Group::~OpenGl_Group()
59 {
60   Release (Handle(OpenGl_Context)());
61 }
62
63 // =======================================================================
64 // function : UpdateAspectLine
65 // purpose  :
66 // =======================================================================
67 void OpenGl_Group::UpdateAspectLine (const Standard_Boolean theIsGlobal)
68 {
69   if (!ContextLine.IsDef)
70   {
71     return;
72   }
73
74   if (theIsGlobal || myFirst == NULL)
75   {
76     if (myAspectLine == NULL)
77     {
78       myAspectLine = new OpenGl_AspectLine();
79     }
80     myAspectLine->SetAspect (ContextLine);
81   }
82   else
83   {
84     OpenGl_AspectLine* anAspectLine = new OpenGl_AspectLine();
85     anAspectLine->SetAspect (ContextLine);
86     AddElement (anAspectLine);
87   }
88 }
89
90 // =======================================================================
91 // function : UpdateAspectFace
92 // purpose  :
93 // =======================================================================
94 void OpenGl_Group::UpdateAspectFace (const Standard_Boolean theIsGlobal)
95 {
96   if (!ContextFillArea.IsDef)
97   {
98     return;
99   }
100
101   if (theIsGlobal || myFirst == NULL)
102   {
103     if (myAspectFace == NULL)
104     {
105       myAspectFace = new OpenGl_AspectFace();
106     }
107     myAspectFace->SetAspect (ContextFillArea);
108   }
109   else
110   {
111     OpenGl_AspectFace* anAspectFace = new OpenGl_AspectFace();
112     anAspectFace->SetAspect (ContextFillArea);
113     AddElement (anAspectFace);
114   }
115
116   if (myIsRaytracable)
117   {
118     OpenGl_Structure* aStruct = GlStruct();
119     if (aStruct != NULL)
120     {
121       aStruct->UpdateStateIfRaytracable (Standard_False);
122     }
123   }
124 }
125
126 // =======================================================================
127 // function : UpdateAspectMarker
128 // purpose  :
129 // =======================================================================
130 void OpenGl_Group::UpdateAspectMarker (const Standard_Boolean theIsGlobal)
131 {
132   if (!ContextMarker.IsDef)
133   {
134     return;
135   }
136
137   if (theIsGlobal || myFirst == NULL)
138   {
139     if (myAspectMarker == NULL)
140     {
141       myAspectMarker = new OpenGl_AspectMarker();
142     }
143     myAspectMarker->SetAspect (ContextMarker);
144   }
145   else
146   {
147     OpenGl_AspectMarker* anAspectMarker = new OpenGl_AspectMarker();
148     anAspectMarker->SetAspect (ContextMarker);
149     AddElement (anAspectMarker);
150   }
151 }
152
153 // =======================================================================
154 // function : UpdateAspectText
155 // purpose  :
156 // =======================================================================
157 void OpenGl_Group::UpdateAspectText (const Standard_Boolean theIsGlobal)
158 {
159   if (!ContextText.IsDef)
160   {
161     return;
162   }
163
164   if (theIsGlobal || myFirst == NULL)
165   {
166     if (myAspectText == NULL)
167     {
168       myAspectText = new OpenGl_AspectText();
169     }
170     myAspectText->SetAspect (ContextText);
171   }
172   else
173   {
174     OpenGl_AspectText* anAspectText = new OpenGl_AspectText();
175     anAspectText->SetAspect (ContextText);
176     AddElement (anAspectText);
177   }
178 }
179
180 // =======================================================================
181 // function : AddPrimitiveArray
182 // purpose  :
183 // =======================================================================
184 void OpenGl_Group::AddPrimitiveArray (const Graphic3d_TypeOfPrimitiveArray theType,
185                                       const Handle(Graphic3d_IndexBuffer)& theIndices,
186                                       const Handle(Graphic3d_Buffer)&      theAttribs,
187                                       const Handle(Graphic3d_BoundBuffer)& theBounds,
188                                       const Standard_Boolean               theToEvalMinMax)
189 {
190   if (IsDeleted()
191    || theAttribs.IsNull())
192   {
193     return;
194   }
195
196   OpenGl_Structure* aStruct = GlStruct();
197   const OpenGl_GraphicDriver* aDriver = aStruct->GlDriver();
198
199   OpenGl_PrimitiveArray* anArray = new OpenGl_PrimitiveArray (aDriver, theType, theIndices, theAttribs, theBounds);
200   AddElement (anArray);
201
202   Graphic3d_Group::AddPrimitiveArray (theType, theIndices, theAttribs, theBounds, theToEvalMinMax);
203 }
204
205 // =======================================================================
206 // function : Text
207 // purpose  :
208 // =======================================================================
209 void OpenGl_Group::Text (const Standard_CString                  theTextUtf,
210                          const Graphic3d_Vertex&                 thePoint,
211                          const Standard_Real                     theHeight,
212                          const Quantity_PlaneAngle               theAngle,
213                          const Graphic3d_TextPath                theTp,
214                          const Graphic3d_HorizontalTextAlignment theHta,
215                          const Graphic3d_VerticalTextAlignment   theVta,
216                          const Standard_Boolean                  theToEvalMinMax)
217 {
218   if (IsDeleted())
219   {
220     return;
221   }
222
223   OpenGl_TextParam  aParams;
224   OpenGl_Structure* aStruct = GlStruct();
225   aParams.Height = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
226   aParams.HAlign = theHta;
227   aParams.VAlign = theVta;
228   const OpenGl_Vec3 aPoint (thePoint.X(), thePoint.Y(), thePoint.Z());
229   OpenGl_Text* aText = new OpenGl_Text (theTextUtf, aPoint, aParams);
230   AddElement (aText);
231   Graphic3d_Group::Text (theTextUtf, thePoint, theHeight, theAngle,
232                          theTp, theHta, theVta, theToEvalMinMax);
233 }
234
235 // =======================================================================
236 // function : UserDraw
237 // purpose  :
238 // =======================================================================
239 void OpenGl_Group::UserDraw (const Standard_Address theObject,
240                              const Standard_Boolean theToEvalMinMax,
241                              const Standard_Boolean theContainsFacet)
242 {
243   if (IsDeleted())
244   {
245     return;
246   }
247
248   OpenGl_Structure* aStruct = GlStruct();
249   if (aStruct->GlDriver()->UserDrawCallback() == NULL)
250   {
251     return;
252   }
253
254   Graphic3d_CUserDraw aUserDraw;
255   aUserDraw.Data   = theObject;
256   aUserDraw.Bounds = theToEvalMinMax ? &myBounds : NULL;
257   OpenGl_Element* aUserDrawElem = aStruct->GlDriver()->UserDrawCallback()(&aUserDraw);
258   if (aUserDrawElem != NULL)
259   {
260     AddElement (aUserDrawElem);
261   }
262   Graphic3d_Group::UserDraw (theObject, theToEvalMinMax, theContainsFacet);
263 }
264
265 // =======================================================================
266 // function : SetFlippingOptions
267 // purpose  :
268 // =======================================================================
269 void OpenGl_Group::SetFlippingOptions (const Standard_Boolean theIsEnabled,
270                                        const gp_Ax2&          theRefPlane)
271 {
272   OpenGl_Flipper* aFlipper = new OpenGl_Flipper (theRefPlane);
273   aFlipper->SetOptions (theIsEnabled);
274   AddElement (aFlipper);
275 }
276
277 // =======================================================================
278 // function : SetStencilTestOptions
279 // purpose  :
280 // =======================================================================
281 void OpenGl_Group::SetStencilTestOptions (const Standard_Boolean theIsEnabled)
282 {
283   OpenGl_StencilTest* aStencilTest = new OpenGl_StencilTest();
284   aStencilTest->SetOptions (theIsEnabled);
285   AddElement (aStencilTest);
286 }
287
288 // =======================================================================
289 // function : AddElement
290 // purpose  :
291 // =======================================================================
292 void OpenGl_Group::AddElement (OpenGl_Element* theElem)
293 {
294   OpenGl_ElementNode *aNode = new OpenGl_ElementNode();
295
296   aNode->elem = theElem;
297   aNode->next = NULL;
298   (myLast? myLast->next : myFirst) = aNode;
299   myLast = aNode;
300
301   if (OpenGl_Raytrace::IsRaytracedElement (aNode))
302   {
303     myIsRaytracable = Standard_True;
304
305     OpenGl_Structure* aStruct = GlStruct();
306     if (aStruct != NULL)
307     {
308       aStruct->UpdateStateIfRaytracable (Standard_False);
309     }
310   }
311 }
312
313 // =======================================================================
314 // function : Render
315 // purpose  :
316 // =======================================================================
317 void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
318 {
319   // Is rendering in ADD or IMMEDIATE mode?
320   const Handle(OpenGl_RenderFilter)& aFilter = theWorkspace->GetRenderFilter();
321
322   // Setup aspects
323   const OpenGl_AspectLine*   aBackAspectLine   = theWorkspace->AspectLine   (Standard_False);
324   const OpenGl_AspectFace*   aBackAspectFace   = theWorkspace->AspectFace   (Standard_False);
325   const OpenGl_AspectMarker* aBackAspectMarker = theWorkspace->AspectMarker (Standard_False);
326   const OpenGl_AspectText*   aBackAspectText   = theWorkspace->AspectText   (Standard_False);
327   Standard_Boolean isLineSet   = myAspectLine   && myAspectLine->RenderFiltered (theWorkspace, aFilter);
328   Standard_Boolean isFaceSet   = myAspectFace   && myAspectFace->RenderFiltered (theWorkspace, aFilter);
329   Standard_Boolean isMarkerSet = myAspectMarker && myAspectMarker->RenderFiltered (theWorkspace, aFilter);
330   Standard_Boolean isTextSet   = myAspectText   && myAspectText->RenderFiltered (theWorkspace, aFilter);
331
332   // Render group elements
333   for (OpenGl_ElementNode* aNodeIter = myFirst; aNodeIter != NULL; aNodeIter = aNodeIter->next)
334   {
335     aNodeIter->elem->RenderFiltered (theWorkspace, aFilter);
336   }
337
338   // Restore aspects
339   if (isLineSet)
340     theWorkspace->SetAspectLine (aBackAspectLine);
341   if (isFaceSet)
342     theWorkspace->SetAspectFace (aBackAspectFace);
343   if (isMarkerSet)
344     theWorkspace->SetAspectMarker (aBackAspectMarker);
345   if (isTextSet)
346     theWorkspace->SetAspectText (aBackAspectText);
347 }
348
349 // =======================================================================
350 // function : Clear
351 // purpose  :
352 // =======================================================================
353 void OpenGl_Group::Clear (const Standard_Boolean theToUpdateStructureMgr)
354 {
355   if (IsDeleted())
356   {
357     return;
358   }
359
360   OpenGl_Structure* aStruct = GlStruct();
361   const Handle(OpenGl_Context)& aCtx = aStruct->GlDriver()->GetSharedContext();
362
363   Release (aCtx);
364   Graphic3d_Group::Clear (theToUpdateStructureMgr);
365
366   myIsRaytracable = Standard_False;
367 }
368
369 // =======================================================================
370 // function : Release
371 // purpose  :
372 // =======================================================================
373 void OpenGl_Group::Release (const Handle(OpenGl_Context)& theGlCtx)
374 {
375   // Delete elements
376   while (myFirst != NULL)
377   {
378     OpenGl_ElementNode* aNext = myFirst->next;
379     OpenGl_Element::Destroy (theGlCtx.operator->(), myFirst->elem);
380     delete myFirst;
381     myFirst = aNext;
382   }
383   myLast = NULL;
384
385   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectLine);
386   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectFace);
387   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectMarker);
388   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectText);
389 }