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