0032143: Visualization - add option excluding transparent object from sorting
[occt.git] / src / OpenGl / OpenGl_GraduatedTrihedron.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-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 <OpenGl_GlCore11.hxx>
17
18 #include <OpenGl_GraduatedTrihedron.hxx>
19
20 #include <Graphic3d_ArrayOfPolylines.hxx>
21 #include <Graphic3d_ArrayOfSegments.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23 #include <Graphic3d_Text.hxx>
24 #include <Graphic3d_TransformPers.hxx>
25 #include <Graphic3d_TransformUtils.hxx>
26 #include <gp_Ax3.hxx>
27 #include <OpenGl_Workspace.hxx>
28 #include <OpenGl_View.hxx>
29 #include <Precision.hxx>
30
31 #ifndef _WIN32
32   #include <string.h>
33 #endif
34
35 namespace
36 {
37   static Standard_ShortReal THE_LABEL_HEIGHT = 16;
38   static Graphic3d_HorizontalTextAlignment THE_LABEL_HALIGH = Graphic3d_HTA_LEFT;
39   static Graphic3d_VerticalTextAlignment THE_LABEL_VALIGH = Graphic3d_VTA_BOTTOM;
40 }
41
42 // =======================================================================
43 // function : Constructor
44 // purpose  :
45 // =======================================================================
46 OpenGl_GraduatedTrihedron::OpenGl_GraduatedTrihedron()
47 : myMin (0.0f, 0.0f, 0.0f),
48   myMax (100.0f, 100.0f, 100.0f),
49   myIsInitialized (Standard_False)
50 {
51   //
52 }
53
54 // =======================================================================
55 // function : SetValues
56 // purpose  :
57 // =======================================================================
58 void OpenGl_GraduatedTrihedron::SetValues (const Graphic3d_GraduatedTrihedron& theData)
59 {
60   myData          = theData;
61   myIsInitialized = Standard_False;
62 }
63
64 // =======================================================================
65 // function : Destructor
66 // purpose  :
67 // =======================================================================
68 OpenGl_GraduatedTrihedron::~OpenGl_GraduatedTrihedron()
69 {
70   //
71 }
72
73 // =======================================================================
74 // function : Release
75 // purpose  :
76 // =======================================================================
77 void OpenGl_GraduatedTrihedron::Release (OpenGl_Context* theCtx)
78 {
79   myAxes[0].Release (theCtx);
80   myAxes[1].Release (theCtx);
81   myAxes[2].Release (theCtx);
82   myLabelValues.Release (theCtx);
83 }
84
85 // =======================================================================
86 // function : initResources
87 // purpose  :
88 // =======================================================================
89 void OpenGl_GraduatedTrihedron::initGlResources (const Handle(OpenGl_Context)& theCtx) const
90 {
91   myAxes[0].Release     (theCtx.operator->());
92   myAxes[1].Release     (theCtx.operator->());
93   myAxes[2].Release     (theCtx.operator->());
94   myLabelValues.Release (theCtx.operator->());
95
96   // Initialize text label parameters for x, y, and z axes
97   myAxes[0] = Axis (myData.XAxisAspect(), OpenGl_Vec3 (1.0f, 0.0f, 0.0f));
98   myAxes[1] = Axis (myData.YAxisAspect(), OpenGl_Vec3 (0.0f, 1.0f, 0.0f));
99   myAxes[2] = Axis (myData.ZAxisAspect(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
100
101   // Initialize constant primitives: text, arrows.
102   myAxes[0].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
103   myAxes[1].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
104   myAxes[2].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (1.0f, 0.0f, 0.0f));
105   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
106   {
107     myAxes[anIt].Label.SetFontSize (theCtx, myData.NamesSize());
108   }
109
110   myLabelValues.SetFontSize (theCtx, myData.ValuesSize());
111
112   myAspectLabels.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_MaskBlend, 0.285f);
113   myAspectLabels.Aspect()->SetTextFontAspect (myData.NamesFontAspect());
114   myAspectLabels.Aspect()->SetTextFont (!myData.NamesFont().IsEmpty()
115                                        ? new TCollection_HAsciiString (myData.NamesFont())
116                                        : Handle(TCollection_HAsciiString )());
117
118   myAspectValues.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_MaskBlend, 0.285f);
119   myAspectValues.Aspect()->SetTextFontAspect (myData.ValuesFontAspect());
120   myAspectValues.Aspect()->SetTextFont (!myData.ValuesFont().IsEmpty()
121                                        ? new TCollection_HAsciiString (myData.ValuesFont())
122                                        : Handle(TCollection_HAsciiString )());
123
124   // Grid aspect
125   myGridLineAspect.Aspect()->SetColor (myData.GridColor());
126 }
127
128 // =======================================================================
129 // method  : getNormal
130 // purpose : Normal of the view (not normalized!)
131 // =======================================================================
132 Standard_ShortReal OpenGl_GraduatedTrihedron::getNormal (const Handle(OpenGl_Context)& theContext,
133                                                          OpenGl_Vec3& theNormal) const
134 {
135   const Standard_Integer* aViewport = theContext->Viewport();
136
137   OpenGl_Mat4 aModelMatrix;
138   OpenGl_Mat4 aProjMatrix;
139   aModelMatrix.Convert (theContext->ModelWorldState.Current() * theContext->WorldViewState.Current());
140   aProjMatrix .Convert (theContext->ProjectionState.Current());
141
142   OpenGl_Vec3 aPoint1, aPoint2, aPoint3;
143   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) aViewport[0],
144                                                            (Standard_ShortReal) aViewport[1],
145                                                            0.0f,
146                                                            aModelMatrix, aProjMatrix, aViewport,
147                                                            aPoint1.x(), aPoint1.y(), aPoint1.z());
148
149   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) (aViewport[0] + aViewport[2]),
150                                                            (Standard_ShortReal) aViewport[1],
151                                                            0.0f,
152                                                            aModelMatrix, aProjMatrix, aViewport,
153                                                            aPoint2.x(), aPoint2.y(), aPoint2.z());
154
155   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) aViewport[0],
156                                                            (Standard_ShortReal) (aViewport[1] + aViewport[3]),
157                                                            0.0f,
158                                                            aModelMatrix, aProjMatrix, aViewport,
159                                                            aPoint3.x(), aPoint3.y(), aPoint3.z());
160
161   const OpenGl_Vec3 aD1 = aPoint3 - aPoint1;
162   const OpenGl_Vec3 aD2 = aPoint2 - aPoint1;
163   theNormal =  OpenGl_Vec3::Cross (aD1, aD2);
164
165   // Distance corresponding to 1 pixel
166   return aD2.Modulus() / (float) aViewport[2];
167 }
168
169 // =======================================================================
170 // method  : getDistancetoCorner
171 // purpose : 
172 // =======================================================================
173 Standard_ShortReal OpenGl_GraduatedTrihedron::getDistanceToCorner (const OpenGl_Vec3& theNormal,
174                                                                    const OpenGl_Vec3& theCenter,
175                                                                    const Standard_ShortReal theX,
176                                                                    const Standard_ShortReal theY,
177                                                                    const Standard_ShortReal theZ) const
178 {
179   return theNormal.x() * (theX - theCenter.x())
180        + theNormal.y() * (theY - theCenter.y())
181        + theNormal.z() * (theZ - theCenter.z());
182 }
183
184 // =======================================================================
185 // method  : getGridAxes
186 // purpose : 
187 // =======================================================================
188 Standard_ExtCharacter OpenGl_GraduatedTrihedron::getGridAxes (const Standard_ShortReal theCorners[8],
189                                                               GridAxes& theGridAxes) const
190 {
191   // Find the farest corner
192   Standard_Byte aMaxIndex = 0;
193   Standard_ShortReal aMax = theCorners[aMaxIndex] > 0.0f ? theCorners[aMaxIndex] : 0.0f;
194
195   for (Standard_Byte anIt = 0; anIt < 8; ++anIt)
196   {
197     if (theCorners[anIt] > aMax)
198     {
199       aMax = theCorners[anIt];
200       aMaxIndex = anIt;
201     }
202   }
203
204   switch (aMaxIndex)
205   {
206     case 0: // (0,0,0)
207     {
208       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
209       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
210       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, 1.0f, 0.0f);
211       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, 1.0f);
212
213       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
214       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
215       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
216
217       return OOZ_XOZ | OYO_XYO |
218              XOO_XYO | OOZ_OYZ |
219              XOO_XOZ | OYO_OYZ;
220     }
221     case 1: // (0,0,1)
222     {
223       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
224       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
225       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, 1.0f, 0.0f);
226       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, -1.0f);
227
228       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
229       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
230       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
231
232       return OOZ_XOZ | OYZ_XYZ |
233              OOZ_OYZ | XOZ_XYZ |
234              XOO_XOZ | OYO_OYZ;
235     }
236     case 2: // (0,1,0)
237     {
238       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
239       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
240       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, -1.0f, 0.0f);
241       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, 1.0f);
242
243       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
244       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
245       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
246
247       return OYO_XYO | OYZ_XYZ |
248              XOO_XYO | OOZ_OYZ |
249              XYO_XYZ | OYO_OYZ;
250     }
251     case 3: // (0,1,1)
252     {
253       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMax.y(), myMax.z());
254       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
255       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, -1.0f, 0.0f);
256       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, -1.0f);
257
258       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
259       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
260       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
261
262       return OOZ_XOZ | OYZ_XYZ | OYO_XYO |
263              OOZ_OYZ | XOZ_XYZ |
264              OYO_OYZ | XYO_XYZ;
265     }
266     case 4: // (1,0,0)
267     {
268       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
269       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
270       theGridAxes.Axes[1] = OpenGl_Vec3 (0, 1, 0);
271       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, 1);
272
273       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
274       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
275       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
276
277       return OOZ_XOZ | OYO_XYO |
278              XOO_XYO | XOZ_XYZ |
279              XOO_XOZ | XYO_XYZ;
280     }
281     case 5: // (1,0,1)
282     {
283       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
284       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
285       theGridAxes.Axes[1] = OpenGl_Vec3 (0, 1, 0);
286       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, -1);
287
288       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
289       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
290       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
291
292       return OOZ_XOZ | OYZ_XYZ |
293              XOO_XYO | XOZ_XYZ | OOZ_OYZ |
294              XOO_XOZ | XYO_XYZ;
295     }
296     case 6: // (1,1,0)
297     {
298       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
299       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
300       theGridAxes.Axes[1] = OpenGl_Vec3 (0, -1, 0);
301       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, 1);
302
303       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
304       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
305       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
306
307       return OYO_XYO | OYZ_XYZ |
308              XOO_XYO | XOZ_XYZ |
309              XOO_XOZ | XYO_XYZ | OYO_OYZ;
310     }
311     case 7: // (1,1,1)
312     default:
313     {
314       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMax.y(), myMax.z());
315       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
316       theGridAxes.Axes[1] = OpenGl_Vec3 (0, -1, 0);
317       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, -1);
318
319       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
320       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
321       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
322
323       return OYO_XYO | OYZ_XYZ | OOZ_XOZ |
324              XOO_XYO | XOZ_XYZ | OOZ_OYZ |
325              XOO_XOZ | XYO_XYZ | OYO_OYZ;
326     }
327   }
328 }
329
330 // =======================================================================
331 // function : renderLine
332 // purpose  :
333 // =======================================================================
334 void OpenGl_GraduatedTrihedron::renderLine (const OpenGl_PrimitiveArray&    theLine,
335                                             const Handle(OpenGl_Workspace)& theWorkspace,
336                                             const OpenGl_Mat4& theMat,
337                                             const Standard_ShortReal theXt,
338                                             const Standard_ShortReal theYt,
339                                             const Standard_ShortReal theZt) const
340 {
341   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
342   OpenGl_Mat4 aMat (theMat);
343   Graphic3d_TransformUtils::Translate (aMat, theXt, theYt, theZt);
344   aContext->WorldViewState.SetCurrent (aMat);
345   aContext->ApplyWorldViewMatrix();
346   theLine.Render (theWorkspace);
347 }
348
349 // =======================================================================
350 // function : renderGridPlane
351 // purpose  :
352 // =======================================================================
353 void OpenGl_GraduatedTrihedron::renderGridPlane (const Handle(OpenGl_Workspace)& theWorkspace,
354                                                  const Standard_Integer& theIndex,
355                                                  const GridAxes& theGridAxes,
356                                                  OpenGl_Mat4& theMat) const
357 {
358   const Graphic3d_AxisAspect& aCurAspect = myData.AxisAspect (theIndex);
359   if (aCurAspect.TickmarksNumber() <= 0)
360   {
361     return;
362   }
363
364   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
365
366   Standard_ShortReal aStep = theGridAxes.Axes[theIndex].GetData()[theIndex]
367                             * (myMax.GetData()[theIndex] - myMin.GetData()[theIndex]) / aCurAspect.TickmarksNumber();
368
369   // NOTE:
370   // Get two other axes directions and draw lines Axis.TickmarksNumber times.
371   // Combining together from three axes, these lines will make a grid.
372   for (Standard_Integer anIter = 1; anIter <= 2; ++anIter)
373   {
374     OpenGl_Mat4 aMat (theMat);
375     const Standard_Integer anIndex = (theIndex + anIter) % 3;
376     const Axis& anAxis = myAxes[anIndex];
377     OpenGl_Vec3 aStart (theGridAxes.Origin);
378     if (theGridAxes.Axes[anIndex].GetData()[anIndex] < 0.0)
379     {
380       aStart.ChangeData()[anIndex] = myMin.GetData()[anIndex];
381     }
382
383     Graphic3d_TransformUtils::Translate (aMat, aStart.x(), aStart.y(), aStart.z());
384     aContext->WorldViewState.SetCurrent (aMat);
385     aContext->ApplyWorldViewMatrix();
386
387     const OpenGl_Vec3 aStepVec (myAxes[theIndex].Direction * aStep);
388     for (Standard_Integer anIt = myData.ToDrawAxes() ? 1 : 0; anIt < aCurAspect.TickmarksNumber(); ++anIt)
389     {
390       Graphic3d_TransformUtils::Translate (aMat, aStepVec.x(), aStepVec.y(), aStepVec.z());
391       aContext->WorldViewState.SetCurrent (aMat);
392       aContext->ApplyWorldViewMatrix();
393       anAxis.Line.Render (theWorkspace);
394     }
395   }
396 }
397
398 // =======================================================================
399 // function : renderAxis
400 // purpose  :
401 // =======================================================================
402 void OpenGl_GraduatedTrihedron::renderAxis (const Handle(OpenGl_Workspace)& theWorkspace,
403                                             const Standard_Integer& theIndex,
404                                             const OpenGl_Mat4& theMat) const
405 {
406   const Axis& anAxis = myAxes[theIndex];
407
408   theWorkspace->SetAspects (&anAxis.LineAspect);
409   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
410
411   // Reset transformations
412   aContext->WorldViewState.SetCurrent (theMat);
413   aContext->ApplyWorldViewMatrix();
414
415   // Render arrow
416   OpenGl_Vec3 anArrowVec = myMin + anAxis.Direction * (myMax - myMin);
417
418   Graphic3d_TransformPers aTransMode (Graphic3d_TMF_ZoomPers, gp_Pnt (Standard_Real(anArrowVec.x()),
419                                                                       Standard_Real(anArrowVec.y()),
420                                                                       Standard_Real(anArrowVec.z())));
421   const OpenGl_Mat4& aProjection = aContext->ProjectionState.Current();
422   const OpenGl_Mat4& aWorldView  = aContext->WorldViewState.Current();
423   const Standard_Integer aWidth  = theWorkspace->Width();
424   const Standard_Integer aHeight = theWorkspace->Height();
425
426   // Take into account Transform Persistence
427   aContext->ModelWorldState.SetCurrent (aTransMode.Compute (aContext->Camera(), aProjection, aWorldView, aWidth, aHeight));
428   aContext->ApplyModelViewMatrix();
429
430   anAxis.Arrow.Render (theWorkspace);
431
432   // Get current Model-View and Projection states
433   OpenGl_Mat4 aModelMat;
434   OpenGl_Mat4 aProjMat;
435   aModelMat.Convert (aContext->WorldViewState.Current() * aContext->ModelWorldState.Current());
436   aProjMat .Convert (aContext->ProjectionState.Current());
437
438   // Get the window's (fixed) coordinates for before matrices modifications
439   OpenGl_Vec3 aEndPoint = -anAxis.Direction * myData.ArrowsLength();
440   OpenGl_Vec3 aWinPoint;
441   Graphic3d_TransformUtils::Project<Standard_ShortReal> (aEndPoint.x(), aEndPoint.y(), aEndPoint.z(),
442                                                          aModelMat, aProjMat, aContext->Viewport(),
443                                                          aWinPoint.x(), aWinPoint.y(), aWinPoint.z());
444
445   aContext->ModelWorldState.SetIdentity();
446   aModelMat.Convert (aContext->WorldViewState.Current());
447   aProjMat .Convert (aContext->ProjectionState.Current());
448
449   // Get start point of zoom persistent arrow
450   OpenGl_Vec3 anArrowStart;
451   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> (aWinPoint.x(), aWinPoint.y(), aWinPoint.z(),
452                                                            aModelMat, aProjMat, aContext->Viewport(),
453                                                            anArrowStart.x(), anArrowStart.y(), anArrowStart.z());
454   // Render axis line
455   aModelMat = theMat;
456   Graphic3d_TransformUtils::Translate (aModelMat, myMin.x(), myMin.y(), myMin.z());
457
458   Standard_ShortReal aScaleFactor = ( (anArrowStart - myMin)*anAxis.Direction ).Modulus()
459                                      / (anAxis.Direction * (myMax - myMin) ).Modulus();
460   OpenGl_Vec3 aScaleAxes = anAxis.Direction * aScaleFactor;
461   Graphic3d_TransformUtils::Scale (aModelMat, aScaleAxes.x(), aScaleAxes.y(), aScaleAxes.z());
462
463   aContext->WorldViewState.SetCurrent (aModelMat);
464   aContext->ApplyWorldViewMatrix();
465   anAxis.Line.Render (theWorkspace);
466 }
467
468 // =======================================================================
469 // function : renderTickmarkTextLabels
470 // purpose  :
471 // =======================================================================
472 void OpenGl_GraduatedTrihedron::renderTickmarkLabels (const Handle(OpenGl_Workspace)& theWorkspace,
473                                                       const OpenGl_Mat4& theMat,
474                                                       const Standard_Integer theIndex,
475                                                       const GridAxes& theGridAxes,
476                                                       const Standard_ShortReal theDpix) const
477 {
478   const Graphic3d_AxisAspect& aCurAspect = myData.AxisAspect (theIndex);
479   if (!aCurAspect.ToDrawName() && !aCurAspect.ToDrawValues())
480   {
481     return;
482   }
483
484   Standard_Character aTextValue[128];
485   const Axis& anAxis = myAxes[theIndex];
486   const OpenGl_Vec3 aSizeVec (myMax - myMin);
487   Standard_ShortReal aStep = theGridAxes.Axes[theIndex].GetData()[theIndex]
488                        * (myMax.GetData()[theIndex] - myMin.GetData()[theIndex]) / aCurAspect.TickmarksNumber();
489
490   OpenGl_Vec3 aDir = (theGridAxes.Ticks[theIndex] - theGridAxes.Origin).Normalized();
491   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
492
493   if (aCurAspect.ToDrawTickmarks() && aCurAspect.TickmarksNumber() > 0)
494   {
495     theWorkspace->SetAspects (&myGridLineAspect);
496
497     OpenGl_Mat4 aModelMat (theMat);
498
499     anAxis.InitTickmark (aContext, aDir * (Standard_ShortReal) aCurAspect.TickmarksLength() * theDpix);
500     Graphic3d_TransformUtils::Translate (aModelMat, theGridAxes.Ticks[theIndex].x(),
501                                                     theGridAxes.Ticks[theIndex].y(),
502                                                     theGridAxes.Ticks[theIndex].z());
503     aContext->WorldViewState.SetCurrent (aModelMat);
504     aContext->ApplyWorldViewMatrix();
505     OpenGl_Vec3 aStepVec = anAxis.Direction * aStep;
506     for (Standard_Integer anIter = 0; anIter <= aCurAspect.TickmarksNumber(); ++anIter)
507     {
508       anAxis.Tickmark.Render (theWorkspace);
509       Graphic3d_TransformUtils::Translate (aModelMat, aStepVec.x(), aStepVec.y(), aStepVec.z());
510       aContext->WorldViewState.SetCurrent (aModelMat);
511       aContext->ApplyWorldViewMatrix();
512     }
513   }
514
515   // Restore matrix
516   aContext->WorldViewState.SetCurrent (theMat);
517   aContext->ApplyWorldViewMatrix();
518
519   if (aCurAspect.ToDrawName())
520   {
521     Standard_Real anOffset = aCurAspect.NameOffset() + aCurAspect.TickmarksLength();
522
523     OpenGl_Vec3 aMiddle (theGridAxes.Ticks[theIndex] + aSizeVec * theGridAxes.Axes[theIndex] * 0.5f + aDir * (Standard_ShortReal)(theDpix * anOffset));
524
525     myAspectLabels.Aspect()->SetColor (anAxis.NameColor);
526     theWorkspace->SetAspects (&myAspectLabels);
527     anAxis.Label.Text()->SetPosition (gp_Pnt (aMiddle.x(), aMiddle.y(), aMiddle.z()));
528     anAxis.Label.Render (theWorkspace);
529   }
530
531   if (aCurAspect.ToDrawValues() && aCurAspect.TickmarksNumber() > 0)
532   {
533     myAspectValues.Aspect()->SetColor (anAxis.LineAspect.Aspect()->Color());
534     theWorkspace->SetAspects (&myAspectValues);
535     Standard_Real anOffset = aCurAspect.ValuesOffset() + aCurAspect.TickmarksLength();
536
537     for (Standard_Integer anIt = 0; anIt <= aCurAspect.TickmarksNumber(); ++anIt)
538     {
539       sprintf (aTextValue, "%g", theGridAxes.Ticks[theIndex].GetData()[theIndex] + anIt * aStep);
540       OpenGl_Vec3 aPos (theGridAxes.Ticks[theIndex] + anAxis.Direction* (Standard_ShortReal) (anIt * aStep) + aDir * (Standard_ShortReal) (theDpix * anOffset));
541
542       Handle(Graphic3d_Text) aText = myLabelValues.Text();
543       aText->SetText (aTextValue);
544       aText->SetPosition (gp_Pnt(aPos.x(), aPos.y(), aPos.z()));
545
546       myLabelValues.Reset (theWorkspace->GetGlContext());
547       myLabelValues.Render (theWorkspace);
548     }
549   }
550 }
551
552 // =======================================================================
553 // function : Render
554 // purpose  : call_graduatedtrihedron_redraw
555 // =======================================================================
556 void OpenGl_GraduatedTrihedron::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
557 {
558   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
559   if (!myIsInitialized)
560   {
561     initGlResources (theWorkspace->GetGlContext());
562     myIsInitialized = Standard_True;
563   }
564
565   // Update boundary box
566   OpenGl_Vec3 anOldMin = myMin;
567   OpenGl_Vec3 anOldMax = myMax;
568
569   if (myData.CubicAxesCallback)
570   {
571     myData.CubicAxesCallback (myData.PtrView);
572     if (!myAxes[0].Line.IsInitialized()
573      || !myAxes[1].Line.IsInitialized()
574      || !myAxes[2].Line.IsInitialized()
575      ||  OpenGl_Vec3 (anOldMin - myMin).Modulus() > Precision::Confusion()
576      ||  OpenGl_Vec3 (anOldMax - myMax).Modulus() > Precision::Confusion())
577     {
578       myAxes[0].InitLine (aContext, OpenGl_Vec3 (myMax.x() - myMin.x(), 0.0f, 0.0f));
579       myAxes[1].InitLine (aContext, OpenGl_Vec3 (0.0f, myMax.y() - myMin.y(), 0.0f));
580       myAxes[2].InitLine (aContext, OpenGl_Vec3 (0.0f, 0.0f, myMax.z() - myMin.z()));
581     }
582   }
583
584   // Find the farest point of bounding box
585
586   // Get normal of the view out of user and distance corresponding to 1 pixel
587   OpenGl_Vec3 aNormal;
588   Standard_ShortReal aDpix = getNormal (aContext, aNormal);
589   aNormal.Normalize();
590
591   // Get central point of bounding box
592   OpenGl_Vec3 aCenter;
593   aCenter = (myMin + myMax) * 0.5f;
594
595   // Check distance to corners of bounding box along the normal
596   Standard_ShortReal aCorners[8];
597   aCorners[0] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMin.y(), myMin.z());
598   aCorners[1] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMin.y(), myMax.z());
599   aCorners[2] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMax.y(), myMin.z());
600   aCorners[3] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMax.y(), myMax.z());
601   aCorners[4] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMin.y(), myMin.z());
602   aCorners[5] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMin.y(), myMax.z());
603   aCorners[6] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMax.y(), myMin.z());
604   aCorners[7] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMax.y(), myMax.z());
605
606   // NOTE:
607   // (0, 0, 1), (0, 1, 0) and (0, 0, 1) directions from (myMin.x(), Ymin, Zmin) point
608   // are reserved for trihedron axes.
609   // So for the grid here are 9 edges of cube,
610   // and, depending on the farest point, 2 or 3 of them may not be drawn
611   // if they overlap displayed model.
612   
613   // Write an axes state what axes of bounding box are to be drawn
614   GridAxes aGridAxes;
615   Standard_ExtCharacter anAxesState = getGridAxes (aCorners, aGridAxes);
616
617   // Remember current aspects
618   const OpenGl_Aspects* anOldAspectLine = theWorkspace->Aspects();
619
620   OpenGl_Mat4 aModelMatrix;
621   aModelMatrix.Convert (aContext->WorldViewState.Current());
622
623   // Remember model-view matrix
624   aContext->WorldViewState.Push();
625   aContext->WorldViewState.SetCurrent (aModelMatrix);
626   aContext->ApplyWorldViewMatrix();
627
628   if (myData.ToDrawGrid())
629   {
630     theWorkspace->SetAspects (&myGridLineAspect);
631
632     // render grid edges
633     if (anAxesState & XOO_XYO)
634     {
635       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMin.z());
636     }
637
638     if (anAxesState & XOO_XOZ)
639     {
640       renderLine (myAxes[2].Line,theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMin.z());
641     }
642
643     if (anAxesState & OYO_OYZ)
644     {
645       renderLine (myAxes[2].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMin.z());
646     }
647
648     if (anAxesState & OYO_XYO)
649     {
650       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMin.z());
651     }
652
653     if (anAxesState & OOZ_XOZ)
654     {
655       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.z(), myMin.y(), myMax.z());
656     }
657
658     if (anAxesState & OOZ_OYZ)
659     {
660       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMin.x(), myMin.y(), myMax.z());
661     }
662
663     if (anAxesState & OYZ_XYZ)
664     {
665       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMax.z());
666     }
667
668     if (anAxesState & XOZ_XYZ)
669     {
670       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMax.z());
671     }
672
673     if (anAxesState & XYO_XYZ)
674     {
675       renderLine (myAxes[2].Line, theWorkspace, aModelMatrix, myMax.x(), myMax.y(), myMin.z());
676     }
677
678     for (Standard_Integer anIter = 0 ; anIter < 3; ++anIter)
679     {
680       renderGridPlane (theWorkspace, anIter, aGridAxes, aModelMatrix);
681     }
682   }
683
684   // Axes (arrows)
685   if (myData.ToDrawAxes())
686   {
687     for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
688     {
689       renderAxis (theWorkspace, anIter, aModelMatrix);
690     }
691   }
692
693   // Names of axes & values
694   for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
695   {
696     // Restore current matrix
697     aContext->WorldViewState.SetCurrent (aModelMatrix);
698     aContext->ApplyWorldViewMatrix();
699     renderTickmarkLabels (theWorkspace, aModelMatrix, anIter, aGridAxes, aDpix);
700   }
701
702   theWorkspace->SetAspects (anOldAspectLine);
703
704   aContext->WorldViewState.Pop();
705   aContext->ApplyWorldViewMatrix();
706 }
707
708 // =======================================================================
709 // method  : SetMinMax
710 // purpose :
711 // =======================================================================
712 void OpenGl_GraduatedTrihedron::SetMinMax (const OpenGl_Vec3& theMin, const OpenGl_Vec3& theMax)
713 {
714   myMin = theMin;
715   myMax = theMax;
716 }
717
718 // =======================================================================
719 // method  : OpenGl_GraduatedTrihedron::Axis constructor
720 // purpose :
721 // =======================================================================
722 OpenGl_GraduatedTrihedron::Axis::Axis (const Graphic3d_AxisAspect& theAspect,
723                                        const OpenGl_Vec3&          theDirection)
724 : Direction (theDirection),
725   Tickmark  (NULL),
726   Line      (NULL),
727   Arrow     (NULL)
728 {
729   Handle(Graphic3d_Text) aText = new Graphic3d_Text (THE_LABEL_HEIGHT);
730   aText->SetText ((Standard_Utf16Char* )theAspect.Name().ToExtString());
731   aText->SetPosition (gp_Pnt (theDirection.x(), theDirection.y(), theDirection.z()));
732   aText->SetHorizontalAlignment (THE_LABEL_HALIGH);
733   aText->SetVerticalAlignment (THE_LABEL_VALIGH);
734   Label = OpenGl_Text (aText);
735   NameColor = theAspect.NameColor();
736   LineAspect.Aspect()->SetColor (theAspect.Color());
737 }
738
739 // =======================================================================
740 // method  : OpenGl_GraduatedTrihedron::Axis::~Axis
741 // purpose :
742 // =======================================================================
743 OpenGl_GraduatedTrihedron::Axis::~Axis()
744 {
745   //
746 }
747
748 // =======================================================================
749 // method  : OpenGl_GraduatedTrihedron::Axis operator=
750 // purpose :
751 // =======================================================================
752 OpenGl_GraduatedTrihedron::Axis& OpenGl_GraduatedTrihedron::Axis::operator= (const Axis& theOther)
753 {
754   Direction  = theOther.Direction;
755   NameColor  = theOther.NameColor;
756   LineAspect = theOther.LineAspect;
757   Label      = theOther.Label;
758
759   Line    .InitBuffers (NULL, Graphic3d_TOPA_SEGMENTS,  theOther.Line.Indices(),     theOther.Line.Attributes(),     theOther.Line.Bounds());
760   Tickmark.InitBuffers (NULL, Graphic3d_TOPA_SEGMENTS,  theOther.Tickmark.Indices(), theOther.Tickmark.Attributes(), theOther.Tickmark.Bounds());
761   Arrow   .InitBuffers (NULL, Graphic3d_TOPA_POLYLINES, theOther.Arrow.Indices(),    theOther.Arrow.Attributes(),    theOther.Arrow.Bounds());
762   return *this;
763 }
764
765 // =======================================================================
766 // method  : InitArrow
767 // purpose :
768 // =======================================================================
769 void OpenGl_GraduatedTrihedron::Axis::InitArrow (const Handle(OpenGl_Context)& theContext,
770                                                  const Standard_ShortReal theLength,
771                                                  const OpenGl_Vec3& theNormal) const
772 {
773   // Draw from the end point of the aris
774   OpenGl_Vec3 aLengthVec = -Direction * theLength;
775
776   // Radial direction to the arrow
777   OpenGl_Vec3 aRadial = OpenGl_Vec3::Cross (this->Direction, theNormal);
778   if (aRadial.Modulus() < (Standard_ShortReal) Precision::Confusion())
779   {
780     return;
781   }
782   aRadial = aRadial.Normalized() * theLength * 0.2f;
783
784   // Initialize arrow primitive array
785   // Make loop from polyline
786   const OpenGl_Vec3 aPoint1 = aRadial + aLengthVec;
787   const OpenGl_Vec3 aPoint2 (0.0f, 0.0f, 0.0f);
788   const OpenGl_Vec3 aPoint3 = -aRadial + aLengthVec;
789
790   Handle(Graphic3d_ArrayOfPolylines) anArray = new Graphic3d_ArrayOfPolylines (4);
791   anArray->AddVertex (aPoint1);
792   anArray->AddVertex (aPoint2);
793   anArray->AddVertex (aPoint3);
794   anArray->AddVertex (aPoint1);
795
796   Arrow.InitBuffers (theContext, Graphic3d_TOPA_POLYLINES,
797                      anArray->Indices(), anArray->Attributes(), anArray->Bounds());
798 }
799
800 // =======================================================================
801 // function : InitTickmark
802 // purpose  :
803 // =======================================================================
804 void OpenGl_GraduatedTrihedron::Axis::InitTickmark (const Handle(OpenGl_Context)& theContext,
805                                                     const OpenGl_Vec3& theDir) const
806 {
807
808   Handle(Graphic3d_ArrayOfSegments) anArray = new Graphic3d_ArrayOfSegments (2);
809   anArray->AddVertex (0.0f, 0.0f, 0.0f);
810   anArray->AddVertex (theDir);
811   Tickmark.InitBuffers (theContext, Graphic3d_TOPA_SEGMENTS,
812                         anArray->Indices(), anArray->Attributes(), anArray->Bounds());
813
814 }
815
816 // =======================================================================
817 // function : InitLine
818 // purpose  :
819 // =======================================================================
820 void OpenGl_GraduatedTrihedron::Axis::InitLine (const Handle(OpenGl_Context)& theContext,
821                                                 const OpenGl_Vec3& theDir) const
822 {
823
824   Handle(Graphic3d_ArrayOfSegments) anArray = new Graphic3d_ArrayOfSegments (2);
825   anArray->AddVertex (0.0f, 0.0f, 0.0f);
826   anArray->AddVertex (theDir);
827
828   Line.InitBuffers (theContext, Graphic3d_TOPA_SEGMENTS,
829                     anArray->Indices(), anArray->Attributes(), anArray->Bounds());
830 }
831
832 // =======================================================================
833 // function : Release
834 // purpose  :
835 // =======================================================================
836 void OpenGl_GraduatedTrihedron::Axis::Release (OpenGl_Context* theCtx)
837 {
838   Label   .Release (theCtx);
839   Tickmark.Release (theCtx);
840   Line    .Release (theCtx);
841   Arrow   .Release (theCtx);
842 }
843
844 // =======================================================================
845 // function : DumpJson
846 // purpose  :
847 // =======================================================================
848 void OpenGl_GraduatedTrihedron::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
849 {
850   OCCT_DUMP_CLASS_BEGIN (theOStream, OpenGl_GraduatedTrihedron)
851
852   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, OpenGl_Element)
853 }