0027130: Visualization, Ray tracing - skip structures with transformation persistence...
[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 // =======================================================================
33 // function : OpenGl_Group
34 // purpose  :
35 // =======================================================================
36 OpenGl_Group::OpenGl_Group (const Handle(Graphic3d_Structure)& theStruct)
37 : Graphic3d_Group (theStruct),
38   myAspects(NULL),
39   myFirst(NULL),
40   myLast(NULL),
41   myIsRaytracable (Standard_False)
42 {
43   Handle(OpenGl_Structure) aStruct = Handle(OpenGl_Structure)::DownCast (myStructure->CStructure());
44   if (aStruct.IsNull())
45   {
46     throw Graphic3d_GroupDefinitionError("OpenGl_Group should be created by OpenGl_Structure!");
47   }
48 }
49
50 // =======================================================================
51 // function : ~OpenGl_Group
52 // purpose  :
53 // =======================================================================
54 OpenGl_Group::~OpenGl_Group()
55 {
56   Release (Handle(OpenGl_Context)());
57 }
58
59 // =======================================================================
60 // function : SetGroupPrimitivesAspect
61 // purpose  :
62 // =======================================================================
63 void OpenGl_Group::SetGroupPrimitivesAspect (const Handle(Graphic3d_Aspects)& theAspect)
64 {
65   if (IsDeleted())
66   {
67     return;
68   }
69
70   if (myAspects == NULL)
71   {
72     myAspects = new OpenGl_Aspects (theAspect);
73   }
74   else
75   {
76     myAspects->SetAspect (theAspect);
77   }
78
79   if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
80   {
81     aStruct->UpdateStateIfRaytracable (Standard_False);
82   }
83
84   Update();
85 }
86
87 // =======================================================================
88 // function : SetPrimitivesAspect
89 // purpose  :
90 // =======================================================================
91 void OpenGl_Group::SetPrimitivesAspect (const Handle(Graphic3d_Aspects)& theAspect)
92 {
93   if (myAspects == NULL)
94   {
95     SetGroupPrimitivesAspect (theAspect);
96     return;
97   }
98   else if (IsDeleted())
99   {
100     return;
101   }
102
103   OpenGl_Aspects* anAspects = new OpenGl_Aspects (theAspect);
104   AddElement (anAspects);
105   Update();
106 }
107
108 // =======================================================================
109 // function : SynchronizeAspects
110 // purpose  :
111 // =======================================================================
112 void OpenGl_Group::SynchronizeAspects()
113 {
114   if (myAspects != NULL)
115   {
116     myAspects->SynchronizeAspects();
117     if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
118     {
119       aStruct->UpdateStateIfRaytracable (Standard_False);
120     }
121   }
122   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
123   {
124     aNode->elem->SynchronizeAspects();
125   }
126 }
127
128 // =======================================================================
129 // function : ReplaceAspects
130 // purpose  :
131 // =======================================================================
132 void OpenGl_Group::ReplaceAspects (const Graphic3d_MapOfAspectsToAspects& theMap)
133 {
134   if (theMap.IsEmpty())
135   {
136     return;
137   }
138
139   Handle(Graphic3d_Aspects) anAspect;
140   if (myAspects != NULL
141    && theMap.Find (myAspects->Aspect(), anAspect))
142   {
143     myAspects->SetAspect (anAspect);
144     if (OpenGl_Structure* aStruct = myIsRaytracable ? GlStruct() : NULL)
145     {
146       aStruct->UpdateStateIfRaytracable (Standard_False);
147     }
148   }
149   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
150   {
151     OpenGl_Aspects* aGlAspect = dynamic_cast<OpenGl_Aspects*> (aNode->elem);
152     if (aGlAspect != NULL
153      && theMap.Find (aGlAspect->Aspect(), anAspect))
154     {
155       aGlAspect->SetAspect (anAspect);
156     }
157   }
158 }
159
160 // =======================================================================
161 // function : AddPrimitiveArray
162 // purpose  :
163 // =======================================================================
164 void OpenGl_Group::AddPrimitiveArray (const Graphic3d_TypeOfPrimitiveArray theType,
165                                       const Handle(Graphic3d_IndexBuffer)& theIndices,
166                                       const Handle(Graphic3d_Buffer)&      theAttribs,
167                                       const Handle(Graphic3d_BoundBuffer)& theBounds,
168                                       const Standard_Boolean               theToEvalMinMax)
169 {
170   if (IsDeleted()
171    || theAttribs.IsNull())
172   {
173     return;
174   }
175
176   OpenGl_Structure* aStruct = GlStruct();
177   const OpenGl_GraphicDriver* aDriver = aStruct->GlDriver();
178
179   OpenGl_PrimitiveArray* anArray = new OpenGl_PrimitiveArray (aDriver, theType, theIndices, theAttribs, theBounds);
180   AddElement (anArray);
181
182   Graphic3d_Group::AddPrimitiveArray (theType, theIndices, theAttribs, theBounds, theToEvalMinMax);
183 }
184
185 // =======================================================================
186 // function : AddText
187 // purpose  :
188 // =======================================================================
189 void OpenGl_Group::AddText (const Handle(Graphic3d_Text)& theTextParams,
190                             const Standard_Boolean theToEvalMinMax)
191 {
192   if (IsDeleted())
193   {
194     return;
195   }
196
197   if (theTextParams->Height() < 2.0)
198   {
199     // TODO - this should be handled in different way (throw exception / take default text height without modifying Graphic3d_Text / log warning, etc.)
200     OpenGl_Structure* aStruct = GlStruct();
201     theTextParams->SetHeight (aStruct->GlDriver()->DefaultTextHeight());
202   }
203   OpenGl_Text* aText = new OpenGl_Text (theTextParams);
204
205   AddElement (aText);
206   Graphic3d_Group::AddText (theTextParams, theToEvalMinMax);
207 }
208
209 // =======================================================================
210 // function : SetFlippingOptions
211 // purpose  :
212 // =======================================================================
213 void OpenGl_Group::SetFlippingOptions (const Standard_Boolean theIsEnabled,
214                                        const gp_Ax2&          theRefPlane)
215 {
216   OpenGl_Flipper* aFlipper = new OpenGl_Flipper (theRefPlane);
217   aFlipper->SetOptions (theIsEnabled);
218   AddElement (aFlipper);
219 }
220
221 // =======================================================================
222 // function : SetStencilTestOptions
223 // purpose  :
224 // =======================================================================
225 void OpenGl_Group::SetStencilTestOptions (const Standard_Boolean theIsEnabled)
226 {
227   OpenGl_StencilTest* aStencilTest = new OpenGl_StencilTest();
228   aStencilTest->SetOptions (theIsEnabled);
229   AddElement (aStencilTest);
230 }
231
232 // =======================================================================
233 // function : AddElement
234 // purpose  :
235 // =======================================================================
236 void OpenGl_Group::AddElement (OpenGl_Element* theElem)
237 {
238   OpenGl_ElementNode *aNode = new OpenGl_ElementNode();
239
240   aNode->elem = theElem;
241   aNode->next = NULL;
242   (myLast? myLast->next : myFirst) = aNode;
243   myLast = aNode;
244
245   if (OpenGl_Raytrace::IsRaytracedElement (aNode) && !HasPersistence())
246   {
247     myIsRaytracable = Standard_True;
248
249     OpenGl_Structure* aStruct = GlStruct();
250     if (aStruct != NULL)
251     {
252       aStruct->UpdateStateIfRaytracable (Standard_False);
253     }
254   }
255 }
256
257 // =======================================================================
258 // function : renderFiltered
259 // purpose  :
260 // =======================================================================
261 bool OpenGl_Group::renderFiltered (const Handle(OpenGl_Workspace)& theWorkspace,
262                                    OpenGl_Element* theElement) const
263 {
264   if (!theWorkspace->ShouldRender (theElement, this))
265   {
266     return false;
267   }
268
269   theElement->Render (theWorkspace);
270   return true;
271 }
272
273 // =======================================================================
274 // function : Render
275 // purpose  :
276 // =======================================================================
277 void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
278 {
279   // Setup aspects
280   theWorkspace->SetAllowFaceCulling (myIsClosed
281                                  && !theWorkspace->GetGlContext()->Clipping().IsClippingOrCappingOn());
282   const OpenGl_Aspects* aBackAspects = theWorkspace->Aspects();
283   const bool isAspectSet = myAspects != NULL && renderFiltered (theWorkspace, myAspects);
284
285   // Render group elements
286   for (OpenGl_ElementNode* aNodeIter = myFirst; aNodeIter != NULL; aNodeIter = aNodeIter->next)
287   {
288     renderFiltered (theWorkspace, aNodeIter->elem);
289   }
290
291   // Restore aspects
292   if (isAspectSet)
293     theWorkspace->SetAspects (aBackAspects);
294 }
295
296 // =======================================================================
297 // function : Clear
298 // purpose  :
299 // =======================================================================
300 void OpenGl_Group::Clear (const Standard_Boolean theToUpdateStructureMgr)
301 {
302   if (IsDeleted())
303   {
304     return;
305   }
306
307   OpenGl_Structure* aStruct = GlStruct();
308   const Handle(OpenGl_Context)& aCtx = aStruct->GlDriver()->GetSharedContext();
309
310   Release (aCtx);
311   Graphic3d_Group::Clear (theToUpdateStructureMgr);
312
313   myIsRaytracable = Standard_False;
314 }
315
316 // =======================================================================
317 // function : Release
318 // purpose  :
319 // =======================================================================
320 void OpenGl_Group::Release (const Handle(OpenGl_Context)& theGlCtx)
321 {
322   // Delete elements
323   while (myFirst != NULL)
324   {
325     OpenGl_ElementNode* aNext = myFirst->next;
326     OpenGl_Element::Destroy (theGlCtx.get(), myFirst->elem);
327     delete myFirst;
328     myFirst = aNext;
329   }
330   myLast = NULL;
331
332   OpenGl_Element::Destroy (theGlCtx.get(), myAspects);
333 }
334
335 // =======================================================================
336 // function : DumpJson
337 // purpose  :
338 // =======================================================================
339 void OpenGl_Group::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
340 {
341   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
342
343   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Graphic3d_Group)
344
345   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAspects)
346   for (OpenGl_ElementNode* aNode = myFirst; aNode != NULL; aNode = aNode->next)
347   {
348     OpenGl_Element* anElement = aNode->elem;
349     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, anElement)
350   }
351   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsRaytracable)
352 }