Camera: some code refactoring, use an intermediate CameraParams struct instead
[blender.git] / source / blender / blenkernel / intern / camera.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) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/camera.c
29  *  \ingroup bke
30  */
31
32 #include <stdlib.h>
33
34 #include "DNA_camera_types.h"
35 #include "DNA_lamp_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_animsys.h"
43 #include "BKE_camera.h"
44 #include "BKE_object.h"
45 #include "BKE_global.h"
46 #include "BKE_library.h"
47 #include "BKE_main.h"
48
49 /****************************** Camera Datablock *****************************/
50
51 void *add_camera(const char *name)
52 {
53         Camera *cam;
54         
55         cam=  alloc_libblock(&G.main->camera, ID_CA, name);
56
57         cam->lens= 35.0f;
58         cam->sensor_x= 32.0f;
59         cam->sensor_y= 18.0f;
60         cam->clipsta= 0.1f;
61         cam->clipend= 100.0f;
62         cam->drawsize= 0.5f;
63         cam->ortho_scale= 6.0;
64         cam->flag |= CAM_SHOWPASSEPARTOUT;
65         cam->passepartalpha = 0.5f;
66         
67         return cam;
68 }
69
70 Camera *copy_camera(Camera *cam)
71 {
72         Camera *camn;
73         
74         camn= copy_libblock(&cam->id);
75         
76         return camn;
77 }
78
79 void make_local_camera(Camera *cam)
80 {
81         Main *bmain= G.main;
82         Object *ob;
83         int is_local= FALSE, is_lib= FALSE;
84
85         /* - only lib users: do nothing
86          * - only local users: set flag
87          * - mixed: make copy
88          */
89         
90         if(cam->id.lib==NULL) return;
91         if(cam->id.us==1) {
92                 id_clear_lib_data(bmain, &cam->id);
93                 return;
94         }
95         
96         for(ob= bmain->object.first; ob && ELEM(0, is_lib, is_local); ob= ob->id.next) {
97                 if(ob->data==cam) {
98                         if(ob->id.lib) is_lib= TRUE;
99                         else is_local= TRUE;
100                 }
101         }
102         
103         if(is_local && is_lib == FALSE) {
104                 id_clear_lib_data(bmain, &cam->id);
105         }
106         else if(is_local && is_lib) {
107                 Camera *camn= copy_camera(cam);
108
109                 camn->id.us= 0;
110
111                 /* Remap paths of new ID using old library as base. */
112                 BKE_id_lib_local_paths(bmain, &camn->id);
113
114                 for(ob= bmain->object.first; ob; ob= ob->id.next) {
115                         if(ob->data == cam) {
116                                 if(ob->id.lib==NULL) {
117                                         ob->data= camn;
118                                         camn->id.us++;
119                                         cam->id.us--;
120                                 }
121                         }
122                 }
123         }
124 }
125
126 void free_camera(Camera *ca)
127 {
128         BKE_free_animdata((ID *)ca);
129 }
130
131 /******************************** Camera Usage *******************************/
132
133 void object_camera_mode(RenderData *rd, Object *cam_ob)
134 {
135         rd->mode &= ~(R_ORTHO|R_PANORAMA);
136
137         if(cam_ob && cam_ob->type==OB_CAMERA) {
138                 Camera *cam= cam_ob->data;
139                 if(cam->type == CAM_ORTHO) rd->mode |= R_ORTHO;
140                 if(cam->flag & CAM_PANORAMA) rd->mode |= R_PANORAMA;
141         }
142 }
143
144 /* get the camera's dof value, takes the dof object into account */
145 float object_camera_dof_distance(Object *ob)
146 {
147         Camera *cam = (Camera *)ob->data; 
148         if (ob->type != OB_CAMERA)
149                 return 0.0f;
150         if (cam->dof_ob) {      
151                 /* too simple, better to return the distance on the view axis only
152                  * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */
153                 float mat[4][4], imat[4][4], obmat[4][4];
154                 
155                 copy_m4_m4(obmat, ob->obmat);
156                 normalize_m4(obmat);
157                 invert_m4_m4(imat, obmat);
158                 mul_m4_m4m4(mat, cam->dof_ob->obmat, imat);
159                 return (float)fabs(mat[3][2]);
160         }
161         return cam->YF_dofdist;
162 }
163
164 /******************************** Camera Params *******************************/
165
166 static int camera_sensor_fit(int sensor_fit, float sizex, float sizey)
167 {
168         if(sensor_fit == CAMERA_SENSOR_FIT_AUTO) {
169                 if(sizex >= sizey)
170                         return CAMERA_SENSOR_FIT_HOR;
171                 else
172                         return CAMERA_SENSOR_FIT_VERT;
173         }
174
175         return sensor_fit;
176 }
177
178 void camera_params_init(CameraParams *params)
179 {
180         memset(params, 0, sizeof(CameraParams));
181
182         /* defaults */
183         params->sensor_x= DEFAULT_SENSOR_WIDTH;
184         params->sensor_y= DEFAULT_SENSOR_HEIGHT;
185         params->sensor_fit= CAMERA_SENSOR_FIT_AUTO;
186 }
187
188 void camera_params_from_object(CameraParams *params, Object *ob)
189 {
190         if(!ob)
191                 return;
192
193         if(ob->type==OB_CAMERA) {
194                 /* camera object */
195                 Camera *cam= ob->data;
196
197                 if(cam->type == CAM_ORTHO)
198                         params->is_ortho= TRUE;
199                 params->lens= cam->lens;
200                 params->ortho_scale= cam->ortho_scale;
201
202                 params->shiftx= cam->shiftx;
203                 params->shifty= cam->shifty;
204
205                 params->sensor_x= cam->sensor_x;
206                 params->sensor_y= cam->sensor_y;
207                 params->sensor_fit= cam->sensor_fit;
208
209                 params->clipsta= cam->clipsta;
210                 params->clipend= cam->clipend;
211         }
212         else if(ob->type==OB_LAMP) {
213                 /* lamp object */
214                 Lamp *la= ob->data;
215                 float fac= cosf((float)M_PI*la->spotsize/360.0f);
216                 float phi= acos(fac);
217
218                 params->lens= 16.0f*fac/sinf(phi);
219                 if(params->lens==0.0f)
220                         params->lens= 35.0f;
221
222                 params->clipsta= la->clipsta;
223                 params->clipend= la->clipend;
224         }
225 }
226
227 void camera_params_compute(CameraParams *params, int winx, int winy, float xasp, float yasp)
228 {
229         rctf viewplane;
230         float pixsize, winside, viewfac;
231         int sensor_fit;
232
233         /* fields rendering */
234         params->ycor= yasp/xasp;
235         if(params->use_fields)
236                 params->ycor *= 2.0f;
237
238         /* determine sensor fit */
239         sensor_fit = camera_sensor_fit(params->sensor_fit, xasp*winx, yasp*winy);
240
241         if(params->is_ortho) {
242                 /* orthographic camera, scale == 1.0 means exact 1 to 1 mapping */
243                 if(sensor_fit==CAMERA_SENSOR_FIT_HOR)
244                         viewfac= winx;
245                 else
246                         viewfac= params->ycor * winy;
247
248                 pixsize= params->ortho_scale/viewfac;
249         }
250         else {
251                 /* perspective camera */
252                 float sensor_size;
253
254                 /* note for auto fit sensor_x is both width and height */
255                 if(params->sensor_fit == CAMERA_SENSOR_FIT_VERT)
256                         sensor_size= params->sensor_y;
257                 else
258                         sensor_size= params->sensor_x;
259                 
260                 if(sensor_fit == CAMERA_SENSOR_FIT_HOR)
261                         viewfac= (params->lens * winx) / sensor_size;
262                 else
263                         viewfac= params->ycor * (params->lens * winy) / sensor_size;
264
265                 pixsize= params->clipsta/viewfac;
266         }
267
268         /* compute view plane:
269          * fully centered, zbuffer fills in jittered between -.5 and +.5 */
270         if(sensor_fit == CAMERA_SENSOR_FIT_HOR)
271                 winside= winx;
272         else
273                 winside= winy;
274
275         viewplane.xmin= -0.5f*(float)winx + params->shiftx*winside;
276         viewplane.ymin= -0.5f*params->ycor*(float)winy + params->shifty*winside;
277         viewplane.xmax=  0.5f*(float)winx + params->shiftx*winside;
278         viewplane.ymax=  0.5f*params->ycor*(float)winy + params->shifty*winside;
279
280         if(params->field_second) {
281                 if(params->field_odd) {
282                         viewplane.ymin-= 0.5f * params->ycor;
283                         viewplane.ymax-= 0.5f * params->ycor;
284                 }
285                 else {
286                         viewplane.ymin+= 0.5f * params->ycor;
287                         viewplane.ymax+= 0.5f * params->ycor;
288                 }
289         }
290
291         /* the window matrix is used for clipping, and not changed during OSA steps */
292         /* using an offset of +0.5 here would give clip errors on edges */
293         viewplane.xmin *= pixsize;
294         viewplane.xmax *= pixsize;
295         viewplane.ymin *= pixsize;
296         viewplane.ymax *= pixsize;
297
298         params->viewdx= pixsize;
299         params->viewdy= params->ycor * pixsize;
300
301         if(params->is_ortho)
302                 orthographic_m4(params->winmat, viewplane.xmin, viewplane.xmax,
303                         viewplane.ymin, viewplane.ymax, params->clipsta, params->clipend);
304         else
305                 perspective_m4(params->winmat, viewplane.xmin, viewplane.xmax,
306                         viewplane.ymin, viewplane.ymax, params->clipsta, params->clipend);
307         
308         params->viewplane= viewplane;
309 }
310
311 /***************************** Camera View Frame *****************************/
312
313 void camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const short do_clip, const float scale[3],
314                           float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
315 {
316         float facx, facy;
317         float depth;
318
319         /* aspect correcton */
320         if (scene) {
321                 float aspx= (float) scene->r.xsch*scene->r.xasp;
322                 float aspy= (float) scene->r.ysch*scene->r.yasp;
323
324                 if(camera->sensor_fit==CAMERA_SENSOR_FIT_AUTO) {
325                         if(aspx < aspy) {
326                                 r_asp[0]= aspx / aspy;
327                                 r_asp[1]= 1.0;
328                         }
329                         else {
330                                 r_asp[0]= 1.0;
331                                 r_asp[1]= aspy / aspx;
332                         }
333                 }
334                 else if(camera->sensor_fit==CAMERA_SENSOR_FIT_HOR) {
335                         r_asp[0]= aspx / aspy;
336                         r_asp[1]= 1.0;
337                 }
338                 else {
339                         r_asp[0]= 1.0;
340                         r_asp[1]= aspy / aspx;
341                 }
342         }
343         else {
344                 r_asp[0]= 1.0f;
345                 r_asp[1]= 1.0f;
346         }
347
348         if(camera->type==CAM_ORTHO) {
349                 facx= 0.5f * camera->ortho_scale * r_asp[0] * scale[0];
350                 facy= 0.5f * camera->ortho_scale * r_asp[1] * scale[1];
351                 r_shift[0]= camera->shiftx * camera->ortho_scale * scale[0];
352                 r_shift[1]= camera->shifty * camera->ortho_scale * scale[1];
353                 depth= do_clip ? -((camera->clipsta * scale[2]) + 0.1f) : - drawsize * camera->ortho_scale * scale[2];
354
355                 *r_drawsize= 0.5f * camera->ortho_scale;
356         }
357         else {
358                 /* that way it's always visible - clipsta+0.1 */
359                 float fac;
360                 float half_sensor= 0.5f*((camera->sensor_fit==CAMERA_SENSOR_FIT_VERT) ? (camera->sensor_y) : (camera->sensor_x));
361
362                 *r_drawsize= drawsize / ((scale[0] + scale[1] + scale[2]) / 3.0f);
363
364                 if(do_clip) {
365                         /* fixed depth, variable size (avoids exceeding clipping range) */
366                         depth = -(camera->clipsta + 0.1f);
367                         fac = depth / (camera->lens/(-half_sensor) * scale[2]);
368                 }
369                 else {
370                         /* fixed size, variable depth (stays a reasonable size in the 3D view) */
371                         depth= *r_drawsize * camera->lens/(-half_sensor) * scale[2];
372                         fac= *r_drawsize;
373                 }
374
375                 facx= fac * r_asp[0] * scale[0];
376                 facy= fac * r_asp[1] * scale[1];
377                 r_shift[0]= camera->shiftx*fac*2 * scale[0];
378                 r_shift[1]= camera->shifty*fac*2 * scale[1];
379         }
380
381         r_vec[0][0]= r_shift[0] + facx; r_vec[0][1]= r_shift[1] + facy; r_vec[0][2]= depth;
382         r_vec[1][0]= r_shift[0] + facx; r_vec[1][1]= r_shift[1] - facy; r_vec[1][2]= depth;
383         r_vec[2][0]= r_shift[0] - facx; r_vec[2][1]= r_shift[1] - facy; r_vec[2][2]= depth;
384         r_vec[3][0]= r_shift[0] - facx; r_vec[3][1]= r_shift[1] + facy; r_vec[3][2]= depth;
385 }
386
387 void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3])
388 {
389         float dummy_asp[2];
390         float dummy_shift[2];
391         float dummy_drawsize;
392         const float dummy_scale[3]= {1.0f, 1.0f, 1.0f};
393
394         camera_view_frame_ex(scene, camera, FALSE, 1.0, dummy_scale,
395                              dummy_asp, dummy_shift, &dummy_drawsize, r_vec);
396 }
397
398
399 typedef struct CameraViewFrameData {
400         float frame_tx[4][3];
401         float normal_tx[4][3];
402         float dist_vals[4];
403         unsigned int tot;
404 } CameraViewFrameData;
405
406 static void camera_to_frame_view_cb(const float co[3], void *user_data)
407 {
408         CameraViewFrameData *data= (CameraViewFrameData *)user_data;
409         unsigned int i;
410
411         for (i= 0; i < 4; i++) {
412                 float nd= -dist_to_plane_v3(co, data->frame_tx[i], data->normal_tx[i]);
413                 if (nd < data->dist_vals[i]) {
414                         data->dist_vals[i]= nd;
415                 }
416         }
417
418         data->tot++;
419 }
420
421 /* dont move the camera, just yield the fit location */
422 int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3])
423 {
424         float shift[2];
425         float plane_tx[4][3];
426         float rot_obmat[3][3];
427         const float zero[3]= {0,0,0};
428         CameraViewFrameData data_cb;
429
430         unsigned int i;
431
432         camera_view_frame(scene, camera_ob->data, data_cb.frame_tx);
433
434         copy_m3_m4(rot_obmat, camera_ob->obmat);
435         normalize_m3(rot_obmat);
436
437         for (i= 0; i < 4; i++) {
438                 /* normalize so Z is always 1.0f*/
439                 mul_v3_fl(data_cb.frame_tx[i], 1.0f/data_cb.frame_tx[i][2]);
440         }
441
442         /* get the shift back out of the frame */
443         shift[0]= (data_cb.frame_tx[0][0] +
444                    data_cb.frame_tx[1][0] +
445                    data_cb.frame_tx[2][0] +
446                    data_cb.frame_tx[3][0]) / 4.0f;
447         shift[1]= (data_cb.frame_tx[0][1] +
448                    data_cb.frame_tx[1][1] +
449                    data_cb.frame_tx[2][1] +
450                    data_cb.frame_tx[3][1]) / 4.0f;
451
452         for (i= 0; i < 4; i++) {
453                 mul_m3_v3(rot_obmat, data_cb.frame_tx[i]);
454         }
455
456         for (i= 0; i < 4; i++) {
457                 normal_tri_v3(data_cb.normal_tx[i],
458                               zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]);
459         }
460
461         /* initialize callback data */
462         data_cb.dist_vals[0]=
463         data_cb.dist_vals[1]=
464         data_cb.dist_vals[2]=
465         data_cb.dist_vals[3]= FLT_MAX;
466         data_cb.tot= 0;
467         /* run callback on all visible points */
468         BKE_scene_foreach_display_point(scene, v3d, BA_SELECT,
469                                         camera_to_frame_view_cb, &data_cb);
470
471         if (data_cb.tot <= 1) {
472                 return FALSE;
473         }
474         else {
475                 float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
476                 float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];
477
478                 float plane_isect_pt_1[3], plane_isect_pt_2[3];
479
480                 /* apply the dist-from-plane's to the transformed plane points */
481                 for (i= 0; i < 4; i++) {
482                         mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]);
483                 }
484
485                 if ( (isect_plane_plane_v3(plane_isect_1, plane_isect_1_no,
486                                            plane_tx[0], data_cb.normal_tx[0],
487                                            plane_tx[2], data_cb.normal_tx[2]) == 0) ||
488                      (isect_plane_plane_v3(plane_isect_2, plane_isect_2_no,
489                                            plane_tx[1], data_cb.normal_tx[1],
490                                            plane_tx[3], data_cb.normal_tx[3]) == 0))
491                 {
492                         /* this is very unlikely */
493                         return FALSE;
494                 }
495                 else {
496
497                         add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
498                         add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
499
500                         if (isect_line_line_v3(plane_isect_1, plane_isect_1_other,
501                                                plane_isect_2, plane_isect_2_other,
502                                                plane_isect_pt_1, plane_isect_pt_2) == 0)
503                         {
504                                 return FALSE;
505                         }
506                         else {
507                                 float cam_plane_no[3]= {0.0f, 0.0f, -1.0f};
508                                 float plane_isect_delta[3];
509                                 float plane_isect_delta_len;
510
511                                 mul_m3_v3(rot_obmat, cam_plane_no);
512
513                                 sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
514                                 plane_isect_delta_len= len_v3(plane_isect_delta);
515
516                                 if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
517                                         copy_v3_v3(r_co, plane_isect_pt_1);
518
519                                         /* offset shift */
520                                         normalize_v3(plane_isect_1_no);
521                                         madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len);
522                                 }
523                                 else {
524                                         copy_v3_v3(r_co, plane_isect_pt_2);
525
526                                         /* offset shift */
527                                         normalize_v3(plane_isect_2_no);
528                                         madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len);
529                                 }
530
531
532                                 return TRUE;
533                         }
534                 }
535         }
536 }