0025180: Visualization - Homogeneous transformation API in TKV3d
[occt.git] / src / OpenGl / OpenGl_Structure.cxx
... / ...
CommitLineData
1// Created on: 2011-08-01
2// Created by: Sergey ZERCHANINOV
3// Copyright (c) 2011-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
16#include <OpenGl_CappingAlgo.hxx>
17#include <OpenGl_Context.hxx>
18#include <OpenGl_GlCore11.hxx>
19#include <OpenGl_GraphicDriver.hxx>
20#include <OpenGl_ShaderManager.hxx>
21#include <OpenGl_ShaderProgram.hxx>
22#include <OpenGl_StructureShadow.hxx>
23#include <OpenGl_Vec.hxx>
24#include <OpenGl_View.hxx>
25#include <OpenGl_Workspace.hxx>
26
27#include <Graphic3d_SequenceOfHClipPlane.hxx>
28
29
30IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Structure,Graphic3d_CStructure)
31
32//! Auxiliary class for bounding box presentation
33class OpenGl_BndBoxPrs : public OpenGl_Element
34{
35
36public:
37
38 //! Main constructor
39 OpenGl_BndBoxPrs (const Graphic3d_BndBox4f& theBndBox)
40 {
41 const float Xm = theBndBox.CornerMin().x();
42 const float Ym = theBndBox.CornerMin().y();
43 const float Zm = theBndBox.CornerMin().z();
44 const float XM = theBndBox.CornerMax().x();
45 const float YM = theBndBox.CornerMax().y();
46 const float ZM = theBndBox.CornerMax().z();
47
48 myVerts[0] = OpenGl_Vec3 (Xm, Ym, Zm);
49 myVerts[1] = OpenGl_Vec3 (Xm, Ym, ZM);
50 myVerts[2] = OpenGl_Vec3 (Xm, YM, ZM);
51 myVerts[3] = OpenGl_Vec3 (Xm, YM, Zm);
52 myVerts[4] = OpenGl_Vec3 (Xm, Ym, Zm);
53 myVerts[5] = OpenGl_Vec3 (XM, Ym, Zm);
54 myVerts[6] = OpenGl_Vec3 (XM, Ym, ZM);
55 myVerts[7] = OpenGl_Vec3 (XM, YM, ZM);
56 myVerts[8] = OpenGl_Vec3 (XM, YM, Zm);
57 myVerts[9] = OpenGl_Vec3 (XM, Ym, Zm);
58 myVerts[10] = OpenGl_Vec3 (XM, YM, Zm);
59 myVerts[11] = OpenGl_Vec3 (Xm, YM, Zm);
60 myVerts[12] = OpenGl_Vec3 (Xm, YM, ZM);
61 myVerts[13] = OpenGl_Vec3 (XM, YM, ZM);
62 myVerts[14] = OpenGl_Vec3 (XM, Ym, ZM);
63 myVerts[15] = OpenGl_Vec3 (Xm, Ym, ZM);
64 }
65
66 //! Render presentation
67 virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
68 {
69 #if !defined(GL_ES_VERSION_2_0)
70 // Apply line aspect
71 const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
72
73 glDisable (GL_LIGHTING);
74
75 // Use highlight colors
76 theWorkspace->GetGlContext()->core11->glColor3fv (theWorkspace->LineColor().GetData());
77
78 glEnableClientState (GL_VERTEX_ARRAY);
79 glVertexPointer (3, GL_FLOAT, 0, (GLfloat* )&myVerts);
80 glDrawArrays (GL_LINE_STRIP, 0, 16);
81 glDisableClientState (GL_VERTEX_ARRAY);
82
83 // restore aspects
84 if (!aPrevTexture.IsNull())
85 {
86 theWorkspace->EnableTexture (aPrevTexture);
87 }
88 #else
89 (void )theWorkspace;
90 #endif
91 }
92
93 //! Release graphical resources
94 virtual void Release (OpenGl_Context*)
95 {
96 //
97 }
98
99protected:
100
101 //! Protected destructor
102 virtual ~OpenGl_BndBoxPrs() {}
103
104private:
105
106 OpenGl_Vec3 myVerts[16]; //!< vertices array
107
108public:
109
110 DEFINE_STANDARD_ALLOC
111
112};
113
114/*----------------------------------------------------------------------*/
115
116// =======================================================================
117// function : OpenGl_Structure
118// purpose :
119// =======================================================================
120OpenGl_Structure::OpenGl_Structure (const Handle(Graphic3d_StructureManager)& theManager)
121: Graphic3d_CStructure (theManager),
122 myHighlightColor (NULL),
123 myInstancedStructure (NULL),
124 myIsRaytracable (Standard_False),
125 myModificationState (0),
126 myIsCulled (Standard_True),
127 myIsMirrored (Standard_False)
128{
129 //
130}
131
132// =======================================================================
133// function : ~OpenGl_Structure
134// purpose :
135// =======================================================================
136OpenGl_Structure::~OpenGl_Structure()
137{
138 Release (Handle(OpenGl_Context)());
139}
140
141// =======================================================================
142// function : SetTransformation
143// purpose :
144// =======================================================================
145void OpenGl_Structure::SetTransformation (const Handle(Geom_Transformation)& theTrsf)
146{
147 myTrsf = theTrsf;
148 myIsMirrored = Standard_False;
149 if (!myTrsf.IsNull())
150 {
151 // Determinant of transform matrix less then 0 means that mirror transform applied.
152 const Standard_Real aDet = myTrsf->Value(1, 1) * (myTrsf->Value (2, 2) * myTrsf->Value (3, 3) - myTrsf->Value (3, 2) * myTrsf->Value (2, 3))
153 - myTrsf->Value(1, 2) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 3) - myTrsf->Value (3, 1) * myTrsf->Value (2, 3))
154 + myTrsf->Value(1, 3) * (myTrsf->Value (2, 1) * myTrsf->Value (3, 2) - myTrsf->Value (3, 1) * myTrsf->Value (2, 2));
155 myIsMirrored = aDet < 0.0;
156 }
157
158 if (IsRaytracable())
159 {
160 ++myModificationState;
161 }
162}
163
164// =======================================================================
165// function : clearHighlightBox
166// purpose :
167// =======================================================================
168void OpenGl_Structure::clearHighlightBox (const Handle(OpenGl_Context)& theGlCtx)
169{
170 if (!myHighlightBox.IsNull())
171 {
172 myHighlightBox->Release (theGlCtx);
173 myHighlightBox.Nullify();
174 }
175}
176
177// =======================================================================
178// function : HighlightWithColor
179// purpose :
180// =======================================================================
181void OpenGl_Structure::HighlightWithColor (const Graphic3d_Vec3& theColor,
182 const Standard_Boolean theToCreate)
183{
184 const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
185 if (theToCreate)
186 setHighlightColor (aContext, theColor);
187 else
188 clearHighlightColor (aContext);
189}
190
191// =======================================================================
192// function : HighlightWithBndBox
193// purpose :
194// =======================================================================
195void OpenGl_Structure::HighlightWithBndBox (const Handle(Graphic3d_Structure)& theStruct,
196 const Standard_Boolean theToCreate)
197{
198 const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext();
199 if (!theToCreate)
200 {
201 clearHighlightBox (aContext);
202 return;
203 }
204
205 if (!myHighlightBox.IsNull())
206 {
207 myHighlightBox->Release (aContext);
208 }
209 else
210 {
211 myHighlightBox = new OpenGl_Group (theStruct);
212 }
213
214 myHighlightBox->SetGroupPrimitivesAspect (new Graphic3d_AspectLine3d (HighlightColor, Aspect_TOL_SOLID, 1.0));
215
216 OpenGl_BndBoxPrs* aBndBoxPrs = new OpenGl_BndBoxPrs (myBndBox);
217 myHighlightBox->AddElement (aBndBoxPrs);
218}
219
220// =======================================================================
221// function : setHighlightColor
222// purpose :
223// =======================================================================
224void OpenGl_Structure::setHighlightColor (const Handle(OpenGl_Context)& theGlCtx,
225 const Graphic3d_Vec3& theColor)
226{
227 clearHighlightBox (theGlCtx);
228 if (myHighlightColor == NULL)
229 {
230 myHighlightColor = new OpenGl_Vec4 (theColor, 1.0f);
231 }
232 else
233 {
234 myHighlightColor->xyz() = theColor;
235 }
236}
237
238// =======================================================================
239// function : clearHighlightColor
240// purpose :
241// =======================================================================
242void OpenGl_Structure::clearHighlightColor (const Handle(OpenGl_Context)& theGlCtx)
243{
244 clearHighlightBox(theGlCtx);
245 delete myHighlightColor;
246 myHighlightColor = NULL;
247}
248
249// =======================================================================
250// function : OnVisibilityChanged
251// purpose :
252// =======================================================================
253void OpenGl_Structure::OnVisibilityChanged()
254{
255 if (IsRaytracable())
256 {
257 ++myModificationState;
258 }
259}
260
261// =======================================================================
262// function : IsRaytracable
263// purpose :
264// =======================================================================
265Standard_Boolean OpenGl_Structure::IsRaytracable() const
266{
267 if (!myGroups.IsEmpty()
268 && myIsRaytracable)
269 {
270 return Standard_True;
271 }
272
273 return myInstancedStructure != NULL
274 && myInstancedStructure->IsRaytracable();
275}
276
277// =======================================================================
278// function : UpdateRaytracableState
279// purpose :
280// =======================================================================
281void OpenGl_Structure::UpdateStateIfRaytracable (const Standard_Boolean toCheck) const
282{
283 myIsRaytracable = !toCheck;
284 if (!myIsRaytracable)
285 {
286 for (OpenGl_Structure::GroupIterator anIter (myGroups); anIter.More(); anIter.Next())
287 {
288 if (anIter.Value()->IsRaytracable())
289 {
290 myIsRaytracable = Standard_True;
291 break;
292 }
293 }
294 }
295
296 if (IsRaytracable())
297 {
298 ++myModificationState;
299 }
300}
301
302// =======================================================================
303// function : Connect
304// purpose :
305// =======================================================================
306void OpenGl_Structure::Connect (Graphic3d_CStructure& theStructure)
307{
308 OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
309
310 Standard_ASSERT_RAISE (myInstancedStructure == NULL || myInstancedStructure == aStruct,
311 "Error! Instanced structure is already defined");
312
313 myInstancedStructure = aStruct;
314
315 if (aStruct->IsRaytracable())
316 {
317 UpdateStateIfRaytracable (Standard_False);
318 }
319}
320
321// =======================================================================
322// function : Disconnect
323// purpose :
324// =======================================================================
325void OpenGl_Structure::Disconnect (Graphic3d_CStructure& theStructure)
326{
327 OpenGl_Structure* aStruct = static_cast<OpenGl_Structure*> (&theStructure);
328
329 if (myInstancedStructure == aStruct)
330 {
331 myInstancedStructure = NULL;
332
333 if (aStruct->IsRaytracable())
334 {
335 UpdateStateIfRaytracable();
336 }
337 }
338}
339
340// =======================================================================
341// function : NewGroup
342// purpose :
343// =======================================================================
344Handle(Graphic3d_Group) OpenGl_Structure::NewGroup (const Handle(Graphic3d_Structure)& theStruct)
345{
346 Handle(OpenGl_Group) aGroup = new OpenGl_Group (theStruct);
347 myGroups.Append (aGroup);
348 return aGroup;
349}
350
351// =======================================================================
352// function : RemoveGroup
353// purpose :
354// =======================================================================
355void OpenGl_Structure::RemoveGroup (const Handle(Graphic3d_Group)& theGroup)
356{
357 if (theGroup.IsNull())
358 {
359 return;
360 }
361
362 for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
363 {
364 // Check for the given group
365 if (aGroupIter.Value() == theGroup)
366 {
367 const Standard_Boolean wasRaytracable =
368 static_cast<const OpenGl_Group&> (*theGroup).IsRaytracable();
369
370 theGroup->Clear (Standard_False);
371
372 if (wasRaytracable)
373 {
374 UpdateStateIfRaytracable();
375 }
376
377 myGroups.Remove (aGroupIter);
378 return;
379 }
380 }
381}
382
383// =======================================================================
384// function : Clear
385// purpose :
386// =======================================================================
387void OpenGl_Structure::Clear()
388{
389 Clear (GlDriver()->GetSharedContext());
390}
391
392// =======================================================================
393// function : Clear
394// purpose :
395// =======================================================================
396void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx)
397{
398 Standard_Boolean aRaytracableGroupDeleted (Standard_False);
399
400 // Release groups
401 for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
402 {
403 aRaytracableGroupDeleted |= aGroupIter.Value()->IsRaytracable();
404
405 // Delete objects
406 aGroupIter.ChangeValue()->Release (theGlCtx);
407 }
408 myGroups.Clear();
409
410 if (aRaytracableGroupDeleted)
411 {
412 myIsRaytracable = Standard_False;
413 }
414
415 Is2dText = Standard_False;
416 IsForHighlight = Standard_False;
417}
418
419// =======================================================================
420// function : renderGeometry
421// purpose :
422// =======================================================================
423void OpenGl_Structure::renderGeometry (const Handle(OpenGl_Workspace)& theWorkspace,
424 bool& theHasClosed) const
425{
426 if (myInstancedStructure != NULL)
427 {
428 myInstancedStructure->renderGeometry (theWorkspace, theHasClosed);
429 }
430
431 for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
432 {
433 theHasClosed = theHasClosed || aGroupIter.Value()->IsClosed();
434 aGroupIter.Value()->Render (theWorkspace);
435 }
436}
437
438// =======================================================================
439// function : Render
440// purpose :
441// =======================================================================
442void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
443{
444 // Process the structure only if visible
445 if (!visible)
446 {
447 return;
448 }
449
450 const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
451
452 // Render named status
453 if (highlight)
454 {
455 theWorkspace->SetHighlight (true);
456 }
457
458 // Apply local transformation
459 aCtx->ModelWorldState.Push();
460 OpenGl_Mat4& aModelWorld = aCtx->ModelWorldState.ChangeCurrent();
461 if (!myTrsf.IsNull())
462 {
463 myTrsf->Trsf().GetMat4 (aModelWorld);
464 }
465 else
466 {
467 aModelWorld.InitIdentity();
468 }
469
470 const Standard_Boolean anOldGlNormalize = aCtx->IsGlNormalizeEnabled();
471
472#if !defined(GL_ES_VERSION_2_0)
473 // detect scale transform
474 if (aCtx->core11 != NULL
475 && !myTrsf.IsNull())
476 {
477 const Standard_Real aScale = myTrsf->ScaleFactor();
478 if (Abs (aScale - 1.0) > Precision::Confusion())
479 {
480 aCtx->SetGlNormalizeEnabled (Standard_True);
481 }
482 }
483#endif
484
485 if (!myTrsfPers.IsNull())
486 {
487 OpenGl_Mat4 aWorldView = aCtx->WorldViewState.Current();
488 myTrsfPers->Apply (theWorkspace->View()->Camera(), aCtx->ProjectionState.Current(), aWorldView,
489 aCtx->Viewport()[2], aCtx->Viewport()[3]);
490
491 aCtx->WorldViewState.Push();
492 aCtx->WorldViewState.SetCurrent (aWorldView);
493
494 #if !defined(GL_ES_VERSION_2_0)
495 if (!aCtx->IsGlNormalizeEnabled()
496 && aCtx->core11 != NULL)
497 {
498 const Standard_Real aScale = Graphic3d_TransformUtils::ScaleFactor<Standard_ShortReal> (aWorldView);
499 if (Abs (aScale - 1.0f) > Precision::Confusion())
500 {
501 aCtx->SetGlNormalizeEnabled (Standard_True);
502 }
503 }
504 #endif
505 }
506
507 // Take into account transform persistence
508 aCtx->ApplyModelViewMatrix();
509
510 // remember aspects
511 const OpenGl_AspectLine* aPrevAspectLine = theWorkspace->AspectLine();
512 const OpenGl_AspectFace* aPrevAspectFace = theWorkspace->AspectFace();
513 const OpenGl_AspectMarker* aPrevAspectMarker = theWorkspace->AspectMarker();
514 const OpenGl_AspectText* aPrevAspectText = theWorkspace->AspectText();
515
516 // Apply correction for mirror transform
517 if (myIsMirrored)
518 {
519 aCtx->core11fwd->glFrontFace (GL_CW);
520 }
521
522 // Apply highlight color
523 const OpenGl_Vec4* aHighlightColor = theWorkspace->HighlightColor;
524 if (myHighlightColor)
525 theWorkspace->HighlightColor = myHighlightColor;
526
527 // Collect clipping planes of structure scope
528 aCtx->ChangeClipping().SetLocalPlanes (aCtx, myClipPlanes);
529
530 // True if structure is fully clipped
531 bool isClipped = false;
532 bool hasDisabled = false;
533 if (aCtx->Clipping().IsClippingOrCappingOn())
534 {
535 const Graphic3d_BndBox4f& aBBox = BoundingBox();
536 if ((!myTrsfPers.IsNull() && myTrsfPers->IsTrihedronOr2d())
537 || (!myClipPlanes.IsNull() && myClipPlanes->ToOverrideGlobal()))
538 {
539 aCtx->ChangeClipping().DisableGlobal (aCtx);
540 hasDisabled = aCtx->Clipping().HasDisabled();
541 }
542
543 // Set of clipping planes that do not intersect the structure,
544 // and thus can be disabled to improve rendering performance
545 if (aBBox.IsValid()
546 && myTrsfPers.IsNull())
547 {
548 for (OpenGl_ClippingIterator aPlaneIt (aCtx->Clipping()); aPlaneIt.More(); aPlaneIt.Next())
549 {
550 const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
551 if (!aPlane->IsOn())
552 {
553 continue;
554 }
555
556 // check for clipping
557 const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation();
558 const Graphic3d_Vec4d aMaxPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMax().x() : aBBox.CornerMin().x(),
559 aPlaneEquation.y() > 0.0 ? aBBox.CornerMax().y() : aBBox.CornerMin().y(),
560 aPlaneEquation.z() > 0.0 ? aBBox.CornerMax().z() : aBBox.CornerMin().z(),
561 1.0);
562 if (aPlaneEquation.Dot (aMaxPnt) < 0.0) // max vertex is outside the half-space
563 {
564 isClipped = true;
565 break;
566 }
567
568 // check for no intersection (e.g. object is "entirely not clipped")
569 const Graphic3d_Vec4d aMinPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMin().x() : aBBox.CornerMax().x(),
570 aPlaneEquation.y() > 0.0 ? aBBox.CornerMin().y() : aBBox.CornerMax().y(),
571 aPlaneEquation.z() > 0.0 ? aBBox.CornerMin().z() : aBBox.CornerMax().z(),
572 1.0);
573 if (aPlaneEquation.Dot (aMinPnt) > 0.0) // min vertex is inside the half-space
574 {
575 aCtx->ChangeClipping().SetEnabled (aCtx, aPlaneIt, Standard_False);
576 hasDisabled = true;
577 }
578 }
579 }
580
581 if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
582 || hasDisabled)
583 {
584 // Set OCCT state uniform variables
585 aCtx->ShaderManager()->UpdateClippingState();
586 }
587 }
588
589 // Render groups
590 bool hasClosedPrims = false;
591 if (!isClipped)
592 {
593 renderGeometry (theWorkspace, hasClosedPrims);
594 }
595
596 // Reset correction for mirror transform
597 if (myIsMirrored)
598 {
599 aCtx->core11fwd->glFrontFace (GL_CCW);
600 }
601
602 // Render capping for structure groups
603 if (hasClosedPrims
604 && aCtx->Clipping().IsCappingOn())
605 {
606 OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
607 }
608
609 // Revert structure clippings
610 if (hasDisabled)
611 {
612 // enable planes that were previously disabled
613 aCtx->ChangeClipping().RestoreDisabled (aCtx);
614 }
615 aCtx->ChangeClipping().SetLocalPlanes (aCtx, Handle(Graphic3d_SequenceOfHClipPlane)());
616 if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty())
617 || hasDisabled)
618 {
619 // Set OCCT state uniform variables
620 aCtx->ShaderManager()->RevertClippingState();
621 }
622
623 // Restore local transformation
624 aCtx->ModelWorldState.Pop();
625 aCtx->SetGlNormalizeEnabled (anOldGlNormalize);
626 if (!myTrsfPers.IsNull())
627 {
628 aCtx->WorldViewState.Pop();
629 }
630
631 // Restore highlight color
632 theWorkspace->HighlightColor = aHighlightColor;
633
634 // Restore aspects
635 theWorkspace->SetAspectLine (aPrevAspectLine);
636 theWorkspace->SetAspectFace (aPrevAspectFace);
637 theWorkspace->SetAspectMarker (aPrevAspectMarker);
638 theWorkspace->SetAspectText (aPrevAspectText);
639
640 // Apply highlight box
641 if (!myHighlightBox.IsNull())
642 {
643 myHighlightBox->Render (theWorkspace);
644 }
645
646 // Restore named status
647 theWorkspace->SetHighlight (false);
648}
649
650// =======================================================================
651// function : Release
652// purpose :
653// =======================================================================
654void OpenGl_Structure::Release (const Handle(OpenGl_Context)& theGlCtx)
655{
656 // Release groups
657 Clear (theGlCtx);
658 clearHighlightColor (theGlCtx);
659}
660
661// =======================================================================
662// function : ReleaseGlResources
663// purpose :
664// =======================================================================
665void OpenGl_Structure::ReleaseGlResources (const Handle(OpenGl_Context)& theGlCtx)
666{
667 for (OpenGl_Structure::GroupIterator aGroupIter (myGroups); aGroupIter.More(); aGroupIter.Next())
668 {
669 aGroupIter.ChangeValue()->Release (theGlCtx);
670 }
671 if (!myHighlightBox.IsNull())
672 {
673 myHighlightBox->Release (theGlCtx.operator->());
674 }
675}
676
677//=======================================================================
678//function : ShadowLink
679//purpose :
680//=======================================================================
681Handle(Graphic3d_CStructure) OpenGl_Structure::ShadowLink (const Handle(Graphic3d_StructureManager)& theManager) const
682{
683 return new OpenGl_StructureShadow (theManager, this);
684}