0030949: Foundation Classes - Dump improvement for OCCT classes
[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 : AddText
210 // purpose  :
211 // =======================================================================
212 void OpenGl_Group::AddText (const Handle(Graphic3d_Text)& theTextParams,
213                             const Standard_Boolean theToEvalMinMax)
214 {
215   if (IsDeleted())
216   {
217     return;
218   }
219
220   if (theTextParams->Height() < 2.0)
221   {
222     // TODO - this should be handled in different way (throw exception / take default text height without modifying Graphic3d_Text / log warning, etc.)
223     OpenGl_Structure* aStruct = GlStruct();
224     theTextParams->SetHeight (aStruct->GlDriver()->DefaultTextHeight());
225   }
226   OpenGl_Text* aText = new OpenGl_Text (theTextParams);
227
228   AddElement (aText);
229   Graphic3d_Group::AddText (theTextParams, theToEvalMinMax);
230 }
231
232 // =======================================================================
233 // function : SetFlippingOptions
234 // purpose  :
235 // =======================================================================
236 void OpenGl_Group::SetFlippingOptions (const Standard_Boolean theIsEnabled,
237                                        const gp_Ax2&          theRefPlane)
238 {
239   OpenGl_Flipper* aFlipper = new OpenGl_Flipper (theRefPlane);
240   aFlipper->SetOptions (theIsEnabled);
241   AddElement (aFlipper);
242 }
243
244 // =======================================================================
245 // function : SetStencilTestOptions
246 // purpose  :
247 // =======================================================================
248 void OpenGl_Group::SetStencilTestOptions (const Standard_Boolean theIsEnabled)
249 {
250   OpenGl_StencilTest* aStencilTest = new OpenGl_StencilTest();
251   aStencilTest->SetOptions (theIsEnabled);
252   AddElement (aStencilTest);
253 }
254
255 // =======================================================================
256 // function : AddElement
257 // purpose  :
258 // =======================================================================
259 void OpenGl_Group::AddElement (OpenGl_Element* theElem)
260 {
261   OpenGl_ElementNode *aNode = new OpenGl_ElementNode();
262
263   aNode->elem = theElem;
264   aNode->next = NULL;
265   (myLast? myLast->next : myFirst) = aNode;
266   myLast = aNode;
267
268   if (OpenGl_Raytrace::IsRaytracedElement (aNode))
269   {
270     myIsRaytracable = Standard_True;
271
272     OpenGl_Structure* aStruct = GlStruct();
273     if (aStruct != NULL)
274     {
275       aStruct->UpdateStateIfRaytracable (Standard_False);
276     }
277   }
278 }
279
280 // =======================================================================
281 // function : Render
282 // purpose  :
283 // =======================================================================
284 void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
285 {
286   // Setup aspects
287   theWorkspace->SetAllowFaceCulling (myIsClosed
288                                  && !theWorkspace->GetGlContext()->Clipping().IsClippingOrCappingOn());
289   const OpenGl_Aspects* aBackAspects = theWorkspace->Aspects();
290   const bool isAspectSet = myAspects != NULL && renderFiltered (theWorkspace, myAspects);
291
292   // Render group elements
293   for (OpenGl_ElementNode* aNodeIter = myFirst; aNodeIter != NULL; aNodeIter = aNodeIter->next)
294   {
295     renderFiltered (theWorkspace, aNodeIter->elem);
296   }
297
298   // Restore aspects
299   if (isAspectSet)
300     theWorkspace->SetAspects (aBackAspects);
301 }
302
303 // =======================================================================
304 // function : Clear
305 // purpose  :
306 // =======================================================================
307 void OpenGl_Group::Clear (const Standard_Boolean theToUpdateStructureMgr)
308 {
309   if (IsDeleted())
310   {
311     return;
312   }
313
314   OpenGl_Structure* aStruct = GlStruct();
315   const Handle(OpenGl_Context)& aCtx = aStruct->GlDriver()->GetSharedContext();
316
317   Release (aCtx);
318   Graphic3d_Group::Clear (theToUpdateStructureMgr);
319
320   myIsRaytracable = Standard_False;
321 }
322
323 // =======================================================================
324 // function : Release
325 // purpose  :
326 // =======================================================================
327 void OpenGl_Group::Release (const Handle(OpenGl_Context)& theGlCtx)
328 {
329   // Delete elements
330   while (myFirst != NULL)
331   {
332     OpenGl_ElementNode* aNext = myFirst->next;
333     OpenGl_Element::Destroy (theGlCtx.get(), myFirst->elem);
334     delete myFirst;
335     myFirst = aNext;
336   }
337   myLast = NULL;
338
339   OpenGl_Element::Destroy (theGlCtx.get(), myAspects);
340 }
341
342 // =======================================================================
343 // function : DumpJson
344 // purpose  :
345 // =======================================================================
346 void OpenGl_Group::DumpJson (Standard_OStream& theOStream, const Standard_Integer theDepth) const
347 {
348   DUMP_CLASS_BEGIN (theOStream, OpenGl_Group);
349
350   DUMP_FIELD_VALUES_BY_KIND (theOStream, theDepth, Graphic3d_Group);
351   DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAspects);
352   DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsRaytracable);
353 }