2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2008 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_view3d/space_view3d.c
35 #include "DNA_lightprobe_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_gpencil_types.h"
41 #include "MEM_guardedalloc.h"
43 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
47 #include "BKE_context.h"
48 #include "BKE_curve.h"
49 #include "BKE_icons.h"
50 #include "BKE_lattice.h"
52 #include "BKE_mball.h"
54 #include "BKE_object.h"
55 #include "BKE_scene.h"
56 #include "BKE_screen.h"
57 #include "BKE_workspace.h"
59 #include "ED_space_api.h"
60 #include "ED_screen.h"
61 #include "ED_transform.h"
63 #include "GPU_framebuffer.h"
64 #include "GPU_material.h"
65 #include "GPU_viewport.h"
66 #include "GPU_matrix.h"
68 #include "DRW_engine.h"
72 #include "WM_message.h"
73 #include "WM_toolsystem.h"
75 #include "RE_engine.h"
76 #include "RE_pipeline.h"
78 #include "RNA_access.h"
80 #include "UI_interface.h"
81 #include "UI_resources.h"
84 # include "BPY_extern.h"
87 #include "DEG_depsgraph.h"
89 #include "view3d_intern.h" /* own include */
91 /* ******************** manage regions ********************* */
93 ARegion *view3d_has_buttons_region(ScrArea *sa)
97 ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
100 /* add subdiv level; after header */
101 ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
104 if (ar == NULL) return NULL;
106 arnew = MEM_callocN(sizeof(ARegion), "buttons for view3d");
108 BLI_insertlinkafter(&sa->regionbase, ar, arnew);
109 arnew->regiontype = RGN_TYPE_UI;
110 arnew->alignment = RGN_ALIGN_RIGHT;
112 arnew->flag = RGN_FLAG_HIDDEN;
117 ARegion *view3d_has_tools_region(ScrArea *sa)
119 ARegion *ar, *artool = NULL, *arhead;
121 for (ar = sa->regionbase.first; ar; ar = ar->next) {
122 if (ar->regiontype == RGN_TYPE_TOOLS)
126 /* tool region hide/unhide also hides props */
131 if (artool == NULL) {
132 /* add subdiv level; after header */
133 for (arhead = sa->regionbase.first; arhead; arhead = arhead->next)
134 if (arhead->regiontype == RGN_TYPE_HEADER)
138 if (arhead == NULL) return NULL;
140 artool = MEM_callocN(sizeof(ARegion), "tools for view3d");
142 BLI_insertlinkafter(&sa->regionbase, arhead, artool);
143 artool->regiontype = RGN_TYPE_TOOLS;
144 artool->alignment = RGN_ALIGN_LEFT;
145 artool->flag = RGN_FLAG_HIDDEN;
151 /* ****************************************************** */
153 /* function to always find a regionview3d context inside 3D window */
154 RegionView3D *ED_view3d_context_rv3d(bContext *C)
156 RegionView3D *rv3d = CTX_wm_region_view3d(C);
159 ScrArea *sa = CTX_wm_area(C);
160 if (sa && sa->spacetype == SPACE_VIEW3D) {
161 ARegion *ar = BKE_area_find_region_active_win(sa);
163 rv3d = ar->regiondata;
170 /* ideally would return an rv3d but in some cases the region is needed too
171 * so return that, the caller can then access the ar->regiondata */
172 bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
174 ScrArea *sa = CTX_wm_area(C);
179 if (sa && sa->spacetype == SPACE_VIEW3D) {
180 ARegion *ar = CTX_wm_region(C);
181 View3D *v3d = (View3D *)sa->spacedata.first;
185 if ((ar->regiontype == RGN_TYPE_WINDOW) && (rv3d = ar->regiondata) && (rv3d->viewlock & RV3D_LOCKED) == 0) {
191 ARegion *ar_unlock_user = NULL;
192 ARegion *ar_unlock = NULL;
193 for (ar = sa->regionbase.first; ar; ar = ar->next) {
194 /* find the first unlocked rv3d */
195 if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
196 rv3d = ar->regiondata;
197 if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
199 if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
207 /* camera/perspective view get priority when the active region is locked */
208 if (ar_unlock_user) {
210 *r_ar = ar_unlock_user;
226 /* Most of the time this isn't needed since you could assume the view matrix was
227 * set while drawing, however when functions like mesh_foreachScreenVert are
228 * called by selection tools, we can't be sure this object was the last.
230 * for example, transparent objects are drawn after editmode and will cause
231 * the rv3d mat's to change and break selection.
233 * 'ED_view3d_init_mats_rv3d' should be called before
234 * view3d_project_short_clip and view3d_project_short_noclip in cases where
235 * these functions are not used during draw_object
237 void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
239 /* local viewmat and persmat, to calculate projections */
240 mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat);
241 mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->obmat);
243 /* initializes object space clipping, speeds up clip tests */
244 ED_view3d_clipping_local(rv3d, ob->obmat);
247 void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d)
249 ED_view3d_init_mats_rv3d(ob, rv3d);
251 /* we have to multiply instead of loading viewmatob to make
252 * it work with duplis using displists, otherwise it will
253 * override the dupli-matrix */
254 GPU_matrix_mul(ob->obmat);
258 /* ensure we correctly initialize */
259 void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d)
261 zero_m4(rv3d->viewmatob);
262 zero_m4(rv3d->persmatob);
265 void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d)
267 BLI_ASSERT_ZERO_M4(rv3d->viewmatob);
268 BLI_ASSERT_ZERO_M4(rv3d->persmatob);
272 void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
274 RegionView3D *rv3d = ar->regiondata;
276 if (rv3d->render_engine) {
278 BPy_BEGIN_ALLOW_THREADS;
281 WM_jobs_kill_type(wm, ar, WM_JOB_TYPE_RENDER_PREVIEW);
284 BPy_END_ALLOW_THREADS;
287 RE_engine_free(rv3d->render_engine);
288 rv3d->render_engine = NULL;
292 void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
294 wmWindowManager *wm = bmain->wm.first;
296 if (v3d->shading.type != OB_RENDER) {
299 for (ar = sa->regionbase.first; ar; ar = ar->next) {
300 if ((ar->regiontype == RGN_TYPE_WINDOW) && ar->regiondata) {
301 ED_view3d_stop_render_preview(wm, ar);
308 /* ******************** default callbacks for view3d space ***************** */
310 static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
316 v3d = MEM_callocN(sizeof(View3D), "initview3d");
317 v3d->spacetype = SPACE_VIEW3D;
319 v3d->camera = scene->camera;
321 v3d->scenelock = true;
324 v3d->gridsubdiv = 10;
325 BKE_screen_view3d_shading_init(&v3d->shading);
327 v3d->overlay.wireframe_threshold = 0.5f;
328 v3d->overlay.xray_alpha_bone = 0.5f;
329 v3d->overlay.texture_paint_mode_opacity = 0.8;
330 v3d->overlay.weight_paint_mode_opacity = 1.0f;
331 v3d->overlay.vertex_paint_mode_opacity = 0.8;
332 v3d->overlay.edit_flag = V3D_OVERLAY_EDIT_FACES |
333 V3D_OVERLAY_EDIT_SEAMS |
334 V3D_OVERLAY_EDIT_SHARP |
335 V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
336 V3D_OVERLAY_EDIT_FREESTYLE_FACE |
337 V3D_OVERLAY_EDIT_EDGES |
338 V3D_OVERLAY_EDIT_CREASES |
339 V3D_OVERLAY_EDIT_BWEIGHTS |
340 V3D_OVERLAY_EDIT_CU_HANDLES |
341 V3D_OVERLAY_EDIT_CU_NORMALS;
343 v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR;
345 v3d->flag = V3D_SELECT_OUTLINE;
346 v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION;
352 v3d->overlay.gpencil_paper_opacity = 0.5f;
353 v3d->overlay.gpencil_grid_opacity = 0.9f;
355 v3d->bundle_size = 0.2f;
356 v3d->bundle_drawtype = OB_PLAINAXES;
359 v3d->stereo3d_camera = STEREO_3D_ID;
360 v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
361 v3d->stereo3d_convergence_alpha = 0.15f;
362 v3d->stereo3d_volume_alpha = 0.05f;
364 /* grease pencil settings */
365 v3d->vertex_opacity = 1.0f;
366 v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
369 ar = MEM_callocN(sizeof(ARegion), "header for view3d");
371 BLI_addtail(&v3d->regionbase, ar);
372 ar->regiontype = RGN_TYPE_HEADER;
373 ar->alignment = RGN_ALIGN_TOP;
376 ar = MEM_callocN(sizeof(ARegion), "toolshelf for view3d");
378 BLI_addtail(&v3d->regionbase, ar);
379 ar->regiontype = RGN_TYPE_TOOLS;
380 ar->alignment = RGN_ALIGN_LEFT;
381 ar->flag = RGN_FLAG_HIDDEN;
383 /* buttons/list view */
384 ar = MEM_callocN(sizeof(ARegion), "buttons for view3d");
386 BLI_addtail(&v3d->regionbase, ar);
387 ar->regiontype = RGN_TYPE_UI;
388 ar->alignment = RGN_ALIGN_RIGHT;
389 ar->flag = RGN_FLAG_HIDDEN;
392 ar = MEM_callocN(sizeof(ARegion), "main region for view3d");
394 BLI_addtail(&v3d->regionbase, ar);
395 ar->regiontype = RGN_TYPE_WINDOW;
397 ar->regiondata = MEM_callocN(sizeof(RegionView3D), "region view3d");
398 rv3d = ar->regiondata;
399 rv3d->viewquat[0] = 1.0f;
400 rv3d->persp = RV3D_PERSP;
401 rv3d->view = RV3D_VIEW_USER;
404 return (SpaceLink *)v3d;
407 /* not spacelink itself */
408 static void view3d_free(SpaceLink *sl)
410 View3D *vd = (View3D *) sl;
412 if (vd->localvd) MEM_freeN(vd->localvd);
414 if (vd->properties_storage) MEM_freeN(vd->properties_storage);
416 if (vd->fx_settings.ssao)
417 MEM_freeN(vd->fx_settings.ssao);
418 if (vd->fx_settings.dof)
419 MEM_freeN(vd->fx_settings.dof);
423 /* spacetype; init callback */
424 static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
429 static SpaceLink *view3d_duplicate(SpaceLink *sl)
431 View3D *v3do = (View3D *)sl;
432 View3D *v3dn = MEM_dupallocN(sl);
434 /* clear or remove stuff from old */
437 v3dn->localvd = NULL;
438 v3dn->properties_storage = NULL;
441 if (v3dn->shading.type == OB_RENDER)
442 v3dn->shading.type = OB_SOLID;
444 /* copy or clear inside new stuff */
446 v3dn->properties_storage = NULL;
447 if (v3dn->fx_settings.dof)
448 v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
449 if (v3dn->fx_settings.ssao)
450 v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao);
452 return (SpaceLink *)v3dn;
455 /* add handlers, stuff you only do once or on area/region changes */
456 static void view3d_main_region_init(wmWindowManager *wm, ARegion *ar)
463 /* important to be before Pose keymap since they can both be enabled at once */
464 keymap = WM_keymap_ensure(wm->defaultconf, "Face Mask", 0, 0);
465 WM_event_add_keymap_handler(&ar->handlers, keymap);
468 keymap = WM_keymap_ensure(wm->defaultconf, "Weight Paint Vertex Selection", 0, 0);
469 WM_event_add_keymap_handler(&ar->handlers, keymap);
471 /* pose is not modal, operator poll checks for this */
472 keymap = WM_keymap_ensure(wm->defaultconf, "Pose", 0, 0);
473 WM_event_add_keymap_handler(&ar->handlers, keymap);
475 keymap = WM_keymap_ensure(wm->defaultconf, "Object Mode", 0, 0);
476 WM_event_add_keymap_handler(&ar->handlers, keymap);
478 keymap = WM_keymap_ensure(wm->defaultconf, "Paint Curve", 0, 0);
479 WM_event_add_keymap_handler(&ar->handlers, keymap);
481 keymap = WM_keymap_ensure(wm->defaultconf, "Curve", 0, 0);
482 WM_event_add_keymap_handler(&ar->handlers, keymap);
484 keymap = WM_keymap_ensure(wm->defaultconf, "Image Paint", 0, 0);
485 WM_event_add_keymap_handler(&ar->handlers, keymap);
487 keymap = WM_keymap_ensure(wm->defaultconf, "Vertex Paint", 0, 0);
488 WM_event_add_keymap_handler(&ar->handlers, keymap);
490 keymap = WM_keymap_ensure(wm->defaultconf, "Weight Paint", 0, 0);
491 WM_event_add_keymap_handler(&ar->handlers, keymap);
493 keymap = WM_keymap_ensure(wm->defaultconf, "Sculpt", 0, 0);
494 WM_event_add_keymap_handler(&ar->handlers, keymap);
496 keymap = WM_keymap_ensure(wm->defaultconf, "Mesh", 0, 0);
497 WM_event_add_keymap_handler(&ar->handlers, keymap);
499 keymap = WM_keymap_ensure(wm->defaultconf, "Curve", 0, 0);
500 WM_event_add_keymap_handler(&ar->handlers, keymap);
502 keymap = WM_keymap_ensure(wm->defaultconf, "Armature", 0, 0);
503 WM_event_add_keymap_handler(&ar->handlers, keymap);
505 keymap = WM_keymap_ensure(wm->defaultconf, "Pose", 0, 0);
506 WM_event_add_keymap_handler(&ar->handlers, keymap);
508 keymap = WM_keymap_ensure(wm->defaultconf, "Metaball", 0, 0);
509 WM_event_add_keymap_handler(&ar->handlers, keymap);
511 keymap = WM_keymap_ensure(wm->defaultconf, "Lattice", 0, 0);
512 WM_event_add_keymap_handler(&ar->handlers, keymap);
514 keymap = WM_keymap_ensure(wm->defaultconf, "Particle", 0, 0);
515 WM_event_add_keymap_handler(&ar->handlers, keymap);
517 /* editfont keymap swallows all... */
518 keymap = WM_keymap_ensure(wm->defaultconf, "Font", 0, 0);
519 WM_event_add_keymap_handler(&ar->handlers, keymap);
521 keymap = WM_keymap_ensure(wm->defaultconf, "Object Non-modal", 0, 0);
522 WM_event_add_keymap_handler(&ar->handlers, keymap);
524 keymap = WM_keymap_ensure(wm->defaultconf, "Frames", 0, 0);
525 WM_event_add_keymap_handler(&ar->handlers, keymap);
527 /* own keymap, last so modes can override it */
528 keymap = WM_keymap_ensure(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
529 WM_event_add_keymap_handler(&ar->handlers, keymap);
531 keymap = WM_keymap_ensure(wm->defaultconf, "3D View", SPACE_VIEW3D, 0);
532 WM_event_add_keymap_handler(&ar->handlers, keymap);
535 lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
537 WM_event_add_dropbox_handler(&ar->handlers, lb);
541 static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar)
543 RegionView3D *rv3d = ar->regiondata;
545 ED_view3d_stop_render_preview(wm, ar);
547 if (rv3d->gpuoffscreen) {
548 GPU_offscreen_free(rv3d->gpuoffscreen);
549 rv3d->gpuoffscreen = NULL;
553 static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
555 return WM_drag_ID(drag, ID_OB) != NULL;
558 static bool view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
560 return WM_drag_ID(drag, ID_GR) != NULL;
563 static bool view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
565 return WM_drag_ID(drag, ID_MA) != NULL;
568 static bool view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
570 if (drag->type == WM_DRAG_PATH) {
571 return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); /* rule might not work? */
574 return WM_drag_ID(drag, ID_IM) != NULL;
578 static bool view3d_ima_bg_is_camera_view(bContext *C)
580 RegionView3D *rv3d = CTX_wm_region_view3d(C);
581 if ((rv3d && (rv3d->persp == RV3D_CAMOB))) {
582 View3D *v3d = CTX_wm_view3d(C);
583 if (v3d && v3d->camera && v3d->camera->type == OB_CAMERA) {
590 static bool view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
592 if (!view3d_ima_drop_poll(C, drag, event, tooltip)) {
596 if (ED_view3d_is_object_under_cursor(C, event->mval)) {
600 return view3d_ima_bg_is_camera_view(C);
603 static bool view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
605 if (!view3d_ima_drop_poll(C, drag, event, tooltip)) {
609 Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
615 if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
622 static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
624 ID *id = WM_drag_ID(drag, ID_OB);
626 RNA_string_set(drop->ptr, "name", id->name + 2);
629 static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
631 ID *id = WM_drag_ID(drag, ID_GR);
633 drop->opcontext = WM_OP_EXEC_DEFAULT;
634 RNA_string_set(drop->ptr, "name", id->name + 2);
637 static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
639 ID *id = WM_drag_ID(drag, 0);
641 RNA_string_set(drop->ptr, "name", id->name + 2);
644 static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
646 ID *id = WM_drag_ID(drag, 0);
649 RNA_string_set(drop->ptr, "name", id->name + 2);
650 RNA_struct_property_unset(drop->ptr, "filepath");
652 else if (drag->path[0]) {
653 RNA_string_set(drop->ptr, "filepath", drag->path);
654 RNA_struct_property_unset(drop->ptr, "image");
658 static void view3d_lightcache_update(bContext *C)
662 Scene *scene = CTX_data_scene(C);
664 if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
665 /* Only do auto bake if eevee is the active engine */
669 WM_operator_properties_create(&op_ptr, "SCENE_OT_light_cache_bake");
670 RNA_int_set(&op_ptr, "delay", 200);
671 RNA_enum_set_identifier(C, &op_ptr, "subset", "DIRTY");
673 WM_operator_name_call(C, "SCENE_OT_light_cache_bake", WM_OP_INVOKE_DEFAULT, &op_ptr);
675 WM_operator_properties_free(&op_ptr);
678 /* region dropbox definition */
679 static void view3d_dropboxes(void)
681 ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
683 WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy);
684 WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
685 WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
686 WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
687 WM_dropbox_add(lb, "OBJECT_OT_collection_instance_add", view3d_collection_drop_poll, view3d_collection_drop_copy);
690 static void view3d_widgets(void)
692 wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
693 &(const struct wmGizmoMapType_Params){SPACE_VIEW3D, RGN_TYPE_WINDOW});
695 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_spot);
696 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_area);
697 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_target);
698 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_force_field);
699 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera);
700 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view);
701 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image);
702 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline);
704 WM_gizmogrouptype_append(TRANSFORM_GGT_gizmo);
705 WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage);
706 WM_gizmogrouptype_append(VIEW3D_GGT_xform_shear);
707 WM_gizmogrouptype_append(VIEW3D_GGT_xform_extrude);
708 WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem);
709 WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering);
711 WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
712 WM_gizmotype_append(VIEW3D_GT_ruler_item);
714 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
715 WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
719 /* type callback, not region itself */
720 static void view3d_main_region_free(ARegion *ar)
722 RegionView3D *rv3d = ar->regiondata;
725 if (rv3d->localvd) MEM_freeN(rv3d->localvd);
726 if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
728 if (rv3d->render_engine)
729 RE_engine_free(rv3d->render_engine);
732 if (rv3d->depths->depths) MEM_freeN(rv3d->depths->depths);
733 MEM_freeN(rv3d->depths);
736 MEM_freeN(rv3d->sms);
738 if (rv3d->gpuoffscreen) {
739 GPU_offscreen_free(rv3d->gpuoffscreen);
743 ar->regiondata = NULL;
747 /* copy regiondata */
748 static void *view3d_main_region_duplicate(void *poin)
751 RegionView3D *rv3d = poin, *new;
753 new = MEM_dupallocN(rv3d);
755 new->localvd = MEM_dupallocN(rv3d->localvd);
757 new->clipbb = MEM_dupallocN(rv3d->clipbb);
760 new->gpuoffscreen = NULL;
761 new->render_engine = NULL;
763 new->smooth_timer = NULL;
770 static void view3d_main_region_listener(
771 wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar,
772 wmNotifier *wmn, const Scene *scene)
774 View3D *v3d = sa->spacedata.first;
775 RegionView3D *rv3d = ar->regiondata;
776 wmGizmoMap *gzmap = ar->gizmo_map;
778 /* context changes */
779 switch (wmn->category) {
781 if (ELEM(wmn->data, ND_UNDO)) {
782 WM_gizmomap_tag_refresh(gzmap);
787 case ND_KEYFRAME_PROP:
788 case ND_NLA_ACTCHANGE:
789 ED_region_tag_redraw(ar);
793 if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
794 ED_region_tag_redraw(ar);
797 if (wmn->action == NA_SELECTED)
798 ED_region_tag_redraw(ar);
805 case ND_LAYER_CONTENT:
806 ED_region_tag_redraw(ar);
807 WM_gizmomap_tag_refresh(gzmap);
810 if (wmn->reference) {
811 BKE_screen_view3d_sync(v3d, wmn->reference);
813 ED_region_tag_redraw(ar);
814 WM_gizmomap_tag_refresh(gzmap);
822 case ND_RENDER_OPTIONS:
825 ED_region_tag_redraw(ar);
826 WM_gizmomap_tag_refresh(gzmap);
829 /* handled by space_view3d_listener() for v3d access */
831 case ND_DRAW_RENDER_VIEWPORT:
833 if (v3d->camera && (scene == wmn->reference)) {
834 if (rv3d->persp == RV3D_CAMOB) {
835 ED_region_tag_redraw(ar);
841 if (wmn->action == NA_EDITED)
842 ED_region_tag_redraw(ar);
857 ED_region_tag_redraw(ar);
858 WM_gizmomap_tag_refresh(gzmap);
861 switch (wmn->action) {
863 ED_region_tag_redraw(ar);
871 WM_gizmomap_tag_refresh(gzmap);
875 case ND_VERTEX_GROUP:
876 ED_region_tag_redraw(ar);
879 switch (wmn->action) {
881 ED_region_tag_redraw(ar);
887 case ND_DRAW_RENDER_VIEWPORT:
889 if (v3d->camera && (v3d->camera->data == wmn->reference)) {
890 if (rv3d->persp == RV3D_CAMOB) {
891 ED_region_tag_redraw(ar);
899 /* all group ops for now */
900 ED_region_tag_redraw(ar);
903 switch (wmn->action) {
905 ED_region_tag_redraw_overlay(ar);
908 /* used on brush changes - needed because 3d cursor
909 * has to be drawn if clone brush is selected */
910 ED_region_tag_redraw(ar);
918 /* TODO(sergey) This is a bit too much updates, but needed to
919 * have proper material drivers update in the viewport.
923 ED_region_tag_redraw(ar);
925 case ND_SHADING_DRAW:
926 case ND_SHADING_LINKS:
927 ED_region_tag_redraw(ar);
934 /* handled by space_view3d_listener() for v3d access */
937 /* Needed for updating world materials */
938 ED_region_tag_redraw(ar);
945 /* TODO(sergey): This is a bit too much, but needed to
946 * handle updates from new depsgraph.
948 ED_region_tag_redraw(ar);
950 case ND_LIGHTING_DRAW:
951 ED_region_tag_redraw(ar);
952 WM_gizmomap_tag_refresh(gzmap);
957 ED_area_tag_refresh(sa);
960 /* this could be more fine grained checks if we had
961 * more context than just the region */
962 ED_region_tag_redraw(ar);
966 ED_region_tag_redraw(ar);
969 if (wmn->data == ND_DISPLAY || wmn->action == NA_EDITED)
970 ED_region_tag_redraw(ar);
973 if (wmn->data == ND_SPACE_VIEW3D) {
974 if (wmn->subtype == NS_VIEW3D_GPU) {
975 rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
977 ED_region_tag_redraw(ar);
978 WM_gizmomap_tag_refresh(gzmap);
982 if (wmn->action == NA_RENAME)
983 ED_region_tag_redraw(ar);
989 ED_region_tag_redraw(ar);
991 case ND_LAYOUTBROWSE:
992 case ND_LAYOUTDELETE:
994 WM_gizmomap_tag_refresh(gzmap);
995 ED_region_tag_redraw(ar);
998 ED_region_tag_redraw(ar);
1004 if (wmn->data == ND_DATA || ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
1005 ED_region_tag_redraw(ar);
1011 static void view3d_main_region_message_subscribe(
1012 const struct bContext *C,
1013 struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
1014 struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar,
1015 struct wmMsgBus *mbus)
1017 /* Developer note: there are many properties that impact 3D view drawing,
1018 * so instead of subscribing to individual properties, just subscribe to types
1019 * accepting some redundant redraws.
1021 * For other space types we might try avoid this, keep the 3D view as an exceptional case! */
1022 wmMsgParams_RNA msg_key_params = {{{0}}};
1024 /* Only subscribe to types. */
1025 StructRNA *type_array[] = {
1028 /* These object have properties that impact drawing. */
1035 /* General types the 3D view depends on. */
1037 &RNA_UnitSettings, /* grid-floor */
1044 wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
1047 .notify = ED_region_do_msg_notify_tag_redraw,
1050 for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
1051 msg_key_params.ptr.type = type_array[i];
1052 WM_msg_subscribe_rna_params(
1055 &msg_sub_value_region_tag_redraw,
1059 /* Subscribe to a handful of other properties. */
1060 RegionView3D *rv3d = ar->regiondata;
1062 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, engine, &msg_sub_value_region_tag_redraw);
1063 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw);
1064 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw);
1065 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw);
1066 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw);
1067 if (rv3d->persp == RV3D_CAMOB) {
1068 WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw);
1071 WM_msg_subscribe_rna_anon_type(mbus, SceneEEVEE, &msg_sub_value_region_tag_redraw);
1072 WM_msg_subscribe_rna_anon_type(mbus, SceneDisplay, &msg_sub_value_region_tag_redraw);
1073 WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw);
1075 ViewLayer *view_layer = CTX_data_view_layer(C);
1076 Object *obact = OBACT(view_layer);
1077 if (obact != NULL) {
1078 switch (obact->mode) {
1079 case OB_MODE_PARTICLE_EDIT:
1080 WM_msg_subscribe_rna_anon_type(mbus, ParticleEdit, &msg_sub_value_region_tag_redraw);
1088 wmMsgSubscribeValue msg_sub_value_region_tag_refresh = {
1091 .notify = WM_toolsystem_do_msg_notify_tag_refresh,
1093 WM_msg_subscribe_rna_anon_prop(
1095 &msg_sub_value_region_tag_refresh);
1099 /* concept is to retrieve cursor type context-less */
1100 static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
1102 if (WM_cursor_set_from_tool(win, sa, ar)) {
1106 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
1107 Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
1109 WM_cursor_set(win, CURSOR_EDIT);
1112 WM_cursor_set(win, CURSOR_STD);
1116 /* add handlers, stuff you only do once or on area/region changes */
1117 static void view3d_header_region_init(wmWindowManager *wm, ARegion *ar)
1119 wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
1121 WM_event_add_keymap_handler(&ar->handlers, keymap);
1123 ED_region_header_init(ar);
1126 static void view3d_header_region_draw(const bContext *C, ARegion *ar)
1128 ED_region_header(C, ar);
1131 static void view3d_header_region_listener(
1132 wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
1133 wmNotifier *wmn, const Scene *UNUSED(scene))
1135 /* context changes */
1136 switch (wmn->category) {
1138 switch (wmn->data) {
1145 case ND_TOOLSETTINGS:
1146 case ND_LAYER_CONTENT:
1147 case ND_RENDER_OPTIONS:
1148 ED_region_tag_redraw(ar);
1153 if (wmn->data == ND_SPACE_VIEW3D)
1154 ED_region_tag_redraw(ar);
1157 if (wmn->data & ND_GPENCIL_EDITMODE)
1158 ED_region_tag_redraw(ar);
1163 static void view3d_header_region_message_subscribe(
1164 const struct bContext *UNUSED(C),
1165 struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
1166 struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
1167 struct wmMsgBus *mbus)
1169 wmMsgParams_RNA msg_key_params = {{{0}}};
1171 /* Only subscribe to types. */
1172 StructRNA *type_array[] = {
1176 wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
1179 .notify = ED_region_do_msg_notify_tag_redraw,
1182 for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
1183 msg_key_params.ptr.type = type_array[i];
1184 WM_msg_subscribe_rna_params(
1187 &msg_sub_value_region_tag_redraw,
1193 /* add handlers, stuff you only do once or on area/region changes */
1194 static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar)
1198 ED_region_panels_init(wm, ar);
1200 keymap = WM_keymap_ensure(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
1201 WM_event_add_keymap_handler(&ar->handlers, keymap);
1204 static void view3d_buttons_region_draw(const bContext *C, ARegion *ar)
1206 ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true);
1209 static void view3d_buttons_region_listener(
1210 wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
1211 wmNotifier *wmn, const Scene *UNUSED(scene))
1213 /* context changes */
1214 switch (wmn->category) {
1216 switch (wmn->data) {
1217 case ND_KEYFRAME_PROP:
1218 case ND_NLA_ACTCHANGE:
1219 ED_region_tag_redraw(ar);
1223 if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
1224 ED_region_tag_redraw(ar);
1229 switch (wmn->data) {
1236 case ND_LAYER_CONTENT:
1237 case ND_TOOLSETTINGS:
1238 ED_region_tag_redraw(ar);
1241 switch (wmn->action) {
1243 ED_region_tag_redraw(ar);
1248 switch (wmn->data) {
1249 case ND_BONE_ACTIVE:
1250 case ND_BONE_SELECT:
1256 ED_region_tag_redraw(ar);
1261 switch (wmn->data) {
1263 case ND_VERTEX_GROUP:
1265 ED_region_tag_redraw(ar);
1268 if (wmn->action == NA_EDITED)
1269 ED_region_tag_redraw(ar);
1273 /* for brush textures */
1274 ED_region_tag_redraw(ar);
1277 /* NA_SELECTED is used on brush changes */
1278 if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
1279 ED_region_tag_redraw(ar);
1282 if (wmn->data == ND_SPACE_VIEW3D)
1283 ED_region_tag_redraw(ar);
1286 if (wmn->action == NA_RENAME)
1287 ED_region_tag_redraw(ar);
1290 if ((wmn->data & (ND_DATA | ND_GPENCIL_EDITMODE)) || (wmn->action == NA_EDITED))
1291 ED_region_tag_redraw(ar);
1294 /* Update for the image layers in texture paint. */
1295 if (wmn->action == NA_EDITED)
1296 ED_region_tag_redraw(ar);
1301 /* add handlers, stuff you only do once or on area/region changes */
1302 static void view3d_tools_region_init(wmWindowManager *wm, ARegion *ar)
1306 ED_region_panels_init(wm, ar);
1308 keymap = WM_keymap_ensure(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
1309 WM_event_add_keymap_handler(&ar->handlers, keymap);
1312 static void view3d_tools_region_draw(const bContext *C, ARegion *ar)
1314 ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true);
1317 /* area (not region) level listener */
1318 static void space_view3d_listener(
1319 wmWindow *UNUSED(win), ScrArea *sa, struct wmNotifier *wmn, Scene *UNUSED(scene))
1321 View3D *v3d = sa->spacedata.first;
1323 /* context changes */
1324 switch (wmn->category) {
1326 switch (wmn->data) {
1328 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1329 ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
1334 switch (wmn->data) {
1337 if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
1338 ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
1344 switch (wmn->data) {
1346 if (v3d->shading.type == OB_TEXTURE)
1347 ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
1354 static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
1356 Scene *scene = CTX_data_scene(C);
1357 LightCache *lcache = scene->eevee.light_cache;
1359 if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) {
1360 lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO;
1361 view3d_lightcache_update((bContext *)C);
1365 const char *view3d_context_dir[] = {
1366 "active_base", "active_object", NULL
1369 static int view3d_context(const bContext *C, const char *member, bContextDataResult *result)
1371 /* fallback to the scene layer, allows duplicate and other object operators to run outside the 3d view */
1373 if (CTX_data_dir(member)) {
1374 CTX_data_dir_set(result, view3d_context_dir);
1376 else if (CTX_data_equals(member, "active_base")) {
1377 Scene *scene = CTX_data_scene(C);
1378 ViewLayer *view_layer = CTX_data_view_layer(C);
1379 if (view_layer->basact) {
1380 Object *ob = view_layer->basact->object;
1381 /* if hidden but in edit mode, we still display, can happen with animation */
1382 if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) {
1383 CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
1389 else if (CTX_data_equals(member, "active_object")) {
1390 ViewLayer *view_layer = CTX_data_view_layer(C);
1391 if (view_layer->basact) {
1392 Object *ob = view_layer->basact->object;
1393 /* if hidden but in edit mode, we still display, can happen with animation */
1394 if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) {
1395 CTX_data_id_pointer_set(result, &ob->id);
1402 return 0; /* not found */
1405 return -1; /* found but not available */
1408 static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
1412 bool is_local = false;
1414 if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
1418 for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
1419 if ((ID *)v3d->camera == old_id) {
1420 v3d->camera = (Object *)new_id;
1422 /* 3D view might be inactive, in that case needs to use slink->regionbase */
1423 ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase : &slink->regionbase;
1424 for (ar = regionbase->first; ar; ar = ar->next) {
1425 if (ar->regiontype == RGN_TYPE_WINDOW) {
1426 RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata;
1427 if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
1428 rv3d->persp = RV3D_PERSP;
1435 /* Values in local-view aren't used, see: T52663 */
1436 if (is_local == false) {
1437 if ((ID *)v3d->ob_centre == old_id) {
1438 v3d->ob_centre = (Object *)new_id;
1439 /* Otherwise, bonename may remain valid... We could be smart and check this, too? */
1440 if (new_id == NULL) {
1441 v3d->ob_centre_bone[0] = '\0';
1452 /* only called once, from space/spacetypes.c */
1453 void ED_spacetype_view3d(void)
1455 SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype view3d");
1458 st->spaceid = SPACE_VIEW3D;
1459 strncpy(st->name, "View3D", BKE_ST_MAXNAME);
1461 st->new = view3d_new;
1462 st->free = view3d_free;
1463 st->init = view3d_init;
1464 st->listener = space_view3d_listener;
1465 st->refresh = space_view3d_refresh;
1466 st->duplicate = view3d_duplicate;
1467 st->operatortypes = view3d_operatortypes;
1468 st->keymap = view3d_keymap;
1469 st->dropboxes = view3d_dropboxes;
1470 st->gizmos = view3d_widgets;
1471 st->context = view3d_context;
1472 st->id_remap = view3d_id_remap;
1474 /* regions: main window */
1475 art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
1476 art->regionid = RGN_TYPE_WINDOW;
1477 art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_GPENCIL;
1478 art->draw = view3d_main_region_draw;
1479 art->init = view3d_main_region_init;
1480 art->exit = view3d_main_region_exit;
1481 art->free = view3d_main_region_free;
1482 art->duplicate = view3d_main_region_duplicate;
1483 art->listener = view3d_main_region_listener;
1484 art->message_subscribe = view3d_main_region_message_subscribe;
1485 art->cursor = view3d_main_region_cursor;
1486 art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
1487 BLI_addhead(&st->regiontypes, art);
1489 /* regions: listview/buttons */
1490 art = MEM_callocN(sizeof(ARegionType), "spacetype view3d buttons region");
1491 art->regionid = RGN_TYPE_UI;
1492 art->prefsizex = 180; /* XXX */
1493 art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
1494 art->listener = view3d_buttons_region_listener;
1495 art->init = view3d_buttons_region_init;
1496 art->draw = view3d_buttons_region_draw;
1497 BLI_addhead(&st->regiontypes, art);
1499 view3d_buttons_register(art);
1501 /* regions: tool(bar) */
1502 art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
1503 art->regionid = RGN_TYPE_TOOLS;
1504 art->prefsizex = 58; /* XXX */
1505 art->prefsizey = 50; /* XXX */
1506 art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
1507 art->listener = view3d_buttons_region_listener;
1508 art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
1509 art->snap_size = ED_region_generic_tools_region_snap_size;
1510 art->init = view3d_tools_region_init;
1511 art->draw = view3d_tools_region_draw;
1512 BLI_addhead(&st->regiontypes, art);
1514 /* regions: header */
1515 art = MEM_callocN(sizeof(ARegionType), "spacetype view3d header region");
1516 art->regionid = RGN_TYPE_HEADER;
1517 art->prefsizey = HEADERY;
1518 art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
1519 art->listener = view3d_header_region_listener;
1520 art->init = view3d_header_region_init;
1521 art->draw = view3d_header_region_draw;
1522 art->message_subscribe = view3d_header_region_message_subscribe;
1523 BLI_addhead(&st->regiontypes, art);
1526 art = ED_area_type_hud(st->spaceid);
1527 BLI_addhead(&st->regiontypes, art);
1529 BKE_spacetype_register(st);