d325cb7f |
1 | // Copyright (c) 2011-2019 OPEN CASCADE SAS |
c5751993 |
2 | // |
3 | // This file is part of Open CASCADE Technology software library. |
4 | // |
0a36ca0a |
5 | // This library is free software; you can redistribute it and/or modify it under |
6 | // the terms of the GNU Lesser General Public License version 2.1 as published |
c5751993 |
7 | // by the Free Software Foundation, with special exception defined in the file |
8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
9 | // distribution for complete text of the license and disclaimer of any warranty. |
10 | // |
11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. |
13 | |
d325cb7f |
14 | #include <Graphic3d_Layer.hxx> |
a1954302 |
15 | |
d325cb7f |
16 | #include <Graphic3d_CStructure.hxx> |
17 | #include <Graphic3d_CullingTool.hxx> |
c5751993 |
18 | |
d325cb7f |
19 | IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Layer, Standard_Transient) |
f5b72419 |
20 | |
a1954302 |
21 | // ======================================================================= |
d325cb7f |
22 | // function : Graphic3d_Layer |
a1954302 |
23 | // purpose : |
24 | // ======================================================================= |
1c728f2d |
25 | Graphic3d_Layer::Graphic3d_Layer (Graphic3d_ZLayerId theId, |
26 | Standard_Integer theNbPriorities, |
d325cb7f |
27 | const Handle(Select3D_BVHBuilder3d)& theBuilder) |
50d06d8f |
28 | : myArray (0, theNbPriorities - 1), |
29 | myNbStructures (0), |
15669413 |
30 | myNbStructuresNotCulled (0), |
1c728f2d |
31 | myLayerId (theId), |
f5b72419 |
32 | myBVHPrimitivesTrsfPers (theBuilder), |
a1954302 |
33 | myBVHIsLeftChildQueuedFirst (Standard_True), |
15669413 |
34 | myIsBVHPrimitivesNeedsReset (Standard_False) |
c5751993 |
35 | { |
50d06d8f |
36 | myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true; |
c5751993 |
37 | } |
38 | |
a1954302 |
39 | // ======================================================================= |
d325cb7f |
40 | // function : ~Graphic3d_Layer |
a1954302 |
41 | // purpose : |
42 | // ======================================================================= |
d325cb7f |
43 | Graphic3d_Layer::~Graphic3d_Layer() |
a1954302 |
44 | { |
45 | // |
46 | } |
47 | |
48 | // ======================================================================= |
49 | // function : Add |
50 | // purpose : |
51 | // ======================================================================= |
d325cb7f |
52 | void Graphic3d_Layer::Add (const Graphic3d_CStructure* theStruct, |
53 | Standard_Integer thePriority, |
54 | Standard_Boolean isForChangePriority) |
a1954302 |
55 | { |
56 | const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1); |
57 | if (theStruct == NULL) |
58 | { |
59 | return; |
60 | } |
61 | |
9f112210 |
62 | myArray (anIndex).Add (theStruct); |
a1954302 |
63 | if (theStruct->IsAlwaysRendered()) |
64 | { |
65 | theStruct->MarkAsNotCulled(); |
3fe9ce0e |
66 | if (!isForChangePriority) |
67 | { |
68 | myAlwaysRenderedMap.Add (theStruct); |
69 | } |
a1954302 |
70 | } |
71 | else if (!isForChangePriority) |
72 | { |
778cd667 |
73 | if (theStruct->TransformPersistence().IsNull()) |
825aa485 |
74 | { |
75 | myBVHPrimitives.Add (theStruct); |
76 | } |
77 | else |
78 | { |
79 | myBVHPrimitivesTrsfPers.Add (theStruct); |
80 | } |
a1954302 |
81 | } |
82 | ++myNbStructures; |
83 | } |
84 | |
85 | // ======================================================================= |
86 | // function : Remove |
87 | // purpose : |
88 | // ======================================================================= |
d325cb7f |
89 | bool Graphic3d_Layer::Remove (const Graphic3d_CStructure* theStruct, |
90 | Standard_Integer& thePriority, |
91 | Standard_Boolean isForChangePriority) |
a1954302 |
92 | { |
93 | if (theStruct == NULL) |
94 | { |
95 | thePriority = -1; |
96 | return false; |
97 | } |
98 | |
99 | const Standard_Integer aNbPriorities = myArray.Length(); |
100 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
101 | { |
d325cb7f |
102 | Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); |
9f112210 |
103 | const Standard_Integer anIndex = aStructures.FindIndex (theStruct); |
d325cb7f |
104 | if (anIndex == 0) |
a1954302 |
105 | { |
d325cb7f |
106 | continue; |
107 | } |
108 | |
109 | aStructures.Swap (anIndex, aStructures.Size()); |
110 | aStructures.RemoveLast(); |
9f112210 |
111 | |
d325cb7f |
112 | if (!isForChangePriority) |
113 | { |
114 | Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered(); |
115 | if (!isAlwaysRend) |
a1954302 |
116 | { |
d325cb7f |
117 | if (!myBVHPrimitives.Remove (theStruct)) |
825aa485 |
118 | { |
d325cb7f |
119 | if (!myBVHPrimitivesTrsfPers.Remove (theStruct)) |
3fe9ce0e |
120 | { |
d325cb7f |
121 | isAlwaysRend = Standard_True; |
3fe9ce0e |
122 | } |
123 | } |
d325cb7f |
124 | } |
125 | if (isAlwaysRend) |
126 | { |
127 | const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct); |
128 | if (anIndex2 != 0) |
3fe9ce0e |
129 | { |
d325cb7f |
130 | myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2); |
131 | myAlwaysRenderedMap.RemoveLast(); |
825aa485 |
132 | } |
a1954302 |
133 | } |
134 | } |
d325cb7f |
135 | --myNbStructures; |
136 | thePriority = aPriorityIter; |
137 | return true; |
a1954302 |
138 | } |
139 | |
140 | thePriority = -1; |
141 | return false; |
142 | } |
143 | |
144 | // ======================================================================= |
145 | // function : InvalidateBVHData |
146 | // purpose : |
147 | // ======================================================================= |
d325cb7f |
148 | void Graphic3d_Layer::InvalidateBVHData() |
a1954302 |
149 | { |
150 | myIsBVHPrimitivesNeedsReset = Standard_True; |
151 | } |
152 | |
3fe9ce0e |
153 | //! Calculate a finite bounding box of infinite object as its middle point. |
7c3ef2f7 |
154 | inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
155 | { |
156 | // bounding borders of infinite line has been calculated as own point in center of this line |
7c3ef2f7 |
157 | const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin(); |
158 | return aDiagVec.SquareModulus() >= 500000.0 * 500000.0 |
159 | ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5) |
160 | : Graphic3d_BndBox3d(); |
3fe9ce0e |
161 | } |
162 | |
163 | //! Return true if at least one vertex coordinate out of float range. |
7c3ef2f7 |
164 | inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
165 | { |
166 | return Abs (theBndBox.CornerMax().x()) >= ShortRealLast() |
167 | || Abs (theBndBox.CornerMax().y()) >= ShortRealLast() |
168 | || Abs (theBndBox.CornerMax().z()) >= ShortRealLast() |
169 | || Abs (theBndBox.CornerMin().x()) >= ShortRealLast() |
170 | || Abs (theBndBox.CornerMin().y()) >= ShortRealLast() |
171 | || Abs (theBndBox.CornerMin().z()) >= ShortRealLast(); |
172 | } |
173 | |
a1954302 |
174 | // ======================================================================= |
50d06d8f |
175 | // function : BoundingBox |
176 | // purpose : |
177 | // ======================================================================= |
d325cb7f |
178 | Bnd_Box Graphic3d_Layer::BoundingBox (Standard_Integer theViewId, |
179 | const Handle(Graphic3d_Camera)& theCamera, |
180 | Standard_Integer theWindowWidth, |
181 | Standard_Integer theWindowHeight, |
182 | Standard_Boolean theToIncludeAuxiliary) const |
50d06d8f |
183 | { |
150ed3d5 |
184 | updateBVH(); |
185 | |
3fe9ce0e |
186 | const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1; |
7c3ef2f7 |
187 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
188 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
189 | if (myIsBoundingBoxNeedsReset[aBoxId]) |
190 | { |
191 | // Recompute layer bounding box |
7c3ef2f7 |
192 | myBoundingBox[aBoxId].SetVoid(); |
50d06d8f |
193 | |
d325cb7f |
194 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
195 | { |
d325cb7f |
196 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
197 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
198 | { |
d325cb7f |
199 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
200 | if (!aStructure->IsVisible (theViewId)) |
50d06d8f |
201 | { |
202 | continue; |
203 | } |
204 | |
205 | // "FitAll" operation ignores object with transform persistence parameter |
206 | // but adds transform persistence point in a bounding box of layer (only zoom pers. objects). |
778cd667 |
207 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
208 | { |
3fe9ce0e |
209 | if (!theToIncludeAuxiliary |
778cd667 |
210 | && aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
211 | { |
778cd667 |
212 | const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint(); |
7c3ef2f7 |
213 | myBoundingBox[aBoxId].Add (anAnchor); |
50d06d8f |
214 | continue; |
215 | } |
216 | // Panning and 2d persistence apply changes to projection or/and its translation components. |
217 | // It makes them incompatible with z-fitting algorithm. Ignored by now. |
3fe9ce0e |
218 | else if (!theToIncludeAuxiliary |
778cd667 |
219 | || aStructure->TransformPersistence()->IsTrihedronOr2d()) |
50d06d8f |
220 | { |
221 | continue; |
222 | } |
223 | } |
224 | |
7c3ef2f7 |
225 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
226 | if (!aBox.IsValid()) |
227 | { |
228 | continue; |
229 | } |
50d06d8f |
230 | |
231 | if (aStructure->IsInfinite |
3fe9ce0e |
232 | && !theToIncludeAuxiliary) |
50d06d8f |
233 | { |
3fe9ce0e |
234 | // include center of infinite object |
235 | aBox = centerOfinfiniteBndBox (aBox); |
50d06d8f |
236 | } |
237 | |
778cd667 |
238 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
239 | { |
778cd667 |
240 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
241 | } |
242 | |
3fe9ce0e |
243 | // skip too big boxes to prevent float overflow at camera parameters calculation |
7c3ef2f7 |
244 | if (aBox.IsValid() |
245 | && !isInfiniteBndBox (aBox)) |
50d06d8f |
246 | { |
7c3ef2f7 |
247 | myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z())); |
248 | myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z())); |
50d06d8f |
249 | } |
50d06d8f |
250 | } |
251 | } |
252 | |
253 | myIsBoundingBoxNeedsReset[aBoxId] = false; |
254 | } |
255 | |
7c3ef2f7 |
256 | Bnd_Box aResBox = myBoundingBox[aBoxId]; |
3fe9ce0e |
257 | if (!theToIncludeAuxiliary |
258 | || myAlwaysRenderedMap.IsEmpty()) |
259 | { |
7c3ef2f7 |
260 | return aResBox; |
3fe9ce0e |
261 | } |
262 | |
263 | // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit |
d325cb7f |
264 | for (NCollection_IndexedMap<const Graphic3d_CStructure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next()) |
3fe9ce0e |
265 | { |
d325cb7f |
266 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
267 | if (!aStructure->IsVisible (theViewId)) |
268 | { |
269 | continue; |
270 | } |
778cd667 |
271 | else if (aStructure->TransformPersistence().IsNull() |
272 | || !aStructure->TransformPersistence()->IsTrihedronOr2d()) |
3fe9ce0e |
273 | { |
274 | continue; |
275 | } |
276 | |
7c3ef2f7 |
277 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
278 | if (!aBox.IsValid()) |
279 | { |
280 | continue; |
281 | } |
282 | |
778cd667 |
283 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
7c3ef2f7 |
284 | if (aBox.IsValid() |
285 | && !isInfiniteBndBox (aBox)) |
3fe9ce0e |
286 | { |
7c3ef2f7 |
287 | aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z())); |
288 | aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z())); |
3fe9ce0e |
289 | } |
290 | } |
291 | |
292 | return aResBox; |
50d06d8f |
293 | } |
294 | |
295 | // ======================================================================= |
296 | // function : considerZoomPersistenceObjects |
297 | // purpose : |
298 | // ======================================================================= |
d325cb7f |
299 | Standard_Real Graphic3d_Layer::considerZoomPersistenceObjects (Standard_Integer theViewId, |
300 | const Handle(Graphic3d_Camera)& theCamera, |
301 | Standard_Integer theWindowWidth, |
302 | Standard_Integer theWindowHeight) const |
50d06d8f |
303 | { |
304 | if (NbOfTransformPersistenceObjects() == 0) |
305 | { |
306 | return 1.0; |
307 | } |
308 | |
7c3ef2f7 |
309 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
310 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
311 | Standard_Real aMaxCoef = -std::numeric_limits<double>::max(); |
312 | |
d325cb7f |
313 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
314 | { |
d325cb7f |
315 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
316 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
317 | { |
d325cb7f |
318 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
3fe9ce0e |
319 | if (!aStructure->IsVisible (theViewId) |
778cd667 |
320 | || aStructure->TransformPersistence().IsNull() |
321 | || !aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
322 | { |
323 | continue; |
324 | } |
325 | |
7c3ef2f7 |
326 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
327 | if (!aBox.IsValid()) |
50d06d8f |
328 | { |
329 | continue; |
330 | } |
331 | |
778cd667 |
332 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
333 | |
7c3ef2f7 |
334 | const BVH_Vec3d& aCornerMin = aBox.CornerMin(); |
335 | const BVH_Vec3d& aCornerMax = aBox.CornerMax(); |
50d06d8f |
336 | const Standard_Integer aNbOfPoints = 8; |
337 | const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()), |
338 | gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()), |
339 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()), |
340 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()), |
341 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()), |
342 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()), |
343 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()), |
344 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) }; |
345 | gp_Pnt aConvertedPoints[aNbOfPoints]; |
346 | Standard_Real aConvertedMinX = std::numeric_limits<double>::max(); |
347 | Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max(); |
348 | Standard_Real aConvertedMinY = std::numeric_limits<double>::max(); |
349 | Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max(); |
350 | for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx) |
351 | { |
352 | aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]); |
353 | |
354 | aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X()); |
355 | aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X()); |
356 | |
357 | aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y()); |
358 | aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y()); |
359 | } |
360 | |
361 | const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window |
362 | || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window |
363 | const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0) |
364 | && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0) |
365 | && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0) |
366 | && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0); |
367 | if (isBigObject || isAlreadyInScreen) |
368 | { |
369 | continue; |
370 | } |
371 | |
778cd667 |
372 | const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint(); |
50d06d8f |
373 | gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint); |
374 | aConvertedTPPoint.SetZ (0.0); |
375 | |
376 | if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion()) |
377 | { |
378 | continue; |
379 | } |
380 | |
381 | Standard_Real aShiftX = 0.0; |
382 | if (aConvertedMinX < -1.0) |
383 | { |
384 | aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX)); |
385 | } |
386 | else if (aConvertedMaxX > 1.0) |
387 | { |
388 | aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0)); |
389 | } |
390 | |
391 | Standard_Real aShiftY = 0.0; |
392 | if (aConvertedMinY < -1.0) |
393 | { |
394 | aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY)); |
395 | } |
396 | else if (aConvertedMaxY > 1.0) |
397 | { |
398 | aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0)); |
399 | } |
400 | |
401 | const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX; |
402 | const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY; |
403 | if (aDifX > Precision::Confusion()) |
404 | { |
405 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX); |
406 | } |
407 | if (aDifY > Precision::Confusion()) |
408 | { |
409 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY); |
410 | } |
411 | } |
412 | } |
413 | |
414 | return (aMaxCoef > 0.0) ? aMaxCoef : 1.0; |
415 | } |
416 | |
a1954302 |
417 | // ======================================================================= |
3fe9ce0e |
418 | // function : updateBVH |
a1954302 |
419 | // purpose : |
420 | // ======================================================================= |
d325cb7f |
421 | void Graphic3d_Layer::updateBVH() const |
a1954302 |
422 | { |
3fe9ce0e |
423 | if (!myIsBVHPrimitivesNeedsReset) |
424 | { |
425 | return; |
426 | } |
427 | |
428 | myBVHPrimitives.Clear(); |
429 | myBVHPrimitivesTrsfPers.Clear(); |
150ed3d5 |
430 | myAlwaysRenderedMap.Clear(); |
3fe9ce0e |
431 | myIsBVHPrimitivesNeedsReset = Standard_False; |
d325cb7f |
432 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
a1954302 |
433 | { |
d325cb7f |
434 | const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
435 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
825aa485 |
436 | { |
d325cb7f |
437 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
3fe9ce0e |
438 | if (aStruct->IsAlwaysRendered()) |
825aa485 |
439 | { |
150ed3d5 |
440 | aStruct->MarkAsNotCulled(); |
441 | myAlwaysRenderedMap.Add (aStruct); |
3fe9ce0e |
442 | } |
778cd667 |
443 | else if (aStruct->TransformPersistence().IsNull()) |
3fe9ce0e |
444 | { |
445 | myBVHPrimitives.Add (aStruct); |
446 | } |
447 | else |
448 | { |
449 | myBVHPrimitivesTrsfPers.Add (aStruct); |
825aa485 |
450 | } |
451 | } |
a1954302 |
452 | } |
3fe9ce0e |
453 | } |
454 | |
9ad4ff93 |
455 | namespace |
456 | { |
457 | //! This structure describes the node in BVH |
458 | struct NodeInStack |
459 | { |
460 | NodeInStack (Standard_Integer theId = 0, |
461 | Standard_Boolean theIsFullInside = false) : Id (theId), IsFullInside (theIsFullInside) {} |
462 | |
463 | Standard_Integer Id; //!< node identifier |
464 | Standard_Boolean IsFullInside; //!< if the node is completely inside |
465 | }; |
466 | } |
467 | |
3fe9ce0e |
468 | // ======================================================================= |
2b8832bb |
469 | // function : UpdateCulling |
3fe9ce0e |
470 | // purpose : |
471 | // ======================================================================= |
d325cb7f |
472 | void Graphic3d_Layer::UpdateCulling (Standard_Integer theViewId, |
473 | const Graphic3d_CullingTool& theSelector, |
474 | const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState) |
3fe9ce0e |
475 | { |
476 | updateBVH(); |
a1954302 |
477 | |
15669413 |
478 | myNbStructuresNotCulled = myNbStructures; |
0e3025bc |
479 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate) |
a1954302 |
480 | { |
d325cb7f |
481 | Standard_Boolean toTraverse = (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On); |
482 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next()) |
0e3025bc |
483 | { |
d325cb7f |
484 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
0e3025bc |
485 | aStruct->SetCulled (toTraverse); |
486 | } |
d325cb7f |
487 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next()) |
0e3025bc |
488 | { |
d325cb7f |
489 | const Graphic3d_CStructure* aStruct = aStructIter.Value(); |
0e3025bc |
490 | aStruct->SetCulled (toTraverse); |
491 | } |
a1954302 |
492 | } |
a1954302 |
493 | |
0e3025bc |
494 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On) |
2b8832bb |
495 | { |
496 | return; |
497 | } |
498 | if (myBVHPrimitives .Size() == 0 |
499 | && myBVHPrimitivesTrsfPers.Size() == 0) |
500 | { |
501 | return; |
502 | } |
503 | |
15669413 |
504 | myNbStructuresNotCulled = myAlwaysRenderedMap.Extent(); |
d325cb7f |
505 | Graphic3d_CullingTool::CullingContext aCullCtx; |
2b8832bb |
506 | theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance()); |
507 | theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize()); |
825aa485 |
508 | for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx) |
a1954302 |
509 | { |
825aa485 |
510 | const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1; |
2b8832bb |
511 | opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree; |
825aa485 |
512 | if (isTrsfPers) |
a1954302 |
513 | { |
825aa485 |
514 | if (myBVHPrimitivesTrsfPers.Size() == 0) |
825aa485 |
515 | continue; |
97f937cc |
516 | |
d325cb7f |
517 | const Graphic3d_Mat4d& aProjection = theSelector.ProjectionMatrix(); |
518 | const Graphic3d_Mat4d& aWorldView = theSelector.WorldViewMatrix(); |
825aa485 |
519 | const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState(); |
91d96372 |
520 | const Standard_Integer aViewportWidth = theSelector.ViewportWidth(); |
521 | const Standard_Integer aViewportHeight = theSelector.ViewportHeight(); |
522 | |
3fe9ce0e |
523 | aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState); |
825aa485 |
524 | } |
525 | else |
526 | { |
527 | if (myBVHPrimitives.Size() == 0) |
825aa485 |
528 | continue; |
97f937cc |
529 | |
825aa485 |
530 | aBVHTree = myBVHPrimitives.BVH(); |
531 | } |
532 | |
9ad4ff93 |
533 | const bool toCheckFullInside = true; |
534 | NodeInStack aNode (0, toCheckFullInside); // a root node |
535 | if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0), toCheckFullInside ? &aNode.IsFullInside : NULL)) |
825aa485 |
536 | { |
537 | continue; |
538 | } |
539 | |
9ad4ff93 |
540 | NodeInStack aStack[BVH_Constants_MaxTreeDepth]; |
825aa485 |
541 | Standard_Integer aHead = -1; |
542 | for (;;) |
543 | { |
9ad4ff93 |
544 | if (!aBVHTree->IsOuter (aNode.Id)) |
a1954302 |
545 | { |
9ad4ff93 |
546 | NodeInStack aLeft (aBVHTree->Child<0> (aNode.Id), toCheckFullInside); |
547 | NodeInStack aRight(aBVHTree->Child<1> (aNode.Id), toCheckFullInside); |
548 | bool isLeftChildIn = true, isRightChildIn = true; |
549 | if (aNode.IsFullInside) |
550 | { |
551 | // small size should be always checked |
552 | isLeftChildIn = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aLeft.Id), aBVHTree->MaxPoint (aLeft.Id)); |
553 | isRightChildIn = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id)); |
554 | } |
555 | else |
556 | { |
557 | isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeft.Id), aBVHTree->MaxPoint (aLeft.Id), toCheckFullInside ? &aLeft.IsFullInside : NULL); |
558 | if (!isLeftChildIn) |
559 | { |
560 | aLeft.IsFullInside = false; |
561 | } |
562 | |
563 | isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id), toCheckFullInside ? &aRight.IsFullInside : NULL); |
564 | if (!isRightChildIn) |
565 | { |
566 | aRight.IsFullInside = false; |
567 | } |
568 | } |
569 | |
825aa485 |
570 | if (isLeftChildIn |
571 | && isRightChildIn) |
572 | { |
9ad4ff93 |
573 | aNode = myBVHIsLeftChildQueuedFirst ? aLeft : aRight; |
574 | aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRight : aLeft; |
825aa485 |
575 | myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst; |
576 | } |
577 | else if (isLeftChildIn |
578 | || isRightChildIn) |
579 | { |
9ad4ff93 |
580 | aNode = isLeftChildIn ? aLeft : aRight; |
825aa485 |
581 | } |
582 | else |
583 | { |
584 | if (aHead < 0) |
585 | { |
586 | break; |
587 | } |
588 | |
589 | aNode = aStack[aHead--]; |
590 | } |
a1954302 |
591 | } |
592 | else |
593 | { |
9ad4ff93 |
594 | const Standard_Integer aStartIdx = aBVHTree->BegPrimitive (aNode.Id); |
595 | const Standard_Integer anEndIdx = aBVHTree->EndPrimitive (aNode.Id); |
a2803f37 |
596 | for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx) |
5dc0517d |
597 | { |
a2803f37 |
598 | const Graphic3d_CStructure* aStruct = isTrsfPers |
599 | ? myBVHPrimitivesTrsfPers.GetStructureById (anIdx) |
600 | : myBVHPrimitives.GetStructureById (anIdx); |
601 | if (aStruct->IsVisible (theViewId)) |
602 | { |
603 | aStruct->MarkAsNotCulled(); |
604 | ++myNbStructuresNotCulled; |
605 | } |
5dc0517d |
606 | } |
a1954302 |
607 | if (aHead < 0) |
608 | { |
825aa485 |
609 | break; |
a1954302 |
610 | } |
611 | |
14a35e5d |
612 | aNode = aStack[aHead--]; |
a1954302 |
613 | } |
614 | } |
a1954302 |
615 | } |
616 | } |
617 | |
618 | // ======================================================================= |
619 | // function : Append |
620 | // purpose : |
621 | // ======================================================================= |
d325cb7f |
622 | Standard_Boolean Graphic3d_Layer::Append (const Graphic3d_Layer& theOther) |
a1954302 |
623 | { |
624 | // the source priority list shouldn't have more priorities |
625 | const Standard_Integer aNbPriorities = theOther.NbPriorities(); |
626 | if (aNbPriorities > NbPriorities()) |
627 | { |
628 | return Standard_False; |
629 | } |
630 | |
631 | // add all structures to destination priority list |
632 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
633 | { |
d325cb7f |
634 | const Graphic3d_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter); |
635 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
a1954302 |
636 | { |
7c3ef2f7 |
637 | Add (aStructIter.Value(), aPriorityIter); |
a1954302 |
638 | } |
639 | } |
640 | |
641 | return Standard_True; |
642 | } |
643 | |
7c3ef2f7 |
644 | //======================================================================= |
645 | //function : SetLayerSettings |
646 | //purpose : |
647 | //======================================================================= |
d325cb7f |
648 | void Graphic3d_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings) |
7c3ef2f7 |
649 | { |
650 | const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution()); |
651 | myLayerSettings = theSettings; |
d325cb7f |
652 | if (!toUpdateTrsf) |
7c3ef2f7 |
653 | { |
d325cb7f |
654 | return; |
7c3ef2f7 |
655 | } |
656 | |
d325cb7f |
657 | for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
83da37b1 |
658 | { |
d325cb7f |
659 | Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue(); |
660 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
661 | { |
662 | Graphic3d_CStructure* aStructure = const_cast<Graphic3d_CStructure* >(aStructIter.Value()); |
663 | aStructure->updateLayerTransformation(); |
664 | } |
83da37b1 |
665 | } |
c5751993 |
666 | } |
bc73b006 |
667 | |
668 | // ======================================================================= |
669 | // function : DumpJson |
670 | // purpose : |
671 | // ======================================================================= |
672 | void Graphic3d_Layer::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const |
673 | { |
674 | OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream) |
675 | |
676 | OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, this) |
677 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLayerId) |
678 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructures) |
679 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructuresNotCulled) |
680 | |
681 | const Standard_Integer aNbPriorities = myArray.Length(); |
682 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
683 | { |
684 | const Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); |
685 | for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
686 | { |
687 | const Graphic3d_CStructure* aStructure = aStructIter.Value(); |
688 | OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, aStructure) |
689 | } |
690 | } |
691 | |
692 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myLayerSettings) |
693 | |
694 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myBVHIsLeftChildQueuedFirst) |
695 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBVHPrimitivesNeedsReset) |
696 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[0]) |
697 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[1]) |
698 | |
699 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[0]) |
700 | OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[1]) |
701 | } |