0030153: Visualization, TKOpenGl - AIS_ColoredShape::SynchronizeAspects() doesn't...
[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_SceneGeometry.hxx>
22 #include <OpenGl_StencilTest.hxx>
23 #include <OpenGl_Structure.hxx>
24 #include <OpenGl_Text.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 #include <Graphic3d_ArrayOfPrimitives.hxx>
28 #include <Graphic3d_GroupDefinitionError.hxx>
29
30 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Group,Graphic3d_Group)
31
32 namespace
33 {
34   //! Render element if it passes the filtering procedure. This method should
35   //! be used for elements which can be used in scope of rendering algorithms.
36   //! E.g. elements of groups during recursive rendering.
37   //! If render filter is null, pure rendering is performed.
38   //! @param theWorkspace [in] the rendering workspace.
39   //! @param theFilter [in] the rendering filter to check whether the element
40   //! should be rendered or not.
41   //! @return True if element passes the check and renders,
42   static bool renderFiltered (const Handle(OpenGl_Workspace)& theWorkspace,
43                               OpenGl_Element* theElement)
44   {
45     if (!theWorkspace->ShouldRender (theElement))
46     {
47       return false;
48     }
49
50     theElement->Render (theWorkspace);
51     return true;
52   }
53 }
54
55 // =======================================================================
56 // function : OpenGl_Group
57 // purpose  :
58 // =======================================================================
59 OpenGl_Group::OpenGl_Group (const Handle(Graphic3d_Structure)& theStruct)
60 : Graphic3d_Group (theStruct),
61   myAspectLine(NULL),
62   myAspectFace(NULL),
63   myAspectMarker(NULL),
64   myAspectText(NULL),
65   myFirst(NULL),
66   myLast(NULL),
67   myIsRaytracable (Standard_False)
68 {
69   Handle(OpenGl_Structure) aStruct = Handle(OpenGl_Structure)::DownCast (myStructure->CStructure());
70   if (aStruct.IsNull())
71   {
72     throw Graphic3d_GroupDefinitionError("OpenGl_Group should be created by OpenGl_Structure!");
73   }
74 }
75
76 // =======================================================================
77 // function : ~OpenGl_Group
78 // purpose  :
79 // =======================================================================
80 OpenGl_Group::~OpenGl_Group()
81 {
82   Release (Handle(OpenGl_Context)());
83 }
84
85 // =======================================================================
86 // function : SetGroupPrimitivesAspect
87 // purpose  :
88 // =======================================================================
89 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectLine3d)& theAspect)
90 {
91   if (IsDeleted())
92   {
93     return;
94   }
95
96   if (myAspectLine == NULL)
97   {
98     myAspectLine = new OpenGl_AspectLine (theAspect);
99   }
100   else
101   {
102     myAspectLine->SetAspect (theAspect);
103   }
104   Update();
105 }
106
107 // =======================================================================
108 // function : SetPrimitivesAspect
109 // purpose  :
110 // =======================================================================
111 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectLine3d)& theAspect)
112 {
113   if (myAspectLine == NULL)
114   {
115     SetGroupPrimitivesAspect (theAspect);
116     return;
117   }
118   else if (IsDeleted())
119   {
120     return;
121   }
122
123   OpenGl_AspectLine* anAspectLine = new OpenGl_AspectLine (theAspect);
124   AddElement (anAspectLine);
125   Update();
126 }
127
128 // =======================================================================
129 // function : SetGroupPrimitivesAspect
130 // purpose  :
131 // =======================================================================
132 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
133 {
134   if (IsDeleted())
135   {
136     return;
137   }
138
139   if (myAspectFace == NULL)
140   {
141     myAspectFace = new OpenGl_AspectFace (theAspect);
142   }
143   else
144   {
145     myAspectFace->SetAspect (theAspect);
146   }
147
148   if (myIsRaytracable)
149   {
150     OpenGl_Structure* aStruct = GlStruct();
151     if (aStruct != NULL)
152     {
153       aStruct->UpdateStateIfRaytracable (Standard_False);
154     }
155   }
156
157   Update();
158 }
159
160 // =======================================================================
161 // function : SetPrimitivesAspect
162 // purpose  :
163 // =======================================================================
164 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
165 {
166   if (myAspectFace == NULL)
167   {
168     SetGroupPrimitivesAspect (theAspect);
169     return;
170   }
171   else if (IsDeleted())
172   {
173     return;
174   }
175
176   OpenGl_AspectFace* anAspectFace = new OpenGl_AspectFace (theAspect);
177   AddElement (anAspectFace);
178   Update();
179 }
180
181 // =======================================================================
182 // function : SetGroupPrimitivesAspect
183 // purpose  :
184 // =======================================================================
185 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectMarker3d)& theAspMarker)
186 {
187   if (IsDeleted())
188   {
189     return;
190   }
191
192   if (myAspectMarker == NULL)
193   {
194     myAspectMarker = new OpenGl_AspectMarker (theAspMarker);
195   }
196   else
197   {
198     myAspectMarker->SetAspect (theAspMarker);
199   }
200   Update();
201 }
202
203 // =======================================================================
204 // function : SetPrimitivesAspect
205 // purpose  :
206 // =======================================================================
207 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectMarker3d)& theAspMarker)
208 {
209   if (myAspectMarker == NULL)
210   {
211     SetGroupPrimitivesAspect (theAspMarker);
212     return;
213   }
214   else if (IsDeleted())
215   {
216     return;
217   }
218
219   OpenGl_AspectMarker* anAspectMarker = new OpenGl_AspectMarker (theAspMarker);
220   AddElement (anAspectMarker);
221   Update();
222 }
223
224 // =======================================================================
225 // function : SetGroupPrimitivesAspect
226 // purpose  :
227 // =======================================================================
228 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_AspectText3d)& theAspText)
229 {
230   if (IsDeleted())
231   {
232     return;
233   }
234
235   if (myAspectText == NULL)
236   {
237     myAspectText = new OpenGl_AspectText (theAspText);
238   }
239   else
240   {
241     myAspectText->SetAspect (theAspText);
242   }
243   Update();
244 }
245
246 // =======================================================================
247 // function : SetPrimitivesAspect
248 // purpose  :
249 // =======================================================================
250 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_AspectText3d)& theAspText)
251 {
252   if (myAspectText == NULL)
253   {
254     SetGroupPrimitivesAspect (theAspText);
255     return;
256   }
257   else if (IsDeleted())
258   {
259     return;
260   }
261
262   OpenGl_AspectText* anAspectText = new OpenGl_AspectText (theAspText);
263   AddElement (anAspectText);
264   Update();
265 }
266
267 // =======================================================================
268 // function : SynchronizeAspects
269 // purpose  :
270 // =======================================================================
271 void OpenGl_Group::SynchronizeAspects()
272 {
273   if (myAspectFace != NULL)
274   {
275     myAspectFace->SynchronizeAspects();
276   }
277   if (myAspectLine != NULL)
278   {
279     myAspectLine->SynchronizeAspects();
280   }
281   if (myAspectMarker != NULL)
282   {
283     myAspectMarker->SynchronizeAspects();
284   }
285   if (myAspectText != NULL)
286   {
287     myAspectText->SynchronizeAspects();
288   }
289   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
290   {
291     aNode->elem->SynchronizeAspects();
292   }
293 }
294
295 // =======================================================================
296 // function : AddPrimitiveArray
297 // purpose  :
298 // =======================================================================
299 void OpenGl_Group::AddPrimitiveArray (const Graphic3d_TypeOfPrimitiveArray theType,
300                                       const Handle(Graphic3d_IndexBuffer)& theIndices,
301                                       const Handle(Graphic3d_Buffer)&      theAttribs,
302                                       const Handle(Graphic3d_BoundBuffer)& theBounds,
303                                       const Standard_Boolean               theToEvalMinMax)
304 {
305   if (IsDeleted()
306    || theAttribs.IsNull())
307   {
308     return;
309   }
310
311   OpenGl_Structure* aStruct = GlStruct();
312   const OpenGl_GraphicDriver* aDriver = aStruct->GlDriver();
313
314   OpenGl_PrimitiveArray* anArray = new OpenGl_PrimitiveArray (aDriver, theType, theIndices, theAttribs, theBounds);
315   AddElement (anArray);
316
317   Graphic3d_Group::AddPrimitiveArray (theType, theIndices, theAttribs, theBounds, theToEvalMinMax);
318 }
319
320 // =======================================================================
321 // function : Text
322 // purpose  :
323 // =======================================================================
324 void OpenGl_Group::Text (const Standard_CString                  theTextUtf,
325                          const Graphic3d_Vertex&                 thePoint,
326                          const Standard_Real                     theHeight,
327                          const Standard_Real                     theAngle,
328                          const Graphic3d_TextPath                theTp,
329                          const Graphic3d_HorizontalTextAlignment theHta,
330                          const Graphic3d_VerticalTextAlignment   theVta,
331                          const Standard_Boolean                  theToEvalMinMax)
332 {
333   if (IsDeleted())
334   {
335     return;
336   }
337
338   OpenGl_TextParam  aParams;
339   OpenGl_Structure* aStruct = GlStruct();
340   aParams.Height = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
341   aParams.HAlign = theHta;
342   aParams.VAlign = theVta;
343   const OpenGl_Vec3 aPoint (thePoint.X(), thePoint.Y(), thePoint.Z());
344   OpenGl_Text* aText = new OpenGl_Text (theTextUtf, aPoint, aParams);
345   AddElement (aText);
346   Graphic3d_Group::Text (theTextUtf, thePoint, theHeight, theAngle,
347                          theTp, theHta, theVta, theToEvalMinMax);
348 }
349
350 // =======================================================================
351 // function : Text
352 // purpose  :
353 // =======================================================================
354 void OpenGl_Group::Text (const Standard_CString                  theTextUtf,
355                          const gp_Ax2&                           theOrientation,
356                          const Standard_Real                     theHeight,
357                          const Standard_Real                     theAngle,
358                          const Graphic3d_TextPath                theTp,
359                          const Graphic3d_HorizontalTextAlignment theHTA,
360                          const Graphic3d_VerticalTextAlignment   theVTA,
361                          const Standard_Boolean                  theToEvalMinMax,
362                          const Standard_Boolean                  theHasOwnAnchor)
363 {
364   if (IsDeleted())
365   {
366     return;
367   }
368
369   OpenGl_TextParam  aParams;
370   OpenGl_Structure* aStruct = GlStruct();
371
372   aParams.Height      = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
373   aParams.HAlign      = theHTA;
374   aParams.VAlign      = theVTA;
375
376   OpenGl_Text* aText = new OpenGl_Text (theTextUtf, theOrientation, aParams, theHasOwnAnchor != Standard_False);
377
378   AddElement (aText);
379
380   Graphic3d_Group::Text (theTextUtf,
381                          theOrientation,
382                          theHeight,
383                          theAngle,
384                          theTp,
385                          theHTA,
386                          theVTA,
387                          theToEvalMinMax,
388                          theHasOwnAnchor);
389
390 }
391
392 // =======================================================================
393 // function : SetFlippingOptions
394 // purpose  :
395 // =======================================================================
396 void OpenGl_Group::SetFlippingOptions (const Standard_Boolean theIsEnabled,
397                                        const gp_Ax2&          theRefPlane)
398 {
399   OpenGl_Flipper* aFlipper = new OpenGl_Flipper (theRefPlane);
400   aFlipper->SetOptions (theIsEnabled);
401   AddElement (aFlipper);
402 }
403
404 // =======================================================================
405 // function : SetStencilTestOptions
406 // purpose  :
407 // =======================================================================
408 void OpenGl_Group::SetStencilTestOptions (const Standard_Boolean theIsEnabled)
409 {
410   OpenGl_StencilTest* aStencilTest = new OpenGl_StencilTest();
411   aStencilTest->SetOptions (theIsEnabled);
412   AddElement (aStencilTest);
413 }
414
415 // =======================================================================
416 // function : AddElement
417 // purpose  :
418 // =======================================================================
419 void OpenGl_Group::AddElement (OpenGl_Element* theElem)
420 {
421   OpenGl_ElementNode *aNode = new OpenGl_ElementNode();
422
423   aNode->elem = theElem;
424   aNode->next = NULL;
425   (myLast? myLast->next : myFirst) = aNode;
426   myLast = aNode;
427
428   if (OpenGl_Raytrace::IsRaytracedElement (aNode))
429   {
430     myIsRaytracable = Standard_True;
431
432     OpenGl_Structure* aStruct = GlStruct();
433     if (aStruct != NULL)
434     {
435       aStruct->UpdateStateIfRaytracable (Standard_False);
436     }
437   }
438 }
439
440 // =======================================================================
441 // function : Render
442 // purpose  :
443 // =======================================================================
444 void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
445 {
446   // Setup aspects
447   theWorkspace->SetAllowFaceCulling (myIsClosed
448                                  && !theWorkspace->GetGlContext()->Clipping().IsClippingOrCappingOn());
449   const OpenGl_AspectLine*   aBackAspectLine   = theWorkspace->AspectLine();
450   const OpenGl_AspectFace*   aBackAspectFace   = theWorkspace->AspectFace();
451   const OpenGl_AspectMarker* aBackAspectMarker = theWorkspace->AspectMarker();
452   const OpenGl_AspectText*   aBackAspectText   = theWorkspace->AspectText();
453   const bool isLineSet   = myAspectLine   && renderFiltered (theWorkspace, myAspectLine);
454   const bool isFaceSet   = myAspectFace   && renderFiltered (theWorkspace, myAspectFace);
455   const bool isMarkerSet = myAspectMarker && renderFiltered (theWorkspace, myAspectMarker);
456   const bool isTextSet   = myAspectText   && renderFiltered (theWorkspace, myAspectText);
457
458   // Render group elements
459   for (OpenGl_ElementNode* aNodeIter = myFirst; aNodeIter != NULL; aNodeIter = aNodeIter->next)
460   {
461     renderFiltered (theWorkspace, aNodeIter->elem);
462   }
463
464   // Restore aspects
465   if (isLineSet)
466     theWorkspace->SetAspectLine (aBackAspectLine);
467   if (isFaceSet)
468     theWorkspace->SetAspectFace (aBackAspectFace);
469   if (isMarkerSet)
470     theWorkspace->SetAspectMarker (aBackAspectMarker);
471   if (isTextSet)
472     theWorkspace->SetAspectText (aBackAspectText);
473 }
474
475 // =======================================================================
476 // function : Clear
477 // purpose  :
478 // =======================================================================
479 void OpenGl_Group::Clear (const Standard_Boolean theToUpdateStructureMgr)
480 {
481   if (IsDeleted())
482   {
483     return;
484   }
485
486   OpenGl_Structure* aStruct = GlStruct();
487   const Handle(OpenGl_Context)& aCtx = aStruct->GlDriver()->GetSharedContext();
488
489   Release (aCtx);
490   Graphic3d_Group::Clear (theToUpdateStructureMgr);
491
492   myIsRaytracable = Standard_False;
493 }
494
495 // =======================================================================
496 // function : Release
497 // purpose  :
498 // =======================================================================
499 void OpenGl_Group::Release (const Handle(OpenGl_Context)& theGlCtx)
500 {
501   // Delete elements
502   while (myFirst != NULL)
503   {
504     OpenGl_ElementNode* aNext = myFirst->next;
505     OpenGl_Element::Destroy (theGlCtx.operator->(), myFirst->elem);
506     delete myFirst;
507     myFirst = aNext;
508   }
509   myLast = NULL;
510
511   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectLine);
512   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectFace);
513   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectMarker);
514   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspectText);
515 }