0029365: Visualization, TKOpenGl - do not include hidden structures to Rendered withi...
[occt.git] / src / OpenGl / OpenGl_Layer.cxx
CommitLineData
c5751993 1// Created on: 2014-03-31
2// Created by: Danila ULYANOV
3// Copyright (c) 2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
0a36ca0a 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
c5751993 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_Layer.hxx>
a1954302 17
18#include <OpenGl_BVHTreeSelector.hxx>
19#include <OpenGl_Structure.hxx>
7c3ef2f7 20#include <OpenGl_ShaderManager.hxx>
a1954302 21#include <OpenGl_View.hxx>
550f3b8b 22#include <OpenGl_Workspace.hxx>
c04c30b3 23#include <Graphic3d_GraphicDriver.hxx>
c5751993 24
f5b72419 25IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Layer, Standard_Transient)
26
a1954302 27// =======================================================================
825aa485 28// function : OpenGl_Layer
a1954302 29// purpose :
30// =======================================================================
f5b72419 31OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities,
32 const Handle(Select3D_BVHBuilder3d)& theBuilder)
50d06d8f 33: myArray (0, theNbPriorities - 1),
34 myNbStructures (0),
15669413 35 myNbStructuresNotCulled (0),
f5b72419 36 myBVHPrimitivesTrsfPers (theBuilder),
a1954302 37 myBVHIsLeftChildQueuedFirst (Standard_True),
15669413 38 myIsBVHPrimitivesNeedsReset (Standard_False)
c5751993 39{
50d06d8f 40 myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
c5751993 41}
42
a1954302 43// =======================================================================
44// function : ~OpenGl_Layer
45// purpose :
46// =======================================================================
47OpenGl_Layer::~OpenGl_Layer()
48{
49 //
50}
51
52// =======================================================================
53// function : Add
54// purpose :
55// =======================================================================
56void OpenGl_Layer::Add (const OpenGl_Structure* theStruct,
57 const Standard_Integer thePriority,
58 Standard_Boolean isForChangePriority)
59{
60 const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
61 if (theStruct == NULL)
62 {
63 return;
64 }
65
9f112210 66 myArray (anIndex).Add (theStruct);
a1954302 67 if (theStruct->IsAlwaysRendered())
68 {
69 theStruct->MarkAsNotCulled();
3fe9ce0e 70 if (!isForChangePriority)
71 {
72 myAlwaysRenderedMap.Add (theStruct);
73 }
a1954302 74 }
75 else if (!isForChangePriority)
76 {
778cd667 77 if (theStruct->TransformPersistence().IsNull())
825aa485 78 {
79 myBVHPrimitives.Add (theStruct);
80 }
81 else
82 {
83 myBVHPrimitivesTrsfPers.Add (theStruct);
84 }
a1954302 85 }
86 ++myNbStructures;
87}
88
89// =======================================================================
90// function : Remove
91// purpose :
92// =======================================================================
93bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
94 Standard_Integer& thePriority,
95 Standard_Boolean isForChangePriority)
96{
97 if (theStruct == NULL)
98 {
99 thePriority = -1;
100 return false;
101 }
102
103 const Standard_Integer aNbPriorities = myArray.Length();
104 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
105 {
9f112210 106 OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
107
108 const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
109 if (anIndex != 0)
a1954302 110 {
9f112210 111 aStructures.Swap (anIndex, aStructures.Size());
112 aStructures.RemoveLast();
113
3fe9ce0e 114 if (!isForChangePriority)
a1954302 115 {
ef9a9362 116 Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered();
117 if (!isAlwaysRend)
825aa485 118 {
ef9a9362 119 if (!myBVHPrimitives.Remove (theStruct))
3fe9ce0e 120 {
ef9a9362 121 if (!myBVHPrimitivesTrsfPers.Remove (theStruct))
122 {
123 isAlwaysRend = Standard_True;
124 }
3fe9ce0e 125 }
126 }
ef9a9362 127 if (isAlwaysRend)
3fe9ce0e 128 {
ef9a9362 129 const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
130 if (anIndex2 != 0)
3fe9ce0e 131 {
ef9a9362 132 myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
133 myAlwaysRenderedMap.RemoveLast();
3fe9ce0e 134 }
825aa485 135 }
a1954302 136 }
9f112210 137 --myNbStructures;
138 thePriority = aPriorityIter;
139 return true;
a1954302 140 }
141 }
142
143 thePriority = -1;
144 return false;
145}
146
147// =======================================================================
148// function : InvalidateBVHData
149// purpose :
150// =======================================================================
2b8832bb 151void OpenGl_Layer::InvalidateBVHData()
a1954302 152{
153 myIsBVHPrimitivesNeedsReset = Standard_True;
154}
155
3fe9ce0e 156//! Calculate a finite bounding box of infinite object as its middle point.
7c3ef2f7 157inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
3fe9ce0e 158{
159 // bounding borders of infinite line has been calculated as own point in center of this line
7c3ef2f7 160 const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
161 return aDiagVec.SquareModulus() >= 500000.0 * 500000.0
162 ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5)
163 : Graphic3d_BndBox3d();
3fe9ce0e 164}
165
166//! Return true if at least one vertex coordinate out of float range.
7c3ef2f7 167inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
3fe9ce0e 168{
169 return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
170 || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
171 || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
172 || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
173 || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
174 || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
175}
176
a1954302 177// =======================================================================
50d06d8f 178// function : BoundingBox
179// purpose :
180// =======================================================================
7c3ef2f7 181Bnd_Box OpenGl_Layer::BoundingBox (const Standard_Integer theViewId,
182 const Handle(Graphic3d_Camera)& theCamera,
183 const Standard_Integer theWindowWidth,
184 const Standard_Integer theWindowHeight,
185 const Standard_Boolean theToIncludeAuxiliary) const
50d06d8f 186{
150ed3d5 187 updateBVH();
188
3fe9ce0e 189 const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
7c3ef2f7 190 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
191 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
50d06d8f 192 if (myIsBoundingBoxNeedsReset[aBoxId])
193 {
194 // Recompute layer bounding box
7c3ef2f7 195 myBoundingBox[aBoxId].SetVoid();
50d06d8f 196
7c3ef2f7 197 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
50d06d8f 198 {
7c3ef2f7 199 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
200 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
50d06d8f 201 {
7c3ef2f7 202 const OpenGl_Structure* aStructure = aStructIter.Value();
3fe9ce0e 203 if (!aStructure->IsVisible (theViewId))
50d06d8f 204 {
205 continue;
206 }
207
208 // "FitAll" operation ignores object with transform persistence parameter
209 // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
778cd667 210 if (!aStructure->TransformPersistence().IsNull())
50d06d8f 211 {
3fe9ce0e 212 if (!theToIncludeAuxiliary
778cd667 213 && aStructure->TransformPersistence()->IsZoomOrRotate())
50d06d8f 214 {
778cd667 215 const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint();
7c3ef2f7 216 myBoundingBox[aBoxId].Add (anAnchor);
50d06d8f 217 continue;
218 }
219 // Panning and 2d persistence apply changes to projection or/and its translation components.
220 // It makes them incompatible with z-fitting algorithm. Ignored by now.
3fe9ce0e 221 else if (!theToIncludeAuxiliary
778cd667 222 || aStructure->TransformPersistence()->IsTrihedronOr2d())
50d06d8f 223 {
224 continue;
225 }
226 }
227
7c3ef2f7 228 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
3fe9ce0e 229 if (!aBox.IsValid())
230 {
231 continue;
232 }
50d06d8f 233
234 if (aStructure->IsInfinite
3fe9ce0e 235 && !theToIncludeAuxiliary)
50d06d8f 236 {
3fe9ce0e 237 // include center of infinite object
238 aBox = centerOfinfiniteBndBox (aBox);
50d06d8f 239 }
240
778cd667 241 if (!aStructure->TransformPersistence().IsNull())
50d06d8f 242 {
778cd667 243 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
50d06d8f 244 }
245
3fe9ce0e 246 // skip too big boxes to prevent float overflow at camera parameters calculation
7c3ef2f7 247 if (aBox.IsValid()
248 && !isInfiniteBndBox (aBox))
50d06d8f 249 {
7c3ef2f7 250 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
251 myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
50d06d8f 252 }
50d06d8f 253 }
254 }
255
256 myIsBoundingBoxNeedsReset[aBoxId] = false;
257 }
258
7c3ef2f7 259 Bnd_Box aResBox = myBoundingBox[aBoxId];
3fe9ce0e 260 if (!theToIncludeAuxiliary
261 || myAlwaysRenderedMap.IsEmpty())
262 {
7c3ef2f7 263 return aResBox;
3fe9ce0e 264 }
265
266 // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
3fe9ce0e 267 for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
268 {
269 const OpenGl_Structure* aStructure = aStructIter.Value();
270 if (!aStructure->IsVisible (theViewId))
271 {
272 continue;
273 }
778cd667 274 else if (aStructure->TransformPersistence().IsNull()
275 || !aStructure->TransformPersistence()->IsTrihedronOr2d())
3fe9ce0e 276 {
277 continue;
278 }
279
7c3ef2f7 280 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
3fe9ce0e 281 if (!aBox.IsValid())
282 {
283 continue;
284 }
285
778cd667 286 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
7c3ef2f7 287 if (aBox.IsValid()
288 && !isInfiniteBndBox (aBox))
3fe9ce0e 289 {
7c3ef2f7 290 aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
291 aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
3fe9ce0e 292 }
293 }
294
295 return aResBox;
50d06d8f 296}
297
298// =======================================================================
299// function : considerZoomPersistenceObjects
300// purpose :
301// =======================================================================
302Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer theViewId,
303 const Handle(Graphic3d_Camera)& theCamera,
304 Standard_Integer theWindowWidth,
3fe9ce0e 305 Standard_Integer theWindowHeight) const
50d06d8f 306{
307 if (NbOfTransformPersistenceObjects() == 0)
308 {
309 return 1.0;
310 }
311
7c3ef2f7 312 const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
313 const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix();
50d06d8f 314 Standard_Real aMaxCoef = -std::numeric_limits<double>::max();
315
7c3ef2f7 316 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
50d06d8f 317 {
7c3ef2f7 318 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
319 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
50d06d8f 320 {
7c3ef2f7 321 const OpenGl_Structure* aStructure = aStructIter.Value();
3fe9ce0e 322 if (!aStructure->IsVisible (theViewId)
778cd667 323 || aStructure->TransformPersistence().IsNull()
324 || !aStructure->TransformPersistence()->IsZoomOrRotate())
50d06d8f 325 {
326 continue;
327 }
328
7c3ef2f7 329 Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
3fe9ce0e 330 if (!aBox.IsValid())
50d06d8f 331 {
332 continue;
333 }
334
778cd667 335 aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
50d06d8f 336
7c3ef2f7 337 const BVH_Vec3d& aCornerMin = aBox.CornerMin();
338 const BVH_Vec3d& aCornerMax = aBox.CornerMax();
50d06d8f 339 const Standard_Integer aNbOfPoints = 8;
340 const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
341 gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
342 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
343 gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
344 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
345 gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
346 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
347 gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
348 gp_Pnt aConvertedPoints[aNbOfPoints];
349 Standard_Real aConvertedMinX = std::numeric_limits<double>::max();
350 Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
351 Standard_Real aConvertedMinY = std::numeric_limits<double>::max();
352 Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
353 for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
354 {
355 aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
356
357 aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
358 aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
359
360 aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
361 aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
362 }
363
364 const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window
365 || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
366 const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
367 && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
368 && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
369 && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
370 if (isBigObject || isAlreadyInScreen)
371 {
372 continue;
373 }
374
778cd667 375 const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint();
50d06d8f 376 gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
377 aConvertedTPPoint.SetZ (0.0);
378
379 if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
380 {
381 continue;
382 }
383
384 Standard_Real aShiftX = 0.0;
385 if (aConvertedMinX < -1.0)
386 {
387 aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
388 }
389 else if (aConvertedMaxX > 1.0)
390 {
391 aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
392 }
393
394 Standard_Real aShiftY = 0.0;
395 if (aConvertedMinY < -1.0)
396 {
397 aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
398 }
399 else if (aConvertedMaxY > 1.0)
400 {
401 aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
402 }
403
404 const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
405 const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
406 if (aDifX > Precision::Confusion())
407 {
408 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
409 }
410 if (aDifY > Precision::Confusion())
411 {
412 aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
413 }
414 }
415 }
416
417 return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
418}
419
420// =======================================================================
a1954302 421// function : renderAll
422// purpose :
423// =======================================================================
424void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const
425{
7c3ef2f7 426 const Standard_Integer aViewId = theWorkspace->View()->Identification();
427 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
a1954302 428 {
7c3ef2f7 429 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
430 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
a1954302 431 {
7c3ef2f7 432 const OpenGl_Structure* aStruct = aStructIter.Value();
2b8832bb 433 if (aStruct->IsCulled()
434 || !aStruct->IsVisible (aViewId))
a272ed94 435 {
436 continue;
437 }
a1954302 438
439 aStruct->Render (theWorkspace);
440 }
441 }
442}
443
444// =======================================================================
3fe9ce0e 445// function : updateBVH
a1954302 446// purpose :
447// =======================================================================
3fe9ce0e 448void OpenGl_Layer::updateBVH() const
a1954302 449{
3fe9ce0e 450 if (!myIsBVHPrimitivesNeedsReset)
451 {
452 return;
453 }
454
455 myBVHPrimitives.Clear();
456 myBVHPrimitivesTrsfPers.Clear();
150ed3d5 457 myAlwaysRenderedMap.Clear();
3fe9ce0e 458 myIsBVHPrimitivesNeedsReset = Standard_False;
7c3ef2f7 459 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
a1954302 460 {
7c3ef2f7 461 const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
462 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
825aa485 463 {
3fe9ce0e 464 const OpenGl_Structure* aStruct = aStructIter.Value();
465 if (aStruct->IsAlwaysRendered())
825aa485 466 {
150ed3d5 467 aStruct->MarkAsNotCulled();
468 myAlwaysRenderedMap.Add (aStruct);
3fe9ce0e 469 }
778cd667 470 else if (aStruct->TransformPersistence().IsNull())
3fe9ce0e 471 {
472 myBVHPrimitives.Add (aStruct);
473 }
474 else
475 {
476 myBVHPrimitivesTrsfPers.Add (aStruct);
825aa485 477 }
478 }
a1954302 479 }
3fe9ce0e 480}
481
482// =======================================================================
2b8832bb 483// function : UpdateCulling
3fe9ce0e 484// purpose :
485// =======================================================================
5dc0517d 486void OpenGl_Layer::UpdateCulling (const Standard_Integer theViewId,
487 const OpenGl_BVHTreeSelector& theSelector,
2b8832bb 488 const Standard_Boolean theToTraverse)
3fe9ce0e 489{
490 updateBVH();
a1954302 491
15669413 492 myNbStructuresNotCulled = myNbStructures;
493 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next())
a1954302 494 {
15669413 495 const OpenGl_Structure* aStruct = aStructIter.Value();
496 aStruct->SetCulled (theToTraverse);
497 }
498 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next())
499 {
500 const OpenGl_Structure* aStruct = aStructIter.Value();
501 aStruct->SetCulled (theToTraverse);
a1954302 502 }
a1954302 503
2b8832bb 504 if (!theToTraverse)
505 {
506 return;
507 }
508 if (myBVHPrimitives .Size() == 0
509 && myBVHPrimitivesTrsfPers.Size() == 0)
510 {
511 return;
512 }
513
15669413 514 myNbStructuresNotCulled = myAlwaysRenderedMap.Extent();
2b8832bb 515 OpenGl_BVHTreeSelector::CullingContext aCullCtx;
516 theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
517 theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize());
825aa485 518 for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
a1954302 519 {
825aa485 520 const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
2b8832bb 521 opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
825aa485 522 if (isTrsfPers)
a1954302 523 {
825aa485 524 if (myBVHPrimitivesTrsfPers.Size() == 0)
825aa485 525 continue;
97f937cc 526
7c3ef2f7 527 const OpenGl_Mat4d& aProjection = theSelector.ProjectionMatrix();
528 const OpenGl_Mat4d& aWorldView = theSelector.WorldViewMatrix();
825aa485 529 const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
91d96372 530 const Standard_Integer aViewportWidth = theSelector.ViewportWidth();
531 const Standard_Integer aViewportHeight = theSelector.ViewportHeight();
532
3fe9ce0e 533 aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
825aa485 534 }
535 else
536 {
537 if (myBVHPrimitives.Size() == 0)
825aa485 538 continue;
97f937cc 539
825aa485 540 aBVHTree = myBVHPrimitives.BVH();
541 }
542
2b8832bb 543 if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
825aa485 544 {
545 continue;
546 }
547
f5b72419 548 Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
825aa485 549 Standard_Integer aHead = -1;
2b8832bb 550 Standard_Integer aNode = 0; // a root node
825aa485 551 for (;;)
552 {
553 if (!aBVHTree->IsOuter (aNode))
a1954302 554 {
f2474958 555 const Standard_Integer aLeftChildIdx = aBVHTree->Child<0> (aNode);
556 const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
2b8832bb 557 const Standard_Boolean isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeftChildIdx), aBVHTree->MaxPoint (aLeftChildIdx));
558 const Standard_Boolean isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
825aa485 559 if (isLeftChildIn
560 && isRightChildIn)
561 {
562 aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx;
563 aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx;
564 myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
565 }
566 else if (isLeftChildIn
567 || isRightChildIn)
568 {
569 aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
570 }
571 else
572 {
573 if (aHead < 0)
574 {
575 break;
576 }
577
578 aNode = aStack[aHead--];
579 }
a1954302 580 }
581 else
582 {
825aa485 583 Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode);
4ecf34cc 584 const OpenGl_Structure* aStruct = isTrsfPers
585 ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx)
586 : myBVHPrimitives.GetStructureById (aIdx);
5dc0517d 587 if (aStruct->IsVisible (theViewId))
588 {
589 aStruct->MarkAsNotCulled();
590 ++myNbStructuresNotCulled;
591 }
a1954302 592 if (aHead < 0)
593 {
825aa485 594 break;
a1954302 595 }
596
14a35e5d 597 aNode = aStack[aHead--];
a1954302 598 }
599 }
a1954302 600 }
601}
602
603// =======================================================================
604// function : Append
605// purpose :
606// =======================================================================
607Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther)
608{
609 // the source priority list shouldn't have more priorities
610 const Standard_Integer aNbPriorities = theOther.NbPriorities();
611 if (aNbPriorities > NbPriorities())
612 {
613 return Standard_False;
614 }
615
616 // add all structures to destination priority list
617 for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
618 {
9f112210 619 const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
7c3ef2f7 620 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
a1954302 621 {
7c3ef2f7 622 Add (aStructIter.Value(), aPriorityIter);
a1954302 623 }
624 }
625
626 return Standard_True;
627}
628
7c3ef2f7 629//=======================================================================
630//function : SetLayerSettings
631//purpose :
632//=======================================================================
633void OpenGl_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings)
634{
635 const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution());
636 myLayerSettings = theSettings;
637 if (toUpdateTrsf)
638 {
639 for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
640 {
641 OpenGl_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue();
642 for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
643 {
644 OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructIter.Value());
645 aStructure->updateLayerTransformation();
646 }
647 }
648 }
649}
650
c5751993 651//=======================================================================
652//function : Render
a1954302 653//purpose :
c5751993 654//=======================================================================
a1954302 655void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace,
656 const OpenGl_GlobalLayerSettings& theDefaultSettings) const
c5751993 657{
8d1a539c 658 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
659 const Graphic3d_PolygonOffset anAppliedOffsetParams = aCtx->PolygonOffset();
b3eab8ef 660 // myLayerSettings.ToClearDepth() is handled outside
eae454e3 661
c5751993 662 // handle depth test
7c3ef2f7 663 if (myLayerSettings.ToEnableDepthTest())
c5751993 664 {
550f3b8b 665 // assuming depth test is enabled by default
666 glDepthFunc (theDefaultSettings.DepthFunc);
c5751993 667 }
668 else
669 {
670 glDepthFunc (GL_ALWAYS);
671 }
eae454e3 672
83da37b1 673 // save environment texture
cc8cbabe 674 Handle(OpenGl_TextureSet) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
7c3ef2f7 675 if (!myLayerSettings.UseEnvironmentTexture())
83da37b1 676 {
cc8cbabe 677 theWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
83da37b1 678 }
679
c5751993 680 // handle depth offset
8d1a539c 681 aCtx->SetPolygonOffset (myLayerSettings.PolygonOffset());
c5751993 682
683 // handle depth write
a1073ae2 684 theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE;
eae454e3 685 glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
c5751993 686
7c3ef2f7 687 const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull();
992ed6b3 688 const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
689 Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
690 const bool hasOwnLights = aCtx->ColorMask() && !myLayerSettings.Lights().IsNull() && myLayerSettings.Lights() != aLightsBack;
691 if (hasOwnLights)
692 {
693 myLayerSettings.Lights()->UpdateRevision();
694 aManager->UpdateLightSourceStateTo (myLayerSettings.Lights());
695 }
696
7c3ef2f7 697 const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
7c3ef2f7 698 if (hasLocalCS)
699 {
700 // Apply local camera transformation.
701 // The vertex position is computed by the following formula in GLSL program:
702 // gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
703 // where:
704 // occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection
705 // occWorldViewMatrix - world-view matrix defining Camera position and orientation
706 // occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system
707 // occVertex - input vertex position
708 //
709 // Since double precision is quite expensive on modern GPUs, and not available on old hardware,
710 // all these values are passed with single float precision to the shader.
711 // As result, single precision become insufficient for handling objects far from the world origin.
712 //
713 // Several approaches can be used to solve precision issues:
714 // - [Broute force] migrate to double precision for all matrices and vertex position.
715 // This is too expensive for most hardware.
716 // - Store only translation part with double precision and pass it to GLSL program.
717 // This requires modified GLSL programs for computing transformation
718 // and extra packing mechanism for hardware not supporting double precision natively.
719 // This solution is less expensive then previous one.
720 // - Move translation part of occModelWorldMatrix into occWorldViewMatrix.
721 // The main idea here is that while moving Camera towards the object,
722 // Camera translation part and Object translation part will compensate each other
723 // to fit into single float precision.
724 // But this operation should be performed with double precision - this is why we are moving
725 // translation part of occModelWorldMatrix to occWorldViewMatrix.
726 //
727 // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario.
728 // Here we do the trick:
729 // - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it.
730 // This Local Origin is included into occWorldViewMatrix during rendering.
731 // - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer.
732 // This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer.
733 theWorkspace->View()->SetLocalOrigin (myLayerSettings.Origin());
734
735 NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix();
736 Graphic3d_TransformUtils::Translate (aWorldView, myLayerSettings.Origin().X(), myLayerSettings.Origin().Y(), myLayerSettings.Origin().Z());
737
738 NCollection_Mat4<Standard_ShortReal> aWorldViewF;
739 aWorldViewF.ConvertFrom (aWorldView);
740 aCtx->WorldViewState.SetCurrent (aWorldViewF);
741 aCtx->ShaderManager()->UpdateClippingState();
742 aCtx->ShaderManager()->UpdateLightSourceState();
743 }
744
c5751993 745 // render priority list
2b8832bb 746 renderAll (theWorkspace);
550f3b8b 747
992ed6b3 748 if (hasOwnLights)
749 {
750 aManager->UpdateLightSourceStateTo (aLightsBack);
751 }
7c3ef2f7 752 if (hasLocalCS)
753 {
754 aCtx->ShaderManager()->RevertClippingState();
755 aCtx->ShaderManager()->UpdateLightSourceState();
756
757 aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF());
758 theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0));
759 }
760
550f3b8b 761 // always restore polygon offset between layers rendering
8d1a539c 762 aCtx->SetPolygonOffset (anAppliedOffsetParams);
83da37b1 763
764 // restore environment texture
7c3ef2f7 765 if (!myLayerSettings.UseEnvironmentTexture())
83da37b1 766 {
767 theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
768 }
c5751993 769}