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