Fix gizmos showing for non-visible objects
[blender.git] / source / blender / editors / space_view3d / view3d_gizmo_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  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/editors/space_view3d/view3d_gizmo_camera.c
22  *  \ingroup spview3d
23  */
24
25
26 #include "BLI_blenlib.h"
27 #include "BLI_math.h"
28 #include "BLI_utildefines.h"
29
30 #include "BKE_camera.h"
31 #include "BKE_context.h"
32
33 #include "DNA_object_types.h"
34 #include "DNA_camera_types.h"
35
36 #include "ED_armature.h"
37 #include "ED_screen.h"
38 #include "ED_gizmo_library.h"
39
40 #include "UI_resources.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48 #include "WM_message.h"
49
50 #include "view3d_intern.h"  /* own include */
51
52
53 /* -------------------------------------------------------------------- */
54
55 /** \name Camera Gizmos
56  * \{ */
57
58 struct CameraWidgetGroup {
59         wmGizmo *dop_dist;
60         wmGizmo *focal_len;
61         wmGizmo *ortho_scale;
62 };
63
64 static bool WIDGETGROUP_camera_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
65 {
66         View3D *v3d = CTX_wm_view3d(C);
67         if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
68             (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
69         {
70                 return false;
71         }
72
73         ViewLayer *view_layer = CTX_data_view_layer(C);
74         Base *base = BASACT(view_layer);
75         if (base && BASE_VISIBLE(v3d, base)) {
76                 Object *ob = base->object;
77                 if (ob->type == OB_CAMERA) {
78                         Camera *camera = ob->data;
79                         /* TODO: support overrides. */
80                         if (camera->id.lib == NULL) {
81                                 return true;
82                         }
83                 }
84         }
85         return false;
86 }
87
88 static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup)
89 {
90         ViewLayer *view_layer = CTX_data_view_layer(C);
91         Object *ob = OBACT(view_layer);
92         float dir[3];
93
94         const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
95
96         struct CameraWidgetGroup *cagzgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__);
97         gzgroup->customdata = cagzgroup;
98
99         negate_v3_v3(dir, ob->obmat[2]);
100
101         /* dof distance */
102         {
103                 wmGizmo *gz;
104                 gz = cagzgroup->dop_dist = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
105                 RNA_enum_set(gz->ptr, "draw_style",  ED_GIZMO_ARROW_STYLE_CROSS);
106                 WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true);
107
108                 UI_GetThemeColor3fv(TH_GIZMO_A, gz->color);
109                 UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
110         }
111
112         /* focal length
113          * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */
114         {
115                 wmGizmo *gz;
116                 gz = cagzgroup->focal_len = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
117                 gz->flag |= WM_GIZMO_DRAW_NO_SCALE;
118                 RNA_enum_set(gz->ptr, "draw_style",  ED_GIZMO_ARROW_STYLE_CONE);
119                 RNA_enum_set(gz->ptr, "transform",  ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED);
120
121                 UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
122                 UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
123
124                 gz = cagzgroup->ortho_scale = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
125                 gz->flag |= WM_GIZMO_DRAW_NO_SCALE;
126                 RNA_enum_set(gz->ptr, "draw_style",  ED_GIZMO_ARROW_STYLE_CONE);
127                 RNA_enum_set(gz->ptr, "transform",  ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED);
128
129                 UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
130                 UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
131         }
132 }
133
134 static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup)
135 {
136         if (!gzgroup->customdata)
137                 return;
138
139         struct CameraWidgetGroup *cagzgroup = gzgroup->customdata;
140         ViewLayer *view_layer = CTX_data_view_layer(C);
141         Object *ob = OBACT(view_layer);
142         Camera *ca = ob->data;
143         PointerRNA camera_ptr;
144         float dir[3];
145
146         RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr);
147
148         negate_v3_v3(dir, ob->obmat[2]);
149
150         if (ca->flag & CAM_SHOWLIMITS) {
151                 WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->obmat[3]);
152                 WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->obmat[1], dir);
153                 WM_gizmo_set_scale(cagzgroup->dop_dist, ca->drawsize);
154                 WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, false);
155
156                 /* need to set property here for undo. TODO would prefer to do this in _init */
157                 WM_gizmo_target_property_def_rna(cagzgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1);
158         }
159         else {
160                 WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, true);
161         }
162
163         /* TODO - make focal length/ortho ob_scale_inv widget optional */
164         const Scene *scene = CTX_data_scene(C);
165         const float aspx = (float)scene->r.xsch * scene->r.xasp;
166         const float aspy = (float)scene->r.ysch * scene->r.yasp;
167         const bool is_ortho = (ca->type == CAM_ORTHO);
168         const int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, aspx, aspy);
169         wmGizmo *widget = is_ortho ? cagzgroup->ortho_scale : cagzgroup->focal_len;
170         float scale_matrix;
171         if (true) {
172                 float offset[3];
173                 float aspect[2];
174
175                 WM_gizmo_set_flag(widget, WM_GIZMO_HIDDEN, false);
176                 WM_gizmo_set_flag(is_ortho ? cagzgroup->focal_len : cagzgroup->ortho_scale, WM_GIZMO_HIDDEN, true);
177
178
179                 /* account for lens shifting */
180                 offset[0] = ((ob->size[0] > 0.0f) ? -2.0f : 2.0f) * ca->shiftx;
181                 offset[1] = 2.0f * ca->shifty;
182                 offset[2] = 0.0f;
183
184                 /* get aspect */
185                 aspect[0] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? 1.0f : aspx / aspy;
186                 aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f;
187
188                 unit_m4(widget->matrix_basis);
189                 WM_gizmo_set_matrix_location(widget, ob->obmat[3]);
190                 WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir);
191
192                 if (is_ortho) {
193                         scale_matrix = ca->ortho_scale * 0.5f;
194                 }
195                 else {
196                         const float ob_scale_inv[3] = {
197                                 1.0f / len_v3(ob->obmat[0]),
198                                 1.0f / len_v3(ob->obmat[1]),
199                                 1.0f / len_v3(ob->obmat[2]),
200                         };
201                         const float ob_scale_uniform_inv = (ob_scale_inv[0] + ob_scale_inv[1] + ob_scale_inv[2]) / 3.0f;
202                         scale_matrix = (ca->drawsize * 0.5f) / ob_scale_uniform_inv;
203                 }
204                 mul_v3_fl(widget->matrix_basis[0], scale_matrix);
205                 mul_v3_fl(widget->matrix_basis[1], scale_matrix);
206
207                 RNA_float_set_array(widget->ptr, "aspect", aspect);
208
209                 WM_gizmo_set_matrix_offset_location(widget, offset);
210         }
211
212         /* define & update properties */
213         {
214                 const char *propname = is_ortho ? "ortho_scale" : "lens";
215                 PropertyRNA *prop = RNA_struct_find_property(&camera_ptr, propname);
216                 const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(widget->type, "offset");
217
218                 WM_gizmo_target_property_clear_rna_ptr(widget, gz_prop_type);
219
220                 float min, max, range;
221                 float step, precision;
222
223                 /* get property range */
224                 RNA_property_float_ui_range(&camera_ptr, prop, &min, &max, &step, &precision);
225                 range = max - min;
226
227                 ED_gizmo_arrow3d_set_range_fac(
228                         widget, is_ortho ?
229                         ((range / ca->ortho_scale) * ca->drawsize) :
230                         (scale_matrix * range /
231                          /* Half sensor, intentionally use sensor from camera and not calculated above. */
232                          (0.5f * ((sensor_fit == CAMERA_SENSOR_FIT_HOR) ? ca->sensor_x : ca->sensor_y))));
233
234                 WM_gizmo_target_property_def_rna_ptr(widget, gz_prop_type, &camera_ptr, prop, -1);
235         }
236
237 }
238
239 static void WIDGETGROUP_camera_message_subscribe(
240         const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
241 {
242         ARegion *ar = CTX_wm_region(C);
243         ViewLayer *view_layer = CTX_data_view_layer(C);
244         Object *ob = OBACT(view_layer);
245         Camera *ca = ob->data;
246
247         wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
248                 .owner = ar,
249                 .user_data = gzgroup->parent_gzmap,
250                 .notify = WM_gizmo_do_msg_notify_tag_refresh,
251         };
252
253         {
254                 extern PropertyRNA rna_Camera_dof_distance;
255                 extern PropertyRNA rna_Camera_display_size;
256                 extern PropertyRNA rna_Camera_ortho_scale;
257                 extern PropertyRNA rna_Camera_sensor_fit;
258                 extern PropertyRNA rna_Camera_sensor_width;
259                 extern PropertyRNA rna_Camera_shift_x;
260                 extern PropertyRNA rna_Camera_shift_y;
261                 extern PropertyRNA rna_Camera_type;
262                 extern PropertyRNA rna_Camera_lens;
263                 const PropertyRNA *props[] = {
264                         &rna_Camera_dof_distance,
265                         &rna_Camera_display_size,
266                         &rna_Camera_ortho_scale,
267                         &rna_Camera_sensor_fit,
268                         &rna_Camera_sensor_width,
269                         &rna_Camera_shift_x,
270                         &rna_Camera_shift_y,
271                         &rna_Camera_type,
272                         &rna_Camera_lens,
273                 };
274
275                 PointerRNA idptr;
276                 RNA_id_pointer_create(&ca->id, &idptr);
277
278                 for (int i = 0; i < ARRAY_SIZE(props); i++) {
279                         WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
280                 }
281         }
282
283         /* Subscribe to render settings */
284         {
285                 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_gz_tag_refresh);
286                 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_gz_tag_refresh);
287                 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_gz_tag_refresh);
288                 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_gz_tag_refresh);
289         }
290 }
291
292 void VIEW3D_GGT_camera(wmGizmoGroupType *gzgt)
293 {
294         gzgt->name = "Camera Widgets";
295         gzgt->idname = "VIEW3D_GGT_camera";
296
297         gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
298                      WM_GIZMOGROUPTYPE_3D |
299                      WM_GIZMOGROUPTYPE_DEPTH_3D);
300
301         gzgt->poll = WIDGETGROUP_camera_poll;
302         gzgt->setup = WIDGETGROUP_camera_setup;
303         gzgt->refresh = WIDGETGROUP_camera_refresh;
304         gzgt->message_subscribe = WIDGETGROUP_camera_message_subscribe;
305 }
306
307 /** \} */
308
309 /* -------------------------------------------------------------------- */
310
311 /** \name CameraView Gizmos
312  * \{ */
313
314 struct CameraViewWidgetGroup {
315         wmGizmo *border;
316
317         struct {
318                 rctf *edit_border;
319                 rctf view_border;
320         } state;
321 };
322
323 /* scale callbacks */
324 static void gizmo_render_border_prop_matrix_get(
325         const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
326         void *value_p)
327 {
328         float (*matrix)[4] = value_p;
329         BLI_assert(gz_prop->type->array_length == 16);
330         struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data;
331         const rctf *border = viewgroup->state.edit_border;
332
333         unit_m4(matrix);
334         matrix[0][0] = BLI_rctf_size_x(border);
335         matrix[1][1] = BLI_rctf_size_y(border);
336         matrix[3][0] = BLI_rctf_cent_x(border);
337         matrix[3][1] = BLI_rctf_cent_y(border);
338 }
339
340 static void gizmo_render_border_prop_matrix_set(
341         const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
342         const void *value_p)
343 {
344         const float (*matrix)[4] = value_p;
345         struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data;
346         rctf *border = viewgroup->state.edit_border;
347         BLI_assert(gz_prop->type->array_length == 16);
348
349         BLI_rctf_resize(border, len_v3(matrix[0]), len_v3(matrix[1]));
350         BLI_rctf_recenter(border, matrix[3][0], matrix[3][1]);
351         BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, border, border);
352 }
353
354 static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
355 {
356         Scene *scene = CTX_data_scene(C);
357
358         /* This is just so the border isn't always in the way,
359          * stealing mouse clicks from regular usage.
360          * We could change the rules for when to show. */
361         {
362                 ViewLayer *view_layer = CTX_data_view_layer(C);
363                 if (scene->camera != OBACT(view_layer)) {
364                         return false;
365                 }
366         }
367
368         View3D *v3d = CTX_wm_view3d(C);
369         if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
370             (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
371         {
372                 return false;
373         }
374
375         ARegion *ar = CTX_wm_region(C);
376         RegionView3D *rv3d = ar->regiondata;
377         if (rv3d->persp == RV3D_CAMOB) {
378                 if (scene->r.mode & R_BORDER) {
379                         /* TODO: support overrides. */
380                         if (scene->id.lib == NULL) {
381                                 return true;
382                         }
383                 }
384         }
385         else if (v3d->flag2 & V3D_RENDER_BORDER) {
386                 return true;
387         }
388         return false;
389 }
390
391 static void WIDGETGROUP_camera_view_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
392 {
393         struct CameraViewWidgetGroup *viewgroup = MEM_mallocN(sizeof(struct CameraViewWidgetGroup), __func__);
394
395         viewgroup->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
396
397         RNA_enum_set(viewgroup->border->ptr, "transform",
398                      ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
399         /* Box style is more subtle in this case. */
400         RNA_enum_set(viewgroup->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_BOX);
401
402
403         gzgroup->customdata = viewgroup;
404 }
405
406 static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
407 {
408         struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata;
409
410         ARegion *ar = CTX_wm_region(C);
411         struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
412         RegionView3D *rv3d = ar->regiondata;
413         if (rv3d->persp == RV3D_CAMOB) {
414                 Scene *scene = CTX_data_scene(C);
415                 View3D *v3d = CTX_wm_view3d(C);
416                 ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false);
417         }
418         else {
419                 viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy};
420         }
421
422         wmGizmo *gz = viewgroup->border;
423         unit_m4(gz->matrix_space);
424         mul_v3_fl(gz->matrix_space[0], BLI_rctf_size_x(&viewgroup->state.view_border));
425         mul_v3_fl(gz->matrix_space[1], BLI_rctf_size_y(&viewgroup->state.view_border));
426         gz->matrix_space[3][0] = viewgroup->state.view_border.xmin;
427         gz->matrix_space[3][1] = viewgroup->state.view_border.ymin;
428 }
429
430 static void WIDGETGROUP_camera_view_refresh(const bContext *C, wmGizmoGroup *gzgroup)
431 {
432         struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata;
433
434         View3D *v3d = CTX_wm_view3d(C);
435         ARegion *ar = CTX_wm_region(C);
436         RegionView3D *rv3d = ar->regiondata;
437         Scene *scene = CTX_data_scene(C);
438
439         {
440                 wmGizmo *gz = viewgroup->border;
441                 WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
442
443                 RNA_enum_set(viewgroup->border->ptr, "transform",
444                              ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
445
446                 if (rv3d->persp == RV3D_CAMOB) {
447                         viewgroup->state.edit_border = &scene->r.border;
448                 }
449                 else {
450                         viewgroup->state.edit_border = &v3d->render_border;
451                 }
452
453                 WM_gizmo_target_property_def_func(
454                         gz, "matrix",
455                         &(const struct wmGizmoPropertyFnParams) {
456                             .value_get_fn = gizmo_render_border_prop_matrix_get,
457                             .value_set_fn = gizmo_render_border_prop_matrix_set,
458                             .range_get_fn = NULL,
459                             .user_data = viewgroup,
460                         });
461         }
462
463 }
464
465 void VIEW3D_GGT_camera_view(wmGizmoGroupType *gzgt)
466 {
467         gzgt->name = "Camera View Widgets";
468         gzgt->idname = "VIEW3D_GGT_camera_view";
469
470         gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
471                      WM_GIZMOGROUPTYPE_SCALE);
472
473         gzgt->poll = WIDGETGROUP_camera_view_poll;
474         gzgt->setup = WIDGETGROUP_camera_view_setup;
475         gzgt->draw_prepare = WIDGETGROUP_camera_view_draw_prepare;
476         gzgt->refresh = WIDGETGROUP_camera_view_refresh;
477 }
478
479 /** \} */