0024228: TKOpenGL - destroy GL context at view close
[occt.git] / src / OpenGl / OpenGl_telem_view.cxx
1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
2 //
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
7 //
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
10 //
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
17
18 /***********************************************************************
19
20 FONCTION :
21 ----------
22 File OpenGl_telem_view :
23
24 ************************************************************************/
25
26 #include <OpenGl_GlCore11.hxx>
27 #include <OpenGl_telem_view.hxx>
28 #include <OpenGl_telem_util.hxx>
29 #include <OpenGl_Display.hxx>
30
31 static  void
32 EvalViewMappingMatrix (const Handle(OpenGl_Display)& theGlDisplay,
33                        tel_view_mapping mapping /* View Mapping */,
34                        Tint* error_ind          /* Out: Error Indicator */,
35                        Tmatrix3 mat             /* Out: Mapping Matrix * */,
36                        Tint     flag,
37                        Tfloat   cx,
38                        Tfloat   cy,
39                        Tint     /*clip_flag*/,
40                        Tlimit3* /*clip_limit*/
41                       )
42 {
43   Tfloat    gx, gy, xsf, ysf, zsf;
44   Tfloat    fpd, bpd;
45
46   /* OCC18942 */
47   Tfloat    n, f, r, l, t, b, Zprp, dx, dy, VPD;
48
49   /* FSXXX */
50   /* GLint gdtmp; */
51   Tlimit3   vp = { ( float )-1.0, ( float )1.0, ( float )-1.0, ( float )1.0, ( float )1.0, ( float )-1.0 };
52   Tmatrix3  pmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
53   { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
54   { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
55   { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
56   Tmatrix3  mmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
57   { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
58   { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
59   { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
60
61   fpd = mapping->fpd;
62   bpd = mapping->bpd;
63
64   /* invalid window */
65   if( mapping->window.xmin >= mapping->window.xmax ||
66     mapping->window.ymin >= mapping->window.ymax )
67   {
68     *error_ind = 1;    
69     return;
70   }
71
72   /* invalid viewport */
73   if( mapping->viewport.xmin >= mapping->viewport.xmax ||
74     mapping->viewport.ymin >= mapping->viewport.ymax ||
75     mapping->viewport.zmin >= mapping->viewport.zmax )
76   {
77     *error_ind = 2;   
78     return;
79   }
80
81   /* invalid back/front plane distances */
82   if( mapping->bpd >= mapping->fpd )
83   {
84     *error_ind = 3;   
85     return;
86   }
87
88   /* prp between front and back planes */
89   if (theGlDisplay.IsNull() || !theGlDisplay->Walkthrough())
90   {
91     if( mapping->prp[2] < mapping->fpd &&
92       mapping->prp[2] > mapping->bpd )
93     {
94       *error_ind = 4;   
95       return;
96     } 
97   }
98
99   if( mapping->prp[2] == mapping->vpd )
100   {
101     *error_ind = 5;   /* prp on view plane */
102     return;
103   }
104
105   if( mapping->viewport.xmin < 0 ||
106     mapping->viewport.xmax > 1 ||
107     mapping->viewport.ymin < 0 ||
108     mapping->viewport.ymax > 1 ||
109     mapping->viewport.zmin < 0 ||
110     mapping->viewport.zmax > 1 )
111   {
112     *error_ind = 6;   /* viewport limits outside NPC space */
113     return;
114   }
115
116   *error_ind = 0;
117
118   /* OCC18942: Moved here while debugging perspective projection matrix */
119   /* centers */
120   if( flag == 0 )
121   {
122     cx = mapping->window.xmin + mapping->window.xmax, cx /= ( float )2.0;
123     cy = mapping->window.ymin + mapping->window.ymax, cy /= ( float )2.0;
124   }
125
126   gx = (cx - mapping->prp[0]) / (mapping->vpd - mapping->prp[2]);
127   gy = (cy - mapping->prp[1]) / (mapping->vpd - mapping->prp[2]);
128
129 #ifdef PRINT
130   printf("EvalViewMappingMatrix \n");
131   printf("prp %f %f %f \n", mapping->prp[0], mapping->prp[1], mapping->prp[2]);
132   printf("vpd fpd bpd %f %f %f \n", mapping->vpd, mapping->fpd, mapping->bpd);
133   printf("window limit %f %f %f %f\n", mapping->window.xmin, mapping->window.xmax, 
134     mapping->window.ymin, mapping->window.ymax);
135   printf("viewport limit %f %f %f %f\n", mapping->viewport.xmin, mapping->viewport.xmax, 
136     mapping->viewport.ymin, mapping->viewport.ymax);
137 #endif
138
139   /* projection matrix */
140   if( mapping->proj == TelParallel )
141   {
142
143     pmat[2][0] = -gx; pmat[3][0] = mapping->vpd*gx;
144     pmat[2][1] = -gy; pmat[3][1] = mapping->vpd*gy;
145   }
146   else if (!theGlDisplay.IsNull() && !theGlDisplay->SymPerspective())/* TelPerspective */
147   {
148     pmat[0][0] = pmat[1][1] = mapping->prp[2] - mapping->vpd;
149     pmat[2][0] = -gx; 
150     pmat[2][1] = -gy; 
151     pmat[2][3] = ( float )-1.0;
152     pmat[3][0] = mapping->vpd * gx; 
153     pmat[3][1] = mapping->vpd * gy; 
154     pmat[3][3] = mapping->prp[2];
155
156     /* modify the next two cells to change clipping policy */
157     if (!theGlDisplay.IsNull() && !theGlDisplay->Walkthrough())
158     {
159       pmat[2][2] = mapping->prp[2] - ( fpd + bpd );
160       pmat[3][2] = fpd * bpd; 
161     }
162   }
163   /* OCC18942: New approach to calculation of mapping (projection) matrix */
164   else 
165   {
166     dx = mapping->window.xmax - mapping->window.xmin;
167     dy = mapping->window.ymax - mapping->window.ymin;
168     Zprp = mapping->prp[2];
169     VPD = Zprp - mapping->vpd;
170
171     /* 
172     Calculate canonical perspective projection parameters as if we were about 
173     to use glFrustum() to create symmetric perspective frustum.
174
175     After the view orientation matrix is applied, the coordinate system origin is located 
176     at the VRP and oriented properly. However, the viewplane has width = dx and height = dy 
177     and its center (cx, cy, VPD) is not always located at the view Z axis.
178     The canonical perspective projection matrix assumes the eye is located at (0, 0, 0).
179     Thus the old approach resulted in a non-symmetric perspective, 
180     as X and Y coordinates of the projection reference point (PRP) were not updated
181     when cx and cy changed. Moreover, such "static" perspective had some other disadvantages,
182     such as non-realistic panning, i.e. instead of moving the eye (or camera) over the model
183     a sort of "frame" moved over the static perspective projection picture, 
184     exposing a part of this static picture to the user.
185
186     In order to make the perspective symmetric, we need to translate 
187     the coordinate system to PRP before projection.
188     Thus we translate X, Y and Z co-ordinates by -cx, -cy and -Zprp respectively.
189
190     NOTE: mat[i][j] means j-th element of i-th column, as OpenGL accepts the matrices
191     in column-major order, while in C two-dimensional arrays are stored in memory
192     in row-major order!
193
194     VPD is used below instead of near clipping plane dispance (n) in order to simplify 
195     calculation of l and r values. If we did not use VPD in the matrix calculation, we would have to 
196     project 0.5 * dx, -0.5 * dx, 0.5 * dy and - 0.5 * dy onto the near clipping plane 
197     to calculate these values.
198
199     Pending issues:
200     1. It is still necessary to find a way to calculate the perspective projection matrix 
201     for TPM_WALKTHROUGH projection model. This projection model is not supported yet 
202     by the new code.
203     */
204     r = .5f * dx;
205     l = -r;
206     t = .5f * dy;
207     b = -t;
208     n = Zprp - fpd; f = Zprp - bpd;
209
210     mat[0][0] = 2.f * VPD / (r - l);
211     mat[1][1] = 2.f * VPD / (t - b);
212     mat[2][0] = (r + l) / (r - l);
213     mat[2][1] = (t + b) / (t - b);
214     mat[2][2] = - (f + n) / (f - n);
215     mat[2][3] = -1.f;
216     /* 
217     The last column takes into account translation along X, Y and Z axis
218     before projecting. This can be considered as a result of right-multiplying the canonical 
219     perspective projection matrix P by a translation matrix T 
220     (it differs form the canonical matrix by the last column only):
221     | 1 0 0  -cx  |
222     | 0 1 0  -cy  |
223     mat = P * T, where T = | 0 0 1 -Zprp |
224     | 0 0 0   1   |
225     */
226     mat[3][0] = -mat[2][0] * Zprp - mat[0][0] * cx;
227     mat[3][1] = -mat[2][1] * Zprp - mat[1][1] * cy;
228     mat[3][2] = -2.f * f * n / (f - n) - mat[2][2] * Zprp;
229     mat[3][3] = Zprp;
230
231 #ifdef PRINT
232     printf("r l t b n f: %f %f %f %f %f %f \n", r,l,t,b,n,f);
233     printf( "mapping_matrix (new code):\n" );
234     pr_matrix(mat);
235 #endif
236
237     /* return here, as further calculations are related to the old approach */
238     return;
239   }
240
241   /* scale factors */
242   xsf = (vp.xmax - vp.xmin) / (mapping->window.xmax - mapping->window.xmin);
243   ysf = (vp.ymax - vp.ymin) / (mapping->window.ymax - mapping->window.ymin);
244   zsf = (vp.zmax - vp.zmin) / (fpd - bpd);
245
246   /* map matrix */
247   mmat[0][0] = xsf, mmat[1][1] = ysf, mmat[2][2] = zsf;
248   mmat[3][0] = vp.xmin - xsf*mapping->window.xmin;
249   mmat[3][1] = vp.ymin - ysf*mapping->window.ymin;
250   mmat[3][2] = vp.zmin - zsf*bpd;
251
252   /* multiply to obtain mapping matrix */
253   TelMultiplymat3( mat, pmat, mmat );
254
255 #ifdef PRINT
256   printf( "mapping_matrix :\n" );
257   pr_matrix(mat);
258 #endif
259 }
260
261 void
262 TelEvalViewOrientationMatrix( Tfloat *vrp    /* View Reference Point */,
263                               Tfloat *vpn    /* View Plane Normal */,
264                               Tfloat *vup    /* View Up Vector */,
265                               Tfloat *asf    /* Axial Scale Factors */,
266                               Tint *error_ind/* Out: Error indicator */,
267                               Tmatrix3  rmat  /* Out: Orientation Matrix  */
268                              )
269 {
270   Tfloat  u[3], v[3], n[3], f;
271
272   /* view plane normal of zero length */
273   if( vecmag(vpn) == 0.0 )
274   {
275     *error_ind = 1;   
276     return;
277   }
278
279   /* view up vector of zero length */
280   if( vecmag(vup) == 0.0 )
281   {
282     *error_ind = 2;    
283     return;
284   }
285
286   /* view up vector parallel to view plane normal */
287   vecang(vup, vpn, f);
288   if( f == 0.0 )
289   {
290     *error_ind = 3;    
291     return;
292   }
293
294   *error_ind = 0;
295
296   veccpy(n, vpn);
297   veccpy(v, vup);
298   vecnrm(n);  
299
300   veccrs(u,v,n);      /* up vector cross plane normal gives U axis */
301   vecnrm(u);
302
303   veccrs(v,n,u);      /* plane normal cross U axis gives modified up vector */
304   vecnrm(v); /* redundant ? */
305
306   /* rotate to align along u, v, n */
307   rmat[0][0] = ( float )u[0] * asf[0],
308     rmat[0][1] = ( float )v[0] * asf[0],
309     rmat[0][2] = ( float )n[0] * asf[0],
310     rmat[0][3] = ( float )0.0;
311
312   rmat[1][0] = ( float )u[1] * asf[1],
313     rmat[1][1] = ( float )v[1] * asf[1],
314     rmat[1][2] = ( float )n[1] * asf[1],
315     rmat[1][3] = ( float )0.0;
316
317   rmat[2][0] = ( float )u[2] * asf[2],
318     rmat[2][1] = ( float )v[2] * asf[2],
319     rmat[2][2] = ( float )n[2] * asf[2],
320     rmat[2][3] = ( float )0.0;
321
322   /* translate to centre at vrp */
323
324   rmat[3][0] = - ( float ) (u[0]*vrp[0] + u[1]*vrp[1] + u[2]*vrp[2]);
325   rmat[3][1] = - ( float ) (v[0]*vrp[0] + v[1]*vrp[1] + v[2]*vrp[2]);
326   rmat[3][2] = - ( float ) (n[0]*vrp[0] + n[1]*vrp[1] + n[2]*vrp[2]);
327   rmat[3][3] = ( float )1.0;
328
329 #ifdef PRINT
330   printf("TelEvalViewOrientationMatrix \n");
331   printf("view_ref_pt %f %f %f \n", vrp[0], vrp[1], vrp[2]);
332   printf("view_up_vec %f %f %f \n", vup[0], vup[1], vup[2]);
333   printf("view_plane_normal %f %f %f \n", vpn[0], vpn[1], vpn[2]);
334   pr_matrix(rmat);
335 #endif
336
337   return;
338 }
339
340 void TelEvalViewMappingMatrix (const Handle(OpenGl_Display)& theGlDisplay,
341                                tel_view_mapping mapping /* View Mapping */,
342                                Tint *error_ind          /* Out: Error Indicator */,
343                                Tmatrix3 mat             /* Out: Mapping Matrix */
344                                )
345 {
346   EvalViewMappingMatrix (theGlDisplay, mapping, error_ind, mat, 0, ( float )0.0, ( float )0.0, 0, 0);
347 }