Cleanup: comment blocks
[blender.git] / source / blender / editors / space_view3d / view3d_project.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_project.c
28  *  \ingroup spview3d
29  */
30
31 #include "DNA_object_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_view3d_types.h"
35
36 #include "BLI_sys_types.h"  /* int64_t */
37
38 #include "BIF_gl.h"  /* bglMats */
39 #include "BIF_glutil.h"  /* bglMats */
40
41 #include "BLI_math_vector.h"
42
43 #include "BKE_screen.h"
44
45 #include "ED_view3d.h"  /* own include */
46
47 #define BL_NEAR_CLIP 0.001
48 #define BL_ZERO_CLIP 0.001
49
50 /* Non Clipping Projection Functions
51  * ********************************* */
52
53 /**
54  * \note use #ED_view3d_ob_project_mat_get to get the projection matrix
55  */
56 void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r_co[2], float mat[4][4])
57 {
58         float vec4[4];
59         
60         copy_v3_v3(vec4, co);
61         vec4[3] = 1.0;
62         /* r_co[0] = IS_CLIPPED; */ /* always overwritten */
63         
64         mul_m4_v4(mat, vec4);
65         
66         if (vec4[3] > FLT_EPSILON) {
67                 r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3];
68                 r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3];
69         }
70         else {
71                 zero_v2(r_co);
72         }
73 }
74
75 /**
76  * \note use #ED_view3d_ob_project_mat_get to get projecting mat
77  */
78 void ED_view3d_project_float_v3_m4(const ARegion *ar, const float vec[3], float r_co[3], float mat[4][4])
79 {
80         float vec4[4];
81         
82         copy_v3_v3(vec4, vec);
83         vec4[3] = 1.0;
84         /* r_co[0] = IS_CLIPPED; */ /* always overwritten */
85         
86         mul_m4_v4(mat, vec4);
87         
88         if (vec4[3] > FLT_EPSILON) {
89                 r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3];
90                 r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3];
91                 r_co[2] = vec4[2] / vec4[3];
92         }
93         else {
94                 zero_v3(r_co);
95         }
96 }
97
98
99 /* Clipping Projection Functions
100  * ***************************** */
101
102 eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base)
103 {
104         eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT);
105
106         if (ret != V3D_PROJ_RET_OK) {
107                 base->sx = IS_CLIPPED;
108                 base->sy = 0;
109         }
110
111         return ret;
112 }
113
114 /* perspmat is typically...
115  * - 'rv3d->perspmat',   is_local == false
116  * - 'rv3d->persmatob', is_local == true
117  */
118 static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar,
119                                                   float perspmat[4][4], const bool is_local,  /* normally hidden */
120                                                   const float co[3], float r_co[2], const eV3DProjTest flag)
121 {
122         float vec4[4];
123
124         /* check for bad flags */
125         BLI_assert((flag & V3D_PROJ_TEST_ALL) == flag);
126
127         if (flag & V3D_PROJ_TEST_CLIP_BB) {
128                 RegionView3D *rv3d = ar->regiondata;
129                 if (rv3d->rflag & RV3D_CLIPPING) {
130                         if (ED_view3d_clipping_test(rv3d, co, is_local)) {
131                                 return V3D_PROJ_RET_CLIP_BB;
132                         }
133                 }
134         }
135
136         copy_v3_v3(vec4, co);
137         vec4[3] = 1.0;
138         mul_m4_v4(perspmat, vec4);
139
140
141
142         if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) {
143                 if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0)  || (vec4[3] > (float)BL_NEAR_CLIP)) {
144                         const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]) : 0.0f;
145                         const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar));
146                         if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) {
147                                 const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar));
148                                 if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
149                                         r_co[0] = fx;
150                                         r_co[1] = fy;
151
152                                         /* check if the point is behind the view, we need to flip in this case */
153                                         if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) {
154                                                 negate_v2(r_co);
155                                         }
156                                 }
157                                 else {
158                                         return V3D_PROJ_RET_CLIP_WIN;
159                                 }
160                         }
161                         else {
162                                 return V3D_PROJ_RET_CLIP_WIN;
163                         }
164                 }
165                 else {
166                         return V3D_PROJ_RET_CLIP_NEAR;
167                 }
168         }
169         else {
170                 return V3D_PROJ_RET_CLIP_ZERO;
171         }
172
173         return V3D_PROJ_RET_OK;
174 }
175
176 eV3DProjStatus ED_view3d_project_short_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
177                                           const float co[3], short r_co[2], const eV3DProjTest flag)
178 {
179         float tvec[2];
180         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
181         if (ret == V3D_PROJ_RET_OK) {
182                 if ((tvec[0] > -32700.0f && tvec[0] < 32700.0f) &&
183                     (tvec[1] > -32700.0f && tvec[1] < 32700.0f))
184                 {
185                         r_co[0] = (short)floorf(tvec[0]);
186                         r_co[1] = (short)floorf(tvec[1]);
187                 }
188                 else {
189                         ret = V3D_PROJ_RET_OVERFLOW;
190                 }
191         }
192         return ret;
193 }
194
195 eV3DProjStatus ED_view3d_project_int_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
196                                         const float co[3], int r_co[2], const eV3DProjTest flag)
197 {
198         float tvec[2];
199         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
200         if (ret == V3D_PROJ_RET_OK) {
201                 if ((tvec[0] > -2140000000.0f && tvec[0] < 2140000000.0f) &&
202                     (tvec[1] > -2140000000.0f && tvec[1] < 2140000000.0f))
203                 {
204                         r_co[0] = (int)floorf(tvec[0]);
205                         r_co[1] = (int)floorf(tvec[1]);
206                 }
207                 else {
208                         ret = V3D_PROJ_RET_OVERFLOW;
209                 }
210         }
211         return ret;
212 }
213
214 eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4], const bool is_local,
215                                         const float co[3], float r_co[2], const eV3DProjTest flag)
216 {
217         float tvec[2];
218         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
219         if (ret == V3D_PROJ_RET_OK) {
220                 if (isfinite(tvec[0]) &&
221                     isfinite(tvec[1]))
222                 {
223                         copy_v2_v2(r_co, tvec);
224                 }
225                 else {
226                         ret = V3D_PROJ_RET_OVERFLOW;
227                 }
228         }
229         return ret;
230 }
231
232 /* --- short --- */
233 eV3DProjStatus ED_view3d_project_short_global(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
234 {
235         RegionView3D *rv3d = ar->regiondata;
236         return ED_view3d_project_short_ex(ar, rv3d->persmat, false, co, r_co, flag);
237 }
238 /* object space, use ED_view3d_init_mats_rv3d before calling */
239 eV3DProjStatus ED_view3d_project_short_object(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
240 {
241         RegionView3D *rv3d = ar->regiondata;
242         ED_view3d_check_mats_rv3d(rv3d);
243         return ED_view3d_project_short_ex(ar, rv3d->persmatob, true, co, r_co, flag);
244 }
245
246 /* --- int --- */
247 eV3DProjStatus ED_view3d_project_int_global(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
248 {
249         RegionView3D *rv3d = ar->regiondata;
250         return ED_view3d_project_int_ex(ar, rv3d->persmat, false, co, r_co, flag);
251 }
252 /* object space, use ED_view3d_init_mats_rv3d before calling */
253 eV3DProjStatus ED_view3d_project_int_object(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
254 {
255         RegionView3D *rv3d = ar->regiondata;
256         ED_view3d_check_mats_rv3d(rv3d);
257         return ED_view3d_project_int_ex(ar, rv3d->persmatob, true, co, r_co, flag);
258 }
259
260 /* --- float --- */
261 eV3DProjStatus ED_view3d_project_float_global(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
262 {
263         RegionView3D *rv3d = ar->regiondata;
264         return ED_view3d_project_float_ex(ar, rv3d->persmat, false, co, r_co, flag);
265 }
266 /* object space, use ED_view3d_init_mats_rv3d before calling */
267 eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
268 {
269         RegionView3D *rv3d = ar->regiondata;
270         ED_view3d_check_mats_rv3d(rv3d);
271         return ED_view3d_project_float_ex(ar, rv3d->persmatob, true, co, r_co, flag);
272 }
273
274
275
276 /* More Generic Window/Ray/Vector projection functions
277  * *************************************************** */
278
279 /**
280  * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
281  */
282 float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
283 {
284         float zfac = mul_project_m4_v3_zfac((float (*)[4])rv3d->persmat, co);
285
286         if (r_flip) {
287                 *r_flip = (zfac < 0.0f);
288         }
289
290         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
291          * (accounting for near zero values) */
292         if (zfac < 1.e-6f && zfac > -1.e-6f) {
293                 zfac = 1.0f;
294         }
295
296         /* Negative zfac means x, y, z was behind the camera (in perspective).
297          * This gives flipped directions, so revert back to ok default case. */
298         if (zfac < 0.0f) {
299                 zfac = -zfac;
300         }
301
302         return zfac;
303 }
304
305 static void view3d_win_to_ray_segment(
306         const ARegion *ar, const View3D *v3d, const float mval[2],
307         float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
308 {
309         RegionView3D *rv3d = ar->regiondata;
310         float _ray_co[3], _ray_dir[3], start_offset, end_offset;
311
312         if (!r_ray_co) r_ray_co = _ray_co;
313         if (!r_ray_dir) r_ray_dir = _ray_dir;
314
315         ED_view3d_win_to_origin(ar, mval, r_ray_co);
316         ED_view3d_win_to_vector(ar, mval, r_ray_dir);
317
318         if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) {
319                 end_offset = v3d->far / 2.0f;
320                 start_offset = -end_offset;
321         }
322         else {
323                 ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false);
324         }
325
326         if (r_ray_start) {
327                 madd_v3_v3v3fl(r_ray_start, r_ray_co, r_ray_dir, start_offset);
328         }
329         if (r_ray_end) {
330                 madd_v3_v3v3fl(r_ray_end, r_ray_co, r_ray_dir, end_offset);
331         }
332 }
333
334 bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
335 {
336         if ((rv3d->rflag & RV3D_CLIPPING) &&
337             (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
338                                      ray_start, ray_end) == false))
339         {
340                 return false;
341         }
342         return true;
343 }
344
345 /**
346  * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
347  * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
348  * ray_start is clipped by the view near limit so points in front of it are always in view.
349  * In orthographic view the resulting ray_normal will match the view vector.
350  * This version also returns the ray_co point of the ray on window plane, useful to fix precision
351  * issues esp. with ortho view, where default ray_start is set rather far away.
352  * \param ar The region (used for the window width and height).
353  * \param v3d The 3d viewport (used for near clipping value).
354  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
355  * \param r_ray_co The world-space point where the ray intersects the window plane.
356  * \param r_ray_normal The normalized world-space direction of towards mval.
357  * \param r_ray_start The world-space starting point of the ray.
358  * \param do_clip Optionally clip the start of the ray by the view clipping planes.
359  * \return success, false if the ray is totally clipped.
360  */
361 bool ED_view3d_win_to_ray_ex(
362         const ARegion *ar, const View3D *v3d, const float mval[2],
363         float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
364 {
365         float ray_end[3];
366
367         view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
368
369         /* bounds clipping */
370         if (do_clip) {
371                 return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
372         }
373
374         return true;
375 }
376
377 /**
378  * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
379  * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
380  * ray_start is clipped by the view near limit so points in front of it are always in view.
381  * In orthographic view the resulting ray_normal will match the view vector.
382  * \param ar The region (used for the window width and height).
383  * \param v3d The 3d viewport (used for near clipping value).
384  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
385  * \param r_ray_start The world-space point where the ray intersects the window plane.
386  * \param r_ray_normal The normalized world-space direction of towards mval.
387  * \param do_clip Optionally clip the start of the ray by the view clipping planes.
388  * \return success, false if the ray is totally clipped.
389  */
390 bool ED_view3d_win_to_ray(
391         const ARegion *ar, const View3D *v3d, const float mval[2],
392         float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
393 {
394         return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
395 }
396
397 /**
398  * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
399  * In orthographic view the resulting vector will match the view vector.
400  * \param rv3d The region (used for the window width and height).
401  * \param coord The world-space location.
402  * \param vec The resulting normalized vector.
403  */
404 void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3])
405 {
406         if (rv3d->is_persp) {
407                 float p1[4], p2[4];
408
409                 copy_v3_v3(p1, coord);
410                 p1[3] = 1.0f;
411                 copy_v3_v3(p2, p1);
412                 p2[3] = 1.0f;
413                 mul_m4_v4((float (*)[4])rv3d->viewmat, p2);
414
415                 mul_v3_fl(p2, 2.0f);
416
417                 mul_m4_v4((float (*)[4])rv3d->viewinv, p2);
418
419                 sub_v3_v3v3(vec, p1, p2);
420         }
421         else {
422                 copy_v3_v3(vec, rv3d->viewinv[2]);
423         }
424         normalize_v3(vec);
425 }
426
427 /* very similar to ED_view3d_win_to_3d() but has no advantage, de-duplicating */
428 #if 0
429 bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval[2], const bool do_fallback)
430 {
431         RegionView3D *rv3d = ar->regiondata;
432         float dvec[3];
433         int mval_cpy[2];
434         eV3DProjStatus ret;
435
436         ret = ED_view3d_project_int_global(ar, fp, mval_cpy, V3D_PROJ_TEST_NOP);
437
438         if (ret == V3D_PROJ_RET_OK) {
439                 const float mval_f[2] = {(float)(mval_cpy[0] - mval[0]),
440                                          (float)(mval_cpy[1] - mval[1])};
441                 const float zfac = ED_view3d_calc_zfac(rv3d, fp, NULL);
442                 ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
443                 sub_v3_v3(fp, dvec);
444
445                 return true;
446         }
447         else {
448                 /* fallback to the view center */
449                 if (do_fallback) {
450                         negate_v3_v3(fp, rv3d->ofs);
451                         return view3d_get_view_aligned_coordinate(ar, fp, mval, false);
452                 }
453                 else {
454                         return false;
455                 }
456         }
457 }
458 #endif
459
460 /**
461  * Calculate a 3d location from 2d window coordinates.
462  * \param ar The region (used for the window width and height).
463  * \param depth_pt The reference location used to calculate the Z depth.
464  * \param mval The area relative location (such as event->mval converted to floats).
465  * \param out The resulting world-space location.
466  */
467 void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
468 {
469         RegionView3D *rv3d = ar->regiondata;
470
471         float ray_origin[3];
472         float ray_direction[3];
473         float lambda;
474
475         if (rv3d->is_persp) {
476                 float plane[4];
477
478                 copy_v3_v3(ray_origin, rv3d->viewinv[3]);
479                 ED_view3d_win_to_vector(ar, mval, ray_direction);
480
481                 /* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the
482                  * view no matter what, so apply the unsigned factor instead */
483                 plane_from_point_normal_v3(plane, depth_pt, rv3d->viewinv[2]);
484
485                 isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, false);
486                 lambda = fabsf(lambda);
487         }
488         else {
489                 float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
490                 float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f;
491                 if (rv3d->persp == RV3D_CAMOB) {
492                         /* ortho camera needs offset applied */
493                         const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f;
494                         dx += rv3d->camdx * zoomfac;
495                         dy += rv3d->camdy * zoomfac;
496                 }
497                 ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
498                 ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
499                 ray_origin[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
500
501                 copy_v3_v3(ray_direction, rv3d->viewinv[2]);
502                 lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction);
503         }
504
505         madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda);
506 }
507
508 void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3])
509 {
510         const float mval_fl[2] = {mval[0], mval[1]};
511         ED_view3d_win_to_3d(ar, depth_pt, mval_fl, out);
512 }
513
514 /**
515  * Calculate a 3d difference vector from 2d window offset.
516  * note that ED_view3d_calc_zfac() must be called first to determine
517  * the depth used to calculate the delta.
518  * \param ar The region (used for the window width and height).
519  * \param mval The area relative 2d difference (such as event->mval[0] - other_x).
520  * \param out The resulting world-space delta.
521  */
522 void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3], const float zfac)
523 {
524         RegionView3D *rv3d = ar->regiondata;
525         float dx, dy;
526         
527         dx = 2.0f * mval[0] * zfac / ar->winx;
528         dy = 2.0f * mval[1] * zfac / ar->winy;
529         
530         out[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy);
531         out[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy);
532         out[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy);
533 }
534
535 /**
536  * Calculate a 3d origin from 2d window coordinates.
537  * \note Orthographic views have a less obvious origin,
538  * Since far clip can be a very large value resulting in numeric precision issues,
539  * the origin in this case is close to zero coordinate.
540  *
541  * \param ar The region (used for the window width and height).
542  * \param mval The area relative 2d location (such as event->mval converted to floats).
543  * \param out The resulting normalized world-space direction vector.
544  */
545 void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3])
546 {
547         RegionView3D *rv3d = ar->regiondata;
548         if (rv3d->is_persp) {
549                 copy_v3_v3(out, rv3d->viewinv[3]);
550         }
551         else {
552                 out[0] = 2.0f * mval[0] / ar->winx - 1.0f;
553                 out[1] = 2.0f * mval[1] / ar->winy - 1.0f;
554
555                 if (rv3d->persp == RV3D_CAMOB) {
556                         out[2] = -1.0f;
557                 }
558                 else {
559                         out[2] = 0.0f;
560                 }
561
562                 mul_project_m4_v3(rv3d->persinv, out);
563         }
564 }
565
566 /**
567  * Calculate a 3d direction vector from 2d window coordinates.
568  * This direction vector starts and the view in the direction of the 2d window coordinates.
569  * In orthographic view all window coordinates yield the same vector.
570  *
571  * \note doesn't rely on ED_view3d_calc_zfac
572  * for perspective view, get the vector direction to
573  * the mouse cursor as a normalized vector.
574  *
575  * \param ar The region (used for the window width and height).
576  * \param mval The area relative 2d location (such as event->mval converted to floats).
577  * \param out The resulting normalized world-space direction vector.
578  */
579 void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3])
580 {
581         RegionView3D *rv3d = ar->regiondata;
582
583         if (rv3d->is_persp) {
584                 out[0] = 2.0f * (mval[0] / ar->winx) - 1.0f;
585                 out[1] = 2.0f * (mval[1] / ar->winy) - 1.0f;
586                 out[2] = -0.5f;
587                 mul_project_m4_v3(rv3d->persinv, out);
588                 sub_v3_v3(out, rv3d->viewinv[3]);
589         }
590         else {
591                 negate_v3_v3(out, rv3d->viewinv[2]);
592         }
593         normalize_v3(out);
594 }
595
596 /**
597  * Calculate a 3d segment from 2d window coordinates.
598  * This ray_start is located at the viewpoint, ray_end is a far point.
599  * ray_start and ray_end are clipped by the view near and far limits
600  * so points along this line are always in view.
601  * In orthographic view all resulting segments will be parallel.
602  * \param ar The region (used for the window width and height).
603  * \param v3d The 3d viewport (used for near and far clipping range).
604  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
605  * \param r_ray_start The world-space starting point of the segment.
606  * \param r_ray_end The world-space end point of the segment.
607  * \param do_clip Optionally clip the ray by the view clipping planes.
608  * \return success, false if the segment is totally clipped.
609  */
610 bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2],
611                               float r_ray_start[3], float r_ray_end[3], const bool do_clip)
612 {
613         view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
614
615         /* bounds clipping */
616         if (do_clip) {
617                 return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
618         }
619
620         return true;
621 }
622
623 /* Utility functions for projection
624  * ******************************** */
625
626 void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pmat[4][4])
627 {
628         float vmat[4][4];
629
630         mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
631         mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
632 }
633
634 void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obmat[4][4], float pmat[4][4])
635 {
636         float vmat[4][4];
637
638         mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, obmat);
639         mul_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat);
640 }
641
642 /**
643  * Uses window coordinates (x,y) and depth component z to find a point in
644  * modelspace */
645 void ED_view3d_unproject(bglMats *mats, float out[3], const float x, const float y, const float z)
646 {
647         double ux, uy, uz;
648
649         gluUnProject(x, y, z, mats->modelview, mats->projection,
650                      (GLint *)mats->viewport, &ux, &uy, &uz);
651
652         out[0] = ux;
653         out[1] = uy;
654         out[2] = uz;
655 }