diff options
Diffstat (limited to 'source/blender/editors')
145 files changed, 9267 insertions, 4665 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index afbd8e5bd41..24f6a2dab2c 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -147,7 +147,7 @@ bAction *verify_adt_action(ID *id, short add) BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); /* create action */ - adt->action = add_empty_action(G.main, actname); + adt->action = BKE_action_add(G.main, actname); /* set ID-type from ID-block that this is going to be assigned to * so that users can't accidentally break actions by assigning them diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 1d63b3aee43..de2611f7092 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -126,50 +126,40 @@ typedef struct tJoinArmature_AdtFixData { GHash *names_map; } tJoinArmature_AdtFixData; -/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ +/* Callback to pass to BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ /* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation * on the rigs being edited already, so it should be safe to skip these. */ -static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data) +static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) { tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data; ID *src_id = &afd->srcArm->id; ID *dst_id = &afd->tarArm->id; GHashIterator gh_iter; - FCurve *fcu; /* Fix paths - If this is the target object, it will have some "dirty" paths */ - if (id == src_id) { - /* Fix drivers */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - /* skip driver if it doesn't affect the bones */ - if (strstr(fcu->rna_path, "pose.bones[") == NULL) { - continue; - } + if ((id == src_id) && strstr(fcu->rna_path, "pose.bones[")) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); - // FIXME: this is too crude... it just does everything! - GHASH_ITER(gh_iter, afd->names_map) { - const char *old_name = BLI_ghashIterator_getKey(&gh_iter); - const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); - /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ - if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { - fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", - old_name, new_name, 0, 0, false); - - /* we don't want to apply a second remapping on this driver now, - * so stop trying names, but keep fixing drivers - */ - break; - } + /* we don't want to apply a second remapping on this driver now, + * so stop trying names, but keep fixing drivers + */ + break; } } } /* Driver targets */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + if (fcu->driver) { ChannelDriver *driver = fcu->driver; DriverVar *dvar; @@ -373,7 +363,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Fix all the drivers (and animation data) */ - BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); + BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); BLI_ghash_free(afd.names_map, MEM_freeN, NULL); /* Only copy over animdata now, after all the remapping has been done, diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 4dd8e4bd6fa..f4bebfd85e0 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -929,7 +929,7 @@ static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float pval[2] = {0, 0}; ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP); - ED_view3d_win_to_ray(ar, v3d, pval, ray_start, ray_normal, false); + ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, pval, ray_start, ray_normal, false); mul_v3_fl(ray_normal, distance * progress / length); add_v3_v3(stk->points[i].p, ray_normal); @@ -1486,6 +1486,7 @@ static int cmpIntersections(const void *i1, const void *i2) /* returns the maximum number of intersections per stroke */ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -1526,7 +1527,7 @@ static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, S mval[0] = vi[0]; mval[1] = vi[1]; - ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end, true); + ED_view3d_win_to_segment(depsgraph, ar, v3d, mval, ray_start, ray_end, true); isect_line_line_v3(stk->points[s_i].p, stk->points[s_i + 1].p, diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 0dbe3ddaa0a..d89b2fcfe84 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -201,7 +201,7 @@ static bAction *poselib_init_new(Object *ob) if (ob->poselib) id_us_min(&ob->poselib->id); - ob->poselib = add_empty_action(G.main, "PoseLib"); + ob->poselib = BKE_action_add(G.main, "PoseLib"); ob->poselib->idroot = ID_OB; return ob->poselib; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index f808f09f1f4..9bc678cd9e6 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -156,7 +156,7 @@ bool ED_do_pose_selectbuffer( * always give predictable behavior in weight paint mode - campbell */ if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) { /* when we are entering into posemode via toggle-select, - * frop another active object - always select the bone. */ + * from another active object - always select the bone. */ if (!extend && !deselect && toggle) { /* re-select below */ nearBone->flag &= ~BONE_SELECTED; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 18d6408f026..bfe365d04fd 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -158,6 +158,28 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) curbone->roll = eul[1]; } + /* combine pose and rest values for bendy bone settings, + * then clear the pchan values (so we don't get a double-up) + */ + if (pchan->bone->segments > 1) { + curbone->curveInX += pchan->curveInX; + curbone->curveInY += pchan->curveInY; + curbone->curveOutX += pchan->curveOutX; + curbone->curveOutY += pchan->curveOutY; + curbone->roll1 += pchan->roll1; + curbone->roll2 += pchan->roll2; + curbone->ease1 += pchan->ease1; + curbone->ease2 += pchan->ease2; + curbone->scaleIn += pchan->scaleIn; + curbone->scaleOut += pchan->scaleOut; + + pchan->curveInX = pchan->curveOutX = 0.0f; + pchan->curveInY = pchan->curveOutY = 0.0f; + pchan->roll1 = pchan->roll2 = 0.0f; + pchan->ease1 = pchan->ease2 = 0.0f; + pchan->scaleIn = pchan->scaleOut = 1.0f; + } + /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 4dfd4a5c0f0..71cccdfa33d 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -241,6 +241,9 @@ void ED_keymap_curve(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "wait_for_input", false); + kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", TABLET_STYLUS, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE); kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 79b63f36b76..4b578ba389e 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6135,8 +6135,10 @@ int join_curve_exec(bContext *C, wmOperator *op) cu = ob->data; BLI_movelisttolist(&cu->nurb, &tempbase); - /* Account for mixed 2D/3D curves when joining */ - BKE_curve_curve_dimension_update(cu); + if (ob->type == OB_CURVE) { + /* Account for mixed 2D/3D curves when joining */ + BKE_curve_curve_dimension_update(cu); + } DEG_relations_tag_update(bmain); // because we removed object(s), call before editmode! diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 5a71cc39f80..062b9c94a1b 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -93,6 +93,8 @@ struct StrokeElem { }; struct CurveDrawData { + const Depsgraph *depsgraph; + short init_event_type; short curve_type; @@ -199,7 +201,7 @@ static bool stroke_elem_project( if (cdd->project.use_plane) { /* get the view vector to 'location' */ float ray_origin[3], ray_direction[3]; - ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false); + ED_view3d_win_to_ray(cdd->depsgraph, cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false); float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) { @@ -603,6 +605,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke) struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__); + cdd->depsgraph = CTX_data_depsgraph(C); + if (is_invoke) { view3d_set_viewcontext(C, &cdd->vc); if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) { diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 2a84ca7f297..65c55b6cd22 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -31,6 +31,500 @@ set(SRC ) +# Order matches "UI_icons.h", final name will be formatted: "icons{size}_{name}.dat" +set(ICON_NAMES + question + error + cancel + tria_right + tria_down + tria_left + tria_up + arrow_leftright + plus + disclosure_tri_down + disclosure_tri_right + radiobut_off + radiobut_on + menu_panel + blender + grip + dot + collapsemenu + x + go_left + plug + ui + node + node_sel + fullscreen + splitscreen + rightarrow_thin + bordermove + viewzoom + zoomin + zoomout + panel_close + copy_id + eyedropper + link_area + auto + checkbox_dehlt + checkbox_hlt + unlocked + locked + unpinned + pinned + screen_back + rightarrow + downarrow_hlt + dotsup + dotsdown + link + inlink + plugin + help + ghost_enabled + color + linked + unlinked + hand + zoom_all + zoom_selected + zoom_previous + zoom_in + zoom_out + render_region + border_rect + border_lasso + freeze + stylus_pressure + ghost_disabled + new + file_tick + quit + url + recover_last + fullscreen_enter + fullscreen_exit + lamp + material + texture + anim + world + scene + edit + game + radio + script + particles + physics + speaker + texture_shaded + view3d + ipo + oops + buts + filesel + image_col + info + sequence + text + imasel + sound + action + nla + scriptwin + time + nodetree + logic + console + preferences + clip + asset_manager + object_datamode + editmode_hlt + facesel_hlt + vpaint_hlt + tpaint_hlt + wpaint_hlt + sculptmode_hlt + pose_hlt + particlemode + lightpaint + greasepencil_stroke_paint + scene_data + renderlayers + world_data + object_data + mesh_data + curve_data + meta_data + lattice_data + lamp_data + material_data + texture_data + anim_data + camera_data + particle_data + library_data_direct + group + armature_data + pose_data + bone_data + constraint + shapekey_data + constraint_bone + camera_stereo + package + uglypackage + brush_data + image_data + file + fcurve + font_data + render_result + surface_data + empty_data + settings + render_animation + render_still + library_data_broken + boids + strands + library_data_indirect + greasepencil + line_data + library_data_override + group_bone + group_vertex + group_vcol + group_uvs + rna + rna_add + outliner_ob_empty + outliner_ob_mesh + outliner_ob_curve + outliner_ob_lattice + outliner_ob_meta + outliner_ob_lamp + outliner_ob_camera + outliner_ob_armature + outliner_ob_font + outliner_ob_surface + outliner_ob_speaker + outliner_ob_force_field + outliner_ob_group_instance + outliner_ob_greasepencil + restrict_color_off + restrict_color_on + restrict_view_off + restrict_view_on + restrict_select_off + restrict_select_on + restrict_render_off + restrict_render_on + outliner_data_empty + outliner_data_mesh + outliner_data_curve + outliner_data_lattice + outliner_data_meta + outliner_data_lamp + outliner_data_camera + outliner_data_armature + outliner_data_font + outliner_data_surface + outliner_data_speaker + outliner_data_pose + outliner_data_greasepencil + mesh_plane + mesh_cube + mesh_circle + mesh_uvsphere + mesh_icosphere + mesh_grid + mesh_monkey + mesh_cylinder + mesh_torus + mesh_cone + mesh_capsule + lamp_point + lamp_sun + lamp_spot + lamp_hemi + lamp_area + meta_empty + meta_plane + meta_cube + meta_ball + meta_ellipsoid + meta_capsule + surface_ncurve + surface_ncircle + surface_nsurface + surface_ncylinder + surface_nsphere + surface_ntorus + curve_bezcurve + curve_bezcircle + curve_ncurve + curve_ncircle + curve_path + color_red + color_green + color_blue + tria_right_bar + tria_down_bar + tria_left_bar + tria_up_bar + force_force + force_wind + force_vortex + force_magnetic + force_harmonic + force_charge + force_lennardjones + force_texture + force_curve + force_boid + force_turbulence + force_drag + force_smokeflow + node_insert_on + node_insert_off + modifier + mod_wave + mod_build + mod_decim + mod_mirror + mod_soft + mod_subsurf + hook + mod_physics + mod_particles + mod_boolean + mod_edgesplit + mod_array + mod_uvproject + mod_displace + mod_curve + mod_lattice + constraint_data + mod_armature + mod_shrinkwrap + mod_cast + mod_meshdeform + mod_bevel + mod_smooth + mod_simpledeform + mod_mask + mod_cloth + mod_explode + mod_fluidsim + mod_multires + mod_smoke + mod_solidify + mod_screw + mod_vertex_weight + mod_dynamicpaint + mod_remesh + mod_ocean + mod_warp + mod_skin + mod_triangulate + mod_wireframe + mod_data_transfer + mod_normaledit + rec + play + ff + rew + pause + prev_keyframe + next_keyframe + play_audio + play_reverse + preview_range + action_tweak + pmarker_act + pmarker_sel + pmarker + marker_hlt + marker + space2 + space3 + keyingset + key_dehlt + key_hlt + mute_ipo_off + mute_ipo_on + visible_ipo_off + visible_ipo_on + driver + solo_off + solo_on + frame_prev + frame_next + nla_pushdown + ipo_constant + ipo_linear + ipo_bezier + ipo_sine + ipo_quad + ipo_cubic + ipo_quart + ipo_quint + ipo_expo + ipo_circ + ipo_bounce + ipo_elastic + ipo_back + ipo_ease_in + ipo_ease_out + ipo_ease_in_out + normalize_fcurves + vertexsel + edgesel + facesel + loopsel + rotate + cursor + rotatecollection + rotatecenter + rotactive + align + smoothcurve + spherecurve + rootcurve + sharpcurve + lincurve + nocurve + rndcurve + prop_off + prop_on + prop_con + particle_point + particle_tip + particle_path + man_trans + man_rot + man_scale + manipul + snap_off + snap_on + snap_normal + snap_grid + snap_vertex + snap_edge + snap_face + snap_volume + snap_increment + sticky_uvs_loc + sticky_uvs_disable + sticky_uvs_vert + clipuv_dehlt + clipuv_hlt + snap_peel_object + grid + object_origin + pastedown + copydown + pasteflipup + pasteflipdown + snap_surface + automerge_on + automerge_off + retopo + uv_vertexsel + uv_edgesel + uv_facesel + uv_islandsel + uv_sync_select + bbox + wire + solid + smooth + potato + ortho + lockview_off + lockview_on + axis_side + axis_front + axis_top + ndof_dom + ndof_turn + ndof_fly + ndof_trans + layer_used + layer_active + sortalpha + sortbyext + sorttime + sortsize + longdisplay + shortdisplay + ghost + imgdisplay + save_as + save_copy + bookmarks + fontpreview + filter + newfolder + open_recent + file_parent + file_refresh + file_folder + file_blend + file_image + file_movie + file_script + file_sound + file_font + file_text + recover_auto + save_prefs + link_blend + append_blend + import + export + external_data + load_factory + loop_back + loop_forwards + back + forward + file_hidden + file_backup + disk_drive + matplane + matsphere + matcube + monkey + hair + aliased + antialiased + mat_sphere_sky + wordwrap_off + wordwrap_on + syntax_off + syntax_on + linenumbers_off + linenumbers_on + scriptplugins + seq_sequencer + seq_preview + seq_luma_waveform + seq_chroma_scope + seq_histogram + seq_splitview + image_rgb + image_rgb_alpha + image_alpha + image_zdepth + imagefile +) + data_to_c_simple(../../../../release/datafiles/bfont.pfb SRC) data_to_c_simple(../../../../release/datafiles/bfont.ttf SRC) data_to_c_simple(../../../../release/datafiles/bmonofont.ttf SRC) @@ -53,12 +547,12 @@ if(WITH_BLENDER) #../../../../release/datafiles/blender_icons16.png #90 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons16 "icon16_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC) #svg_to_png(../../../../release/datafiles/blender_icons.svg #../../../../release/datafiles/blender_icons32.png #180 SRC) - data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 SRC) + data_to_c_simple_icons(../../../../release/datafiles/blender_icons32 "icon32_" "${ICON_NAMES}" SRC) #data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC) #svg_to_png(../../../../release/datafiles/prvicons.svg #../../../../release/datafiles/prvicons.png @@ -130,4 +624,6 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/startup.blend SRC) endif() +unset(ICON_NAMES) + blender_add_lib(bf_editor_datafiles "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 1674091f138..4a95027528b 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1672,6 +1672,7 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, ViewLayer *view_layer, + const struct Depsgraph *depsgraph, View3D *v3d, ARegion *ar, bool only3d) @@ -1688,7 +1689,7 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */ + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */ offsx = round_fl_to_int(rectf.xmin); offsy = round_fl_to_int(rectf.ymin); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index f3b12b9bc85..76fa3b3f9ea 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1111,7 +1111,8 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true); /* no shift */ return 1; } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a82148788c8..22a3224e563 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -105,7 +105,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ED_gpencil_reset_layers_parent(gpd); } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; @@ -153,7 +154,8 @@ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ts->gp_sculpt.alpha = 1.0f; } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 09ccc4600ef..472b88cb18b 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1609,7 +1609,7 @@ static void gp_session_cleanup(tGPsdata *p) } /* init new stroke */ -static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) +static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, const Depsgraph *depsgraph) { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; @@ -1738,7 +1738,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(p->scene, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ + ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ p->subrect = &p->subrect_data; } } @@ -1979,7 +1979,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) } /* init painting data */ - gp_paint_initstroke(p, paintmode); + gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { gpencil_draw_exit(C, op); return 0; @@ -2056,7 +2056,7 @@ static void gpencil_draw_status_indicators(tGPsdata *p) /* ------------------------------- */ /* create a new stroke point at the point indicated by the painting context */ -static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) +static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, const Depsgraph *depsgraph) { /* handle drawing/erasing -> test for erasing first */ if (p->paintmode == GP_PAINTMODE_ERASER) { @@ -2078,7 +2078,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) /* finish off old stroke */ gp_paint_strokeend(p); /* And start a new one!!! Else, projection errors! */ - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, depsgraph); /* start a new stroke, starting from previous point */ /* XXX Must manually reset inittime... */ @@ -2111,7 +2111,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) } /* handle draw event */ -static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) +static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, const Depsgraph *depsgraph) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -2216,7 +2216,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ - gpencil_draw_apply(op, p); + gpencil_draw_apply(op, p, depsgraph); /* force refresh */ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ @@ -2228,6 +2228,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) static int gpencil_draw_exec(bContext *C, wmOperator *op) { tGPsdata *p = NULL; + Depsgraph *depsgraph = CTX_data_depsgraph(C); /* printf("GPencil - Starting Re-Drawing\n"); */ @@ -2265,7 +2266,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { /* TODO: both of these ops can set error-status, but we probably don't need to worry */ gp_paint_strokeend(p); - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, depsgraph); } } @@ -2280,7 +2281,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } /* apply this data as necessary now (as per usual) */ - gpencil_draw_apply(op, p); + gpencil_draw_apply(op, p, depsgraph); } RNA_END; @@ -2339,7 +2340,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - gpencil_draw_apply_event(op, event); + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -2380,7 +2381,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) * it'd be nice to allow changing paint-mode when in sketching-sessions */ if (gp_session_initdata(C, p)) - gp_paint_initstroke(p, p->paintmode); + gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C)); if (p->status != GP_STATUS_ERROR) { p->status = GP_STATUS_PAINTING; @@ -2671,7 +2672,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ - gpencil_draw_apply_event(op, event); + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index e1e4f850039..94689fb59fa 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -553,7 +553,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ + ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */ r_gsc->subrect = &r_gsc->subrect_data; } } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 7e384e0056b..3ea754b242c 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -35,6 +35,7 @@ struct ID; struct ListBase; struct bContext; +struct Depsgraph; struct ScrArea; struct ARegion; struct View3D; @@ -152,6 +153,7 @@ void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d); void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct ViewLayer *view_layer, + const struct Depsgraph *depsgraph, struct View3D *v3d, struct ARegion *ar, bool only3d); diff --git a/source/blender/editors/include/ED_manipulator_library.h b/source/blender/editors/include/ED_manipulator_library.h index 80703321490..7166292147e 100644 --- a/source/blender/editors/include/ED_manipulator_library.h +++ b/source/blender/editors/include/ED_manipulator_library.h @@ -33,6 +33,7 @@ /* initialize manipulators */ void ED_manipulatortypes_arrow_2d(void); void ED_manipulatortypes_arrow_3d(void); +void ED_manipulatortypes_button_2d(void); void ED_manipulatortypes_cage_2d(void); void ED_manipulatortypes_cage_3d(void); void ED_manipulatortypes_dial_3d(void); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1fd7756df77..78497b29313 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -40,6 +40,7 @@ struct EvaluationContext; struct View3D; struct ARegion; struct bContext; +struct Depsgraph; struct wmOperator; struct wmKeyConfig; struct ReportList; @@ -126,6 +127,7 @@ void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag); void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, + const struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, struct Object *obedit); /* editmesh_select.c */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index d931109b941..32e6ddf6f54 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -141,7 +141,9 @@ int ED_region_global_size_y(void); /* screens */ void ED_screens_initialize(struct wmWindowManager *wm); -void ED_screen_draw(struct wmWindow *win); +void ED_screen_draw_edges(struct wmWindow *win); +void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2); +void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac); void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win); void ED_screen_ensure_updated(struct wmWindowManager *wm, struct wmWindow *win, struct bScreen *screen); void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 69061bdcd26..7eee053061e 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -70,6 +70,7 @@ struct wmWindowManager; struct GPUFX; struct GPUOffScreen; struct GPUFXSettings; +struct GPUViewport; struct WorkSpace; enum eGPUFXFlags; @@ -223,12 +224,16 @@ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspm eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); +float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); + float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); bool ED_view3d_win_to_ray( + const struct Depsgraph *depsgraph, const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3], const bool do_clip); bool ED_view3d_win_to_ray_ex( + const struct Depsgraph *depsgraph, const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); @@ -243,7 +248,8 @@ void ED_view3d_win_to_3d_int( void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); -bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], +bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph, + const struct ARegion *ar, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip); void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]); @@ -258,24 +264,29 @@ void ED_view3d_dist_range_get( const struct View3D *v3d, float r_dist_range[2]); bool ED_view3d_clip_range_get( + const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor); bool ED_view3d_viewplane_get( + const struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize); void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist); void ED_view3d_calc_camera_border( - const struct Scene *scene, const struct ARegion *ar, + const struct Scene *scene, const struct Depsgraph *depsgraph, + const struct ARegion *ar, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, const bool no_shift); void ED_view3d_calc_camera_border_size( - const struct Scene *scene, const struct ARegion *ar, + const struct Scene *scene, const struct Depsgraph *depsgraph, + const struct ARegion *ar, const struct View3D *v3d, const struct RegionView3D *rv3d, float r_size[2]); bool ED_view3d_calc_render_border( - const struct Scene *scene, struct View3D *v3d, + const struct Scene *scene, const struct Depsgraph *depsgraph, + struct View3D *v3d, struct ARegion *ar, struct rcti *rect); void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip); @@ -287,8 +298,6 @@ void ED_view3d_clipping_set(struct RegionView3D *rv3d); void ED_view3d_clipping_enable(void); void ED_view3d_clipping_disable(void); -float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); - float ED_view3d_radius_to_dist_persp(const float angle, const float radius); float ED_view3d_radius_to_dist_ortho(const float lens, const float radius); float ED_view3d_radius_to_dist( @@ -380,7 +389,7 @@ void ED_view3d_draw_offscreen( struct ViewLayer *view_layer, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, struct GPUFX *fx, struct GPUFXSettings *fx_settings, - struct GPUOffScreen *ofs); + struct GPUOffScreen *ofs, struct GPUViewport *viewport); void ED_view3d_draw_setup_view( struct wmWindow *win, const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ARegion *ar, struct View3D *v3d, float viewmat[4][4], float winmat[4][4], const struct rcti *rect); @@ -425,6 +434,9 @@ uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d) uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen); bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); +void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp); +bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar); + /* camera lock functions */ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d); @@ -441,7 +453,7 @@ bool ED_view3d_camera_lock_autokey( struct View3D *v3d, struct RegionView3D *rv3d, struct bContext *C, const bool do_rotate, const bool do_translate); -void ED_view3D_lock_clear(struct View3D *v3d); +void ED_view3d_lock_clear(struct View3D *v3d); #define VIEW3D_MARGIN 1.4f #define VIEW3D_DIST_FALLBACK 1.0f @@ -471,4 +483,11 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id); +/* view3d_draw_legacy.c */ +/* Try avoid using these more move out of legacy. */ +void ED_view3d_draw_bgpic_test( + struct Scene *scene, const struct Depsgraph *depsgraph, + struct ARegion *ar, struct View3D *v3d, + const bool do_foreground, const bool do_camera_frame); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 0c83038b7a3..923038a7490 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -190,8 +190,8 @@ DEF_ICON(SCULPTMODE_HLT) DEF_ICON(POSE_HLT) DEF_ICON(PARTICLEMODE) DEF_ICON(LIGHTPAINT) +DEF_ICON(GREASEPENCIL_STROKE_PAINT) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK063) DEF_ICON(BLANK064) DEF_ICON(BLANK065) DEF_ICON(BLANK066) @@ -257,9 +257,7 @@ DEF_ICON(STRANDS) DEF_ICON(LIBRARY_DATA_INDIRECT) DEF_ICON(GREASEPENCIL) DEF_ICON(LINE_DATA) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK084) -#endif +DEF_ICON(LIBRARY_DATA_OVERRIDE) DEF_ICON(GROUP_BONE) DEF_ICON(GROUP_VERTEX) DEF_ICON(GROUP_VCOL) @@ -315,8 +313,8 @@ DEF_ICON(OUTLINER_OB_SURFACE) DEF_ICON(OUTLINER_OB_SPEAKER) DEF_ICON(OUTLINER_OB_FORCE_FIELD) DEF_ICON(OUTLINER_OB_GROUP_INSTANCE) +DEF_ICON(OUTLINER_OB_GREASEPENCIL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK122) DEF_ICON(BLANK123) DEF_ICON(BLANK124) DEF_ICON(BLANK125) @@ -346,8 +344,8 @@ DEF_ICON(OUTLINER_DATA_FONT) DEF_ICON(OUTLINER_DATA_SURFACE) DEF_ICON(OUTLINER_DATA_SPEAKER) DEF_ICON(OUTLINER_DATA_POSE) +DEF_ICON(OUTLINER_DATA_GREASEPENCIL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK130) DEF_ICON(BLANK131) DEF_ICON(BLANK132) DEF_ICON(BLANK133) @@ -715,8 +713,8 @@ DEF_ICON(CLIPUV_DEHLT) DEF_ICON(CLIPUV_HLT) DEF_ICON(SNAP_PEEL_OBJECT) DEF_ICON(GRID) +DEF_ICON(OBJECT_ORIGIN) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK221) DEF_ICON(BLANK222) DEF_ICON(BLANK224) DEF_ICON(BLANK225) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9a816f21fb8..c1f2f68dbeb 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -73,6 +73,7 @@ struct bNodeSocket; struct wmDropBox; struct wmDrag; struct wmEvent; +struct wmManipulator; struct wmMsgBus; typedef struct uiBut uiBut; @@ -667,8 +668,18 @@ void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0 #define UI_ID_FAKE_USER (1 << 8) #define UI_ID_PIN (1 << 9) #define UI_ID_PREVIEWS (1 << 10) +#define UI_ID_OVERRIDE (1 << 11) #define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL) +/** + * Ways to limit what is displayed in ID-search popup. + * \note We may want to add LOCAL, LIBRARY ... as needed. + */ +enum { + UI_TEMPLATE_ID_FILTER_ALL = 0, + UI_TEMPLATE_ID_FILTER_AVAILABLE = 1, +}; + int UI_icon_from_id(struct ID *id); int UI_icon_from_report_type(int type); @@ -952,16 +963,20 @@ uiLayout *uiLayoutRadial(uiLayout *layout); /* templates */ void uiTemplateHeader(uiLayout *layout, struct bContext *C); -void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); -void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); -void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop, int rows, int cols); +void uiTemplateID( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int filter); +void uiTemplateIDBrowse( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int filter); +void uiTemplateIDPreview( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter); void uiTemplateIDTabs( uiLayout *layout, struct bContext *C, PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop); + const char *newop, const char *openop, const char *unlinkop, + int filter); void uiTemplateAnyID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *proptypename, const char *text); void uiTemplateSearch( @@ -1125,6 +1140,8 @@ void UI_context_active_but_prop_get_templateID( struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); +uiBut *UI_region_active_but_get(struct ARegion *ar); + /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, @@ -1168,6 +1185,13 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p); bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src); void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); +/* ui_interface_region_tooltip.c */ +struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but); +struct ARegion *UI_tooltip_create_from_manipulator(struct bContext *C, struct wmManipulator *mpr); +void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar); + +/* How long before a tool-tip shows. */ +#define UI_TOOLTIP_DELAY 0.5 /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 6 diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 03a2c1ec414..94f377fb35e 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -45,6 +45,11 @@ set(SRC interface_anim.c interface_draw.c interface_eyedropper.c + interface_eyedropper_color.c + interface_eyedropper_colorband.c + interface_eyedropper_datablock.c + interface_eyedropper_depth.c + interface_eyedropper_driver.c interface_handlers.c interface_icons.c interface_layout.c diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index e46c6a0e267..3ecb72353bc 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -40,9 +40,9 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_node.h" -#include "BKE_texture.h" #include "BKE_tracking.h" @@ -1335,7 +1335,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; - do_colorband(coba, pos, colf); + BKE_colorband_evaluate(coba, pos, colf); if (display) IMB_colormanagement_scene_linear_to_display_v3(colf, display); @@ -1354,7 +1354,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2); for (int a = 0; a <= sizex; a++) { float pos = ((float)a) / sizex; - do_colorband(coba, pos, colf); + BKE_colorband_evaluate(coba, pos, colf); if (display) IMB_colormanagement_scene_linear_to_display_v3(colf, display); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index e92139ada0c..8cb55b724fb 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -27,55 +27,23 @@ * \ingroup edinterface */ -#include "MEM_guardedalloc.h" - -#include "DNA_anim_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" -#include "DNA_object_types.h" #include "BLI_blenlib.h" #include "BLI_math_vector.h" -#include "BLT_translation.h" - #include "BKE_context.h" #include "BKE_screen.h" -#include "BKE_report.h" -#include "BKE_animsys.h" -#include "BKE_idcode.h" -#include "BKE_unit.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "BIF_gl.h" #include "UI_interface.h" -#include "IMB_colormanagement.h" - #include "WM_api.h" #include "WM_types.h" #include "interface_intern.h" -/* for HDR color sampling */ -#include "ED_image.h" -#include "ED_node.h" -#include "ED_clip.h" - -/* for ID data eyedropper */ -#include "ED_space_api.h" -#include "ED_screen.h" -#include "ED_view3d.h" - -/* for Driver eyedropper */ -#include "ED_keyframing.h" - +#include "interface_eyedropper_intern.h" /* own include */ /* -------------------------------------------------------------------- */ /* Keymap @@ -83,12 +51,6 @@ /** \name Modal Keymap * \{ */ -enum { - EYE_MODAL_CANCEL = 1, - EYE_MODAL_SAMPLE_CONFIRM, - EYE_MODAL_SAMPLE_BEGIN, - EYE_MODAL_SAMPLE_RESET, -}; wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) { @@ -118,6 +80,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET); /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth"); @@ -126,6 +89,37 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) return keymap; } +wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items_point[] = { + {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""}, + {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""}, + {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""}, + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map"); + if (keymap && keymap->modal_items) + return keymap; + + keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE); + WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET); + + /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point"); + + return keymap; +} + /** \} */ @@ -135,7 +129,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) /** \name Generic Shared Functions * \{ */ -static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name) +void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, const char *name) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; wmWindow *win = CTX_wm_window(C); @@ -169,14 +163,14 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c * * \return A button under the mouse which relates to some RNA Property, or NULL */ -static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) +uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y); ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y); - + uiBut *but = ui_but_find_mouse_over(ar, event); - + if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) { return NULL; } @@ -187,1128 +181,3 @@ static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEv /** \} */ - -/* -------------------------------------------------------------------- */ -/* Eyedropper - */ - -/** \name Eyedropper (RGB Color) - * \{ */ - -typedef struct Eyedropper { - struct ColorManagedDisplay *display; - - PointerRNA ptr; - PropertyRNA *prop; - int index; - - float init_col[3]; /* for resetting on cancel */ - - bool accum_start; /* has mouse been pressed */ - float accum_col[3]; - int accum_tot; -} Eyedropper; - -static bool eyedropper_init(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Eyedropper *eye; - - op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); - - UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); - - if ((eye->ptr.data == NULL) || - (eye->prop == NULL) || - (RNA_property_editable(&eye->ptr, eye->prop) == false) || - (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || - (RNA_property_type(eye->prop) != PROP_FLOAT)) - { - return false; - } - - if (RNA_property_subtype(eye->prop) != PROP_COLOR) { - const char *display_device; - float col[4]; - - display_device = scene->display_settings.display_device; - eye->display = IMB_colormanagement_display_get_named(display_device); - - /* store inital color */ - RNA_property_float_get_array(&eye->ptr, eye->prop, col); - if (eye->display) { - IMB_colormanagement_display_to_scene_linear_v3(col, eye->display); - } - copy_v3_v3(eye->init_col, col); - } - - return true; -} - -static void eyedropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } -} - -/* *** eyedropper_color_ helper functions *** */ - -/** - * \brief get the color from the screen. - * - * Special check for image or nodes where we MAY have HDR pixels which don't display. - */ -static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3]) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - const char *display_device = CTX_data_scene(C)->display_settings.display_device; - struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); - - if (sa) { - if (sa->spacetype == SPACE_IMAGE) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceImage *sima = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_image_color_sample(sima, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_NODE) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceNode *snode = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_node_color_sample(snode, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_CLIP) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - SpaceClip *sc = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { - return; - } - } - } - } - - /* fallback to simple opengl picker */ - glReadBuffer(GL_FRONT); - glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); - glReadBuffer(GL_BACK); - - IMB_colormanagement_display_to_scene_linear_v3(r_col, display); -} - -/* sets the sample color RGB, maintaining A */ -static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) -{ - float col_conv[4]; - - /* to maintain alpha */ - RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); - - /* convert from linear rgb space to display space */ - if (eye->display) { - copy_v3_v3(col_conv, col); - IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); - } - else { - copy_v3_v3(col_conv, col); - } - - RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); - - RNA_property_update(C, &eye->ptr, eye->prop); -} - -/* set sample from accumulated values */ -static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) -{ - float col[3]; - mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); - eyedropper_color_set(C, eye, col); -} - -/* single point sample & set */ -static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - eyedropper_color_set(C, eye, col); -} - -static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - /* delay linear conversion */ - add_v3_v3(eye->accum_col, col); - eye->accum_tot++; -} - -static void eyedropper_cancel(bContext *C, wmOperator *op) -{ - Eyedropper *eye = op->customdata; - eyedropper_color_set(C, eye, eye->init_col); - eyedropper_exit(C, op); -} - -/* main modal status check */ -static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Eyedropper *eye = (Eyedropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - eyedropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - if (eye->accum_tot == 0) { - eyedropper_color_sample(C, eye, event->x, event->y); - } - else { - eyedropper_color_set_accum(C, eye); - } - eyedropper_exit(C, op); - return OPERATOR_FINISHED; - case EYE_MODAL_SAMPLE_BEGIN: - /* enable accum and make first sample */ - eye->accum_start = true; - eyedropper_color_sample_accum(C, eye, event->x, event->y); - break; - case EYE_MODAL_SAMPLE_RESET: - eye->accum_tot = 0; - zero_v3(eye->accum_col); - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - break; - } - } - else if (event->type == MOUSEMOVE) { - if (eye->accum_start) { - /* button is pressed so keep sampling */ - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (eyedropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - eyedropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int eyedropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (eyedropper_init(C, op)) { - - /* do something */ - - /* cleanup */ - eyedropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int eyedropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* Only color buttons */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_COLOR)) - { - return 1; - } - - return 0; -} - -void UI_OT_eyedropper_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper"; - ot->idname = "UI_OT_eyedropper_color"; - ot->description = "Sample a color from the Blender Window to store in a property"; - - /* api callbacks */ - ot->invoke = eyedropper_invoke; - ot->modal = eyedropper_modal; - ot->cancel = eyedropper_cancel; - ot->exec = eyedropper_exec; - ot->poll = eyedropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/* Data Dropper */ - -/** \name Eyedropper (ID data-blocks) - * - * \note: datadropper is only internal name to avoid confusion in this file. - * \{ */ - -typedef struct DataDropper { - PointerRNA ptr; - PropertyRNA *prop; - short idcode; - const char *idcode_name; - - ID *init_id; /* for resetting on cancel */ - - ARegionType *art; - void *draw_handle_pixel; - char name[200]; -} DataDropper; - - -static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) -{ - DataDropper *ddr = arg; - eyedropper_draw_cursor_text(C, ar, ddr->name); -} - - -static int datadropper_init(bContext *C, wmOperator *op) -{ - DataDropper *ddr; - int index_dummy; - StructRNA *type; - - SpaceType *st; - ARegionType *art; - - st = BKE_spacetype_from_id(SPACE_VIEW3D); - art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); - - op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper"); - - UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_type(ddr->prop) != PROP_POINTER)) - { - return false; - } - - ddr->art = art; - ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); - - type = RNA_property_pointer_type(&ddr->ptr, ddr->prop); - ddr->idcode = RNA_type_to_ID_code(type); - BLI_assert(ddr->idcode != 0); - /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */ - ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode)); - - PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop); - ddr->init_id = ptr.id.data; - - return true; -} - -static void datadropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - DataDropper *ddr = (DataDropper *)op->customdata; - - if (ddr->art) { - ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); - } - - MEM_freeN(op->customdata); - - op->customdata = NULL; - } - - WM_event_add_mousemove(C); -} - -/* *** datadropper id helper functions *** */ -/** - * \brief get the ID from the screen. - * - */ -static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my); - - ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); - - ddr->name[0] = '\0'; - - if (sa) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - Base *base; - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - base = ED_view3d_give_base_under_cursor(C, mval); - if (base) { - Object *ob = base->object; - ID *id = NULL; - if (ddr->idcode == ID_OB) { - id = (ID *)ob; - } - else if (ob->data) { - if (GS(((ID *)ob->data)->name) == ddr->idcode) { - id = (ID *)ob->data; - } - else { - BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", - ddr->idcode_name); - } - } - - if (id) { - BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", - ddr->idcode_name, id->name + 2); - *r_id = id; - } - } - } - } - } - - CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); -} - -/* sets the ID, returns success */ -static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) -{ - PointerRNA ptr_value; - - RNA_id_pointer_create(id, &ptr_value); - - RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); - - RNA_property_update(C, &ddr->ptr, ddr->prop); - - ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop); - - return (ptr_value.id.data == id); -} - -/* single point sample & set */ -static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) -{ - ID *id = NULL; - - datadropper_id_sample_pt(C, ddr, mx, my, &id); - return datadropper_id_set(C, ddr, id); -} - -static void datadropper_cancel(bContext *C, wmOperator *op) -{ - DataDropper *ddr = op->customdata; - datadropper_id_set(C, ddr, ddr->init_id); - datadropper_exit(C, op); -} - -/* main modal status check */ -static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - DataDropper *ddr = (DataDropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - datadropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - { - bool success; - - success = datadropper_id_sample(C, ddr, event->x, event->y); - datadropper_exit(C, op); - - if (success) { - return OPERATOR_FINISHED; - } - else { - BKE_report(op->reports, RPT_WARNING, "Failed to set value"); - return OPERATOR_CANCELLED; - } - } - } - } - else if (event->type == MOUSEMOVE) { - ID *id = NULL; - datadropper_id_sample_pt(C, ddr, event->x, event->y, &id); - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (datadropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - datadropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int datadropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (datadropper_init(C, op)) { - /* cleanup */ - datadropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int datadropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* data dropper only supports object data */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_VALUE_CLEAR)) - { - if (prop && RNA_property_type(prop) == PROP_POINTER) { - StructRNA *type = RNA_property_pointer_type(&ptr, prop); - const short idcode = RNA_type_to_ID_code(type); - if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) { - return 1; - } - } - } - - return 0; -} - -void UI_OT_eyedropper_id(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Data-Block"; - ot->idname = "UI_OT_eyedropper_id"; - ot->description = "Sample a data-block from the 3D View to store in a property"; - - /* api callbacks */ - ot->invoke = datadropper_invoke; - ot->modal = datadropper_modal; - ot->cancel = datadropper_cancel; - ot->exec = datadropper_exec; - ot->poll = datadropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/* Depth Dropper */ - -/** \name Eyedropper (Depth) - * - * \note: depthdropper is only internal name to avoid confusion in this file. - * \{ */ - -typedef struct DepthDropper { - PointerRNA ptr; - PropertyRNA *prop; - - float init_depth; /* for resetting on cancel */ - - bool accum_start; /* has mouse been presed */ - float accum_depth; - int accum_tot; - - ARegionType *art; - void *draw_handle_pixel; - char name[200]; -} DepthDropper; - - -static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) -{ - DepthDropper *ddr = arg; - eyedropper_draw_cursor_text(C, ar, ddr->name); -} - - -static int depthdropper_init(bContext *C, wmOperator *op) -{ - DepthDropper *ddr; - int index_dummy; - - SpaceType *st; - ARegionType *art; - - st = BKE_spacetype_from_id(SPACE_VIEW3D); - art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); - - op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper"); - - UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); - - /* fallback to the active camera's dof */ - if (ddr->prop == NULL) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (rv3d && rv3d->persp == RV3D_CAMOB) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); - ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); - } - } - } - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_type(ddr->prop) != PROP_FLOAT)) - { - return false; - } - - ddr->art = art; - ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); - ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop); - - return true; -} - -static void depthdropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - DepthDropper *ddr = (DepthDropper *)op->customdata; - - if (ddr->art) { - ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); - } - - MEM_freeN(op->customdata); - - op->customdata = NULL; - } -} - -/* *** depthdropper id helper functions *** */ -/** - * \brief get the ID from the screen. - * - */ -static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) -{ - /* we could use some clever */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - Scene *scene = CTX_data_scene(C); - UnitSettings *unit = &scene->unit; - const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; - - ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); - - ddr->name[0] = '\0'; - - if (sa) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (ar) { - struct Depsgraph *graph = CTX_data_depsgraph(C); - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - /* weak, we could pass in some reference point */ - const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - float co[3]; - - EvaluationContext eval_ctx; - CTX_data_eval_ctx(C, &eval_ctx); - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - view3d_operator_needs_opengl(C); - - if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) { - const float mval_center_fl[2] = { - (float)ar->winx / 2, - (float)ar->winy / 2}; - float co_align[3]; - - /* quick way to get view-center aligned point */ - ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align); - - *r_depth = len_v3v3(view_co, co_align); - - bUnit_AsString(ddr->name, sizeof(ddr->name), - (double)*r_depth, - 4, unit->system, B_UNIT_LENGTH, do_split, false); - } - else { - BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); - } - } - } - } - - CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); -} - -/* sets the sample depth RGB, maintaining A */ -static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth) -{ - RNA_property_float_set(&ddr->ptr, ddr->prop, depth); - RNA_property_update(C, &ddr->ptr, ddr->prop); -} - -/* set sample from accumulated values */ -static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) -{ - float depth = ddr->accum_depth; - if (ddr->accum_tot) { - depth /= (float)ddr->accum_tot; - } - depthdropper_depth_set(C, ddr, depth); -} - -/* single point sample & set */ -static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) -{ - float depth = -1.0f; - if (depth != -1.0f) { - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); - depthdropper_depth_set(C, ddr, depth); - } -} - -static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) -{ - float depth = -1.0f; - depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); - if (depth != -1.0f) { - ddr->accum_depth += depth; - ddr->accum_tot++; - } -} - -static void depthdropper_cancel(bContext *C, wmOperator *op) -{ - DepthDropper *ddr = op->customdata; - depthdropper_depth_set(C, ddr, ddr->init_depth); - depthdropper_exit(C, op); -} - -/* main modal status check */ -static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - DepthDropper *ddr = (DepthDropper *)op->customdata; - - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - depthdropper_cancel(C, op); - return OPERATOR_CANCELLED; - case EYE_MODAL_SAMPLE_CONFIRM: - if (ddr->accum_tot == 0) { - depthdropper_depth_sample(C, ddr, event->x, event->y); - } - else { - depthdropper_depth_set_accum(C, ddr); - } - depthdropper_exit(C, op); - return OPERATOR_FINISHED; - case EYE_MODAL_SAMPLE_BEGIN: - /* enable accum and make first sample */ - ddr->accum_start = true; - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - break; - case EYE_MODAL_SAMPLE_RESET: - ddr->accum_tot = 0; - ddr->accum_depth = 0.0f; - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - depthdropper_depth_set_accum(C, ddr); - break; - } - } - else if (event->type == MOUSEMOVE) { - if (ddr->accum_start) { - /* button is pressed so keep sampling */ - depthdropper_depth_sample_accum(C, ddr, event->x, event->y); - depthdropper_depth_set_accum(C, ddr); - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (depthdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - depthdropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int depthdropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (depthdropper_init(C, op)) { - /* cleanup */ - depthdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int depthdropper_poll(bContext *C) -{ - PointerRNA ptr; - PropertyRNA *prop; - int index_dummy; - uiBut *but; - - /* check if there's an active button taking depth value */ - if ((CTX_wm_window(C) != NULL) && - (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && - (but->type == UI_BTYPE_NUM) && - (prop != NULL)) - { - if ((RNA_property_type(prop) == PROP_FLOAT) && - (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && - (RNA_property_array_check(prop) == false)) - { - return 1; - } - } - else { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - if (rv3d && rv3d->persp == RV3D_CAMOB) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - return 1; - } - } - } - - return 0; -} - -void UI_OT_eyedropper_depth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Depth"; - ot->idname = "UI_OT_eyedropper_depth"; - ot->description = "Sample depth from the 3D view"; - - /* api callbacks */ - ot->invoke = depthdropper_invoke; - ot->modal = depthdropper_modal; - ot->cancel = depthdropper_cancel; - ot->exec = depthdropper_exec; - ot->poll = depthdropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; - - /* properties */ -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/* Eyedropper - */ - -/* NOTE: This is here (instead of in drivers.c) because we need access the button internals, - * which we cannot access outside of the interface module - */ - -/** \name Eyedropper (Driver Target) - * \{ */ - -typedef struct DriverDropper { - /* Destination property (i.e. where we'll add a driver) */ - PointerRNA ptr; - PropertyRNA *prop; - int index; - - // TODO: new target? -} DriverDropper; - -static bool driverdropper_init(bContext *C, wmOperator *op) -{ - DriverDropper *ddr; - uiBut *but; - - op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper"); - - but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index); - - if ((ddr->ptr.data == NULL) || - (ddr->prop == NULL) || - (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || - (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) || - (but->flag & UI_BUT_DRIVEN)) - { - return false; - } - - return true; -} - -static void driverdropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_modal_restore(CTX_wm_window(C)); - - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } -} - -static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) -{ - DriverDropper *ddr = (DriverDropper *)op->customdata; - uiBut *but = eyedropper_get_property_button_under_mouse(C, event); - - short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); - short flag = 0; - - /* we can only add a driver if we know what RNA property it corresponds to */ - if (but == NULL) { - return; - } - else { - /* Get paths for src... */ - PointerRNA *target_ptr = &but->rnapoin; - PropertyRNA *target_prop = but->rnaprop; - int target_index = but->rnaindex; - - char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); - - /* ... and destination */ - char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); - - /* Now create driver(s) */ - if (target_path && dst_path) { - int success = ANIM_add_driver_with_target(op->reports, - ddr->ptr.id.data, dst_path, ddr->index, - target_ptr->id.data, target_path, target_index, - flag, DRIVER_TYPE_PYTHON, mapping_type); - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - DEG_relations_tag_update(CTX_data_main(C)); - DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX - } - } - - /* cleanup */ - if (target_path) - MEM_freeN(target_path); - if (dst_path) - MEM_freeN(dst_path); - } -} - -static void driverdropper_cancel(bContext *C, wmOperator *op) -{ - driverdropper_exit(C, op); -} - -/* main modal status check */ -static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - /* handle modal keymap */ - if (event->type == EVT_MODAL_MAP) { - switch (event->val) { - case EYE_MODAL_CANCEL: - driverdropper_cancel(C, op); - return OPERATOR_CANCELLED; - - case EYE_MODAL_SAMPLE_CONFIRM: - driverdropper_sample(C, op, event); - driverdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (driverdropper_init(C, op)) { - WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - driverdropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int driverdropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (driverdropper_init(C, op)) { - /* cleanup */ - driverdropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int driverdropper_poll(bContext *C) -{ - if (!CTX_wm_window(C)) return 0; - else return 1; -} - -void UI_OT_eyedropper_driver(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper Driver"; - ot->idname = "UI_OT_eyedropper_driver"; - ot->description = "Pick a property to use as a driver target"; - - /* api callbacks */ - ot->invoke = driverdropper_invoke; - ot->modal = driverdropper_modal; - ot->cancel = driverdropper_cancel; - ot->exec = driverdropper_exec; - ot->poll = driverdropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0, - "Mapping Type", "Method used to match target and driven properties"); -} - -/** \} */ diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c new file mode 100644 index 00000000000..f3301d55284 --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -0,0 +1,356 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_color.c + * \ingroup edinterface + * + * Eyedropper (RGB Color) + * + * Defines: + * - #UI_OT_eyedropper_color + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "RNA_access.h" + +#include "BIF_gl.h" + +#include "UI_interface.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + +#include "ED_image.h" +#include "ED_node.h" +#include "ED_clip.h" + +#include "interface_eyedropper_intern.h" + +typedef struct Eyedropper { + struct ColorManagedDisplay *display; + + PointerRNA ptr; + PropertyRNA *prop; + int index; + + float init_col[3]; /* for resetting on cancel */ + + bool accum_start; /* has mouse been pressed */ + float accum_col[3]; + int accum_tot; +} Eyedropper; + +static bool eyedropper_init(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Eyedropper *eye; + + op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); + + UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index); + + if ((eye->ptr.data == NULL) || + (eye->prop == NULL) || + (RNA_property_editable(&eye->ptr, eye->prop) == false) || + (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || + (RNA_property_type(eye->prop) != PROP_FLOAT)) + { + return false; + } + + if (RNA_property_subtype(eye->prop) != PROP_COLOR) { + const char *display_device; + float col[4]; + + display_device = scene->display_settings.display_device; + eye->display = IMB_colormanagement_display_get_named(display_device); + + /* store inital color */ + RNA_property_float_get_array(&eye->ptr, eye->prop, col); + if (eye->display) { + IMB_colormanagement_display_to_scene_linear_v3(col, eye->display); + } + copy_v3_v3(eye->init_col, col); + } + + return true; +} + +static void eyedropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } +} + +/* *** eyedropper_color_ helper functions *** */ + +/** + * \brief get the color from the screen. + * + * Special check for image or nodes where we MAY have HDR pixels which don't display. + * + * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking. + */ +void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + const char *display_device = CTX_data_scene(C)->display_settings.display_device; + struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); + + if (sa) { + if (sa->spacetype == SPACE_IMAGE) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceImage *sima = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_image_color_sample(sima, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_NODE) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceNode *snode = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_node_color_sample(snode, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_CLIP) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + SpaceClip *sc = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { + return; + } + } + } + } + + /* fallback to simple opengl picker */ + glReadBuffer(GL_FRONT); + glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); + glReadBuffer(GL_BACK); + + IMB_colormanagement_display_to_scene_linear_v3(r_col, display); +} + +/* sets the sample color RGB, maintaining A */ +static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) +{ + float col_conv[4]; + + /* to maintain alpha */ + RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); + + /* convert from linear rgb space to display space */ + if (eye->display) { + copy_v3_v3(col_conv, col); + IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); + } + else { + copy_v3_v3(col_conv, col); + } + + RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); + + RNA_property_update(C, &eye->ptr, eye->prop); +} + +/* set sample from accumulated values */ +static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) +{ + float col[3]; + mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); + eyedropper_color_set(C, eye, col); +} + +/* single point sample & set */ +static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, mx, my, col); + eyedropper_color_set(C, eye, col); +} + +static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, mx, my, col); + /* delay linear conversion */ + add_v3_v3(eye->accum_col, col); + eye->accum_tot++; +} + +static void eyedropper_cancel(bContext *C, wmOperator *op) +{ + Eyedropper *eye = op->customdata; + eyedropper_color_set(C, eye, eye->init_col); + eyedropper_exit(C, op); +} + +/* main modal status check */ +static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Eyedropper *eye = (Eyedropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + eyedropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + if (eye->accum_tot == 0) { + eyedropper_color_sample(C, eye, event->x, event->y); + } + else { + eyedropper_color_set_accum(C, eye); + } + eyedropper_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + eye->accum_start = true; + eyedropper_color_sample_accum(C, eye, event->x, event->y); + break; + case EYE_MODAL_SAMPLE_RESET: + eye->accum_tot = 0; + zero_v3(eye->accum_col); + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + break; + } + } + else if (event->type == MOUSEMOVE) { + if (eye->accum_start) { + /* button is pressed so keep sampling */ + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + eyedropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int eyedropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* Only color buttons */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_COLOR)) + { + return 1; + } + + return 0; +} + +void UI_OT_eyedropper_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper"; + ot->idname = "UI_OT_eyedropper_color"; + ot->description = "Sample a color from the Blender Window to store in a property"; + + /* api callbacks */ + ot->invoke = eyedropper_invoke; + ot->modal = eyedropper_modal; + ot->cancel = eyedropper_cancel; + ot->exec = eyedropper_exec; + ot->poll = eyedropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c new file mode 100644 index 00000000000..b13d552dbeb --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -0,0 +1,337 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_colorband.c + * \ingroup edinterface + * + * Eyedropper (Color Band). + * + * Operates by either: + * - Dragging a straight line, sampling pixels formed by the line to extract a gradient. + * - Clicking on points, adding each color to the end of the color-band. + * + * Defines: + * - #UI_OT_eyedropper_colorband + * - #UI_OT_eyedropper_colorband_point + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_screen_types.h" + +#include "BLI_bitmap_draw_2d.h" +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_colorband.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + +#include "interface_eyedropper_intern.h" + +typedef struct Colorband_RNAUpdateCb { + PointerRNA ptr; + PropertyRNA *prop; +} Colorband_RNAUpdateCb; + +typedef struct EyedropperColorband { + int last_x, last_y; + /* Alpha is currently fixed at 1.0, may support in future. */ + float (*color_buffer)[4]; + int color_buffer_alloc; + int color_buffer_len; + bool sample_start; + ColorBand init_color_band; + ColorBand *color_band; + PointerRNA ptr; + PropertyRNA *prop; +} EyedropperColorband; + +/* For user-data only. */ +struct EyedropperColorband_Context { + bContext *context; + EyedropperColorband *eye; +}; + +static bool eyedropper_colorband_init(bContext *C, wmOperator *op) +{ + ColorBand *band = NULL; + EyedropperColorband *eye; + + uiBut *but = UI_context_active_but_get(C); + + if (but == NULL) { + /* pass */ + } + else if (but->type == UI_BTYPE_COLORBAND) { + /* When invoked with a hotkey, we can find the band in 'but->poin'. */ + band = (ColorBand *)but->poin; + } + else { + /* When invoked from a button it's in custom_data field. */ + band = (ColorBand *)but->custom_data; + } + + if (!band) + return false; + + op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__); + eye->color_buffer_alloc = 16; + eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__); + eye->color_buffer_len = 0; + eye->color_band = band; + eye->init_color_band = *eye->color_band; + eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; + eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; + + return true; +} + +static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + if (eye->last_x != mx || eye->last_y != my) { + float col[4]; + col[3] = 1.0f; /* TODO: sample alpha */ + eyedropper_color_sample_fl(C, mx, my, col); + if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) { + eye->color_buffer_alloc *= 2; + eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc); + } + copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col); + eye->color_buffer_len += 1; + eye->last_x = mx; + eye->last_y = my; + } +} + +static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata) +{ + struct EyedropperColorband_Context *data = userdata; + bContext *C = data->context; + EyedropperColorband *eye = data->eye; + eyedropper_colorband_sample_point(C, eye, mx, my); + return true; +} + +static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i + * to interpolate between the reported coordinates */ + struct EyedropperColorband_Context userdata = {C, eye}; + int p1[2] = {eye->last_x, eye->last_y}; + int p2[2] = {mx, my}; + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata); +} + +static void eyedropper_colorband_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + EyedropperColorband *eye = op->customdata; + MEM_freeN(eye->color_buffer); + MEM_freeN(eye); + op->customdata = NULL; + } +} + +static void eyedropper_colorband_apply(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + /* Always filter, avoids noise in resulting color-band. */ + bool filter_samples = true; + BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples); + RNA_property_update(C, &eye->ptr, eye->prop); +} + +static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eyedropper_colorband_exit(C, op); +} + +/* main modal status check */ +static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + eye->sample_start = true; + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eye->last_x = event->x; + eye->last_y = event->y; + break; + case EYE_MODAL_SAMPLE_RESET: + break; + } + } + else if (event->type == MOUSEMOVE) { + if (eye->sample_start) { + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + } + } + return OPERATOR_RUNNING_MODAL; +} + +static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_POINT_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_POINT_CONFIRM: + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_POINT_REMOVE_LAST: + if (eye->color_buffer_len > 0) { + eye->color_buffer_len -= 1; + eyedropper_colorband_apply(C, op); + } + break; + case EYE_MODAL_POINT_SAMPLE: + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + if (eye->color_buffer_len == MAXCOLORBAND ) { + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + } + break; + case EYE_MODAL_SAMPLE_RESET: + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eye->color_buffer_len = 0; + break; + } + } + return OPERATOR_RUNNING_MODAL; +} + + +/* Modal Operator init */ +static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + eyedropper_colorband_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_colorband_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_colorband_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int eyedropper_colorband_poll(bContext *C) +{ + uiBut *but = UI_context_active_but_get(C); + return (but && but->type == UI_BTYPE_COLORBAND); +} + + +void UI_OT_eyedropper_colorband(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband"; + ot->idname = "UI_OT_eyedropper_colorband"; + ot->description = "Sample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + ot->poll = eyedropper_colorband_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} + +void UI_OT_eyedropper_colorband_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband (points)"; + ot->idname = "UI_OT_eyedropper_colorband_point"; + ot->description = "Pointsample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_point_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + ot->poll = eyedropper_colorband_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c new file mode 100644 index 00000000000..f814048c0c0 --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -0,0 +1,351 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_datablock.c + * \ingroup edinterface + * + * Eyedropper (ID data-blocks) + * + * Defines: + * - #UI_OT_eyedropper_id + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" + +#include "BLI_string.h" +#include "BLI_math_vector.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_report.h" +#include "BKE_idcode.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_space_api.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +/** + * \note #DataDropper is only internal name to avoid confusion with other kinds of eye-droppers. + */ +typedef struct DataDropper { + PointerRNA ptr; + PropertyRNA *prop; + short idcode; + const char *idcode_name; + + ID *init_id; /* for resetting on cancel */ + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} DataDropper; + + +static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) +{ + DataDropper *ddr = arg; + eyedropper_draw_cursor_text(C, ar, ddr->name); +} + + +static int datadropper_init(bContext *C, wmOperator *op) +{ + DataDropper *ddr; + int index_dummy; + StructRNA *type; + + SpaceType *st; + ARegionType *art; + + st = BKE_spacetype_from_id(SPACE_VIEW3D); + art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + + op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper"); + + UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_POINTER)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + + type = RNA_property_pointer_type(&ddr->ptr, ddr->prop); + ddr->idcode = RNA_type_to_ID_code(type); + BLI_assert(ddr->idcode != 0); + /* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */ + ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode)); + + PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop); + ddr->init_id = ptr.id.data; + + return true; +} + +static void datadropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + DataDropper *ddr = (DataDropper *)op->customdata; + + if (ddr->art) { + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + } + + MEM_freeN(op->customdata); + + op->customdata = NULL; + } + + WM_event_add_mousemove(C); +} + +/* *** datadropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my); + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *ar_prev = CTX_wm_region(C); + + ddr->name[0] = '\0'; + + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + Base *base; + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + base = ED_view3d_give_base_under_cursor(C, mval); + if (base) { + Object *ob = base->object; + ID *id = NULL; + if (ddr->idcode == ID_OB) { + id = (ID *)ob; + } + else if (ob->data) { + if (GS(((ID *)ob->data)->name) == ddr->idcode) { + id = (ID *)ob->data; + } + else { + BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", + ddr->idcode_name); + } + } + + if (id) { + BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", + ddr->idcode_name, id->name + 2); + *r_id = id; + } + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the ID, returns success */ +static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) +{ + PointerRNA ptr_value; + + RNA_id_pointer_create(id, &ptr_value); + + RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); + + RNA_property_update(C, &ddr->ptr, ddr->prop); + + ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop); + + return (ptr_value.id.data == id); +} + +/* single point sample & set */ +static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) +{ + ID *id = NULL; + + datadropper_id_sample_pt(C, ddr, mx, my, &id); + return datadropper_id_set(C, ddr, id); +} + +static void datadropper_cancel(bContext *C, wmOperator *op) +{ + DataDropper *ddr = op->customdata; + datadropper_id_set(C, ddr, ddr->init_id); + datadropper_exit(C, op); +} + +/* main modal status check */ +static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DataDropper *ddr = (DataDropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + datadropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + { + bool success; + + success = datadropper_id_sample(C, ddr, event->x, event->y); + datadropper_exit(C, op); + + if (success) { + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_WARNING, "Failed to set value"); + return OPERATOR_CANCELLED; + } + } + } + } + else if (event->type == MOUSEMOVE) { + ID *id = NULL; + datadropper_id_sample_pt(C, ddr, event->x, event->y, &id); + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (datadropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + datadropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int datadropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (datadropper_init(C, op)) { + /* cleanup */ + datadropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int datadropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* data dropper only supports object data */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_SEARCH_MENU) && + (but->flag & UI_BUT_VALUE_CLEAR)) + { + if (prop && RNA_property_type(prop) == PROP_POINTER) { + StructRNA *type = RNA_property_pointer_type(&ptr, prop); + const short idcode = RNA_type_to_ID_code(type); + if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) { + return 1; + } + } + } + + return 0; +} + +void UI_OT_eyedropper_id(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Data-Block"; + ot->idname = "UI_OT_eyedropper_id"; + ot->description = "Sample a data-block from the 3D View to store in a property"; + + /* api callbacks */ + ot->invoke = datadropper_invoke; + ot->modal = datadropper_modal; + ot->cancel = datadropper_cancel; + ot->exec = datadropper_exec; + ot->poll = datadropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c new file mode 100644 index 00000000000..6e85d091fdb --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -0,0 +1,391 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_depth.c + * \ingroup edinterface + * + * This file defines an eyedropper for picking 3D depth value (primary use is depth-of-field). + * + * Defines: + * - #UI_OT_eyedropper_depth + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_string.h" +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_unit.h" + +#include "DEG_depsgraph.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +/** + * \note #DepthDropper is only internal name to avoid confusion with other kinds of eye-droppers. + */ +typedef struct DepthDropper { + PointerRNA ptr; + PropertyRNA *prop; + + float init_depth; /* for resetting on cancel */ + + bool accum_start; /* has mouse been presed */ + float accum_depth; + int accum_tot; + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} DepthDropper; + + +static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg) +{ + DepthDropper *ddr = arg; + eyedropper_draw_cursor_text(C, ar, ddr->name); +} + + +static int depthdropper_init(bContext *C, wmOperator *op) +{ + DepthDropper *ddr; + int index_dummy; + + SpaceType *st; + ARegionType *art; + + st = BKE_spacetype_from_id(SPACE_VIEW3D); + art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW); + + op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper"); + + UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy); + + /* fallback to the active camera's dof */ + if (ddr->prop == NULL) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { + RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); + } + } + } + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_FLOAT)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop); + + return true; +} + +static void depthdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + DepthDropper *ddr = (DepthDropper *)op->customdata; + + if (ddr->art) { + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + } + + MEM_freeN(op->customdata); + + op->customdata = NULL; + } +} + +/* *** depthdropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) +{ + /* we could use some clever */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + Scene *scene = CTX_data_scene(C); + + UnitSettings *unit = &scene->unit; + const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *ar_prev = CTX_wm_region(C); + + ddr->name[0] = '\0'; + + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (ar) { + struct Depsgraph *graph = CTX_data_depsgraph(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + /* weak, we could pass in some reference point */ + const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + float co[3]; + + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + view3d_operator_needs_opengl(C); + + if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) { + const float mval_center_fl[2] = { + (float)ar->winx / 2, + (float)ar->winy / 2}; + float co_align[3]; + + /* quick way to get view-center aligned point */ + ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align); + + *r_depth = len_v3v3(view_co, co_align); + + bUnit_AsString(ddr->name, sizeof(ddr->name), + (double)*r_depth, + 4, unit->system, B_UNIT_LENGTH, do_split, false); + } + else { + BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the sample depth RGB, maintaining A */ +static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth) +{ + RNA_property_float_set(&ddr->ptr, ddr->prop, depth); + RNA_property_update(C, &ddr->ptr, ddr->prop); +} + +/* set sample from accumulated values */ +static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) +{ + float depth = ddr->accum_depth; + if (ddr->accum_tot) { + depth /= (float)ddr->accum_tot; + } + depthdropper_depth_set(C, ddr, depth); +} + +/* single point sample & set */ +static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + if (depth != -1.0f) { + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + depthdropper_depth_set(C, ddr, depth); + } +} + +static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my) +{ + float depth = -1.0f; + depthdropper_depth_sample_pt(C, ddr, mx, my, &depth); + if (depth != -1.0f) { + ddr->accum_depth += depth; + ddr->accum_tot++; + } +} + +static void depthdropper_cancel(bContext *C, wmOperator *op) +{ + DepthDropper *ddr = op->customdata; + depthdropper_depth_set(C, ddr, ddr->init_depth); + depthdropper_exit(C, op); +} + +/* main modal status check */ +static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DepthDropper *ddr = (DepthDropper *)op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + depthdropper_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + if (ddr->accum_tot == 0) { + depthdropper_depth_sample(C, ddr, event->x, event->y); + } + else { + depthdropper_depth_set_accum(C, ddr); + } + depthdropper_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + ddr->accum_start = true; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + break; + case EYE_MODAL_SAMPLE_RESET: + ddr->accum_tot = 0; + ddr->accum_depth = 0.0f; + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + break; + } + } + else if (event->type == MOUSEMOVE) { + if (ddr->accum_start) { + /* button is pressed so keep sampling */ + depthdropper_depth_sample_accum(C, ddr, event->x, event->y); + depthdropper_depth_set_accum(C, ddr); + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (depthdropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + depthdropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int depthdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (depthdropper_init(C, op)) { + /* cleanup */ + depthdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int depthdropper_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index_dummy; + uiBut *but; + + /* check if there's an active button taking depth value */ + if ((CTX_wm_window(C) != NULL) && + (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && + (but->type == UI_BTYPE_NUM) && + (prop != NULL)) + { + if ((RNA_property_type(prop) == PROP_FLOAT) && + (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) && + (RNA_property_array_check(prop) == false)) + { + return 1; + } + } + else { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { + return 1; + } + } + } + + return 0; +} + +void UI_OT_eyedropper_depth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Depth"; + ot->idname = "UI_OT_eyedropper_depth"; + ot->description = "Sample depth from the 3D view"; + + /* api callbacks */ + ot->invoke = depthdropper_invoke; + ot->modal = depthdropper_modal; + ot->cancel = depthdropper_cancel; + ot->exec = depthdropper_exec; + ot->poll = depthdropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c new file mode 100644 index 00000000000..50a8473135a --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -0,0 +1,234 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_driver.c + * \ingroup edinterface + * + * Eyedropper (Animation Driver Targets). + * + * Defines: + * - #UI_OT_eyedropper_driver + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" + +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_animsys.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" + +#include "interface_intern.h" +#include "interface_eyedropper_intern.h" + +typedef struct DriverDropper { + /* Destination property (i.e. where we'll add a driver) */ + PointerRNA ptr; + PropertyRNA *prop; + int index; + + // TODO: new target? +} DriverDropper; + +static bool driverdropper_init(bContext *C, wmOperator *op) +{ + DriverDropper *ddr; + uiBut *but; + + op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper"); + + but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index); + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) || + (but->flag & UI_BUT_DRIVEN)) + { + return false; + } + + return true; +} + +static void driverdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } +} + +static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) +{ + DriverDropper *ddr = (DriverDropper *)op->customdata; + uiBut *but = eyedropper_get_property_button_under_mouse(C, event); + + short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); + short flag = 0; + + /* we can only add a driver if we know what RNA property it corresponds to */ + if (but == NULL) { + return; + } + else { + /* Get paths for src... */ + PointerRNA *target_ptr = &but->rnapoin; + PropertyRNA *target_prop = but->rnaprop; + int target_index = but->rnaindex; + + char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); + + /* ... and destination */ + char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); + + /* Now create driver(s) */ + if (target_path && dst_path) { + int success = ANIM_add_driver_with_target(op->reports, + ddr->ptr.id.data, dst_path, ddr->index, + target_ptr->id.data, target_path, target_index, + flag, DRIVER_TYPE_PYTHON, mapping_type); + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX + } + } + + /* cleanup */ + if (target_path) + MEM_freeN(target_path); + if (dst_path) + MEM_freeN(dst_path); + } +} + +static void driverdropper_cancel(bContext *C, wmOperator *op) +{ + driverdropper_exit(C, op); +} + +/* main modal status check */ +static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + driverdropper_cancel(C, op); + return OPERATOR_CANCELLED; + + case EYE_MODAL_SAMPLE_CONFIRM: + driverdropper_sample(C, op, event); + driverdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (driverdropper_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + driverdropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int driverdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (driverdropper_init(C, op)) { + /* cleanup */ + driverdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int driverdropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) return 0; + else return 1; +} + +void UI_OT_eyedropper_driver(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Driver"; + ot->idname = "UI_OT_eyedropper_driver"; + ot->description = "Pick a property to use as a driver target"; + + /* api callbacks */ + ot->invoke = driverdropper_invoke; + ot->modal = driverdropper_modal; + ot->cancel = driverdropper_cancel; + ot->exec = driverdropper_exec; + ot->poll = driverdropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0, + "Mapping Type", "Method used to match target and driven properties"); +} diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h new file mode 100644 index 00000000000..18935c6cc9f --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper_intern.h @@ -0,0 +1,54 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper_intern.h + * \ingroup edinterface + * + * Share between interface_eyedropper_*.c files. + */ + +#ifndef __INTERFACE_EYEDROPPER_INTERN_H__ +#define __INTERFACE_EYEDROPPER_INTERN_H__ + +/* interface_eyedropper.c */ +void eyedropper_draw_cursor_text(const struct bContext *C, const struct ARegion *ar, const char *name); +uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event); + +/* interface_eyedropper_color.c (expose for color-band picker) */ +void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]); + +/* Used for most eye-dropper operators. */ +enum { + EYE_MODAL_CANCEL = 1, + EYE_MODAL_SAMPLE_CONFIRM, + EYE_MODAL_SAMPLE_BEGIN, + EYE_MODAL_SAMPLE_RESET, +}; + +/* Color-band point sample. */ +enum { + EYE_MODAL_POINT_CANCEL = 1, + EYE_MODAL_POINT_SAMPLE, + EYE_MODAL_POINT_CONFIRM, + EYE_MODAL_POINT_RESET, + EYE_MODAL_POINT_REMOVE_LAST, +}; + +#endif /* __INTERFACE_EYEDROPPER_INTERN_H__ */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 53505fc39a4..9ccb47938d2 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -61,6 +61,7 @@ #include "PIL_time.h" +#include "BKE_colorband.h" #include "BKE_blender_undo.h" #include "BKE_brush.h" #include "BKE_colortools.h" @@ -68,7 +69,6 @@ #include "BKE_idprop.h" #include "BKE_report.h" #include "BKE_screen.h" -#include "BKE_texture.h" #include "BKE_tracking.h" #include "BKE_unit.h" #include "BKE_paint.h" @@ -130,7 +130,6 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve /***************** structs and defines ****************/ -#define BUTTON_TOOLTIP_DELAY 0.500 #define BUTTON_FLASH_DELAY 0.020 #define MENU_SCROLL_INTERVAL 0.1 #define PIE_MENU_INTERVAL 0.01 @@ -297,8 +296,6 @@ typedef struct uiHandleButtonData { ColorBand *coba; /* tooltip */ - ARegion *tooltip; - wmTimer *tooltiptimer; unsigned int tooltip_force : 1; /* auto open */ @@ -2295,7 +2292,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char buf_copy[UI_MAX_DRAW_STR]; if (array_length == 4) { - values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); } else { values[3] = 0.0f; @@ -5971,7 +5968,7 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m data->dragcbd->pos += dx; CLAMP(data->dragcbd->pos, 0.0f, 1.0f); - colorband_update_sort(data->coba); + BKE_colorband_update_sort(data->coba); data->dragcbd = data->coba->data + data->coba->cur; /* because qsort */ data->draglastx = mx; @@ -6001,7 +5998,7 @@ static int ui_do_but_COLORBAND( if (event->ctrl) { /* insert new key on mouse location */ float pos = ((float)(mx - but->rect.xmin)) / BLI_rctf_size_x(&but->rect); - colorband_element_add(coba, pos); + BKE_colorband_element_add(coba, pos); button_activate_state(C, but, BUTTON_STATE_EXIT); } else { @@ -6022,6 +6019,7 @@ static int ui_do_but_COLORBAND( } data->dragcbd = coba->data + coba->cur; + data->dragfstart = data->dragcbd->pos; button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); } @@ -6038,7 +6036,15 @@ static int ui_do_but_COLORBAND( else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_EXIT); } - + else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) { + if (event->val == KM_PRESS) { + data->dragcbd->pos = data->dragfstart; + BKE_colorband_update_sort(data->coba); + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + } return WM_UI_HANDLER_BREAK; } @@ -6047,8 +6053,8 @@ static int ui_do_but_COLORBAND( static bool ui_numedit_but_CURVE( uiBlock *block, uiBut *but, uiHandleButtonData *data, - int evtx, int evty, - bool snap, const bool shift) + int evtx, int evty, + bool snap, const bool shift) { CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; @@ -7733,12 +7739,12 @@ static bool button_modal_state(uiHandleButtonState state) */ void UI_but_tooltip_refresh(bContext *C, uiBut *but) { - uiHandleButtonData *data; - - data = but->active; - if (data && data->tooltip) { - ui_tooltip_free(C, data->tooltip); - data->tooltip = ui_tooltip_create(C, data->region, but); + uiHandleButtonData *data = but->active; + if (data) { + bScreen *sc = WM_window_get_active_screen(data->window); + if (sc->tool_tip && sc->tool_tip->region) { + WM_tooltip_refresh(C, data->window); + } } } @@ -7749,39 +7755,38 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) data = but->active; if (data) { - - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } - if (data->tooltip) { - ui_tooltip_free(C, data->tooltip); - data->tooltip = NULL; - } - if (data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; } + + if (data->window) { + WM_tooltip_clear(C, data->window); + } } } +static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event) +{ + uiBut *but = UI_region_active_but_get(ar); + *r_exit_on_event = false; + if (but) { + return UI_tooltip_create_from_button(C, ar, but); + } + return NULL; +} + static void button_tooltip_timer_reset(bContext *C, uiBut *but) { wmWindowManager *wm = CTX_wm_manager(C); - uiHandleButtonData *data; - - data = but->active; + uiHandleButtonData *data = but->active; - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } + WM_tooltip_timer_clear(C, data->window); if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); + WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init); } } } @@ -8141,12 +8146,10 @@ void ui_but_active_free(const bContext *C, uiBut *but) } /* returns the active button with an optional checking function */ -static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *)) +static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *)) { uiBut *but_found = NULL; - ARegion *ar = CTX_wm_region(C); - while (ar) { uiBlock *block; uiBut *but, *activebut = NULL; @@ -8189,12 +8192,17 @@ static bool ui_context_rna_button_active_test(uiBut *but) } static uiBut *ui_context_rna_button_active(const bContext *C) { - return ui_context_button_active(C, ui_context_rna_button_active_test); + return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); } uiBut *UI_context_active_but_get(const struct bContext *C) { - return ui_context_button_active(C, NULL); + return ui_context_button_active(CTX_wm_region(C), NULL); +} + +uiBut *UI_region_active_but_get(ARegion *ar) +{ + return ui_context_button_active(ar, NULL); } /** @@ -8477,16 +8485,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } case TIMER: { - /* handle tooltip timer */ - if (event->customdata == data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - - if (!data->tooltip) - data->tooltip = ui_tooltip_create(C, data->region, but); - } /* handle menu auto open timer */ - else if (event->customdata == data->autoopentimer) { + if (event->customdata == data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 6f450093d30..b2f7d400254 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -595,8 +595,7 @@ struct uiPopupBlockHandle { /* interface_region_*.c */ /* interface_region_tooltip.c */ -struct ARegion *ui_tooltip_create(struct bContext *C, struct ARegion *butregion, uiBut *but); -void ui_tooltip_free(struct bContext *C, struct ARegion *ar); +/* exposed as public API in UI_interface.h */ /* interface_region_color_picker.c */ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]); @@ -764,9 +763,22 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl /* interface_eyedropper.c */ struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf); +struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf); + +/* interface_eyedropper_color.c */ void UI_OT_eyedropper_color(struct wmOperatorType *ot); + +/* interface_eyedropper_colorband.c */ +void UI_OT_eyedropper_colorband(struct wmOperatorType *ot); +void UI_OT_eyedropper_colorband_point(struct wmOperatorType *ot); + +/* interface_eyedropper_datablock.c */ void UI_OT_eyedropper_id(struct wmOperatorType *ot); + +/* interface_eyedropper_depth.c */ void UI_OT_eyedropper_depth(struct wmOperatorType *ot); + +/* interface_eyedropper_driver.c */ void UI_OT_eyedropper_driver(struct wmOperatorType *ot); /* interface_util.c */ diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 645afc03603..27d58c3be1b 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1746,7 +1746,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN } else if (but->type == UI_BTYPE_SEARCH_MENU) { /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */ - but->type = UI_BTYPE_LABEL; + but->flag |= UI_BUT_DISABLED; } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index bbcd10270d5..16525dfbc9e 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1466,6 +1466,8 @@ void ED_operatortypes_ui(void) /* external */ WM_operatortype_append(UI_OT_eyedropper_color); + WM_operatortype_append(UI_OT_eyedropper_colorband); + WM_operatortype_append(UI_OT_eyedropper_colorband_point); WM_operatortype_append(UI_OT_eyedropper_id); WM_operatortype_append(UI_OT_eyedropper_depth); WM_operatortype_append(UI_OT_eyedropper_driver); @@ -1482,6 +1484,8 @@ void ED_keymap_ui(wmKeyConfig *keyconf) /* eyedroppers - notice they all have the same shortcut, but pass the event * through until a suitable eyedropper for the active button is found */ WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0); @@ -1504,4 +1508,5 @@ void ED_keymap_ui(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0); eyedropper_modal_keymap(keyconf); + eyedropper_colorband_modal_keymap(keyconf); } diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index f71b71fce43..07fbefa42e1 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -29,6 +29,14 @@ * ToolTip Region and Construction */ +/* TODO(campbell): + * We may want to have a higher level API that initializes a timer, + * checks for mouse motion and clears the tool-tip afterwards. + * We never want multiple tool-tips at once so this could be handled on the window / window-manager level. + * + * For now it's not a priority, so leave as-is. + */ + #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -97,7 +105,6 @@ typedef struct uiTooltipField { } uiTooltipField; -#define MAX_TOOLTIP_LINES 8 typedef struct uiTooltipData { rcti bbox; uiTooltipField *fields; @@ -314,8 +321,6 @@ static uiTooltipData *ui_tooltip_data_from_keymap(bContext *C, wmKeyMap *keymap) /* create tooltip data */ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); if (ot != NULL) { @@ -609,8 +614,6 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) if (rna_prop.strinfo) MEM_freeN(rna_prop.strinfo); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - if (data->fields_len == 0) { MEM_freeN(data); return NULL; @@ -620,13 +623,116 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) } } -/** \} */ +static uiTooltipData *ui_tooltip_data_from_manipulator(bContext *C, wmManipulator *mpr) +{ + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); -/* -------------------------------------------------------------------- */ -/** \name ToolTip Public API - * \{ */ + /* TODO(campbell): a way for manipulators to have their own descriptions (low priority). */ + + /* Operator Actions */ + { + bool use_drag = mpr->drag_part != -1 && mpr->highlight_part != mpr->drag_part; + + const struct { + int part; + const char *prefix; + } mpop_actions[] = { + { + .part = mpr->highlight_part, + .prefix = use_drag ? TIP_("Click") : NULL, + }, { + .part = use_drag ? mpr->drag_part : -1, + .prefix = use_drag ? TIP_("Drag") : NULL, + }, + }; + + for (int i = 0; i < ARRAY_SIZE(mpop_actions); i++) { + wmManipulatorOpElem *mpop = (mpop_actions[i].part != -1) ? WM_manipulator_operator_get(mpr, mpop_actions[i].part) : NULL; + if (mpop != NULL) { + /* Description */ + const char *info = RNA_struct_ui_description(mpop->type->srna); + if (!(info && info[0])) { + info = RNA_struct_ui_name(mpop->type->srna); + } -ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) + if (info && info[0]) { + char *text = NULL; + if (mpop_actions[i].prefix != NULL) { + text = BLI_sprintfN("%s: %s", mpop_actions[i].prefix, info); + } + else { + text = BLI_strdup(info); + } + + if (text != NULL) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_HEADER, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = text; + } + } + + /* Shortcut */ + { + bool found = false; + IDProperty *prop = mpop->ptr.data; + char buf[128]; + if (WM_key_event_operator_string( + C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, + buf, ARRAY_SIZE(buf))) + { + found = true; + } + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); + } + } + } + } + + /* Property Actions */ + if (mpr->type->target_property_defs_len) { + wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr); + for (int i = 0; i < mpr->type->target_property_defs_len; i++) { + /* TODO(campbell): function callback descriptions. */ + wmManipulatorProperty *mpr_prop = &mpr_prop_array[i]; + if (mpr_prop->prop != NULL) { + const char *info = RNA_property_ui_description(mpr_prop->prop); + if (info && info[0]) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_strdup(info); + } + } + } + } + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } +} + + +static ARegion *ui_tooltip_create_with_data( + bContext *C, uiTooltipData *data, + const float init_position[2], + const float aspect) { const float pad_px = UI_TIP_PADDING; wmWindow *win = CTX_wm_window(C); @@ -634,43 +740,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) uiStyle *style = UI_style_get(); static ARegionType type; ARegion *ar; -/* IDProperty *prop;*/ - /* aspect values that shrink text are likely unreadable */ - const float aspect = min_ff(1.0f, but->block->aspect); int fonth, fontw; - int ofsx, ofsy, h, i; + int h, i; rctf rect_fl; rcti rect_i; int font_flag = 0; - if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; - } - uiTooltipData *data = NULL; - - /* custom tips for pre-defined operators */ - if (but->optype) { - if (STREQ(but->optype->idname, "WM_OT_tool_set")) { - char keymap[64] = ""; - RNA_string_get(but->opptr, "keymap", keymap); - if (keymap[0]) { - ScrArea *sa = CTX_wm_area(C); - wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); - if (km != NULL) { - data = ui_tooltip_data_from_keymap(C, km); - } - } - } - } - /* toolsystem exception */ - - if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); - } - if (data == NULL) { - return NULL; - } - /* create area region */ ar = ui_region_temp_add(CTX_wm_screen(C)); @@ -748,31 +823,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->lineh = h; /* compute position */ - ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0; - ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0; - rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X; + rect_fl.xmin = init_position[0] - TIP_BORDER_X; rect_fl.xmax = rect_fl.xmin + fontw + pad_px; - rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y; + rect_fl.ymax = init_position[1] - TIP_BORDER_Y; rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; - /* since the text has beens caled already, the size of tooltips is defined now */ - /* here we try to figure out the right location */ - if (butregion) { - float mx, my; - float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax; - ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl); - -#if 1 - /* use X mouse location */ - mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect); -#else - mx = ofsx_fl - rect_fl.xmin; -#endif - my = ofsy_fl - rect_fl.ymax; - - BLI_rctf_translate(&rect_fl, mx, my); - } BLI_rcti_rctf_copy(&rect_i, &rect_fl); #undef TIP_BORDER_X @@ -827,9 +883,79 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) return ar; } -void ui_tooltip_free(bContext *C, ARegion *ar) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ToolTip Public API + * \{ */ + + +ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but) +{ + wmWindow *win = CTX_wm_window(C); + /* aspect values that shrink text are likely unreadable */ + const float aspect = min_ff(1.0f, but->block->aspect); + float init_position[2]; + + if (but->drawflag & UI_BUT_NO_TOOLTIP) { + return NULL; + } + uiTooltipData *data = NULL; + + /* custom tips for pre-defined operators */ + if (but->optype) { + if (STREQ(but->optype->idname, "WM_OT_tool_set")) { + char keymap[64] = ""; + RNA_string_get(but->opptr, "keymap", keymap); + if (keymap[0]) { + ScrArea *sa = CTX_wm_area(C); + wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); + if (km != NULL) { + data = ui_tooltip_data_from_keymap(C, km); + } + } + } + } + /* toolsystem exception */ + + if (data == NULL) { + data = ui_tooltip_data_from_button(C, but); + } + if (data == NULL) { + return NULL; + } + + init_position[0] = BLI_rctf_cent_x(&but->rect); + init_position[1] = but->rect.ymin; + + if (butregion) { + ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); + init_position[0] = win->eventstate->x; + } + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr) +{ + wmWindow *win = CTX_wm_window(C); + const float aspect = 1.0f; + float init_position[2]; + + uiTooltipData *data = ui_tooltip_data_from_manipulator(C, mpr); + if (data == NULL) { + return NULL; + } + + init_position[0] = win->eventstate->x; + init_position[1] = win->eventstate->y; + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) { - ui_region_temp_remove(C, CTX_wm_screen(C), ar); + ui_region_temp_remove(C, sc, ar); } /** \} */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 78874076b92..ce2d3bebb97 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -53,6 +53,7 @@ #include "BLF_api.h" #include "BLT_translation.h" +#include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" @@ -60,6 +61,7 @@ #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -70,7 +72,6 @@ #include "BKE_report.h" #include "BKE_sca.h" #include "BKE_screen.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -233,6 +234,8 @@ typedef struct TemplateID { PropertyRNA *prop; ListBase *idlb; + short idcode; + short filter; int prv_rows, prv_cols; bool preview; } TemplateID; @@ -240,73 +243,147 @@ typedef struct TemplateID { /* Search browse menu, assign */ static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item) { - TemplateID *template = (TemplateID *)arg_template; + TemplateID *template_ui = (TemplateID *)arg_template; /* ID */ if (item) { PointerRNA idptr; RNA_id_pointer_create(item, &idptr); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } } +static bool id_search_add( + const bContext *C, TemplateID *template_ui, + const int flag, const char *str, uiSearchItems *items, + ID *id) +{ + ID *id_from = template_ui->ptr.id.data; + + if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) { + + /* use filter */ + if (RNA_property_type(template_ui->prop) == PROP_POINTER) { + PointerRNA ptr; + RNA_id_pointer_create(id, &ptr); + if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) { + return true; + } + } + + /* hide dot-datablocks, but only if filter does not force it visible */ + if (U.uiflag & USER_HIDE_DOT) { + if ((id->name[2] == '.') && (str[0] != '.')) { + return true; + } + } + + if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) { + /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix + * followed by ID_NAME-2 characters from id->name + */ + char name_ui[MAX_ID_NAME + 1]; + BKE_id_ui_prefix(name_ui, id); + + int iconid = ui_id_icon_get(C, id, template_ui->preview); + + if (false == UI_search_item_add(items, name_ui, id, iconid)) { + return false; + } + } + } + return true; +} + /* ID Search browse menu, do the search */ static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) { - TemplateID *template = (TemplateID *)arg_template; - ListBase *lb = template->idlb; - ID *id, *id_from = template->ptr.id.data; - int iconid; - int flag = RNA_property_flag(template->prop); + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + ID *id; + int flag = RNA_property_flag(template_ui->prop); /* ID listbase */ for (id = lb->first; id; id = id->next) { - if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) { - - /* use filter */ - if (RNA_property_type(template->prop) == PROP_POINTER) { - PointerRNA ptr; - RNA_id_pointer_create(id, &ptr); - if (RNA_property_pointer_poll(&template->ptr, template->prop, &ptr) == 0) - continue; + if (!id_search_add(C, template_ui, flag, str, items, id)) { + break; + } + } +} + +/** + * Use id tags for filtering. + */ +static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) +{ + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + ID *id; + int flag = RNA_property_flag(template_ui->prop); + + /* ID listbase */ + for (id = lb->first; id; id = id->next) { + if (id->tag & LIB_TAG_DOIT) { + if (!id_search_add(C, template_ui, flag, str, items, id)) { + break; } + id->tag &= ~LIB_TAG_DOIT; + } + } +} - /* hide dot-datablocks, but only if filter does not force it visible */ - if (U.uiflag & USER_HIDE_DOT) - if ((id->name[2] == '.') && (str[0] != '.')) - continue; +/** + * A version of 'id_search_cb' that lists scene objects. + */ +static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items) +{ + TemplateID *template_ui = (TemplateID *)arg_template; + ListBase *lb = template_ui->idlb; + Scene *scene = NULL; + ID *id_from = template_ui->ptr.id.data; - if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) { - /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix - * followed by ID_NAME-2 characters from id->name - */ - char name_ui[MAX_ID_NAME + 1]; - BKE_id_ui_prefix(name_ui, id); + if (id_from && GS(id_from->name) == ID_SCE) { + scene = (Scene *)id_from; + } + else { + scene = CTX_data_scene(C); + } - iconid = ui_id_icon_get(C, id, template->preview); + BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false); - if (false == UI_search_item_add(items, name_ui, id, iconid)) - break; - } - } + FOREACH_SCENE_OBJECT(scene, ob_iter) + { + ob_iter->id.tag |= LIB_TAG_DOIT; } + FOREACH_SCENE_OBJECT_END + id_search_cb_tagged(C, arg_template, str, items); } /* ID Search browse menu, open */ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) { - static TemplateID template; + static TemplateID template_ui; PointerRNA active_item_ptr; + void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb; /* arg_litem is malloced, can be freed by parent button */ - template = *((TemplateID *)arg_litem); - active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop); + template_ui = *((TemplateID *)arg_litem); + active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop); + + if (template_ui.filter) { + /* Currently only used for objects. */ + if (template_ui.idcode == ID_OB) { + if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) { + id_search_cb_p = id_search_cb_objects_from_scene; + } + } + } return template_common_search_menu( - C, ar, id_search_cb, &template, template_ID_set_property_cb, active_item_ptr.data, - template.prv_rows, template.prv_cols); + C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data, + template_ui.prv_rows, template_ui.prv_cols); } /************************ ID Template ***************************/ @@ -317,7 +394,7 @@ void UI_context_active_but_prop_get_templateID( bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop) { - TemplateID *template; + TemplateID *template_ui; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; @@ -333,9 +410,9 @@ void UI_context_active_but_prop_get_templateID( /* find the button before the active one */ if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { - template = but->func_argN; - *r_ptr = template->ptr; - *r_prop = template->prop; + template_ui = but->func_argN; + *r_ptr = template_ui->ptr; + *r_prop = template_ui->prop; return; } } @@ -346,8 +423,8 @@ void UI_context_active_but_prop_get_templateID( static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) { - TemplateID *template = (TemplateID *)arg_litem; - PointerRNA idptr = RNA_property_pointer_get(&template->ptr, template->prop); + TemplateID *template_ui = (TemplateID *)arg_litem; + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); ID *id = idptr.data; int event = GET_INT_FROM_POINTER(arg_event); @@ -362,8 +439,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_DELETE: memset(&idptr, 0, sizeof(idptr)); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); if (id && CTX_wm_window(C)->eventstate->shift) { /* only way to force-remove data (on save) */ @@ -384,20 +461,40 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) case UI_ID_LOCAL: if (id) { Main *bmain = CTX_data_main(C); - if (id_make_local(bmain, id, false, false)) { - BKE_main_id_clear_newpoins(bmain); + if (CTX_wm_window(C)->eventstate->shift) { + ID *override_id = BKE_override_static_create_from_id(bmain, id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); - /* reassign to get get proper updates/notifiers */ - idptr = RNA_property_pointer_get(&template->ptr, template->prop); - RNA_property_pointer_set(&template->ptr, template->prop, idptr); - RNA_property_update(C, &template->ptr, template->prop); + /* Assign new pointer, takes care of updates/notifiers */ + RNA_id_pointer_create(override_id, &idptr); + } } + else { + if (id_make_local(bmain, id, false, false)) { + BKE_main_id_clear_newpoins(bmain); + + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + } + } + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + } + break; + case UI_ID_OVERRIDE: + if (id && id->override_static) { + BKE_override_static_free(&id->override_static); + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; case UI_ID_ALONE: if (id) { const bool do_scene_obj = (GS(id->name) == ID_OB) && - (template->ptr.type == &RNA_SceneObjects); + (template_ui->ptr.type == &RNA_SceneObjects); /* make copy */ if (do_scene_obj) { @@ -410,7 +507,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) else { if (id) { Main *bmain = CTX_data_main(C); - id_single_user(C, id, &template->ptr, template->prop); + id_single_user(C, id, &template_ui->ptr, template_ui->prop); DEG_relations_tag_update(bmain); } } @@ -477,10 +574,10 @@ static const char *template_id_context(StructRNA *type) #endif static uiBut *template_id_def_new_but( - uiBlock *block, const ID *id, const TemplateID *template, StructRNA *type, + uiBlock *block, const ID *id, const TemplateID *template_ui, StructRNA *type, const char * const newop, const bool editable, const bool id_open, const bool use_tab_but) { - ID *idfrom = template->ptr.id.data; + ID *idfrom = template_ui->ptr.id.data; uiBut *but; const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6; const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT; @@ -518,12 +615,12 @@ static uiBut *template_id_def_new_but( if (newop) { but = uiDefIconTextButO(block, but_type, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); } else { but = uiDefIconTextBut(block, but_type, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW)); } if ((idfrom && idfrom->lib) || !editable) { @@ -538,7 +635,7 @@ static uiBut *template_id_def_new_but( } static void template_ID( - bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag, + bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop) { uiBut *but; @@ -546,13 +643,13 @@ static void template_ID( PointerRNA idptr; // ListBase *lb; // UNUSED ID *id, *idfrom; - const bool editable = RNA_property_editable(&template->ptr, template->prop); - const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0; + const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop); + const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0; - idptr = RNA_property_pointer_get(&template->ptr, template->prop); + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); id = idptr.data; - idfrom = template->ptr.id.data; - // lb = template->idlb; + idfrom = template_ui->ptr.id.data; + // lb = template_ui->idlb; block = uiLayoutGetBlock(layout); UI_block_align_begin(block); @@ -562,8 +659,8 @@ static void template_ID( if (flag & UI_ID_BROWSE) { template_add_button_search_menu( - C, layout, block, &template->ptr, template->prop, - id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)), + C, layout, block, &template_ui->ptr, template_ui->prop, + id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)), use_previews, editable); } @@ -577,7 +674,7 @@ static void template_ID( but = uiDefButR( block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT, &idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type)); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_RENAME)); if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT); if (id->lib) { @@ -587,13 +684,25 @@ static void template_ID( UI_but_flag_enable(but, UI_BUT_DISABLED); } else { + const bool disabled = (!id_make_local(CTX_data_main(C), id, true /* test */, false) || + (idfrom && idfrom->lib)); but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local")); - if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)) + NULL, 0, 0, 0, 0, + TIP_("Direct linked library data-block, click to make local, " + "Shift + Click to create a static override")); + if (disabled) { UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL)); + } } - - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL)); + } + else if (ID_IS_STATIC_OVERRIDE(id)) { + but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, + TIP_("Static override of linked library data-block, click to make fully local")); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE)); } if (id->us > 1) { @@ -607,7 +716,7 @@ static void template_ID( TIP_("Display number of users of this data (click to make a single-user copy)")); but->flag |= UI_BUT_UNDO; - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ALONE)); if (/* test only */ (id_copy(CTX_data_main(C), id, NULL, true) == false) || (idfrom && idfrom->lib) || @@ -627,7 +736,7 @@ static void template_ID( } if (flag & UI_ID_ADD_NEW) { - template_id_def_new_but(block, id, template, type, newop, editable, flag & UI_ID_OPEN, false); + template_id_def_new_but(block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false); } /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. @@ -647,12 +756,12 @@ static void template_ID( if (openop) { but = uiDefIconTextButO(block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN)); } else { but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN)); } if ((idfrom && idfrom->lib) || !editable) @@ -668,16 +777,16 @@ static void template_ID( if (unlinkop) { but = uiDefIconButO(block, UI_BTYPE_BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); /* so we can access the template from operators, font unlinking needs this */ - UI_but_funcN_set(but, NULL, MEM_dupallocN(template), NULL); + UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); } else { - if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) { + if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) { but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Unlink data-block " "(Shift + Click to set users to zero, data will then not be saved)")); - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_DELETE)); - if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) { + if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) { UI_but_flag_enable(but, UI_BUT_DISABLED); } } @@ -690,9 +799,9 @@ static void template_ID( } } - if (idcode == ID_TE) - uiTemplateTextureShow(layout, C, &template->ptr, template->prop); - + if (template_ui->idcode == ID_TE) { + uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); + } UI_block_align_end(block); } @@ -746,9 +855,9 @@ static void ui_template_id( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, - int flag, int prv_rows, int prv_cols, bool use_tabs) + int flag, int prv_rows, int prv_cols, int filter, bool use_tabs) { - TemplateID *template; + TemplateID *template_ui; PropertyRNA *prop; StructRNA *type; short idcode; @@ -760,11 +869,18 @@ static void ui_template_id( return; } - template = MEM_callocN(sizeof(TemplateID), "TemplateID"); - template->ptr = *ptr; - template->prop = prop; - template->prv_rows = prv_rows; - template->prv_cols = prv_cols; + template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID"); + template_ui->ptr = *ptr; + template_ui->prop = prop; + template_ui->prv_rows = prv_rows; + template_ui->prv_cols = prv_cols; + + if ((flag & UI_ID_PIN) == 0) { + template_ui->filter = filter; + } + else { + template_ui->filter = 0; + } if (newop) flag |= UI_ID_ADD_NEW; @@ -773,56 +889,57 @@ static void ui_template_id( type = RNA_property_pointer_type(ptr, prop); idcode = RNA_type_to_ID_code(type); - template->idlb = which_libbase(CTX_data_main(C), idcode); - + template_ui->idcode = idcode; + template_ui->idlb = which_libbase(CTX_data_main(C), idcode); + /* create UI elements for this template * - template_ID makes a copy of the template data and assigns it to the relevant buttons */ - if (template->idlb) { + if (template_ui->idlb) { if (use_tabs) { uiLayoutRow(layout, false); - template_ID_tabs(C, layout, template, type, flag, newop, openop, unlinkop); + template_ID_tabs(C, layout, template_ui, type, flag, newop, openop, unlinkop); } else { uiLayoutRow(layout, true); - template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop); + template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop); } } - MEM_freeN(template); + MEM_freeN(template_ui); } void uiTemplateID( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop) + const char *openop, const char *unlinkop, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, false); + 0, 0, filter, false); } void uiTemplateIDBrowse( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop) + const char *openop, const char *unlinkop, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, - 0, 0, false); + 0, 0, filter, false); } void uiTemplateIDPreview( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop, int rows, int cols) + const char *openop, const char *unlinkop, int rows, int cols, int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, - rows, cols, false); + rows, cols, filter, false); } /** @@ -831,13 +948,14 @@ void uiTemplateIDPreview( void uiTemplateIDTabs( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop) + const char *newop, const char *openop, const char *unlinkop, + int filter) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, true); + 0, 0, filter, true); } /************************ ID Chooser Template ***************************/ @@ -1868,7 +1986,7 @@ static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v) else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f; } - if (colorband_element_add(coba, pos)) { + if (BKE_colorband_element_add(coba, pos)) { rna_update_cb(C, cb_v, NULL); ED_undo_push(C, "Add colorband"); } @@ -1878,7 +1996,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v) { ColorBand *coba = coba_v; - if (colorband_element_remove(coba, coba->cur)) { + if (BKE_colorband_element_remove(coba, coba->cur)) { ED_undo_push(C, "Delete colorband"); rna_update_cb(C, cb_v, NULL); } @@ -1914,7 +2032,7 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v) /* sneaky update here, we need to sort the colorband points to be in order, * however the RNA pointer then is wrong, so we update it */ - colorband_update_sort(coba); + BKE_colorband_update_sort(coba); bt->rnapoin.data = coba->data + coba->cur; } @@ -1949,6 +2067,11 @@ static void colorband_buttons_layout( bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip the color ramp")); UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba); + + bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL); + bt->custom_data = coba; + bt->func_argN = MEM_dupallocN(cb); + UI_block_align_end(block); UI_block_emboss_set(block, UI_EMBOSS); @@ -3902,6 +4025,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs( uiLayout *col; /* needed to avoid alignment errors with previous buttons */ col = uiLayoutColumn(layout, false); + block = uiLayoutGetBlock(col); but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults")); UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); @@ -4493,7 +4617,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); - uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL); + uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!file) { return; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 8c894c7852e..a9c3f973569 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -707,6 +707,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* backdrop non AA */ if (wtb->draw_inner) { + BLI_assert(wtb->totvert != 0); if (wcol->shaded == 0) { if (wcol->alpha_check) { float inner_v_half[WIDGET_SIZE_MAX][2]; @@ -784,6 +785,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* for each AA step */ if (wtb->draw_outline) { + BLI_assert(wtb->totvert != 0); float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ @@ -2784,6 +2786,10 @@ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int if (!emboss) { round_box_edges(&wtb, roundboxalign, rect, rad); } + else { + wtb.draw_inner = false; + wtb.draw_outline = false; + } /* decoration */ if (!(state & UI_STATE_TEXT_INPUT)) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index cd90da24951..ac5fb3e40cb 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -46,10 +46,10 @@ #include "BLI_math.h" #include "BKE_appdir.h" +#include "BKE_colorband.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_main.h" -#include "BKE_texture.h" #include "BIF_gl.h" @@ -2011,7 +2011,7 @@ void init_userdef_do_versions(void) rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128); } if (U.coba_weight.tot == 0) - init_colorband(&U.coba_weight, true); + BKE_colorband_init(&U.coba_weight, true); } if (!USER_VERSION_ATLEAST(245, 3)) { bTheme *btheme; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index b271b0b5bc6..dc68c8b58de 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1509,6 +1509,9 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), v2d->smooth_timer); v2d->smooth_timer = NULL; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } else { /* ease in/out */ diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index fc227a2aa75..1b7fd319da0 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -40,6 +40,8 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" + #include "ED_screen.h" #include "ED_object.h" @@ -447,6 +449,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) min_chain_length, keep_bind_info) ) { + DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE); return OPERATOR_FINISHED; } else { diff --git a/source/blender/editors/manipulator_library/CMakeLists.txt b/source/blender/editors/manipulator_library/CMakeLists.txt index 9f7df8c6425..86e1bb3b6d7 100644 --- a/source/blender/editors/manipulator_library/CMakeLists.txt +++ b/source/blender/editors/manipulator_library/CMakeLists.txt @@ -47,6 +47,7 @@ set(SRC geometry/geom_dial_manipulator.c manipulator_types/arrow2d_manipulator.c manipulator_types/arrow3d_manipulator.c + manipulator_types/button2d_manipulator.c manipulator_types/cage2d_manipulator.c manipulator_types/cage3d_manipulator.c manipulator_types/dial3d_manipulator.c diff --git a/source/blender/editors/manipulator_library/manipulator_library_utils.c b/source/blender/editors/manipulator_library/manipulator_library_utils.c index 38b518b1992..12f9d1b48d3 100644 --- a/source/blender/editors/manipulator_library/manipulator_library_utils.c +++ b/source/blender/editors/manipulator_library/manipulator_library_utils.c @@ -195,7 +195,7 @@ bool manipulator_window_project_2d( float ray_origin[3], ray_direction[3]; - if (ED_view3d_win_to_ray(ar, v3d, mval, ray_origin, ray_direction, false)) { + if (ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, mval, ray_origin, ray_direction, false)) { float lambda; if (isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, true)) { float co[3]; diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c index e9760e3e270..cc8fd72aa03 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c @@ -236,90 +236,65 @@ static int manipulator_arrow_modal( { ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; ManipulatorInteraction *inter = mpr->interaction_data; + View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; - float orig_origin[4]; - float viewvec[3], tangent[3], plane[3]; - float offset[4]; - float m_diff[2]; - float dir_2d[2], dir2d_final[2]; + float offset[3]; float facdir = 1.0f; - bool use_vertical = false; + /* (src, dst) */ + struct { + float mval[2]; + float ray_origin[3], ray_direction[3]; + float location[3]; + } proj[2] = { + {.mval = {UNPACK2(inter->init_mval)}}, + {.mval = {UNPACK2(event->mval)}}, + }; - copy_v3_v3(orig_origin, inter->init_matrix_basis[3]); - orig_origin[3] = 1.0f; - add_v3_v3v3(offset, orig_origin, arrow->manipulator.matrix_basis[2]); - offset[3] = 1.0f; - - /* calculate view vector */ - if (rv3d->is_persp) { - sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]); - } - else { - copy_v3_v3(viewvec, rv3d->viewinv[2]); - } - normalize_v3(viewvec); - - /* first determine if view vector is really close to the direction. If it is, we use - * vertical movement to determine offset, just like transform system does */ - if (RAD2DEGF(acosf(dot_v3v3(viewvec, arrow->manipulator.matrix_basis[2]))) > 5.0f) { - /* multiply to projection space */ - mul_m4_v4(rv3d->persmat, orig_origin); - mul_v4_fl(orig_origin, 1.0f / orig_origin[3]); - mul_m4_v4(rv3d->persmat, offset); - mul_v4_fl(offset, 1.0f / offset[3]); - - sub_v2_v2v2(dir_2d, offset, orig_origin); - dir_2d[0] *= ar->winx; - dir_2d[1] *= ar->winy; - normalize_v2(dir_2d); - } - else { - dir_2d[0] = 0.0f; - dir_2d[1] = 1.0f; - use_vertical = true; - } - - /* find mouse difference */ - m_diff[0] = event->mval[0] - inter->init_mval[0]; - m_diff[1] = event->mval[1] - inter->init_mval[1]; - - /* project the displacement on the screen space arrow direction */ - project_v2_v2v2(dir2d_final, m_diff, dir_2d); + float arrow_co[3]; + float arrow_no[3]; + copy_v3_v3(arrow_co, inter->init_matrix_basis[3]); + normalize_v3_v3(arrow_no, arrow->manipulator.matrix_basis[2]); + + int ok = 0; + + for (int j = 0; j < 2; j++) { + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + ar, v3d, proj[j].mval, + proj[j].ray_origin, proj[j].ray_direction, false)) + { + /* Force Y axis if we're view aligned */ + if (j == 0) { + if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->manipulator.matrix_basis[2]))) < 5.0f) { + normalize_v3_v3(arrow_no, rv3d->viewinv[1]); + } + } - float zfac = ED_view3d_calc_zfac(rv3d, orig_origin, NULL); - ED_view3d_win_to_delta(ar, dir2d_final, offset, zfac); + float arrow_no_proj[3]; + project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction); - add_v3_v3v3(orig_origin, offset, inter->init_matrix_basis[3]); + normalize_v3(arrow_no_proj); - /* calculate view vector for the new position */ - if (rv3d->is_persp) { - sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]); - } - else { - copy_v3_v3(viewvec, rv3d->viewinv[2]); - } + float plane[4]; + plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj); - normalize_v3(viewvec); - if (!use_vertical) { - /* now find a plane parallel to the view vector so we can intersect with the arrow direction */ - cross_v3_v3v3(tangent, viewvec, offset); - cross_v3_v3v3(plane, tangent, viewvec); - - const float plane_offset = dot_v3v3(plane, offset); - const float plane_dir = dot_v3v3(plane, arrow->manipulator.matrix_basis[2]); - const float fac = (plane_dir != 0.0f) ? (plane_offset / plane_dir) : 0.0f; - facdir = (fac < 0.0f) ? -1.0f : 1.0f; - if (isfinite(fac)) { - mul_v3_v3fl(offset, arrow->manipulator.matrix_basis[2], fac); + float lambda; + if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) { + madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda); + ok++; + } } } - else { - facdir = (m_diff[1] < 0.0f) ? -1.0f : 1.0f; + + if (ok != 2) { + return OPERATOR_RUNNING_MODAL; } + sub_v3_v3v3(offset, proj[1].location, proj[0].location); + facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1; ManipulatorCommonData *data = &arrow->data; const float ofs_new = facdir * len_v3(offset); diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c new file mode 100644 index 00000000000..7e57b48c77c --- /dev/null +++ b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c @@ -0,0 +1,262 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file button2d_manipulator.c + * \ingroup wm + * + * \name Button Manipulator + * + * 2D Manipulator, also works in 3D views. + * + * \brief Single click button action for use in manipulator groups. + * + * \note Currently only basic icon & vector-shape buttons are supported. + * + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_select.h" +#include "GPU_batch.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_manipulator_library.h" + +#include "UI_interface_icons.h" +#include "UI_resources.h" + +/* own includes */ +#include "../manipulator_geometry.h" +#include "../manipulator_library_intern.h" + +typedef struct ButtonManipulator2D { + wmManipulator manipulator; + bool is_init; + /* Use an icon or shape */ + int icon; + Gwn_Batch *shape_batch[2]; +} ButtonManipulator2D; + +#define CIRCLE_RESOLUTION 32 + +/* -------------------------------------------------------------------- */ + +static void button2d_geom_draw_backdrop( + const wmManipulator *mpr, const float color[4], const bool select) +{ + glLineWidth(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + /* TODO, other draw styles */ + imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION); + + immUnbindProgram(); + + UNUSED_VARS(select); +} + +static void button2d_draw_intern( + const bContext *UNUSED(C), wmManipulator *mpr, + const bool select, const bool highlight) +{ + ButtonManipulator2D *button = (ButtonManipulator2D *)mpr; + + if (button->is_init == false) { + button->is_init = true; + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "icon"); + if (RNA_property_is_set(mpr->ptr, prop)) { + button->icon = RNA_property_enum_get(mpr->ptr, prop); + } + else { + prop = RNA_struct_find_property(mpr->ptr, "shape"); + const uint polys_len = RNA_property_string_length(mpr->ptr, prop); + /* We shouldn't need the +1, but a NULL char is set. */ + char *polys = MEM_mallocN(polys_len + 1, __func__); + RNA_property_string_get(mpr->ptr, prop, polys); + button->shape_batch[0] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + button->shape_batch[1] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + MEM_freeN(polys); + } + } + + float color[4]; + float matrix_final[4][4]; + + manipulator_color_get(mpr, highlight, color); + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + glEnable(GL_BLEND); + + if (select == false) { + if (button->shape_batch[0] != NULL) { + glEnable(GL_LINE_SMOOTH); + glLineWidth(1.0f); + for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) { + /* Invert line color for wire. */ + color[0] = 1.0f - color[0]; + color[1] = 1.0f - color[1]; + color[2] = 1.0f - color[2]; + + GWN_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR); + GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color)); + GWN_batch_draw(button->shape_batch[i]); + } + glDisable(GL_LINE_SMOOTH); + gpuPopMatrix(); + } + else if (button->icon != ICON_NONE) { + button2d_geom_draw_backdrop(mpr, color, select); + gpuPopMatrix(); + UI_icon_draw( + mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * U.ui_scale, + mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * U.ui_scale, + button->icon); + } + else { + gpuPopMatrix(); + } + } + glDisable(GL_BLEND); +} + +static void manipulator_button2d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + GPU_select_load_id(select_id); + button2d_draw_intern(C, mpr, true, false); +} + +static void manipulator_button2d_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + glEnable(GL_BLEND); + button2d_draw_intern(C, mpr, false, is_highlight); + glDisable(GL_BLEND); +} + +static int manipulator_button2d_test_select( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2]; + + if (0) { + /* correct, but unnecessarily slow. */ + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) + { + return -1; + } + } + else { + copy_v2_v2(point_local, (float [2]){UNPACK2(event->mval)}); + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); + } + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_button2d_cursor_get(wmManipulator *mpr) +{ + if (RNA_boolean_get(mpr->ptr, "show_drag")) { + return BC_NSEW_SCROLLCURSOR; + } + return CURSOR_STD; +} + +static void manipulator_button2d_free(wmManipulator *mpr) +{ + ButtonManipulator2D *shape = (ButtonManipulator2D *)mpr; + + for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) { + GWN_BATCH_DISCARD_SAFE(shape->shape_batch[i]); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Button Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_button_2d"; + + /* api callbacks */ + wt->draw = manipulator_button2d_draw; + wt->draw_select = manipulator_button2d_draw_select; + wt->test_select = manipulator_button2d_test_select; + wt->cursor_get = manipulator_button2d_cursor_get; + wt->free = manipulator_button2d_free; + + wt->struct_size = sizeof(ButtonManipulator2D); + + /* rna */ + PropertyRNA *prop; + prop = RNA_def_property(wt->srna, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_icon_items); + + /* Passed to 'GPU_batch_from_poly_2d_encoded' */ + RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING); + + /* Currently only used for cursor display. */ + RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", ""); +} + +void ED_manipulatortypes_button_2d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_button_2d); +} + +/** \} */ // Button Manipulator API diff --git a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c index f2f5851ff0c..2991c972f6e 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c @@ -191,6 +191,7 @@ static void dial_ghostarc_draw( } static void dial_ghostarc_get_angles( + const struct Depsgraph *depsgraph, const wmManipulator *mpr, const wmEvent *event, const ARegion *ar, const View3D *v3d, @@ -218,7 +219,7 @@ static void dial_ghostarc_get_angles( plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec); - if (!ED_view3d_win_to_ray(ar, v3d, inter->init_mval, ray_co, ray_no, false) || + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, inter->init_mval, ray_co, ray_no, false) || !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) { goto fail; @@ -226,7 +227,7 @@ static void dial_ghostarc_get_angles( madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda); sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]); - if (!ED_view3d_win_to_ray(ar, v3d, mval, ray_co, ray_no, false) || + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, mval, ray_co, ray_no, false) || !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) { goto fail; @@ -396,6 +397,7 @@ static int manipulator_dial_modal( dial_calc_matrix(mpr, matrix); dial_ghostarc_get_angles( + CTX_data_depsgraph(C), mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta); DialInteraction *inter = mpr->interaction_data; diff --git a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c index 151e173e5e6..4e62c9c396e 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c @@ -302,7 +302,8 @@ static int manipulator_grab_test_select( return -1; } - if (len_squared_v2(point_local) < SQUARE(mpr->scale_final)) { + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { return 0; } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 77772cfc8cc..a21fc2fffde 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -60,30 +60,35 @@ /* ********* add primitive operators ************* */ +typedef struct MakePrimitiveData { + float mat[4][4]; + bool was_editmode; +} MakePrimitiveData; + static Object *make_prim_init(bContext *C, const char *idname, - float *dia, float mat[4][4], - bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer) + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); - *was_editmode = false; + r_creation_data->was_editmode = false; if (obedit == NULL || obedit->type != OB_MESH) { obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer); /* create editmode */ ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - *was_editmode = true; + r_creation_data->was_editmode = true; } - *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); return obedit; } -static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int enter_editmode) +static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool exit_editmode = ((was_editmode == true) && (enter_editmode == false)); + const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false)); /* Primitive has all verts selected, use vert select flush * to push this up to edges & faces. */ @@ -101,17 +106,17 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int static int add_primitive_plane_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -121,12 +126,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", - 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + 1, 1, RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -152,17 +157,17 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) static int add_primitive_cube_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -172,13 +177,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_cube matrix=%m4 size=%f calc_uvs=%b", - mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) + creation_data.mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) { return OPERATOR_CANCELLED; } /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -210,13 +215,13 @@ static const EnumPropertyItem fill_type_items[] = { static int add_primitive_circle_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; int cap_end, cap_tri; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); cap_end = RNA_enum_get(op->ptr, "fill_type"); @@ -224,7 +229,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -235,12 +240,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, mat, calc_uvs)) + cap_end, cap_tri, creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -270,12 +275,12 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -283,7 +288,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -297,12 +302,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) RNA_float_get(op->ptr, "radius"), RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -333,12 +338,12 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) static int add_primitive_cone_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -346,7 +351,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -357,12 +362,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), - RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), + creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -394,17 +400,17 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) static int add_primitive_grid_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -416,12 +422,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "x_subdivisions"), RNA_int_get(op->ptr, "y_subdivisions"), - RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -453,22 +459,21 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float mat[4][4]; float loc[3], rot[3]; float dia; bool enter_editmode; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, layer, &creation_data); dia = RNA_float_get(op->ptr, "radius"); - mul_mat3_m4_fl(mat, dia); + mul_mat3_m4_fl(creation_data.mat, dia); em = BKE_editmesh_from_object(obedit); @@ -478,12 +483,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs)) + "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -510,17 +515,17 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -531,12 +536,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -566,17 +571,17 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -587,12 +592,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index afe52ec69f4..6fd4203e085 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -373,10 +373,12 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: case PADENTER: case RETKEY: - edbm_inset_calc(op); - edbm_inset_exit(C, op); - return OPERATOR_FINISHED; - + if (event->val == KM_PRESS) { + edbm_inset_calc(op); + edbm_inset_exit(C, op); + return OPERATOR_FINISHED; + } + break; case LEFTSHIFTKEY: case RIGHTSHIFTKEY: if (event->val == KM_PRESS) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index c0501078424..5d5e54edf56 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1562,8 +1562,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } /* unproject screen line */ - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true); - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s2, v2, v4, true); + ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true); + ED_view3d_win_to_segment(kcd->eval_ctx.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true); mul_m4_v3(kcd->ob->imat, v1); mul_m4_v3(kcd->ob->imat, v2); @@ -2519,7 +2519,8 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd) mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); normalize_v3(kcd->proj_zaxis); - kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d, + kcd->is_ortho = ED_view3d_clip_range_get(kcd->eval_ctx.depsgraph, + kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); } diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 3ab56f2ebcb..793e5609d31 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -762,7 +762,15 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) handled = true; break; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - if (!has_numinput) { + + /* This is normally disabled for all modal operators. + * This is an exception since mouse movement doesn't relate to numeric input. + * + * If numeric input changes we'll need to add this back see: D2973 */ +#if 0 + if (!has_numinput) +#endif + { lcd->vc.mval[0] = event->mval[0]; lcd->vc.mval[1] = event->mval[1]; loopcut_mouse_move(&eval_ctx, lcd, (int)lcd->cuts); diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index f398f087da9..dff501ece13 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -416,6 +416,7 @@ static BMElem *edbm_hover_preselect( BMElem *ele_best = NULL; if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), vc.ar, vc.v3d, mval_fl, ray_origin, ray_direction, true)) { diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 1a2f9fdb62b..0c8bd560bb2 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -590,7 +590,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve } } - if (e_best && (is_manifold_region == false)) { + if (e_best && e_best->l && (is_manifold_region == false)) { /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next; BMVert *v_new; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 27fe93b049a..a52f12ec055 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -398,7 +398,7 @@ void EDBM_mesh_load(Object *ob) * of freed data on scene update, especially in cases when there are dependency * cycles. */ - /* +#if 0 for (Object *other_object = G.main->object.first; other_object != NULL; other_object = other_object->id.next) @@ -407,7 +407,7 @@ void EDBM_mesh_load(Object *ob) BKE_object_free_derived_caches(other_object); } } - */ +#endif } /** @@ -1392,7 +1392,9 @@ static void scale_point(float c1[3], const float p[3], const float s) add_v3_v3(c1, p); } -bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit) +bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, + const struct Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, Object *obedit) { BMFace *f; float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3]; @@ -1402,7 +1404,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v const float mval_f[2] = {ar->winx / 2.0f, ar->winy / 2.0f}; - ED_view3d_win_to_segment(ar, v3d, mval_f, origin, end, false); + ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); invert_m4_m4(invmat, obedit->obmat); mul_m4_v3(invmat, origin); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index d7e59a05772..bd2ad21d51c 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -75,7 +75,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, DerivedMesh *dm; Scene *scene = CTX_data_scene(C); EvaluationContext eval_ctx; - LinkNode *dms = NULL; + LinkNodePair dms_pair = {NULL, NULL}; int nverts, ntris, *tris; float *verts; @@ -90,7 +90,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, ob = (Object *) oblink->link; dm = mesh_create_derived_no_virtual(&eval_ctx, scene, ob, NULL, CD_MASK_MESH); DM_ensure_tessface(dm); - BLI_linklist_prepend(&dms, dm); + BLI_linklist_append(&dms_pair, dm); nverts += dm->getNumVerts(dm); nfaces = dm->getNumTessFaces(dm); @@ -106,6 +106,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, *r_lay |= ob->lay; } + LinkNode *dms = dms_pair.list; /* create data */ verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts"); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index e8807432328..5c96c13ebed 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -92,7 +92,6 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_speaker.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -1101,6 +1100,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) /* works without this except if you try render right after, see: 22027 */ DEG_relations_tag_update(bmain); + DEG_id_tag_update(&group->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -2086,7 +2086,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer #define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } #define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } - Base *basen = NULL; + Base *base, *basen = NULL; Material ***matarar; Object *obn; ID *id; @@ -2099,7 +2099,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - BKE_collection_object_add_from(scene, ob, obn); + base = BKE_view_layer_base_find(view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLED)) { + BKE_collection_object_add_from(scene, ob, obn); + } + else { + LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer); + BKE_collection_object_add(&scene->id, layer_collection->scene_collection, obn); + } basen = BKE_view_layer_base_find(view_layer, obn); /* 1) duplis should end up in same group as the original @@ -2449,13 +2456,13 @@ static int add_named_exec(bContext *C, wmOperator *op) clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag); - BKE_scene_object_base_flag_sync_from_object(basen); if (basen == NULL) { BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated"); return OPERATOR_CANCELLED; } + BKE_scene_object_base_flag_sync_from_object(basen); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2473,9 +2480,11 @@ static int add_named_exec(bContext *C, wmOperator *op) BKE_main_id_clear_newpoins(bmain); + /* TODO(sergey): Only update relations for the current scene. */ DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_OB_ACTIVE, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index c38a7d58904..03aacc86ea7 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -68,7 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); -void OBJECT_OT_make_override(struct wmOperatorType *ot); +void OBJECT_OT_make_override_static(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index ceea3b9c0ac..9c321f5cb79 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -84,7 +84,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_slow_parent_set); WM_operatortype_append(OBJECT_OT_slow_parent_clear); WM_operatortype_append(OBJECT_OT_make_local); - WM_operatortype_append(OBJECT_OT_make_override); + WM_operatortype_append(OBJECT_OT_make_override_static); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 436364ec6c3..d73e3aabaf0 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1678,9 +1678,6 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen } } - /* we reset filter objects because they should be regenerated after this */ - BLI_freelistN(&sc->filter_objects); - for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { single_object_users_scene_collection(bmain, scene, nsc, flag, copy_groups); } @@ -1740,9 +1737,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in libblock_relink_scene_collection(msc); set_sca_new_poins(); - - /* TODO redo filter */ - TODO_LAYER_SYNC_FILTER } /* not an especially efficient function, only added so the single user @@ -2335,42 +2329,194 @@ void OBJECT_OT_make_local(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } -static int make_override_exec(bContext *C, wmOperator *UNUSED(op)) + +static void make_override_static_tag_object(Object *obact, Object *ob) +{ + if (ob == obact) { + return; + } + + if (!ID_IS_LINKED(ob)) { + return; + } + + /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full 'automatic', generic + * handling of all this, will probably require adding some override-aware stuff to library_query code... */ + + if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) { + for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object == obact) { + ob->id.tag |= LIB_TAG_DOIT; + break; + } + } + } + } + else if (ob->parent == obact) { + ob->id.tag |= LIB_TAG_DOIT; + } + + if (ob->id.tag & LIB_TAG_DOIT) { + printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name); + } +} + +/* Set the object to override. */ +static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + Object *obact = ED_object_active_context(C); + + /* Sanity checks. */ + if (!scene || ID_IS_LINKED(scene) || !obact) { + return OPERATOR_CANCELLED; + } + + /* Get object to work on - use a menu if we need to... */ + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { + /* Gives menu with list of objects in group. */ + WM_enum_search_invoke(C, op, event); + return OPERATOR_CANCELLED; + } + else if (ID_IS_LINKED(obact)) { + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* Create operator menu item with relevant properties filled in. */ + PointerRNA opptr_dummy; + uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, + WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy); + + /* Present the menu and be done... */ + UI_popup_menu_end(C, pup); + + /* This invoke just calls another instance of this operator... */ + return OPERATOR_INTERFACE; + } + else { + /* Error.. cannot continue. */ + BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or group"); + return OPERATOR_CANCELLED; + } + +} + +static int make_override_static_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Object *locobj, *refobj = CTX_data_active_object(C); + Object *obact = CTX_data_active_object(C); + + bool success = false; + + if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) { +#if 0 /* Not working yet! */ + Base *base = BLI_findlink(&obact->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); + Object *obgroup = obact; + obact = base->object; + + /* First, we make a static override of the linked group itself. */ + obgroup->dup_group->id.tag |= LIB_TAG_DOIT; + + /* Then, we tag our 'main' object and its detected dependencies to be also overridden. */ + obact->id.tag |= LIB_TAG_DOIT; + + FOREACH_GROUP_OBJECT(obgroup->dup_group, ob) + { + make_override_tag_object(obact, ob); + } + FOREACH_GROUP_OBJECT_END; + + success = BKE_override_static_create_from_tag(bmain); + + /* Intantiate our 'main' newly overridden object in scene, if not yet done. */ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *new_obact = (Object *)obact->id.newid; + if (new_obact != NULL && (base = BKE_view_layer_base_find(view_layer, new_obact)) == NULL) { + BKE_collection_object_add_from(scene, obact, new_obact); + base = BKE_view_layer_base_find(view_layer, new_obact); + BKE_view_layer_base_select(view_layer, base); + } + + /* Parent the group instantiating object to the new overridden one, or vice-versa, if possible. */ + if (obgroup->parent == NULL) { + obgroup->parent = new_obact; + } + else if (new_obact->parent == NULL) { + new_obact->parent = obgroup; + } + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); +#else + UNUSED_VARS(op); +#endif + } + /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */ + else if (obact->type == OB_ARMATURE) { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id); - UNUSED_VARS(locobj); + obact->id.tag |= LIB_TAG_DOIT; + + for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) { + make_override_static_tag_object(obact, ob); + } + + success = BKE_override_static_create_from_tag(bmain); + + /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */ + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false); + } + /* TODO: probably more cases where we want ot do automated smart things in the future! */ + else { + success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL); + } WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } -static int make_override_poll(bContext *C) +static int make_override_static_poll(bContext *C) { Object *obact = CTX_data_active_object(C); /* Object must be directly linked to be overridable. */ - return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN); + return (ED_operator_objectmode(C) && obact != NULL && + ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) || + (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)))); } -void OBJECT_OT_make_override(wmOperatorType *ot) +void OBJECT_OT_make_override_static(wmOperatorType *ot) { /* identifiers */ - ot->name = "Make Override"; + ot->name = "Make Static Override"; ot->description = "Make local override of this library linked data-block"; - ot->idname = "OBJECT_OT_make_override"; + ot->idname = "OBJECT_OT_make_override_static"; /* api callbacks */ - ot->exec = make_override_exec; - ot->poll = make_override_poll; + ot->invoke = make_override_static_invoke; + ot->exec = make_override_static_exec; + ot->poll = make_override_static_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", + "Name of lib-linked/grouped object to make a proxy for"); + RNA_def_enum_funcs(prop, proxy_group_object_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } enum { diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 552380cebdb..b20fe9a004c 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -625,9 +625,9 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob) for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Hook) { hmd = (HookModifierData *) md; - if (hmd->object && !(hmd->object->flag & SELECT)) { + if (hmd->object) { base = BKE_view_layer_base_find(view_layer, hmd->object); - if (base && (BASE_SELECTABLE(base))) { + if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(base))) { ED_object_base_select(base, BA_SELECT); changed = true; } @@ -1107,12 +1107,12 @@ static bool object_select_more_less(bContext *C, const bool select) bool changed = false; const short select_mode = select ? BA_SELECT : BA_DESELECT; - const short select_flag = select ? SELECT : 0; + const short select_flag = select ? BASE_SELECTED : 0; for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) { Base *base = ctx_base->ptr.data; Object *ob = base->object; - if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) { + if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) { ED_object_base_select(base, select_mode); changed = true; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 53bc289d378..89dd46681cb 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3517,6 +3517,7 @@ static int particle_intersect_dm(const bContext *C, Scene *scene, Object *ob, De static int brush_add(const bContext *C, PEData *data, short number) { EvaluationContext eval_ctx; + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene= data->scene; Object *ob= data->ob; DerivedMesh *dm; @@ -3580,7 +3581,7 @@ static int brush_add(const bContext *C, PEData *data, short number) mco[0] = data->mval[0] + dmx; mco[1] = data->mval[1] + dmy; - ED_view3d_win_to_segment(data->vc.ar, data->vc.v3d, mco, co1, co2, true); + ED_view3d_win_to_segment(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true); mul_m4_v3(imat, co1); mul_m4_v3(imat, co2); diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 4fee14dc71d..1536c15525f 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -200,7 +200,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op)) if (psys->part) part= BKE_particlesettings_copy(bmain, psys->part); else - part= psys_new_settings("ParticleSettings", bmain); + part= BKE_particlesettings_add(bmain, "ParticleSettings"); ob= ptr.id.data; diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 4e75ca3e6f1..3be890f2c36 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -295,6 +295,7 @@ static void screen_render_view_layer_set(wmOperator *op, Main *mainp, Scene **sc static int screen_render_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = NULL; Depsgraph *depsgraph = CTX_data_depsgraph(C); Render *re; @@ -306,6 +307,11 @@ static int screen_render_exec(bContext *C, wmOperator *op) const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + /* custom scene and single layer re-render */ screen_render_view_layer_set(op, mainp, &scene, &view_layer); @@ -844,6 +850,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *mainp; ViewLayer *view_layer = NULL; Scene *scene = CTX_data_scene(C); + RenderEngineType *re_type = RE_engines_find(scene->view_render.engine_id); Render *re; wmJob *wm_job; RenderJob *rj; @@ -856,6 +863,18 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; ScrArea *sa; + + /* Cannot do render if there is not this function. */ + if (re_type->render_to_image == NULL) { + return OPERATOR_CANCELLED; + } + + /* XXX FIXME If engine is an OpenGL engine do not run modal. + * This is a problem for animation rendering since you cannot abort them. + * This also does not open an image editor space. */ + if (RE_engine_is_opengl(re_type)) { + return screen_render_exec(C, op); + } /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) @@ -1067,6 +1086,7 @@ typedef struct RenderPreview { wmJob *job; Scene *scene; + Depsgraph *depsgraph; ScrArea *sa; ARegion *ar; View3D *v3d; @@ -1081,7 +1101,8 @@ typedef struct RenderPreview { bool has_freestyle; } RenderPreview; -static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) +static int render_view3d_disprect(Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) { /* copied code from view3d_draw.c */ rctf viewborder; @@ -1094,7 +1115,7 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region if (draw_border) { if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); disprect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); disprect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); @@ -1116,13 +1137,15 @@ static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, Region } /* returns true if OK */ -static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine, - float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho) +static bool render_view3d_get_rects( + const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine, + float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho) { if (ar->winx < 4 || ar->winy < 4) return false; - *r_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize); + *r_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize); engine->resolution_x = ar->winx; engine->resolution_y = ar->winy; @@ -1229,7 +1252,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda G.is_break = false; - if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth)) + if (false == render_view3d_get_rects(rp->depsgraph, rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth)) return; rp->stop = stop; @@ -1262,8 +1285,9 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda } } - use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d, - rp->rv3d, &cliprct); + use_border = render_view3d_disprect(rp->scene, rp->depsgraph, + rp->ar, rp->v3d, rp->rv3d, + &cliprct); if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) { RenderData rdata; @@ -1386,6 +1410,7 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Render *re; rctf viewplane; rcti disprect; @@ -1435,14 +1460,14 @@ static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C) job_update_flag |= PR_UPDATE_VIEW; } - render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); + render_view3d_get_rects(depsgraph, ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth); if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) { engine->last_viewplane = viewplane; job_update_flag |= PR_UPDATE_VIEW; } - render_view3d_disprect(scene, ar, v3d, rv3d, &disprect); + render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &disprect); if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) { engine->last_disprect = disprect; job_update_flag |= PR_UPDATE_RENDERSIZE; @@ -1462,6 +1487,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); int width = ar->winx, height = ar->winy; int divider = BKE_render_preview_pixel_size(&scene->r); @@ -1486,6 +1512,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) /* customdata for preview thread */ rp->scene = scene; + rp->depsgraph = depsgraph; rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); @@ -1543,6 +1570,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) RegionView3D *rv3d = CTX_wm_region_view3d(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ARegion *ar = CTX_wm_region(C); bool force_fallback = false; bool need_fallback = true; @@ -1551,7 +1579,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) rcti clip_rect; int xof, yof; - if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) { + if (render_view3d_disprect(scene, depsgraph, ar, v3d, rv3d, &clip_rect)) { scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx; scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty; xof = clip_rect.xmin; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 3c63aed9473..6e969067985 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -279,7 +279,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R const short view_context = (v3d != NULL); bool draw_bgpic = true; bool draw_sky = (scene->r.alphamode == R_ADDSKY); - unsigned char *rect = NULL; + float *rectf = NULL; const char *viewname = RE_GetActiveRenderView(oglrender->re); ImBuf *ibuf_result = NULL; EvaluationContext eval_ctx; @@ -360,7 +360,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ibuf_view = ED_view3d_draw_offscreen_imbuf( &eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, - IB_rect, draw_flags, alpha_mode, oglrender->ofs_samples, viewname, + IB_rectfloat, draw_flags, alpha_mode, oglrender->ofs_samples, viewname, oglrender->fx, oglrender->ofs, err_out); /* for stamp only */ @@ -372,7 +372,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R draw_flags |= (V3D_OFSDRAW_USE_GPENCIL | V3D_OFSDRAW_USE_BACKGROUND); ibuf_view = ED_view3d_draw_offscreen_imbuf_simple( &eval_ctx, scene, view_layer, scene->camera, oglrender->sizex, oglrender->sizey, - IB_rect, draw_flags, OB_SOLID, + IB_rectfloat, draw_flags, OB_SOLID, alpha_mode, oglrender->ofs_samples, viewname, oglrender->fx, oglrender->ofs, err_out); camera = scene->camera; @@ -380,7 +380,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_view) { ibuf_result = ibuf_view; - rect = (unsigned char *)ibuf_view->rect; + rectf = (float *)ibuf_view->rect_float; } else { fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); @@ -389,7 +389,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (ibuf_result != NULL) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { - BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4); + BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); @@ -652,7 +652,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 47794e0e357..2e3091268a9 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -313,11 +313,10 @@ static void set_preview_layer(ViewLayer *view_layer, char pr_type) for (lc = view_layer->layer_collections.first; lc; lc = lc->next) { if (STREQ(lc->scene_collection->name, collection_name)) { - lc->flag = COLLECTION_VISIBLE | COLLECTION_DISABLED; - BKE_collection_enable(view_layer, lc); + lc->flag = COLLECTION_VIEWPORT | COLLECTION_RENDER; } else { - BKE_collection_disable(view_layer, lc); + lc->flag = COLLECTION_DISABLED; } } } @@ -330,7 +329,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) if (sp->worldcopy != NULL) { return sp->worldcopy; } - sp->worldcopy = localize_world(world); + sp->worldcopy = BKE_world_localize(world); BLI_addtail(&sp->pr_main->world, sp->worldcopy); return sp->worldcopy; } @@ -396,7 +395,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty if (origmat) { /* work on a copy */ - mat = localize_material(origmat); + mat = BKE_material_localize(origmat); sp->matcopy = mat; BLI_addtail(&pr_main->mat, mat); @@ -551,7 +550,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty /* work on a copy */ if (origla) { - la = localize_lamp(origla); + la = BKE_lamp_localize(origla); sp->lampcopy = la; BLI_addtail(&pr_main->lamp, la); } @@ -589,7 +588,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty World *wrld = NULL, *origwrld = (World *)id; if (origwrld) { - wrld = localize_world(origwrld); + wrld = BKE_world_localize(origwrld); sp->worldcopy = wrld; BLI_addtail(&pr_main->world, wrld); } @@ -722,7 +721,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r if (ok) *rect = newrect; - /* start a new preview render job if signalled through sbuts->preview, + /* start a new preview render job if signaled through sbuts->preview, * if no render result was found and no preview render job is running, * or if the job is running and the size of preview changed */ if ((sbuts != NULL && sbuts->preview) || diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 04604feab6a..270ba2a7947 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -427,7 +427,8 @@ static int material_slot_move_exec(bContext *C, wmOperator *op) MEM_freeN(slot_remap); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob); return OPERATOR_FINISHED; } @@ -582,7 +583,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) wo = BKE_world_copy(bmain, wo); } else { - wo = add_world(bmain, DATA_("World")); + wo = BKE_world_add(bmain, DATA_("World")); if (BKE_scene_use_new_shading_nodes(scene)) { ED_node_shader_default(C, &wo->id); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index a391b13a000..4943222f038 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -153,6 +153,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update DRW_notify_view_update( (&(DRWUpdateContext){ .bmain = bmain, + .depsgraph = update_ctx->depsgraph, .scene = scene, .view_layer = view_layer, .ar = ar, @@ -201,7 +202,9 @@ void ED_render_engine_changed(Main *bmain) update_ctx.bmain = bmain; for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { update_ctx.scene = scene; - LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + BLI_LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + /* TDODO(sergey): Iterate over depsgraphs instead? */ + update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); update_ctx.view_layer = view_layer; ED_render_id_flush_update(&update_ctx, &scene->id); } @@ -309,7 +312,7 @@ static void material_changed(Main *bmain, Material *ma) BKE_icon_changed(BKE_icon_id_ensure(&ma->id)); /* glsl */ - if (ma->id.tag & LIB_TAG_ID_RECALC) { + if (ma->id.recalc & ID_RECALC) { if (!BLI_listbase_is_empty(&ma->gpumaterial)) { GPU_material_free(&ma->gpumaterial); } @@ -493,7 +496,7 @@ static void world_changed(Main *UNUSED(bmain), World *wo) wo->update_flag = 1; /* glsl */ - if (wo->id.tag & LIB_TAG_ID_RECALC) { + if (wo->id.recalc & ID_RECALC) { if (!BLI_listbase_is_empty(&defmaterial.gpumaterial)) { GPU_material_free(&defmaterial.gpumaterial); } @@ -539,8 +542,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) return; } Main *bmain = update_ctx->bmain; - Scene *scene = update_ctx->scene; - ViewLayer *view_layer = update_ctx->view_layer; /* Internal ID update handlers. */ switch (GS(id->name)) { case ID_MA: @@ -567,42 +568,6 @@ void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; } - /* Inform all draw managers about changes. - * - * TODO(sergey): This code is run for every updated ID, via flushing - * mechanism. How can we avoid iterating over the whole interface for - * every of those IDs? One of the ideas would be to call draw manager's - * ID update which is not bound to any of contexts. - */ - { - wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { - bScreen *sc = WM_window_get_active_screen(win); - WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); - ViewRender *view_render = BKE_viewrender_get(win->scene, workspace); - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->spacetype != SPACE_VIEW3D) { - continue; - } - for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype != RGN_TYPE_WINDOW) { - continue; - } - RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); - DRW_notify_id_update( - (&(DRWUpdateContext){ - .bmain = bmain, - .scene = scene, - .view_layer = view_layer, - .ar = ar, - .v3d = (View3D *)sa->spacedata.first, - .engine_type = engine_type - }), - id); - } - } - } - } } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index dbeac782e10..f886a6ad613 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -769,6 +769,10 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea return; } + if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) { + return; + } + /* can't click on bottom corners on OS X, already used for resizing */ #ifdef __APPLE__ if (!(sa->totrct.xmin == 0 && sa->totrct.ymin == 0) || WM_window_is_fullscreen(win)) diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 5690076fedb..2e4e9127ed6 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -33,7 +33,6 @@ #include "screen_intern.h" - /** * Draw horizontal shape visualizing future joining (left as well right direction of future joining). */ @@ -289,18 +288,15 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos } /** - * Only for edge lines between areas, and the blended join arrows. + * Only for edge lines between areas. */ -void ED_screen_draw(wmWindow *win) +void ED_screen_draw_edges(wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); ScrArea *sa; - ScrArea *sa1 = NULL; - ScrArea *sa2 = NULL; - ScrArea *sa3 = NULL; wmSubWindowSet(win, screen->mainwin); @@ -323,36 +319,47 @@ void ED_screen_draw(wmWindow *win) for (sa = screen->areabase.first; sa; sa = sa->next) { drawscredge_area(sa, winsize_x, winsize_y, pos); - - /* gather area split/join info */ - if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; - if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; - if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; } + immUnbindProgram(); + + screen->do_draw = false; +} + +/** + * The blended join arrows. + * + * \param sa1: Area from which the resultant originates. + * \param sa2: Target area that will be replaced. + */ +void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glLineWidth(1); + /* blended join arrow */ - if (sa1 && sa2) { - int dir = area_getorientation(sa1, sa2); - int dira = -1; - if (dir != -1) { - switch (dir) { - case 0: /* W */ - dir = 'r'; - dira = 'l'; - break; - case 1: /* N */ - dir = 'd'; - dira = 'u'; - break; - case 2: /* E */ - dir = 'l'; - dira = 'r'; - break; - case 3: /* S */ - dir = 'u'; - dira = 'd'; - break; - } + int dir = area_getorientation(sa1, sa2); + int dira = -1; + if (dir != -1) { + switch (dir) { + case 0: /* W */ + dir = 'r'; + dira = 'l'; + break; + case 1: /* N */ + dir = 'd'; + dira = 'u'; + break; + case 2: /* E */ + dir = 'l'; + dira = 'r'; + break; + case 3: /* S */ + dir = 'u'; + dira = 'd'; + break; } glEnable(GL_BLEND); @@ -363,48 +370,59 @@ void ED_screen_draw(wmWindow *win) glDisable(GL_BLEND); } - /* splitpoint */ - if (sa3) { - glEnable(GL_BLEND); - immUniformColor4ub(255, 255, 255, 100); + immUnbindProgram(); +} - immBegin(GWN_PRIM_LINES, 2); +void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) { - immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y); - immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y); + /* splitpoint */ + glEnable(GL_BLEND); + immUniformColor4ub(255, 255, 255, 100); - immEnd(); + immBegin(GWN_PRIM_LINES, 2); - immUniformColor4ub(0, 0, 0, 100); + if (dir == 'h') { + const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax; - immBegin(GWN_PRIM_LINES, 2); + immVertex2f(pos, sa->totrct.xmin, y); + immVertex2f(pos, sa->totrct.xmax, y); - immVertex2f(pos, sa3->totrct.xmin, win->eventstate->y + 1); - immVertex2f(pos, sa3->totrct.xmax, win->eventstate->y + 1); - } - else { - immVertex2f(pos, win->eventstate->x, sa3->totrct.ymin); - immVertex2f(pos, win->eventstate->x, sa3->totrct.ymax); + immEnd(); - immEnd(); + immUniformColor4ub(0, 0, 0, 100); - immUniformColor4ub(0, 0, 0, 100); + immBegin(GWN_PRIM_LINES, 2); - immBegin(GWN_PRIM_LINES, 2); + immVertex2f(pos, sa->totrct.xmin, y + 1); + immVertex2f(pos, sa->totrct.xmax, y + 1); - immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymin); - immVertex2f(pos, win->eventstate->x + 1, sa3->totrct.ymax); - } + immEnd(); + } + else { + BLI_assert(dir == 'v'); + const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax; + + immVertex2f(pos, x, sa->totrct.ymin); + immVertex2f(pos, x, sa->totrct.ymax); immEnd(); - glDisable(GL_BLEND); + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GWN_PRIM_LINES, 2); + + immVertex2f(pos, x + 1, sa->totrct.ymin); + immVertex2f(pos, x + 1, sa->totrct.ymax); + + immEnd(); } - immUnbindProgram(); + glDisable(GL_BLEND); - screen->do_draw = false; + immUnbindProgram(); } @@ -481,7 +499,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) { char err_out[256] = "unknown"; - GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, err_out); + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, false, err_out); GPU_offscreen_bind(offscreen, true); glClearColor(0.0, 0.0, 0.0, 0.0); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 4b5ce2f4b81..57f45bf95ce 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -426,8 +426,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) /*printf("dir is : %i\n", dir);*/ if (dir == -1) { - if (sa1) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (sa2) sa2->flag &= ~AREA_FLAG_DRAWJOINTO; return 0; } @@ -458,7 +456,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) screen_delarea(C, scr, sa2); BKE_screen_remove_double_scrverts(scr); - sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; /* Update preview thumbnail */ BKE_icon_changed(scr->id.icon_id); diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index 39c3d72af6a..9214b4b7a68 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -31,6 +31,7 @@ #ifndef __SCREEN_INTERN_H__ #define __SCREEN_INTERN_H__ +struct bContext; struct bContextDataResult; struct Main; @@ -65,7 +66,8 @@ ScrEdge *screen_find_active_scredge(const bScreen *sc, struct AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2]); /* screen_context.c */ -int ed_screen_context(const struct bContext *C, const char *member, struct bContextDataResult *result); +int ed_screen_context( + const struct bContext *C, const char *member, struct bContextDataResult *result); extern const char *screen_context_dir[]; /* doc access */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 4e8bf6ea769..09af0d86f84 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -90,10 +90,12 @@ #define KM_MODAL_CANCEL 1 #define KM_MODAL_APPLY 2 -#define KM_MODAL_STEP10 3 -#define KM_MODAL_STEP10_OFF 4 +#define KM_MODAL_SNAP_ON 3 +#define KM_MODAL_SNAP_OFF 4 -/* ************** Exported Poll tests ********************** */ +/* -------------------------------------------------------------------- */ +/** \name Public Poll API + * \{ */ int ED_operator_regionactive(bContext *C) { @@ -127,36 +129,6 @@ static int ED_operator_screenactive_norender(bContext *C) return 1; } - -static int screen_active_editable(bContext *C) -{ - if (ED_operator_screenactive(C)) { - /* no full window splitting allowed */ - if (CTX_wm_screen(C)->state != SCREENNORMAL) - return 0; - return 1; - } - return 0; -} - -static ARegion *screen_find_region_type(bContext *C, int type) -{ - ARegion *ar = CTX_wm_region(C); - - /* find the header region - * - try context first, but upon failing, search all regions in area... - */ - if ((ar == NULL) || (ar->regiontype != type)) { - ScrArea *sa = CTX_wm_area(C); - ar = BKE_area_find_region_type(sa, type); - } - else { - ar = NULL; - } - - return ar; -} - /* when mouse is over area-edge */ int ED_operator_screen_mainwinactive(bContext *C) { @@ -589,7 +561,46 @@ int ED_operator_camera(bContext *C) return (cam != NULL); } -/* *************************** action zone operator ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Screen Utilities + * \{ */ + +static int screen_active_editable(bContext *C) +{ + if (ED_operator_screenactive(C)) { + /* no full window splitting allowed */ + if (CTX_wm_screen(C)->state != SCREENNORMAL) + return 0; + return 1; + } + return 0; +} + +static ARegion *screen_find_region_type(bContext *C, int type) +{ + ARegion *ar = CTX_wm_region(C); + + /* find the header region + * - try context first, but upon failing, search all regions in area... + */ + if ((ar == NULL) || (ar->regiontype != type)) { + ScrArea *sa = CTX_wm_area(C); + ar = BKE_area_find_region_type(sa, type); + } + else { + ar = NULL; + } + + return ar; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Zone Operator + * \{ */ /* operator state vars used: * none @@ -807,8 +818,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* once we drag outside the actionzone, register a gesture * check we're not on an edge so join finds the other area */ is_gesture = ((is_in_area_actionzone(sad->sa1, &event->x) != sad->az) && - (screen_find_active_scredge(sc, screen_size_x, screen_size_y, - event->x, event->y) == NULL)); + (screen_find_active_scredge(sc, screen_size_x, screen_size_y, event->x, event->y) == NULL)); } else { const int delta_min = 1; @@ -1098,6 +1108,7 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot) typedef struct sAreaMoveData { int bigger, smaller, origval, step; char dir; + bool do_snap; } sAreaMoveData; /* helper call to move area-edge, sets limits @@ -1189,55 +1200,98 @@ static int area_move_init(bContext *C, wmOperator *op) return 1; } +static int area_snap_calc_location( + const bScreen *sc, const int delta, + const int origval, const int dir, + const int bigger, const int smaller) +{ + int final_loc = -1; + + const int m_loc = origval + delta; + const int axis = (dir == 'v') ? 0 : 1; + int snap_dist; + int dist; + { + /* Test the snap to middle. */ + int middle = origval + (bigger - smaller) / 2; + middle -= (middle % AREAGRID); + + snap_dist = abs(m_loc - middle); + final_loc = middle; + } + + for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) { + if (v1->editflag) { + const int v_loc = (&v1->vec.x)[!axis]; + + for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) { + if (!v2->editflag) { + if (v_loc == (&v2->vec.x)[!axis]) { + const int v_loc2 = (&v2->vec.x)[axis]; + /* Do not snap to the vertices at the ends. */ + if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) { + dist = abs(m_loc - v_loc2); + if (dist <= snap_dist) { + snap_dist = dist; + final_loc = v_loc2; + } + } + } + } + } + } + } + + return final_loc; +} + /* moves selected screen edge amount of delta, used by split & move */ -static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller) +static void area_move_apply_do( + const bContext *C, int delta, + const int origval, const int dir, + const int bigger, const int smaller, + const bool do_snap) { - wmWindow *win = CTX_wm_window(C); - const int screen_size_x = WM_window_screen_pixels_x(win); - const int screen_size_y = WM_window_screen_pixels_y(win); bScreen *sc = CTX_wm_screen(C); ScrVert *v1; - ScrArea *sa; - int doredraw = 0; - int oldval; - - delta = CLAMPIS(delta, -smaller, bigger); - + bool doredraw = false; + CLAMP(delta, -smaller, bigger); + + short final_loc = -1; + + if (do_snap) { + final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller); + } + else { + final_loc = origval + delta; + if (delta != bigger && delta != -smaller) { + final_loc -= (final_loc % AREAGRID); + } + } + + BLI_assert(final_loc != -1); + short axis = (dir == 'v') ? 0 : 1; + for (v1 = sc->vertbase.first; v1; v1 = v1->next) { if (v1->editflag) { - /* that way a nice AREAGRID */ - if ((dir == 'v') && v1->vec.x > 0 && v1->vec.x < screen_size_x - 1) { - oldval = v1->vec.x; - v1->vec.x = origval + delta; - - if (delta != bigger && delta != -smaller) { - v1->vec.x -= (v1->vec.x % AREAGRID); - v1->vec.x = CLAMPIS(v1->vec.x, origval - smaller, origval + bigger); - } - if (oldval != v1->vec.x) - doredraw = 1; - } - if ((dir == 'h') && v1->vec.y > 0 && v1->vec.y < screen_size_y - 1) { - oldval = v1->vec.y; - v1->vec.y = origval + delta; - - if (delta != bigger && delta != smaller) { - v1->vec.y -= (v1->vec.y % AREAGRID); - v1->vec.y = CLAMPIS(v1->vec.y, origval - smaller, origval + bigger); - } - if (oldval != v1->vec.y) - doredraw = 1; + short oldval = (&v1->vec.x)[axis]; + (&v1->vec.x)[axis] = final_loc; + + if (oldval == final_loc) { + /* nothing will change to the other vertices either. */ + break; } + doredraw = true; } } /* only redraw if we actually moved a screen vert, for AREAGRID */ if (doredraw) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) { ED_area_tag_redraw(sa); + } } - WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */ /* Update preview thumbnail */ BKE_icon_changed(sc->id.icon_id); @@ -1247,10 +1301,9 @@ static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int static void area_move_apply(bContext *C, wmOperator *op) { sAreaMoveData *md = op->customdata; - int delta; - - delta = RNA_int_get(op->ptr, "delta"); - area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller); + int delta = RNA_int_get(op->ptr, "delta"); + + area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap); } static void area_move_exit(bContext *C, wmOperator *op) @@ -1312,7 +1365,6 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) y = RNA_int_get(op->ptr, "y"); delta = (md->dir == 'v') ? event->x - x : event->y - y; - if (md->step) delta = delta - (delta % md->step); RNA_int_set(op->ptr, "delta", delta); area_move_apply(C, op); @@ -1328,12 +1380,12 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) case KM_MODAL_CANCEL: area_move_cancel(C, op); return OPERATOR_CANCELLED; - - case KM_MODAL_STEP10: - md->step = 10; + + case KM_MODAL_SNAP_ON: + md->do_snap = true; break; - case KM_MODAL_STEP10_OFF: - md->step = 0; + case KM_MODAL_SNAP_OFF: + md->do_snap = false; break; } break; @@ -1365,7 +1417,11 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -/* ************** split area operator *********************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Split Area Operator + * \{ */ /* * operator state vars: @@ -1402,13 +1458,13 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) */ typedef struct sAreaSplitData { - int x, y; /* last used mouse position */ - int origval; /* for move areas */ int bigger, smaller; /* constraints for moving new edge */ int delta; /* delta move edge */ int origmin, origsize; /* to calculate fac, for property storage */ int previewmode; /* draw previewline, then split */ + void *draw_callback; /* call `ED_screen_draw_split_preview` */ + bool do_snap; ScrEdge *nedge; /* new edge */ ScrArea *sarea; /* start area */ @@ -1416,6 +1472,19 @@ typedef struct sAreaSplitData { } sAreaSplitData; +static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata) +{ + const wmOperator *op = userdata; + + sAreaSplitData *sd = op->customdata; + if (sd->sarea) { + int dir = RNA_enum_get(op->ptr, "direction"); + float fac = RNA_float_get(op->ptr, "factor"); + + ED_screen_draw_split_preview(sd->sarea, dir, fac); + } +} + /* generic init, menu case, doesn't need active area */ static int area_split_menu_init(bContext *C, wmOperator *op) { @@ -1426,15 +1495,7 @@ static int area_split_menu_init(bContext *C, wmOperator *op) op->customdata = sd; sd->sarea = CTX_wm_area(C); - - if (sd->sarea) { - int dir = RNA_enum_get(op->ptr, "direction"); - if (dir == 'h') - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - else - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - } return 1; } @@ -1545,9 +1606,9 @@ static void area_split_exit(bContext *C, wmOperator *op) if (sd->sarea) ED_area_tag_redraw(sd->sarea); if (sd->narea) ED_area_tag_redraw(sd->narea); - if (sd->sarea) - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - + if (sd->draw_callback) + WM_draw_cb_exit(CTX_wm_window(C), sd->draw_callback); + MEM_freeN(op->customdata); op->customdata = NULL; } @@ -1560,6 +1621,12 @@ static void area_split_exit(bContext *C, wmOperator *op) BKE_screen_remove_double_scredges(CTX_wm_screen(C)); } +static void area_split_preview_update_cursor(bContext *C, wmOperator *op) +{ + wmWindow *win = CTX_wm_window(C); + int dir = RNA_enum_get(op->ptr, "direction"); + WM_cursor_set(win, (dir == 'v') ? CURSOR_X_MOVE : CURSOR_Y_MOVE); +} /* UI callback, adds new handler */ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1637,9 +1704,6 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) sd = (sAreaSplitData *)op->customdata; - sd->x = event->x; - sd->y = event->y; - if (event->type == EVT_ACTIONZONE_AREA) { /* do the split */ @@ -1654,9 +1718,11 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { sd->previewmode = 1; + sd->draw_callback = WM_draw_cb_activate(win, area_split_draw_cb, op); /* add temp handler for edge move or cancel */ WM_event_add_modal_handler(C, op); - + area_split_preview_update_cursor(C, op); + return OPERATOR_RUNNING_MODAL; } @@ -1699,48 +1765,15 @@ static void area_split_cancel(bContext *C, wmOperator *op) static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) { sAreaSplitData *sd = (sAreaSplitData *)op->customdata; - float fac; - int dir; - + PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction"); + bool update_factor = false; + /* execute the events */ switch (event->type) { case MOUSEMOVE: - dir = RNA_enum_get(op->ptr, "direction"); - - sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; - if (sd->previewmode == 0) - area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller); - else { - if (sd->sarea) { - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - ED_area_tag_redraw(sd->sarea); - } - /* area context not set */ - sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); - - if (sd->sarea) { - ED_area_tag_redraw(sd->sarea); - if (dir == 'v') { - sd->origsize = sd->sarea->winx; - sd->origmin = sd->sarea->totrct.xmin; - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - } - else { - sd->origsize = sd->sarea->winy; - sd->origmin = sd->sarea->totrct.ymin; - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - } - } - - CTX_wm_screen(C)->do_draw = true; - - } - - fac = (dir == 'v') ? event->x - sd->origmin : event->y - sd->origmin; - RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize); - + update_factor = true; break; - + case LEFTMOUSE: if (sd->previewmode) { area_split_apply(C, op); @@ -1758,27 +1791,15 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) case MIDDLEMOUSE: case TABKEY: if (sd->previewmode == 0) { + /* pass */ } else { - dir = RNA_enum_get(op->ptr, "direction"); - if (event->val == KM_PRESS) { if (sd->sarea) { - sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); - ED_area_tag_redraw(sd->sarea); - - if (dir == 'v') { - RNA_enum_set(op->ptr, "direction", 'h'); - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H; - - WM_cursor_set(CTX_wm_window(C), CURSOR_X_MOVE); - } - else { - RNA_enum_set(op->ptr, "direction", 'v'); - sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V; - - WM_cursor_set(CTX_wm_window(C), CURSOR_Y_MOVE); - } + int dir = RNA_property_enum_get(op->ptr, prop_dir); + RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v'); + area_split_preview_update_cursor(C, op); + update_factor = true; } } } @@ -1789,8 +1810,64 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) case ESCKEY: area_split_cancel(C, op); return OPERATOR_CANCELLED; + + case LEFTCTRLKEY: + sd->do_snap = event->val == KM_PRESS; + update_factor = true; + break; } - + + if (update_factor) { + const int dir = RNA_property_enum_get(op->ptr, prop_dir); + + sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; + + if (sd->previewmode == 0) { + if (sd->do_snap) { + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller); + sd->delta = snap_loc - sd->origval; + } + area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false); + } + else { + if (sd->sarea) { + ED_area_tag_redraw(sd->sarea); + } + /* area context not set */ + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); + + if (sd->sarea) { + ScrArea *sa = sd->sarea; + if (dir == 'v') { + sd->origsize = sa->winx; + sd->origmin = sa->totrct.xmin; + } + else { + sd->origsize = sa->winy; + sd->origmin = sa->totrct.ymin; + } + + if (sd->do_snap) { + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1; + + const int snap_loc = area_snap_calc_location( + CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin); + + sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0; + sd->delta = snap_loc - sd->origval; + } + + ED_area_tag_redraw(sd->sarea); + } + + CTX_wm_screen(C)->do_draw = true; + } + + float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize; + RNA_float_set(op->ptr, "factor", fac); + } + return OPERATOR_RUNNING_MODAL; } @@ -1823,9 +1900,11 @@ static void SCREEN_OT_area_split(wmOperatorType *ot) RNA_def_int(ot->srna, "mouse_y", -100, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); } +/** \} */ - -/* ************** scale region edge operator *********************************** */ +/* -------------------------------------------------------------------- */ +/** \name Scale Region Edge Operator + * \{ */ typedef struct RegionMoveData { AZone *az; @@ -2094,8 +2173,11 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; } +/** \} */ -/* ************** frame change operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Frame Change Operator + * \{ */ static void areas_do_frame_follow(bContext *C, bool middle) { @@ -2176,6 +2258,11 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frame Jump Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int frame_jump_exec(bContext *C, wmOperator *op) @@ -2230,8 +2317,11 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range"); } +/** \} */ -/* ************** jump to keyframe operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Jump to Key-Frame Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int keyframe_jump_exec(bContext *C, wmOperator *op) @@ -2340,7 +2430,11 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", ""); } -/* ************** jump to marker operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Jump to Marker Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int marker_jump_exec(bContext *C, wmOperator *op) @@ -2403,7 +2497,11 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) RNA_def_boolean(ot->srna, "next", true, "Next Marker", ""); } -/* ************** switch screen operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Screen Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int screen_set_exec(bContext *C, wmOperator *op) @@ -2431,8 +2529,11 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot) RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -/* ************** screen full-area operator ***************************** */ +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name Screen Full-Area Operator + * \{ */ /* function to be called outside UI context, or for redo */ static int screen_maximize_area_exec(bContext *C, wmOperator *op) @@ -2491,7 +2592,11 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************** join area operator ********************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Screen Join-Area Operator + * \{ */ /* operator state vars used: * x1, y1 mouse coord in first area, which will disappear @@ -2521,13 +2626,23 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) */ typedef struct sAreaJoinData { - ScrArea *sa1; /* first area to be considered */ - ScrArea *sa2; /* second area to be considered */ - ScrArea *scr; /* designed for removal */ + ScrArea *sa1; /* first area to be considered */ + ScrArea *sa2; /* second area to be considered */ + void *draw_callback; /* call `ED_screen_draw_join_shape` */ } sAreaJoinData; +static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata) +{ + const wmOperator *op = userdata; + + sAreaJoinData *sd = op->customdata; + if (sd->sa1 && sd->sa2) { + ED_screen_draw_join_shape(sd->sa1, sd->sa2); + } +} + /* validate selection inside screen, set variables OK */ /* return 0: init failed */ /* XXX todo: find edge based on (x,y) and set other area? */ @@ -2561,14 +2676,14 @@ static int area_join_init(bContext *C, wmOperator *op) } jd = (sAreaJoinData *)MEM_callocN(sizeof(sAreaJoinData), "op_area_join"); - + jd->sa1 = sa1; - jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; jd->sa2 = sa2; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; - + op->customdata = jd; - + + jd->draw_callback = WM_draw_cb_activate(CTX_wm_window(C), area_join_draw_cb, op); + return 1; } @@ -2592,8 +2707,13 @@ static int area_join_apply(bContext *C, wmOperator *op) /* finish operation */ static void area_join_exit(bContext *C, wmOperator *op) { - if (op->customdata) { - MEM_freeN(op->customdata); + sAreaJoinData *jd = (sAreaJoinData *)op->customdata; + + if (jd) { + if (jd->draw_callback) + WM_draw_cb_exit(CTX_wm_window(C), jd->draw_callback); + + MEM_freeN(jd); op->customdata = NULL; } @@ -2652,17 +2772,6 @@ static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event) static void area_join_cancel(bContext *C, wmOperator *op) { - sAreaJoinData *jd = (sAreaJoinData *)op->customdata; - - if (jd->sa1) { - jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO; - } - if (jd->sa2) { - jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM; - jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; - } - WM_event_add_notifier(C, NC_WINDOW, NULL); area_join_exit(C, op); @@ -2686,9 +2795,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) if (jd->sa1 != sa) { dir = area_getorientation(jd->sa1, sa); if (dir != -1) { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = sa; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } else { /* we are not bordering on the previously selected area @@ -2697,15 +2804,10 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) */ dir = area_getorientation(sa, jd->sa2); if (dir != -1) { - if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa1 = jd->sa2; jd->sa2 = sa; - if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } else { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = NULL; } } @@ -2715,12 +2817,8 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we are back in the area previously selected for keeping * we swap the areas if possible to allow user to choose */ if (jd->sa2 != NULL) { - if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa1 = jd->sa2; jd->sa2 = sa; - if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM; - if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; dir = area_getorientation(jd->sa1, jd->sa2); if (dir == -1) { printf("oops, didn't expect that!\n"); @@ -2729,9 +2827,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) else { dir = area_getorientation(jd->sa1, sa); if (dir != -1) { - if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO; jd->sa2 = sa; - jd->sa2->flag |= AREA_FLAG_DRAWJOINTO; } } WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -2785,7 +2881,11 @@ static void SCREEN_OT_area_join(wmOperatorType *ot) RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX); } -/* ******************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Screen Area Options Operator + * \{ */ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -2838,9 +2938,11 @@ static void SCREEN_OT_area_options(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } +/** \} */ -/* ******************************* */ - +/* -------------------------------------------------------------------- */ +/** \name Space Data Cleanup Operator + * \{ */ static int spacedata_cleanup_exec(bContext *C, wmOperator *op) { @@ -2879,7 +2981,11 @@ static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot) } -/* ************** repeat last operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Repeat Last Operator + * \{ */ static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2918,6 +3024,12 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Repeat History Operator + * \{ */ + static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindowManager *wm = CTX_wm_manager(C); @@ -2975,7 +3087,11 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); } -/* ********************** redo operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Redo Operator + * \{ */ static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { @@ -3000,7 +3116,11 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/* ************** region four-split operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Quad-View Operator + * \{ */ static void view3d_localview_update_rv3d(struct RegionView3D *rv3d) { @@ -3153,8 +3273,11 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot) ot->flag = 0; } +/** \} */ -/* ************** region flip operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Region Flip Operator + * \{ */ /* flip a region alignment */ static int region_flip_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3205,7 +3328,11 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot) ot->flag = 0; } -/* ************** header operator ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Header Toggle Operator + * \{ */ static int header_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3235,8 +3362,11 @@ static void SCREEN_OT_header(wmOperatorType *ot) ot->exec = header_exec; } +/** \} */ -/* ************** show menus operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Header Toggle Menu Operator + * \{ */ /* show/hide header text menus */ static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3265,8 +3395,11 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot) ot->flag = 0; } +/** \} */ -/* ************** header tools operator ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Header Tools Operator + * \{ */ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) { @@ -3318,7 +3451,13 @@ static void SCREEN_OT_header_toolbox(wmOperatorType *ot) ot->invoke = header_toolbox_invoke; } -/* ****************** anim player, with timer ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Step Operator + * + * Animation Step. + * \{ */ static int match_area_with_refresh(int spacetype, int refresh) { @@ -3615,7 +3754,13 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot) } -/* ****************** anim player, starts or ends timer ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Playback Operator + * + * Animation Playback with Timer. + * \{ */ /* find window that owns the animation timer */ bScreen *ED_screen_animation_playing(const wmWindowManager *wm) @@ -3708,6 +3853,12 @@ static void SCREEN_OT_animation_play(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Cancel Operator + * \{ */ + static int screen_animation_cancel_exec(bContext *C, wmOperator *op) { bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C)); @@ -3747,7 +3898,11 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "restore_frame", true, "Restore Frame", "Restore the frame when animation was initialized"); } -/* ************** border select operator (template) ***************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Select Operator (Template) + * \{ */ /* operator state vars used: (added by default WM callbacks) * xmin, ymin @@ -3802,6 +3957,12 @@ static void SCREEN_OT_border_select(wmOperatorType *ot) } #endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Full Screen Back Operator + * \{ */ + /* *********************** generic fullscreen 'back' button *************** */ @@ -3836,7 +3997,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/* *********** show user pref window ****** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Show User Preferences Operator + * \{ */ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -3866,7 +4031,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; } -/********************* new screen operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name New Screen Operator + * \{ */ static int screen_new_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3893,7 +4062,11 @@ static void SCREEN_OT_new(wmOperatorType *ot) ot->poll = WM_operator_winactive; } -/********************* delete screen operator *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Screen Operator + * \{ */ static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3917,7 +4090,11 @@ static void SCREEN_OT_delete(wmOperatorType *ot) ot->exec = screen_delete_exec; } -/* ***************** region alpha blending ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Alpha Blending Operator + * \{ */ /* implementation note: a disappearing region needs at least 1 last draw with 100% backbuffer * texture over it- then triple buffer will clear it entirely. @@ -4059,7 +4236,11 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot) /* properties */ } -/* ******************** space context cycling operator ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Space Context Cycle Operator + * \{ */ /* SCREEN_OT_space_context_cycle direction */ enum { @@ -4142,9 +4323,11 @@ static void SCREEN_OT_space_context_cycle(wmOperatorType *ot) "Direction to cycle through"); } +/** \} */ -/* **************** Assigning operatortypes to global list, adding handlers **************** */ - +/* -------------------------------------------------------------------- */ +/** \name Assigning Operator Types + * \{ */ /* called in spacetypes.c */ void ED_operatortypes_screen(void) @@ -4203,13 +4386,19 @@ void ED_operatortypes_screen(void) } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Key Map + * \{ */ + static void keymap_modal_set(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""}, - {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""}, - {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""}, + {KM_MODAL_SNAP_ON, "SNAP", 0, "Snap on", ""}, + {KM_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap off", ""}, {0, NULL, 0, NULL, NULL}}; wmKeyMap *keymap; @@ -4221,8 +4410,8 @@ static void keymap_modal_set(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY); WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_SNAP_ON); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_SNAP_OFF); WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move"); @@ -4404,3 +4593,4 @@ void ED_keymap_screen(wmKeyConfig *keyconf) keymap_modal_set(keyconf); } +/** \} */ diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index e1e90506299..3a43c7a6585 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -151,7 +151,10 @@ typedef struct LoadTexData { float radius; } LoadTexData; -static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), const int j, const int thread_id) +static void load_tex_task_cb_ex( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict tls) { LoadTexData *data = userdata; Brush *br = data->br; @@ -212,7 +215,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c if (col) { float rgba[4]; - paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace); + paint_get_tex_pixel_col(mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace); buffer[index * 4] = rgba[0] * 255; buffer[index * 4 + 1] = rgba[1] * 255; @@ -220,7 +223,7 @@ static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), c buffer[index * 4 + 3] = rgba[3] * 255; } else { - float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id); + float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id); avg += br->texture_sample_bias; @@ -318,7 +321,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima .pool = pool, .size = size, .rotation = rotation, .radius = radius, }; - BLI_task_parallel_range_ex(0, size, &data, NULL, 0, load_tex_task_cb_ex, true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, size, &data, load_tex_task_cb_ex, &settings); if (mtex->tex && mtex->tex->nodetree) ntreeTexEndExecTree(mtex->tex->nodetree->execdata); @@ -365,7 +370,10 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima return 1; } -static void load_tex_cursor_task_cb(void *userdata, const int j) +static void load_tex_cursor_task_cb( + void *__restrict userdata, + const int j, + const ParallelRangeTLS *__restrict UNUSED(tls)) { LoadTexData *data = userdata; Brush *br = data->br; @@ -445,7 +453,9 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) .br = br, .buffer = buffer, .size = size, }; - BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, true); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, &settings); if (!cursor_snap.overlay_texture) glGenTextures(1, &cursor_snap.overlay_texture); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 2d1f0cb3b0d..aebd0c10e9c 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -50,6 +50,7 @@ #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_brush.h" @@ -58,7 +59,6 @@ #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" @@ -666,17 +666,17 @@ void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_cor float color_gr[4]; switch (br->gradient_stroke_mode) { case BRUSH_GRADIENT_PRESSURE: - do_colorband(br->gradient, pressure, color_gr); + BKE_colorband_evaluate(br->gradient, pressure, color_gr); break; case BRUSH_GRADIENT_SPACING_REPEAT: { float coord = fmod(distance / br->gradient_spacing, 1.0); - do_colorband(br->gradient, coord, color_gr); + BKE_colorband_evaluate(br->gradient, coord, color_gr); break; } case BRUSH_GRADIENT_SPACING_CLAMP: { - do_colorband(br->gradient, distance / br->gradient_spacing, color_gr); + BKE_colorband_evaluate(br->gradient, distance / br->gradient_spacing, color_gr); break; } } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 30830e4e7bc..2ce7c51b6b4 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -44,12 +44,12 @@ #include "BLI_bitmap.h" #include "BLI_task.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" -#include "BKE_texture.h" #include "DEG_depsgraph.h" @@ -1071,7 +1071,10 @@ typedef struct Paint2DForeachData { int tilew; } Paint2DForeachData; -static void paint_2d_op_foreach_do(void *data_v, const int iter) +static void paint_2d_op_foreach_do( + void *__restrict data_v, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) { Paint2DForeachData *data = (Paint2DForeachData *)data_v; paint_2d_do_making_brush(data->s, data->region, data->curveb, @@ -1157,9 +1160,12 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign data.blend = blend; data.tilex = tilex; data.tilew = tilew; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); BLI_task_parallel_range(tiley, tileh + 1, &data, paint_2d_op_foreach_do, - true); + &settings); } } @@ -1667,7 +1673,7 @@ void paint_2d_gradient_fill( break; } } - do_colorband(br->gradient, f, color_f); + BKE_colorband_evaluate(br->gradient, f, color_f); /* convert to premultiplied */ mul_v3_fl(color_f, color_f[3]); color_f[3] *= br->alpha; @@ -1697,7 +1703,7 @@ void paint_2d_gradient_fill( } } - do_colorband(br->gradient, f, color_f); + BKE_colorband_evaluate(br->gradient, f, color_f); linearrgb_to_srgb_v3_v3(color_f, color_f); rgba_float_to_uchar((unsigned char *)&color_b, color_f); ((unsigned char *)&color_b)[3] *= br->alpha; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 900ca844dbf..4a14e985827 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -62,6 +62,7 @@ #include "DNA_object_types.h" #include "BKE_camera.h" +#include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_colortools.h" #include "BKE_DerivedMesh.h" @@ -226,6 +227,7 @@ typedef struct ProjPaintState { View3D *v3d; RegionView3D *rv3d; ARegion *ar; + const Depsgraph *depsgraph; Scene *scene; int source; /* PROJ_SRC_**** */ @@ -3132,7 +3134,7 @@ static void proj_paint_state_viewport_init( ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat); - ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); + ps->is_ortho = ED_view3d_clip_range_get(ps->depsgraph, ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); } else { /* re-projection */ @@ -4582,7 +4584,7 @@ static void *do_projectpaint_thread(void *ph_v) break; } } - do_colorband(brush->gradient, f, color_f); + BKE_colorband_evaluate(brush->gradient, f, color_f); color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; if (is_floatbuf) { @@ -5097,6 +5099,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->rv3d = CTX_wm_region_view3d(C); ps->ar = CTX_wm_region(C); + ps->depsgraph = CTX_data_depsgraph(C); ps->scene = scene; ps->ob = ob; /* allow override of active object */ @@ -5507,7 +5510,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) array = (float *)IDP_Array(view_data); memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float); memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float); - is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true); + is_ortho = ED_view3d_clip_range_get(CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true); /* using float for a bool is dodgy but since its an extra member in the array... * easier then adding a single bool prop */ array[2] = is_ortho ? 1.0f : 0.0f; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0fec4c4fc80..ff261a808da 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -104,7 +104,10 @@ typedef struct MaskTaskData { float (*clip_planes_final)[4]; } MaskTaskData; -static void mask_flood_fill_task_cb(void *userdata, const int i) +static void mask_flood_fill_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MaskTaskData *data = userdata; @@ -158,9 +161,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .mode = mode, .value = value, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( 0, totnode, &data, mask_flood_fill_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + &settings); if (multires) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); @@ -221,7 +227,10 @@ static void flip_plane(float out[4], const float in[4], const char symm) out[3] = in[3]; } -static void mask_box_select_task_cb(void *userdata, const int i) +static void mask_box_select_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { MaskTaskData *data = userdata; @@ -303,9 +312,12 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r .mode = mode, .value = value, .clip_planes_final = clip_planes_final, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( 0, totnode, &data, mask_box_select_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + &settings); if (nodes) MEM_freeN(nodes); @@ -377,7 +389,10 @@ static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data) } while (++index != index_end); } -static void mask_gesture_lasso_task_cb(void *userdata, const int i) +static void mask_gesture_lasso_task_cb( + void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { LassoMaskData *lasso_data = userdata; MaskTaskData *data = &lasso_data->task_data; @@ -484,9 +499,12 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT)); BLI_task_parallel_range( 0, totnode, &data, mask_gesture_lasso_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT))); + &settings); if (nodes) MEM_freeN(nodes); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 40210d63566..004d2757a71 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -68,10 +68,13 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); ePaintMode mode = BKE_paintmode_get_active_from_context(C); - if (br) + if (br) { br = BKE_brush_copy(bmain, br); - else + } + else { br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode)); + id_us_min(&br->id); /* fake user only */ + } BKE_paint_brush_set(paint, br); @@ -376,6 +379,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool, if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) { brush = BKE_brush_add(bmain, tool_name, ob_mode); + id_us_min(&brush->id); /* fake user only */ brush_tool_set(brush, tool_offset, tool); brush->toggle_brush = brush_orig; } @@ -1273,6 +1277,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "PAINT_OT_mask_lasso_gesture", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0); + /* Toggle mask visibility */ + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "data_path", "scene.tool_settings.sculpt.show_mask"); + /* Toggle dynamic topology */ WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index dacaea6a96e..3982c9a3c30 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -109,6 +109,8 @@ typedef struct PaintStroke { * e.g. in sculpt mode, stroke doesn't start until cursor * passes over the mesh */ bool stroke_started; + /* Set when enough motion was found for rake rotation */ + bool rake_started; /* event that started stroke, for modal() return */ int event_type; /* check if stroke variables have been initialized */ @@ -233,6 +235,9 @@ static bool paint_brush_update(bContext *C, UnifiedPaintSettings *ups = stroke->ups; bool location_sampled = false; bool location_success = false; + /* Use to perform all operations except applying the stroke, + * needed for operations that require cursor motion (rake). */ + bool is_dry_run = false; bool do_random = false; bool do_random_mask = false; /* XXX: Use pressure value from first brush step for brushes which don't @@ -371,7 +376,15 @@ static bool paint_brush_update(bContext *C, } /* curve strokes do their own rake calculation */ else if (!(brush->flag & BRUSH_CURVE)) { - paint_calculate_rake_rotation(ups, brush, mouse_init); + if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) { + /* Not enough motion to define an angle. */ + if (!stroke->rake_started) { + is_dry_run = true; + } + } + else { + stroke->rake_started = true; + } } } @@ -402,7 +415,7 @@ static bool paint_brush_update(bContext *C, } } - return location_success; + return location_success && (is_dry_run == false); } static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert) diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 57a3044cc2b..1ec1e052d43 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -282,7 +282,7 @@ static void imapaint_pick_uv(EvaluationContext *eval_ctx, Scene *scene, Object * float p[2], w[3], absw, minabsw; float matrix[4][4], proj[4][4]; GLint view[4]; - const eImageePaintMode mode = scene->toolsettings->imapaint.mode; + const eImagePaintMode mode = scene->toolsettings->imapaint.mode; const MLoopTri *lt = dm->getLoopTriArray(dm); const MPoly *mpoly = dm->getPolyArray(dm); const MLoop *mloop = dm->getLoopArray(dm); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index d9df8c78ba9..0c1df71b1aa 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1195,7 +1195,7 @@ static void vwpaint_update_cache_invariants( cache->invert = mode == BRUSH_STROKE_INVERT; cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH; /* not very nice, but with current events system implementation - * we can't handle brush appearance inversion hotkey separately (sergey) */ + * we can't handle brush appearance inversion hotkey separately (sergey) */ if (cache->invert) ups->draw_inverted = true; else ups->draw_inverted = false; @@ -1441,7 +1441,9 @@ static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintIn } static void do_wpaint_precompute_weight_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; const MDeformVert *dv = &data->me->dvert[n]; @@ -1460,15 +1462,21 @@ static void precompute_weight_values( .C = C, .ob = ob, .wpd = wpd, .wpi = wpi, .me = me, }; - BLI_task_parallel_range_ex( - 0, me->totvert, &data, NULL, 0, do_wpaint_precompute_weight_cb_ex, - true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range( + 0, me->totvert, + &data, + do_wpaint_precompute_weight_cb_ex, + &settings); wpd->precomputed_weight_ready = true; } static void do_wpaint_brush_blur_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1557,7 +1565,9 @@ static void do_wpaint_brush_blur_task_cb_ex( } static void do_wpaint_brush_smear_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1664,7 +1674,9 @@ static void do_wpaint_brush_smear_task_cb_ex( } static void do_wpaint_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1734,7 +1746,9 @@ static void do_wpaint_brush_draw_task_cb_ex( } static void do_wpaint_brush_calc_average_weight_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1785,9 +1799,14 @@ static void calculate_average_weight(SculptThreadedTaskData *data, PBVHNode **UN struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - BLI_task_parallel_range_ex( - 0, totnode, data, NULL, 0, do_wpaint_brush_calc_average_weight_cb_ex, - ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + data, + do_wpaint_brush_calc_average_weight_cb_ex, + &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -1819,30 +1838,40 @@ static void wpaint_paint_leaves( /* Use this so average can modify its weight without touching the brush. */ data.strength = BKE_brush_weight_get(scene, brush); - /* current mirroring code cannot be run in parallel */ - bool use_threading = !(me->editflag & ME_EDIT_MIRROR_X); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + /* NOTE: current mirroring code cannot be run in parallel */ + settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X); switch (brush->vertexpaint_tool) { case PAINT_BLEND_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_draw_task_cb_ex, + &settings); break; case PAINT_BLEND_SMEAR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_smear_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_smear_task_cb_ex, + &settings); break; case PAINT_BLEND_BLUR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_blur_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_blur_task_cb_ex, + &settings); break; default: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_wpaint_brush_draw_task_cb_ex, use_threading, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_wpaint_brush_draw_task_cb_ex, + &settings); break; } } @@ -2398,7 +2427,9 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f } static void do_vpaint_brush_calc_average_color_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2460,7 +2491,9 @@ static float tex_color_alpha_ubyte( } static void do_vpaint_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2552,7 +2585,9 @@ static void do_vpaint_brush_draw_task_cb_ex( } static void do_vpaint_brush_blur_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2661,7 +2696,9 @@ static void do_vpaint_brush_blur_task_cb_ex( } static void do_vpaint_brush_smear_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2799,9 +2836,13 @@ static void calculate_average_color(SculptThreadedTaskData *data, PBVHNode **UNU struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - BLI_task_parallel_range_ex( - 0, totnode, data, NULL, 0, do_vpaint_brush_calc_average_color_cb_ex, - true, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + BLI_task_parallel_range( + 0, totnode, + data, + do_vpaint_brush_calc_average_color_cb_ex, + &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -2833,27 +2874,37 @@ static void vpaint_paint_leaves( .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd, .lcol = (uint *)me->mloopcol, .me = me, .C = C, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); switch (brush->vertexpaint_tool) { case PAINT_BLEND_AVERAGE: calculate_average_color(&data, nodes, totnode); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_draw_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_draw_task_cb_ex, + &settings); break; case PAINT_BLEND_BLUR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_blur_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_blur_task_cb_ex, + &settings); break; case PAINT_BLEND_SMEAR: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_smear_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_smear_task_cb_ex, + &settings); break; default: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, - do_vpaint_brush_draw_task_cb_ex, true, false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_vpaint_brush_draw_task_cb_ex, + &settings); break; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 6e08f47f60d..c9d550aa4bd 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -377,7 +377,10 @@ static bool sculpt_stroke_is_dynamic_topology( /*** paint mesh ***/ -static void paint_mesh_restore_co_task_cb(void *userdata, const int n) +static void paint_mesh_restore_co_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -439,9 +442,14 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, paint_mesh_restore_co_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + paint_mesh_restore_co_task_cb, + &settings); if (nodes) MEM_freeN(nodes); @@ -794,7 +802,10 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \note These are all _very_ similar, when changing one, check others. * \{ */ -static void calc_area_normal_and_center_task_cb(void *userdata, const int n) +static void calc_area_normal_and_center_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -946,9 +957,14 @@ static void calc_area_center( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -996,9 +1012,14 @@ void sculpt_pbvh_calc_area_normal( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = use_threading; BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - use_threading); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -1036,9 +1057,14 @@ static void calc_area_normal_and_center( }; BLI_mutex_init(&data.mutex); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, calc_area_normal_and_center_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + calc_area_normal_and_center_task_cb, + &settings); BLI_mutex_end(&data.mutex); @@ -1626,7 +1652,9 @@ typedef struct { } SculptFindNearestToRayData; static void do_smooth_brush_mesh_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1648,7 +1676,7 @@ static void do_smooth_brush_mesh_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), thread_id); + vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), tls->thread_id); if (smooth_mask) { float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -1674,7 +1702,9 @@ static void do_smooth_brush_mesh_task_cb_ex( } static void do_smooth_brush_bmesh_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1696,7 +1726,7 @@ static void do_smooth_brush_bmesh_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id); + vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, tls->thread_id); if (smooth_mask) { float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask; val *= fade * bstrength; @@ -1722,10 +1752,12 @@ static void do_smooth_brush_bmesh_task_cb_ex( } static void do_smooth_brush_multires_task_cb_ex( - void *userdata, void *userdata_chunk, const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; - SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk; + SculptDoBrushSmoothGridDataChunk *data_chunk = tls->userdata_chunk; SculptSession *ss = data->ob->sculpt; Sculpt *sd = data->sd; const Brush *brush = data->brush; @@ -1837,7 +1869,7 @@ static void do_smooth_brush_multires_task_cb_ex( const float strength_mask = (smooth_mask ? 0.0f : *mask); const float fade = bstrength * tex_strength( ss, brush, co, sqrtf(test.dist), - NULL, fno, strength_mask, thread_id); + NULL, fno, strength_mask, tls->thread_id); float f = 1.0f / 16.0f; if (x == 0 || x == gridsize - 1) @@ -1895,6 +1927,10 @@ static void smooth( .smooth_mask = smooth_mask, .strength = strength, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + switch (type) { case PBVH_GRIDS: { @@ -1909,22 +1945,30 @@ static void smooth( data_chunk->tmpgrid_size = size; size += sizeof(*data_chunk); - BLI_task_parallel_range_ex( - 0, totnode, &data, data_chunk, size, do_smooth_brush_multires_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + settings.userdata_chunk = data_chunk; + settings.userdata_chunk_size = size; + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_multires_task_cb_ex, + &settings); MEM_freeN(data_chunk); break; } case PBVH_FACES: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_smooth_brush_mesh_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_mesh_task_cb_ex, + &settings); break; case PBVH_BMESH: - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_smooth_brush_bmesh_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + BLI_task_parallel_range( + 0, totnode, + &data, + do_smooth_brush_bmesh_task_cb_ex, + &settings); break; } @@ -1940,7 +1984,9 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod } static void do_mask_brush_draw_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -1958,7 +2004,7 @@ static void do_mask_brush_draw_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, 0.0f, thread_id); + vd.no, vd.fno, 0.0f, tls->thread_id); (*vd.mask) += fade * bstrength; CLAMP(*vd.mask, 0, 1); @@ -1979,9 +2025,14 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_mask_brush_draw_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_mask_brush_draw_task_cb_ex, + &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2000,7 +2051,9 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } static void do_draw_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2022,7 +2075,7 @@ static void do_draw_brush_task_cb_ex( /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2055,16 +2108,23 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_draw_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_draw_brush_task_cb_ex, + &settings); } /** * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' */ static void do_crease_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2088,7 +2148,7 @@ static void do_crease_brush_task_cb_ex( /* offset vertex */ const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val1[3]; float val2[3]; @@ -2152,13 +2212,20 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_crease_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_crease_brush_task_cb_ex, + &settings); } static void do_pinch_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2179,7 +2246,7 @@ static void do_pinch_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val[3]; sub_v3_v3v3(val, test.location, vd.co); @@ -2203,13 +2270,20 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_pinch_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_pinch_brush_task_cb_ex, + &settings); } static void do_grab_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2236,7 +2310,7 @@ static void do_grab_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2264,13 +2338,20 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_grab_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_grab_brush_task_cb_ex, + &settings); } static void do_nudge_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2292,7 +2373,7 @@ static void do_nudge_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2320,13 +2401,20 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_nudge_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_nudge_brush_task_cb_ex, + &settings); } static void do_snake_hook_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2353,7 +2441,7 @@ static void do_snake_hook_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2426,13 +2514,20 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .spvc = &spvc, .grab_delta = grab_delta, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_snake_hook_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_snake_hook_brush_task_cb_ex, + &settings); } static void do_thumb_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2459,7 +2554,7 @@ static void do_thumb_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2487,13 +2582,20 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_thumb_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_thumb_brush_task_cb_ex, + &settings); } static void do_rotate_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2521,7 +2623,7 @@ static void do_rotate_brush_task_cb_ex( float vec[3], rot[3][3]; const float fade = bstrength * tex_strength( ss, brush, orig_data.co, sqrtf(test.dist), - orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, tls->thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -2549,13 +2651,20 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_rotate_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_rotate_brush_task_cb_ex, + &settings); } static void do_layer_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2589,7 +2698,7 @@ static void do_layer_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float *disp = &layer_disp[vd.i]; float val[3]; @@ -2634,15 +2743,22 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; BLI_mutex_init(&data.mutex); - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_layer_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_layer_brush_task_cb_ex, + &settings); BLI_mutex_end(&data.mutex); } static void do_inflate_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2663,7 +2779,7 @@ static void do_inflate_brush_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); float val[3]; if (vd.fno) @@ -2689,9 +2805,14 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_inflate_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_inflate_brush_task_cb_ex, + &settings); } static void calc_sculpt_plane( @@ -2806,7 +2927,9 @@ static float get_offset(Sculpt *sd, SculptSession *ss) } static void do_flatten_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2839,7 +2962,7 @@ static void do_flatten_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2878,13 +3001,20 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_flatten_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_flatten_brush_task_cb_ex, + &settings); } static void do_clay_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -2921,7 +3051,7 @@ static void do_clay_brush_task_cb_ex( * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2964,13 +3094,20 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_clay_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_clay_brush_task_cb_ex, + &settings); } static void do_clay_strips_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3006,7 +3143,7 @@ static void do_clay_strips_brush_task_cb_ex( * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( ss, brush, vd.co, ss->cache->radius * test.dist, - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3074,13 +3211,20 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_clay_strips_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_clay_strips_brush_task_cb_ex, + &settings); } static void do_fill_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3114,7 +3258,7 @@ static void do_fill_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3155,13 +3299,20 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_fill_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_fill_brush_task_cb_ex, + &settings); } static void do_scrape_brush_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3194,7 +3345,7 @@ static void do_scrape_brush_task_cb_ex( if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3235,13 +3386,20 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_no = area_no, .area_co = area_co, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_scrape_brush_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_scrape_brush_task_cb_ex, + &settings); } static void do_gravity_task_cb_ex( - void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict tls) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3261,7 +3419,7 @@ static void do_gravity_task_cb_ex( if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = tex_strength( ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, tls->thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -3292,9 +3450,14 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - BLI_task_parallel_range_ex( - 0, totnode, &data, NULL, 0, do_gravity_task_cb_ex, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( + 0, totnode, + &data, + do_gravity_task_cb_ex, + &settings); } @@ -3396,7 +3559,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified } } -static void do_brush_action_task_cb(void *userdata, const int n) +static void do_brush_action_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; @@ -3423,9 +3589,14 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &task_data, do_brush_action_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &task_data, + do_brush_action_task_cb, + &settings); if (sculpt_brush_needs_normal(brush, ss->cache->normal_weight)) update_sculpt_normal(sd, ob, nodes, totnode); @@ -3537,7 +3708,10 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) copy_v3_v3(me->mvert[index].co, newco); } -static void sculpt_combine_proxies_task_cb(void *userdata, const int n) +static void sculpt_combine_proxies_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3604,9 +3778,14 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, sculpt_combine_proxies_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + sculpt_combine_proxies_task_cb, + &settings); } if (nodes) @@ -3632,7 +3811,10 @@ static void sculpt_update_keyblock(Object *ob) } } -static void sculpt_flush_stroke_deform_task_cb(void *userdata, const int n) +static void sculpt_flush_stroke_deform_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; @@ -3685,9 +3867,14 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) .vertCos = vertCos, }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, &data, sculpt_flush_stroke_deform_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + &data, + sculpt_flush_stroke_deform_task_cb, + &settings); if (vertCos) { sculpt_vertcos_to_key(ob, ss->kb, vertCos); @@ -4505,7 +4692,7 @@ static float sculpt_raycast_init( RegionView3D *rv3d = vc->ar->regiondata; /* TODO: what if the segment is totally clipped? (return == 0) */ - ED_view3d_win_to_segment(vc->ar, vc->v3d, mouse, ray_start, ray_end, true); + ED_view3d_win_to_segment(vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true); invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index aaea13ce5d0..5fb9eee805f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -119,7 +119,7 @@ typedef struct SculptUndoNode { } SculptUndoNode; /* Factor of brush to have rake point following behind -* (could be configurable but this is reasonable default). */ + * (could be configurable but this is reasonable default). */ #define SCULPT_RAKE_BRUSH_FACTOR 0.25f struct SculptRakeData { @@ -148,7 +148,7 @@ typedef struct SculptThreadedTaskData { /* Data specific to some callbacks. */ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out - * what it is, and memory overhead is ridiculous anyway... */ + * what it is, and memory overhead is ridiculous anyway... */ float flippedbstrength; float angle; float strength; @@ -239,10 +239,10 @@ void sculpt_pbvh_calc_area_normal( float r_area_no[3]); /* Cache stroke properties. Used because -* RNA property lookup isn't particularly fast. -* -* For descriptions of these settings, check the operator properties. -*/ + * RNA property lookup isn't particularly fast. + * + * For descriptions of these settings, check the operator properties. + */ typedef struct StrokeCache { /* Invariants */ @@ -296,13 +296,13 @@ typedef struct StrokeCache { float view_normal[3]; /* sculpt_normal gets calculated by calc_sculpt_normal(), then the - * sculpt_normal_symm gets updated quickly with the usual symmetry - * transforms */ + * sculpt_normal_symm gets updated quickly with the usual symmetry + * transforms */ float sculpt_normal[3]; float sculpt_normal_symm[3]; /* Used for area texture mode, local_mat gets calculated by - * calc_brush_local_mat() and used in tex_strength(). */ + * calc_brush_local_mat() and used in tex_strength(). */ float brush_local_mat[4][4]; float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index a10c7477dc6..63017a0e576 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -319,7 +319,10 @@ static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNod return 1; } -static void sculpt_undo_bmesh_restore_generic_task_cb(void *userdata, const int n) +static void sculpt_undo_bmesh_restore_generic_task_cb( + void *__restrict userdata, + const int n, + const ParallelRangeTLS *__restrict UNUSED(tls)) { PBVHNode **nodes = userdata; @@ -347,9 +350,14 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); BLI_task_parallel_range( - 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, - ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT)); + 0, totnode, + nodes, + sculpt_undo_bmesh_restore_generic_task_cb, + &settings); if (nodes) MEM_freeN(nodes); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index fdf2dfe8371..29b3c6f2f6c 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -125,7 +125,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact) } else { /* just make a new (empty) action */ - action = add_empty_action(CTX_data_main(C), "Action"); + action = BKE_action_add(CTX_data_main(C), "Action"); } /* when creating new ID blocks, there is already 1 user (as for all new datablocks), diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 1c55a0d76cf..110c4d1789d 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1127,7 +1127,8 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op) actkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1577,7 +1578,8 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent mouse_action_keys(&ac, event->mval, selectmode, column, channel); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 7850a57f534..e47841ab574 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -128,6 +128,7 @@ void ED_spacetypes_init(void) ED_operatortypes_ui(); /* manipulator types */ + ED_manipulatortypes_button_2d(); ED_manipulatortypes_dial_3d(); ED_manipulatortypes_grab_3d(); ED_manipulatortypes_arrow_2d(); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index d2f407bfa8c..179780bf517 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -225,6 +225,28 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar) ED_region_header(C, ar); } +static void buttons_header_region_message_subscribe( + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceButs *sbuts = sa->spacedata.first; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* Don't check for SpaceButs.mainb here, we may toggle between view-layers + * where one has no active object, so that available contexts changes. */ + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + + if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_WORLD)) { + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); + } +} + /* draw a certain button set only if properties area is currently * showing that button set, to reduce unnecessary drawing. */ static void buttons_area_redraw(ScrArea *sa, short buttons) @@ -503,6 +525,7 @@ void ED_spacetype_buttons(void) art->init = buttons_header_region_init; art->draw = buttons_header_region_draw; + art->message_subscribe = buttons_header_region_message_subscribe; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index eb9aadd2e72..469d94fed3a 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -107,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr); if (!compact) - uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (clip) { uiLayout *col; diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 60736cfb885..7e37ae1238c 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -138,6 +138,8 @@ void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track); void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); +void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); + void clip_view_center_to_point(SpaceClip *sc, float x, float y); void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 40661937bae..7f9d9bf577c 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -184,37 +184,37 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); bool has_bundle = false; - char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; - const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)); - - if (track == act_track) + const bool used_for_stabilization = + (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) != 0; + if (track == act_track) { tracking->act_track = NULL; - - /* handle reconstruction display in 3d viewport */ - if (track->flag & TRACK_HAS_BUNDLE) + } + /* Handle reconstruction display in 3d viewport. */ + if (track->flag & TRACK_HAS_BUNDLE) { has_bundle = true; - + } /* Make sure no plane will use freed track */ BKE_tracking_plane_tracks_remove_point_track(tracking, track); - /* Delete f-curves associated with the track (such as weight, i.e.) */ - BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped)); - BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped); - BKE_animdata_fix_paths_remove(&clip->id, prefix); - + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_track(tracking, + track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete track itself. */ BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); - + /* Send notifiers. */ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); - if (used_for_stabilization) { WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } - + /* Inform dependency graph. */ DEG_id_tag_update(&clip->id, 0); - - if (has_bundle) + if (has_bundle) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } } void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, @@ -230,6 +230,28 @@ void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, } } +void clip_delete_plane_track(bContext *C, + MovieClip *clip, + MovieTrackingPlaneTrack *plane_track) +{ + MovieTracking *tracking = &clip->tracking; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + /* Delete f-curves associated with the track (such as weight, i.e.) */ + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_plane_track(tracking, + plane_track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete the plane track itself. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + /* TODO(sergey): Any notifiers to be sent here? */ + (void) C; + /* Inform dependency graph. */ + DEG_id_tag_update(&clip->id, 0); +} + void clip_view_center_to_point(SpaceClip *sc, float x, float y) { int width, height; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 2439ac06d9c..4ca2b54eaaf 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -227,7 +227,6 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; bool changed = false; - /* Delete selected plane tracks. */ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first, @@ -236,14 +235,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) plane_track = next_plane_track) { next_plane_track = plane_track->next; - if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { - BKE_tracking_plane_track_free(plane_track); - BLI_freelinkN(plane_tracks_base, plane_track); + clip_delete_plane_track(C, clip, plane_track); changed = true; } } - /* Remove selected point tracks (they'll also be removed from planes which * uses them). */ @@ -258,14 +254,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) changed = true; } } - /* Nothing selected now, unlock view so it can be scrolled nice again. */ sc->flag &= ~SC_LOCK_SELECTION; - if (changed) { WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); } - return OPERATOR_FINISHED; } @@ -1866,6 +1859,10 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del) } } + if (count == 0) { + ok = 0; + } + if (del) { MEM_freeN(track->markers); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index eddd65475a2..4ee85ace271 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -906,7 +906,7 @@ void CLIP_OT_select_all(wmOperatorType *ot) /********************** select grouped operator *********************/ -static int select_groped_exec(bContext *C, wmOperator *op) +static int select_grouped_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -989,7 +989,7 @@ void CLIP_OT_select_grouped(wmOperatorType *ot) ot->idname = "CLIP_OT_select_grouped"; /* api callbacks */ - ot->exec = select_groped_exec; + ot->exec = select_grouped_exec; ot->poll = ED_space_clip_tracking_poll; /* flags */ diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3f26604c23a..3c90f2957df 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -289,8 +289,9 @@ static void file_refresh(const bContext *C, ScrArea *sa) file_tools_region(sa); ED_area_initialize(wm, CTX_wm_window(C), sa); - ED_area_tag_redraw(sa); } + + ED_area_tag_redraw(sa); } static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene), @@ -304,16 +305,13 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Sce switch (wmn->data) { case ND_SPACE_FILE_LIST: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PARAMS: ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); break; case ND_SPACE_FILE_PREVIEW: if (sfile->files && filelist_cache_previews_update(sfile->files)) { ED_area_tag_refresh(sa); - ED_area_tag_redraw(sa); } break; } @@ -372,6 +370,15 @@ static void file_main_region_message_subscribe( .notify = ED_area_do_msg_notify_tag_refresh, }; + /* SpaceFile itself. */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } + /* FileSelectParams */ { PointerRNA ptr; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 2876fccaa51..29e3f99e1d4 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2747,3 +2747,89 @@ void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) } /* ************************************************************************** */ + +static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool ok = false; + unsigned int deleted = 0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* NOTE: we might need a scene update to evaluate the driver flags */ + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* find invalid drivers */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->data; + if (ELEM(NULL, fcu, fcu->driver)) { + continue; + } + if (!(fcu->driver->flag & DRIVER_FLAG_INVALID)) { + continue; + } + + ok |= ANIM_remove_driver(op->reports, ale->id, fcu->rna_path, fcu->array_index, 0); + if (!ok) { + break; + } + deleted += 1; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + + if (deleted > 0) { + /* notify the world of any changes */ + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + WM_reportf(RPT_INFO, "Deleted %u drivers", deleted); + } + else { + WM_report(RPT_INFO, "No drivers deleted"); + } + + /* successful or not? */ + if (!ok) { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +static int graph_driver_delete_invalid_poll(bContext *C) +{ + bAnimContext ac; + ScrArea *sa = CTX_wm_area(C); + + /* firstly, check if in Graph Editor */ + if ((sa == NULL) || (sa->spacetype != SPACE_IPO)) + return 0; + + /* try to init Anim-Context stuff ourselves and check */ + return ANIM_animdata_get_context(C, &ac) != 0; +} + + +void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Invalid Drivers"; + ot->idname = "GRAPH_OT_driver_delete_invalid"; + ot->description = "Delete all visible drivers considered invalid"; + + /* api callbacks */ + ot->exec = graph_driver_delete_invalid_exec; + ot->poll = graph_driver_delete_invalid_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 534b712fd5e..6c375b23352 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -152,6 +152,7 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot); void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot); void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot); +void GRAPH_OT_driver_delete_invalid(struct wmOperatorType *ot); /* ----------- */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 62275abcd02..57d8f45905d 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -468,6 +468,7 @@ void graphedit_operatortypes(void) /* Drivers */ WM_operatortype_append(GRAPH_OT_driver_variables_copy); WM_operatortype_append(GRAPH_OT_driver_variables_paste); + WM_operatortype_append(GRAPH_OT_driver_delete_invalid); } void ED_operatormacros_graph(void) diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 1683fbdbdb9..392db4ef4b5 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1003,7 +1003,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) graphkeys_select_leftright(&ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -1517,7 +1518,8 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEve } /* set notifier that keyframe selection (and also channel selection in some cases) has changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); /* for tweak grab to work */ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 51ccaf6800a..20f9658020d 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -871,8 +871,11 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char uiLayoutSetContextPointer(layout, "edit_image", &imaptr); uiLayoutSetContextPointer(layout, "edit_image_user", userptr); - if (!compact) - uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); + if (!compact) { + uiTemplateID( + layout, C, ptr, propname, + ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + } if (ima) { UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index a95f7ccd69e..de158f84a4d 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1152,9 +1152,10 @@ static int image_cmp_frame(const void *a, const void *b) } /** - * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames - * \param frames [in] the list of frame numbers, as a side-effect the list is sorted - * \param ofs [out] offest, the first frame number in the sequence + * Return the start (offset) and the length of the sequence of continuous frames in the list of frames + * + * \param frames: [in] the list of frame numbers, as a side-effect the list is sorted. + * \param ofs: [out] offset the first frame number in the sequence. * \return the number of contiguous frames in the sequence */ static int image_sequence_get_len(ListBase *frames, int *ofs) @@ -1857,7 +1858,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI scene = CTX_data_scene(C); rr = BKE_image_acquire_renderresult(scene, ima); bool is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2; - bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && RE_HasFloatPixels(rr); /* error handling */ if (!rr) { diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 4f595ad98c6..a89ae2b869a 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -95,6 +95,18 @@ static void image_scopes_tag_refresh(ScrArea *sa) sima->scopes.ok = 0; } +static void image_user_refresh_scene(const bContext *C, SpaceImage *sima) +{ + if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { + /* for render result, try to use the currently rendering scene */ + Scene *render_scene = ED_render_job_get_current_scene(C); + if (render_scene) { + sima->iuser.scene = render_scene; + return; + } + } + sima->iuser.scene = CTX_data_scene(C); +} /* ******************** manage regions ********************* */ @@ -734,17 +746,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); - /* put scene context variable in iuser */ - if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { - /* for render result, try to use the currently rendering scene */ - Scene *render_scene = ED_render_job_get_current_scene(C); - if (render_scene) - sima->iuser.scene = render_scene; - else - sima->iuser.scene = scene; - } - else - sima->iuser.scene = scene; + image_user_refresh_scene(C, sima); /* we set view2d from own zoom and offset each time */ image_main_region_set_view2d(sima, ar); @@ -1014,6 +1016,11 @@ static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) static void image_header_region_draw(const bContext *C, ARegion *ar) { + ScrArea *sa = CTX_wm_area(C); + SpaceImage *sima = sa->spacedata.first; + + image_user_refresh_scene(C, sima); + ED_region_header(C, ar); } diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 4f042364c63..b13152883c3 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -50,6 +50,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" #include "UI_resources.h" #include "UI_interface.h" @@ -284,6 +287,22 @@ static void info_header_listener( } +static void info_header_region_message_subscribe( + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, + struct wmMsgBus *mbus) +{ + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); +} + static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) { struct RecentFile *recent; @@ -347,6 +366,7 @@ void ED_spacetype_info(void) art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = info_header_listener; + art->message_subscribe = info_header_region_message_subscribe; art->init = info_header_region_init; art->draw = info_header_region_draw; diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 69bf51ade3a..c6fd70a60dd 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -2011,7 +2011,7 @@ static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C) { uiLayout *row, *col; - uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL); + uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!RNA_pointer_get(ptr, "sound").data) { uiItemL(layout, IFACE_("Select a sound from the list or load a new one"), ICON_NONE); return; diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index c774b99629c..3080ac2de84 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -285,7 +285,9 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) /* Active Action Properties ------------------------------------- */ /* action */ row = uiLayoutRow(layout, true); - uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, "NLA_OT_action_unlink"); + uiTemplateID( + row, (bContext *)C, &adt_ptr, "action", + "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL); /* extrapolation */ row = uiLayoutRow(layout, true); diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 1179401f346..e09e4417d5d 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -444,7 +444,8 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op) nlaedit_select_leftright(C, &ac, leftright, selectmode); /* set notifier that keyframe selection (and channels too) have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c591433f7b1..1bee2716e65 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -284,7 +284,7 @@ static int node_resize_area_default(bNode *node, int x, int y) static void node_draw_buttons_group(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL); + uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); } /* XXX Does a bounding box update by iterating over all children. @@ -633,7 +633,8 @@ static void node_common_set_butfunc(bNodeType *ntype) /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, - PointerRNA *imaptr, PointerRNA *iuserptr) + PointerRNA *imaptr, PointerRNA *iuserptr, + bool compositor) { uiLayout *col; int source; @@ -668,7 +669,8 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); } - if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && + if (compositor && + RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); @@ -681,7 +683,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA bNode *node = ptr->data; uiLayout *col; - uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL); + uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -778,7 +780,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -792,7 +794,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. */ - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -807,9 +809,11 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); @@ -823,7 +827,9 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P Image *ima = imaptr.data; uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!ima) return; @@ -1250,12 +1256,14 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID( + layout, C, ptr, "image", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; imaptr = RNA_pointer_get(ptr, "image"); - node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr); + node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true); node_buts_image_views(layout, C, ptr, &imaptr); } @@ -1280,7 +1288,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer const char *layer_name; char scene_name[MAX_ID_NAME - 2]; - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -1394,7 +1402,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE); - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE); @@ -1961,7 +1969,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); } static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1969,7 +1977,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point bNode *node = ptr->data; PointerRNA clipptr; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -1983,7 +1991,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -2007,7 +2015,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (!node->id) return; @@ -2315,7 +2323,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE); @@ -2337,7 +2345,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2373,7 +2381,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2413,7 +2421,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P bNode *node = ptr->data; NodePlaneTrackDeformData *data = node->storage; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2791,7 +2799,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); } static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 64c019d12a3..70f7553cf41 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -31,12 +31,14 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_node_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_easing.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" @@ -63,6 +65,15 @@ /* ****************** Relations helpers *********************** */ +static bool ntree_has_drivers(bNodeTree *ntree) +{ + AnimData *adt = BKE_animdata_from_id(&ntree->id); + if (adt == NULL) { + return false; + } + return !BLI_listbase_is_empty(&adt->drivers); +} + static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree, bNode *from, bNode *to) @@ -134,6 +145,14 @@ static bool node_group_has_output(bNode *node) bool node_connected_to_output(bNodeTree *ntree, bNode *node) { + /* Special case for drivers: if node tree has any drivers we assume it is + * always to be tagged for update when node changes. Otherwise we will be + * doomed to do some deep and nasty deep search of indirect dependencies, + * which will be too complicated without real benefit. + */ + if (ntree_has_drivers(ntree)) { + return true; + } for (bNode *current_node = ntree->nodes.first; current_node != NULL; current_node = current_node->next) @@ -144,11 +163,17 @@ bool node_connected_to_output(bNodeTree *ntree, bNode *node) * We could make check more grained here by taking which socket the node * is connected to and so eventually. */ - if (current_node->type == NODE_GROUP && - ntree_check_nodes_connected(ntree, node, current_node) && - node_group_has_output(current_node)) - { - return true; + if (current_node->type == NODE_GROUP) { + if (current_node->id != NULL && + ntree_has_drivers((bNodeTree *)current_node->id)) + { + return true; + } + if (ntree_check_nodes_connected(ntree, node, current_node) && + node_group_has_output(current_node)) + { + return true; + } } if (current_node->flag & NODE_DO_OUTPUT) { if (ntree_check_nodes_connected(ntree, node, current_node)) { diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index d5c833a7b5f..8999555521a 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -51,13 +51,13 @@ #include "outliner_intern.h" /* own include */ +/* Prototypes. */ +static int collection_delete_exec(struct bContext *C, struct wmOperator *op); + /* -------------------------------------------------------------------- */ static LayerCollection *outliner_collection_active(bContext *C) { - TODO_LAYER_OPERATORS; - /* consider that we may have overrides or objects active - * leading to no active collections */ return CTX_data_layer_collection(C); } @@ -76,14 +76,20 @@ SceneCollection *outliner_scene_collection_from_tree_element(TreeElement *te) return NULL; } -#if 0 -static CollectionOverride *outliner_override_active(bContext *UNUSED(C)) +/* -------------------------------------------------------------------- */ +/* Poll functions. */ + +static int collections_editor_poll(bContext *C) { - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - return NULL; + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (so->outlinevis == SO_COLLECTIONS); +} + +static int view_layer_editor_poll(bContext *C) +{ + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); } -#endif /* -------------------------------------------------------------------- */ /* collection manager operators */ @@ -108,6 +114,44 @@ static SceneCollection *scene_collection_from_index(ListBase *lb, const int numb return NULL; } +typedef struct TreeElementFindData { + SceneCollection *collection; + TreeElement *r_result_te; +} TreeElementFindData; + +static TreeTraversalAction tree_element_find_by_scene_collection_cb(TreeElement *te, void *customdata) +{ + TreeElementFindData *data = customdata; + const SceneCollection *current_element_sc = outliner_scene_collection_from_tree_element(te); + + if (current_element_sc == data->collection) { + data->r_result_te = te; + return TRAVERSE_BREAK; + } + + return TRAVERSE_CONTINUE; +} + +static TreeElement *outliner_tree_element_from_layer_collection_index( + SpaceOops *soops, ViewLayer *view_layer, + const int index) +{ + LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index); + + if (lc == NULL) { + return NULL; + } + + /* Find the tree element containing the LayerCollection's scene_collection. */ + TreeElementFindData data = { + .collection = lc->scene_collection, + .r_result_te = NULL, + }; + outliner_tree_traverse(soops, &soops->tree, 0, 0, tree_element_find_by_scene_collection_cb, &data); + + return data.r_result_te; +} + static int collection_link_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); @@ -187,7 +231,7 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Add Collection"; + ot->name = "Link Collection"; ot->idname = "OUTLINER_OT_collection_link"; ot->description = "Link a new collection to the active layer"; @@ -210,6 +254,10 @@ void OUTLINER_OT_collection_link(wmOperatorType *ot) */ static int collection_unlink_poll(bContext *C) { + if (view_layer_editor_poll(C) == 0) { + return 0; + } + LayerCollection *lc = outliner_collection_active(C); if (lc == NULL) { @@ -249,7 +297,7 @@ static int collection_unlink_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_unlink(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Collection"; + ot->name = "Unlink Collection"; ot->idname = "OUTLINER_OT_collection_unlink"; ot->description = "Unlink collection from the active layer"; @@ -292,40 +340,218 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) } /**********************************************************************************/ +/* Add new nested collection. */ -/** - * Returns true is selected element is a collection - */ -static int collection_override_new_poll(bContext *(C)) +struct CollectionNewData +{ + bool error; + SceneCollection *scene_collection; +}; + +static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) +{ + struct CollectionNewData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + if (data->scene_collection != NULL) { + data->error = true; + return TRAVERSE_BREAK; + } + + data->scene_collection = scene_collection; + return TRAVERSE_CONTINUE; +} + +static int collection_nested_new_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct CollectionNewData data = { + .error = false, + .scene_collection = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); + + if (data.error) { + BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); + return OPERATOR_CANCELLED; + } + + BKE_collection_add( + &scene->id, + data.scene_collection, + COLLECTION_TYPE_NONE, + NULL); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_nested_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Nested Collection"; + ot->idname = "OUTLINER_OT_collection_nested_new"; + ot->description = "Add a new collection inside selected collection"; + + /* api callbacks */ + ot->exec = collection_nested_new_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ +/* Delete selected collection. */ + +void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Selected Collections"; + ot->idname = "OUTLINER_OT_collection_delete_selected"; + ot->description = "Delete all the selected collections"; + + /* api callbacks */ + ot->exec = collection_delete_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ +/* Add new selected objects. */ + +struct SceneCollectionSelectedData { + ListBase scene_collections_array; +}; + +static TreeTraversalAction collection_find_selected_scene_collections(TreeElement *te, void *customdata) +{ + struct SceneCollectionSelectedData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_addtail(&data->scene_collections_array, BLI_genericNodeN(scene_collection)); + return TRAVERSE_CONTINUE; +} + +static int collection_objects_add_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct SceneCollectionSelectedData data = { + .scene_collections_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data); + + if (BLI_listbase_is_empty(&data.scene_collections_array)) { + BKE_report(op->reports, RPT_ERROR, "No collection is selected"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) + { + BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + SceneCollection *scene_collection = link->data; + BKE_collection_object_add( + &scene->id, + scene_collection, + ob); + } + } + CTX_DATA_END; + BLI_freelistN(&data.scene_collections_array); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_objects_add(wmOperatorType *ot) { -#ifdef TODO_LAYER_OVERRIDE - /* disable for now, since it's not implemented */ - (void) C; - return 0; -#else - return outliner_collection_active(C) ? 1 : 0; -#endif + /* identifiers */ + ot->name = "Add Objects"; + ot->idname = "OUTLINER_OT_collection_objects_add"; + ot->description = "Add selected objects to collection"; + + /* api callbacks */ + ot->exec = collection_objects_add_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int collection_override_new_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) +/**********************************************************************************/ +/* Remove selected objects. */ + + +static int collection_objects_remove_exec(bContext *C, wmOperator *op) { - TODO_LAYER_OPERATORS; - TODO_LAYER_OVERRIDE; - BKE_report(op->reports, RPT_ERROR, "OUTLINER_OT_collections_override_new not implemented yet"); - return OPERATOR_CANCELLED; + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct SceneCollectionSelectedData data = { + .scene_collections_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_scene_collections, &data); + + if (BLI_listbase_is_empty(&data.scene_collections_array)) { + BKE_report(op->reports, RPT_ERROR, "No collection is selected"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, struct Object *, ob, selected_objects) + { + BLI_LISTBASE_FOREACH (LinkData *, link, &data.scene_collections_array) { + SceneCollection *scene_collection = link->data; + BKE_collection_object_remove( + bmain, + &scene->id, + scene_collection, + ob, + true); + } + } + CTX_DATA_END; + BLI_freelistN(&data.scene_collections_array); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; } -/* in the middle of renames remove s */ -void OUTLINER_OT_collection_override_new(wmOperatorType *ot) +void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) { /* identifiers */ - ot->name = "New Override"; - ot->idname = "OUTLINER_OT_collection_override_new"; - ot->description = "Add a new override to the active collection"; + ot->name = "Remove Objects"; + ot->idname = "OUTLINER_OT_collection_objects_remove"; + ot->description = "Remove selected objects from collection"; /* api callbacks */ - ot->invoke = collection_override_new_invoke; - ot->poll = collection_override_new_poll; + ot->exec = collection_objects_remove_exec; + ot->poll = collections_editor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -352,6 +578,26 @@ static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void } else { BLI_gset_add(data->collections_to_delete, scene_collection); + return TRAVERSE_SKIP_CHILDS; /* Childs will be gone anyway, no need to recurse deeper. */ + } + + return TRAVERSE_CONTINUE; +} + +static TreeTraversalAction collection_delete_elements_from_collection(TreeElement *te, void *customdata) +{ + struct CollectionDeleteData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + const bool will_be_deleted = BLI_gset_haskey(data->collections_to_delete, scene_collection); + if (will_be_deleted) { + outliner_free_tree_element(te, te->parent ? &te->parent->subtree : &data->soops->tree); + /* Childs are freed now, so don't recurse into them. */ + return TRAVERSE_SKIP_CHILDS; } return TRAVERSE_CONTINUE; @@ -365,26 +611,33 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op)) data.collections_to_delete = BLI_gset_ptr_new(__func__); - TODO_LAYER_OVERRIDE; /* handle overrides */ - /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data); + /* Now, delete all tree elements representing a collection that will be deleted. We'll look for a + * new element to select in a few lines, so we can't wait until the tree is recreated on redraw. */ + outliner_tree_traverse(soops, &soops->tree, 0, 0, collection_delete_elements_from_collection, &data); + /* Effectively delete the collections. */ GSetIterator collections_to_delete_iter; GSET_ITER(collections_to_delete_iter, data.collections_to_delete) { - SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter); BKE_collection_remove(&data.scene->id, sc); } BLI_gset_free(data.collections_to_delete, NULL); + TreeElement *select_te = outliner_tree_element_from_layer_collection_index(soops, CTX_data_view_layer(C), 0); + if (select_te) { + outliner_item_select(soops, select_te, false, false); + } + DEG_relations_tag_update(CTX_data_main(C)); /* TODO(sergey): Use proper flag for tagging here. */ DEG_id_tag_update(&scene->id, 0); + soops->storeflag |= SO_TREESTORE_REDRAW; WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; @@ -438,13 +691,12 @@ static int collection_toggle_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); int action = RNA_enum_get(op->ptr, "action"); LayerCollection *layer_collection = CTX_data_layer_collection(C); if (layer_collection->flag & COLLECTION_DISABLED) { if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) { - BKE_collection_enable(view_layer, layer_collection); + layer_collection->flag &= ~COLLECTION_DISABLED; } else { /* ACTION_DISABLE */ BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled", @@ -454,7 +706,7 @@ static int collection_toggle_exec(bContext *C, wmOperator *op) } else { if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) { - BKE_collection_disable(view_layer, layer_collection); + layer_collection->flag |= COLLECTION_DISABLED; } else { /* ACTION_ENABLE */ BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled", @@ -505,68 +757,3 @@ void OUTLINER_OT_collection_toggle(wmOperatorType *ot) #undef ACTION_TOGGLE #undef ACTION_ENABLE #undef ACTION_DISABLE - -/* -------------------------------------------------------------------- */ - -static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) -{ - TODO_LAYER_OPERATORS; - BKE_report(op->reports, RPT_ERROR, "Operator not implemented yet"); - return OPERATOR_CANCELLED; -} - -void OUTLINER_OT_collection_objects_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Objects"; - ot->idname = "OUTLINER_OT_collection_objects_add"; - ot->description = "Add selected objects to collection"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Object"; - ot->idname = "OUTLINER_OT_collection_objects_remove"; - ot->description = "Remove objects from collection"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Objects"; - ot->idname = "OUTLINER_OT_collection_objects_select"; - ot->description = "Select collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Deselect Objects"; - ot->idname = "OUTLINER_OT_collection_objects_deselect"; - ot->description = "Deselect collection objects"; - - /* api callbacks */ - ot->invoke = stubs_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 670fc4e6627..1478792b38b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -247,49 +247,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } -static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ID *id = poin; - LayerCollection *layer_collection = poin2; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection); - - /* TODO: This breaks when you see the collections of a group. (dfelinto) */ - if (view_layer == NULL) { - WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now"); - return; - } - - /* We need to toggle the flag since this is called after the flag is already set. */ - layer_collection->flag ^= COLLECTION_DISABLED; - - if (layer_collection->flag & COLLECTION_DISABLED) { - BKE_collection_enable(view_layer, layer_collection); - } - else { - BKE_collection_disable(view_layer, layer_collection); - } - - DEG_relations_tag_update(bmain); - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); -} - static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { ID *id = (ID *)poin; - /* hide and deselect bases that are directly influenced by this LayerCollection */ /* TODO(sergey): Use proper flag for tagging here. */ DEG_id_tag_update(id, 0); if (GS(id->name) == ID_SCE) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id); } - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } @@ -602,21 +569,6 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS_NONE); - bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, - is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Enable/Disable collection from depsgraph")); - UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View visibility of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - if (collection->scene_collection->type == COLLECTION_TYPE_NONE) { bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, @@ -625,6 +577,31 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); } + else if ((soops->outlinevis == SO_GROUPS) && + (collection->scene_collection->type == COLLECTION_TYPE_GROUP_INTERNAL)) + { + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VIEWPORT, 0, ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_RENDER, 0, ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + + bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, + is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Enable/Disable collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_block_emboss_set(block, UI_EMBOSS); } @@ -694,7 +671,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops } } -static void outliner_draw_rnacols(ARegion *ar, int sizex) +static void UNUSED_FUNCTION(outliner_draw_rnacols)(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; @@ -720,6 +697,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) immUnbindProgram(); } +#if 0 static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb) { TreeElement *te; @@ -764,6 +742,7 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, UI_block_emboss_set(block, UI_EMBOSS); } +#endif static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) { @@ -1131,6 +1110,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto ICON_DRAW(icon); } break; + case TSE_LAYER_COLLECTION: + case TSE_SCENE_COLLECTION: + ICON_DRAW(ICON_COLLAPSEMENU); + break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ #if 0 case TSE_GP_LAYER: @@ -1378,22 +1361,24 @@ static void outliner_draw_tree_element( } else if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; - - if (ob == OBACT(view_layer) || (ob->flag & SELECT)) { + Base *base = (Base *)te->directdata; + const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); + + if (ob == OBACT(view_layer) || is_selected) { char col[4] = {0, 0, 0, 0}; /* outliner active ob: always white text, circle color now similar to view3d */ active = OL_DRAWSEL_ACTIVE; if (ob == OBACT(view_layer)) { - if (ob->flag & SELECT) { + if (is_selected) { UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); col[3] = alpha; } active = OL_DRAWSEL_NORMAL; } - else if (ob->flag & SELECT) { + else if (is_selected) { UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); col[3] = alpha; } @@ -1432,13 +1417,12 @@ static void outliner_draw_tree_element( te->flag |= TE_ACTIVE; // for lookup in display hierarchies } + if ((soops->outlinevis == SO_COLLECTIONS) && (tselem->type == TSE_SCENE_COLLECTION) && (te->parent == NULL)) { + /* Master collection can't expand/collapse. */ + } + else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ - if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { - int icon_x; - if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE)) - icon_x = startx; - else - icon_x = startx + 5 * ufac; + int icon_x = startx; // icons a bit higher if (TSELEM_OPEN(tselem, soops)) @@ -1474,6 +1458,11 @@ static void outliner_draw_tree_element( } offsx += UI_UNIT_X + 2 * ufac; } + else if (tselem->type == 0 && ID_IS_STATIC_OVERRIDE(tselem->id)) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE, + alpha_fac); + offsx += UI_UNIT_X + 2 * ufac; + } glDisable(GL_BLEND); /* name */ @@ -1612,7 +1601,7 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo const unsigned char col[4], bool draw_grayed_out, int *starty) { - TreeElement *te; + TreeElement *te, *te_vertical_line_last = NULL; TreeStoreElem *tselem; int y1, y2; @@ -1622,10 +1611,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo const unsigned char grayed_alpha = col[3] / 2; - y1 = y2 = *starty; /* for vertical lines between objects */ + /* For vertical lines between objects. */ + y1 = *starty; for (te = lb->first; te; te = te->next) { bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL); - y2 = *starty; tselem = TREESTORE(te); if (draw_childs_grayed_out) { @@ -1635,10 +1624,17 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo immUniformColor4ubv(col); } - /* horizontal line? */ - if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) + /* Horizontal Line? */ + if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) { immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1); - + + /* Vertical Line? */ + if (te->idcode == ID_OB) { + te_vertical_line_last = te; + y2 = *starty; + } + } + *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) @@ -1653,12 +1649,10 @@ static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soo immUniformColor4ubv(col); } - /* vertical line */ - te = lb->last; - if (te->parent || lb->first != lb->last) { - tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) - immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); + /* Vertical line. */ + te = te_vertical_line_last; + if ((te != NULL) && (te->parent || lb->first != lb->last)) { + immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); } } @@ -1724,7 +1718,9 @@ static void outliner_draw_highlights_recursive( int start_x, int *io_start_y) { const bool is_searching = SEARCHING_OUTLINER(soops) || - (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0); + (soops->outlinevis == SO_DATABLOCKS && + (soops->filter & SO_FILTER_SEARCH) && + soops->search_string[0] != 0); for (TreeElement *te = lb->first; te; te = te->next) { const TreeStoreElem *tselem = TREESTORE(te); @@ -1790,7 +1786,7 @@ static void outliner_draw_tree( glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { + if (soops->outlinevis == SO_DATABLOCKS) { /* struct marks */ starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); @@ -1814,7 +1810,7 @@ static void outliner_draw_tree( // gray hierarchy lines starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; - startx = 6; + startx = UI_UNIT_X / 2 - 1.0f; outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); // items themselves @@ -1879,15 +1875,12 @@ static void outliner_draw_restrictcols(ARegion *ar) immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); immBegin(GWN_PRIM_LINES, 6); - /* view */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin); - /* render */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin); - /* render */ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin); @@ -1911,12 +1904,12 @@ void draw_outliner(const bContext *C) TreeElement *te_edit = NULL; bool has_restrict_icons; - outliner_build_tree(mainvar, scene, view_layer, soops); // always + outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always /* get extents of data */ outliner_height(soops, &soops->tree, &sizey); - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { + if (soops->outlinevis == SO_DATABLOCKS) { /* RNA has two columns: * - column 1 is (max_width + OL_RNA_COL_SPACEX) or * (OL_RNA_COL_X), whichever is wider... @@ -1941,8 +1934,9 @@ void draw_outliner(const bContext *C) /* constant offset for restriction columns */ // XXX this isn't that great yet... - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) + if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { sizex += OL_TOGW * 3; + } has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); } @@ -1962,13 +1956,8 @@ void draw_outliner(const bContext *C) outliner_back(ar); block = UI_block_begin(C, ar, __func__, UI_EMBOSS); outliner_draw_tree((bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); - - if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { - /* draw rna buttons */ - outliner_draw_rnacols(ar, sizex_rna); - outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); - } - else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + + if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { /* draw user toggle columns */ outliner_draw_restrictcols(ar); outliner_draw_userbuts(block, ar, soops, &soops->tree); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 8cd76179f23..fc0e30c78ce 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -949,7 +949,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeEle } /* to retrieve coordinates with redrawing the entire tree */ -static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) +void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) { TreeElement *te; int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; @@ -2085,7 +2085,7 @@ static int outliner_parenting_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); if (soops) { - return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); + return ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS); } return false; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f69eb9af1bf..b06c9b85eb8 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -36,6 +36,7 @@ /* internal exports only */ +struct ARegion; struct wmOperatorType; struct TreeElement; struct TreeStoreElem; @@ -47,6 +48,7 @@ struct ID; struct Object; struct bPoseChannel; struct EditBone; +struct wmEvent; struct wmKeyConfig; @@ -69,8 +71,11 @@ typedef enum TreeTraversalAction { * Callback type for reinserting elements at a different position, used to allow user customizable element order. */ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, + struct SpaceOops *soops, struct TreeElement *insert_element, - struct TreeElement *insert_handle, TreeElementInsertType action); + struct TreeElement *insert_handle, + TreeElementInsertType action, + const struct wmEvent *event); /** * Executed on (almost) each mouse move while dragging. It's supposed to give info * if reinserting insert_element before/after/into insert_handle would be allowed. @@ -102,6 +107,7 @@ typedef struct TreeElement { TreeElementInsertType insert_type; /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */ struct TreeElement *insert_handle; + void *tooltip_draw_handle; } *drag_data; } TreeElement; @@ -143,17 +149,19 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_ENABLEX (UI_UNIT_X * 3.0f) -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f) -#define OL_TOG_RESTRICT_SELECTX UI_UNIT_X +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X -#define OL_TOGW OL_TOG_RESTRICT_ENABLEX +#define OL_TOGW OL_TOG_RESTRICT_VIEWX #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) #define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f) +/* The outliner display modes that support the filter system. + * Note: keep it synced with space_outliner.py */ +#define SUPPORT_FILTER_OUTLINER(soops_) ELEM((soops_)->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS) /* Outliner Searching -- * @@ -171,18 +179,20 @@ typedef enum { * - not searching into RNA items helps but isn't the complete solution */ -#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE) +#define SEARCHING_OUTLINER(sov) ((sov->search_flags & SO_SEARCH_RECURSIVE) && (sov->filter & SO_FILTER_SEARCH)) /* is the currrent element open? if so we also show children */ #define TSELEM_OPEN(telm, sv) ( (telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) ) /* outliner_tree.c ----------------------------------------------- */ -void outliner_free_tree(ListBase *lb); +void outliner_free_tree(ListBase *tree); void outliner_cleanup_tree(struct SpaceOops *soops); +void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree); void outliner_remove_treestore_element(struct SpaceOops *soops, TreeStoreElem *tselem); -void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops); +void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct ViewLayer *view_layer, + struct SpaceOops *soops, struct ARegion *ar); /* outliner_draw.c ---------------------------------------------- */ @@ -203,6 +213,10 @@ int outliner_item_do_activate_from_cursor( struct bContext *C, const int mval[2], bool extend, bool recursive); +void outliner_item_select( + struct SpaceOops *soops, const struct TreeElement *te, + const bool extend, const bool toggle); + /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_cb)( struct bContext *C, struct ReportList *, struct Scene *scene, @@ -260,6 +274,8 @@ void id_remap_cb( TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); +void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops); + /* ...................................................... */ void OUTLINER_OT_highlight_update(struct wmOperatorType *ot); @@ -328,11 +344,11 @@ void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_override_new(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); -void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); + +void OUTLINER_OT_collection_objects_add(struct wmOperatorType *ot); +void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_delete_selected(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 856dd022c14..52f27b9708e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -33,9 +33,13 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_main.h" +#include "GPU_immediate.h" + #include "RNA_access.h" #include "UI_interface.h" @@ -48,6 +52,11 @@ #include "outliner_intern.h" +typedef struct OutlinerDragDropTooltip { + TreeElement *te; + void *handle; +} OutlinerDragDropTooltip; + enum { OUTLINER_ITEM_DRAG_CANCEL, OUTLINER_ITEM_DRAG_CONFIRM, @@ -58,7 +67,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS); + ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS, SO_GROUPS); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -69,9 +78,15 @@ static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *a return outliner_find_item_at_y(soops, &soops->tree, my); } -static void outliner_item_drag_end(TreeElement *dragged_te) +static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data) { - MEM_SAFE_FREE(dragged_te->drag_data); + MEM_SAFE_FREE(data->te->drag_data); + + if (data->handle) { + WM_draw_cb_exit(win, data->handle); + } + + MEM_SAFE_FREE(data); } static void outliner_item_drag_get_insert_data( @@ -164,8 +179,35 @@ static void outliner_item_drag_handle( te_dragged->drag_data->insert_handle = te_insert_handle; } -static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) +/** + * Returns true if it is a collection and empty. + */ +static bool is_empty_collection(TreeElement *te) +{ + if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { + return false; + } + + SceneCollection *scene_collection; + if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) { + scene_collection = (SceneCollection *)te->directdata; + } + else { + BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION); + scene_collection = ((LayerCollection *)te->directdata)->scene_collection; + } + + return BLI_listbase_is_empty(&scene_collection->objects) && + BLI_listbase_is_empty(&scene_collection->scene_collections); +} + +static bool outliner_item_drag_drop_apply( + Main *bmain, + SpaceOops *soops, + OutlinerDragDropTooltip *data, + const wmEvent *event) { + TreeElement *dragged_te = data->te; TreeElement *insert_handle = dragged_te->drag_data->insert_handle; TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; @@ -178,7 +220,16 @@ static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) /* call of assert above should not have changed insert_handle and insert_type at this point */ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && dragged_te->drag_data->insert_type == insert_type); - dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type); + + /* If the collection was just created and you moved objects/collections inside it, + * it is strange to have it closed and we not see the newly dragged elements. */ + const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); + + dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event); + + if (should_open_collection && !is_empty_collection(insert_handle)) { + TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; + } return true; } @@ -190,7 +241,8 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv Main *bmain = CTX_data_main(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te_dragged = op->customdata; + OutlinerDragDropTooltip *data = op->customdata; + TreeElement *te_dragged = data->te; int retval = OPERATOR_RUNNING_MODAL; bool redraw = false; bool skip_rebuild = true; @@ -198,7 +250,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, te_dragged)) { + if (outliner_item_drag_drop_apply(bmain, soops, data, event)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -210,7 +262,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv BLI_assert(0); } WM_event_add_mousemove(C); /* update highlight */ - outliner_item_drag_end(te_dragged); + outliner_item_drag_end(CTX_wm_window(C), data); redraw = true; break; case MOUSEMOVE: @@ -229,6 +281,93 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv return retval; } +/** + * Check if the given TreeElement is a collection + * + * This test is mainly used to see if next/prev TreeElement is a collection. + * It will fail when there is no next/prev TreeElement, or when the + * element is an Override or something else in the future. + */ +static bool tree_element_is_collection_get(const TreeElement *te) { + if (te == NULL) { + return false; + } + + TreeStoreElem *tselem = TREESTORE(te); + return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); +} + +static const char *outliner_drag_drop_tooltip_get( + const TreeElement *te_float) +{ + const char *name = NULL; + + const TreeElement *te_insert = te_float->drag_data->insert_handle; + if (tree_element_is_collection_get(te_float)) { + if (te_insert == NULL) { + name = TIP_("Move collection"); + } + else { + switch (te_float->drag_data->insert_type) { + case TE_INSERT_BEFORE: + if (tree_element_is_collection_get(te_insert->prev)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move before collection"); + } + break; + case TE_INSERT_AFTER: + if (tree_element_is_collection_get(te_insert->next)) { + name = TIP_("Move between collections"); + } + else { + name = TIP_("Move after collection"); + } + break; + case TE_INSERT_INTO: + name = TIP_("Move inside collection"); + break; + } + } + } + else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { + name = TIP_("Move to collection (Ctrl to add)"); + } + + return name; +} + +static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) +{ + OutlinerDragDropTooltip *data = vdata; + const char *tooltip; + + int cursorx, cursory; + int x, y; + + tooltip = outliner_drag_drop_tooltip_get(data->te); + if (tooltip == NULL) { + return; + } + + cursorx = win->eventstate->x; + cursory = win->eventstate->y; + + x = cursorx + U.widget_unit; + y = cursory - U.widget_unit; + + /* Drawing. */ + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + + const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; + + glEnable(GL_BLEND); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg); + glDisable(GL_BLEND); +} + static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -239,7 +378,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } - op->customdata = te_dragged; + OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__); + data->te = te_dragged; + + op->customdata = data; te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__); /* by default we don't change the item position */ te_dragged->drag_data->insert_handle = te_dragged; @@ -251,6 +393,8 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE WM_event_add_modal_handler(C, op); + data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data); + return OPERATOR_RUNNING_MODAL; } @@ -330,11 +474,11 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); - WM_operatortype_append(OUTLINER_OT_collection_override_new); + + WM_operatortype_append(OUTLINER_OT_collection_nested_new); + WM_operatortype_append(OUTLINER_OT_collection_delete_selected); WM_operatortype_append(OUTLINER_OT_collection_objects_add); WM_operatortype_append(OUTLINER_OT_collection_objects_remove); - WM_operatortype_append(OUTLINER_OT_collection_objects_select); - WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) @@ -432,6 +576,9 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0); + outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 08b5f337936..b9222e62bb0 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -97,8 +97,8 @@ static eOLDrawState tree_element_active_renderlayer( /** * Select object tree: - * CTRL+LMB: Select/Deselect object and all cildren - * CTRL+SHIFT+LMB: Add/Remove object and all children + * CTRL+LMB: Select/Deselect object and all children. + * CTRL+SHIFT+LMB: Add/Remove object and all children. */ static void do_outliner_object_select_recursive(ViewLayer *view_layer, Object *ob_parent, bool select) { @@ -185,7 +185,7 @@ static eOLDrawState tree_element_set_active_object( if (recursive) { /* Recursive select/deselect for Object hierarchies */ - do_outliner_object_select_recursive(view_layer, ob, (ob->flag & SELECT) != 0); + do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0); } if (set != OL_SETSEL_NONE) { @@ -973,7 +973,7 @@ static void do_outliner_item_activate_tree_element( * \param extend: Don't deselect other items, only modify \a te. * \param toggle: Select \a te when not selected, deselect when selected. */ -static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) +void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle) { TreeStoreElem *tselem = TREESTORE(te); const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); @@ -1005,7 +1005,7 @@ static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_ static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x) { - return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) && + return ((soops->outlinevis != SO_DATABLOCKS) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 99fd539293f..9f0165d1272 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,7 @@ #include "BKE_group.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_main.h" @@ -454,6 +455,19 @@ static void id_local_cb( } } +static void id_static_override_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); + ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + } + } +} + static void id_fake_user_set_cb( bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) @@ -1002,9 +1016,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", 0, "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, - {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, - {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, - {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1117,6 +1128,7 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) typedef enum eOutliner_PropGroupOps { OL_GROUPOP_UNLINK = 1, OL_GROUPOP_LOCAL, + OL_GROUPOP_STATIC_OVERRIDE, OL_GROUPOP_LINK, OL_GROUPOP_DELETE, OL_GROUPOP_REMAP, @@ -1130,6 +1142,8 @@ typedef enum eOutliner_PropGroupOps { static const EnumPropertyItem prop_group_op_types[] = { {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, + {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", + 0, "Add Static Override", "Add a local static override of that group"}, {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""}, {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", @@ -1161,6 +1175,9 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) case OL_GROUPOP_LOCAL: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); break; + case OL_GROUPOP_STATIC_OVERRIDE: + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + break; case OL_GROUPOP_LINK: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); break; @@ -1213,6 +1230,7 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, + OUTLINER_IDOP_STATIC_OVERRIDE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1228,6 +1246,8 @@ typedef enum eOutlinerIdOpTypes { static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, + {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", + 0, "Add Static Override", "Add a local static override of this data-block"}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"}, {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", @@ -1297,6 +1317,13 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Localized Data"); break; } + case OUTLINER_IDOP_STATIC_OVERRIDE: + { + /* make local */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + ED_undo_push(C, "Overrided Data"); + break; + } case OUTLINER_IDOP_SINGLE: { /* make single user */ @@ -1841,7 +1868,7 @@ static const EnumPropertyItem *outliner_collection_operation_type_itemf( switch (soops->outlinevis) { case SO_GROUPS: return prop_collection_op_group_internal_types; - case SO_ACT_LAYER: + case SO_VIEW_LAYER: return prop_collection_op_none_types; } return NULL; @@ -2021,7 +2048,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } } else if (objectlevel) { - WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); + WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); } else if (idlevel) { if (idlevel == -1 || datalevel) { @@ -2066,6 +2093,9 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_LAYER_COLLECTION) { WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); } + else if (datalevel == TSE_SCENE_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN); + } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index a9c9ab74970..06b3319935d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -71,6 +71,7 @@ #include "BKE_idcode.h" #include "BKE_outliner_treehash.h" +#include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "ED_armature.h" @@ -81,6 +82,8 @@ #include "RNA_access.h" +#include "UI_interface.h" + #include "outliner_intern.h" #ifdef WIN32 @@ -89,7 +92,11 @@ /* prototypes */ static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten); + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, + const bool show_objects); +static void outliner_add_view_layer( + SpaceOops *soops, ListBase *tree, TreeElement *parent, + Scene *scene, ViewLayer *layer, const bool show_objects); static void outliner_make_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -189,16 +196,11 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty /* ********************************************************* */ /* Tree Management */ -void outliner_free_tree(ListBase *lb) +void outliner_free_tree(ListBase *tree) { - while (lb->first) { - TreeElement *te = lb->first; - - outliner_free_tree(&te->subtree); - BLI_remlink(lb, te); - - if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); - MEM_freeN(te); + for (TreeElement *element = tree->first, *element_next; element; element = element_next) { + element_next = element->next; + outliner_free_tree_element(element, tree); } } @@ -208,6 +210,25 @@ void outliner_cleanup_tree(SpaceOops *soops) outliner_storage_cleanup(soops); } +/** + * Free \a element and its sub-tree and remove its link in \a parent_subtree. + * + * \note Does not remove the TreeStoreElem of \a element! + * \param parent_subtree Subtree of the parent element, so the list containing \a element. + */ +void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) +{ + BLI_assert(BLI_findindex(parent_subtree, element) > -1); + BLI_remlink(parent_subtree, element); + + outliner_free_tree(&element->subtree); + + if (element->flag & TE_FREE_NAME) { + MEM_freeN((void *)element->name); + } + MEM_freeN(element); +} + /* ********************************************************* */ @@ -365,12 +386,21 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); int a; - tenla->name = IFACE_("RenderLayers"); + tenla->name = IFACE_("View Layers"); for (a = 0, view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next, a++) { TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a); tenlay->name = view_layer->name; tenlay->directdata = &view_layer->flag; - outliner_add_passes(soops, tenlay, &sce->id, view_layer); + + TreeElement *te_view_layers; + te_view_layers = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0); + te_view_layers->name = IFACE_("Collections"); + outliner_add_view_layer(soops, &te_view_layers->subtree, te_view_layers, sce, view_layer, false); + + TreeElement *te_passes; + te_passes = outliner_add_element(soops, &tenlay->subtree, sce, tenlay, TSE_LAYER_COLLECTION_BASE, 0); + te_passes->name = IFACE_("Passes"); + outliner_add_passes(soops, te_passes, &sce->id, view_layer); } // TODO: move this to the front? @@ -379,20 +409,45 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s outliner_add_element(soops, lb, sce->gpd, te, 0, 0); - outliner_add_element(soops, lb, sce->world, te, 0, 0); - #ifdef WITH_FREESTYLE if (STREQ(sce->view_render->engine_id, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS)) outliner_add_line_styles(soops, lb, sce, te); #endif } +struct ObjectsSelectedData { + ListBase objects_selected_array; +}; + +static TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) +{ + struct ObjectsSelectedData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { + return TRAVERSE_CONTINUE; + } + + if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); + + return TRAVERSE_CONTINUE; +} + +/** + * Move objects from a collection to another. + * We ignore the original object being inserted, we used it for polling only. + * Instead we move all the selected objects around. + */ static void outliner_object_reorder( - Main *UNUSED(bmain), - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + Main *bmain, SpaceOops *soops, + TreeElement *insert_element, + TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *event) { - TreeStoreElem *tselem_insert = TREESTORE(insert_element); - Object *ob = (Object *)tselem_insert->id; SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); SceneCollection *sc_ob_parent = NULL; ID *id = insert_handle->store_elem->id; @@ -400,19 +455,49 @@ static void outliner_object_reorder( BLI_assert(action == TE_INSERT_INTO); UNUSED_VARS_NDEBUG(action); - /* find parent scene-collection of object */ - if (insert_element->parent) { - for (TreeElement *te_ob_parent = insert_element->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { - if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { - sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); - break; + struct ObjectsSelectedData data = { + .objects_selected_array = {NULL, NULL}, + }; + + const bool is_append = event->ctrl; + + /* Make sure we include the originally inserted element as well. */ + TREESTORE(insert_element)->flag |= TSE_SELECTED; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); + BLI_LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { + TreeElement *ten_selected = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(ten_selected)->id; + + if (is_append) { + BKE_collection_object_add(id, sc, ob); + continue; + } + + /* Find parent scene-collection of object. */ + if (ten_selected->parent) { + for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { + if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { + sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); + break; + } } } + else { + sc_ob_parent = BKE_collection_master(id); + } + + BKE_collection_object_move(id, sc, sc_ob_parent, ob); } - else { - sc_ob_parent = BKE_collection_master(id); - } - BKE_collection_object_move(id, sc, sc_ob_parent, ob); + + BLI_freelistN(&data.objects_selected_array); + + DEG_relations_tag_update(bmain); + + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(id, 0); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } static bool outliner_object_reorder_poll( @@ -1202,9 +1287,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->flag |= TE_LAZY_CLOSED; } - if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) { + if ((type != TSE_LAYER_COLLECTION) && (te->idcode == ID_GR)) { Group *group = (Group *)id; - outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL, true); } return te; @@ -1358,7 +1443,9 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) static void outliner_layer_collections_reorder( Main *bmain, - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + SpaceOops *UNUSED(soops), + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { LayerCollection *lc_insert = insert_element->directdata; LayerCollection *lc_handle = insert_handle->directdata; @@ -1393,7 +1480,8 @@ static bool outliner_layer_collections_reorder_poll( } static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten) + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, + const bool show_objects) { for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); @@ -1403,23 +1491,29 @@ static void outliner_add_layer_collections_recursive( ten->reinsert = outliner_layer_collections_reorder; ten->reinsert_poll = outliner_layer_collections_reorder_poll; - outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten); - for (LinkData *link = collection->object_bases.first; link; link = link->next) { - Base *base = (Base *)link->data; - TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); - te_object->directdata = base; + outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten, show_objects); + if (show_objects) { + for (LinkData *link = collection->object_bases.first; link; link = link->next) { + Base *base = (Base *)link->data; + TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); + te_object->directdata = base; + } } outliner_make_hierarchy(&ten->subtree); } } -static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer) + +static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent, + Scene *scene, ViewLayer *layer, const bool show_objects) { - outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, tree, &scene->id, &layer->layer_collections, parent, show_objects); } static void outliner_scene_collections_reorder( Main *bmain, - TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) + SpaceOops *UNUSED(soops), + TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, + const wmEvent *UNUSED(event)) { SceneCollection *sc_insert = insert_element->directdata; SceneCollection *sc_handle = insert_handle->directdata; @@ -1474,35 +1568,46 @@ static bool outliner_scene_collections_reorder_poll( return true; } -static void outliner_add_scene_collection_objects( +BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, SceneCollection *collection) +{ + te->name = collection->name; + te->directdata = collection; + te->reinsert = outliner_scene_collections_reorder; + te->reinsert_poll = outliner_scene_collections_reorder_poll; +} + +BLI_INLINE void outliner_add_scene_collection_objects( SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent) { for (LinkData *link = collection->objects.first; link; link = link->next) { outliner_add_element(soops, tree, link->data, parent, 0, 0); } - outliner_make_hierarchy(tree); } -static void outliner_add_scene_collections_recursive( - SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten) +static TreeElement *outliner_add_scene_collection_recursive( + SpaceOops *soops, ListBase *tree, ID *id, SceneCollection *scene_collection, TreeElement *parent_ten) { - for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) { - TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0); + TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_SCENE_COLLECTION, 0); + outliner_add_scene_collection_init(ten, scene_collection); + outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten); - ten->name = collection->name; - ten->directdata = collection; - ten->reinsert = outliner_scene_collections_reorder; - ten->reinsert_poll = outliner_scene_collections_reorder_poll; - - outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten); - outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten); + for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested != NULL; + scene_collection_nested = scene_collection_nested->next) + { + outliner_add_scene_collection_recursive(soops, &ten->subtree, id, scene_collection_nested, ten); } + + outliner_make_hierarchy(&ten->subtree); + return ten; } -static void outliner_add_collections_master(SpaceOops *soops, Scene *scene) + +static void outliner_add_collections(SpaceOops *soops, Scene *scene) { - SceneCollection *master = BKE_collection_master(&scene->id); - outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL); - outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL); + SceneCollection *master_collection = BKE_collection_master(&scene->id); + TreeElement *ten = outliner_add_scene_collection_recursive(soops, &soops->tree, &scene->id, master_collection, NULL); + /* Master Collection should always be expanded. */ + TREESTORE(ten)->flag &= ~TSE_CLOSED; } /* ======================================================= */ @@ -1676,6 +1781,305 @@ static void outliner_sort(ListBase *lb) /* Filtering ----------------------------------------------- */ +typedef struct OutlinerTreeElementFocus { + TreeStoreElem *tselem; + int ys; +} OutlinerTreeElementFocus; + +/** + * Bring the outliner scrolling back to where it was in relation to the original focus element + * Caller is expected to handle redrawing of ARegion. + */ +static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +{ + View2D *v2d = &ar->v2d; + int ytop; + + if (focus->tselem != NULL) { + outliner_set_coordinates(ar, soops); + + TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem); + + if (te_new != NULL) { + int ys_new, ys_old; + + ys_new = te_new->ys; + ys_old = focus->ys; + + ytop = v2d->cur.ymax + (ys_new - ys_old) -1; + if (ytop > 0) ytop = 0; + + v2d->cur.ymax = (float)ytop; + v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); + } + else { + return; + } + + soops->storeflag |= SO_TREESTORE_REDRAW; + } +} + +static bool test_collection_callback(TreeElement *te) +{ + TreeStoreElem *tselem = TREESTORE(te); + return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); +} + +static bool test_object_callback(TreeElement *te) +{ + TreeStoreElem *tselem = TREESTORE(te); + return ((tselem->type == 0) && (te->idcode == ID_OB)); +} + +/** + * See if TreeElement or any of its children pass the callback_test. + */ +static TreeElement *outliner_find_first_desired_element_at_y_recursive( + const SpaceOops *soops, + TreeElement *te, + const float limit, + bool (*callback_test)(TreeElement *)) +{ + if (callback_test(te)) { + return te; + } + + if (TSELEM_OPEN(te->store_elem, soops)) { + TreeElement *te_iter, *te_sub; + for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) { + te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test); + if (te_sub != NULL) { + return te_sub; + } + } + } + + return NULL; +} + +/** + * Find the first element that passes a test starting from a reference vertical coordinate + * + * If the element that is in the position is not what we are looking for, keep looking for its + * children, siblings, and eventually, aunts, cousins, disntant families, ... + * + * Basically we keep going up and down the outliner tree from that point forward, until we find + * what we are looking for. If we are past the visible range and we can't find a valid element + * we return NULL. + */ +static TreeElement *outliner_find_first_desired_element_at_y( + const SpaceOops *soops, + const float view_co, + const float view_co_limit) +{ + TreeElement *te, *te_sub; + te = outliner_find_item_at_y(soops, &soops->tree, view_co); + + bool (*callback_test)(TreeElement *); + if (soops->filter & SO_FILTER_NO_COLLECTION) { + callback_test = test_object_callback; + } + else { + callback_test = test_collection_callback; + } + + while (te != NULL) { + te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test); + if (te_sub != NULL) { + /* Skip the element if it was not visible to start with. */ + if (te->ys + UI_UNIT_Y > view_co_limit) { + return te_sub; + } + else { + return NULL; + } + } + + if (te->next) { + te = te->next; + continue; + } + + if (te->parent == NULL) { + break; + } + + while (te->parent) { + if (te->parent->next) { + te = te->parent->next; + break; + } + te = te->parent; + } + } + + return NULL; +} + +/** + * Store information of current outliner scrolling status to be restored later + * + * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus + * struct to retrieve this element later to make sure it is in the same original position as before filtering + */ +static void outliner_store_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +{ + TreeElement *te; + float limit = ar->v2d.cur.ymin; + + outliner_set_coordinates(ar, soops); + + te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit); + + if (te != NULL) { + focus->tselem = TREESTORE(te); + focus->ys = te->ys; + } + else { + focus->tselem = NULL; + } +} + +static int outliner_exclude_filter_get(SpaceOops *soops) +{ + int exclude_filter = soops->filter & ~(SO_FILTER_OB_STATE_VISIBLE | + SO_FILTER_OB_STATE_SELECTED | + SO_FILTER_OB_STATE_ACTIVE); + + if (soops->filter & SO_FILTER_SEARCH) { + if (soops->search_string[0] == 0) { + exclude_filter &= ~SO_FILTER_SEARCH; + } + } + + /* Let's have this for the collection options at first. */ + if (!SUPPORT_FILTER_OUTLINER(soops)) { + return (exclude_filter & SO_FILTER_SEARCH); + } + + if ((exclude_filter & SO_FILTER_NO_OB_ALL) == 0) { + exclude_filter &= ~SO_FILTER_OB_TYPE; + } + + if (exclude_filter & SO_FILTER_OB_STATE) { + switch (soops->filter_state) { + case SO_FILTER_OB_VISIBLE: + exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; + break; + case SO_FILTER_OB_SELECTED: + exclude_filter |= SO_FILTER_OB_STATE_SELECTED; + break; + case SO_FILTER_OB_ACTIVE: + exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; + break; + } + } + + if ((exclude_filter & SO_FILTER_ANY) == 0) { + exclude_filter &= ~(SO_FILTER_OB_STATE); + } + + return exclude_filter; +} + +static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter) +{ + if ((exclude_filter & SO_FILTER_ENABLE) == 0) { + return true; + } + + TreeStoreElem *tselem = TREESTORE(te); + if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((exclude_filter & SO_FILTER_NO_OBJECT)) { + return false; + } + + Object *ob = (Object *)tselem->id; + Base *base = (Base *)te->directdata; + BLI_assert((base == NULL) || (base->object == ob)); + + if (exclude_filter & SO_FILTER_OB_TYPE) { + switch (ob->type) { + case OB_MESH: + if (exclude_filter & SO_FILTER_NO_OB_MESH) { + return false; + } + break; + case OB_ARMATURE: + if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) { + return false; + } + break; + case OB_EMPTY: + if (exclude_filter & SO_FILTER_NO_OB_EMPTY) { + return false; + } + break; + case OB_LAMP: + if (exclude_filter & SO_FILTER_NO_OB_LAMP) { + return false; + } + break; + case OB_CAMERA: + if (exclude_filter & SO_FILTER_NO_OB_CAMERA) { + return false; + } + break; + default: + if (exclude_filter & SO_FILTER_NO_OB_OTHERS) { + return false; + } + break; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE) { + if (base == NULL) { + base = BKE_view_layer_base_find(view_layer, ob); + + if (base == NULL) { + return false; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { + if ((base->flag & BASE_VISIBLED) == 0) { + return false; + } + } + else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) { + if ((base->flag & BASE_SELECTED) == 0) { + return false; + } + } + else { + BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE); + if (base != BASACT(view_layer)) { + return false; + } + } + } + + if ((te->parent != NULL) && + (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB)) + { + if (exclude_filter & SO_FILTER_NO_CHILDREN) { + return false; + } + } + } + else if (te->parent != NULL && + TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) + { + if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { + return false; + } + } + + return true; +} + static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags) { int fn_flag = 0; @@ -1686,31 +2090,25 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag return fnmatch(name, te->name, fn_flag) == 0; } -static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) +static int outliner_filter_subtree( + SpaceOops *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter) { - TreeElement *te, *ten; + TreeElement *te, *te_next; TreeStoreElem *tselem; - char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; - char *search_string; - /* although we don't have any search string, we return true - * since the entire tree is ok then... - */ - if (soops->search_string[0] == 0) - return 1; + for (te = lb->first; te; te = te_next) { + te_next = te->next; - if (soops->search_flags & SO_FIND_COMPLETE) { - search_string = soops->search_string; - } - else { - /* Implicitly add heading/trailing wildcards if needed. */ - BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); - search_string = search_buff; - } + if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { + outliner_free_tree_element(te, lb); + continue; + } + else if ((exclude_filter & SO_FILTER_SEARCH) == 0) { + /* Filter subtree too. */ + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); + continue; + } - for (te = lb->first; te; te = ten) { - ten = te->next; - if (!outliner_filter_has_name(te, search_string, soops->search_flags)) { /* item isn't something we're looking for, but... * - if the subtree is expanded, check if there are any matches that can be easily found @@ -1719,39 +2117,60 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb) * so these can be safely ignored (i.e. the subtree can get freed) */ tselem = TREESTORE(te); - + /* flag as not a found item */ tselem->flag &= ~TSE_SEARCHMATCH; - if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) { - outliner_free_tree(&te->subtree); - BLI_remlink(lb, te); - - if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name); - MEM_freeN(te); + if ((!TSELEM_OPEN(tselem, soops)) || + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0) + { + outliner_free_tree_element(te, lb); } } else { tselem = TREESTORE(te); - + /* flag as a found item - we can then highlight it */ tselem->flag |= TSE_SEARCHMATCH; - + /* filter subtree too */ - outliner_filter_tree(soops, &te->subtree); + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); } } - + /* if there are still items in the list, that means that there were still some matches */ return (BLI_listbase_is_empty(lb) == false); } +static void outliner_filter_tree(SpaceOops *soops, ViewLayer *view_layer) +{ + char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2]; + char *search_string; + + const int exclude_filter = outliner_exclude_filter_get(soops); + + if (exclude_filter == 0) { + return; + } + + if (soops->search_flags & SO_FIND_COMPLETE) { + search_string = soops->search_string; + } + else { + /* Implicitly add heading/trailing wildcards if needed. */ + BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); + search_string = search_buff; + } + + outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter); +} + /* ======================================================= */ /* Main Tree Building API */ /* Main entry point for building the tree data-structure that the outliner represents */ // TODO: split each mode into its own function? -void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops) +void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, ARegion *ar) { TreeElement *te = NULL, *ten; TreeStoreElem *tselem; @@ -1773,6 +2192,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW)) return; + OutlinerTreeElementFocus focus; + outliner_store_scrolling_position(soops, ar, &focus); + outliner_free_tree(&soops->tree); outliner_storage_cleanup(soops); @@ -1826,51 +2248,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa lib->id.newid = NULL; } - else if (soops->outlinevis == SO_ALL_SCENES) { + else if (soops->outlinevis == SO_SCENES) { Scene *sce; for (sce = mainvar->scene.first; sce; sce = sce->id.next) { te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0); tselem = TREESTORE(te); - if (sce == scene && show_opened) - tselem->flag &= ~TSE_CLOSED; - FOREACH_SCENE_OBJECT(scene, ob) - { - outliner_add_element(soops, &te->subtree, ob, te, 0, 0); + if (sce == scene && show_opened) { + tselem->flag &= ~TSE_CLOSED; } - FOREACH_SCENE_OBJECT_END outliner_make_hierarchy(&te->subtree); - - /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ - FOREACH_SCENE_OBJECT(scene, ob) - { - ob->id.newid = NULL; - } - FOREACH_SCENE_OBJECT_END } } - else if (soops->outlinevis == SO_CUR_SCENE) { - - outliner_add_scene_contents(soops, &soops->tree, scene, NULL); - - FOREACH_SCENE_OBJECT(scene, ob) - { - outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); - } - FOREACH_SCENE_OBJECT_END - outliner_make_hierarchy(&soops->tree); - } - else if (soops->outlinevis == SO_VISIBLE) { - FOREACH_VISIBLE_BASE(view_layer, base) - { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; - - } - FOREACH_VISIBLE_BASE_END - outliner_make_hierarchy(&soops->tree); - } else if (soops->outlinevis == SO_GROUPS) { Group *group; for (group = mainvar->group.first; group; group = group->id.next) { @@ -1878,28 +2268,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_make_hierarchy(&te->subtree); } } - else if (soops->outlinevis == SO_SAME_TYPE) { - Object *ob_active = OBACT(view_layer); - if (ob_active) { - FOREACH_SCENE_OBJECT(scene, ob) - { - if (ob->type == ob_active->type) { - outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); - } - } - FOREACH_SCENE_OBJECT_END - outliner_make_hierarchy(&soops->tree); - } - } - else if (soops->outlinevis == SO_SELECTED) { - FOREACH_SELECTED_BASE(view_layer, base) - { - ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - ten->directdata = base; - } - FOREACH_SELECTED_BASE_END - outliner_make_hierarchy(&soops->tree); - } else if (soops->outlinevis == SO_SEQUENCE) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, false); @@ -1936,36 +2304,47 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa tselem->flag &= ~TSE_CLOSED; } } - else if (soops->outlinevis == SO_USERDEF) { - PointerRNA userdefptr; - - RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr); - - ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1); - - if (show_opened) { - tselem = TREESTORE(ten); - tselem->flag &= ~TSE_CLOSED; - } - } else if (soops->outlinevis == SO_ID_ORPHANS) { outliner_add_orphaned_datablocks(mainvar, soops); } - else if (soops->outlinevis == SO_ACT_LAYER) { - outliner_add_collections_act_layer(soops, scene, view_layer); + else if (soops->outlinevis == SO_VIEW_LAYER) { + if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); + te_object->directdata = base; + } + outliner_make_hierarchy(&soops->tree); + } + else { + outliner_add_view_layer(soops, &soops->tree, NULL, scene, view_layer, true); + } } else if (soops->outlinevis == SO_COLLECTIONS) { - outliner_add_collections_master(soops, scene); + if ((soops->filter & SO_FILTER_ENABLE) && (soops->filter & SO_FILTER_NO_COLLECTION)) { + FOREACH_SCENE_OBJECT(scene, ob) + { + outliner_add_element(soops, &soops->tree, ob, NULL, 0, 0); + } + FOREACH_SCENE_OBJECT_END + outliner_make_hierarchy(&soops->tree); + } + else { + outliner_add_collections(soops, scene); + } } else { - ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); - ten->directdata = BASACT(view_layer); + if (BASACT(view_layer)) { + ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); + ten->directdata = BASACT(view_layer); + } } if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { outliner_sort(&soops->tree); } - outliner_filter_tree(soops, &soops->tree); + + outliner_filter_tree(soops, view_layer); + outliner_restore_scrolling_position(soops, ar, &focus); BKE_main_id_clear_newpoins(mainvar); } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 1bc1a227a03..1529e6143c3 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -48,6 +48,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_message.h" #include "WM_types.h" #include "BIF_gl.h" @@ -162,7 +163,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { + if (!ELEM(soops->outlinevis, SO_SCENES, SO_GROUPS, SO_VIEW_LAYER, SO_COLLECTIONS)) { return false; } @@ -423,6 +424,24 @@ static void outliner_main_region_listener( } +static void outliner_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceOops *soops = sa->spacedata.first; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)) { + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + } +} + /* ************************ header outliner area region *********************** */ @@ -576,6 +595,7 @@ void ED_spacetype_outliner(void) art->draw = outliner_main_region_draw; art->free = outliner_main_region_free; art->listener = outliner_main_region_listener; + art->message_subscribe = outliner_main_region_message_subscribe; BLI_addhead(&st->regiontypes, art); /* regions: header */ diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8f6eb064b0d..cb0c5bd3717 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2190,23 +2190,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq; MetaStack *ms; - bool nothingSelected = true; + bool nothing_selected = true; seq = BKE_sequencer_active_get(scene); if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */ - nothingSelected = false; + nothing_selected = false; } else { for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - nothingSelected = false; + nothing_selected = false; break; } } } - if (nothingSelected) + if (nothing_selected) { return OPERATOR_FINISHED; + } /* for effects and modifiers, try to find a replacement input */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index 80cb42c0b3d..c5d6edadb53 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -459,13 +459,15 @@ typedef struct MakeHistogramViewData { } MakeHistogramViewData; static void make_histogram_view_from_ibuf_byte_cb_ex( - void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict tls) { MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; const unsigned char *src = (unsigned char *)ibuf->rect; - uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; + uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk; for (int x = 0; x < ibuf->x; x++) { const unsigned char *pixel = src + (y * ibuf->x + x) * 4; @@ -476,7 +478,8 @@ static void make_histogram_view_from_ibuf_byte_cb_ex( } } -static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk) +static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) { MakeHistogramViewData *data = userdata; uint32_t (*bins)[HIS_STEPS] = data->bins; @@ -501,9 +504,17 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) memset(bins, 0, sizeof(bins)); MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; - BLI_task_parallel_range_finalize( - 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex, - make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (ibuf->y >= 256); + settings.userdata_chunk = bins; + settings.userdata_chunk_size = sizeof(bins); + settings.func_finalize = make_histogram_view_from_ibuf_finalize; + BLI_task_parallel_range( + 0, ibuf->y, + &data, + make_histogram_view_from_ibuf_byte_cb_ex, + &settings); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { @@ -548,13 +559,15 @@ BLI_INLINE int get_bin_float(float f) } static void make_histogram_view_from_ibuf_float_cb_ex( - void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) + void *__restrict userdata, + const int y, + const ParallelRangeTLS *__restrict tls) { const MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; const float *src = ibuf->rect_float; - uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk; + uint32_t (*cur_bins)[HIS_STEPS] = tls->userdata_chunk; for (int x = 0; x < ibuf->x; x++) { const float *pixel = src + (y * ibuf->x + x) * 4; @@ -576,9 +589,17 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) memset(bins, 0, sizeof(bins)); MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins}; - BLI_task_parallel_range_finalize( - 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex, - make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (ibuf->y >= 256); + settings.userdata_chunk = bins; + settings.userdata_chunk_size = sizeof(bins); + settings.func_finalize = make_histogram_view_from_ibuf_finalize; + BLI_task_parallel_range( + 0, ibuf->y, + &data, + make_histogram_view_from_ibuf_float_cb_ex, + &settings); nr = nb = ng = 0; for (x = 0; x < HIS_STEPS; x++) { diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index fcb675abcf2..62fde49cade 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -596,7 +596,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) drawcache->total_lines = 0; if (st->showlinenrs) - st->linenrs_tot = (int)floor(log10((float)nlines)) + 1; + st->linenrs_tot = integer_digits_i(nlines); while (line) { if (drawcache->valid_head) { /* we're inside valid head lines */ @@ -630,7 +630,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) nlines = BLI_listbase_count(&txt->lines); if (st->showlinenrs) - st->linenrs_tot = (int)floor(log10((float)nlines)) + 1; + st->linenrs_tot = integer_digits_i(nlines); } drawcache->total_lines = nlines; diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index de8380aa8bb..d148ef3c6fe 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -64,6 +64,8 @@ set(SRC view3d_manipulator_empty.c view3d_manipulator_forcefield.c view3d_manipulator_lamp.c + view3d_manipulator_navigate.c + view3d_manipulator_navigate_type.c view3d_manipulator_ruler.c view3d_ops.c view3d_project.c @@ -71,6 +73,7 @@ set(SRC view3d_select.c view3d_snap.c view3d_toolbar.c + view3d_utils.c view3d_view.c view3d_intern.h diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 66355a50478..9fa85b55362 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -77,15 +77,15 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar) } /* set color -* - more intense for active/selected bones, less intense for unselected bones -* - black for before current frame, green for current frame, blue for after current frame -* - intensity decreases as distance from current frame increases -* -* If the user select custom color, the color is replaced for the color selected in UI panel -* - 75% Darker color is used for previous frames -* - 50% Darker color for current frame -* - User selected color for next frames -*/ + * - more intense for active/selected bones, less intense for unselected bones + * - black for before current frame, green for current frame, blue for after current frame + * - intensity decreases as distance from current frame increases + * + * If the user select custom color, the color is replaced for the color selected in UI panel + * - 75% Darker color is used for previous frames + * - 50% Darker color for current frame + * - User selected color for next frames + */ static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, float prev_color[3], float frame_color[3], float next_color[3], unsigned color) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 08ef9cc21cb..51dc56bafaf 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -980,14 +980,12 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write) col_pack_prev = vos->col.pack; } - ((vos->flag & V3D_CACHE_TEXT_ASCII) ? - BLF_draw_default_ascii : - BLF_draw_default - )((float)(vos->sco[0] + vos->xoffs), - (float)(vos->sco[1]), - (depth_write) ? 0.0f : 2.0f, - vos->str, - vos->str_len); + ((vos->flag & V3D_CACHE_TEXT_ASCII) ? BLF_draw_default_ascii : BLF_draw_default)( + (float)(vos->sco[0] + vos->xoffs), + (float)(vos->sco[1]), + (depth_write) ? 0.0f : 2.0f, + vos->str, + vos->str_len); } } @@ -1036,7 +1034,7 @@ static void drawcube_size(float size, unsigned pos) { size, size, size} }; - const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6}; + const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6}; #if 0 glEnableClientState(GL_VERTEX_ARRAY); @@ -6098,46 +6096,46 @@ static void draw_new_particle_system( /* 4. */ if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) { - int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); + int partsize = 3 * sizeof(float); int create_ndata = 0; if (!pdd) pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData"); if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { - tot_vec_size *= part->trail_count; + partsize *= part->trail_count; psys_make_temp_pointcache(ob, psys); } switch (draw_as) { case PART_DRAW_AXIS: case PART_DRAW_CROSS: - tot_vec_size *= 6; + partsize *= 6; if (draw_as != PART_DRAW_CROSS) create_cdata = 1; break; case PART_DRAW_LINE: - tot_vec_size *= 2; + partsize *= 2; break; case PART_DRAW_BB: - tot_vec_size *= 6; /* New OGL only understands tris, no choice here. */ + partsize *= 6; /* New OGL only understands tris, no choice here. */ create_ndata = 1; break; } - if (pdd->tot_vec_size != tot_vec_size) + if (pdd->totpart != totpart + totchild || pdd->partsize != partsize) psys_free_pdd(psys); if (!pdd->vdata) - pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata"); + pdd->vdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_vdata"); if (create_cdata && !pdd->cdata) - pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata"); + pdd->cdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_cdata"); if (create_ndata && !pdd->ndata) - pdd->ndata = MEM_callocN(tot_vec_size, "particle_ndata"); + pdd->ndata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_ndata"); if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { if (!pdd->vedata) - pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata"); + pdd->vedata = MEM_calloc_arrayN(totpart + totchild, 2 * 3 * sizeof(float), "particle_vedata"); need_v = 1; } @@ -6151,7 +6149,8 @@ static void draw_new_particle_system( pdd->ved = pdd->vedata; pdd->cd = pdd->cdata; pdd->nd = pdd->ndata; - pdd->tot_vec_size = tot_vec_size; + pdd->totpart = totpart + totchild; + pdd->partsize = partsize; } else if (psys->pdd) { psys_free_pdd(psys); @@ -6630,7 +6629,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) const int totkeys = (*edit->pathcache)->segments + 1; glEnable(GL_BLEND); - float *pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data"); + float *pathcol = MEM_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data"); if (pset->brushtype == PE_BRUSH_WEIGHT) glLineWidth(2.0f); @@ -6707,8 +6706,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) if (totkeys_visible) { if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO)) - pd = pdata = MEM_callocN(totkeys_visible * 3 * sizeof(float), "particle edit point data"); - cd = cdata = MEM_callocN(totkeys_visible * (timed ? 4 : 3) * sizeof(float), "particle edit color data"); + pd = pdata = MEM_calloc_arrayN(totkeys_visible, 3 * sizeof(float), "particle edit point data"); + cd = cdata = MEM_calloc_arrayN(totkeys_visible, (timed ? 4 : 3) * sizeof(float), "particle edit color data"); } for (i = 0, point = edit->points; i < totpoint; i++, point++) { @@ -7405,7 +7404,7 @@ static void draw_editnurb( } #else /* Same as loop above */ - count += 4 * max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0); + count += 4 * ((nr / (skip + 1)) + ((nr % (skip + 1)) != 0)); #endif } @@ -8066,7 +8065,7 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) if (solid) { /* Adpated from "Optimizing Triangle Strips for Fast Rendering" by F. Evans, S. Skiena and A. Varshney * (http://www.cs.umd.edu/gvil/papers/av_ts.pdf). */ - static const GLubyte tris_strip_indices[14] = {0,1,3,2,6,1,5,0,4,3,7,6,4,5}; + static const GLubyte tris_strip_indices[14] = {0, 1, 3, 2, 6, 1, 5, 0, 4, 3, 7, 6, 4, 5}; immBegin(GWN_PRIM_TRI_STRIP, 14); for (int i = 0; i < 14; ++i) { immVertex3fv(pos, vec[tris_strip_indices[i]]); @@ -8074,7 +8073,8 @@ static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos) immEnd(); } else { - static const GLubyte line_indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7}; + static const GLubyte line_indices[24] = + {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7}; immBegin(GWN_PRIM_LINES, 24); for (int i = 0; i < 24; ++i) { immVertex3fv(pos, vec[line_indices[i]]); @@ -9217,7 +9217,10 @@ afterdraw: /* help lines and so */ if (ob != scene->obedit && ob->parent) { - if (BKE_object_is_visible(ob->parent)) { + const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + if (BKE_object_is_visible(ob->parent, mode)) { setlinestyle(3); immBegin(GWN_PRIM_LINES, 2); immVertex3fv(pos, ob->obmat[3]); @@ -9769,8 +9772,9 @@ void draw_object_backbufsel( bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0); if (ts->selectmode & SCE_SELECT_FACE) bm_solidoffs = 1 + em->bm->totface; - else + else { bm_solidoffs = 1; + } ED_view3d_polygon_offset(rv3d, 1.0); @@ -9779,6 +9783,10 @@ void draw_object_backbufsel( bbs_mesh_wire(em, dm, bm_solidoffs); bm_wireoffs = bm_solidoffs + em->bm->totedge; } + else { + /* `bm_vertoffs` is calculated from `bm_wireoffs`. (otherwise see T53512) */ + bm_wireoffs = bm_solidoffs; + } /* we draw verts if vert select mode. */ if (ts->selectmode & SCE_SELECT_VERTEX) { diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 3a80624acd9..d39f3937a9d 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -41,7 +41,7 @@ #include "BLI_math.h" #include "BKE_DerivedMesh.h" -#include "BKE_texture.h" +#include "BKE_colorband.h" #include "BKE_particle.h" #include "smoke_API.h" @@ -111,7 +111,7 @@ static void create_flame_spectrum_texture(float *data) static void create_color_ramp(const ColorBand *coba, float *data) { for (int i = 0; i < TFUNC_WIDTH; i++) { - do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7cf1573de43..6540a1fb234 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -711,6 +711,9 @@ static void view3d_widgets(void) WM_manipulatorgrouptype_append(VIEW3D_WGT_ruler); WM_manipulatortype_append(VIEW3D_WT_ruler_item); + + WM_manipulatorgrouptype_append_and_link(mmap_type, VIEW3D_WGT_navigate); + WM_manipulatortype_append(VIEW3D_WT_navigate_rotate); } @@ -1055,6 +1058,8 @@ static void view3d_main_region_message_subscribe( /* Only subscribe to types. */ StructRNA *type_array[] = { + &RNA_Window, + /* These object have properties that impact drawing. */ &RNA_AreaLamp, &RNA_Camera, @@ -1102,10 +1107,12 @@ static void view3d_main_region_message_subscribe( extern StructRNA RNA_ViewLayerEngineSettingsEevee; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); } +#ifdef WITH_CLAY_ENGINE else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) { extern StructRNA RNA_ViewLayerEngineSettingsClay; WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); } +#endif } /* concept is to retrieve cursor type context-less */ diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 9b07593e576..c39057431c2 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -138,13 +138,10 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl) * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { View3DCameraControl *vctrl; - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(C, &eval_ctx); vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__); @@ -181,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( /* store the original camera loc and rot */ vctrl->obtfm = BKE_object_tfm_backup(ob_back); - BKE_object_where_is_calc(&eval_ctx, scene, v3d->camera); + BKE_object_where_is_calc(eval_ctx, scene, v3d->camera); negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); rv3d->dist = 0.0; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 6ea2ff10af2..f734bb085d0 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -123,21 +123,28 @@ void ED_view3d_update_viewmat( const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect) { + const Depsgraph *depsgraph = eval_ctx->depsgraph; RegionView3D *rv3d = ar->regiondata; - /* setup window matrices */ if (winmat) copy_m4_m4(rv3d->winmat, winmat); else - view3d_winmatrix_set(ar, v3d, rect); + view3d_winmatrix_set(depsgraph, ar, v3d, rect); /* setup view matrix */ - if (viewmat) + if (viewmat) { copy_m4_m4(rv3d->viewmat, viewmat); - else - view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - + } + else { + float rect_scale[2]; + if (rect) { + rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx; + rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy; + } + /* note: calls BKE_object_where_is_calc for camera... */ + view3d_viewmatrix_set(eval_ctx, scene, v3d, rv3d, rect ? rect_scale : NULL); + } /* update utility matrices */ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); @@ -148,7 +155,7 @@ void ED_view3d_update_viewmat( /* store window coordinates scaling/offset */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { rctf cameraborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); + ED_view3d_calc_camera_border(scene, eval_ctx->depsgraph, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); @@ -307,7 +314,8 @@ void ED_view3d_draw_setup_view( /* ******************** view border ***************** */ static void view3d_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const struct Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift, const bool no_zoom) { CameraParams params; @@ -315,7 +323,7 @@ static void view3d_camera_border( /* get viewport viewplane */ BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); if (no_zoom) params.zoom = 1.0f; BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); @@ -342,21 +350,23 @@ static void view3d_camera_border( } void ED_view3d_calc_camera_border_size( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, float r_size[2]) { rctf viewborder; - view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true); r_size[0] = BLI_rctf_size_x(&viewborder); r_size[1] = BLI_rctf_size_y(&viewborder); } void ED_view3d_calc_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, const Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift) { - view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false); } static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac) @@ -435,7 +445,7 @@ static void drawviewborder_triangle( immEnd(); } -static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) +static void drawviewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { float x1, x2, y1, y2; float x1i, x2i, y1i, y2i; @@ -449,7 +459,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) if (v3d->camera->type == OB_CAMERA) ca = v3d->camera->data; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); /* the offsets */ x1 = viewborder.xmin; y1 = viewborder.ymin; @@ -1318,6 +1328,10 @@ float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) static bool is_cursor_visible(Scene *scene, ViewLayer *view_layer) { + if (U.app_flag & USER_APP_VIEW3D_HIDE_CURSOR) { + return false; + } + Object *ob = OBACT(view_layer); /* don't draw cursor in paint modes, but with a few exceptions */ @@ -1594,11 +1608,12 @@ static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d) static void view3d_draw_border(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; View3D *v3d = CTX_wm_view3d(C); if (rv3d->persp == RV3D_CAMOB) { - drawviewborder(scene, ar, v3d); + drawviewborder(scene, depsgraph, ar, v3d); } else if (v3d->flag2 & V3D_RENDER_BORDER) { drawrenderborder(ar, v3d); @@ -1966,7 +1981,7 @@ void ED_view3d_draw_offscreen( float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, GPUFX *fx, GPUFXSettings *fx_settings, - GPUOffScreen *ofs) + GPUOffScreen *ofs, GPUViewport *viewport) { bool do_compositing = false; RegionView3D *rv3d = ar->regiondata; @@ -2015,6 +2030,10 @@ void ED_view3d_draw_offscreen( else view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL); + /* XXX, should take depsgraph as arg */ + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); + BLI_assert(depsgraph != NULL); + /* main drawing call */ RenderEngineType *engine_type = eval_ctx->engine_type; if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { @@ -2049,7 +2068,7 @@ void ED_view3d_draw_offscreen( if (v3d->flag2 & V3D_SHOW_GPENCIL) { /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(NULL, scene, view_layer, v3d, ar, false); + ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, false); } /* freeing the images again here could be done after the operator runs, leaving for now */ @@ -2057,10 +2076,7 @@ void ED_view3d_draw_offscreen( } } else { - /* XXX, should take depsgraph as arg */ - Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); - BLI_assert(depsgraph != NULL); - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs); + DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, do_sky, ofs, viewport); } /* restore size */ @@ -2090,6 +2106,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( /* output vars */ GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) { + const Depsgraph *depsgraph = eval_ctx->depsgraph; RegionView3D *rv3d = ar->regiondata; const bool draw_sky = (alpha_mode == R_ADDSKY); const bool draw_background = (draw_flags & V3D_OFSDRAW_USE_BACKGROUND); @@ -2109,7 +2126,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, false, err_out); if (ofs == NULL) { return NULL; } @@ -2145,7 +2162,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( rctf viewplane; float clipsta, clipend; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) { orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); } @@ -2159,7 +2176,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); + fx, &fx_settings, ofs, NULL); if (ibuf->rect_float) { GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); @@ -2173,9 +2190,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ static float jit_ofs[32][2]; float winmat_jitter[4][4]; - /* use imbuf as temp storage, before writing into it from accumulation buffer */ - unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; - unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); + float *rect_temp = (ibuf->rect_float) ? ibuf->rect_float : MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp"); + float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer"); + GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs); BLI_jitter_init(jit_ofs, samples); @@ -2183,13 +2200,8 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - unsigned i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] = rect_temp[i]; - } + fx, &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); /* skip the first sample */ for (int j = 1; j < samples; j++) { @@ -2202,27 +2214,38 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ED_view3d_draw_offscreen( eval_ctx, scene, view_layer, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + fx, &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { accum_buffer[i] += rect_temp[i]; } } + { + /* don't free data owned by 'ofs' */ + GPU_viewport_clear_from_offscreen(viewport); + GPU_viewport_free(viewport); + MEM_freeN(viewport); + } + + if (ibuf->rect_float == NULL) { + MEM_freeN(rect_temp); + } + if (ibuf->rect_float) { float *rect_float = ibuf->rect_float; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + rect_float[i] = accum_buffer[i] / samples; } } else { unsigned char *rect_ub = (unsigned char *)ibuf->rect; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_ub[i] = accum_buffer[i] / samples; + rect_ub[i] = (unsigned char)(255.0f * accum_buffer[i] / samples); } } @@ -2383,9 +2406,9 @@ bool VP_legacy_use_depth(Scene *scene, View3D *v3d) return use_depth_doit(scene, v3d); } -void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) +void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { - drawviewborder(scene, ar, v3d); + drawviewborder(scene, depsgraph, ar, v3d); } void VP_drawrenderborder(ARegion *ar, View3D *v3d) diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 84f0f96fe0b..7cb362ffb92 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -284,7 +284,7 @@ static void backdrawview3d(const struct EvaluationContext *eval_ctx, Scene *scen } if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, false, error); if (!rv3d->gpuoffscreen) fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); @@ -530,7 +530,8 @@ static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, Ima } } -static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, +static void view3d_draw_bgpic(Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, const bool do_foreground, const bool do_camera_frame) { RegionView3D *rv3d = ar->regiondata; @@ -629,7 +630,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, { if (do_camera_frame) { rctf vb; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); x1 = vb.xmin; y1 = vb.ymin; x2 = vb.xmax; @@ -773,8 +774,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, } } -void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) +void ED_view3d_draw_bgpic_test( + Scene *scene, const Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) { RegionView3D *rv3d = ar->regiondata; @@ -797,11 +800,11 @@ void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { if (rv3d->persp == RV3D_CAMOB) { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); } } else { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); } } @@ -1182,7 +1185,7 @@ void ED_view3d_draw_depth_gpencil( glEnable(GL_DEPTH_TEST); if (v3d->flag2 & V3D_SHOW_GPENCIL) { - ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, v3d, ar, true); + ED_gpencil_draw_view3d(NULL, scene, eval_ctx->view_layer, eval_ctx->depsgraph, v3d, ar, true); } v3d->zbuf = zbuf; @@ -1423,7 +1426,7 @@ static void gpu_update_lamps_shadows_world(const EvaluationContext *eval_ctx, Sc ED_view3d_draw_offscreen( eval_ctx, scene, eval_ctx->view_layer, v3d, &ar, winsize, winsize, viewmat, winmat, false, false, true, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); GPU_lamp_shadow_buffer_unbind(shadow->lamp); v3d->drawtype = drawtype; @@ -1500,6 +1503,7 @@ static void view3d_draw_objects( const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) { ViewLayer *view_layer = C ? CTX_data_view_layer(C) : BKE_view_layer_from_scene_get(scene); + Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; Base *base; const bool do_camera_frame = !draw_offscreen; @@ -1544,7 +1548,7 @@ static void view3d_draw_objects( /* important to do before clipping */ if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, do_camera_frame); } if (rv3d->rflag & RV3D_CLIPPING) { @@ -1625,7 +1629,7 @@ static void view3d_draw_objects( /* must be before xray draw which clears the depth buffer */ if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, true); + ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, true); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -1654,7 +1658,7 @@ static void view3d_draw_objects( /* important to do after clipping */ if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, do_camera_frame); } /* cleanup */ @@ -1773,7 +1777,7 @@ static bool view3d_main_region_do_render_draw(const Scene *scene) return (type && type->view_update && type->render_to_view); } -bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, rcti *rect) +bool ED_view3d_calc_render_border(const Scene *scene, const Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect) { RegionView3D *rv3d = ar->regiondata; bool use_border; @@ -1794,7 +1798,7 @@ bool ED_view3d_calc_render_border(const Scene *scene, View3D *v3d, ARegion *ar, /* compute border */ if (rv3d->persp == RV3D_CAMOB) { rctf viewborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); @@ -1823,11 +1827,11 @@ static bool view3d_main_region_draw_engine( ARegion *ar, View3D *v3d, bool clip_border, const rcti *border_rect) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; RenderEngineType *type; GLint scissor[4]; - /* create render engine */ if (!rv3d->render_engine) { RenderEngine *engine; @@ -1872,7 +1876,7 @@ static bool view3d_main_region_draw_engine( Camera *cam = ED_view3d_camera_data_get(v3d, rv3d); if (cam->flag & CAM_SHOW_BG_IMAGE) { show_image = true; - view3d_draw_bgpic_test(scene, ar, v3d, false, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true); } else { imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy); @@ -1880,7 +1884,7 @@ static bool view3d_main_region_draw_engine( } if (show_image) { - view3d_draw_bgpic_test(scene, ar, v3d, false, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true); } else { imm_draw_box_checker_2d(0, 0, ar->winx, ar->winy); @@ -1891,7 +1895,7 @@ static bool view3d_main_region_draw_engine( type->render_to_view(rv3d->render_engine, C); if (show_image) { - view3d_draw_bgpic_test(scene, ar, v3d, true, true); + ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true); } if (clip_border) { @@ -2007,11 +2011,6 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie /* main drawing call */ view3d_draw_objects(C, &eval_ctx, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - /* draw depth culled manipulators - manipulators need to be updated *after* view matrix was set up */ - /* TODO depth culling manipulators is not yet supported, just drawing _3D here, should - * later become _IN_SCENE (and draw _3D separate) */ - WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D); - /* post process */ if (do_compositing) { GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); @@ -2038,6 +2037,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, const char *grid_unit, bool render_border) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewLayer *view_layer = CTX_data_view_layer(C); wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *rv3d = ar->regiondata; @@ -2047,7 +2047,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, ED_region_visible_rect(ar, &rect); if (rv3d->persp == RV3D_CAMOB) { - VP_drawviewborder(scene, ar, v3d); + VP_drawviewborder(scene, CTX_data_depsgraph(C), ar, v3d); } else if (v3d->flag2 & V3D_RENDER_BORDER) { VP_drawrenderborder(ar, v3d); @@ -2055,7 +2055,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, if (v3d->flag2 & V3D_SHOW_GPENCIL) { /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(wm, scene, view_layer, v3d, ar, false); + ED_gpencil_draw_view3d(wm, scene, view_layer, depsgraph, v3d, ar, false); } if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { @@ -2102,6 +2102,7 @@ static void view3d_main_region_draw_info(const bContext *C, Scene *scene, void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); EvaluationContext eval_ctx; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -2111,7 +2112,7 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) /* if we only redraw render border area, skip opengl draw and also * don't do scissor because it's already set */ - bool render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); + bool render_border = ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect); bool clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); gpuPushProjectionMatrix(); @@ -2141,12 +2142,14 @@ void view3d_main_region_draw_legacy(const bContext *C, ARegion *ar) VP_legacy_view3d_main_region_setup_view(&eval_ctx, scene, v3d, ar, NULL, NULL); glClear(GL_DEPTH_BUFFER_BIT); - ED_region_pixelspace(ar); + WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_3D); - WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); + ED_region_pixelspace(ar); view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); + WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); + gpuPopProjectionMatrix(); gpuPopMatrix(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 0dba87bef25..2457a890f71 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -26,6 +26,8 @@ /** \file blender/editors/space_view3d/view3d_edit.c * \ingroup spview3d + * + * 3D view manipulation/operators. */ #include <string.h> @@ -42,9 +44,7 @@ #include "MEM_guardedalloc.h" -#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" -#include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -63,7 +63,6 @@ #include "DEG_depsgraph.h" -#include "BIF_gl.h" #include "WM_api.h" #include "WM_types.h" @@ -73,499 +72,129 @@ #include "ED_armature.h" #include "ED_particle.h" -#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" #include "ED_gpencil.h" #include "ED_view3d.h" -#include "DEG_depsgraph_query.h" - #include "UI_resources.h" -#include "PIL_time.h" /* smoothview */ +#include "PIL_time.h" #include "view3d_intern.h" /* own include */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar); - -bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); -} - -/* ********************** view3d_edit: view manipulations ********************* */ - -/** - * \return true when the view-port is locked to its camera. - */ -bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) -{ - return ((v3d->camera) && - (!ID_IS_LINKED(v3d->camera)) && - (v3d->flag2 & V3D_LOCK_CAMERA) && - (rv3d->persp == RV3D_CAMOB)); -} - -/** - * Apply the camera object transformation to the view-port. - * (needed so we can use regular view-port manipulation operators, that sync back to the camera). - */ -void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - if (calc_dist) { - /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - } - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } -} - -void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) -{ - ED_view3d_camera_lock_init_ex(v3d, rv3d, true); -} - -/** - * Apply the view-port transformation back to the camera object. - * - * \return true if the camera is moved. - */ -bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) -{ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - ObjectTfmProtectedChannels obtfm; - Object *root_parent; - - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - Object *ob_update; - float tmat[4][4]; - float imat[4][4]; - float view_mat[4][4]; - float diff_mat[4][4]; - float parent_mat[4][4]; - - while (root_parent->parent) { - root_parent = root_parent->parent; - } - - ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - - normalize_m4_m4(tmat, v3d->camera->obmat); - - invert_m4_m4(imat, tmat); - mul_m4_m4m4(diff_mat, view_mat, imat); - - mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); - - BKE_object_tfm_protected_backup(root_parent, &obtfm); - BKE_object_apply_mat4(root_parent, parent_mat, true, false); - BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); - - ob_update = v3d->camera; - while (ob_update) { - DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); - ob_update = ob_update->parent; - } - } - else { - /* always maintain the same scale */ - const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); - BKE_object_tfm_protected_backup(v3d->camera, &obtfm); - ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); - BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); - - DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); - WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); - } - - return true; - } - else { - return false; - } -} - -bool ED_view3d_camera_autokey( - Scene *scene, ID *id_key, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - if (autokeyframe_cfra_can_key(scene, id_key)) { - const float cfra = (float)CFRA; - ListBase dsources = {NULL, NULL}; - - /* add data-source override for the camera object */ - ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); - - /* insert keyframes - * 1) on the first frame - * 2) on each subsequent frame - * TODO: need to check in future that frame changed before doing this - */ - if (do_rotate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - if (do_translate) { - struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - } - - /* free temp data */ - BLI_freelistN(&dsources); - - return true; - } - else { - return false; - } -} - -/** - * Call after modifying a locked view. - * - * \note Not every view edit currently auto-keys (numpad for eg), - * this is complicated because of smoothview. - */ -bool ED_view3d_camera_lock_autokey( - View3D *v3d, RegionView3D *rv3d, - struct bContext *C, const bool do_rotate, const bool do_translate) -{ - /* similar to ED_view3d_cameracontrol_update */ - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - Scene *scene = CTX_data_scene(C); - ID *id_key; - Object *root_parent; - if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { - while (root_parent->parent) { - root_parent = root_parent->parent; - } - id_key = &root_parent->id; - } - else { - id_key = &v3d->camera->id; - } - - return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); - } - else { - return false; - } -} - -/** - * For viewport operators that exit camera persp. - * - * \note This differs from simply setting ``rv3d->persp = persp`` because it - * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, - * otherwise switching out of camera view may jump to a different part of the scene. - */ -static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) -{ - BLI_assert(rv3d->persp == RV3D_CAMOB); - BLI_assert(persp != RV3D_CAMOB); - - if (v3d->camera) { - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } - - if (!ED_view3d_camera_lock_check(v3d, rv3d)) { - rv3d->persp = persp; - } -} - -/* ********************* box view support ***************** */ - -static void view3d_boxview_clip(ScrArea *sa) -{ - ARegion *ar; - BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); - float clip[6][4]; - float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; - int val; - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { - if (ar->winx > ar->winy) x1 = rv3d->dist; - else x1 = ar->winx * rv3d->dist / ar->winy; - - if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; - else y1 = rv3d->dist; - copy_v2_v2(ofs, rv3d->ofs); - } - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { - ofs[2] = rv3d->ofs[2]; - - if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; - else z1 = rv3d->dist; - } - } - } - } - - for (val = 0; val < 8; val++) { - if (ELEM(val, 0, 3, 4, 7)) - bb->vec[val][0] = -x1 - ofs[0]; - else - bb->vec[val][0] = x1 - ofs[0]; - - if (ELEM(val, 0, 1, 4, 5)) - bb->vec[val][1] = -y1 - ofs[1]; - else - bb->vec[val][1] = y1 - ofs[1]; - - if (val > 3) - bb->vec[val][2] = -z1 - ofs[2]; - else - bb->vec[val][2] = z1 - ofs[2]; - } - - /* normals for plane equations */ - normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); - normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); - normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); - normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); - normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); - normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); - - /* then plane equations */ - for (val = 0; val < 6; val++) { - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); - } - - /* create bounding box */ - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->viewlock & RV3D_BOXCLIP) { - rv3d->rflag |= RV3D_CLIPPING; - memcpy(rv3d->clip, clip, sizeof(clip)); - if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); - rv3d->clipbb = MEM_dupallocN(bb); - } - } - } - MEM_freeN(bb); -} - -/** - * Find which axis values are shared between both views and copy to \a rv3d_dst - * taking axis flipping into account. - */ -static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) -{ - /* absolute axis values above this are considered to be set (will be ~1.0f) */ - const float axis_eps = 0.5f; - float viewinv[4]; - - /* use the view rotation to identify which axis to sync on */ - float view_axis_all[4][3] = { - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}, - {1.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f}}; - - float *view_src_x = &view_axis_all[0][0]; - float *view_src_y = &view_axis_all[1][0]; - - float *view_dst_x = &view_axis_all[2][0]; - float *view_dst_y = &view_axis_all[3][0]; - int i; - - - /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_src_x); - mul_qt_v3(viewinv, view_src_y); - - if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { - return; - } - invert_qt_normalized(viewinv); - mul_qt_v3(viewinv, view_dst_x); - mul_qt_v3(viewinv, view_dst_y); +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Properties + * \{ */ - /* check source and dest have a matching axis */ - for (i = 0; i < 3; i++) { - if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && - ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) - { - rv3d_dst->ofs[i] = rv3d_src->ofs[i]; - } - } -} +enum eV3D_OpPropFlag { + V3D_OP_PROP_MOUSE_CO = (1 << 0), + V3D_OP_PROP_DELTA = (1 << 1), + V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), + V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), +}; -/* sync center/zoom view of region to others, for view transforms */ -static void view3d_boxview_sync(ScrArea *sa, ARegion *ar) +static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPropFlag flag) { - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - short clip = 0; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock & RV3D_LOCKED) { - rv3dtest->dist = rv3d->dist; - view3d_boxview_sync_axis(rv3dtest, rv3d); - clip |= rv3dtest->viewlock & RV3D_BOXCLIP; - - ED_region_tag_redraw(artest); - } - } + if (flag & V3D_OP_PROP_MOUSE_CO) { + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Region Position X", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Region Position Y", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } - - if (clip) { - view3d_boxview_clip(sa); + if (flag & V3D_OP_PROP_DELTA) { + RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); } -} - -/* for home, center etc */ -void view3d_boxview_copy(ScrArea *sa, ARegion *ar) -{ - ARegion *artest; - RegionView3D *rv3d = ar->regiondata; - bool clip = false; - - for (artest = sa->regionbase.first; artest; artest = artest->next) { - if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3dtest = artest->regiondata; - - if (rv3dtest->viewlock) { - rv3dtest->dist = rv3d->dist; - copy_v3_v3(rv3dtest->ofs, rv3d->ofs); - ED_region_tag_redraw(artest); - - clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); - } - } + if (flag & V3D_OP_PROP_USE_ALL_REGIONS) { + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - - if (clip) { - view3d_boxview_clip(sa); + if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { + /* Disable when view operators are initialized from buttons. */ + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "use_mouse_init", true, "Mouse Init", "Use initial mouse position"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } } -/* 'clip' is used to know if our clip setting has changed */ -void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) -{ - ARegion *ar_sync = NULL; - RegionView3D *rv3d = ar->regiondata; - short viewlock; - /* this function copies flags from the first of the 3 other quadview - * regions to the 2 other, so it assumes this is the region whose - * properties are always being edited, weak */ - viewlock = rv3d->viewlock; - - if ((viewlock & RV3D_LOCKED) == 0) { - do_clip = (viewlock & RV3D_BOXCLIP) != 0; - viewlock = 0; - } - else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { - do_clip = true; - viewlock &= ~RV3D_BOXCLIP; - } - - for (; ar; ar = ar->prev) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - rv3d->viewlock = viewlock; - - if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { - rv3d->rflag &= ~RV3D_BOXCLIP; - } - - /* use ar_sync so we sync with one of the aligned views below - * else the view jumps on changing view settings like 'clip' - * since it copies from the perspective view */ - ar_sync = ar; - } - } - - if (rv3d->viewlock & RV3D_BOXVIEW) { - view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); - } - - /* ensure locked regions have an axis, locked user views don't make much sense */ - if (viewlock & RV3D_LOCKED) { - int index_qsplit = 0; - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->alignment == RGN_ALIGN_QSPLIT) { - rv3d = ar->regiondata; - if (rv3d->viewlock) { - if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); - rv3d->persp = RV3D_ORTHO; - ED_view3d_lock(rv3d); - } - } - index_qsplit++; - } - } - } - - ED_area_tag_redraw(sa); -} +/** \} */ -/* ************************** init for view ops **********************************/ +/* -------------------------------------------------------------------- */ +/** \name Generic View Operator Custom-Data + * \{ */ typedef struct ViewOpsData { - /* context pointers (assigned by viewops_data_alloc) */ + /** Context pointers (assigned by #viewops_data_alloc). */ Scene *scene; ScrArea *sa; ARegion *ar; View3D *v3d; RegionView3D *rv3d; + Depsgraph *depsgraph; - /* needed for continuous zoom */ + /** Needed for continuous zoom. */ wmTimer *timer; - double timer_lastdraw; - float oldquat[4]; - float viewquat[4]; /* working copy of rv3d->viewquat */ - float trackvec[3]; - float mousevec[3]; /* dolly only */ + /** Viewport state on initialization, don't change afterwards. */ + struct { + float dist; + float camzoom; + float quat[4]; + /** #wmEvent.x, y. */ + int event_xy[2]; + /** Offset to use when #VIEWOPS_FLAG_USE_MOUSE_INIT is not set. + * so we can simulate pressing in the middle of the screen. */ + int event_xy_offset[2]; + /** #wmEvent.type that triggered the operator. */ + int event_type; + float ofs[3]; + /** Initial distance to 'ofs'. */ + float zfac; + + /** Trackball rotation only. */ + float trackvec[3]; + /** Dolly only. */ + float mousevec[3]; + } init; + + /** Previous state (previous modal event handled). */ + struct { + int event_xy[2]; + /** For operators that use time-steps (continuous zoom). */ + double time; + } prev; + + /** Current state. */ + struct { + /** Working copy of #RegionView3D.viewquat, needed for rotation calculation + * so we can apply snap to the view-port while keeping the unsnapped rotation + * here to use when snap is disabled and for continued calculation. */ + float viewquat[4]; + } curr; + float reverse; - float dist_prev, camzoom_prev; - float grid, far; bool axis_snap; /* view rotate only */ - float zfac; - /* use for orbit selection and auto-dist */ - float ofs[3], dyn_ofs[3]; + /** Use for orbit selection and auto-dist. */ + float dyn_ofs[3]; bool use_dyn_ofs; - - int origx, origy, oldx, oldy; - int origkey; /* the key that triggered the operator */ - } ViewOpsData; #define TRACKBALLSIZE (1.1f) -static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) +static void calctrackballvec(const rcti *rect, const int event_xy[2], float vec[3]) { const float radius = TRACKBALLSIZE; const float t = radius / (float)M_SQRT2; float x, y, z, d; /* normalize x and y */ - x = BLI_rcti_cent_x(rect) - mx; + x = BLI_rcti_cent_x(rect) - event_xy[0]; x /= (float)(BLI_rcti_size_x(rect) / 4); - y = BLI_rcti_cent_y(rect) - my; + y = BLI_rcti_cent_y(rect) - event_xy[1]; y /= (float)(BLI_rcti_size_y(rect) / 2); d = sqrtf(x * x + y * y); if (d < t) { /* Inside sphere */ @@ -580,13 +209,6 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) vec[2] = -z; /* yah yah! */ } - -/* -------------------------------------------------------------------- */ -/* ViewOpsData */ - -/** \name Generic View Operator Custom-Data. - * \{ */ - /** * Allocate and fill in context pointers for #ViewOpsData */ @@ -596,6 +218,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) /* store data */ op->customdata = vod; + vod->depsgraph = CTX_data_depsgraph(C); vod->scene = CTX_data_scene(C); vod->sa = CTX_wm_area(C); vod->ar = CTX_wm_region(C); @@ -604,7 +227,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) } void view3d_orbit_apply_dyn_ofs( - float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], + float r_ofs[3], const float ofs_init[3], const float viewquat_old[4], const float viewquat_new[4], const float dyn_ofs[3]) { float q[4]; @@ -613,7 +236,7 @@ void view3d_orbit_apply_dyn_ofs( invert_qt_normalized(q); - sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs); + sub_v3_v3v3(r_ofs, ofs_init, dyn_ofs); mul_qt_v3(q, r_ofs); add_v3_v3(r_ofs, dyn_ofs); } @@ -702,48 +325,58 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) return is_set; } -enum eViewOpsOrbit { - VIEWOPS_ORBIT_SELECT = (1 << 0), - VIEWOPS_ORBIT_DEPTH = (1 << 1), +enum eViewOpsFlag { + /** When enabled, rotate around the selection. */ + VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0), + /** When enabled, use the depth under the cursor for navigation. */ + VIEWOPS_FLAG_DEPTH_NAVIGATE = (1 << 1), + /** + * When enabled run #ED_view3d_persp_ensure this may switch out of + * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. + * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common + * so we don't want it to trigger auto-perspective). */ + VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2), + /** When set, ignore any options that depend on initial cursor location. */ + VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3), }; -static enum eViewOpsOrbit viewops_orbit_mode_ex(bool use_select, bool use_depth) +static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth) { - enum eViewOpsOrbit flag = 0; + enum eViewOpsFlag flag = 0; if (use_select) { - flag |= VIEWOPS_ORBIT_SELECT; + flag |= VIEWOPS_FLAG_ORBIT_SELECT; } if (use_depth) { - flag |= VIEWOPS_ORBIT_DEPTH; + flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE; } return flag; } -static enum eViewOpsOrbit viewops_orbit_mode(void) +static enum eViewOpsFlag viewops_flag_from_prefs(void) { - return viewops_orbit_mode_ex( + return viewops_flag_from_args( (U.uiflag & USER_ORBIT_SELECTION) != 0, - (U.uiflag & USER_ZBUF_ORBIT) != 0); + (U.uiflag & USER_DEPTH_NAVIGATE) != 0); } /** * Calculate the values for #ViewOpsData - * - * \param use_ensure_persp: When enabled run #view3d_ensure_persp this may switch out of - * camera view when orbiting or switch from ortho to perspective when auto-persp is enabled. - * Some operations don't require this (view zoom/pan or ndof where subtle rotation is common - * so we don't want it to trigger auto-perspective). */ -static void viewops_data_create_ex( +static void viewops_data_create( bContext *C, wmOperator *op, const wmEvent *event, - bool use_ensure_persp, enum eViewOpsOrbit orbit_mode) + enum eViewOpsFlag viewops_flag) { ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; + /* Could do this more nicely. */ + if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) { + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; + } + /* we need the depth info before changing any viewport options */ - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); float fallback_depth_pt[3]; @@ -762,8 +395,8 @@ static void viewops_data_create_ex( vod->use_dyn_ofs = false; } - if (use_ensure_persp) { - if (view3d_ensure_persp(vod->v3d, vod->ar)) { + if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { + if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders * are properly updated. @@ -776,25 +409,37 @@ static void viewops_data_create_ex( * we may want to make this optional but for now its needed always */ ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); - vod->dist_prev = rv3d->dist; - vod->camzoom_prev = rv3d->camzoom; - copy_qt_qt(vod->viewquat, rv3d->viewquat); - copy_qt_qt(vod->oldquat, rv3d->viewquat); - vod->origx = vod->oldx = event->x; - vod->origy = vod->oldy = event->y; - vod->origkey = event->type; /* the key that triggered the operator. */ - copy_v3_v3(vod->ofs, rv3d->ofs); + vod->init.dist = rv3d->dist; + vod->init.camzoom = rv3d->camzoom; + copy_qt_qt(vod->init.quat, rv3d->viewquat); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; + vod->init.event_xy[1] = vod->prev.event_xy[1] = event->y; + + if (viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) { + vod->init.event_xy_offset[0] = 0; + vod->init.event_xy_offset[1] = 0; + } + else { + /* Simulate the event starting in the middle of the region. */ + vod->init.event_xy_offset[0] = BLI_rcti_cent_x(&vod->ar->winrct) - event->x; + vod->init.event_xy_offset[1] = BLI_rcti_cent_y(&vod->ar->winrct) - event->y; + } - if (orbit_mode & VIEWOPS_ORBIT_SELECT) { + vod->init.event_type = event->type; + copy_v3_v3(vod->init.ofs, rv3d->ofs); + + copy_qt_qt(vod->curr.viewquat, rv3d->viewquat); + + if (viewops_flag & VIEWOPS_FLAG_ORBIT_SELECT) { float ofs[3]; if (view3d_orbit_calc_center(C, ofs) || (vod->use_dyn_ofs == false)) { vod->use_dyn_ofs = true; negate_v3_v3(vod->dyn_ofs, ofs); - orbit_mode &= ~VIEWOPS_ORBIT_DEPTH; + viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE; } } - if (orbit_mode & VIEWOPS_ORBIT_DEPTH) { + if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { if (vod->use_dyn_ofs) { if (rv3d->is_persp) { float my_origin[3]; /* original G.vd->ofs */ @@ -821,7 +466,7 @@ static void viewops_data_create_ex( /* find a new ofs value that is along the view axis (rather than the mouse location) */ closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin); - vod->dist_prev = rv3d->dist = len_v3v3(my_pivot, dvec); + vod->init.dist = rv3d->dist = len_v3v3(my_pivot, dvec); negate_v3_v3(rv3d->ofs, dvec); } @@ -834,27 +479,26 @@ static void viewops_data_create_ex( negate_v3(rv3d->ofs); } negate_v3(vod->dyn_ofs); - copy_v3_v3(vod->ofs, rv3d->ofs); + copy_v3_v3(vod->init.ofs, rv3d->ofs); } } + /* For dolly */ + ED_view3d_win_to_vector(vod->ar, (const float[2]){UNPACK2(event->mval)}, vod->init.mousevec); + { - /* for dolly */ - const float mval_f[2] = {(float)event->mval[0], - (float)event->mval[1]}; - ED_view3d_win_to_vector(vod->ar, mval_f, vod->mousevec); + const int event_xy_offset[2] = { + event->x + vod->init.event_xy_offset[0], + event->y + vod->init.event_xy_offset[1], + }; + /* For rotation with trackball rotation. */ + calctrackballvec(&vod->ar->winrct, event_xy_offset, vod->init.trackvec); } - /* lookup, we don't pass on v3d to prevent confusement */ - vod->grid = vod->v3d->grid; - vod->far = vod->v3d->far; - - calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec); - { float tvec[3]; negate_v3_v3(tvec, rv3d->ofs); - vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + vod->init.zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); } vod->reverse = 1.0f; @@ -864,12 +508,6 @@ static void viewops_data_create_ex( rv3d->rflag |= RV3D_NAVIGATING; } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event, bool use_ensure_persp) -{ - enum eViewOpsOrbit orbit_mode = viewops_orbit_mode(); - viewops_data_create_ex(C, op, event, use_ensure_persp, orbit_mode); -} - static void viewops_data_free(bContext *C, wmOperator *op) { ARegion *ar; @@ -896,10 +534,12 @@ static void viewops_data_free(bContext *C, wmOperator *op) #endif ED_region_tag_redraw(ar); } -/** \} */ +/** \} */ -/* ************************** viewrotate **********************************/ +/* -------------------------------------------------------------------- */ +/** \name View Rotate Operator + * \{ */ enum { VIEW_PASS = 0, @@ -908,12 +548,14 @@ enum { }; /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -#define VIEW_MODAL_CONFIRM 1 /* used for all view operations */ -#define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2 -#define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3 -#define VIEWROT_MODAL_SWITCH_ZOOM 4 -#define VIEWROT_MODAL_SWITCH_MOVE 5 -#define VIEWROT_MODAL_SWITCH_ROTATE 6 +enum { + VIEW_MODAL_CONFIRM = 1, /* used for all view operations */ + VIEWROT_MODAL_AXIS_SNAP_ENABLE = 2, + VIEWROT_MODAL_AXIS_SNAP_DISABLE = 3, + VIEWROT_MODAL_SWITCH_ZOOM = 4, + VIEWROT_MODAL_SWITCH_MOVE = 5, + VIEWROT_MODAL_SWITCH_ROTATE = 6, +}; /* called in transform_ops.c, on each regeneration of keymaps */ void viewrotate_modal_keymap(wmKeyConfig *keyconf) @@ -923,7 +565,7 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""}, {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -950,17 +592,16 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate"); - } static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4]) { if (vod->use_dyn_ofs) { RegionView3D *rv3d = vod->rv3d; - view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->ofs, vod->oldquat, viewquat_new, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->init.ofs, vod->init.quat, viewquat_new, vod->dyn_ofs); } } @@ -976,7 +617,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) int x, y, z; bool found = false; - invert_qt_qt_normalized(viewquat_inv, vod->viewquat); + invert_qt_qt_normalized(viewquat_inv, vod->curr.viewquat); mul_qt_v3(viewquat_inv, zaxis); normalize_v3(zaxis); @@ -1012,7 +653,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) * for testing roll */ rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis); normalize_qt(viewquat_align); - mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align); + mul_qt_qtqt(viewquat_align, vod->curr.viewquat, viewquat_align); normalize_qt(viewquat_align); invert_qt_qt_normalized(viewquat_align_inv, viewquat_align); @@ -1066,7 +707,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod) } } -static void viewrotate_apply(ViewOpsData *vod, int x, int y) +static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) { RegionView3D *rv3d = vod->rv3d; @@ -1076,9 +717,15 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) float axis[3], q1[4], dvec[3], newvec[3]; float angle; - calctrackballvec(&vod->ar->winrct, x, y, newvec); + { + const int event_xy_offset[2] = { + event_xy[0] + vod->init.event_xy_offset[0], + event_xy[1] + vod->init.event_xy_offset[1], + }; + calctrackballvec(&vod->ar->winrct, event_xy_offset, newvec); + } - sub_v3_v3v3(dvec, newvec, vod->trackvec); + sub_v3_v3v3(dvec, newvec, vod->init.trackvec); angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI; @@ -1089,12 +736,12 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) * so that the angle of rotation is linearly proportional to * the distance that the mouse is dragged. */ - cross_v3_v3v3(axis, vod->trackvec, newvec); + cross_v3_v3v3(axis, vod->init.trackvec, newvec); axis_angle_to_quat(q1, axis, angle); - mul_qt_qtqt(vod->viewquat, q1, vod->oldquat); + mul_qt_qtqt(vod->curr.viewquat, q1, vod->init.quat); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } else { /* New turntable view code by John Aughey */ @@ -1111,7 +758,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) const float sensitivity = 0.007f; /* Get the 3x3 matrix and its inverse from the quaternion */ - quat_to_mat3(m, vod->viewquat); + quat_to_mat3(m, vod->curr.viewquat); invert_m3_m3(m_inv, m); /* avoid gimble lock */ @@ -1138,30 +785,30 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) /* This can likely be computed directly from the quaternion. */ /* Perform the up/down rotation */ - axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(y - vod->oldy)); - mul_qt_qtqt(quat_local_x, vod->viewquat, quat_local_x); + axis_angle_to_quat(quat_local_x, xaxis, sensitivity * -(event_xy[1] - vod->prev.event_xy[1])); + mul_qt_qtqt(quat_local_x, vod->curr.viewquat, quat_local_x); /* Perform the orbital rotation */ - axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (x - vod->oldx)); - mul_qt_qtqt(vod->viewquat, quat_local_x, quat_global_z); + axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (event_xy[0] - vod->prev.event_xy[0])); + mul_qt_qtqt(vod->curr.viewquat, quat_local_x, quat_global_z); - viewrotate_apply_dyn_ofs(vod, vod->viewquat); + viewrotate_apply_dyn_ofs(vod, vod->curr.viewquat); } /* avoid precision loss over time */ - normalize_qt(vod->viewquat); + normalize_qt(vod->curr.viewquat); /* use a working copy so view rotation locking doesnt overwrite the locked * rotation back into the view we calculate with */ - copy_qt_qt(rv3d->viewquat, vod->viewquat); + copy_qt_qt(rv3d->viewquat, vod->curr.viewquat); /* check for view snap, * note: don't apply snap to vod->viewquat so the view wont jam up */ if (vod->axis_snap) { viewrotate_apply_snap(vod); } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = event_xy[0]; + vod->prev.event_xy[1] = event_xy[1]; ED_view3d_camera_lock_sync(vod->v3d, rv3d); @@ -1202,12 +849,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewrotate_apply(vod, event->x, event->y); + viewrotate_apply(vod, &event->x); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -1229,41 +876,12 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) return ret; } -/** - * Action to take when rotating the view, - * handle auto-persp and logic for switching out of views. - * - * shared with NDOF. - */ -static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; - - BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - - if (ED_view3d_camera_lock_check(v3d, rv3d)) - return false; - - if (rv3d->persp != RV3D_PERSP) { - if (rv3d->persp == RV3D_CAMOB) { - /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ - char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; - view3d_persp_switch_from_camera(v3d, rv3d, persp); - } - else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { - rv3d->persp = RV3D_PERSP; - } - return true; - } - - return false; -} - static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); vod = op->customdata; @@ -1276,29 +894,33 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); - viewops_data_create(C, op, event, true); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + VIEWOPS_FLAG_PERSP_ENSURE | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) { /* Rotate direction we keep always same */ - int x, y; + int event_xy[2]; if (event->type == MOUSEPAN) { if (U.uiflag2 & USER_TRACKPAD_NATURAL) { - x = 2 * event->x - event->prevx; - y = 2 * event->y - event->prevy; + event_xy[0] = 2 * event->x - event->prevx; + event_xy[1] = 2 * event->y - event->prevy; } else { - x = event->prevx; - y = event->prevy; + event_xy[0] = event->prevx; + event_xy[1] = event->prevy; } } else { /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ - x = event->prevx; - y = event->y; + event_xy[0] = event->prevx; + event_xy[1] = event->y; } - viewrotate_apply(vod, x, y); + viewrotate_apply(vod, event_xy); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -1361,13 +983,17 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } -#ifdef WITH_INPUT_NDOF +/** \} */ +/* -------------------------------------------------------------------- */ /** \name NDOF Utility Functions * \{ */ +#ifdef WITH_INPUT_NDOF #define NDOF_HAS_TRANSLATE ((!ED_view3d_offset_lock_check(v3d, rv3d)) && !is_zero_v3(ndof->tvec)) #define NDOF_HAS_ROTATE (((rv3d->viewlock & RV3D_LOCKED) == 0) && !is_zero_v3(ndof->rvec)) @@ -1417,8 +1043,9 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d) * * \param has_zoom zoom, otherwise dolly, often `!rv3d->is_persp` since it doesnt make sense to dolly in ortho. */ -static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - const bool has_translate, const bool has_zoom) +static void view3d_ndof_pan_zoom( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + const bool has_translate, const bool has_zoom) { RegionView3D *rv3d = ar->regiondata; float view_inv[4]; @@ -1479,9 +1106,10 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s } -static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - /* optional, can be NULL*/ - ViewOpsData *vod) +static void view3d_ndof_orbit( + const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, + /* optional, can be NULL*/ + ViewOpsData *vod) { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; @@ -1490,7 +1118,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); rv3d->view = RV3D_VIEW_USER; @@ -1525,7 +1153,6 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa, axis_angle_to_quat_single(quat, 'Z', angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); - } else { float quat[4]; @@ -1666,14 +1293,16 @@ void view3d_ndof_fly( /** \} */ +/* -------------------------------------------------------------------- */ +/** \name NDOF Operators + * + * - "orbit" navigation (trackball/turntable) + * - zooming + * - panning in rotationally-locked views + * \{ */ -/* -- "orbit" navigation (trackball/turntable) - * -- zooming - * -- panning in rotationally-locked views - */ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1685,9 +1314,9 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -1742,7 +1371,6 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; } @@ -1754,9 +1382,9 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev const wmNDOFMotionData *ndof = event->customdata; viewops_data_alloc(C, op); - viewops_data_create_ex( + viewops_data_create( C, op, event, - false, viewops_orbit_mode_ex((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); + viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0, false)); vod = op->customdata; @@ -1934,8 +1562,11 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) #endif /* WITH_INPUT_NDOF */ -/* ************************ viewmove ******************************** */ +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Move (Pan) Operator + * \{ */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -1944,7 +1575,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"}, {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, @@ -1968,7 +1599,7 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_move"); } @@ -1977,13 +1608,13 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf) static void viewmove_apply(ViewOpsData *vod, int x, int y) { if (ED_view3d_offset_lock_check(vod->v3d, vod->rv3d)) { - vod->rv3d->ofs_lock[0] -= ((vod->oldx - x) * 2.0f) / (float)vod->ar->winx; - vod->rv3d->ofs_lock[1] -= ((vod->oldy - y) * 2.0f) / (float)vod->ar->winy; + vod->rv3d->ofs_lock[0] -= ((vod->prev.event_xy[0] - x) * 2.0f) / (float)vod->ar->winx; + vod->rv3d->ofs_lock[1] -= ((vod->prev.event_xy[1] - y) * 2.0f) / (float)vod->ar->winy; } else if ((vod->rv3d->persp == RV3D_CAMOB) && !ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { const float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - vod->rv3d->camdx += (vod->oldx - x) / (vod->ar->winx * zoomfac); - vod->rv3d->camdy += (vod->oldy - y) / (vod->ar->winy * zoomfac); + vod->rv3d->camdx += (vod->prev.event_xy[0] - x) / (vod->ar->winx * zoomfac); + vod->rv3d->camdy += (vod->prev.event_xy[1] - y) / (vod->ar->winy * zoomfac); CLAMP(vod->rv3d->camdx, -1.0f, 1.0f); CLAMP(vod->rv3d->camdy, -1.0f, 1.0f); } @@ -1991,18 +1622,19 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) float dvec[3]; float mval_f[2]; - mval_f[0] = x - vod->oldx; - mval_f[1] = y - vod->oldy; - ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac); + mval_f[0] = x - vod->prev.event_xy[0]; + mval_f[1] = y - vod->prev.event_xy[1]; + ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->init.zfac); add_v3_v3(vod->rv3d->ofs, dvec); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } } - vod->oldx = x; - vod->oldy = y; + vod->prev.event_xy[0] = x; + vod->prev.event_xy[1] = y; ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2037,7 +1669,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -2068,9 +1700,14 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -2079,9 +1716,9 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* invert it, trackpad scroll follows same principle as 2d windows this way */ viewmove_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); ED_view3d_depth_tag_update(vod->rv3d); - + viewops_data_free(C, op); - + return OPERATOR_FINISHED; } else { @@ -2113,9 +1750,16 @@ void VIEW3D_OT_move(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } -/* ************************ viewzoom ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Zoom Operator + * \{ */ /* viewdolly_modal_keymap has an exact copy of this, apply fixes to both */ /* called in transform_ops.c, on each regeneration of keymaps */ @@ -2123,7 +1767,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, @@ -2147,14 +1791,17 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); #endif - + /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom"); } -static void view_zoom_mouseloc_camera( - Scene *scene, View3D *v3d, - ARegion *ar, float dfac, int mx, int my) +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_camera( + Scene *scene, const Depsgraph *depsgraph, View3D *v3d, + ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); @@ -2162,22 +1809,22 @@ static void view_zoom_mouseloc_camera( const float camzoom_new = BKE_screen_view3d_zoom_from_fac(zoomfac_new); - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float zoomfac_px; rctf camera_frame_old; rctf camera_frame_new; - const float pt_src[2] = {mx, my}; + const float pt_src[2] = {zoom_xy[0], zoom_xy[1]}; float pt_dst[2]; float delta_px[2]; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_old, false); BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin); rv3d->camzoom = camzoom_new; CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_new, false); BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin); BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); @@ -2198,12 +1845,15 @@ static void view_zoom_mouseloc_camera( } } -static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) +/** + * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. + */ +static void view_zoom_to_window_xy_3d(ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; const float dist_new = rv3d->dist * dfac; - if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { + if (zoom_xy != NULL) { float dvec[3]; float tvec[3]; float tpos[3]; @@ -2213,8 +1863,8 @@ static void view_zoom_mouseloc_3d(ARegion *ar, float dfac, int mx, int my) negate_v3_v3(tpos, rv3d->ofs); - mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; - mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; + mval_f[0] = (float)(((zoom_xy[0] - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; + mval_f[1] = (float)(((zoom_xy[1] - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; /* Project cursor position into 3D space */ zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); @@ -2240,7 +1890,7 @@ static float viewzoom_scale_value( const rcti *winrct, const short viewzoom, const bool zoom_invert, const bool zoom_invert_force, - const int xy[2], const int xy_orig[2], + const int xy_curr[2], const int xy_init[2], const float val, const float val_orig, double *r_timer_lastdraw) { @@ -2252,10 +1902,10 @@ static float viewzoom_scale_value( float fac; if (U.uiflag & USER_ZOOM_HORIZ) { - fac = (float)(xy_orig[0] - xy[0]); + fac = (float)(xy_init[0] - xy_curr[0]); } else { - fac = (float)(xy_orig[1] - xy[1]); + fac = (float)(xy_init[1] - xy_curr[1]); } if (zoom_invert != zoom_invert_force) { @@ -2273,8 +1923,8 @@ static float viewzoom_scale_value( BLI_rcti_cent_x(winrct), BLI_rcti_cent_y(winrct), }; - float len_new = 5 + len_v2v2_int(ctr, xy); - float len_old = 5 + len_v2v2_int(ctr, xy_orig); + float len_new = 5 + len_v2v2_int(ctr, xy_curr); + float len_old = 5 + len_v2v2_int(ctr, xy_init); /* intentionally ignore 'zoom_invert' for scale */ if (zoom_invert_force) { @@ -2288,12 +1938,12 @@ static float viewzoom_scale_value( float len_old = 5; if (U.uiflag & USER_ZOOM_HORIZ) { - len_new += (winrct->xmax - xy[0]); - len_old += (winrct->xmax - xy_orig[0]); + len_new += (winrct->xmax - (xy_curr[0])); + len_old += (winrct->xmax - (xy_init[0])); } else { - len_new += (winrct->ymax - xy[1]); - len_old += (winrct->ymax - xy_orig[1]); + len_new += (winrct->ymax - (xy_curr[1])); + len_old += (winrct->ymax - (xy_init[1])); } if (zoom_invert != zoom_invert_force) { @@ -2307,25 +1957,48 @@ static float viewzoom_scale_value( return zfac; } +static float viewzoom_scale_value_offset( + const rcti *winrct, + const short viewzoom, + const bool zoom_invert, const bool zoom_invert_force, + const int xy_curr[2], const int xy_init[2], const int xy_offset[2], + const float val, const float val_orig, + double *r_timer_lastdraw) +{ + const int xy_curr_offset[2] = { + xy_curr[0] + xy_offset[0], + xy_curr[1] + xy_offset[1], + }; + const int xy_init_offset[2] = { + xy_init[0] + xy_offset[0], + xy_init[1] + xy_offset[1], + }; + return viewzoom_scale_value( + winrct, viewzoom, zoom_invert, zoom_invert_force, + xy_curr_offset, xy_init_offset, + val, val_orig, r_timer_lastdraw); +} + static void viewzoom_apply_camera( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; - float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->camzoom_prev) * 2.0f; + float zoomfac_prev = BKE_screen_view3d_zoom_to_fac(vod->init.camzoom) * 2.0f; float zoomfac = BKE_screen_view3d_zoom_to_fac(vod->rv3d->camzoom) * 2.0f; - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, true, xy, &vod->origx, + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, true, + xy, vod->init.event_xy, vod->init.event_xy_offset, zoomfac, zoomfac_prev, - &vod->timer_lastdraw); + &vod->prev.time); if (zfac != 1.0f && zfac != 0.0f) { /* calculate inverted, then invert again (needed because of camera zoom scaling) */ zfac = 1.0f / zfac; - view_zoom_mouseloc_camera( - vod->scene, vod->v3d, - vod->ar, zfac, vod->oldx, vod->oldy); + view_zoom_to_window_xy_camera( + vod->scene, vod->depsgraph, vod->v3d, + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } ED_region_tag_redraw(vod->ar); @@ -2333,32 +2006,34 @@ static void viewzoom_apply_camera( static void viewzoom_apply_3d( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { float zfac; float dist_range[2]; ED_view3d_dist_range_get(vod->v3d, dist_range); - zfac = viewzoom_scale_value( - &vod->ar->winrct, viewzoom, zoom_invert, false, xy, &vod->origx, - vod->rv3d->dist, vod->dist_prev, - &vod->timer_lastdraw); + zfac = viewzoom_scale_value_offset( + &vod->ar->winrct, viewzoom, zoom_invert, false, + xy, vod->init.event_xy, vod->init.event_xy_offset, + vod->rv3d->dist, vod->init.dist, + &vod->prev.time); if (zfac != 1.0f) { const float zfac_min = dist_range[0] / vod->rv3d->dist; const float zfac_max = dist_range[1] / vod->rv3d->dist; CLAMP(zfac, zfac_min, zfac_max); - view_zoom_mouseloc_3d( - vod->ar, zfac, vod->oldx, vod->oldy); + view_zoom_to_window_xy_3d( + vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } /* these limits were in old code too */ CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2367,15 +2042,15 @@ static void viewzoom_apply_3d( static void viewzoom_apply( ViewOpsData *vod, const int xy[2], - const short viewzoom, const bool zoom_invert) + const short viewzoom, const bool zoom_invert, const bool zoom_to_pos) { if ((vod->rv3d->persp == RV3D_CAMOB) && (vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) { - viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } else { - viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert); + viewzoom_apply_3d(vod, xy, viewzoom, zoom_invert, zoom_to_pos); } } @@ -2409,12 +2084,16 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + viewzoom_apply( + vod, &event->x, U.viewzoom, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) ? vod->prev.event_xy : NULL); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -2438,6 +2117,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) static int viewzoom_exec(bContext *C, wmOperator *op) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; RegionView3D *rv3d; @@ -2447,7 +2127,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) float dist_range[2]; const int delta = RNA_int_get(op->ptr, "delta"); - int mx, my; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); if (op->customdata) { ViewOpsData *vod = op->customdata; @@ -2463,39 +2143,46 @@ static int viewzoom_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; - mx = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; - my = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); + int zoom_xy_buf[2]; + const int *zoom_xy = NULL; + if (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { + zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2; + zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2; + zoom_xy = zoom_xy_buf; + } + ED_view3d_dist_range_get(v3d, dist_range); if (delta < 0) { const float step = 1.2f; /* this min and max is also in viewmove() */ if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist < dist_range[1]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } else { const float step = 1.0f / 1.2f; if (use_cam_zoom) { - view_zoom_mouseloc_camera(scene, v3d, ar, step, mx, my); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist > dist_range[0]) { - view_zoom_mouseloc_3d(ar, step, mx, my); + view_zoom_to_window_xy_3d(ar, step, zoom_xy); } } } - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2509,49 +2196,19 @@ static int viewzoom_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* this is an exact copy of viewzoom_modal_keymap */ -/* called in transform_ops.c, on each regeneration of keymaps */ -void viewdolly_modal_keymap(wmKeyConfig *keyconf) -{ - static const EnumPropertyItem modal_items[] = { - {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, - - {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, - {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, - - {0, NULL, 0, NULL, NULL} - }; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) return; - - keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); - - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - - /* disabled mode switching for now, can re-implement better, later on */ -#if 0 - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); -#endif - - /* assign map to operators */ - WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); -} - /* viewdolly_invoke() copied this function, changes here may apply there */ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); @@ -2569,14 +2226,16 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewzoom_apply(vod, &event->prevx, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewzoom_apply( + vod, &event->prevx, USER_ZOOM_DOLLY, + (U.uiflag & USER_ZOOM_INVERT) != 0, + (use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS))); ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true); ED_view3d_depth_tag_update(vod->rv3d); @@ -2588,7 +2247,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (U.viewzoom == USER_ZOOM_CONT) { /* needs a timer to continue redrawing */ vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); - vod->timer_lastdraw = PIL_check_seconds_timer(); + vod->prev.time = PIL_check_seconds_timer(); } /* add temp handler */ @@ -2607,8 +2266,6 @@ static void viewzoom_cancel(bContext *C, wmOperator *op) void VIEW3D_OT_zoom(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Zoom View"; ot->description = "Zoom in/out in the view"; @@ -2624,15 +2281,56 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); + /* properties */ + view3d_operator_properties_common( + ot, + V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Dolly Operator + * + * Like zoom but translates the view offset along the view direction + * which avoids #RegionView3D.dist approaching zero. + * \{ */ + +/* this is an exact copy of viewzoom_modal_keymap */ +/* called in transform_ops.c, on each regeneration of keymaps */ +void viewdolly_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"}, + {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"}, + + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) return; + + keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); + + /* disabled mode switching for now, can re-implement better, later on */ +#if 0 + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE); +#endif + + /* assign map to operators */ + WM_modalkeymap_assign(keymap, "VIEW3D_OT_dolly"); +} -/* ************************ viewdolly ******************************** */ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); @@ -2646,13 +2344,13 @@ static bool viewdolly_offset_lock_check(bContext *C, wmOperator *op) } } -static void view_dolly_mouseloc(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) +static void view_dolly_to_vector_3d(ARegion *ar, float orig_ofs[3], float dvec[3], float dfac) { RegionView3D *rv3d = ar->regiondata; madd_v3_v3v3fl(rv3d->ofs, orig_ofs, dvec, -(1.0f - dfac)); } -static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_invert) +static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_invert) { float zfac = 1.0; @@ -2660,24 +2358,27 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv float len1, len2; if (U.uiflag & USER_ZOOM_HORIZ) { - len1 = (vod->ar->winrct.xmax - x) + 5; - len2 = (vod->ar->winrct.xmax - vod->origx) + 5; + len1 = (vod->ar->winrct.xmax - xy[0]) + 5; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) + 5; } else { - len1 = (vod->ar->winrct.ymax - y) + 5; - len2 = (vod->ar->winrct.ymax - vod->origy) + 5; + len1 = (vod->ar->winrct.ymax - xy[1]) + 5; + len2 = (vod->ar->winrct.ymax - vod->init.event_xy[1]) + 5; } - if (zoom_invert) + if (zoom_invert) { SWAP(float, len1, len2); + } zfac = 1.0f + ((len1 - len2) * 0.01f * vod->rv3d->dist); } - if (zfac != 1.0f) - view_dolly_mouseloc(vod->ar, vod->ofs, vod->mousevec, zfac); + if (zfac != 1.0f) { + view_dolly_to_vector_3d(vod->ar, vod->init.ofs, vod->init.mousevec, zfac); + } - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -2711,12 +2412,12 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } if (event_code == VIEW_APPLY) { - viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0); + viewdolly_apply(vod, &event->x, (U.uiflag & USER_ZOOM_INVERT) != 0); if (ED_screen_animation_playing(CTX_wm_manager(C))) { use_autokey = true; } @@ -2753,7 +2454,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) sa = vod->sa; ar = vod->ar; - copy_v3_v3(mousevec, vod->mousevec); + copy_v3_v3(mousevec, vod->init.mousevec); } else { sa = CTX_wm_area(C); @@ -2765,20 +2466,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op) v3d = sa->spacedata.first; rv3d = ar->regiondata; + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { normalize_v3_v3(mousevec, rv3d->viewinv[2]); } - if (delta < 0) { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 0.2f); - } - else { - view_dolly_mouseloc(ar, rv3d->ofs, mousevec, 1.8f); - } + view_dolly_to_vector_3d(ar, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f); - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(sa, ar); + } ED_view3d_depth_tag_update(rv3d); @@ -2816,7 +2515,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (vod->rv3d->persp != RV3D_PERSP) { if (vod->rv3d->persp == RV3D_CAMOB) { /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ - view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); + ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); } else { vod->rv3d->persp = RV3D_PERSP; @@ -2824,7 +2523,12 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(vod->ar); } - viewops_data_create(C, op, event, false); + const bool use_mouse_init = RNA_boolean_get(op->ptr, "use_mouse_init"); + + viewops_data_create( + C, op, event, + viewops_flag_from_prefs() | + (use_mouse_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0)); /* if one or the other zoom position aren't set, set from event */ @@ -2838,24 +2542,22 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) } else { /* overwrite the mouse vector with the view direction (zoom into the center) */ - if ((U.uiflag & USER_ZOOM_TO_MOUSEPOS) == 0) { - negate_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - normalize_v3(vod->mousevec); + if ((use_mouse_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) == 0) { + negate_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + normalize_v3(vod->init.mousevec); } if (event->type == MOUSEZOOM) { /* Bypass Zoom invert flag for track pads (pass false always) */ if (U.uiflag & USER_ZOOM_HORIZ) { - vod->origx = vod->oldx = event->x; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; } else { - /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */ - vod->origy = vod->oldy = vod->origy + event->x - event->prevx; - viewdolly_apply(vod, event->prevx, event->prevy, (U.uiflag & USER_ZOOM_INVERT) == 0); + vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->x - event->prevx; } + viewdolly_apply(vod, &event->prevx, (U.uiflag & USER_ZOOM_INVERT) == 0); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -2893,14 +2595,23 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); + /* properties */ + view3d_operator_properties_common( + ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); } -static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, - const float min[3], const float max[3], - bool ok_dist, const int smooth_viewtx) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View All Operator + * + * Move & Zoom the view to fit all of it's contents. + * \{ */ + +static void view3d_from_minmax( + bContext *C, View3D *v3d, ARegion *ar, + const float min[3], const float max[3], + bool ok_dist, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; float afm[3]; @@ -2966,10 +2677,13 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, /* smooth view does viewlock RV3D_BOXVIEW copy */ } -/* same as view3d_from_minmax but for all regions (except cameras) */ -static void view3d_from_minmax_multi(bContext *C, View3D *v3d, - const float min[3], const float max[3], - const bool ok_dist, const int smooth_viewtx) +/** + * Same as #view3d_from_minmax but for all regions (except cameras). + */ +static void view3d_from_minmax_multi( + bContext *C, View3D *v3d, + const float min[3], const float max[3], + const bool ok_dist, const int smooth_viewtx) { ScrArea *sa = CTX_wm_area(C); ARegion *ar; @@ -2985,7 +2699,7 @@ static void view3d_from_minmax_multi(bContext *C, View3D *v3d, } } -static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */ +static int view3d_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); @@ -3050,8 +2764,6 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in void VIEW3D_OT_view_all(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View All"; ot->description = "View all objects in scene"; @@ -3064,11 +2776,19 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) /* flags */ ot->flag = 0; - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); RNA_def_boolean(ot->srna, "center", 0, "Center", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Selected Operator + * + * Move & Zoom the view to fit selected contents. + * \{ */ + /* like a localview without local!, was centerview() in 2.4x */ static int viewselected_exec(bContext *C, wmOperator *op) { @@ -3180,8 +2900,6 @@ static int viewselected_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_selected(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "View Selected"; ot->description = "Move the view to the selection center"; @@ -3194,17 +2912,22 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna later */ - prop = RNA_def_boolean(ot->srna, "use_all_regions", 0, "All Regions", "View selected for all regions"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Clear Operator + * \{ */ + static int view_lock_clear_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3231,6 +2954,12 @@ void VIEW3D_OT_view_lock_clear(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock to Active Operator + * \{ */ + static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); @@ -3238,7 +2967,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) if (v3d) { - ED_view3D_lock_clear(v3d); + ED_view3d_lock_clear(v3d); v3d->ob_centre = obact; /* can be NULL */ @@ -3282,12 +3011,18 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Cursor Operator + * \{ */ + static int viewcenter_cursor_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); Scene *scene = CTX_data_scene(C); - + if (rv3d) { ARegion *ar = CTX_wm_region(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -3303,7 +3038,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) /* smooth view does viewlock RV3D_BOXVIEW copy */ } - + return OPERATOR_FINISHED; } @@ -3313,15 +3048,21 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) ot->name = "Center View to Cursor"; ot->description = "Center the view so that the cursor is in the middle of the view"; ot->idname = "VIEW3D_OT_view_center_cursor"; - + /* api callbacks */ ot->exec = viewcenter_cursor_exec; ot->poll = ED_operator_view3d_active; - + /* flags */ ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Center Pick Operator + * \{ */ + static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); @@ -3372,8 +3113,15 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Camera Center Operator + * \{ */ + static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); float xfac, yfac; float size[2]; @@ -3388,7 +3136,7 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was rv3d->camdx = rv3d->camdy = 0.0f; - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); /* 4px is just a little room from the edge of the area */ xfac = (float)ar->winx / (float)(size[0] + 4); @@ -3417,6 +3165,12 @@ void VIEW3D_OT_view_center_camera(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Lock Center Operator + * \{ */ + static int view3d_center_lock_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -3443,10 +3197,15 @@ void VIEW3D_OT_view_center_lock(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Set render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Render Border Operator + * \{ */ static int render_border_exec(bContext *C, wmOperator *op) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ED_view3d_context_rv3d(C); @@ -3467,7 +3226,7 @@ static int render_border_exec(bContext *C, wmOperator *op) /* calculate range */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); } else { vb.xmin = 0; @@ -3513,7 +3272,6 @@ static int render_border_exec(bContext *C, wmOperator *op) } return OPERATOR_FINISHED; - } void VIEW3D_OT_render_border(wmOperatorType *ot) @@ -3536,7 +3294,7 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ + /* properties */ WM_operator_properties_border(ot); prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only", @@ -3544,7 +3302,11 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/* ********************* Clear render border operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Render Border Operator + * \{ */ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3573,7 +3335,6 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) border->ymax = 1.0f; return OPERATOR_FINISHED; - } void VIEW3D_OT_clear_render_border(wmOperatorType *ot) @@ -3591,7 +3352,11 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************* Border Zoom operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Border Zoom Operator + * \{ */ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) { @@ -3612,7 +3377,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* ZBuffer depth vars */ float depth_close = FLT_MAX; - float p[3]; + float cent[2], p[3]; /* note; otherwise opengl won't work */ view3d_operator_needs_opengl(C); @@ -3629,22 +3394,22 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* Get Z Depths, needed for perspective, nice for ortho */ ED_view3d_draw_depth(&eval_ctx, CTX_data_depsgraph(C), ar, v3d, true); - + { /* avoid allocating the whole depth buffer */ ViewDepths depth_temp = {0}; /* avoid view3d_update_depths() for speed. */ view3d_update_depths_rect(ar, &depth_temp, &rect); - + /* find the closest Z pixel */ depth_close = view3d_depth_near(&depth_temp); - + MEM_SAFE_FREE(depth_temp.depths); } - float centx = (((float)rect.xmin) + ((float)rect.xmax)) / 2; - float centy = (((float)rect.ymin) + ((float)rect.ymax)) / 2; + cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; + cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; if (rv3d->is_persp) { float p_corner[3]; @@ -3655,7 +3420,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* convert border to 3d coordinates */ - if ((!ED_view3d_unproject(ar, centx, centy, depth_close, p)) || + if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) || (!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner))) { return OPERATOR_CANCELLED; @@ -3677,7 +3442,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_dist = rv3d->dist; /* convert the drawn rectangle into 3d space */ - if (depth_close != FLT_MAX && ED_view3d_unproject(ar, centx, centy, depth_close, p)) { + if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) { negate_v3_v3(new_ofs, p); } else { @@ -3719,8 +3484,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) C, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist}); - if (rv3d->viewlock & RV3D_BOXVIEW) + if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(CTX_wm_area(C), ar); + } return OPERATOR_FINISHED; } @@ -3755,18 +3521,25 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_gesture_border_zoom(ot); } -/* sets the view to 1:1 camera/render-pixel */ -static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Camera Zoom 1:1 Operator + * + * Sets the view to 1:1 camera/render-pixel. + * \{ */ + +static void view3d_set_1_to_1_viewborder(Scene *scene, const Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { RegionView3D *rv3d = ar->regiondata; float size[2]; int im_width = (scene->r.size * scene->r.xsch) / 100; - - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]); CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); @@ -3774,6 +3547,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; @@ -3782,7 +3556,7 @@ static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* no NULL check is needed, poll checks */ ED_view3d_context_user_region(C, &v3d, &ar); - view3d_set_1_to_1_viewborder(scene, ar, v3d); + view3d_set_1_to_1_viewborder(scene, depsgraph, ar, v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3804,7 +3578,11 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) ot->flag = 0; } -/* ********************* Changing view operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis/Type Operator + * \{ */ static const EnumPropertyItem prop_view_items[] = { {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"}, @@ -3820,10 +3598,11 @@ static const EnumPropertyItem prop_view_items[] = { /* would like to make this a generic function - outside of transform */ -static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, - const float quat_[4], - short view, int perspo, bool align_active, - const int smooth_viewtx) +static void axis_set_view( + bContext *C, View3D *v3d, ARegion *ar, + const float quat_[4], + short view, int perspo, bool align_active, + const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */ float quat[4]; @@ -4002,7 +3781,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) &(const V3D_SmoothParams) { .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat, .dist = &rv3d->dist, .lens = &v3d->lens}); - } else { /* return to settings of last view */ @@ -4043,6 +3821,14 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Orbit Operator + * + * Rotate (orbit) in incremental steps. For interactive orbit see #VIEW3D_OT_rotate. + * \{ */ + static const EnumPropertyItem prop_view_orbit_items[] = { {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"}, {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"}, @@ -4086,7 +3872,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op) float quat_new[4]; if (view_opposite == RV3D_VIEW_USER) { - view3d_ensure_persp(v3d, ar); + ED_view3d_persp_ensure(v3d, ar); } if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { @@ -4157,17 +3943,19 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE); ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); - } +/** \} */ -/* ************************ viewroll ******************************** */ +/* -------------------------------------------------------------------- */ +/** \name View Roll Operator + * \{ */ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle) { @@ -4194,19 +3982,20 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin; len1 = (vod->ar->winrct.xmax - x) / tot; - len2 = (vod->ar->winrct.xmax - vod->origx) / tot; + len2 = (vod->ar->winrct.xmax - vod->init.event_xy[0]) / tot; angle = (len1 - len2) * (float)M_PI * 4.0f; } if (angle != 0.0f) - view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle); + view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->init.quat, vod->init.mousevec, angle); if (vod->use_dyn_ofs) { - view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs); + view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->init.ofs, vod->init.quat, vod->rv3d->viewquat, vod->dyn_ofs); } - if (vod->rv3d->viewlock & RV3D_BOXVIEW) + if (vod->rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_sync(vod->sa, vod->ar); + } ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); @@ -4239,7 +4028,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } } - else if (event->type == vod->origkey && event->val == KM_RELEASE) { + else if (event->type == vod->init.event_type && event->val == KM_RELEASE) { event_code = VIEW_CONFIRM; } @@ -4343,17 +4132,17 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) else { /* makes op->customdata */ viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); vod = op->customdata; ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->ar); /* overwrite the mouse vector with the view direction */ - normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); - negate_v3(vod->mousevec); + normalize_v3_v3(vod->init.mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->init.mousevec); if (event->type == MOUSEROTATE) { - vod->origx = vod->oldx = event->x; + vod->init.event_xy[0] = vod->prev.event_xy[0] = event->x; viewroll_apply(vod, event->prevx, event->prevy); ED_view3d_depth_tag_update(vod->rv3d); @@ -4409,6 +4198,14 @@ static const EnumPropertyItem prop_view_pan_items[] = { {0, NULL, 0, NULL, NULL} }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Pan Operator + * + * Move (pan) in incremental steps. For interactive pan see #VIEW3D_OT_move. + * \{ */ + static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int x = 0, y = 0; @@ -4420,10 +4217,10 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) else if (pandir == V3D_VIEW_PANDOWN) { y = 25; } viewops_data_alloc(C, op); - viewops_data_create(C, op, event, false); + viewops_data_create(C, op, event, viewops_flag_from_prefs()); ViewOpsData *vod = op->customdata; - viewmove_apply(vod, vod->oldx + x, vod->oldy + y); + viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y); ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -4444,11 +4241,17 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* Properties */ ot->prop = RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Toggle Perspective/Orthographic Operator + * \{ */ + static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d_dummy; @@ -4467,7 +4270,6 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) } return OPERATOR_FINISHED; - } void VIEW3D_OT_view_persportho(wmOperatorType *ot) @@ -4485,6 +4287,14 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Navigate Operator + * + * Wraps walk/fly modes. + * \{ */ + static int view3d_navigate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { eViewNavigation_Method mode = U.navigation_mode; @@ -4514,8 +4324,11 @@ void VIEW3D_OT_navigate(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } +/** \} */ -/* ******************** add background image operator **************** */ +/* -------------------------------------------------------------------- */ +/** \name Background Image Add Operator + * \{ */ static CameraBGImage *background_image_add(bContext *C) { @@ -4536,7 +4349,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; Image *ima; CameraBGImage *bgpic; - + ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); /* may be NULL, continue anyway */ @@ -4566,7 +4379,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign"); WM_operator_properties_filesel( @@ -4574,8 +4387,12 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Background Image Remove Operator + * \{ */ -/* ***** remove image operator ******* */ static int background_image_remove_exec(bContext *C, wmOperator *op) { Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; @@ -4593,13 +4410,11 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) BKE_camera_background_image_remove(cam, bgpic_rem); WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); - return OPERATOR_FINISHED; } else { return OPERATOR_CANCELLED; } - } void VIEW3D_OT_background_image_remove(wmOperatorType *ot) @@ -4615,12 +4430,18 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot) /* flags */ ot->flag = 0; - + /* properties */ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove", 0, INT_MAX); } -/* ********************* set clipping operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Planes Operator + * + * Draw border or toggle off. + * \{ */ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float mat[4][4]) { @@ -4677,7 +4498,6 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev } } -/* toggles */ void VIEW3D_OT_clip_border(wmOperatorType *ot) { @@ -4697,11 +4517,15 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* flags */ ot->flag = 0; - /* rna */ + /* properties */ WM_operator_properties_border(ot); } -/* ***************** 3d cursor cursor op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Cursor Operator + * \{ */ /* cursor position in vec, result in vec, mval in region coords */ /* note: cannot use event->mval here (called by object_add() */ @@ -4712,14 +4536,14 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) RegionView3D *rv3d = ar->regiondata; bool flip; bool depth_used = false; - + /* normally the caller should ensure this, * but this is called from areas that aren't already dealing with the viewport */ if (rv3d == NULL) return; ED_view3d_calc_zfac(rv3d, fp, &flip); - + /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ if (flip) { negate_v3_v3(fp, rv3d->ofs); @@ -4727,7 +4551,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ ); } - if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ + if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */ EvaluationContext eval_ctx; struct Depsgraph *graph = CTX_data_depsgraph(C); @@ -4808,26 +4632,27 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* flags */ // ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; - - /* rna later */ - } -/* ***************** manipulator op ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Enable Transform Manipulator Operator + * \{ */ static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { View3D *v3d = CTX_wm_view3d(C); v3d->twtype = 0; - + if (RNA_boolean_get(op->ptr, "translate")) v3d->twtype |= V3D_MANIP_TRANSLATE; if (RNA_boolean_get(op->ptr, "rotate")) v3d->twtype |= V3D_MANIP_ROTATE; if (RNA_boolean_get(op->ptr, "scale")) v3d->twtype |= V3D_MANIP_SCALE; - + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; @@ -4841,12 +4666,12 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) ot->name = "Enable 3D Manipulator"; ot->description = "Enable the transform manipulator for use"; ot->idname = "VIEW3D_OT_enable_manipulator"; - + /* api callbacks */ ot->invoke = enable_manipulator_invoke; ot->poll = ED_operator_view3d_active; - - /* rna later */ + + /* properties */ prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator"); @@ -4855,7 +4680,11 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************* Toggle rendered shading *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Render Shading Operator + * \{ */ static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -4884,315 +4713,4 @@ void VIEW3D_OT_toggle_render(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } -/* ************************* below the line! *********************** */ - - -static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) -{ - ViewDepths depth_temp = {0}; - rcti rect; - float depth_close; - - if (margin == 0) { - /* Get Z Depths, needed for perspective, nice for ortho */ - rect.xmin = mval[0]; - rect.ymin = mval[1]; - rect.xmax = mval[0] + 1; - rect.ymax = mval[1] + 1; - } - else { - BLI_rcti_init_pt_radius(&rect, mval, margin); - } - - view3d_update_depths_rect(ar, &depth_temp, &rect); - depth_close = view3d_depth_near(&depth_temp); - MEM_SAFE_FREE(depth_temp.depths); - return depth_close; -} - -/** - * Get the world-space 3d location from a screen-space 2d point. - * - * \param mval: Input screen-space pixel location. - * \param mouse_worldloc: Output world-space location. - * \param fallback_depth_pt: Use this points depth when no depth can be found. - */ -bool ED_view3d_autodist( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, - const int mval[2], float mouse_worldloc[3], - const bool alphaoverride, const float fallback_depth_pt[3]) -{ - float depth_close; - int margin_arr[] = {0, 2, 4}; - int i; - bool depth_ok = false; - - /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); - - /* Attempt with low margin's first */ - i = 0; - do { - depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); - depth_ok = (depth_close != FLT_MAX); - } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); - - if (depth_ok) { - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - - if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { - return true; - } - } - - if (fallback_depth_pt) { - ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); - return true; - } - else { - return false; - } -} - -void ED_view3d_autodist_init( - const EvaluationContext *eval_ctx, struct Depsgraph *graph, - ARegion *ar, View3D *v3d, int mode) -{ - /* Get Z Depths, needed for perspective, nice for ortho */ - switch (mode) { - case 0: - ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); - break; - case 1: - { - Scene *scene = DEG_get_evaluated_scene(graph); - ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); - break; - } - } -} - -/* no 4x4 sampling, run #ED_view3d_autodist_init first */ -bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], - int margin, float *force_depth) -{ - float depth; - - /* Get Z Depths, needed for perspective, nice for ortho */ - if (force_depth) - depth = *force_depth; - else - depth = view_autodist_depth_margin(ar, mval, margin); - - if (depth == FLT_MAX) - return false; - - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); -} - -bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) -{ - *depth = view_autodist_depth_margin(ar, mval, margin); - - return (*depth != FLT_MAX); -} - -static bool depth_segment_cb(int x, int y, void *userData) -{ - struct { ARegion *ar; int margin; float depth; } *data = userData; - int mval[2]; - float depth; - - mval[0] = x; - mval[1] = y; - - depth = view_autodist_depth_margin(data->ar, mval, data->margin); - - if (depth != FLT_MAX) { - data->depth = depth; - return 0; - } - else { - return 1; - } -} - -bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int mval_end[2], - int margin, float *depth) -{ - struct { ARegion *ar; int margin; float depth; } data = {NULL}; - int p1[2]; - int p2[2]; - - data.ar = ar; - data.margin = margin; - data.depth = FLT_MAX; - - copy_v2_v2_int(p1, mval_sta); - copy_v2_v2_int(p2, mval_end); - - BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); - - *depth = data.depth; - - return (*depth != FLT_MAX); -} - -/* problem - ofs[3] can be on same location as camera itself. - * Blender needs proper dist value for zoom. - * use fallback_dist to override small values - */ -float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) -{ - float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float dist; - - mul_m4_v4(mat, pos); - add_v3_v3(pos, ofs); - mul_m4_v4(mat, dir); - normalize_v3(dir); - - dist = dot_v3v3(pos, dir); - - if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { - dist = fallback_dist; - } - - return dist; -} - -/** - * Set the dist without moving the view (compensate with #RegionView3D.ofs) - * - * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. - */ -void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) -{ - float viewinv[4]; - float tvec[3]; - - BLI_assert(dist >= 0.0f); - - copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); - /* rv3d->viewinv isn't always valid */ -#if 0 - mul_mat3_m4_v3(rv3d->viewinv, tvec); -#else - invert_qt_qt_normalized(viewinv, rv3d->viewquat); - mul_qt_v3(viewinv, tvec); -#endif - sub_v3_v3(rv3d->ofs, tvec); - - rv3d->dist = dist; -} - -/** - * Set the view transformation from a 4x4 matrix. - * - * \param mat The view 4x4 transformation matrix to assign. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) -{ - float nmat[3][3]; - - /* dist depends on offset */ - BLI_assert(dist == NULL || ofs != NULL); - - copy_m3_m4(nmat, mat); - normalize_m3(nmat); - - /* Offset */ - if (ofs) - negate_v3_v3(ofs, mat[3]); - - /* Quat */ - if (quat) { - mat3_normalized_to_quat(quat, nmat); - invert_qt_normalized(quat); - } - - if (ofs && dist) { - madd_v3_v3fl(ofs, nmat[2], *dist); - } -} - -/** - * Calculate the view transformation matrix from RegionView3D input. - * The resulting matrix is equivalent to RegionView3D.viewinv - * \param mat The view 4x4 transformation matrix to calculate. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) -{ - float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; - float dvec[3] = {0.0f, 0.0f, dist}; - - quat_to_mat4(mat, iviewquat); - mul_mat3_m4_v3(mat, dvec); - sub_v3_v3v3(mat[3], dvec, ofs); -} - -/** - * Set the RegionView3D members from an objects transformation and optionally lens. - * \param ob The object to set the view to. - * \param ofs The view offset to be set, normally from RegionView3D.ofs. - * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. - * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. - */ -void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) -{ - ED_view3d_from_m4(ob->obmat, ofs, quat, dist); - - if (lens) { - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, ob); - *lens = params.lens; - } -} - -/** - * Set the object transformation from RegionView3D members. - * \param ob The object which has the transformation assigned. - * \param ofs The view offset, normally from RegionView3D.ofs. - * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. - * \param dist The view distance from ofs, normally from RegionView3D.dist. - */ -void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) -{ - float mat[4][4]; - - ED_view3d_to_m4(mat, ofs, quat, dist); - BKE_object_apply_mat4(ob, mat, true, true); -} - -/** - * Use to store the last view, before entering camera view. - */ -void ED_view3d_lastview_store(RegionView3D *rv3d) -{ - copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); - rv3d->lview = rv3d->view; - if (rv3d->persp != RV3D_CAMOB) { - rv3d->lpersp = rv3d->persp; - } -} - -void ED_view3D_lock_clear(View3D *v3d) -{ - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - v3d->ob_centre_cursor = false; - v3d->flag2 &= ~V3D_LOCK_CAMERA; -} +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 5e7eddb1c22..d2aa19509d7 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -58,6 +58,8 @@ #include "GPU_immediate.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -193,6 +195,7 @@ typedef struct FlyInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + const struct Depsgraph *depsgraph; Scene *scene; wmTimer *timer; /* needed for redraws */ @@ -242,7 +245,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), float x1, x2, y1, y2; if (fly->scene->camera) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); xoff = viewborder.xmin; yoff = viewborder.ymin; } @@ -343,6 +346,10 @@ enum { static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); + rctf viewborder; float upvec[3]; /* tmp */ @@ -351,6 +358,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent fly->rv3d = CTX_wm_region_view3d(C); fly->v3d = CTX_wm_view3d(C); fly->ar = CTX_wm_region(C); + fly->depsgraph = CTX_data_depsgraph(C); fly->scene = CTX_data_scene(C); #ifdef NDOF_FLY_DEBUG @@ -417,12 +425,12 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent } fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, fly->scene, fly->v3d, fly->rv3d, + &eval_ctx, fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* calculate center */ if (fly->scene->camera) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); fly->width = BLI_rctf_size_x(&viewborder); fly->height = BLI_rctf_size_y(&viewborder); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index f86f6423f93..d1968166904 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -111,6 +111,7 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_render(struct wmOperatorType *ot); void view3d_boxview_copy(ScrArea *sa, ARegion *ar); +void view3d_boxview_sync(ScrArea *sa, ARegion *ar); void view3d_orbit_apply_dyn_ofs( float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], @@ -153,7 +154,7 @@ void draw_object_select( const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, struct ARegion *ar, View3D *v3d, Base *base, const short dflag); -void draw_mesh_object_outline(View3D *v3d, Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]); +void draw_mesh_object_outline(View3D *v3d, struct Object *ob, struct DerivedMesh *dm, const unsigned char ob_wire_col[4]); bool draw_glsl_material(Scene *scene, struct ViewLayer *view_layer, struct Object *ob, View3D *v3d, const char dt); void draw_object_instance(const struct EvaluationContext *eval_ctx, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline, const float wire_col[4]); @@ -233,9 +234,6 @@ void ED_view3d_draw_select_loop( void ED_view3d_draw_depth_loop( const struct EvaluationContext *eval_ctx, Scene *scene, ARegion *ar, View3D *v3d); -void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame); - void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect); @@ -279,8 +277,12 @@ void ED_view3d_smooth_view_force_finish( struct bContext *C, struct View3D *v3d, struct ARegion *ar); -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect); -void view3d_viewmatrix_set(const struct EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d); +void view3d_winmatrix_set( + const struct Depsgraph *depsgraph, + ARegion *ar, const View3D *v3d, const rcti *rect); +void view3d_viewmatrix_set( + const struct EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]); void fly_modal_keymap(struct wmKeyConfig *keyconf); void walk_modal_keymap(struct wmKeyConfig *keyconf); @@ -295,7 +297,7 @@ void view3d_buttons_register(struct ARegionType *art); /* view3d_camera_control.c */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - const struct bContext *C, Scene *scene, View3D *v3d, RegionView3D *rv3d, + const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root); void ED_view3d_cameracontrol_update( struct View3DCameraControl *vctrl, @@ -304,7 +306,7 @@ void ED_view3d_cameracontrol_update( void ED_view3d_cameracontrol_release( struct View3DCameraControl *vctrl, const bool restore); -Object *ED_view3d_cameracontrol_object_get( +struct Object *ED_view3d_cameracontrol_object_get( struct View3DCameraControl *vctrl); /* view3d_toolbar.c */ @@ -337,11 +339,14 @@ void VIEW3D_WGT_camera_view(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_force_field(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_empty_image(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_armature_spline(struct wmManipulatorGroupType *wgt); +void VIEW3D_WGT_navigate(struct wmManipulatorGroupType *wgt); void VIEW3D_WGT_ruler(struct wmManipulatorGroupType *wgt); void VIEW3D_WT_ruler_item(struct wmManipulatorType *wt); void VIEW3D_OT_ruler_add(struct wmOperatorType *ot); +void VIEW3D_WT_navigate_rotate(struct wmManipulatorType *wt); + /* draw_volume.c */ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], @@ -364,7 +369,7 @@ extern bool view3d_camera_border_hack_test; void VP_legacy_drawcursor(Scene *scene, struct ViewLayer *view_layer, ARegion *ar, View3D *v3d); void VP_legacy_draw_view_axis(RegionView3D *rv3d, rcti *rect); void VP_legacy_draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect); -void VP_legacy_draw_selected_name(Scene *scene, Object *ob, rcti *rect); +void VP_legacy_draw_selected_name(Scene *scene, struct Object *ob, rcti *rect); void VP_legacy_drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit); void VP_legacy_drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth); void VP_legacy_view3d_main_region_setup_view(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]); @@ -372,7 +377,7 @@ bool VP_legacy_view3d_stereo3d_active(struct wmWindow *win, Scene *scene, View3D void VP_legacy_view3d_stereo3d_setup(const struct EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, ARegion *ar); void draw_dupli_objects(const struct EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, Base *base); bool VP_legacy_use_depth(Scene *scene, View3D *v3d); -void VP_drawviewborder(Scene *scene, ARegion *ar, View3D *v3d); +void VP_drawviewborder(Scene *scene, const struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d); void VP_drawrenderborder(ARegion *ar, View3D *v3d); void VP_view3d_draw_background_none(void); void VP_view3d_draw_background_world(Scene *scene, RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index d020571930a..6a45ec5095f 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -378,11 +378,12 @@ static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmManipulato struct CameraViewWidgetGroup *viewgroup = mgroup->customdata; ARegion *ar = CTX_wm_region(C); + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; if (rv3d->persp == RV3D_CAMOB) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewgroup->state.view_border, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false); } else { viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy}; diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c new file mode 100644 index 00000000000..6a5d63b180f --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -0,0 +1,359 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_manipulator_navigate.c + * \ingroup spview3d + */ + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" + +#include "ED_screen.h" +#include "ED_manipulator_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View3D Navigation Manipulator Group + * \{ */ + +/* Offset from screen edge. */ +#define MANIPULATOR_OFFSET_FAC 2.5 +/* Size of main icon. */ +#define MANIPULATOR_SIZE 64 +/* Factor for size of smaller button. */ +#define MANIPULATOR_MINI_FAC 0.5 +/* How much mini buttons offset from the primary. */ +#define MANIPULATOR_MINI_OFFSET_FAC 0.6666f + + +enum { + MPR_MOVE = 0, + MPR_ROTATE = 1, + MPR_ZOOM = 2, + + /* just buttons */ + /* overlaps MPR_ORTHO (switch between) */ + MPR_PERSP = 3, + MPR_ORTHO = 4, + MPR_CAMERA = 5, + + MPR_TOTAL = 6, +}; + +/* Vector icons compatible with 'GPU_batch_from_poly_2d_encoded' */ +static const uchar shape_camera[] = { + 0xa3, 0x19, 0x78, 0x55, 0x4d, 0x19, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xa9, 0x19, + 0xa9, 0x19, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, + 0x4d, 0x19, 0x47, 0x19, 0x65, 0x55, 0x41, 0x55, 0x41, 0x9e, 0x43, 0xa8, 0x38, 0xb3, + 0x34, 0xc3, 0x38, 0xd2, 0x43, 0xdd, 0x53, 0xe1, 0x62, 0xdd, 0x6d, 0xd2, 0x72, 0xc3, + 0x78, 0xc3, 0x7c, 0xd2, 0x87, 0xdd, 0x96, 0xe1, 0xa6, 0xdd, 0xb1, 0xd2, 0xb5, 0xc3, + 0xb1, 0xb3, 0xa6, 0xa8, 0xa9, 0x9e, 0xa9, 0x8c, 0xbb, 0x8c, 0xbb, 0x86, 0xc7, 0x86, + 0xe0, 0x9e, 0xe0, 0x55, 0xc7, 0x6d, 0xbb, 0x6d, 0xbb, 0x67, 0xa9, 0x67, 0xa9, 0x55, + 0x8a, 0x55, 0xa9, 0x19, 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x4f, 0xf5, 0x7c, 0xb3, 0x78, 0xc3, + 0x72, 0xc3, 0x6d, 0xb3, 0x62, 0xa8, 0x53, 0xa4, 0x43, 0xa8, 0x41, 0x9e, 0xa9, 0x9e, + 0xa6, 0xa8, 0x96, 0xa4, 0x87, 0xa8, 0x87, 0xa8, +}; +static const uchar shape_ortho[] = { + 0x85, 0x15, 0x85, 0x7c, 0xde, 0xb3, 0xde, 0xb8, 0xd9, 0xba, 0x80, 0x85, 0x27, 0xba, + 0x22, 0xb8, 0x22, 0xb3, 0x7b, 0x7c, 0x7b, 0x15, 0x80, 0x12, 0x80, 0x12, 0x1d, 0xba, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x0d, 0x1d, 0x45, 0x1d, 0x45, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x80, 0xf2, 0xe3, 0xba, 0xe3, 0x45, 0x80, 0x0d, 0x7f, 0x00, 0x7f, 0x00, +}; +static const uchar shape_pan[] = { + 0xbf, 0x4c, 0xbf, 0x66, 0x99, 0x66, 0x99, 0x40, 0xb2, 0x40, 0x7f, 0x0d, 0x7f, 0x00, + 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, + 0x80, 0xff, 0x80, 0xf2, 0xb3, 0xbf, 0x99, 0xbf, 0x99, 0x99, 0xbf, 0x99, 0xbf, 0xb2, + 0xf2, 0x7f, 0xf2, 0x7f, 0x40, 0xb3, 0x40, 0x99, 0x66, 0x99, 0x66, 0xbf, 0x4d, 0xbf, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x7f, 0x0d, 0x4c, 0x40, 0x66, 0x40, 0x66, 0x66, + 0x40, 0x66, 0x40, 0x4d, 0x0d, 0x80, 0x0d, 0x80, +}; +static const uchar shape_persp[] = { + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, + 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x07, 0x30, 0x50, 0x18, 0xbd, + 0x80, 0xdb, 0xe8, 0xbd, 0xf5, 0xb0, 0xf5, 0xb0, 0x83, 0x0f, 0x87, 0x7b, 0xe2, 0xb7, + 0xe3, 0xba, 0xe0, 0xbb, 0x80, 0x87, 0x20, 0xbb, 0x1d, 0xba, 0x1d, 0xb7, 0x78, 0x7b, + 0x7d, 0x0f, 0x80, 0x0c, 0x80, 0x0c, 0xd0, 0x50, 0x80, 0x07, 0x7f, 0x00, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xe8, 0xbd, 0xe8, 0xbd, +}; +static const uchar shape_zoom[] = { + 0xad, 0x7f, 0xf1, 0x7f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0d, 0x7f, 0x52, 0x7f, 0x69, 0xb7, + 0x48, 0xb7, 0x80, 0xd8, 0xb8, 0xb7, 0x96, 0xb7, 0x96, 0xb7, 0x7f, 0x2f, 0x0d, 0x7f, + 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xda, 0x25, + 0xf5, 0x4f, 0xff, 0x80, 0xf1, 0x7f, 0xf1, 0x7f, +}; + + +struct NavigateManipulatorInfo { + const char *opname; + const char *manipulator; + const unsigned char *shape; + uint shape_size; +}; + +#define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id) + +struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = { + { + .opname = "VIEW3D_OT_move", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_pan), + }, { + .opname = "VIEW3D_OT_rotate", + .manipulator = "VIEW3D_WT_navigate_rotate", + .shape = NULL, + .shape_size = 0, + }, { + .opname = "VIEW3D_OT_zoom", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_zoom), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_persp), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_ortho), + }, { + .opname = "VIEW3D_OT_viewnumpad", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_camera), + }, +}; + +#undef SHAPE_VARS + +struct NavigateWidgetGroup { + wmManipulator *mpr_array[MPR_TOTAL]; + /* Store the view state to check for changes. */ + struct { + struct { + short winx, winy; + } ar; + struct { + char is_persp; + char viewlock; + } rv3d; + } state; + int region_size[2]; + bool is_persp; +}; + +static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmManipulatorGroupType *UNUSED(wgt)) +{ + if (U.manipulator_flag & USER_MANIPULATOR_DRAW_NAVIGATE) { + return true; + } + return false; + +} + +static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__); + + navgroup->region_size[0] = -1; + navgroup->region_size[1] = -1; + + wmOperatorType *ot_viewnumpad = WM_operatortype_find("VIEW3D_OT_viewnumpad", true); + + for (int i = 0; i < MPR_TOTAL; i++) { + const struct NavigateManipulatorInfo *info = &g_navigate_params[i]; + navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL); + wmManipulator *mpr = navgroup->mpr_array[i]; + mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL; + mpr->color[3] = 0.2f; + mpr->color_hi[3] = 0.4f; + + /* may be overwritten later */ + mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2; + if (info->shape != NULL) { + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "shape"); + RNA_property_string_set_bytes( + mpr->ptr, prop, + (const char *)info->shape, info->shape_size); + } + + wmOperatorType *ot = WM_operatortype_find(info->opname, true); + WM_manipulator_operator_set(mpr, 0, ot, NULL); + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_CAMERA]; + PointerRNA *ptr = WM_manipulator_operator_set(mpr, 0, ot_viewnumpad, NULL); + RNA_enum_set(ptr, "type", RV3D_VIEW_CAMERA); + } + + /* Click only buttons (not modal). */ + { + int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + RNA_boolean_set(mpr->ptr, "show_drag", false); + } + } + + /* Modal operators, don't use initial mouse location since we're clicking on a button. */ + { + int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0); + RNA_boolean_set(&mpop->ptr, "use_mouse_init", false); + } + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->scale_basis = MANIPULATOR_SIZE / 2; + char mapping[6] = { + RV3D_VIEW_LEFT, + RV3D_VIEW_RIGHT, + RV3D_VIEW_FRONT, + RV3D_VIEW_BACK, + RV3D_VIEW_BOTTOM, + RV3D_VIEW_TOP, + }; + + for (int part_index = 0; part_index < 6; part_index += 1) { + PointerRNA *ptr = WM_manipulator_operator_set(mpr, part_index + 1, ot_viewnumpad, NULL); + RNA_enum_set(ptr, "type", mapping[part_index]); + } + + /* When dragging an axis, use this instead. */ + mpr->drag_part = 0; + } + + mgroup->customdata = navgroup; +} + +static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct NavigateWidgetGroup *navgroup = mgroup->customdata; + ARegion *ar = CTX_wm_region(C); + const RegionView3D *rv3d = ar->regiondata; + + for (int i = 0; i < 3; i++) { + copy_v3_v3(navgroup->mpr_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]); + } + + if ((navgroup->state.ar.winx == ar->winx) && + (navgroup->state.ar.winy == ar->winy) && + (navgroup->state.rv3d.is_persp == rv3d->is_persp) && + (navgroup->state.rv3d.viewlock == rv3d->viewlock)) + { + return; + } + + + navgroup->state.ar.winx = ar->winx; + navgroup->state.ar.winy = ar->winy; + navgroup->state.rv3d.is_persp = rv3d->is_persp; + navgroup->state.rv3d.viewlock = rv3d->viewlock; + + + const float icon_size = MANIPULATOR_SIZE; + const float icon_offset = (icon_size / 2.0) * MANIPULATOR_OFFSET_FAC * U.ui_scale; + const float icon_offset_mini = icon_size * MANIPULATOR_MINI_OFFSET_FAC * U.ui_scale; + const float co[2] = {ar->winx - icon_offset, ar->winy - icon_offset}; + + wmManipulator *mpr; + + for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) { + mpr = navgroup->mpr_array[i]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] - icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_ORTHO : MPR_PERSP]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_CAMERA]; + mpr->matrix_basis[3][0] = co[0] - icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } + else { + /* RV3D_LOCKED: only show supported buttons. */ + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] + icon_offset_mini; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0]; + mpr->matrix_basis[3][1] = co[1] + icon_offset_mini; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } +} + +void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) +{ + wgt->name = "View3D Navigate"; + wgt->idname = "VIEW3D_WGT_navigate"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_SCALE | + WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL); + + wgt->poll = WIDGETGROUP_navigate_poll; + wgt->setup = WIDGETGROUP_navigate_setup; + wgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c new file mode 100644 index 00000000000..424b5dae402 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c @@ -0,0 +1,307 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file view3d_manipulator_navigate_type.c + * \ingroup wm + * + * \name Custom Orientation/Navigation Manipulator for the 3D View + * + * \brief Simple manipulator to axis and translate. + * + * - scale_basis: used for the size. + * - matrix_basis: used for the location. + * - matrix_offset: used to store the orientation. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_sort_utils.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" + +#define DIAL_RESOLUTION 32 + +#define HANDLE_SIZE 0.33 + +static void axis_geom_draw( + const wmManipulator *mpr, const float color[4], const bool UNUSED(select)) +{ + glLineWidth(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + const uint pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + /* flip z for reverse */ + const float cone_coords[5][3] = { + {-1, -1, 4}, + {-1, +1, 4}, + {+1, +1, 4}, + {+1, -1, 4}, + {0, 0, 2}, + }; + + struct { + float depth; + char index; + char axis; + char is_pos; + } axis_order[6] = { + {-mpr->matrix_offset[0][2], 0, 0, false}, + {+mpr->matrix_offset[0][2], 1, 0, true}, + {-mpr->matrix_offset[1][2], 2, 1, false}, + {+mpr->matrix_offset[1][2], 3, 1, true}, + {-mpr->matrix_offset[2][2], 4, 2, false}, + {+mpr->matrix_offset[2][2], 5, 2, true}, + }; + qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); + + const float scale_axis = 0.25f; + static const float axis_highlight[4] = {1, 1, 1, 1}; + static const float axis_nop[4] = {1, 1, 1, 0}; + static const float axis_black[4] = {0, 0, 0, 1}; + static float axis_color[3][4]; + gpuPushMatrix(); + gpuMultMatrix(mpr->matrix_offset); + + bool draw_center_done = false; + + for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) { + const int index = axis_order[axis_index].index; + const int axis = axis_order[axis_index].axis; + const bool is_pos = axis_order[axis_index].is_pos; + + /* Draw slightly before, so axis aligned arrows draw ontop. */ + if ((draw_center_done == false) && (axis_order[axis_index].depth > -0.01f)) { + + /* Circle defining active area (revert back to 2D space). */ + { + gpuPopMatrix(); + immUniformColor4fv(color); + imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION); + gpuPushMatrix(); + gpuMultMatrix(mpr->matrix_offset); + } + + /* Center cube. */ + { + float center[3], size[3]; + + zero_v3(center); + copy_v3_fl(size, HANDLE_SIZE); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + glBlendFunc(GL_ONE, GL_ZERO); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glLineWidth(1.0f); + /* Just draw depth values. */ + immUniformColor4fv(axis_nop); + imm_draw_cube_fill_3d(pos_id, center, size); + immUniformColor4fv(axis_black); + madd_v3_v3fl( + center, + (float [3]){ + mpr->matrix_offset[0][2], + mpr->matrix_offset[1][2], + mpr->matrix_offset[2][2]}, + 0.08f); + imm_draw_cube_wire_3d(pos_id, center, size); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_DEPTH_TEST); + } + + draw_center_done = true; + } + UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]); + axis_color[axis][3] = 1.0f; + + const int index_z = axis; + const int index_y = (axis + 1) % 3; + const int index_x = (axis + 2) % 3; + +#define ROTATED_VERT(v_orig) \ + { \ + float v[3]; \ + copy_v3_v3(v, v_orig); \ + if (is_pos == 0) { \ + v[2] *= -1.0f; \ + } \ + immVertex3f(pos_id, v[index_x] * scale_axis, v[index_y] * scale_axis, v[index_z] * scale_axis); \ + } ((void)0) + + bool ok = true; + + /* skip view align axis */ + if (len_squared_v2(mpr->matrix_offset[axis]) < 1e-6f && (mpr->matrix_offset[axis][2] > 0.0f) == is_pos) { + ok = false; + } + if (ok) { + immUniformColor4fv(index + 1 == mpr->highlight_part ? axis_highlight : axis_color[axis]); + immBegin(GWN_PRIM_TRI_FAN, 6); + ROTATED_VERT(cone_coords[4]); + for (int j = 0; j <= 4; j++) { + ROTATED_VERT(cone_coords[j % 4]); + } + immEnd(); + } + +#undef ROTATED_VERT + } + + gpuPopMatrix(); + immUnbindProgram(); +} + +static void axis3d_draw_intern( + const bContext *UNUSED(C), wmManipulator *mpr, + const bool select, const bool highlight) +{ + const float *color = highlight ? mpr->color_hi : mpr->color; + float matrix_final[4][4]; + float matrix_unit[4][4]; + + unit_m4(matrix_unit); + + WM_manipulator_calc_matrix_final_params( + mpr, + &((struct WM_ManipulatorMatrixParams) { + .matrix_offset = matrix_unit, + }), matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + glEnable(GL_BLEND); + axis_geom_draw(mpr, color, select); + glDisable(GL_BLEND); + gpuPopMatrix(); +} + +static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + (void)is_modal; + + glEnable(GL_BLEND); + axis3d_draw_intern(C, mpr, false, is_highlight); + glDisable(GL_BLEND); +} + +static int manipulator_axis_test_select( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2] = {UNPACK2(event->mval)}; + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); + + const float len_sq = len_squared_v2(point_local); + if (len_sq > 1.0) { + return -1; + } + + int part_best = -1; + int part_index = 1; + /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */ + float i_best_len_sq = FLT_MAX; + for (int i = 0; i < 3; i++) { + for (int is_pos = 0; is_pos < 2; is_pos++) { + float co[2] = { + mpr->matrix_offset[i][0] * (is_pos ? 1 : -1), + mpr->matrix_offset[i][1] * (is_pos ? 1 : -1), + }; + + bool ok = true; + + /* Check if we're viewing on an axis, there is no point to clicking on the current axis so show the reverse. */ + if (len_squared_v2(co) < 1e-6f && (mpr->matrix_offset[i][2] > 0.0f) == is_pos) { + ok = false; + } + + if (ok) { + const float len_axis_sq = len_squared_v2v2(co, point_local); + if (len_axis_sq < i_best_len_sq) { + part_best = part_index; + i_best_len_sq = len_axis_sq; + } + } + part_index += 1; + } + } + + if (part_best != -1) { + return part_best; + } + + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_sq < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_axis_cursor_get(wmManipulator *mpr) +{ + if (mpr->highlight_part > 0) { + return CURSOR_EDIT; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_WT_navigate_rotate(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "VIEW3D_WT_navigate_rotate"; + + /* api callbacks */ + wt->draw = manipulator_axis_draw; + wt->test_select = manipulator_axis_test_select; + wt->cursor_get = manipulator_axis_cursor_get; + + wt->struct_size = sizeof(wmManipulator); +} diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 230b4f44c16..e8d540bcc9d 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -148,6 +148,11 @@ static RulerItem *ruler_item_add(wmManipulatorGroup *mgroup) return ruler_item; } +static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item) +{ + WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C); +} + static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, char *numstr, size_t numstr_size, int prec) { @@ -908,16 +913,24 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c { wmManipulatorGroup *mgroup = mpr->parent_mgroup; RulerInfo *ruler_info = mgroup->customdata; - RulerItem *ruler_item = (RulerItem *)mpr; - RulerInteraction *inter = mpr->interaction_data; if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { + RulerItem *ruler_item = (RulerItem *)mpr; + RulerInteraction *inter = mpr->interaction_data; /* rubber-band angle removal */ - if (ruler_item && (inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { - if (!inter->inside_region) { + if (!inter->inside_region) { + if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { ruler_item->flag &= ~RULERITEM_USE_ANGLE; } + else { + /* Not ideal, since the ruler isn't a mode and we don't want to override delete key + * use dragging out of the view for removal. */ + ruler_item_remove(C, mgroup, ruler_item); + ruler_item = NULL; + mpr = NULL; + inter = NULL; + } } if (ruler_info->snap_flag & RULER_SNAP_OK) { ruler_info->snap_flag &= ~RULER_SNAP_OK; @@ -928,7 +941,9 @@ static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool c view3d_ruler_to_gpencil(C, mgroup); } - MEM_SAFE_FREE(mpr->interaction_data); + if (mpr) { + MEM_SAFE_FREE(mpr->interaction_data); + } ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); } @@ -996,7 +1011,7 @@ void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) wgt->name = "Ruler Widgets"; wgt->idname = view3d_wgt_ruler_id; - wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE; + wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL; wgt->mmap_params.spaceid = SPACE_VIEW3D; wgt->mmap_params.regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index f8b02f0b405..ba3e78b25b9 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -277,6 +277,11 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[ /* More Generic Window/Ray/Vector projection functions * *************************************************** */ +float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) +{ + return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; +} + /** * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta */ @@ -304,6 +309,7 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f } static void view3d_win_to_ray_segment( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) { @@ -321,7 +327,7 @@ static void view3d_win_to_ray_segment( start_offset = -end_offset; } else { - ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false); + ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false); } if (r_ray_start) { @@ -360,12 +366,13 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray_ex( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) { float ray_end[3]; - view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); /* bounds clipping */ if (do_clip) { @@ -389,10 +396,11 @@ bool ED_view3d_win_to_ray_ex( * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray( + const struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_normal[3], const bool do_clip) { - return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); + return ED_view3d_win_to_ray_ex(depsgraph,ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); } /** @@ -622,10 +630,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3 * \param do_clip Optionally clip the ray by the view clipping planes. * \return success, false if the segment is totally clipped. */ -bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2], +bool ED_view3d_win_to_segment(const struct Depsgraph *depsgraph, + const ARegion *ar, View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip) { - view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); /* bounds clipping */ if (do_clip) { diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c new file mode 100644 index 00000000000..7bb3f443ac6 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -0,0 +1,1436 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_utils.c + * \ingroup spview3d + * + * 3D View checks and manipulation (no operators). + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <float.h> + +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap_draw_2d.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_screen.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_matrix.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View Data Access Utilities + * + * \{ */ + +float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) +{ + if (v3d && v3d->localvd) return v3d->cursor; + else return scene->cursor; +} + +Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) +{ + /* establish the camera object, so we can default to view mapping if anything is wrong with it */ + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { + return v3d->camera->data; + } + else { + return NULL; + } +} + +void ED_view3d_dist_range_get( + const View3D *v3d, + float r_dist_range[2]) +{ + r_dist_range[0] = v3d->grid * 0.001f; + r_dist_range[1] = v3d->far * 10.0f; +} + +/** + * \note copies logic of #ED_view3d_viewplane_get(), keep in sync. + */ +bool ED_view3d_clip_range_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, + float *r_clipsta, float *r_clipend, + const bool use_ortho_factor) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + + if (use_ortho_factor && params.is_ortho) { + const float fac = 2.0f / (params.clipend - params.clipsta); + params.clipsta *= fac; + params.clipend *= fac; + } + + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + + return params.is_ortho; +} + +bool ED_view3d_viewplane_get( + const Depsgraph *depsgraph, + const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, + rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) +{ + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); + BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); + + if (r_viewplane) *r_viewplane = params.viewplane; + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; + if (r_pixsize) *r_pixsize = params.viewdx; + + return params.is_ortho; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name View State/Context Utilities + * + * \{ */ + +/** + * Use this call when executing an operator, + * event system doesn't set for each event the OpenGL drawing context. + */ +void view3d_operator_needs_opengl(const bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + + view3d_region_operator_needs_opengl(win, ar); +} + +void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) +{ + /* for debugging purpose, context should always be OK */ + if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { + printf("view3d_region_operator_needs_opengl error, wrong region\n"); + } + else { + RegionView3D *rv3d = ar->regiondata; + + wmSubWindowSet(win, ar->swinid); + gpuLoadProjectionMatrix(rv3d->winmat); + gpuLoadMatrix(rv3d->viewmat); + } +} + +/** + * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] + */ +void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) +{ + float viewdist; + + if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { + return; + } + + viewdist = rv3d->dist; + + /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ + if (dist != 0.0f) { + if (rv3d->persp == RV3D_CAMOB) { + if (rv3d->is_persp == false) { + viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); + } + } + } + + bglPolygonOffset(viewdist, dist); +} + +bool ED_view3d_context_activate(bContext *C) +{ + bScreen *sc = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar; + + /* sa can be NULL when called from python */ + if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { + sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); + } + + if (sa == NULL) { + return false; + } + + ar = BKE_area_find_region_active_win(sa); + if (ar == NULL) { + return false; + } + + /* bad context switch .. */ + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Clipping Utilities + * + * \{ */ + +void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) +{ + int val; + + for (val = 0; val < 4; val++) { + normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); + if (UNLIKELY(is_flip)) { + negate_v3(clip[val]); + } + + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); + } +} + +void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) +{ + /* init in case unproject fails */ + memset(bb->vec, 0, sizeof(bb->vec)); + + /* four clipping planes and bounding volume */ + /* first do the bounding volume */ + for (int val = 0; val < 4; val++) { + float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; + float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; + + ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); + ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); + } + + /* optionally transform to object space */ + if (ob) { + float imat[4][4]; + invert_m4_m4(imat, ob->obmat); + + for (int val = 0; val < 8; val++) { + mul_m4_v3(imat, bb->vec[val]); + } + } + + /* verify if we have negative scale. doing the transform before cross + * product flips the sign of the vector compared to doing cross product + * before transform then, so we correct for that. */ + int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; + + ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Bound-Box Utilities + * + * \{ */ + +static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) +{ + int a, flag = -1, fl; + + for (a = 0; a < 8; a++) { + float vec[4], min, max; + copy_v3_v3(vec, bb->vec[a]); + vec[3] = 1.0; + mul_m4_v4(persmatob, vec); + max = vec[3]; + min = -vec[3]; + + fl = 0; + if (vec[0] < min) fl += 1; + if (vec[0] > max) fl += 2; + if (vec[1] < min) fl += 4; + if (vec[1] > max) fl += 8; + if (vec[2] < min) fl += 16; + if (vec[2] > max) fl += 32; + + flag &= fl; + if (flag == 0) return true; + } + + return false; +} + +bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) +{ + /* return 1: draw */ + + float persmatob[4][4]; + + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); + + return view3d_boundbox_clip_m4(bb, persmatob); +} + +bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) +{ + if (bb == NULL) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; + + return view3d_boundbox_clip_m4(bb, rv3d->persmatob); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Perspective & Mode Switching + * + * Misc view utility functions. + * \{ */ + +bool ED_view3d_offset_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); +} + +/** + * Use to store the last view, before entering camera view. + */ +void ED_view3d_lastview_store(RegionView3D *rv3d) +{ + copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); + rv3d->lview = rv3d->view; + if (rv3d->persp != RV3D_CAMOB) { + rv3d->lpersp = rv3d->persp; + } +} + +void ED_view3d_lock_clear(View3D *v3d) +{ + v3d->ob_centre = NULL; + v3d->ob_centre_bone[0] = '\0'; + v3d->ob_centre_cursor = false; + v3d->flag2 &= ~V3D_LOCK_CAMERA; +} + +/** + * For viewport operators that exit camera perspective. + * + * \note This differs from simply setting ``rv3d->persp = persp`` because it + * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, + * otherwise switching out of camera view may jump to a different part of the scene. + */ +void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) +{ + BLI_assert(rv3d->persp == RV3D_CAMOB); + BLI_assert(persp != RV3D_CAMOB); + + if (v3d->camera) { + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } + + if (!ED_view3d_camera_lock_check(v3d, rv3d)) { + rv3d->persp = persp; + } +} +/** + * Action to take when rotating the view, + * handle auto-persp and logic for switching out of views. + * + * shared with NDOF. + */ +bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; + + BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); + + if (ED_view3d_camera_lock_check(v3d, rv3d)) + return false; + + if (rv3d->persp != RV3D_PERSP) { + if (rv3d->persp == RV3D_CAMOB) { + /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ + char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; + ED_view3d_persp_switch_from_camera(v3d, rv3d, persp); + } + else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->persp = RV3D_PERSP; + } + return true; + } + + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Lock API + * + * Lock the camera to the view-port, allowing view manipulation to transform the camera. + * \{ */ + +/** + * \return true when the view-port is locked to its camera. + */ +bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) +{ + return ((v3d->camera) && + (!ID_IS_LINKED(v3d->camera)) && + (v3d->flag2 & V3D_LOCK_CAMERA) && + (rv3d->persp == RV3D_CAMOB)); +} + +/** + * Apply the camera object transformation to the view-port. + * (needed so we can use regular view-port manipulation operators, that sync back to the camera). + */ +void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + if (calc_dist) { + /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + } + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } +} + +void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) +{ + ED_view3d_camera_lock_init_ex(v3d, rv3d, true); +} + +/** + * Apply the view-port transformation back to the camera object. + * + * \return true if the camera is moved. + */ +bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) +{ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + ObjectTfmProtectedChannels obtfm; + Object *root_parent; + + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + Object *ob_update; + float tmat[4][4]; + float imat[4][4]; + float view_mat[4][4]; + float diff_mat[4][4]; + float parent_mat[4][4]; + + while (root_parent->parent) { + root_parent = root_parent->parent; + } + + ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); + + normalize_m4_m4(tmat, v3d->camera->obmat); + + invert_m4_m4(imat, tmat); + mul_m4_m4m4(diff_mat, view_mat, imat); + + mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); + + BKE_object_tfm_protected_backup(root_parent, &obtfm); + BKE_object_apply_mat4(root_parent, parent_mat, true, false); + BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag); + + ob_update = v3d->camera; + while (ob_update) { + DEG_id_tag_update(&ob_update->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); + ob_update = ob_update->parent; + } + } + else { + /* always maintain the same scale */ + const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); + BKE_object_tfm_protected_backup(v3d->camera, &obtfm); + ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); + + DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); + } + + return true; + } + else { + return false; + } +} + +bool ED_view3d_camera_autokey( + Scene *scene, ID *id_key, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + if (autokeyframe_cfra_can_key(scene, id_key)) { + const float cfra = (float)CFRA; + ListBase dsources = {NULL, NULL}; + + /* add data-source override for the camera object */ + ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); + + /* insert keyframes + * 1) on the first frame + * 2) on each subsequent frame + * TODO: need to check in future that frame changed before doing this + */ + if (do_rotate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_ROTATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + if (do_translate) { + struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + } + + /* free temp data */ + BLI_freelistN(&dsources); + + return true; + } + else { + return false; + } +} + +/** + * Call after modifying a locked view. + * + * \note Not every view edit currently auto-keys (numpad for eg), + * this is complicated because of smoothview. + */ +bool ED_view3d_camera_lock_autokey( + View3D *v3d, RegionView3D *rv3d, + struct bContext *C, const bool do_rotate, const bool do_translate) +{ + /* similar to ED_view3d_cameracontrol_update */ + if (ED_view3d_camera_lock_check(v3d, rv3d)) { + Scene *scene = CTX_data_scene(C); + ID *id_key; + Object *root_parent; + if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) { + while (root_parent->parent) { + root_parent = root_parent->parent; + } + id_key = &root_parent->id; + } + else { + id_key = &v3d->camera->id; + } + + return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate); + } + else { + return false; + } +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ +/** \name Box View Support + * + * Use with quad-split so each view is clipped by the bounds of each view axis. + * \{ */ + +static void view3d_boxview_clip(ScrArea *sa) +{ + ARegion *ar; + BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); + float clip[6][4]; + float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; + int val; + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { + if (ar->winx > ar->winy) x1 = rv3d->dist; + else x1 = ar->winx * rv3d->dist / ar->winy; + + if (ar->winx > ar->winy) y1 = ar->winy * rv3d->dist / ar->winx; + else y1 = rv3d->dist; + copy_v2_v2(ofs, rv3d->ofs); + } + else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { + ofs[2] = rv3d->ofs[2]; + + if (ar->winx > ar->winy) z1 = ar->winy * rv3d->dist / ar->winx; + else z1 = rv3d->dist; + } + } + } + } + + for (val = 0; val < 8; val++) { + if (ELEM(val, 0, 3, 4, 7)) + bb->vec[val][0] = -x1 - ofs[0]; + else + bb->vec[val][0] = x1 - ofs[0]; + + if (ELEM(val, 0, 1, 4, 5)) + bb->vec[val][1] = -y1 - ofs[1]; + else + bb->vec[val][1] = y1 - ofs[1]; + + if (val > 3) + bb->vec[val][2] = -z1 - ofs[2]; + else + bb->vec[val][2] = z1 - ofs[2]; + } + + /* normals for plane equations */ + normal_tri_v3(clip[0], bb->vec[0], bb->vec[1], bb->vec[4]); + normal_tri_v3(clip[1], bb->vec[1], bb->vec[2], bb->vec[5]); + normal_tri_v3(clip[2], bb->vec[2], bb->vec[3], bb->vec[6]); + normal_tri_v3(clip[3], bb->vec[3], bb->vec[0], bb->vec[7]); + normal_tri_v3(clip[4], bb->vec[4], bb->vec[5], bb->vec[6]); + normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); + + /* then plane equations */ + for (val = 0; val < 6; val++) { + clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); + } + + /* create bounding box */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->viewlock & RV3D_BOXCLIP) { + rv3d->rflag |= RV3D_CLIPPING; + memcpy(rv3d->clip, clip, sizeof(clip)); + if (rv3d->clipbb) MEM_freeN(rv3d->clipbb); + rv3d->clipbb = MEM_dupallocN(bb); + } + } + } + MEM_freeN(bb); +} + +/** + * Find which axis values are shared between both views and copy to \a rv3d_dst + * taking axis flipping into account. + */ +static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_src) +{ + /* absolute axis values above this are considered to be set (will be ~1.0f) */ + const float axis_eps = 0.5f; + float viewinv[4]; + + /* use the view rotation to identify which axis to sync on */ + float view_axis_all[4][3] = { + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}}; + + float *view_src_x = &view_axis_all[0][0]; + float *view_src_y = &view_axis_all[1][0]; + + float *view_dst_x = &view_axis_all[2][0]; + float *view_dst_y = &view_axis_all[3][0]; + int i; + + + /* we could use rv3d->viewinv, but better not depend on view matrix being updated */ + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_src_x); + mul_qt_v3(viewinv, view_src_y); + + if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) { + return; + } + invert_qt_normalized(viewinv); + mul_qt_v3(viewinv, view_dst_x); + mul_qt_v3(viewinv, view_dst_y); + + /* check source and dest have a matching axis */ + for (i = 0; i < 3; i++) { + if (((fabsf(view_src_x[i]) > axis_eps) || (fabsf(view_src_y[i]) > axis_eps)) && + ((fabsf(view_dst_x[i]) > axis_eps) || (fabsf(view_dst_y[i]) > axis_eps))) + { + rv3d_dst->ofs[i] = rv3d_src->ofs[i]; + } + } +} + +/* sync center/zoom view of region to others, for view transforms */ +void view3d_boxview_sync(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + short clip = 0; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock & RV3D_LOCKED) { + rv3dtest->dist = rv3d->dist; + view3d_boxview_sync_axis(rv3dtest, rv3d); + clip |= rv3dtest->viewlock & RV3D_BOXCLIP; + + ED_region_tag_redraw(artest); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* for home, center etc */ +void view3d_boxview_copy(ScrArea *sa, ARegion *ar) +{ + ARegion *artest; + RegionView3D *rv3d = ar->regiondata; + bool clip = false; + + for (artest = sa->regionbase.first; artest; artest = artest->next) { + if (artest != ar && artest->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3dtest = artest->regiondata; + + if (rv3dtest->viewlock) { + rv3dtest->dist = rv3d->dist; + copy_v3_v3(rv3dtest->ofs, rv3d->ofs); + ED_region_tag_redraw(artest); + + clip |= ((rv3dtest->viewlock & RV3D_BOXCLIP) != 0); + } + } + } + + if (clip) { + view3d_boxview_clip(sa); + } +} + +/* 'clip' is used to know if our clip setting has changed */ +void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) +{ + ARegion *ar_sync = NULL; + RegionView3D *rv3d = ar->regiondata; + short viewlock; + /* this function copies flags from the first of the 3 other quadview + * regions to the 2 other, so it assumes this is the region whose + * properties are always being edited, weak */ + viewlock = rv3d->viewlock; + + if ((viewlock & RV3D_LOCKED) == 0) { + do_clip = (viewlock & RV3D_BOXCLIP) != 0; + viewlock = 0; + } + else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { + do_clip = true; + viewlock &= ~RV3D_BOXCLIP; + } + + for (; ar; ar = ar->prev) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + rv3d->viewlock = viewlock; + + if (do_clip && (viewlock & RV3D_BOXCLIP) == 0) { + rv3d->rflag &= ~RV3D_BOXCLIP; + } + + /* use ar_sync so we sync with one of the aligned views below + * else the view jumps on changing view settings like 'clip' + * since it copies from the perspective view */ + ar_sync = ar; + } + } + + if (rv3d->viewlock & RV3D_BOXVIEW) { + view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last); + } + + /* ensure locked regions have an axis, locked user views don't make much sense */ + if (viewlock & RV3D_LOCKED) { + int index_qsplit = 0; + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->alignment == RGN_ALIGN_QSPLIT) { + rv3d = ar->regiondata; + if (rv3d->viewlock) { + if (!RV3D_VIEW_IS_AXIS(rv3d->view)) { + rv3d->view = ED_view3d_lock_view_from_index(index_qsplit); + rv3d->persp = RV3D_ORTHO; + ED_view3d_lock(rv3d); + } + } + index_qsplit++; + } + } + } + + ED_area_tag_redraw(sa); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Auto-Depth Utilities + * \{ */ + +static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int margin) +{ + ViewDepths depth_temp = {0}; + rcti rect; + float depth_close; + + if (margin == 0) { + /* Get Z Depths, needed for perspective, nice for ortho */ + rect.xmin = mval[0]; + rect.ymin = mval[1]; + rect.xmax = mval[0] + 1; + rect.ymax = mval[1] + 1; + } + else { + BLI_rcti_init_pt_radius(&rect, mval, margin); + } + + view3d_update_depths_rect(ar, &depth_temp, &rect); + depth_close = view3d_depth_near(&depth_temp); + MEM_SAFE_FREE(depth_temp.depths); + return depth_close; +} + +/** + * Get the world-space 3d location from a screen-space 2d point. + * + * \param mval: Input screen-space pixel location. + * \param mouse_worldloc: Output world-space location. + * \param fallback_depth_pt: Use this points depth when no depth can be found. + */ +bool ED_view3d_autodist( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, ARegion *ar, View3D *v3d, + const int mval[2], float mouse_worldloc[3], + const bool alphaoverride, const float fallback_depth_pt[3]) +{ + float depth_close; + int margin_arr[] = {0, 2, 4}; + int i; + bool depth_ok = false; + + /* Get Z Depths, needed for perspective, nice for ortho */ + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, alphaoverride); + + /* Attempt with low margin's first */ + i = 0; + do { + depth_close = view_autodist_depth_margin(ar, mval, margin_arr[i++] * U.pixelsize); + depth_ok = (depth_close != FLT_MAX); + } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); + + if (depth_ok) { + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + + if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { + return true; + } + } + + if (fallback_depth_pt) { + ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); + return true; + } + else { + return false; + } +} + +void ED_view3d_autodist_init( + const EvaluationContext *eval_ctx, struct Depsgraph *graph, + ARegion *ar, View3D *v3d, int mode) +{ + /* Get Z Depths, needed for perspective, nice for ortho */ + switch (mode) { + case 0: + ED_view3d_draw_depth(eval_ctx, graph, ar, v3d, true); + break; + case 1: + { + Scene *scene = DEG_get_evaluated_scene(graph); + ED_view3d_draw_depth_gpencil(eval_ctx, scene, ar, v3d); + break; + } + } +} + +/* no 4x4 sampling, run #ED_view3d_autodist_init first */ +bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], + int margin, float *force_depth) +{ + float depth; + + /* Get Z Depths, needed for perspective, nice for ortho */ + if (force_depth) + depth = *force_depth; + else + depth = view_autodist_depth_margin(ar, mval, margin); + + if (depth == FLT_MAX) + return false; + + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); +} + +bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) +{ + *depth = view_autodist_depth_margin(ar, mval, margin); + + return (*depth != FLT_MAX); +} + +static bool depth_segment_cb(int x, int y, void *userData) +{ + struct { ARegion *ar; int margin; float depth; } *data = userData; + int mval[2]; + float depth; + + mval[0] = x; + mval[1] = y; + + depth = view_autodist_depth_margin(data->ar, mval, data->margin); + + if (depth != FLT_MAX) { + data->depth = depth; + return 0; + } + else { + return 1; + } +} + +bool ED_view3d_autodist_depth_seg( + ARegion *ar, const int mval_sta[2], const int mval_end[2], + int margin, float *depth) +{ + struct { ARegion *ar; int margin; float depth; } data = {NULL}; + int p1[2]; + int p2[2]; + + data.ar = ar; + data.margin = margin; + data.depth = FLT_MAX; + + copy_v2_v2_int(p1, mval_sta); + copy_v2_v2_int(p2, mval_end); + + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); + + *depth = data.depth; + + return (*depth != FLT_MAX); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Radius/Distance Utilities + * + * Use to calculate a distance to a point based on it's radius. + * \{ */ + +float ED_view3d_radius_to_dist_persp(const float angle, const float radius) +{ + return radius * (1.0f / tanf(angle / 2.0f)); +} + +float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) +{ + return radius / (DEFAULT_SENSOR_WIDTH / lens); +} + +/** + * Return a new RegionView3D.dist value to fit the \a radius. + * + * \note Depth isn't taken into account, this will fit a flat plane exactly, + * but points towards the view (with a perspective projection), + * may be within the radius but outside the view. eg: + * + * <pre> + * + + * pt --> + /^ radius + * / | + * / | + * view + + + * \ | + * \ | + * \| + * + + * </pre> + * + * \param ar Can be NULL if \a use_aspect is false. + * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) + * \param use_aspect Increase the distance to account for non 1:1 view aspect. + * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). + */ +float ED_view3d_radius_to_dist( + const View3D *v3d, const ARegion *ar, + const char persp, const bool use_aspect, + const float radius) +{ + float dist; + + BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); + BLI_assert((persp != RV3D_CAMOB) || v3d->camera); + + if (persp == RV3D_ORTHO) { + dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); + } + else { + float lens, sensor_size, zoom; + float angle; + + if (persp == RV3D_CAMOB) { + CameraParams params; + BKE_camera_params_init(¶ms); + params.clipsta = v3d->near; + params.clipend = v3d->far; + BKE_camera_params_from_object(¶ms, v3d->camera); + + lens = params.lens; + sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); + + /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ + zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; + } + else { + lens = v3d->lens; + sensor_size = DEFAULT_SENSOR_WIDTH; + zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; + } + + angle = focallength_to_fov(lens, sensor_size); + + /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ + angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; + + dist = ED_view3d_radius_to_dist_persp(angle, radius); + } + + if (use_aspect) { + const RegionView3D *rv3d = ar->regiondata; + + float winx, winy; + + if (persp == RV3D_CAMOB) { + /* camera frame x/y in pixels */ + winx = ar->winx / rv3d->viewcamtexcofac[0]; + winy = ar->winy / rv3d->viewcamtexcofac[1]; + } + else { + winx = ar->winx; + winy = ar->winy; + } + + if (winx && winy) { + float aspect = winx / winy; + if (aspect < 1.0f) { + aspect = 1.0f / aspect; + } + dist *= aspect; + } + } + + return dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Distance Utilities + * \{ */ + +/* problem - ofs[3] can be on same location as camera itself. + * Blender needs proper dist value for zoom. + * use fallback_dist to override small values + */ +float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float fallback_dist) +{ + float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float dist; + + mul_m4_v4(mat, pos); + add_v3_v3(pos, ofs); + mul_m4_v4(mat, dir); + normalize_v3(dir); + + dist = dot_v3v3(pos, dir); + + if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { + dist = fallback_dist; + } + + return dist; +} + +/** + * Set the dist without moving the view (compensate with #RegionView3D.ofs) + * + * \note take care that viewinv is up to date, #ED_view3d_update_viewmat first. + */ +void ED_view3d_distance_set(RegionView3D *rv3d, const float dist) +{ + float viewinv[4]; + float tvec[3]; + + BLI_assert(dist >= 0.0f); + + copy_v3_fl3(tvec, 0.0f, 0.0f, rv3d->dist - dist); + /* rv3d->viewinv isn't always valid */ +#if 0 + mul_mat3_m4_v3(rv3d->viewinv, tvec); +#else + invert_qt_qt_normalized(viewinv, rv3d->viewquat); + mul_qt_v3(viewinv, tvec); +#endif + sub_v3_v3(rv3d->ofs, tvec); + + rv3d->dist = dist; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Axis Utilities + * \{ */ +static float view3d_quat_axis[6][4] = { + {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ + {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ + {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ + {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ + {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ + {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ +}; + + +bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) +{ + if (RV3D_VIEW_IS_AXIS(view)) { + copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); + return true; + } + else { + return false; + } +} + +char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) +{ + /* quat values are all unit length */ + + char view; + + for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { + if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) { + return view; + } + } + + return RV3D_VIEW_USER; +} + +char ED_view3d_lock_view_from_index(int index) +{ + switch (index) { + case 0: return RV3D_VIEW_FRONT; + case 1: return RV3D_VIEW_TOP; + case 2: return RV3D_VIEW_RIGHT; + default: return RV3D_VIEW_USER; + } + +} + +char ED_view3d_axis_view_opposite(char view) +{ + switch (view) { + case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; + case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; + case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; + case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; + case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; + case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; + } + + return RV3D_VIEW_USER; +} + + +bool ED_view3d_lock(RegionView3D *rv3d) +{ + return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Transform Utilities + * \{ */ + +/** + * Set the view transformation from a 4x4 matrix. + * + * \param mat The view 4x4 transformation matrix to assign. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) +{ + float nmat[3][3]; + + /* dist depends on offset */ + BLI_assert(dist == NULL || ofs != NULL); + + copy_m3_m4(nmat, mat); + normalize_m3(nmat); + + /* Offset */ + if (ofs) + negate_v3_v3(ofs, mat[3]); + + /* Quat */ + if (quat) { + mat3_normalized_to_quat(quat, nmat); + invert_qt_normalized(quat); + } + + if (ofs && dist) { + madd_v3_v3fl(ofs, nmat[2], *dist); + } +} + +/** + * Calculate the view transformation matrix from RegionView3D input. + * The resulting matrix is equivalent to RegionView3D.viewinv + * \param mat The view 4x4 transformation matrix to calculate. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist) +{ + float iviewquat[4] = {-quat[0], quat[1], quat[2], quat[3]}; + float dvec[3] = {0.0f, 0.0f, dist}; + + quat_to_mat4(mat, iviewquat); + mul_mat3_m4_v3(mat, dvec); + sub_v3_v3v3(mat[3], dvec, ofs); +} + +/** + * Set the RegionView3D members from an objects transformation and optionally lens. + * \param ob The object to set the view to. + * \param ofs The view offset to be set, normally from RegionView3D.ofs. + * \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs to be set, normally from RegionView3D.dist. + * \param lens The view lens angle set for cameras and lamps, normally from View3D.lens. + */ +void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) +{ + ED_view3d_from_m4(ob->obmat, ofs, quat, dist); + + if (lens) { + CameraParams params; + + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, ob); + *lens = params.lens; + } +} + +/** + * Set the object transformation from RegionView3D members. + * \param ob The object which has the transformation assigned. + * \param ofs The view offset, normally from RegionView3D.ofs. + * \param quat The view rotation, quaternion normally from RegionView3D.viewquat. + * \param dist The view distance from ofs, normally from RegionView3D.dist. + */ +void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) +{ + float mat[4][4]; + ED_view3d_to_m4(mat, ofs, quat, dist); + BKE_object_apply_mat4(ob, mat, true, true); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Depth Buffer Utilities + * \{ */ + +float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) +{ + ViewDepths *vd = vc->rv3d->depths; + + int x = mval[0]; + int y = mval[1]; + + if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { + return vd->depths[y * vd->w + x]; + } + else { + BLI_assert(1.0 <= vd->depth_range[1]); + return 1.0f; + } +} + +bool ED_view3d_depth_read_cached_normal( + const ViewContext *vc, const int mval[2], + float r_normal[3]) +{ + /* Note: we could support passing in a radius. + * For now just read 9 pixels. */ + + /* pixels surrounding */ + bool depths_valid[9] = {false}; + float coords[9][3] = {{0}}; + + ARegion *ar = vc->ar; + const ViewDepths *depths = vc->rv3d->depths; + + for (int x = 0, i = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; + + const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); + if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { + if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { + depths_valid[i] = true; + } + } + i++; + } + } + + const int edges[2][6][2] = { + /* x edges */ + {{0, 1}, {1, 2}, + {3, 4}, {4, 5}, + {6, 7}, {7, 8}}, + /* y edges */ + {{0, 3}, {3, 6}, + {1, 4}, {4, 7}, + {2, 5}, {5, 8}}, + }; + + float cross[2][3] = {{0.0f}}; + + for (int i = 0; i < 6; i++) { + for (int axis = 0; axis < 2; axis++) { + if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { + float delta[3]; + sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); + add_v3_v3(cross[axis], delta); + } + } + } + + cross_v3_v3v3(r_normal, cross[0], cross[1]); + + if (normalize_v3(r_normal) != 0.0f) { + return true; + } + else { + return false; + } +} + +bool ED_view3d_depth_unproject( + const ARegion *ar, + const int mval[2], const double depth, + float r_location_world[3]) +{ + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); +} + +void ED_view3d_depth_tag_update(RegionView3D *rv3d) +{ + if (rv3d->depths) + rv3d->depths->damaged = true; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 882f0ec0bc0..0597f2806b3 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -28,7 +28,6 @@ * \ingroup spview3d */ - #include "DNA_camera_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -39,7 +38,6 @@ #include "BLI_rect.h" #include "BLI_utildefines.h" -#include "BKE_anim.h" #include "BKE_action.h" #include "BKE_camera.h" #include "BKE_context.h" @@ -48,12 +46,9 @@ #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_screen.h" #include "DEG_depsgraph.h" -#include "BIF_glutil.h" - #include "UI_resources.h" #include "GPU_glew.h" @@ -64,10 +59,10 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_armature.h" #include "DRW_engine.h" +#include "DEG_depsgraph_query.h" #ifdef WITH_GAMEENGINE # include "BLI_listbase.h" @@ -78,53 +73,14 @@ # include "BL_System.h" #endif - #include "view3d_intern.h" /* own include */ -/* use this call when executing an operator, - * event system doesn't set for each event the - * opengl drawing context */ -void view3d_operator_needs_opengl(const bContext *C) -{ - wmWindow *win = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); - - view3d_region_operator_needs_opengl(win, ar); -} - -void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) -{ - /* for debugging purpose, context should always be OK */ - if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { - printf("view3d_region_operator_needs_opengl error, wrong region\n"); - } - else { - RegionView3D *rv3d = ar->regiondata; - - wmSubWindowSet(win, ar->swinid); - gpuLoadProjectionMatrix(rv3d->winmat); - gpuLoadMatrix(rv3d->viewmat); - } -} - -float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) -{ - if (v3d && v3d->localvd) return v3d->cursor; - else return scene->cursor; -} - -Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) -{ - /* establish the camera object, so we can default to view mapping if anything is wrong with it */ - if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { - return v3d->camera->data; - } - else { - return NULL; - } -} +/* -------------------------------------------------------------------- */ +/** \name Smooth View Operator & Utilities + * + * Use for view transitions to have smooth (animated) transitions. + * \{ */ -/* ****************** smooth view operator ****************** */ /* This operator is one of the 'timer refresh' ones like animation playback */ struct SmoothView3DState { @@ -273,7 +229,7 @@ void ED_view3d_smooth_view_ex( * this means small rotations wont lag */ if (sview->quat && !sview->ofs && !sview->dist) { /* scale the time allowed by the rotation */ - sms.time_allowed *= (double)angle_normalized_qtqt(sms.dst.quat, sms.src.quat) / M_PI; /* 180deg == 1.0 */ + sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / M_PI; /* 180deg == 1.0 */ } /* ensure it shows correct */ @@ -401,6 +357,8 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(C); } if (sync_boxview && (rv3d->viewlock & RV3D_BOXVIEW)) { @@ -462,22 +420,25 @@ void ED_view3d_smooth_view_force_finish( void VIEW3D_OT_smoothview(wmOperatorType *ot) { - /* identifiers */ ot->name = "Smooth View"; ot->description = ""; ot->idname = "VIEW3D_OT_smoothview"; - + /* api callbacks */ ot->invoke = view3d_smoothview_invoke; - + /* flags */ ot->flag = OPTYPE_INTERNAL; ot->poll = ED_operator_view3d_active; } -/* ****************** change view operators ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera to View Operator + * \{ */ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -541,6 +502,12 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Camera Fit Frame to Selected Operator + * \{ */ + /* unlike VIEW3D_OT_view_selected this is for framing a render and not * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) @@ -600,6 +567,12 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object as Camera Operator + * \{ */ + static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob, const int smooth_viewtx) { Main *bmain = CTX_data_main(C); @@ -650,7 +623,7 @@ static void sync_viewport_camera_smoothview(bContext *C, View3D *v3d, Object *ob } static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) -{ +{ View3D *v3d; ARegion *ar; RegionView3D *rv3d; @@ -703,7 +676,6 @@ int ED_operator_rv3d_user_region_poll(bContext *C) void VIEW3D_OT_object_as_camera(wmOperatorType *ot) { - /* identifiers */ ot->name = "Set Active Object as Camera"; ot->description = "Set the active object as the active camera for this view or scene"; @@ -717,289 +689,23 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************************** */ - -void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) -{ - int val; - - for (val = 0; val < 4; val++) { - normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); - if (UNLIKELY(is_flip)) { - negate_v3(clip[val]); - } - - clip[val][3] = -dot_v3v3(clip[val], bb->vec[val]); - } -} - -void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) -{ - /* init in case unproject fails */ - memset(bb->vec, 0, sizeof(bb->vec)); - - /* four clipping planes and bounding volume */ - /* first do the bounding volume */ - for (int val = 0; val < 4; val++) { - float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; - float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; - - ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); - ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); - } - - /* optionally transform to object space */ - if (ob) { - float imat[4][4]; - invert_m4_m4(imat, ob->obmat); - - for (int val = 0; val < 8; val++) { - mul_m4_v3(imat, bb->vec[val]); - } - } - - /* verify if we have negative scale. doing the transform before cross - * product flips the sign of the vector compared to doing cross product - * before transform then, so we correct for that. */ - int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; - - ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); -} - -static bool view3d_boundbox_clip_m4(const BoundBox *bb, float persmatob[4][4]) -{ - int a, flag = -1, fl; - - for (a = 0; a < 8; a++) { - float vec[4], min, max; - copy_v3_v3(vec, bb->vec[a]); - vec[3] = 1.0; - mul_m4_v4(persmatob, vec); - max = vec[3]; - min = -vec[3]; - - fl = 0; - if (vec[0] < min) fl += 1; - if (vec[0] > max) fl += 2; - if (vec[1] < min) fl += 4; - if (vec[1] > max) fl += 8; - if (vec[2] < min) fl += 16; - if (vec[2] > max) fl += 32; - - flag &= fl; - if (flag == 0) return true; - } - - return false; -} - -bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const BoundBox *bb, float obmat[4][4]) -{ - /* return 1: draw */ - - float persmatob[4][4]; - - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - mul_m4_m4m4(persmatob, (float(*)[4])rv3d->persmat, obmat); - - return view3d_boundbox_clip_m4(bb, persmatob); -} - -bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const BoundBox *bb) -{ - if (bb == NULL) return true; - if (bb->flag & BOUNDBOX_DISABLED) return true; - - return view3d_boundbox_clip_m4(bb, rv3d->persmatob); -} +/** \} */ /* -------------------------------------------------------------------- */ - -/** \name Depth Utilities +/** \name Window and View Matrix Calculation * \{ */ -float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) -{ - ViewDepths *vd = vc->rv3d->depths; - - int x = mval[0]; - int y = mval[1]; - - if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) { - return vd->depths[y * vd->w + x]; - } - else { - BLI_assert(1.0 <= vd->depth_range[1]); - return 1.0f; - } -} - -bool ED_view3d_depth_read_cached_normal( - const ViewContext *vc, const int mval[2], - float r_normal[3]) -{ - /* Note: we could support passing in a radius. - * For now just read 9 pixels. */ - - /* pixels surrounding */ - bool depths_valid[9] = {false}; - float coords[9][3] = {{0}}; - - ARegion *ar = vc->ar; - const ViewDepths *depths = vc->rv3d->depths; - - for (int x = 0, i = 0; x < 2; x++) { - for (int y = 0; y < 2; y++) { - const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)}; - - const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); - if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { - depths_valid[i] = true; - } - } - i++; - } - } - - const int edges[2][6][2] = { - /* x edges */ - {{0, 1}, {1, 2}, - {3, 4}, {4, 5}, - {6, 7}, {7, 8}}, - /* y edges */ - {{0, 3}, {3, 6}, - {1, 4}, {4, 7}, - {2, 5}, {5, 8}}, - }; - - float cross[2][3] = {{0.0f}}; - - for (int i = 0; i < 6; i++) { - for (int axis = 0; axis < 2; axis++) { - if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) { - float delta[3]; - sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]); - add_v3_v3(cross[axis], delta); - } - } - } - - cross_v3_v3v3(r_normal, cross[0], cross[1]); - - if (normalize_v3(r_normal) != 0.0f) { - return true; - } - else { - return false; - } -} - -bool ED_view3d_depth_unproject( - const ARegion *ar, - const int mval[2], const double depth, - float r_location_world[3]) -{ - float centx = (float)mval[0] + 0.5f; - float centy = (float)mval[1] + 0.5f; - return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); -} - -/** \} */ - -void ED_view3d_depth_tag_update(RegionView3D *rv3d) -{ - if (rv3d->depths) - rv3d->depths->damaged = true; -} - -void ED_view3d_dist_range_get( - const View3D *v3d, - float r_dist_range[2]) -{ - r_dist_range[0] = v3d->grid * 0.001f; - r_dist_range[1] = v3d->far * 10.0f; -} - -/* copies logic of get_view3d_viewplane(), keep in sync */ -bool ED_view3d_clip_range_get( - const View3D *v3d, const RegionView3D *rv3d, - float *r_clipsta, float *r_clipend, - const bool use_ortho_factor) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); - - if (use_ortho_factor && params.is_ortho) { - const float fac = 2.0f / (params.clipend - params.clipsta); - params.clipsta *= fac; - params.clipend *= fac; - } - - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - - return params.is_ortho; -} - -bool ED_view3d_viewplane_get( - const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, - rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) -{ - CameraParams params; - - BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); - - if (r_viewplane) *r_viewplane = params.viewplane; - if (r_clipsta) *r_clipsta = params.clipsta; - if (r_clipend) *r_clipend = params.clipend; - if (r_pixsize) *r_pixsize = params.viewdx; - - return params.is_ortho; -} - -/** - * Use instead of: ``bglPolygonOffset(rv3d->dist, ...)`` see bug [#37727] - */ -void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) -{ - float viewdist; - - if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { - return; - } - - viewdist = rv3d->dist; - - /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ - if (dist != 0.0f) { - if (rv3d->persp == RV3D_CAMOB) { - if (rv3d->is_persp == false) { - viewdist = 1.0f / max_ff(fabsf(rv3d->winmat[0][0]), fabsf(rv3d->winmat[1][1])); - } - } - } - - bglPolygonOffset(viewdist, dist); -} - /** * \param rect optional for picking (can be NULL). */ -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect) +void view3d_winmatrix_set(const Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect) { RegionView3D *rv3d = ar->regiondata; rctf viewplane; float clipsta, clipend; bool is_ortho; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); rv3d->is_persp = !is_ortho; #if 0 @@ -1041,80 +747,28 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat); } -static float view3d_quat_axis[6][4] = { - {M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */ - {0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */ - {0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */ - {0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */ - {1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */ - {0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */ -}; - - -bool ED_view3d_quat_from_axis_view(const char view, float quat[4]) -{ - if (RV3D_VIEW_IS_AXIS(view)) { - copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]); - return true; - } - else { - return false; - } -} - -char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) -{ - /* quat values are all unit length */ - - char view; - - for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { - if (angle_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]) < epsilon) { - return view; - } - } - - return RV3D_VIEW_USER; -} - -char ED_view3d_lock_view_from_index(int index) -{ - switch (index) { - case 0: return RV3D_VIEW_FRONT; - case 1: return RV3D_VIEW_TOP; - case 2: return RV3D_VIEW_RIGHT; - default: return RV3D_VIEW_USER; - } - -} - -char ED_view3d_axis_view_opposite(char view) -{ - switch (view) { - case RV3D_VIEW_FRONT: return RV3D_VIEW_BACK; - case RV3D_VIEW_BACK: return RV3D_VIEW_FRONT; - case RV3D_VIEW_LEFT: return RV3D_VIEW_RIGHT; - case RV3D_VIEW_RIGHT: return RV3D_VIEW_LEFT; - case RV3D_VIEW_TOP: return RV3D_VIEW_BOTTOM; - case RV3D_VIEW_BOTTOM: return RV3D_VIEW_TOP; - } - - return RV3D_VIEW_USER; -} - - -bool ED_view3d_lock(RegionView3D *rv3d) -{ - return ED_view3d_quat_from_axis_view(rv3d->view, rv3d->viewquat); -} - -/* don't set windows active in here, is used by renderwin too */ -void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, const View3D *v3d, RegionView3D *rv3d) +/** + * Sets #RegionView3D.viewmat + * + * \param eval_ctx: Context. + * \param scene: Scene for camera and cursor location. + * \param v3d: View 3D space data. + * \param rv3d: 3D region which stores the final matrices. + * \param rect_scale: Optional 2D scale argument, + * Use when displaying a sub-region, eg: when #view3d_winmatrix_set takes a 'rect' argument. + * + * \note don't set windows active in here, is used by renderwin too. + */ +void view3d_viewmatrix_set( + const EvaluationContext *eval_ctx, Scene *scene, + const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { - BKE_object_where_is_calc(eval_ctx, scene, v3d->camera); - obmat_to_viewmat(rv3d, v3d->camera); + const Depsgraph *depsgraph = eval_ctx->depsgraph; + Object *camera_object = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_object_where_is_calc(eval_ctx, scene, camera_object); + obmat_to_viewmat(rv3d, camera_object); } else { quat_to_mat4(rv3d->viewmat, rv3d->viewquat); @@ -1168,6 +822,17 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f); vec[2] = 0.0f; + + if (rect_scale) { + /* Since 'RegionView3D.winmat' has been calculated and this function doesn't take the 'ARegion' + * we don't know about the region size. + * Use 'rect_scale' when drawing a sub-region to apply 2D offset, + * scaled by the difference between the sub-region and the region size. + */ + vec[0] /= rect_scale[0]; + vec[1] /= rect_scale[1]; + } + mul_mat3_m4_v3(persinv, vec); translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]); } @@ -1175,6 +840,12 @@ void view3d_viewmatrix_set(const EvaluationContext *eval_ctx, Scene *scene, cons } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name OpenGL Select Utilities + * \{ */ + /** * Optionally cache data for multiple calls to #view3d_opengl_select * @@ -1326,6 +997,12 @@ finally: return hits; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Layer Utilities + * \{ */ + int ED_view3d_view_layer_set(int lay, const int *values, int *active) { int i, tot = 0; @@ -1364,43 +1041,43 @@ int ED_view3d_view_layer_set(int lay, const int *values, int *active) return lay; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Game Engine Operator + * + * Start the game engine (handles context switching). + * \{ */ + #ifdef WITH_GAMEENGINE static ListBase queue_back; -static void SaveState(bContext *C, wmWindow *win) +static void game_engine_save_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + glPushAttrib(GL_ALL_ATTRIB_BITS); if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(1); - + queue_back = win->queue; - + BLI_listbase_clear(&win->queue); - - //XXX waitcursor(1); } -static void RestoreState(bContext *C, wmWindow *win) +static void game_engine_restore_state(bContext *C, wmWindow *win) { Object *obact = CTX_data_active_object(C); - + if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) GPU_paint_set_mipmap(0); - //XXX curarea->win_swap = 0; - //XXX curarea->head_swap = 0; - //XXX allqueue(REDRAWVIEW3D, 1); - //XXX allqueue(REDRAWBUTSALL, 0); - //XXX reset_slowparents(); - //XXX waitcursor(0); - //XXX G.qual = 0; - - if (win) /* check because closing win can set to NULL */ + /* check because closing win can set to NULL */ + if (win) { win->queue = queue_back; - + } + GPU_state_init(); glPopAttrib(); @@ -1471,33 +1148,6 @@ static int game_engine_poll(bContext *C) return 1; } -bool ED_view3d_context_activate(bContext *C) -{ - bScreen *sc = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar; - - /* sa can be NULL when called from python */ - if (sa == NULL || sa->spacetype != SPACE_VIEW3D) { - sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0); - } - - if (sa == NULL) { - return false; - } - - ar = BKE_area_find_region_active_win(sa); - if (ar == NULL) { - return false; - } - - /* bad context switch .. */ - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - return true; -} - static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE @@ -1509,12 +1159,12 @@ static int game_engine_exec(bContext *C, wmOperator *op) RegionView3D *rv3d; rcti cam_frame; - (void)op; /* unused */ - + UNUSED_VARS(op); + /* bad context switch .. */ if (!ED_view3d_context_activate(C)) return OPERATOR_CANCELLED; - + /* redraw to hide any menus/popups, we don't go back to * the window manager until after this operator exits */ WM_redraw_windows(C); @@ -1526,16 +1176,17 @@ static int game_engine_exec(bContext *C, wmOperator *op) ar = CTX_wm_region(C); view3d_operator_needs_opengl(C); - + game_set_commmandline_options(&startscene->gm); if ((rv3d->persp == RV3D_CAMOB) && (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && (startscene->gm.stereoflag != STEREO_DOME)) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); /* Letterbox */ rctf cam_framef; - ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); + ED_view3d_calc_camera_border(startscene, depsgraph, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; @@ -1550,7 +1201,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) } - SaveState(C, prevwin); + game_engine_save_state(C, prevwin); StartKetsjiShell(C, ar, &cam_frame, 1); @@ -1559,7 +1210,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) prevwin = NULL; CTX_wm_window_set(C, NULL); } - + ED_area_tag_redraw(CTX_wm_area(C)); if (prevwin) { @@ -1570,7 +1221,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) CTX_wm_area_set(C, prevsa); } - RestoreState(C, prevwin); + game_engine_restore_state(C, prevwin); //XXX restore_all_scene_cfra(scene_cfra_store); BKE_scene_set_background(CTX_data_main(C), startscene); @@ -1580,7 +1231,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; #else - (void)C; /* unused */ + UNUSED_VARS(C); BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); return OPERATOR_CANCELLED; #endif @@ -1588,168 +1239,15 @@ static int game_engine_exec(bContext *C, wmOperator *op) void VIEW3D_OT_game_start(wmOperatorType *ot) { - /* identifiers */ ot->name = "Start Game Engine"; ot->description = "Start game engine"; ot->idname = "VIEW3D_OT_game_start"; - + /* api callbacks */ ot->exec = game_engine_exec; - - ot->poll = game_engine_poll; -} - -/* ************************************** */ - -float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3]) -{ - return mul_project_m4_v3_zfac((float(*)[4])rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; -} - -float ED_view3d_radius_to_dist_persp(const float angle, const float radius) -{ - return radius * (1.0f / tanf(angle / 2.0f)); -} - -float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) -{ - return radius / (DEFAULT_SENSOR_WIDTH / lens); -} - -/** - * Return a new RegionView3D.dist value to fit the \a radius. - * - * \note Depth isn't taken into account, this will fit a flat plane exactly, - * but points towards the view (with a perspective projection), - * may be within the radius but outside the view. eg: - * - * <pre> - * + - * pt --> + /^ radius - * / | - * / | - * view + + - * \ | - * \ | - * \| - * + - * </pre> - * - * \param ar Can be NULL if \a use_aspect is false. - * \param persp Allow the caller to tell what kind of perspective to use (ortho/view/camera) - * \param use_aspect Increase the distance to account for non 1:1 view aspect. - * \param radius The radius will be fitted exactly, typically pre-scaled by a margin (#VIEW3D_MARGIN). - */ -float ED_view3d_radius_to_dist( - const View3D *v3d, const ARegion *ar, - const char persp, const bool use_aspect, - const float radius) -{ - float dist; - - BLI_assert(ELEM(persp, RV3D_ORTHO, RV3D_PERSP, RV3D_CAMOB)); - BLI_assert((persp != RV3D_CAMOB) || v3d->camera); - - if (persp == RV3D_ORTHO) { - dist = ED_view3d_radius_to_dist_ortho(v3d->lens, radius); - } - else { - float lens, sensor_size, zoom; - float angle; - - if (persp == RV3D_CAMOB) { - CameraParams params; - BKE_camera_params_init(¶ms); - params.clipsta = v3d->near; - params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, v3d->camera); - - lens = params.lens; - sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); - /* ignore 'rv3d->camzoom' because we want to fit to the cameras frame */ - zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB; - } - else { - lens = v3d->lens; - sensor_size = DEFAULT_SENSOR_WIDTH; - zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; - } - - angle = focallength_to_fov(lens, sensor_size); - - /* zoom influences lens, correct this by scaling the angle as a distance (by the zoom-level) */ - angle = atanf(tanf(angle / 2.0f) * zoom) * 2.0f; - - dist = ED_view3d_radius_to_dist_persp(angle, radius); - } - - if (use_aspect) { - const RegionView3D *rv3d = ar->regiondata; - - float winx, winy; - - if (persp == RV3D_CAMOB) { - /* camera frame x/y in pixels */ - winx = ar->winx / rv3d->viewcamtexcofac[0]; - winy = ar->winy / rv3d->viewcamtexcofac[1]; - } - else { - winx = ar->winx; - winy = ar->winy; - } - - if (winx && winy) { - float aspect = winx / winy; - if (aspect < 1.0f) { - aspect = 1.0f / aspect; - } - dist *= aspect; - } - } - - return dist; -} - -/* view matrix properties utilities */ - -/* unused */ -#if 0 -void ED_view3d_operator_properties_viewmat(wmOperatorType *ot) -{ - PropertyRNA *prop; - - prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN); -} - -void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - - if (!RNA_struct_property_is_set(op->ptr, "region_width")) - RNA_int_set(op->ptr, "region_width", ar->winx); - - if (!RNA_struct_property_is_set(op->ptr, "region_height")) - RNA_int_set(op->ptr, "region_height", ar->winy); - - if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix")) - RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat); + ot->poll = game_engine_poll; } -void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4]) -{ - *winx = RNA_int_get(op->ptr, "region_width"); - *winy = RNA_int_get(op->ptr, "region_height"); - - RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat); -} -#endif +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 76da1faf530..e65f9abae27 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -60,6 +60,8 @@ #include "RE_engine.h" +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -249,6 +251,7 @@ typedef struct WalkInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + const struct Depsgraph *depsgraph; Scene *scene; ViewLayer *view_layer; RenderEngineType *engine_type; @@ -334,7 +337,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a rctf viewborder; if (walk->scene->camera) { - ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false); xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f; yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f; } @@ -509,10 +512,14 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { wmWindow *win = CTX_wm_window(C); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(C, &eval_ctx); walk->rv3d = CTX_wm_region_view3d(C); walk->v3d = CTX_wm_view3d(C); walk->ar = CTX_wm_region(C); + walk->depsgraph = CTX_data_depsgraph(C); walk->scene = CTX_data_scene(C); walk->view_layer = CTX_data_view_layer(C); walk->engine_type = CTX_data_engine_type(C); @@ -608,7 +615,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( - C, walk->scene, walk->v3d, walk->rv3d, + &eval_ctx, walk->scene, walk->v3d, walk->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* center the mouse */ @@ -716,7 +723,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent return; } - if ((walk->is_cursor_absolute == false) && WM_event_is_absolute(event)) { + if ((walk->is_cursor_absolute == false) && event->is_motion_absolute) { walk->is_cursor_absolute = true; copy_v2_v2_int(walk->prev_mval, event->mval); copy_v2_v2_int(walk->center_mval, event->mval); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5a63532b0f5..9f7b438e338 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1969,7 +1969,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } // If modal, save settings back in scene if not set as operator argument - if (t->flag & T_MODAL) { + if ((t->flag & T_MODAL) || (op->flag & OP_IS_REPEAT)) { /* save settings if not set in operator */ /* skip saving proportional edit if it was not actually used */ @@ -1989,10 +1989,9 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->proportional_objects = (proportional != PROP_EDIT_OFF); } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->proportional_size = t->prop_size; + if ((prop = RNA_struct_find_property(op->ptr, "proportional_size"))) { + ts->proportional_size = + RNA_property_is_set(op->ptr, prop) ? RNA_property_float_get(op->ptr, prop) : t->prop_size; } if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && @@ -5654,12 +5653,12 @@ static void slide_origdata_interp_data_vert( if (sod->layer_math_map_num) { if (do_loop_weight) { for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); + BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights); } } else { for (j = 0; j < sod->layer_math_map_num; j++) { - BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); + BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]); } } } @@ -6034,7 +6033,9 @@ static void calcEdgeSlide_mval_range( continue; /* This test is only relevant if object is not wire-drawn! See [#32068]. */ - if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) { + if (use_occlude_geometry && + !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, t->obedit)) + { continue; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d9bfcd0c289..4ad66c0a9a5 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -43,6 +43,7 @@ /* ************************** Types ***************************** */ +struct Depsgraph; struct TransInfo; struct TransData; struct TransformOrientation; @@ -468,6 +469,7 @@ typedef struct TransInfo { struct bContext *context; /* Only valid (non null) during an operator called function. */ struct ScrArea *sa; struct ARegion *ar; + struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; struct RenderEngineType *engine_type; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 10a7677f42b..1aa4513e99b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1115,6 +1115,7 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) */ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *sce = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1125,7 +1126,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve bGPdata *gpd = CTX_data_gpencil_data(C); RenderEngineType *engine_type = CTX_data_engine_type(C); PropertyRNA *prop; - + + t->depsgraph = depsgraph; t->scene = sce; t->view_layer = view_layer; t->engine_type = engine_type; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0e0c2f3ae25..0643687c29a 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1155,6 +1155,8 @@ static void manipulator_xform_message_subscribe( else { BLI_assert(0); } + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); } /** \} */ @@ -1177,14 +1179,17 @@ static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) #define MANIPULATOR_NEW_ARROW(v, draw_style) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) #define MANIPULATOR_NEW_DIAL(v, draw_options) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) #define MANIPULATOR_NEW_PRIM(v, draw_style) { \ man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ + WM_manipulator_set_flag(man->manipulators[v], WM_MANIPULATOR_GRAB_CURSOR, true); \ } ((void)0) /* add/init widgets - order matters! */ @@ -1604,6 +1609,7 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup manipulator_prepare_mat(C, v3d, rv3d, &tbounds); WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true); float dims[3]; sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 63cd5291193..f8b11a0bcae 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -735,10 +735,19 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 SWAP(BMVert *, v_pair[0], v_pair[1]); } - add_v3_v3v3(normal, v_pair[0]->no, v_pair[1]->no); - sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co); - /* flip the plane normal so we point outwards */ - negate_v3(plane); + add_v3_v3v3(normal, v_pair[1]->no, v_pair[0]->no); + sub_v3_v3v3(plane, v_pair[1]->co, v_pair[0]->co); + + if (normalize_v3(plane) != 0.0f) { + /* For edges it'd important the resulting matrix can rotate around the edge, + * project onto the plane so we can use a fallback value. */ + project_plane_normalized_v3_v3v3(normal, normal, plane); + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + /* in the case the normal and plane are aligned, + * use a fallback normal which is orthogonal to the plane. */ + ortho_v3_v3(normal, plane); + } + } } result = ORIENTATION_EDGE; diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index ce8de2ef4d3..8f0590eb5b9 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -141,7 +141,7 @@ struct SnapObjectContext { /* -------------------------------------------------------------------- */ /** Common utilities -* \{ */ + * \{ */ typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); @@ -264,7 +264,7 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); /* -------------------------------------------------------------------- */ /** \name Ray Cast Funcs -* \{ */ + * \{ */ /* Store all ray-hits * Support for storing all depths, not just the first (raycast 'all') */ @@ -2372,6 +2372,7 @@ bool ED_transform_snap_object_project_view3d_ex( ED_view3d_win_to_vector(ar, mval, ray_normal); ED_view3d_clip_range_get( + sctx->eval_ctx.depsgraph, sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, &depth_range[0], &depth_range[1], false); @@ -2438,6 +2439,7 @@ bool ED_transform_snap_object_project_all_view3d_ex( float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_ex( + sctx->eval_ctx.depsgraph, sctx->v3d_data.ar, sctx->v3d_data.v3d, mval, NULL, ray_normal, ray_start, true)) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index db6f2c27623..45fa35766f1 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -622,7 +622,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - unsigned int pos; + unsigned int pos, color; efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */ ts = scene->toolsettings; @@ -671,58 +671,61 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (sima->flag & SI_DRAW_STRETCH) { draw_uvs_stretch(sima, scene, em, efa_act); } - else if (!(sima->flag & SI_NO_DRAWFACES)) { - /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - for (unsigned int i = 0; i < em->tottri; i++) { - efa = em->looptris[i][0]->f; + else { + unsigned int tri_count = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { if (uvedit_face_visible_test(scene, ima, efa)) { - const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); BM_elem_flag_enable(efa, BM_ELEM_TAG); - - if (efa == efa_act) { - /* only once */ - immUniformThemeColor(TH_EDITMESH_ACTIVE); - } - else { - immUniformColor4ubv(is_select ? col2 : col1); - } - - immBegin(GWN_PRIM_TRIS, (em->looptris[i][0]->f->len - 2) * 3); - draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); - immEnd(); + tri_count += efa->len - 2; } else { BM_elem_flag_disable(efa, BM_ELEM_TAG); } } - immUnbindProgram(); + if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { + /* draw transparent faces */ + UI_GetThemeColor4ubv(TH_FACE, col1); + UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); - glDisable(GL_BLEND); - } - else { - /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, ima, efa)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + immBegin(GWN_PRIM_TRIS, tri_count * 3); + for (unsigned int i = 0; i < em->tottri; i++) { + efa = em->looptris[i][0]->f; + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); + + if (efa == efa_act) { + /* only once */ + unsigned char tmp_col[4]; + UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4ubv(color, tmp_col); + } + else { + immAttrib4ubv(color, is_select ? col2 : col1); + } + + draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); + } } - else { - if (efa == efa_act) - efa_act = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); + immEnd(); + + immUnbindProgram(); + + glDisable(GL_BLEND); + } + else { + if (efa_act && !uvedit_face_visible_test(scene, ima, efa_act)) { + efa_act = NULL; } } - } /* 3. draw active face stippled */ @@ -813,7 +816,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); if (interpedges) { immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); @@ -900,7 +903,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); |