Fix T45034: MirrorBall rendering on wrong camera axis
[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 "camera.h"
18 #include "scene.h"
19
20 #include "blender_sync.h"
21 #include "blender_util.h"
22
23 #include "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
40         float aperturesize;
41         uint apertureblades;
42         float aperturerotation;
43         float focaldistance;
44
45         float2 shift;
46         float2 offset;
47         float zoom;
48
49         float2 pixelaspect;
50
51         float aperture_ratio;
52
53         PanoramaType panorama_type;
54         float fisheye_fov;
55         float fisheye_lens;
56         float latitude_min;
57         float latitude_max;
58         float longitude_min;
59         float longitude_max;
60
61         enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
62         float sensor_width;
63         float sensor_height;
64
65         int full_width;
66         int full_height;
67
68         BoundBox2D border;
69         BoundBox2D pano_viewplane;
70         BoundBox2D viewport_camera_border;
71
72         Transform matrix;
73 };
74
75 static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render)
76 {
77         memset(bcam, 0, sizeof(BlenderCamera));
78
79         bcam->type = CAMERA_PERSPECTIVE;
80         bcam->zoom = 1.0f;
81         bcam->pixelaspect = make_float2(1.0f, 1.0f);
82         bcam->sensor_width = 32.0f;
83         bcam->sensor_height = 18.0f;
84         bcam->sensor_fit = BlenderCamera::AUTO;
85         bcam->shuttertime = 1.0f;
86         bcam->border.right = 1.0f;
87         bcam->border.top = 1.0f;
88         bcam->pano_viewplane.right = 1.0f;
89         bcam->pano_viewplane.top = 1.0f;
90         bcam->viewport_camera_border.right = 1.0f;
91         bcam->viewport_camera_border.top = 1.0f;
92
93         /* render resolution */
94         bcam->full_width = render_resolution_x(b_render);
95         bcam->full_height = render_resolution_y(b_render);
96 }
97
98 static float blender_camera_focal_distance(BL::RenderEngine b_engine, BL::Object b_ob, BL::Camera b_camera)
99 {
100         BL::Object b_dof_object = b_camera.dof_object();
101
102         if(!b_dof_object)
103                 return b_camera.dof_distance();
104         
105         /* for dof object, return distance along camera Z direction */
106         BL::Array<float, 16> b_ob_matrix;
107         b_engine.camera_model_matrix(b_ob, b_ob_matrix);
108         Transform obmat = get_transform(b_ob_matrix);
109         Transform dofmat = get_transform(b_dof_object.matrix_world());
110         Transform mat = transform_inverse(obmat) * dofmat;
111
112         return fabsf(transform_get_column(&mat, 3).z);
113 }
114
115 static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Object b_ob, bool skip_panorama = false)
116 {
117         BL::ID b_ob_data = b_ob.data();
118
119         if(b_ob_data.is_a(&RNA_Camera)) {
120                 BL::Camera b_camera(b_ob_data);
121                 PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
122
123                 bcam->nearclip = b_camera.clip_start();
124                 bcam->farclip = b_camera.clip_end();
125
126                 switch(b_camera.type())
127                 {
128                         case BL::Camera::type_ORTHO:
129                                 bcam->type = CAMERA_ORTHOGRAPHIC;
130                                 break;
131                         case BL::Camera::type_PANO:
132                                 if(!skip_panorama)
133                                         bcam->type = CAMERA_PANORAMA;
134                                 else
135                                         bcam->type = CAMERA_PERSPECTIVE;
136                                 break;
137                         case BL::Camera::type_PERSP:
138                         default:
139                                 bcam->type = CAMERA_PERSPECTIVE;
140                                 break;
141                 }       
142
143                 switch(RNA_enum_get(&ccamera, "panorama_type"))
144                 {
145                         case 1:
146                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
147                                 break;
148                         case 2:
149                                 bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
150                                 break;
151                         case 3:
152                                 bcam->panorama_type = PANORAMA_MIRRORBALL;
153                                 break;
154                         case 0:
155                         default:
156                                 bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
157                                 break;
158                 }       
159
160                 bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
161                 bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
162                 bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min");
163                 bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max");
164                 bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
165                 bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
166
167                 bcam->ortho_scale = b_camera.ortho_scale();
168
169                 bcam->lens = b_camera.lens();
170
171                 /* allow f/stop number to change aperture_size but still
172                  * give manual control over aperture radius */
173                 int aperture_type = RNA_enum_get(&ccamera, "aperture_type");
174
175                 if(aperture_type == 1) {
176                         float fstop = RNA_float_get(&ccamera, "aperture_fstop");
177                         fstop = max(fstop, 1e-5f);
178
179                         if(bcam->type == CAMERA_ORTHOGRAPHIC)
180                                 bcam->aperturesize = 1.0f/(2.0f*fstop);
181                         else
182                                 bcam->aperturesize = (bcam->lens*1e-3f)/(2.0f*fstop);
183                 }
184                 else
185                         bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
186
187                 bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
188                 bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
189                 bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera);
190                 bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
191
192                 bcam->shift.x = b_engine.camera_shift_x(b_ob);
193                 bcam->shift.y = b_camera.shift_y();
194
195                 bcam->sensor_width = b_camera.sensor_width();
196                 bcam->sensor_height = b_camera.sensor_height();
197
198                 if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
199                         bcam->sensor_fit = BlenderCamera::AUTO;
200                 else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
201                         bcam->sensor_fit = BlenderCamera::HORIZONTAL;
202                 else
203                         bcam->sensor_fit = BlenderCamera::VERTICAL;
204         }
205         else {
206                 /* from lamp not implemented yet */
207         }
208 }
209
210 static Transform blender_camera_matrix(const Transform& tfm,
211                                        const CameraType type,
212                                        const PanoramaType panorama_type)
213 {
214         Transform result;
215
216         if(type == CAMERA_PANORAMA) {
217                 if(panorama_type == PANORAMA_MIRRORBALL) {
218                         /* Mirror ball camera is looking into the negative Y direction
219                          * which matches texture mirror ball mapping.
220                          */
221                         result = tfm *
222                                 make_transform(1.0f, 0.0f, 0.0f, 0.0f,
223                                                0.0f, 0.0f, 1.0f, 0.0f,
224                                                0.0f, 1.0f, 0.0f, 0.0f,
225                                                0.0f, 0.0f, 0.0f, 1.0f);
226                 }
227                 else {
228                         /* Make it so environment camera needs to be pointed in the direction
229                          * of the positive x-axis to match an environment texture, this way
230                          * it is looking at the center of the texture
231                          */
232                         result = tfm *
233                                 make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
234                                                 0.0f,  0.0f, 1.0f, 0.0f,
235                                                -1.0f,  0.0f, 0.0f, 0.0f,
236                                                 0.0f,  0.0f, 0.0f, 1.0f);
237                 }
238         }
239         else {
240                 /* note the blender camera points along the negative z-axis */
241                 result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
242         }
243
244         return transform_clear_scale(result);
245 }
246
247 static void blender_camera_viewplane(BlenderCamera *bcam, int width, int height,
248         BoundBox2D *viewplane, float *aspectratio, float *sensor_size)
249 {
250         /* dimensions */
251         float xratio = (float)width*bcam->pixelaspect.x;
252         float yratio = (float)height*bcam->pixelaspect.y;
253
254         /* compute x/y aspect and ratio */
255         float xaspect, yaspect;
256         bool horizontal_fit;
257
258         /* sensor fitting */
259         if(bcam->sensor_fit == BlenderCamera::AUTO) {
260                 horizontal_fit = (xratio > yratio);
261                 *sensor_size = bcam->sensor_width;
262         }
263         else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
264                 horizontal_fit = true;
265                 *sensor_size = bcam->sensor_width;
266         }
267         else {
268                 horizontal_fit = false;
269                 *sensor_size = bcam->sensor_height;
270         }
271
272         if(horizontal_fit) {
273                 *aspectratio = xratio/yratio;
274                 xaspect = *aspectratio;
275                 yaspect = 1.0f;
276         }
277         else {
278                 *aspectratio = yratio/xratio;
279                 xaspect = 1.0f;
280                 yaspect = *aspectratio;
281         }
282
283         /* modify aspect for orthographic scale */
284         if(bcam->type == CAMERA_ORTHOGRAPHIC) {
285                 xaspect = xaspect*bcam->ortho_scale/(*aspectratio*2.0f);
286                 yaspect = yaspect*bcam->ortho_scale/(*aspectratio*2.0f);
287                 *aspectratio = bcam->ortho_scale/2.0f;
288         }
289
290         if(bcam->type == CAMERA_PANORAMA) {
291                 /* set viewplane */
292                 *viewplane = bcam->pano_viewplane;
293         }
294         else {
295                 /* set viewplane */
296                 viewplane->left = -xaspect;
297                 viewplane->right = xaspect;
298                 viewplane->bottom = -yaspect;
299                 viewplane->top = yaspect;
300
301                 /* zoom for 3d camera view */
302                 *viewplane = (*viewplane) * bcam->zoom;
303
304                 /* modify viewplane with camera shift and 3d camera view offset */
305                 float dx = 2.0f*(*aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
306                 float dy = 2.0f*(*aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
307
308                 viewplane->left += dx;
309                 viewplane->right += dx;
310                 viewplane->bottom += dy;
311                 viewplane->top += dy;
312         }
313 }
314
315 static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
316 {
317         /* copy camera to compare later */
318         Camera prevcam = *cam;
319         float aspectratio, sensor_size;
320
321         /* viewplane */
322         blender_camera_viewplane(bcam, width, height,
323                 &cam->viewplane, &aspectratio, &sensor_size);
324
325         /* panorama sensor */
326         if(bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
327                 float fit_xratio = (float)bcam->full_width*bcam->pixelaspect.x;
328                 float fit_yratio = (float)bcam->full_height*bcam->pixelaspect.y;
329                 bool horizontal_fit;
330                 float sensor_size;
331
332                 if(bcam->sensor_fit == BlenderCamera::AUTO) {
333                         horizontal_fit = (fit_xratio > fit_yratio);
334                         sensor_size = bcam->sensor_width;
335                 }
336                 else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
337                         horizontal_fit = true;
338                         sensor_size = bcam->sensor_width;
339                 }
340                 else { /* vertical */
341                         horizontal_fit = false;
342                         sensor_size = bcam->sensor_height;
343                 }
344
345                 if(horizontal_fit) {
346                         cam->sensorwidth = sensor_size;
347                         cam->sensorheight = sensor_size * fit_yratio / fit_xratio;
348                 }
349                 else {
350                         cam->sensorwidth = sensor_size * fit_xratio / fit_yratio;
351                         cam->sensorheight = sensor_size;
352                 }
353         }
354
355         /* clipping distances */
356         cam->nearclip = bcam->nearclip;
357         cam->farclip = bcam->farclip;
358
359         /* type */
360         cam->type = bcam->type;
361
362         /* panorama */
363         cam->panorama_type = bcam->panorama_type;
364         cam->fisheye_fov = bcam->fisheye_fov;
365         cam->fisheye_lens = bcam->fisheye_lens;
366         cam->latitude_min = bcam->latitude_min;
367         cam->latitude_max = bcam->latitude_max;
368
369         cam->longitude_min = bcam->longitude_min;
370         cam->longitude_max = bcam->longitude_max;
371
372         /* anamorphic lens bokeh */
373         cam->aperture_ratio = bcam->aperture_ratio;
374
375         /* perspective */
376         cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio);
377         cam->focaldistance = bcam->focaldistance;
378         cam->aperturesize = bcam->aperturesize;
379         cam->blades = bcam->apertureblades;
380         cam->bladesrotation = bcam->aperturerotation;
381
382         /* transform */
383         cam->matrix = blender_camera_matrix(bcam->matrix,
384                                             bcam->type,
385                                             bcam->panorama_type);
386         cam->motion.pre = cam->matrix;
387         cam->motion.post = cam->matrix;
388         cam->use_motion = false;
389         cam->shuttertime = bcam->shuttertime;
390
391         /* border */
392         cam->border = bcam->border;
393         cam->viewport_camera_border = bcam->viewport_camera_border;
394
395         /* set update flag */
396         if(cam->modified(prevcam))
397                 cam->tag_update();
398 }
399
400 /* Sync Render Camera */
401
402 void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override, int width, int height)
403 {
404         BlenderCamera bcam;
405         blender_camera_init(&bcam, b_render);
406
407         /* pixel aspect */
408         bcam.pixelaspect.x = b_render.pixel_aspect_x();
409         bcam.pixelaspect.y = b_render.pixel_aspect_y();
410         bcam.shuttertime = b_render.motion_blur_shutter();
411
412         /* border */
413         if(b_render.use_border()) {
414                 bcam.border.left = b_render.border_min_x();
415                 bcam.border.right = b_render.border_max_x();
416                 bcam.border.bottom = b_render.border_min_y();
417                 bcam.border.top = b_render.border_max_y();
418         }
419
420         /* camera object */
421         BL::Object b_ob = b_scene.camera();
422
423         if(b_override)
424                 b_ob = b_override;
425
426         if(b_ob) {
427                 BL::Array<float, 16> b_ob_matrix;
428                 blender_camera_from_object(&bcam, b_engine, b_ob);
429                 b_engine.camera_model_matrix(b_ob, b_ob_matrix);
430                 bcam.matrix = get_transform(b_ob_matrix);
431         }
432
433         /* sync */
434         Camera *cam = scene->camera;
435         blender_camera_sync(cam, &bcam, width, height);
436 }
437
438 void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
439 {
440         Camera *cam = scene->camera;
441         BL::Array<float, 16> b_ob_matrix;
442         b_engine.camera_model_matrix(b_ob, b_ob_matrix);
443         Transform tfm = get_transform(b_ob_matrix);
444         tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
445
446         if(tfm != cam->matrix) {
447                 VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
448                 if(motion_time == -1.0f) {
449                         cam->motion.pre = tfm;
450                         cam->use_motion = true;
451                 }
452                 else if(motion_time == 1.0f) {
453                         cam->motion.post = tfm;
454                         cam->use_motion = true;
455                 }
456         }
457 }
458
459 /* Sync 3D View Camera */
460
461 static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
462         BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box);
463
464 static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false)
465 {
466         /* 3d view parameters */
467         bcam->nearclip = b_v3d.clip_start();
468         bcam->farclip = b_v3d.clip_end();
469         bcam->lens = b_v3d.lens();
470         bcam->shuttertime = b_scene.render().motion_blur_shutter();
471
472         if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
473                 /* camera view */
474                 BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
475
476                 if(b_ob) {
477                         blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama);
478
479                         if(!skip_panorama && bcam->type == CAMERA_PANORAMA) {
480                                 /* in panorama camera view, we map viewplane to camera border */
481                                 BoundBox2D view_box, cam_box;
482
483                                 blender_camera_view_subset(b_engine, b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
484                                         &view_box, &cam_box);
485
486                                 bcam->pano_viewplane = view_box.make_relative_to(cam_box);
487                         }
488                         else {
489                                 /* magic zoom formula */
490                                 bcam->zoom = (float)b_rv3d.view_camera_zoom();
491                                 bcam->zoom = (1.41421f + bcam->zoom/50.0f);
492                                 bcam->zoom *= bcam->zoom;
493                                 bcam->zoom = 2.0f/bcam->zoom;
494
495                                 /* offset */
496                                 bcam->offset = get_float2(b_rv3d.view_camera_offset());
497                         }
498                 }
499         }
500         else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
501                 /* orthographic view */
502                 bcam->farclip *= 0.5f;
503                 bcam->nearclip = -bcam->farclip;
504
505                 float sensor_size;
506                 if(bcam->sensor_fit == BlenderCamera::VERTICAL)
507                         sensor_size = bcam->sensor_height;
508                 else
509                         sensor_size = bcam->sensor_width;
510
511                 bcam->type = CAMERA_ORTHOGRAPHIC;
512                 bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens();
513         }
514
515         bcam->zoom *= 2.0f;
516
517         /* 3d view transform */
518         bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
519 }
520
521 static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
522         BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box)
523 {
524         BoundBox2D cam, view;
525         float view_aspect, cam_aspect, sensor_size;
526
527         /* get viewport viewplane */
528         BlenderCamera view_bcam;
529         blender_camera_init(&view_bcam, b_render);
530         blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true);
531
532         blender_camera_viewplane(&view_bcam, width, height,
533                 &view, &view_aspect, &sensor_size);
534
535         /* get camera viewplane */
536         BlenderCamera cam_bcam;
537         blender_camera_init(&cam_bcam, b_render);
538         blender_camera_from_object(&cam_bcam, b_engine, b_ob, true);
539
540         blender_camera_viewplane(&cam_bcam, cam_bcam.full_width, cam_bcam.full_height,
541                 &cam, &cam_aspect, &sensor_size);
542         
543         /* return */
544         *view_box = view * (1.0f/view_aspect);
545         *cam_box = cam * (1.0f/cam_aspect);
546 }
547
548 static void blender_camera_border_subset(BL::RenderEngine b_engine,
549                                          BL::RenderSettings b_render,
550                                          BL::Scene b_scene,
551                                          BL::SpaceView3D b_v3d,
552                                          BL::RegionView3D b_rv3d,
553                                          BL::Object b_ob,
554                                          int width, int height,
555                                          const BoundBox2D &border,
556                                          BoundBox2D *result)
557 {
558         /* Determine camera viewport subset. */
559         BoundBox2D view_box, cam_box;
560         blender_camera_view_subset(b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height,
561                                    &view_box, &cam_box);
562
563         /* Determine viewport subset matching given border. */
564         cam_box = cam_box.make_relative_to(view_box);
565         *result = cam_box.subset(border);
566 }
567
568 static void blender_camera_border(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d,
569         BL::RegionView3D b_rv3d, int width, int height)
570 {
571         bool is_camera_view;
572
573         /* camera view? */
574         is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA;
575
576         if(!is_camera_view) {
577                 /* for non-camera view check whether render border is enabled for viewport
578                  * and if so use border from 3d viewport
579                  * assume viewport has got correctly clamped border already
580                  */
581                 if(b_v3d.use_render_border()) {
582                         bcam->border.left = b_v3d.render_border_min_x();
583                         bcam->border.right = b_v3d.render_border_max_x();
584                         bcam->border.bottom = b_v3d.render_border_min_y();
585                         bcam->border.top = b_v3d.render_border_max_y();
586                 }
587                 return;
588         }
589
590         BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
591
592         if(!b_ob)
593                 return;
594
595         /* Determine camera border inside the viewport. */
596         BoundBox2D full_border;
597         blender_camera_border_subset(b_engine,
598                                      b_render,
599                                      b_scene,
600                                      b_v3d,
601                                      b_rv3d,
602                                      b_ob,
603                                      width, height,
604                                      full_border,
605                                      &bcam->viewport_camera_border);
606
607         if(!b_render.use_border()) {
608                 return;
609         }
610
611         bcam->border.left = b_render.border_min_x();
612         bcam->border.right = b_render.border_max_x();
613         bcam->border.bottom = b_render.border_min_y();
614         bcam->border.top = b_render.border_max_y();
615
616         /* Determine viewport subset matching camera border. */
617         blender_camera_border_subset(b_engine,
618                                      b_render,
619                                      b_scene,
620                                      b_v3d,
621                                      b_rv3d,
622                                      b_ob,
623                                      width, height,
624                                      bcam->border,
625                                      &bcam->border);
626         bcam->border.clamp();
627 }
628
629 void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
630 {
631         BlenderCamera bcam;
632         blender_camera_init(&bcam, b_scene.render());
633         blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
634         blender_camera_border(&bcam, b_engine, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
635
636         blender_camera_sync(scene->camera, &bcam, width, height);
637 }
638
639 BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
640 {
641         BufferParams params;
642         bool use_border = false;
643
644         params.full_width = width;
645         params.full_height = height;
646
647         if(b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA)
648                 use_border = b_v3d.use_render_border();
649         else
650                 use_border = b_render.use_border();
651
652         if(use_border) {
653                 /* border render */
654                 /* the viewport may offset the border outside the view */
655                 BoundBox2D border = cam->border.clamp();
656                 params.full_x = (int)(border.left * (float)width);
657                 params.full_y = (int)(border.bottom * (float)height);
658                 params.width = (int)(border.right * (float)width) - params.full_x;
659                 params.height = (int)(border.top * (float)height) - params.full_y;
660
661                 /* survive in case border goes out of view or becomes too small */
662                 params.width = max(params.width, 1);
663                 params.height = max(params.height, 1);
664         }
665         else {
666                 params.width = width;
667                 params.height = height;
668         }
669
670         return params;
671 }
672
673 CCL_NAMESPACE_END
674