0023620: Follow up of 0022939 - make Bezier curve/surface evaluation thread-safe
[occt.git] / src / OpenGl / OpenGl_BVHTreeSelector.cxx
CommitLineData
b7cd4ba7 1// Created on: 2013-12-25
2// Created by: Varvara POSKONINA
3// Copyright (c) 1999-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
14a35e5d 16#include <limits>
17
b7cd4ba7 18#include <OpenGl_BVHTreeSelector.hxx>
19#include <OpenGl_BVHClipPrimitiveSet.hxx>
c04c30b3 20#include <Graphic3d_GraphicDriver.hxx>
b7cd4ba7 21
b7cd4ba7 22// =======================================================================
23// function : OpenGl_BVHTreeSelector
24// purpose :
25// =======================================================================
26OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
825aa485 27: myIsProjectionParallel (Standard_True)
b7cd4ba7 28{
29 //
30}
31
32// =======================================================================
825aa485 33// function : SetViewVolume
34// purpose : Retrieves view volume's planes equations and its vertices from projection and world-view matrices.
b7cd4ba7 35// =======================================================================
36void OpenGl_BVHTreeSelector::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera)
37{
825aa485 38 if (myWorldViewProjState == theCamera->WorldViewProjState())
39 {
40 return;
41 }
42
b7cd4ba7 43 myIsProjectionParallel = theCamera->IsOrthographic();
825aa485 44
45 myProjectionMat = theCamera->ProjectionMatrixF();
46 myWorldViewMat = theCamera->OrientationMatrixF();
47 myWorldViewProjState = theCamera->WorldViewProjState();
b7cd4ba7 48
49 Standard_ShortReal nLeft = 0.0f, nRight = 0.0f, nTop = 0.0f, nBottom = 0.0f;
50 Standard_ShortReal fLeft = 0.0f, fRight = 0.0f, fTop = 0.0f, fBottom = 0.0f;
51 Standard_ShortReal aNear = 0.0f, aFar = 0.0f;
52 if (!myIsProjectionParallel)
53 {
54 // handle perspective projection
825aa485 55 aNear = myProjectionMat.GetValue (2, 3) / (- 1.0f + myProjectionMat.GetValue (2, 2));
56 aFar = myProjectionMat.GetValue (2, 3) / ( 1.0f + myProjectionMat.GetValue (2, 2));
b7cd4ba7 57 // Near plane
825aa485 58 nLeft = aNear * (myProjectionMat.GetValue (0, 2) - 1.0f) / myProjectionMat.GetValue (0, 0);
59 nRight = aNear * (myProjectionMat.GetValue (0, 2) + 1.0f) / myProjectionMat.GetValue (0, 0);
60 nTop = aNear * (myProjectionMat.GetValue (1, 2) + 1.0f) / myProjectionMat.GetValue (1, 1);
61 nBottom = aNear * (myProjectionMat.GetValue (1, 2) - 1.0f) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 62 // Far plane
825aa485 63 fLeft = aFar * (myProjectionMat.GetValue (0, 2) - 1.0f) / myProjectionMat.GetValue (0, 0);
64 fRight = aFar * (myProjectionMat.GetValue (0, 2) + 1.0f) / myProjectionMat.GetValue (0, 0);
65 fTop = aFar * (myProjectionMat.GetValue (1, 2) + 1.0f) / myProjectionMat.GetValue (1, 1);
66 fBottom = aFar * (myProjectionMat.GetValue (1, 2) - 1.0f) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 67 }
68 else
69 {
70 // handle orthographic projection
825aa485 71 aNear = (1.0f / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) + 1.0f);
72 aFar = (1.0f / myProjectionMat.GetValue (2, 2)) * (myProjectionMat.GetValue (2, 3) - 1.0f);
b7cd4ba7 73 // Near plane
825aa485 74 nLeft = ( 1.0f + myProjectionMat.GetValue (0, 3)) / (-myProjectionMat.GetValue (0, 0));
b7cd4ba7 75 fLeft = nLeft;
825aa485 76 nRight = ( 1.0f - myProjectionMat.GetValue (0, 3)) / myProjectionMat.GetValue (0, 0);
b7cd4ba7 77 fRight = nRight;
825aa485 78 nTop = ( 1.0f - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 79 fTop = nTop;
825aa485 80 nBottom = (-1.0f - myProjectionMat.GetValue (1, 3)) / myProjectionMat.GetValue (1, 1);
b7cd4ba7 81 fBottom = nBottom;
82 }
83
84 OpenGl_Vec4 aLeftTopNear (nLeft, nTop, -aNear, 1.0f), aRightBottomFar (fRight, fBottom, -aFar, 1.0f);
85 OpenGl_Vec4 aLeftBottomNear (nLeft, nBottom, -aNear, 1.0f), aRightTopFar (fRight, fTop, -aFar, 1.0f);
86 OpenGl_Vec4 aRightBottomNear (nRight, nBottom, -aNear, 1.0f), aLeftTopFar (fLeft, fTop, -aFar, 1.0f);
87 OpenGl_Vec4 aRightTopNear (nRight, nTop, -aNear, 1.0f), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0f);
88
825aa485 89 const OpenGl_Mat4 aViewProj = myWorldViewMat * myProjectionMat;
90 OpenGl_Mat4 anInvWorldView;
91 myWorldViewMat.Inverted(anInvWorldView);
b7cd4ba7 92
825aa485 93 myClipVerts[ClipVert_LeftTopNear] = anInvWorldView * aLeftTopNear;
94 myClipVerts[ClipVert_RightBottomFar] = anInvWorldView * aRightBottomFar;
95 myClipVerts[ClipVert_LeftBottomNear] = anInvWorldView * aLeftBottomNear;
96 myClipVerts[ClipVert_RightTopFar] = anInvWorldView * aRightTopFar;
97 myClipVerts[ClipVert_RightBottomNear] = anInvWorldView * aRightBottomNear;
98 myClipVerts[ClipVert_LeftTopFar] = anInvWorldView * aLeftTopFar;
99 myClipVerts[ClipVert_RightTopNear] = anInvWorldView * aRightTopNear;
100 myClipVerts[ClipVert_LeftBottomFar] = anInvWorldView * aLeftBottomFar;
b7cd4ba7 101
102 // UNNORMALIZED!
103 myClipPlanes[Plane_Left] = aViewProj.GetRow (3) + aViewProj.GetRow (0);
104 myClipPlanes[Plane_Right] = aViewProj.GetRow (3) - aViewProj.GetRow (0);
105 myClipPlanes[Plane_Top] = aViewProj.GetRow (3) - aViewProj.GetRow (1);
106 myClipPlanes[Plane_Bottom] = aViewProj.GetRow (3) + aViewProj.GetRow (1);
107 myClipPlanes[Plane_Near] = aViewProj.GetRow (3) + aViewProj.GetRow (2);
108 myClipPlanes[Plane_Far] = aViewProj.GetRow (3) - aViewProj.GetRow (2);
109
110 gp_Pnt aPtCenter = theCamera->Center();
111 OpenGl_Vec4 aCenter (static_cast<Standard_ShortReal> (aPtCenter.X()),
112 static_cast<Standard_ShortReal> (aPtCenter.Y()),
113 static_cast<Standard_ShortReal> (aPtCenter.Z()),
114 1.0f);
115
116 for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB; ++aPlaneIter)
117 {
118 OpenGl_Vec4 anEq = myClipPlanes[aPlaneIter];
119 if (SignedPlanePointDistance (anEq, aCenter) > 0)
120 {
121 anEq *= -1.0f;
122 myClipPlanes[aPlaneIter] = anEq;
123 }
124 }
125}
126
127// =======================================================================
128// function : SignedPlanePointDistance
129// purpose :
130// =======================================================================
131Standard_ShortReal OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec4& theNormal,
132 const OpenGl_Vec4& thePnt)
133{
134 const Standard_ShortReal aNormLength = std::sqrt (theNormal.x() * theNormal.x()
135 + theNormal.y() * theNormal.y()
136 + theNormal.z() * theNormal.z());
3c648527 137
138 if (aNormLength < FLT_EPSILON)
139 return 0.0f;
140
b7cd4ba7 141 const Standard_ShortReal anInvNormLength = 1.0f / aNormLength;
142 const Standard_ShortReal aD = theNormal.w() * anInvNormLength;
143 const Standard_ShortReal anA = theNormal.x() * anInvNormLength;
144 const Standard_ShortReal aB = theNormal.y() * anInvNormLength;
145 const Standard_ShortReal aC = theNormal.z() * anInvNormLength;
146 return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
147}
148
149// =======================================================================
150// function : CacheClipPtsProjections
151// purpose : Caches view volume's vertices projections along its normals and AABBs dimensions
152// Must be called at the beginning of each BVH tree traverse loop
153// =======================================================================
154void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
155{
14a35e5d 156 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
157 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
b7cd4ba7 158 {
159 const OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
14a35e5d 160 Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
161 Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
b7cd4ba7 162 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
163 {
14a35e5d 164 Standard_ShortReal aProjection = aPlane.x() * myClipVerts[aCornerIter].x() +
165 aPlane.y() * myClipVerts[aCornerIter].y() +
166 aPlane.z() * myClipVerts[aCornerIter].z();
167 aMaxProj = Max (aProjection, aMaxProj);
168 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 169 }
14a35e5d 170 myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
171 myMinClipProjectionPts[aPlaneIter] = aMinProj;
b7cd4ba7 172 }
173
b7cd4ba7 174 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
175 {
14a35e5d 176 Standard_ShortReal aMaxProj = -std::numeric_limits<Standard_ShortReal>::max();
177 Standard_ShortReal aMinProj = std::numeric_limits<Standard_ShortReal>::max();
b7cd4ba7 178 for (Standard_Integer aCornerIter = 0; aCornerIter < ClipVerticesNB; ++aCornerIter)
179 {
14a35e5d 180 Standard_ShortReal aProjection = aDim == 0 ? myClipVerts[aCornerIter].x()
181 : (aDim == 1 ? myClipVerts[aCornerIter].y() : myClipVerts[aCornerIter].z());
182 aMaxProj = Max (aProjection, aMaxProj);
183 aMinProj = Min (aProjection, aMinProj);
b7cd4ba7 184 }
14a35e5d 185 myMaxOrthoProjectionPts[aDim] = aMaxProj;
186 myMinOrthoProjectionPts[aDim] = aMinProj;
b7cd4ba7 187 }
188}
189
190// =======================================================================
191// function : Intersect
192// purpose : Detects if AABB overlaps view volume using separating axis theorem (SAT)
193// =======================================================================
194Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec4& theMinPt,
195 const OpenGl_Vec4& theMaxPt) const
196{
197 // E1
198 // |_ E0
199 // /
200 // E2
b7cd4ba7 201
202 // E0 test
14a35e5d 203 if (theMinPt.x() > myMaxOrthoProjectionPts[0]
204 || theMaxPt.x() < myMinOrthoProjectionPts[0])
b7cd4ba7 205 {
206 return Standard_False;
207 }
208
209 // E1 test
14a35e5d 210 if (theMinPt.y() > myMaxOrthoProjectionPts[1]
211 || theMaxPt.y() < myMinOrthoProjectionPts[1])
b7cd4ba7 212 {
213 return Standard_False;
214 }
215
216 // E2 test
14a35e5d 217 if (theMinPt.z() > myMaxOrthoProjectionPts[2]
218 || theMaxPt.z() < myMinOrthoProjectionPts[2])
b7cd4ba7 219 {
220 return Standard_False;
221 }
222
14a35e5d 223 Standard_ShortReal aBoxProjMax = 0.0f, aBoxProjMin = 0.0f;
b7cd4ba7 224 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
225 for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
226 {
227 OpenGl_Vec4 aPlane = myClipPlanes[aPlaneIter];
14a35e5d 228 aBoxProjMax = (aPlane.x() > 0.f ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x()) +
229 (aPlane.y() > 0.f ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y()) +
230 (aPlane.z() > 0.f ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
231 if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
232 && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
b7cd4ba7 233 {
234 continue;
235 }
236
14a35e5d 237 aBoxProjMin = (aPlane.x() < 0.f ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x()) +
238 (aPlane.y() < 0.f ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y()) +
239 (aPlane.z() < 0.f ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
240 if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
241 || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
b7cd4ba7 242 {
243 return Standard_False;
244 }
245 }
246
247 return Standard_True;
248}