Code refactoring: split lamp functions from object.c into new lamp.c.
[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_global.h"
45 #include "BKE_library.h"
46 #include "BKE_main.h"
47
48 void *add_camera(const char *name)
49 {
50         Camera *cam;
51         
52         cam=  alloc_libblock(&G.main->camera, ID_CA, name);
53
54         cam->lens= 35.0f;
55         cam->sensor_x= 32.0f;
56         cam->sensor_y= 18.0f;
57         cam->clipsta= 0.1f;
58         cam->clipend= 100.0f;
59         cam->drawsize= 0.5f;
60         cam->ortho_scale= 6.0;
61         cam->flag |= CAM_SHOWPASSEPARTOUT;
62         cam->passepartalpha = 0.5f;
63         
64         return cam;
65 }
66
67 Camera *copy_camera(Camera *cam)
68 {
69         Camera *camn;
70         
71         camn= copy_libblock(cam);
72         
73         return camn;
74 }
75
76 void make_local_camera(Camera *cam)
77 {
78         Main *bmain= G.main;
79         Object *ob;
80         int is_local= FALSE, is_lib= FALSE;
81
82         /* - only lib users: do nothing
83          * - only local users: set flag
84          * - mixed: make copy
85          */
86         
87         if(cam->id.lib==NULL) return;
88         if(cam->id.us==1) {
89                 id_clear_lib_data(bmain, &cam->id);
90                 return;
91         }
92         
93         for(ob= bmain->object.first; ob && ELEM(0, is_lib, is_local); ob= ob->id.next) {
94                 if(ob->data==cam) {
95                         if(ob->id.lib) is_lib= TRUE;
96                         else is_local= TRUE;
97                 }
98         }
99         
100         if(is_local && is_lib == FALSE) {
101                 id_clear_lib_data(bmain, &cam->id);
102         }
103         else if(is_local && is_lib) {
104                 Camera *camn= copy_camera(cam);
105
106                 camn->id.us= 0;
107
108                 /* Remap paths of new ID using old library as base. */
109                 BKE_id_lib_local_paths(bmain, &camn->id);
110
111                 for(ob= bmain->object.first; ob; ob= ob->id.next) {
112                         if(ob->data == cam) {
113                                 if(ob->id.lib==NULL) {
114                                         ob->data= camn;
115                                         camn->id.us++;
116                                         cam->id.us--;
117                                 }
118                         }
119                 }
120         }
121 }
122
123 /* get the camera's dof value, takes the dof object into account */
124 float dof_camera(Object *ob)
125 {
126         Camera *cam = (Camera *)ob->data; 
127         if (ob->type != OB_CAMERA)
128                 return 0.0f;
129         if (cam->dof_ob) {      
130                 /* too simple, better to return the distance on the view axis only
131                  * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */
132                 float mat[4][4], imat[4][4], obmat[4][4];
133                 
134                 copy_m4_m4(obmat, ob->obmat);
135                 normalize_m4(obmat);
136                 invert_m4_m4(imat, obmat);
137                 mul_m4_m4m4(mat, cam->dof_ob->obmat, imat);
138                 return (float)fabs(mat[3][2]);
139         }
140         return cam->YF_dofdist;
141 }
142
143 void free_camera(Camera *ca)
144 {
145         BKE_free_animdata((ID *)ca);
146 }
147
148 void object_camera_mode(RenderData *rd, Object *camera)
149 {
150         rd->mode &= ~(R_ORTHO|R_PANORAMA);
151         if(camera && camera->type==OB_CAMERA) {
152                 Camera *cam= camera->data;
153                 if(cam->type == CAM_ORTHO) rd->mode |= R_ORTHO;
154                 if(cam->flag & CAM_PANORAMA) rd->mode |= R_PANORAMA;
155         }
156 }
157
158 void object_camera_intrinsics(Object *camera, Camera **cam_r, short *is_ortho, float *shiftx, float *shifty,
159                         float *clipsta, float *clipend, float *lens, float *sensor_x, float *sensor_y, short *sensor_fit)
160 {
161         Camera *cam= NULL;
162
163         (*shiftx)= 0.0f;
164         (*shifty)= 0.0f;
165
166         (*sensor_x)= DEFAULT_SENSOR_WIDTH;
167         (*sensor_y)= DEFAULT_SENSOR_HEIGHT;
168         (*sensor_fit)= CAMERA_SENSOR_FIT_AUTO;
169
170         if(camera->type==OB_CAMERA) {
171                 cam= camera->data;
172
173                 if(cam->type == CAM_ORTHO) {
174                         *is_ortho= TRUE;
175                 }
176
177                 /* solve this too... all time depending stuff is in convertblender.c?
178                  * Need to update the camera early because it's used for projection matrices
179                  * and other stuff BEFORE the animation update loop is done
180                  * */
181 #if 0 // XXX old animation system
182                 if(cam->ipo) {
183                         calc_ipo(cam->ipo, frame_to_float(re->scene, re->r.cfra));
184                         execute_ipo(&cam->id, cam->ipo);
185                 }
186 #endif // XXX old animation system
187                 (*shiftx)=cam->shiftx;
188                 (*shifty)=cam->shifty;
189                 (*lens)= cam->lens;
190                 (*sensor_x)= cam->sensor_x;
191                 (*sensor_y)= cam->sensor_y;
192                 (*clipsta)= cam->clipsta;
193                 (*clipend)= cam->clipend;
194                 (*sensor_fit)= cam->sensor_fit;
195         }
196         else if(camera->type==OB_LAMP) {
197                 Lamp *la= camera->data;
198                 float fac= cosf((float)M_PI*la->spotsize/360.0f);
199                 float phi= acos(fac);
200
201                 (*lens)= 16.0f*fac/sinf(phi);
202                 if((*lens)==0.0f)
203                         (*lens)= 35.0f;
204                 (*clipsta)= la->clipsta;
205                 (*clipend)= la->clipend;
206         }
207         else {  /* envmap exception... */;
208                 if((*lens)==0.0f) /* is this needed anymore? */
209                         (*lens)= 16.0f;
210
211                 if((*clipsta)==0.0f || (*clipend)==0.0f) {
212                         (*clipsta)= 0.1f;
213                         (*clipend)= 1000.0f;
214                 }
215         }
216
217         (*cam_r)= cam;
218 }
219
220 /* 'lens' may be set for envmap only */
221 void object_camera_matrix(
222                 RenderData *rd, Object *camera, int winx, int winy, short field_second,
223                 float winmat[][4], rctf *viewplane, float *clipsta, float *clipend, float *lens,
224                 float *sensor_x, float *sensor_y, short *sensor_fit, float *ycor,
225                 float *viewdx, float *viewdy)
226 {
227         Camera *cam=NULL;
228         float pixsize;
229         float shiftx=0.0, shifty=0.0, winside, viewfac;
230         short is_ortho= FALSE;
231
232         /* question mark */
233         (*ycor)= rd->yasp / rd->xasp;
234         if(rd->mode & R_FIELDS)
235                 (*ycor) *= 2.0f;
236
237         object_camera_intrinsics(camera, &cam, &is_ortho, &shiftx, &shifty, clipsta, clipend, lens, sensor_x, sensor_y, sensor_fit);
238
239         /* ortho only with camera available */
240         if(cam && is_ortho) {
241                 if((*sensor_fit)==CAMERA_SENSOR_FIT_AUTO) {
242                         if(rd->xasp*winx >= rd->yasp*winy) viewfac= winx;
243                         else viewfac= (*ycor) * winy;
244                 }
245                 else if((*sensor_fit)==CAMERA_SENSOR_FIT_HOR) {
246                         viewfac= winx;
247                 }
248                 else { /* if((*sensor_fit)==CAMERA_SENSOR_FIT_VERT) { */
249                         viewfac= (*ycor) * winy;
250                 }
251
252                 /* ortho_scale == 1.0 means exact 1 to 1 mapping */
253                 pixsize= cam->ortho_scale/viewfac;
254         }
255         else {
256                 if((*sensor_fit)==CAMERA_SENSOR_FIT_AUTO) {
257                         if(rd->xasp*winx >= rd->yasp*winy)      viewfac= ((*lens) * winx) / (*sensor_x);
258                         else                                    viewfac= (*ycor) * ((*lens) * winy) / (*sensor_x);
259                 }
260                 else if((*sensor_fit)==CAMERA_SENSOR_FIT_HOR) {
261                         viewfac= ((*lens) * winx) / (*sensor_x);
262                 }
263                 else { /* if((*sensor_fit)==CAMERA_SENSOR_FIT_VERT) { */
264                         viewfac= ((*lens) * winy) / (*sensor_y);
265                 }
266
267                 pixsize= (*clipsta) / viewfac;
268         }
269
270         /* viewplane fully centered, zbuffer fills in jittered between -.5 and +.5 */
271         winside= MAX2(winx, winy);
272
273         if(cam) {
274                 if(cam->sensor_fit==CAMERA_SENSOR_FIT_HOR)
275                         winside= winx;
276                 else if(cam->sensor_fit==CAMERA_SENSOR_FIT_VERT)
277                         winside= winy;
278         }
279
280         viewplane->xmin= -0.5f*(float)winx + shiftx*winside;
281         viewplane->ymin= -0.5f*(*ycor)*(float)winy + shifty*winside;
282         viewplane->xmax=  0.5f*(float)winx + shiftx*winside;
283         viewplane->ymax=  0.5f*(*ycor)*(float)winy + shifty*winside;
284
285         if(field_second) {
286                 if(rd->mode & R_ODDFIELD) {
287                         viewplane->ymin-= 0.5f * (*ycor);
288                         viewplane->ymax-= 0.5f * (*ycor);
289                 }
290                 else {
291                         viewplane->ymin+= 0.5f * (*ycor);
292                         viewplane->ymax+= 0.5f * (*ycor);
293                 }
294         }
295         /* the window matrix is used for clipping, and not changed during OSA steps */
296         /* using an offset of +0.5 here would give clip errors on edges */
297         viewplane->xmin *= pixsize;
298         viewplane->xmax *= pixsize;
299         viewplane->ymin *= pixsize;
300         viewplane->ymax *= pixsize;
301
302         (*viewdx)= pixsize;
303         (*viewdy)= (*ycor) * pixsize;
304
305         if(is_ortho)
306                 orthographic_m4(winmat, viewplane->xmin, viewplane->xmax, viewplane->ymin, viewplane->ymax, *clipsta, *clipend);
307         else
308                 perspective_m4(winmat, viewplane->xmin, viewplane->xmax, viewplane->ymin, viewplane->ymax, *clipsta, *clipend);
309
310 }
311
312 void camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const short do_clip, const float scale[3],
313                           float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3])
314 {
315         float facx, facy;
316         float depth;
317
318         /* aspect correcton */
319         if (scene) {
320                 float aspx= (float) scene->r.xsch*scene->r.xasp;
321                 float aspy= (float) scene->r.ysch*scene->r.yasp;
322
323                 if(camera->sensor_fit==CAMERA_SENSOR_FIT_AUTO) {
324                         if(aspx < aspy) {
325                                 r_asp[0]= aspx / aspy;
326                                 r_asp[1]= 1.0;
327                         }
328                         else {
329                                 r_asp[0]= 1.0;
330                                 r_asp[1]= aspy / aspx;
331                         }
332                 }
333                 else if(camera->sensor_fit==CAMERA_SENSOR_FIT_AUTO) {
334                         r_asp[0]= aspx / aspy;
335                         r_asp[1]= 1.0;
336                 }
337                 else {
338                         r_asp[0]= 1.0;
339                         r_asp[1]= aspy / aspx;
340                 }
341         }
342         else {
343                 r_asp[0]= 1.0f;
344                 r_asp[1]= 1.0f;
345         }
346
347         if(camera->type==CAM_ORTHO) {
348                 facx= 0.5f * camera->ortho_scale * r_asp[0] * scale[0];
349                 facy= 0.5f * camera->ortho_scale * r_asp[1] * scale[1];
350                 r_shift[0]= camera->shiftx * camera->ortho_scale * scale[0];
351                 r_shift[1]= camera->shifty * camera->ortho_scale * scale[1];
352                 depth= do_clip ? -((camera->clipsta * scale[2]) + 0.1f) : - drawsize * camera->ortho_scale * scale[2];
353
354                 *r_drawsize= 0.5f * camera->ortho_scale;
355         }
356         else {
357                 /* that way it's always visible - clipsta+0.1 */
358                 float fac;
359                 float half_sensor= 0.5f*((camera->sensor_fit==CAMERA_SENSOR_FIT_VERT) ? (camera->sensor_y) : (camera->sensor_x));
360
361                 *r_drawsize= drawsize / ((scale[0] + scale[1] + scale[2]) / 3.0f);
362
363                 if(do_clip) {
364                         /* fixed depth, variable size (avoids exceeding clipping range) */
365                         depth = -(camera->clipsta + 0.1f);
366                         fac = depth / (camera->lens/(-half_sensor) * scale[2]);
367                 }
368                 else {
369                         /* fixed size, variable depth (stays a reasonable size in the 3D view) */
370                         depth= *r_drawsize * camera->lens/(-half_sensor) * scale[2];
371                         fac= *r_drawsize;
372                 }
373
374                 facx= fac * r_asp[0] * scale[0];
375                 facy= fac * r_asp[1] * scale[1];
376                 r_shift[0]= camera->shiftx*fac*2 * scale[0];
377                 r_shift[1]= camera->shifty*fac*2 * scale[1];
378         }
379
380         r_vec[0][0]= r_shift[0] + facx; r_vec[0][1]= r_shift[1] + facy; r_vec[0][2]= depth;
381         r_vec[1][0]= r_shift[0] + facx; r_vec[1][1]= r_shift[1] - facy; r_vec[1][2]= depth;
382         r_vec[2][0]= r_shift[0] - facx; r_vec[2][1]= r_shift[1] - facy; r_vec[2][2]= depth;
383         r_vec[3][0]= r_shift[0] - facx; r_vec[3][1]= r_shift[1] + facy; r_vec[3][2]= depth;
384 }
385
386 void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3])
387 {
388         float dummy_asp[2];
389         float dummy_shift[2];
390         float dummy_drawsize;
391         const float dummy_scale[3]= {1.0f, 1.0f, 1.0f};
392
393         camera_view_frame_ex(scene, camera, FALSE, 1.0, dummy_scale,
394                              dummy_asp, dummy_shift, &dummy_drawsize, r_vec);
395 }
396