OCC22144 NIS performance and memory usage update
[occt.git] / src / NIS / NIS_SurfaceDrawer.cxx
1 // File:      NIS_SurfaceDrawer.cpp
2 // Created:   20.03.08 09:09
3 // Author:    Alexander GRIGORIEV
4 // Copyright: Open Cascade S.A. 2008
5
6 #include <NIS_SurfaceDrawer.hxx>
7 #include <NIS_Surface.hxx>
8 #include <NIS_InteractiveObject.hxx>
9 #include <Standard_ProgramError.hxx>
10
11 #ifdef WNT
12 #include <windows.h>
13 #endif
14 #include <GL/gl.h>
15
16 static void setColor(GLenum               theFace,
17                      Quantity_Parameter * theAmbient,
18                      const Standard_Real  theSpecularity,
19                      GLint                theShininess);
20
21 IMPLEMENT_STANDARD_HANDLE  (NIS_SurfaceDrawer, NIS_Drawer)
22 IMPLEMENT_STANDARD_RTTIEXT (NIS_SurfaceDrawer, NIS_Drawer)
23
24 //=======================================================================
25 //function : NIS_SurfaceDrawer()
26 //purpose  : Constructor
27 //=======================================================================
28
29 NIS_SurfaceDrawer::NIS_SurfaceDrawer
30                                 (const Quantity_Color   &theNormal,
31                                  const Quantity_Color   &theHilight,
32                                  const Quantity_Color   &theDynHilight)
33   : myBackColor     (theNormal),
34     myPolygonOffset (0.f),
35     myIsWireframe   (Standard_False)
36 {
37   myColor[Draw_Normal]       = theNormal;
38   myColor[Draw_Top]          = theNormal;
39   myColor[Draw_Transparent]  = theNormal;
40   myColor[Draw_Hilighted]    = theHilight;
41   myColor[Draw_DynHilighted] = theDynHilight;
42 }
43
44 //=======================================================================
45 //function : SetColor
46 //purpose  : 
47 //=======================================================================
48
49 void NIS_SurfaceDrawer::SetColor(const Quantity_Color &theColor)
50 {
51   myColor[Draw_Normal]      = theColor;
52   myColor[Draw_Top]         = theColor;
53   myColor[Draw_Transparent] = theColor;
54 }
55
56 //=======================================================================
57 //function : Assign
58 //purpose  : 
59 //=======================================================================
60
61 void NIS_SurfaceDrawer::Assign (const Handle_NIS_Drawer& theOther)
62 {
63   if (theOther.IsNull() == Standard_False) {
64     NIS_Drawer::Assign (theOther);
65     const Handle(NIS_SurfaceDrawer)& anOther =
66       static_cast <const Handle(NIS_SurfaceDrawer)&> (theOther);
67     myColor[Draw_Normal]       = anOther->myColor[Draw_Normal];
68     myColor[Draw_Top]          = anOther->myColor[Draw_Top];
69     myColor[Draw_Transparent]  = anOther->myColor[Draw_Transparent];
70     myColor[Draw_Hilighted]    = anOther->myColor[Draw_Hilighted];
71     myColor[Draw_DynHilighted] = anOther->myColor[Draw_DynHilighted];
72     myBackColor                = anOther->myBackColor;
73     myPolygonOffset            = anOther->myPolygonOffset;
74     myIsWireframe              = anOther->myIsWireframe;
75   }
76 }
77
78 //=======================================================================
79 //function : IsEqual
80 //purpose  : Comparison of two Drawers (for Map impementation)
81 //=======================================================================
82
83 Standard_Boolean NIS_SurfaceDrawer::IsEqual
84                                 (const Handle_NIS_Drawer& theOther)const
85 {
86   static const Standard_Real       anEpsilon2 (1e-7);
87   Standard_Boolean                 aResult (Standard_False);
88   const Handle(NIS_SurfaceDrawer) anOther =
89                         Handle(NIS_SurfaceDrawer)::DownCast (theOther);
90   if (NIS_Drawer::IsEqual(theOther))
91     aResult = (anOther->myColor[Draw_Normal]
92                .SquareDistance (myColor[Draw_Normal]) < anEpsilon2 &&
93                anOther->myColor[Draw_Hilighted]
94                .SquareDistance (myColor[Draw_Hilighted]) < anEpsilon2 &&
95                anOther->myColor[Draw_DynHilighted]
96                .SquareDistance (myColor[Draw_DynHilighted]) < anEpsilon2 &&
97                anOther->myBackColor.SquareDistance(myBackColor) < anEpsilon2 &&
98                fabs(anOther->myPolygonOffset - myPolygonOffset) < 0.999 &&
99                myIsWireframe == anOther->myIsWireframe);
100   if (aResult) {
101     // Arbitrary point for test
102     gp_XYZ aPnt[2] = {
103       gp_XYZ(113., -31.3, 29.19),
104       gp_XYZ(113., -31.3, 29.19)
105     };
106     anOther->myTrsf.Transforms(aPnt[0]);
107     myTrsf.Transforms(aPnt[1]);
108     if ((aPnt[0] - aPnt[1]).SquareModulus() > anEpsilon2)
109       aResult = Standard_False;
110   }
111   return aResult;
112 }
113
114 //=======================================================================
115 //function : redraw
116 //purpose  : 
117 //=======================================================================
118
119 void NIS_SurfaceDrawer::redraw  (const DrawType         theType,
120                                  const Handle_NIS_View& theView)
121 {
122   glMatrixMode( GL_MODELVIEW );
123   glPushMatrix();
124
125   GLdouble aMatrix[16] = {
126     myTrsf.Value(1,1), myTrsf.Value(2,1), myTrsf.Value(3,1),  0.,
127     myTrsf.Value(1,2), myTrsf.Value(2,2), myTrsf.Value(3,2),  0.,
128     myTrsf.Value(1,3), myTrsf.Value(2,3), myTrsf.Value(3,3),  0.,
129     myTrsf.Value(1,4), myTrsf.Value(2,4), myTrsf.Value(3,4),  1.
130   };
131
132   glMultMatrixd( aMatrix );
133
134   NIS_Drawer::redraw(theType, theView);
135
136   glPopMatrix();
137 }
138
139 //=======================================================================
140 //function : BeforeDraw
141 //purpose  : 
142 //=======================================================================
143
144 void NIS_SurfaceDrawer::BeforeDraw (const DrawType      theType,
145                                     const NIS_DrawList&)
146 {
147   glEnable(GL_LIGHTING);
148   //  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
149   glEnableClientState (GL_VERTEX_ARRAY);
150   if (myIsWireframe == Standard_False) {
151     glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
152     glEnable(GL_POLYGON_OFFSET_FILL);
153     glShadeModel(GL_SMOOTH);
154   }
155
156   Quantity_Parameter   aValueCol[4] = {0., 0., 0., 1.};
157   Quantity_TypeOfColor bidTC (Quantity_TOC_RGB);
158   GLfloat aLineWidth (1.f);
159   GLfloat anOffset = myPolygonOffset;
160   static const GLfloat gColorN[4]  = {0.f, 0.f, 0.f, 1.f};
161
162   switch (theType) {
163   case Draw_DynHilighted:
164     aLineWidth = 3.f;
165     myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
166     setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.1, 5);
167     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]);
168     glLineWidth (aLineWidth);
169     if (myIsWireframe == Standard_False)
170       glPolygonOffset(1.f, -(anOffset + 11.f));
171     return;
172   case Draw_Hilighted:
173     anOffset += 10.f;
174   case Draw_Normal:
175   case Draw_Top:
176   case Draw_Transparent:
177     if (myIsWireframe == Standard_False) {
178       glPolygonOffset(1.f, -anOffset);
179       glEnableClientState (GL_NORMAL_ARRAY);
180     }
181     myColor[theType].Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
182     aValueCol[3] = 1. - myTransparency;
183     if (theType == Draw_Transparent) {
184       glEnable(GL_BLEND);
185       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
186       // don't write triangles into depth test
187       glDepthMask(GL_FALSE);
188     }
189     break;
190   default:
191     return;
192   }
193   //  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
194   if (theType == Draw_Hilighted ||
195       myBackColor.SquareDistance(myColor[Draw_Normal]) < 1.e-7)
196   {
197     setColor(GL_FRONT_AND_BACK, &aValueCol[0], 0.5, 10);
198   } else {
199     setColor(GL_FRONT, &aValueCol[0], 0.4, 10);
200     myBackColor.Values (aValueCol[0], aValueCol[1], aValueCol[2], bidTC);
201     setColor(GL_BACK, &aValueCol[0], 0.8, 5);
202   }
203   glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &gColorN[0]);
204   glLineWidth (aLineWidth);
205 }
206
207 //=======================================================================
208 //function : AfterDraw
209 //purpose  : 
210 //=======================================================================
211
212 void NIS_SurfaceDrawer::AfterDraw (const DrawType      theType,
213                                    const NIS_DrawList&)
214 {
215   glDisable(GL_LIGHTING);
216   glDisableClientState(GL_VERTEX_ARRAY);
217   switch (theType) {
218     case Draw_Transparent:
219       glDisable(GL_BLEND);
220       glDepthMask(GL_TRUE);
221     case Draw_Hilighted:
222     case Draw_Normal:
223     case Draw_Top:
224       if (myIsWireframe == Standard_False)
225         glDisableClientState(GL_NORMAL_ARRAY);
226     default:;
227   }
228   if (myIsWireframe == Standard_False)
229     glDisable(GL_POLYGON_OFFSET_FILL);
230 }
231
232 //=======================================================================
233 //function : Draw
234 //purpose  : 
235 //=======================================================================
236
237 void NIS_SurfaceDrawer::Draw (const Handle_NIS_InteractiveObject& theObj,
238                               const DrawType                      theType,
239                               const NIS_DrawList&)
240 {
241   // Assertion for the type of the drawn object
242 #ifdef _DEBUG
243   static const Handle(Standard_Type) ThisType = STANDARD_TYPE(NIS_Surface);
244   Standard_ProgramError_Raise_if (theObj->IsKind(ThisType) == Standard_False,
245                                   "NIS_Surface::Draw: irrelevant object type");
246 #endif
247   const NIS_Surface * pObject =
248     static_cast <const NIS_Surface *> (theObj.operator->());
249   glVertexPointer (3, GL_FLOAT, 0, pObject->Node(0));
250
251   // In Highlited mode the shape must be shown as wireframe 
252   Standard_Boolean isWireframe(myIsWireframe);
253   if (isWireframe == Standard_False && theType == Draw_DynHilighted)
254     if (pObject->NEdges() > 0)
255       isWireframe = Standard_True;
256
257   if (isWireframe)
258   {
259     for (Standard_Integer i = 0; i < pObject->NEdges(); i++) {
260       const GLint * pEdge = static_cast<const GLint *> (pObject->Edge(i));
261       glDrawElements (GL_LINE_STRIP, pEdge[0], GL_UNSIGNED_INT, &pEdge[1]);
262     }
263   } else {
264     if (pObject->NTriangles()) {
265       if (theType != Draw_DynHilighted)
266         glNormalPointer (GL_FLOAT, 0, pObject->Normal(0));
267       glDrawElements (GL_TRIANGLES, pObject->NTriangles()*3,
268                       GL_UNSIGNED_INT, pObject->Triangle(0));
269     }
270   }
271 }
272
273 //=======================================================================
274 //function : setColor
275 //purpose  : 
276 //=======================================================================
277
278 void setColor(GLenum               theFace,
279               Quantity_Parameter * theAmbient,
280               const Standard_Real  theSpecularity,
281               GLint                theShininess)
282 {
283   GLfloat aSpec = static_cast<GLfloat>(theSpecularity);
284   GLfloat aValueCol[4] = {
285     GLfloat(theAmbient[0]),
286     GLfloat(theAmbient[1]),
287     GLfloat(theAmbient[2]),
288     GLfloat(theAmbient[3])
289   };
290   glMaterialfv(theFace, GL_AMBIENT_AND_DIFFUSE, &aValueCol[0]);
291   aValueCol[0] = aSpec * (aValueCol[0] - 1.f) + 1.f;
292   aValueCol[1] = aSpec * (aValueCol[1] - 1.f) + 1.f;
293   aValueCol[2] = aSpec * (aValueCol[2] - 1.f) + 1.f;
294   aValueCol[3] = 1.f;
295   glMaterialfv(theFace, GL_SPECULAR, &aValueCol[0]);
296   glMateriali(theFace, GL_SHININESS, theShininess);
297 }
298