4c9fcf6acd86a8f14d709b3d4654c463477d4ce7
[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   myAspects(NULL),
62   myFirst(NULL),
63   myLast(NULL),
64   myIsRaytracable (Standard_False)
65 {
66   Handle(OpenGl_Structure) aStruct = Handle(OpenGl_Structure)::DownCast (myStructure->CStructure());
67   if (aStruct.IsNull())
68   {
69     throw Graphic3d_GroupDefinitionError("OpenGl_Group should be created by OpenGl_Structure!");
70   }
71 }
72
73 // =======================================================================
74 // function : ~OpenGl_Group
75 // purpose  :
76 // =======================================================================
77 OpenGl_Group::~OpenGl_Group()
78 {
79   Release (Handle(OpenGl_Context)());
80 }
81
82 // =======================================================================
83 // function : SetGroupPrimitivesAspect
84 // purpose  :
85 // =======================================================================
86 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_Aspects)& theAspect)
87 {
88   if (IsDeleted())
89   {
90     return;
91   }
92
93   if (myAspects == NULL)
94   {
95     myAspects = new OpenGl_Aspects (theAspect);
96   }
97   else
98   {
99     myAspects->SetAspect (theAspect);
100   }
101
102   if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
103   {
104     aStruct->UpdateStateIfRaytracable (Standard_False);
105   }
106
107   Update();
108 }
109
110 // =======================================================================
111 // function : SetPrimitivesAspect
112 // purpose  :
113 // =======================================================================
114 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_Aspects)& theAspect)
115 {
116   if (myAspects == NULL)
117   {
118     SetGroupPrimitivesAspect (theAspect);
119     return;
120   }
121   else if (IsDeleted())
122   {
123     return;
124   }
125
126   OpenGl_Aspects* anAspects = new OpenGl_Aspects (theAspect);
127   AddElement (anAspects);
128   Update();
129 }
130
131 // =======================================================================
132 // function : SynchronizeAspects
133 // purpose  :
134 // =======================================================================
135 void OpenGl_Group::SynchronizeAspects()
136 {
137   if (myAspects != NULL)
138   {
139     myAspects->SynchronizeAspects();
140     if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
141     {
142       aStruct->UpdateStateIfRaytracable (Standard_False);
143     }
144   }
145   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
146   {
147     aNode->elem->SynchronizeAspects();
148   }
149 }
150
151 // =======================================================================
152 // function : ReplaceAspects
153 // purpose  :
154 // =======================================================================
155 void OpenGl_Group::ReplaceAspects (const Graphic3d_MapOfAspectsToAspects& theMap)
156 {
157   if (theMap.IsEmpty())
158   {
159     return;
160   }
161
162   Handle(Graphic3d_Aspects) anAspect;
163   if (myAspects != NULL
164    && theMap.Find (myAspects->Aspect(), anAspect))
165   {
166     myAspects->SetAspect (anAspect);
167     if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
168     {
169       aStruct->UpdateStateIfRaytracable (Standard_False);
170     }
171   }
172   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
173   {
174     OpenGl_Aspects* aGlAspect = dynamic_cast<OpenGl_Aspects*> (aNode->elem);
175     if (aGlAspect != NULL
176      && theMap.Find (aGlAspect->Aspect(), anAspect))
177     {
178       aGlAspect->SetAspect (anAspect);
179     }
180   }
181 }
182
183 // =======================================================================
184 // function : AddPrimitiveArray
185 // purpose  :
186 // =======================================================================
187 void OpenGl_Group::AddPrimitiveArray (const Graphic3d_TypeOfPrimitiveArray theType,
188                                       const Handle(Graphic3d_IndexBuffer)& theIndices,
189                                       const Handle(Graphic3d_Buffer)&      theAttribs,
190                                       const Handle(Graphic3d_BoundBuffer)& theBounds,
191                                       const Standard_Boolean               theToEvalMinMax)
192 {
193   if (IsDeleted()
194    || theAttribs.IsNull())
195   {
196     return;
197   }
198
199   OpenGl_Structure* aStruct = GlStruct();
200   const OpenGl_GraphicDriver* aDriver = aStruct->GlDriver();
201
202   OpenGl_PrimitiveArray* anArray = new OpenGl_PrimitiveArray (aDriver, theType, theIndices, theAttribs, theBounds);
203   AddElement (anArray);
204
205   Graphic3d_Group::AddPrimitiveArray (theType, theIndices, theAttribs, theBounds, theToEvalMinMax);
206 }
207
208 // =======================================================================
209 // function : Text
210 // purpose  :
211 // =======================================================================
212 void OpenGl_Group::Text (const Standard_CString                  theTextUtf,
213                          const Graphic3d_Vertex&                 thePoint,
214                          const Standard_Real                     theHeight,
215                          const Standard_Real                     theAngle,
216                          const Graphic3d_TextPath                theTp,
217                          const Graphic3d_HorizontalTextAlignment theHta,
218                          const Graphic3d_VerticalTextAlignment   theVta,
219                          const Standard_Boolean                  theToEvalMinMax)
220 {
221   if (IsDeleted())
222   {
223     return;
224   }
225
226   OpenGl_TextParam  aParams;
227   OpenGl_Structure* aStruct = GlStruct();
228   aParams.Height = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
229   aParams.HAlign = theHta;
230   aParams.VAlign = theVta;
231   const OpenGl_Vec3 aPoint (thePoint.X(), thePoint.Y(), thePoint.Z());
232   OpenGl_Text* aText = new OpenGl_Text (theTextUtf, aPoint, aParams);
233   AddElement (aText);
234   Graphic3d_Group::Text (theTextUtf, thePoint, theHeight, theAngle,
235                          theTp, theHta, theVta, theToEvalMinMax);
236 }
237
238 // =======================================================================
239 // function : Text
240 // purpose  :
241 // =======================================================================
242 void OpenGl_Group::Text (const Standard_CString                  theTextUtf,
243                          const gp_Ax2&                           theOrientation,
244                          const Standard_Real                     theHeight,
245                          const Standard_Real                     theAngle,
246                          const Graphic3d_TextPath                theTp,
247                          const Graphic3d_HorizontalTextAlignment theHTA,
248                          const Graphic3d_VerticalTextAlignment   theVTA,
249                          const Standard_Boolean                  theToEvalMinMax,
250                          const Standard_Boolean                  theHasOwnAnchor)
251 {
252   if (IsDeleted())
253   {
254     return;
255   }
256
257   OpenGl_TextParam  aParams;
258   OpenGl_Structure* aStruct = GlStruct();
259
260   aParams.Height      = int ((theHeight < 2.0) ? aStruct->GlDriver()->DefaultTextHeight() : theHeight);
261   aParams.HAlign      = theHTA;
262   aParams.VAlign      = theVTA;
263
264   OpenGl_Text* aText = new OpenGl_Text (theTextUtf, theOrientation, aParams, theHasOwnAnchor != Standard_False);
265
266   AddElement (aText);
267
268   Graphic3d_Group::Text (theTextUtf,
269                          theOrientation,
270                          theHeight,
271                          theAngle,
272                          theTp,
273                          theHTA,
274                          theVTA,
275                          theToEvalMinMax,
276                          theHasOwnAnchor);
277
278 }
279
280 // =======================================================================
281 // function : SetFlippingOptions
282 // purpose  :
283 // =======================================================================
284 void OpenGl_Group::SetFlippingOptions (const Standard_Boolean theIsEnabled,
285                                        const gp_Ax2&          theRefPlane)
286 {
287   OpenGl_Flipper* aFlipper = new OpenGl_Flipper (theRefPlane);
288   aFlipper->SetOptions (theIsEnabled);
289   AddElement (aFlipper);
290 }
291
292 // =======================================================================
293 // function : SetStencilTestOptions
294 // purpose  :
295 // =======================================================================
296 void OpenGl_Group::SetStencilTestOptions (const Standard_Boolean theIsEnabled)
297 {
298   OpenGl_StencilTest* aStencilTest = new OpenGl_StencilTest();
299   aStencilTest->SetOptions (theIsEnabled);
300   AddElement (aStencilTest);
301 }
302
303 // =======================================================================
304 // function : AddElement
305 // purpose  :
306 // =======================================================================
307 void OpenGl_Group::AddElement (OpenGl_Element* theElem)
308 {
309   OpenGl_ElementNode *aNode = new OpenGl_ElementNode();
310
311   aNode->elem = theElem;
312   aNode->next = NULL;
313   (myLast? myLast->next : myFirst) = aNode;
314   myLast = aNode;
315
316   if (OpenGl_Raytrace::IsRaytracedElement (aNode))
317   {
318     myIsRaytracable = Standard_True;
319
320     OpenGl_Structure* aStruct = GlStruct();
321     if (aStruct != NULL)
322     {
323       aStruct->UpdateStateIfRaytracable (Standard_False);
324     }
325   }
326 }
327
328 // =======================================================================
329 // function : Render
330 // purpose  :
331 // =======================================================================
332 void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
333 {
334   // Setup aspects
335   theWorkspace->SetAllowFaceCulling (myIsClosed
336                                  && !theWorkspace->GetGlContext()->Clipping().IsClippingOrCappingOn());
337   const OpenGl_Aspects* aBackAspects = theWorkspace->Aspects();
338   const bool isAspectSet = myAspects != NULL && renderFiltered (theWorkspace, myAspects);
339
340   // Render group elements
341   for (OpenGl_ElementNode* aNodeIter = myFirst; aNodeIter != NULL; aNodeIter = aNodeIter->next)
342   {
343     renderFiltered (theWorkspace, aNodeIter->elem);
344   }
345
346   // Restore aspects
347   if (isAspectSet)
348     theWorkspace->SetAspects (aBackAspects);
349 }
350
351 // =======================================================================
352 // function : Clear
353 // purpose  :
354 // =======================================================================
355 void OpenGl_Group::Clear (const Standard_Boolean theToUpdateStructureMgr)
356 {
357   if (IsDeleted())
358   {
359     return;
360   }
361
362   OpenGl_Structure* aStruct = GlStruct();
363   const Handle(OpenGl_Context)& aCtx = aStruct->GlDriver()->GetSharedContext();
364
365   Release (aCtx);
366   Graphic3d_Group::Clear (theToUpdateStructureMgr);
367
368   myIsRaytracable = Standard_False;
369 }
370
371 // =======================================================================
372 // function : Release
373 // purpose  :
374 // =======================================================================
375 void OpenGl_Group::Release (const Handle(OpenGl_Context)& theGlCtx)
376 {
377   // Delete elements
378   while (myFirst != NULL)
379   {
380     OpenGl_ElementNode* aNext = myFirst->next;
381     OpenGl_Element::Destroy (theGlCtx.operator->(), myFirst->elem);
382     delete myFirst;
383     myFirst = aNext;
384   }
385   myLast = NULL;
386
387   OpenGl_Element::Destroy (theGlCtx.operator->(), myAspects);
388 }