Cycles: Make all #include statements relative to cycles source directory
[blender.git] / intern / cycles / blender / blender_camera.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "render/camera.h"
18 #include "render/scene.h"
19
20 #include "blender/blender_sync.h"
21 #include "blender/blender_util.h"
22
23 #include "util/util_logging.h"
24
25 CCL_NAMESPACE_BEGIN
26
27 /* Blender Camera Intermediate: we first convert both the offline and 3d view
28  * render camera to this, and from there convert to our native camera format. */
29
30 struct BlenderCamera {
31         float nearclip;
32         float farclip;
33
34         CameraType type;
35         float ortho_scale;
36
37         float lens;
38         float shuttertime;
39         Camera::MotionPosition motion_position;
40         array<float> shutter_curve;
41
42         Camera::RollingShutterType rolling_shutter_type;
43         float rolling_shutter_duration;
44
45         float aperturesize;
46         uint apertureblades;
47         float aperturerotation;
48         float focaldistance;
49
50         float2 shift;
51         float2 offset;
52         float zoom;
53
54         float2 pixelaspect;
55
56         float aperture_ratio;
57
58         PanoramaType panorama_type;
59         float fisheye_fov;
60         float fisheye_lens;
61         float latitude_min;
62         float latitude_max;
63         float longitude_min;
64         float longitude_max;
65         bool use_spherical_stereo;
66         float interocular_distance;
67         float convergence_distance;
68         bool use_pole_merge;
69         float pole_merge_angle_from;
70         float pole_merge_angle_to;
71
72         enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
73         float sensor_width;
74         float sensor_height;
75
76         int full_width;
77         int full_height;
78
79         BoundBox2D border;
80         BoundBox2D pano_viewplane;
81         BoundBox2D viewport_camera_border;
82
83         Transform matrix;
84 };
85
86 static void blender_camera_init(BlenderCamera *bcam,
87                                 BL::RenderSettings& b_render)
88 {
89         memset(bcam, 0, sizeof(BlenderCamera));
90
91         bcam->type = CAMERA_PERSPECTIVE;
92         bcam->zoom = 1.0f;
93         bcam->pixelaspect = make_float2(1.0f, 1.0f);
94         bcam->sensor_width = 32.0f;
95         bcam->sensor_height = 18.0f;
96         bcam->sensor_fit = BlenderCamera::AUTO;
97         bcam->shuttertime = 1.0f;
98         bcam->motion_position = Camera::MOTION_POSITION_CENTER;
99         bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE;
100         bcam->rolling_shutter_duration = 0.1f;
101         bcam->border.right = 1.0f;
102         bcam->border.top = 1.0f;
103         bcam->pano_viewplane.right = 1.0f;
104         bcam->pano_viewplane.top = 1.0f;
105         bcam->viewport_camera_border.right = 1.0f;
106         bcam->viewport_camera_border.top = 1.0f;
107
108         /* render resolution */
109         bcam->full_width = render_resolution_x(b_render);
110         bcam->full_height = render_resolution_y(b_render);
111 }
112
113 static float blender_camera_focal_distance(BL::RenderEngine& b_engine,
114                                            BL::Object& b_ob,
115                                            BL::Camera& b_camera,
116                                            BlenderCamera *bcam)
117 {
118         BL::Object b_dof_object = b_camera.dof_object();
119
120         if(!b_dof_object)
121                 return b_camera.dof_distance();
122         
123         /* for dof object, return distance along camera Z direction */
124         BL::Array<float, 16> b_ob_matrix;
125         b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
126         Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
127         Transform dofmat = get_transform(b_dof_object.matrix_world());
128         float3 view_dir = normalize(transform_get_column(&obmat, 2));
129         float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
130         return fabsf(dot(view_dir, dof_dir));
131 }
132
133 static void blender_camera_from_object(BlenderCamera *bcam,
134                                        BL::RenderEngine& b_engine,
135                                        BL::Object& b_ob,
136                                        bool skip_panorama = false)
137 {
138         BL::ID b_ob_data = b_ob.data();
139
140         if(b_ob_data.is_a(&RNA_Camera)) {
141                 BL::Camera b_camera(b_ob_data);
142                 PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
143
144                 bcam->nearclip = b_camera.clip_start();
145                 bcam->farclip = b_camera.clip_end();
146
147                 switch(b_camera.type())
148                 {
149                         case BL::Camera::type_ORTHO:
150                                 bcam->type = CAMERA_ORTHOGRAPHIC;
151                                 break;
152                         case BL::Camera::type_PANO:
153                                 if(!skip_panorama)
154                                         bcam->type = CAMERA_PANORAMA;
155                                 else
156                                         bcam->type = CAMERA_PERSPECTIVE;
157                                 break;
158                         case BL::Camera::type_PERSP:
159                         default:
160                                 bcam->type = CAMERA_PERSPECTIVE;
161                                 break;
162                 }
163
164                 bcam->panorama_type = (PanoramaType)get_enum(ccamera,
165                                                              "panorama_type",
166                                                              PANORAMA_NUM_TYPES,
167                                                              PANORAMA_EQUIRECTANGULAR);
168
169                 bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
170                 bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
171                 bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min");
172                 bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max");
173                 bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
174                 bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
175
176                 bcam->interocular_distance = b_camera.stereo().interocular_distance();
177                 if(b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
178                         bcam->convergence_distance = FLT_MAX;
179                 }
180                 else {
181                         bcam->convergence_distance = b_camera.stereo().convergence_distance();
182                 }
183                 bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
184
185                 bcam->use_pole_merge = b_camera.stereo().use_pole_merge();
186                 bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from();
187                 bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to();
188
189                 bcam->ortho_scale = b_camera.ortho_scale();
190
191                 bcam->lens = b_camera.lens();
192
193                 /* allow f/stop number to change aperture_size but still
194                  * give manual control over aperture radius */
195                 int aperture_type = get_enum(ccamera, "aperture_type");
196
197                 if(aperture_type == 1) {
198                         float fstop = RNA_float_get(&ccamera, "aperture_fstop");
199                         fstop = max(fstop, 1e-5f);
200
201                         if(bcam->type == CAMERA_ORTHOGRAPHIC)
202                                 bcam->aperturesize = 1.0f/(2.0f*fstop);
203                         else
204                                 bcam->aperturesize = (bcam->lens*1e-3f)/(2.0f*fstop);
205                 }
206                 else
207                         bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
208
209                 bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
210                 bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
211                 bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
212                 bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
213
214                 bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
215                 bcam->shift.y = b_camera.shift_y();
216
217                 bcam->sensor_width = b_camera.sensor_width();
218                 bcam->sensor_height = b_camera.sensor_height();
219
220                 if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
221                         bcam->sensor_fit = BlenderCamera::AUTO;
222                 else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
223                         bcam->sensor_fit = BlenderCamera::HORIZONTAL;
224                 else
225                         bcam->sensor_fit = BlenderCamera::VERTICAL;
226         }
227         else {
228                 /* from lamp not implemented yet */
229         }
230 }
231
232 static Transform blender_camera_matrix(const Transform& tfm,
233                                        const CameraType type,
234                                        const PanoramaType panorama_type)
235 {
236         Transform result;
237
238         if(type == CAMERA_PANORAMA) {
239                 if(panorama_type == PANORAMA_MIRRORBALL) {
240                         /* Mirror ball camera is looking into the negative Y direction
241                          * which matches texture mirror ball mapping.
242                          */
243                         result = tfm *
244                                 make_transform(1.0f, 0.0f, 0.0f, 0.0f,
245                                                0.0f, 0.0f, 1.0f, 0.0f,
246                                                0.0f, 1.0f, 0.0f, 0.0f,
247                                                0.0f, 0.0f, 0.0f, 1.0f);
248                 }
249                 else {
250                         /* Make it so environment camera needs to be pointed in the direction
251                          * of the positive x-axis to match an environment texture, this way
252                          * it is looking at the center of the texture
253                          */
254                         result = tfm *
255                                 make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
256                                                 0.0f,  0.0f, 1.0f, 0.0f,
257                                                -1.0f,  0.0f, 0.0f, 0.0f,
258                                                 0.0f,  0.0f, 0.0f, 1.0f);
259                 }
260         }
261         else {
262                 /* note the blender camera points along the negative z-axis */
263                 result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
264         }
265
266         return transform_clear_scale(result);
267 }
268
269 static void blender_camera_viewplane(BlenderCamera *bcam,
270                                      int width, int height,
271                                      BoundBox2D *viewplane,
272                                      float *aspectratio,
273                                      float *sensor_size)
274 {
275         /* dimensions */
276         float xratio = (float)width*bcam->pixelaspect.x;
277         float yratio = (float)height*bcam->pixelaspect.y;
278
279         /* compute x/y aspect and ratio */
280         float xaspect, yaspect;
281         bool horizontal_fit;
282
283         /* sensor fitting */
284         if(bcam->sensor_fit == BlenderCamera::AUTO) {
285                 horizontal_fit = (xratio > yratio);
286                 if(sensor_size != NULL) {
287                         *sensor_size = bcam->sensor_width;
288                 }
289         }
290         else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
291                 horizontal_fit = true;
292                 if(sensor_size != NULL) {
293                         *sensor_size = bcam->sensor_width;
294                 }
295         }
296         else {
297                 horizontal_fit = false;
298                 if(sensor_size != NULL) {
299                         *sensor_size = bcam->sensor_height;
300                 }
301         }
302
303         if(horizontal_fit) {
304                 if(aspectratio != NULL) {
305                         *aspectratio = xratio/yratio;
306                 }
307                 xaspect = *aspectratio;
308                 yaspect = 1.0f;
309         }
310         else {
311                 if(aspectratio != NULL) {
312                         *aspectratio = yratio/xratio;
313                 }
314                 xaspect = 1.0f;
315                 yaspect = *aspectratio;
316         }
317
318         /* modify aspect for orthographic scale */
319         if(bcam->type == CAMERA_ORTHOGRAPHIC) {
320                 xaspect = xaspect*bcam->ortho_scale/(*aspectratio*2.0f);
321                 yaspect = yaspect*bcam->ortho_scale/(*aspectratio*2.0f);
322                 if(aspectratio != NULL) {
323                         *aspectratio = bcam->ortho_scale/2.0f;
324                 }
325         }
326
327         if(bcam->type == CAMERA_PANORAMA) {
328                 /* set viewplane */
329                 if(viewplane != NULL) {
330                         *viewplane = bcam->pano_viewplane;
331                 }
332         }
333         else {
334                 /* set viewplane */
335                 if(viewplane != NULL) {
336                         viewplane->left = -xaspect;
337                         viewplane->right = xaspect;
338                         viewplane->bottom = -yaspect;
339                         viewplane->top = yaspect;
340
341                         /* zoom for 3d camera view */
342                         *viewplane = (*viewplane) * bcam->zoom;
343
344                         /* modify viewplane with camera shift and 3d camera view offset */
345                         float dx = 2.0f*(*aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
346                         float dy = 2.0f*(*aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
347
348                         viewplane->left += dx;
349                         viewplane->right += dx;
350                         viewplane->bottom += dy;
351                         viewplane->top += dy;
352                 }
353         }
354 }
355
356 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height, const char *viewname)
357 {
358         /* copy camera to compare later */
359         Camera prevcam = *cam;
360         float aspectratio, sensor_size;
361
362         /* viewplane */
363         blender_camera_viewplane(bcam, width, height,
364                 &cam->viewplane, &aspectratio, &sensor_size);
365
366         cam->width = bcam->full_width;
367         cam->height = bcam->full_height;
368
369         cam->full_width = width;
370         cam->full_height = height;
371
372         /* panorama sensor */
373         if(bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
374                 float fit_xratio = (float)bcam->full_width*bcam->pixelaspect.x;
375                 float fit_yratio = (float)bcam->full_height*bcam->pixelaspect.y;
376                 bool horizontal_fit;
377                 float sensor_size;
378
379                 if(bcam->sensor_fit == BlenderCamera::AUTO) {
380                         horizontal_fit = (fit_xratio > fit_yratio);
381                         sensor_size = bcam->sensor_width;
382                 }
383                 else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
384                         horizontal_fit = true;
385                         sensor_size = bcam->sensor_width;
386                 }
387                 else { /* vertical */
388                         horizontal_fit = false;
389                         sensor_size = bcam->sensor_height;
390                 }
391
392                 if(horizontal_fit) {
393                         cam->sensorwidth = sensor_size;
394                         cam->sensorheight = sensor_size * fit_yratio / fit_xratio;
395                 }
396                 else {
397                         cam->sensorwidth = sensor_size * fit_xratio / fit_yratio;
398                         cam->sensorheight = sensor_size;
399                 }
400         }
401
402         /* clipping distances */
403         cam->nearclip = bcam->nearclip;
404         cam->farclip = bcam->farclip;
405
406         /* type */
407         cam->type = bcam->type;
408
409         /* panorama */
410         cam->panorama_type = bcam->panorama_type;
411         cam->fisheye_fov = bcam->fisheye_fov;
412         cam->fisheye_lens = bcam->fisheye_lens;
413         cam->latitude_min = bcam->latitude_min;
414         cam->latitude_max = bcam->latitude_max;
415
416         cam->longitude_min = bcam->longitude_min;
417         cam->longitude_max = bcam->longitude_max;
418
419         /* panorama stereo */
420         cam->interocular_distance = bcam->interocular_distance;
421         cam->convergence_distance = bcam->convergence_distance;
422         cam->use_spherical_stereo = bcam->use_spherical_stereo;
423
424         if(cam->use_spherical_stereo) {
425                 if(strcmp(viewname, "left") == 0)
426                         cam->stereo_eye = Camera::STEREO_LEFT;
427                 else if(strcmp(viewname, "right") == 0)
428                         cam->stereo_eye = Camera::STEREO_RIGHT;
429                 else
430                         cam->stereo_eye = Camera::STEREO_NONE;
431         }
432
433         cam->use_pole_merge = bcam->use_pole_merge;
434         cam->pole_merge_angle_from = bcam->pole_merge_angle_from;
435         cam->pole_merge_angle_to = bcam->pole_merge_angle_to;
436
437         /* anamorphic lens bokeh */
438         cam->aperture_ratio = bcam->aperture_ratio;
439
440         /* perspective */
441         cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio);
442         cam->focaldistance = bcam->focaldistance;
443         cam->aperturesize = bcam->aperturesize;
444         cam->blades = bcam->apertureblades;
445         cam->bladesrotation = bcam->aperturerotation;
446
447         /* transform */
448         cam->matrix = blender_camera_matrix(bcam->matrix,
449                                             bcam->type,
450                                             bcam->panorama_type);
451         cam->motion.pre = cam->matrix;
452         cam->motion.post = cam->matrix;
453         cam->use_motion = false;
454         cam->use_perspective_motion = false;
455         cam->shuttertime = bcam->shuttertime;
456         cam->fov_pre = cam->fov;
457         cam->fov_post = cam->fov;
458         cam->motion_position = bcam->motion_position;
459
460         cam->rolling_shutter_type = bcam->rolling_shutter_type;
461         cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
462
463         cam->shutter_curve = bcam->shutter_curve;
464
465         /* border */
466         cam->border = bcam->border;
467         cam->viewport_camera_border = bcam->viewport_camera_border;
468
469         /* set update flag */
470         if(cam->modified(prevcam))
471                 cam->tag_update();
472 }
473
474 /* Sync Render Camera */
475
476 void BlenderSync::sync_camera(BL::RenderSettings& b_render,
477                               BL::Object& b_override,
478                               int width, int height,
479                               const char *viewname)
480 {
481         BlenderCamera bcam;
482         blender_camera_init(&bcam, b_render);
483
484         /* pixel aspect */
485         bcam.pixelaspect.x = b_render.pixel_aspect_x();
486         bcam.pixelaspect.y = b_render.pixel_aspect_y();
487         bcam.shuttertime = b_render.motion_blur_shutter();
488
489         BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
490         curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
491
492         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
493         bcam.motion_position =
494                 (Camera::MotionPosition)get_enum(cscene,
495                                                  "motion_blur_position",
496                                                  Camera::MOTION_NUM_POSITIONS,
497                                                  Camera::MOTION_POSITION_CENTER);
498         bcam.rolling_shutter_type =
499                 (Camera::RollingShutterType)get_enum(cscene,
500                                                      "rolling_shutter_type",
501                                                      Camera::ROLLING_SHUTTER_NUM_TYPES,
502                                                      Camera::ROLLING_SHUTTER_NONE);
503         bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
504
505         /* border */
506         if(b_render.use_border()) {
507                 bcam.border.left = b_render.border_min_x();
508                 bcam.border.right = b_render.border_max_x();
509                 bcam.border.bottom = b_render.border_min_y();
510                 bcam.border.top = b_render.border_max_y();
511         }
512
513         /* camera object */
514         BL::Object b_ob = b_scene.camera();
515
516         if(b_override)
517                 b_ob = b_override;
518
519         if(b_ob) {
520                 BL::Array<float, 16> b_ob_matrix;
521                 blender_camera_from_object(&bcam, b_engine, b_ob);
522                 b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
523                 bcam.matrix = get_transform(b_ob_matrix);
524         }
525
526         /* sync */
527         Camera *cam = scene->camera;
528         blender_camera_sync(cam, &bcam, width, height, viewname);
529 }
530
531 void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
532                                      BL::Object& b_ob,
533                                      int width, int height,
534                                      float motion_time)
535 {
536         if(!b_ob)
537                 return;
538
539         Camera *cam = scene->camera;
540         BL::Array<float, 16> b_ob_matrix;
541         b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix);
542         Transform tfm = get_transform(b_ob_matrix);
543         tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
544
545         if(tfm != cam->matrix) {
546                 VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
547                 if(motion_time == -1.0f) {
548                         cam->motion.pre = tfm;
549                         cam->use_motion = true;
550                 }
551                 else if(motion_time == 1.0f) {
552                         cam->motion.post = tfm;
553                         cam->use_motion = true;
554                 }
555         }
556
557         if(cam->type == CAMERA_PERSPECTIVE) {
558                 BlenderCamera bcam;
559                 float aspectratio, sensor_size;
560                 blender_camera_init(&bcam, b_render);
561
562                 /* TODO(sergey): Consider making it a part of blender_camera_init(). */
563                 bcam.pixelaspect.x = b_render.pixel_aspect_x();
564                 bcam.pixelaspect.y = b_render.pixel_aspect_y();
565
566                 blender_camera_from_object(&bcam, b_engine, b_ob);
567                 blender_camera_viewplane(&bcam,
568                                          width, height,
569                                          NULL,
570                                          &aspectratio,
571                                          &sensor_size);
572                 /* TODO(sergey): De-duplicate calculation with camera sync. */
573                 float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
574                 if(fov != cam->fov) {
575                         VLOG(1) << "Camera " << b_ob.name() << " FOV change detected.";
576                         if(motion_time == -1.0f) {
577                                 cam->fov_pre = fov;
578                                 cam->use_perspective_motion = true;
579                         }
580                         else if(motion_time == 1.0f) {
581                                 cam->fov_post = fov;
582                                 cam->use_perspective_motion = true;
583                         }
584                 }
585         }
586 }
587
588 /* Sync 3D View Camera */
589
590 static void blender_camera_view_subset(BL::RenderEngine& b_engine,
591                                        BL::RenderSettings& b_render,
592                                        BL::Scene& b_scene,
593                                        BL::Object& b_ob,
594                                        BL::SpaceView3D& b_v3d,
595                                        BL::RegionView3D& b_rv3d,
596                                        int width, int height,
597                                        BoundBox2D *view_box,
598                                        BoundBox2D *cam_box);
599
600 static void blender_camera_from_view(BlenderCamera *bcam,
601                                      BL::RenderEngine& b_engine,
602                                      BL::Scene& b_scene,
603                                      BL::SpaceView3D& b_v3d,
604                                      BL::RegionView3D& b_rv3d,
605                                      int width, int height,
606                                      bool skip_panorama = false)
607 {
608         /* 3d view parameters */
609         bcam->nearclip = b_v3d.clip_start();
610         bcam->farclip = b_v3d.clip_end();
611         bcam->lens = b_v3d.lens();
612         bcam->shuttertime = b_scene.render().motion_blur_shutter();
613
614         BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
615         curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
616
617         if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
618                 /* camera view */
619                 BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
620
621                 if(b_ob) {
622                         blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
623
624                         if(!skip_panorama && bcam->type == CAMERA_PANORAMA) {
625                                 /* in panorama camera view, we map viewplane to camera border */
626                                 BoundBox2D view_box, cam_box;
627
628                                 BL::RenderSettings b_render_settings(b_scene.render());
629                                 blender_camera_view_subset(b_engine,
630                                                            b_render_settings,
631                                                            b_scene,
632                                                            b_ob,
633                                                            b_v3d,
634                                                            b_rv3d,
635                                                            width, height,
636                                                            &view_box,
637                                                            &cam_box);
638
639                                 bcam->pano_viewplane = view_box.make_relative_to(cam_box);
640                         }
641                         else {
642                                 /* magic zoom formula */
643                                 bcam->zoom = (float)b_rv3d.view_camera_zoom();
644                                 bcam->zoom = (1.41421f + bcam->zoom/50.0f);
645                                 bcam->zoom *= bcam->zoom;
646                                 bcam->zoom = 2.0f/bcam->zoom;
647
648                                 /* offset */
649                                 bcam->offset = get_float2(b_rv3d.view_camera_offset());
650                         }
651                 }
652         }
653         else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
654                 /* orthographic view */
655                 bcam->farclip *= 0.5f;
656                 bcam->nearclip = -bcam->farclip;
657
658                 float sensor_size;
659                 if(bcam->sensor_fit == BlenderCamera::VERTICAL)
660                         sensor_size = bcam->sensor_height;
661                 else
662                         sensor_size = bcam->sensor_width;
663
664                 bcam->type = CAMERA_ORTHOGRAPHIC;
665                 bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
666         }
667
668         bcam->zoom *= 2.0f;
669
670         /* 3d view transform */
671         bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
672 }
673
674 static void blender_camera_view_subset(BL::RenderEngine& b_engine,
675                                        BL::RenderSettings& b_render,
676                                        BL::Scene& b_scene,
677                                        BL::Object& b_ob,
678                                        BL::SpaceView3D& b_v3d,
679                                        BL::RegionView3D& b_rv3d,
680                                        int width, int height,
681                                        BoundBox2D *view_box,
682                                        BoundBox2D *cam_box)
683 {
684         BoundBox2D cam, view;
685         float view_aspect, cam_aspect, sensor_size;
686
687         /* get viewport viewplane */
688         BlenderCamera view_bcam;
689         blender_camera_init(&view_bcam, b_render);
690         blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
691
692         blender_camera_viewplane(&view_bcam, width, height,
693                 &view, &view_aspect, &sensor_size);
694
695         /* get camera viewplane */
696         BlenderCamera cam_bcam;
697         blender_camera_init(&cam_bcam, b_render);
698         blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
699
700         blender_camera_viewplane(&cam_bcam, cam_bcam.full_width, cam_bcam.full_height,
701                 &cam, &cam_aspect, &sensor_size);
702         
703         /* return */
704         *view_box = view * (1.0f/view_aspect);
705         *cam_box = cam * (1.0f/cam_aspect);
706 }
707
708 static void blender_camera_border_subset(BL::RenderEngine& b_engine,
709                                          BL::RenderSettings& b_render,
710                                          BL::Scene& b_scene,
711                                          BL::SpaceView3D& b_v3d,
712                                          BL::RegionView3D& b_rv3d,
713                                          BL::Object& b_ob,
714                                          int width, int height,
715                                          const BoundBox2D &border,
716                                          BoundBox2D *result)
717 {
718         /* Determine camera viewport subset. */
719         BoundBox2D view_box, cam_box;
720         blender_camera_view_subset(b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height,
721                                    &view_box, &cam_box);
722
723         /* Determine viewport subset matching given border. */
724         cam_box = cam_box.make_relative_to(view_box);
725         *result = cam_box.subset(border);
726 }
727
728 static void blender_camera_border(BlenderCamera *bcam,
729                                   BL::RenderEngine& b_engine,
730                                   BL::RenderSettings& b_render,
731                                   BL::Scene& b_scene,
732                                   BL::SpaceView3D& b_v3d,
733                                   BL::RegionView3D& b_rv3d,
734                                   int width, int height)
735 {
736         bool is_camera_view;
737
738         /* camera view? */
739         is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
740
741         if(!is_camera_view) {
742                 /* for non-camera view check whether render border is enabled for viewport
743                  * and if so use border from 3d viewport
744                  * assume viewport has got correctly clamped border already
745                  */
746                 if(b_v3d.use_render_border()) {
747                         bcam->border.left = b_v3d.render_border_min_x();
748                         bcam->border.right = b_v3d.render_border_max_x();
749                         bcam->border.bottom = b_v3d.render_border_min_y();
750                         bcam->border.top = b_v3d.render_border_max_y();
751                 }
752                 return;
753         }
754
755         BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
756
757         if(!b_ob)
758                 return;
759
760         /* Determine camera border inside the viewport. */
761         BoundBox2D full_border;
762         blender_camera_border_subset(b_engine,
763                                      b_render,
764                                      b_scene,
765                                      b_v3d,
766                                      b_rv3d,
767                                      b_ob,
768                                      width, height,
769                                      full_border,
770                                      &bcam->viewport_camera_border);
771
772         if(!b_render.use_border()) {
773                 return;
774         }
775
776         bcam->border.left = b_render.border_min_x();
777         bcam->border.right = b_render.border_max_x();
778         bcam->border.bottom = b_render.border_min_y();
779         bcam->border.top = b_render.border_max_y();
780
781         /* Determine viewport subset matching camera border. */
782         blender_camera_border_subset(b_engine,
783                                      b_render,
784                                      b_scene,
785                                      b_v3d,
786                                      b_rv3d,
787                                      b_ob,
788                                      width, height,
789                                      bcam->border,
790                                      &bcam->border);
791         bcam->border = bcam->border.clamp();
792 }
793
794 void BlenderSync::sync_view(BL::SpaceView3D& b_v3d,
795                             BL::RegionView3D& b_rv3d,
796                             int width, int height)
797 {
798         BlenderCamera bcam;
799         BL::RenderSettings b_render_settings(b_scene.render());
800         blender_camera_init(&bcam, b_render_settings);
801         blender_camera_from_view(&bcam,
802                                  b_engine,
803                                  b_scene,
804                                  b_v3d,
805                                  b_rv3d,
806                                  width, height);
807         blender_camera_border(&bcam,
808                               b_engine,
809                               b_render_settings,
810                               b_scene,
811                               b_v3d,
812                               b_rv3d,
813                               width, height);
814         blender_camera_sync(scene->camera, &bcam, width, height, "");
815 }
816
817 BufferParams BlenderSync::get_buffer_params(BL::RenderSettings& b_render,
818                                             BL::SpaceView3D& b_v3d,
819                                             BL::RegionView3D& b_rv3d,
820                                             Camera *cam,
821                                             int width, int height)
822 {
823         BufferParams params;
824         bool use_border = false;
825
826         params.full_width = width;
827         params.full_height = height;
828
829         if(b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
830                 use_border = b_v3d.use_render_border();
831         else
832                 use_border = b_render.use_border();
833
834         if(use_border) {
835                 /* border render */
836                 /* the viewport may offset the border outside the view */
837                 BoundBox2D border = cam->border.clamp();
838                 params.full_x = (int)(border.left * (float)width);
839                 params.full_y = (int)(border.bottom * (float)height);
840                 params.width = (int)(border.right * (float)width) - params.full_x;
841                 params.height = (int)(border.top * (float)height) - params.full_y;
842
843                 /* survive in case border goes out of view or becomes too small */
844                 params.width = max(params.width, 1);
845                 params.height = max(params.height, 1);
846         }
847         else {
848                 params.width = width;
849                 params.height = height;
850         }
851
852         return params;
853 }
854
855 CCL_NAMESPACE_END
856