| 1 | // Created on: 2013-08-27 |
| 2 | // Created by: Denis BOGOLEPOV |
| 3 | // Copyright (c) 2013 OPEN CASCADE SAS |
| 4 | // |
| 5 | // This file is part of Open CASCADE Technology software library. |
| 6 | // |
| 7 | // This library is free software; you can redistribute it and/or modify it under |
| 8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
| 9 | // by the Free Software Foundation, with special exception defined in the file |
| 10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
| 11 | // distribution for complete text of the license and disclaimer of any warranty. |
| 12 | // |
| 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
| 14 | // commercial license or contractual agreement. |
| 15 | |
| 16 | #include <Standard_Assert.hxx> |
| 17 | |
| 18 | #ifdef HAVE_TBB |
| 19 | // On Windows, function TryEnterCriticalSection has appeared in Windows NT |
| 20 | // and is surrounded by #ifdef in MS VC++ 7.1 headers. |
| 21 | // Thus to use it we need to define appropriate macro saying that we wil |
| 22 | // run on Windows NT 4.0 at least |
| 23 | #if ((defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN32_WINNT)) |
| 24 | #define _WIN32_WINNT 0x0501 |
| 25 | #endif |
| 26 | |
| 27 | #include <tbb/tbb.h> |
| 28 | #endif |
| 29 | |
| 30 | #include <OpenGl_SceneGeometry.hxx> |
| 31 | |
| 32 | //! Use this macro to output BVH profiling info |
| 33 | //#define BVH_PRINT_INFO |
| 34 | |
| 35 | #ifdef BVH_PRINT_INFO |
| 36 | #include <OSD_Timer.hxx> |
| 37 | #endif |
| 38 | |
| 39 | namespace |
| 40 | { |
| 41 | //! Useful constant for null floating-point 4D vector. |
| 42 | static const BVH_Vec4f ZERO_VEC_4F; |
| 43 | }; |
| 44 | |
| 45 | // ======================================================================= |
| 46 | // function : OpenGl_RaytraceMaterial |
| 47 | // purpose : Creates new default material |
| 48 | // ======================================================================= |
| 49 | OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial() |
| 50 | : Ambient (ZERO_VEC_4F), |
| 51 | Diffuse (ZERO_VEC_4F), |
| 52 | Specular (ZERO_VEC_4F), |
| 53 | Emission (ZERO_VEC_4F), |
| 54 | Reflection (ZERO_VEC_4F), |
| 55 | Refraction (ZERO_VEC_4F), |
| 56 | Transparency (ZERO_VEC_4F) |
| 57 | { } |
| 58 | |
| 59 | // ======================================================================= |
| 60 | // function : OpenGl_RaytraceMaterial |
| 61 | // purpose : Creates new material with specified properties |
| 62 | // ======================================================================= |
| 63 | OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient, |
| 64 | const BVH_Vec4f& theDiffuse, |
| 65 | const BVH_Vec4f& theSpecular) |
| 66 | : Ambient (theAmbient), |
| 67 | Diffuse (theDiffuse), |
| 68 | Specular (theSpecular), |
| 69 | Emission (ZERO_VEC_4F), |
| 70 | Reflection (ZERO_VEC_4F), |
| 71 | Refraction (ZERO_VEC_4F), |
| 72 | Transparency (ZERO_VEC_4F) |
| 73 | { |
| 74 | // |
| 75 | } |
| 76 | |
| 77 | // ======================================================================= |
| 78 | // function : OpenGl_RaytraceMaterial |
| 79 | // purpose : Creates new material with specified properties |
| 80 | // ======================================================================= |
| 81 | OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient, |
| 82 | const BVH_Vec4f& theDiffuse, |
| 83 | const BVH_Vec4f& theSpecular, |
| 84 | const BVH_Vec4f& theEmission, |
| 85 | const BVH_Vec4f& theTranspar) |
| 86 | : Ambient (theAmbient), |
| 87 | Diffuse (theDiffuse), |
| 88 | Specular (theSpecular), |
| 89 | Emission (theEmission), |
| 90 | Reflection (ZERO_VEC_4F), |
| 91 | Refraction (ZERO_VEC_4F), |
| 92 | Transparency (theTranspar) |
| 93 | { |
| 94 | // |
| 95 | } |
| 96 | |
| 97 | // ======================================================================= |
| 98 | // function : OpenGl_RaytraceMaterial |
| 99 | // purpose : Creates new material with specified properties |
| 100 | // ======================================================================= |
| 101 | OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient, |
| 102 | const BVH_Vec4f& theDiffuse, |
| 103 | const BVH_Vec4f& theSpecular, |
| 104 | const BVH_Vec4f& theEmission, |
| 105 | const BVH_Vec4f& theTranspar, |
| 106 | const BVH_Vec4f& theReflection, |
| 107 | const BVH_Vec4f& theRefraction) |
| 108 | : Ambient (theAmbient), |
| 109 | Diffuse (theDiffuse), |
| 110 | Specular (theSpecular), |
| 111 | Emission (theEmission), |
| 112 | Reflection (theReflection), |
| 113 | Refraction (theRefraction), |
| 114 | Transparency (theTranspar) |
| 115 | { |
| 116 | // |
| 117 | } |
| 118 | |
| 119 | // ======================================================================= |
| 120 | // function : OpenGl_LightSource |
| 121 | // purpose : Creates new light source |
| 122 | // ======================================================================= |
| 123 | OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse, |
| 124 | const BVH_Vec4f& thePosition) |
| 125 | : Diffuse (theDiffuse), |
| 126 | Position (thePosition) |
| 127 | { |
| 128 | // |
| 129 | } |
| 130 | |
| 131 | // ======================================================================= |
| 132 | // function : Clear |
| 133 | // purpose : Clears ray-tracing geometry |
| 134 | // ======================================================================= |
| 135 | void OpenGl_RaytraceGeometry::Clear() |
| 136 | { |
| 137 | BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear(); |
| 138 | |
| 139 | std::vector<OpenGl_RaytraceLight, |
| 140 | NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources; |
| 141 | |
| 142 | Sources.swap (anEmptySources); |
| 143 | |
| 144 | std::vector<OpenGl_RaytraceMaterial, |
| 145 | NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials; |
| 146 | |
| 147 | Materials.swap (anEmptyMaterials); |
| 148 | } |
| 149 | |
| 150 | #ifdef HAVE_TBB |
| 151 | |
| 152 | struct OpenGL_BVHParallelBuilder |
| 153 | { |
| 154 | BVH_ObjectSet<Standard_ShortReal, 4>* Set; |
| 155 | |
| 156 | OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet) |
| 157 | : Set (theSet) |
| 158 | { |
| 159 | // |
| 160 | } |
| 161 | |
| 162 | void operator() (const tbb::blocked_range<size_t>& theRange) const |
| 163 | { |
| 164 | for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx) |
| 165 | { |
| 166 | OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> ( |
| 167 | Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->()); |
| 168 | |
| 169 | if (aTriangleSet != NULL) |
| 170 | { |
| 171 | aTriangleSet->BVH(); |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | }; |
| 176 | |
| 177 | #endif |
| 178 | |
| 179 | // ======================================================================= |
| 180 | // function : ProcessAcceleration |
| 181 | // purpose : Performs post-processing of high-level BVH |
| 182 | // ======================================================================= |
| 183 | Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration() |
| 184 | { |
| 185 | #ifdef BVH_PRINT_INFO |
| 186 | OSD_Timer aTimer; |
| 187 | #endif |
| 188 | |
| 189 | MarkDirty(); // force BVH rebuilding |
| 190 | |
| 191 | #ifdef BVH_PRINT_INFO |
| 192 | aTimer.Reset(); |
| 193 | aTimer.Start(); |
| 194 | #endif |
| 195 | |
| 196 | #ifdef HAVE_TBB |
| 197 | // If Intel TBB is available, perform the preliminary |
| 198 | // construction of bottom-level scene BVHs |
| 199 | tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()), |
| 200 | OpenGL_BVHParallelBuilder (this)); |
| 201 | #endif |
| 202 | |
| 203 | myBottomLevelTreeDepth = 0; |
| 204 | |
| 205 | for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx) |
| 206 | { |
| 207 | OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> ( |
| 208 | myObjects.ChangeValue (anObjectIdx).operator->()); |
| 209 | |
| 210 | Standard_ASSERT_RETURN (aTriangleSet != NULL, |
| 211 | "Error! Failed to get triangulation of OpenGL element", Standard_False); |
| 212 | |
| 213 | Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(), |
| 214 | "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False); |
| 215 | |
| 216 | myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth()); |
| 217 | } |
| 218 | |
| 219 | #ifdef BVH_PRINT_INFO |
| 220 | aTimer.Stop(); |
| 221 | |
| 222 | std::cout << "Updating bottom-level BVHs (sec): " << |
| 223 | aTimer.ElapsedTime() << std::endl; |
| 224 | #endif |
| 225 | |
| 226 | #ifdef BVH_PRINT_INFO |
| 227 | aTimer.Reset(); |
| 228 | aTimer.Start(); |
| 229 | #endif |
| 230 | |
| 231 | NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH(); |
| 232 | |
| 233 | #ifdef BVH_PRINT_INFO |
| 234 | aTimer.Stop(); |
| 235 | |
| 236 | std::cout << "Updating high-level BVH (sec): " << |
| 237 | aTimer.ElapsedTime() << std::endl; |
| 238 | #endif |
| 239 | |
| 240 | Standard_ASSERT_RETURN (!aBVH.IsNull(), |
| 241 | "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False); |
| 242 | |
| 243 | myHighLevelTreeDepth = aBVH->Depth(); |
| 244 | |
| 245 | Standard_Integer aVerticesOffset = 0; |
| 246 | Standard_Integer aElementsOffset = 0; |
| 247 | Standard_Integer aBVHNodesOffset = 0; |
| 248 | |
| 249 | for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx) |
| 250 | { |
| 251 | if (!aBVH->IsOuter (aNodeIdx)) |
| 252 | continue; |
| 253 | |
| 254 | Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx), |
| 255 | "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False); |
| 256 | |
| 257 | Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx); |
| 258 | |
| 259 | Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(), |
| 260 | "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False); |
| 261 | |
| 262 | OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> ( |
| 263 | myObjects.ChangeValue (anObjectIdx).operator->()); |
| 264 | |
| 265 | // Note: We overwrite node info record to store parameters |
| 266 | // of bottom-level BVH and triangulation of OpenGL element |
| 267 | |
| 268 | aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i ( |
| 269 | anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset); |
| 270 | |
| 271 | aVerticesOffset += (int)aTriangleSet->Vertices.size(); |
| 272 | aElementsOffset += (int)aTriangleSet->Elements.size(); |
| 273 | aBVHNodesOffset += aTriangleSet->BVH()->Length(); |
| 274 | } |
| 275 | |
| 276 | return Standard_True; |
| 277 | } |
| 278 | |
| 279 | // ======================================================================= |
| 280 | // function : AccelerationOffset |
| 281 | // purpose : Returns offset of bottom-level BVH for given leaf node |
| 282 | // ======================================================================= |
| 283 | Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx) |
| 284 | { |
| 285 | const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH(); |
| 286 | |
| 287 | if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx)) |
| 288 | return INVALID_OFFSET; |
| 289 | |
| 290 | return aBVH->NodeInfoBuffer().at (theNodeIdx).y(); |
| 291 | } |
| 292 | |
| 293 | // ======================================================================= |
| 294 | // function : VerticesOffset |
| 295 | // purpose : Returns offset of triangulation vertices for given leaf node |
| 296 | // ======================================================================= |
| 297 | Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx) |
| 298 | { |
| 299 | const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH(); |
| 300 | |
| 301 | if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx)) |
| 302 | return INVALID_OFFSET; |
| 303 | |
| 304 | return aBVH->NodeInfoBuffer().at (theNodeIdx).z(); |
| 305 | } |
| 306 | |
| 307 | // ======================================================================= |
| 308 | // function : ElementsOffset |
| 309 | // purpose : Returns offset of triangulation elements for given leaf node |
| 310 | // ======================================================================= |
| 311 | Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx) |
| 312 | { |
| 313 | const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH(); |
| 314 | |
| 315 | if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx)) |
| 316 | return INVALID_OFFSET; |
| 317 | |
| 318 | return aBVH->NodeInfoBuffer().at (theNodeIdx).w(); |
| 319 | } |
| 320 | |
| 321 | // ======================================================================= |
| 322 | // function : TriangleSet |
| 323 | // purpose : Returns triangulation data for given leaf node |
| 324 | // ======================================================================= |
| 325 | OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx) |
| 326 | { |
| 327 | const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH(); |
| 328 | |
| 329 | if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx)) |
| 330 | return NULL; |
| 331 | |
| 332 | if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size()) |
| 333 | return NULL; |
| 334 | |
| 335 | return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue ( |
| 336 | aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->()); |
| 337 | } |
| 338 | |
| 339 | namespace OpenGl_Raytrace |
| 340 | { |
| 341 | // ======================================================================= |
| 342 | // function : IsRaytracedElement |
| 343 | // purpose : Checks to see if the element contains ray-trace geometry |
| 344 | // ======================================================================= |
| 345 | Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode) |
| 346 | { |
| 347 | OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem); |
| 348 | return anArray != NULL |
| 349 | && anArray->PArray()->type >= TelPolygonsArrayType; |
| 350 | } |
| 351 | |
| 352 | // ======================================================================= |
| 353 | // function : IsRaytracedGroup |
| 354 | // purpose : Checks to see if the group contains ray-trace geometry |
| 355 | // ======================================================================= |
| 356 | Standard_Boolean IsRaytracedGroup (const OpenGl_Group *theGroup) |
| 357 | { |
| 358 | const OpenGl_ElementNode* aNode; |
| 359 | for (aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next) |
| 360 | { |
| 361 | if (IsRaytracedElement (aNode)) |
| 362 | { |
| 363 | return Standard_True; |
| 364 | } |
| 365 | } |
| 366 | return Standard_False; |
| 367 | } |
| 368 | |
| 369 | // ======================================================================= |
| 370 | // function : IsRaytracedStructure |
| 371 | // purpose : Checks to see if the structure contains ray-trace geometry |
| 372 | // ======================================================================= |
| 373 | Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure) |
| 374 | { |
| 375 | for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); |
| 376 | aGroupIter.More(); aGroupIter.Next()) |
| 377 | { |
| 378 | if (aGroupIter.Value()->IsRaytracable()) |
| 379 | return Standard_True; |
| 380 | } |
| 381 | for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); |
| 382 | anIts.More(); anIts.Next()) |
| 383 | { |
| 384 | if (IsRaytracedStructure (anIts.Value())) |
| 385 | return Standard_True; |
| 386 | } |
| 387 | return Standard_False; |
| 388 | } |
| 389 | } |