diff options
Diffstat (limited to 'source/blender/editors')
80 files changed, 1837 insertions, 761 deletions
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 98c050950be..0030e78002b 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -17,6 +17,7 @@ set(INC ../include + ../../blenfont ../../blenkernel ../../blenlib ../../blentranslation diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 93d36abe792..f7b54b79601 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -33,6 +33,7 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_vec_types.h" #include "BKE_fcurve.h" #include "BKE_nla.h" @@ -41,6 +42,7 @@ #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_screen.h" #include "BKE_unit.h" #include "RNA_access.h" @@ -50,15 +52,28 @@ #include "WM_types.h" #include "UI_interface.h" +#include "UI_resources.h" #include "ED_armature.h" #include "ED_keyframes_draw.h" #include "ED_markers.h" #include "ED_numinput.h" #include "ED_screen.h" +#include "ED_space_api.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" #include "armature_intern.h" +#include "BLF_api.h" + +/* Pixel distance from 0% to 100%. */ +#define SLIDE_PIXEL_DISTANCE (300 * U.pixelsize) +#define OVERSHOOT_RANGE_DELTA 0.2f + /* **************************************************** */ /* == POSE 'SLIDING' TOOLS == * @@ -110,15 +125,36 @@ typedef struct tPoseSlideOp { /** unused for now, but can later get used for storing runtime settings.... */ short flag; + /* Store overlay settings when invoking the operator. Bones will be temporarily hidden. */ + int overlay_flag; + /** which transforms/channels are affected (ePoseSlide_Channels) */ short channels; /** axis-limits for transforms (ePoseSlide_AxisLock) */ short axislock; - /** 0-1 value for determining the influence of whatever is relevant */ + /* Allow overshoot or clamp between 0% and 100%. */ + bool overshoot; + + /* Reduces percentage delta from mouse movement. */ + bool precision; + + /* Move percentage in 10% steps. */ + bool increments; + + /* Draw callback handler. */ + void *draw_handle; + + /* Accumulative, unclamped and unrounded percentage. */ + float raw_percentage; + + /* 0-1 value for determining the influence of whatever is relevant. */ float percentage; - /** numeric input */ + /* Last cursor position in screen space used for mouse movement delta calculation. */ + int last_cursor_x; + + /* Numeric input. */ NumInput num; struct tPoseSlideObject *ob_data_array; @@ -187,6 +223,240 @@ static const EnumPropertyItem prop_axis_lock_types[] = { /* ------------------------------------ */ +static void draw_overshoot_triangle(const uint8_t color[4], + const bool facing_right, + const float x, + const float y) +{ + const uint shdr_pos_2d = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + GPU_blend(GPU_BLEND_ALPHA); + GPU_polygon_smooth(true); + immUniformColor3ubvAlpha(color, 225); + const float triangle_side_length = facing_right ? 6 * U.pixelsize : -6 * U.pixelsize; + const float triangle_offset = facing_right ? 2 * U.pixelsize : -2 * U.pixelsize; + + immBegin(GPU_PRIM_TRIS, 3); + immVertex2f(shdr_pos_2d, x + triangle_offset + triangle_side_length, y); + immVertex2f(shdr_pos_2d, x + triangle_offset, y + triangle_side_length / 2); + immVertex2f(shdr_pos_2d, x + triangle_offset, y - triangle_side_length / 2); + immEnd(); + + GPU_polygon_smooth(false); + GPU_blend(GPU_BLEND_NONE); + immUnbindProgram(); +} + +static void draw_ticks(const float start_percentage, + const float end_percentage, + const struct vec2f line_start, + const float base_tick_height, + const float line_width, + const uint8_t color_overshoot[4], + const uint8_t color_line[4]) +{ + /* Use percentage represented as 0-100 int to avoid floating point precision problems. */ + const int tick_increment = 10; + + /* Round initial_tick_percentage up to the next tick_increment. */ + int tick_percentage = ceil((start_percentage * 100) / tick_increment) * tick_increment; + float tick_height = base_tick_height; + + while (tick_percentage <= (int)(end_percentage * 100)) { + /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit + * smaller and the rest is the minimum size. */ + if (tick_percentage % 100 == 0) { + tick_height = base_tick_height; + } + else if (tick_percentage % 50 == 0) { + tick_height = base_tick_height * 0.8; + } + else { + tick_height = base_tick_height * 0.5; + } + + const float x = line_start.x + + (((float)tick_percentage / 100) - start_percentage) * SLIDE_PIXEL_DISTANCE; + const struct rctf tick_rect = {.xmin = x - (line_width / 2), + .xmax = x + (line_width / 2), + .ymin = line_start.y - (tick_height / 2), + .ymax = line_start.y + (tick_height / 2)}; + + if (tick_percentage < 0 || tick_percentage > 100) { + UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255); + } + else { + UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); + } + tick_percentage += tick_increment; + } +} + +static void draw_main_line(const struct rctf main_line_rect, + const float percentage, + const bool overshoot, + const uint8_t color_overshoot[4], + const uint8_t color_line[4]) +{ + if (overshoot) { + /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */ + const float line_zero_percent = main_line_rect.xmin - + ((percentage - 0.5f - OVERSHOOT_RANGE_DELTA) * + SLIDE_PIXEL_DISTANCE); + + const float clamped_line_zero_percent = clamp_f( + line_zero_percent, main_line_rect.xmin, main_line_rect.xmax); + const float clamped_line_hundred_percent = clamp_f( + line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect.xmin, main_line_rect.xmax); + + const struct rctf left_overshoot_line_rect = {.xmin = main_line_rect.xmin, + .xmax = clamped_line_zero_percent, + .ymin = main_line_rect.ymin, + .ymax = main_line_rect.ymax}; + const struct rctf right_overshoot_line_rect = {.xmin = clamped_line_hundred_percent, + .xmax = main_line_rect.xmax, + .ymin = main_line_rect.ymin, + .ymax = main_line_rect.ymax}; + UI_draw_roundbox_3ub_alpha(&left_overshoot_line_rect, true, 0, color_overshoot, 255); + UI_draw_roundbox_3ub_alpha(&right_overshoot_line_rect, true, 0, color_overshoot, 255); + + const struct rctf non_overshoot_line_rect = {.xmin = clamped_line_zero_percent, + .xmax = clamped_line_hundred_percent, + .ymin = main_line_rect.ymin, + .ymax = main_line_rect.ymax}; + UI_draw_roundbox_3ub_alpha(&non_overshoot_line_rect, true, 0, color_line, 255); + } + else { + UI_draw_roundbox_3ub_alpha(&main_line_rect, true, 0, color_line, 255); + } +} + +static void draw_backdrop(const int fontid, + const struct rctf main_line_rect, + const float color_bg[4], + const short region_y_size, + const float base_tick_height) +{ + float string_pixel_size[2]; + const char *percentage_placeholder = "000%%"; + BLF_width_and_height(fontid, + percentage_placeholder, + sizeof(percentage_placeholder), + &string_pixel_size[0], + &string_pixel_size[1]); + const struct vec2f pad = {.x = (region_y_size - base_tick_height) / 2, .y = 2.0f * U.pixelsize}; + const struct rctf backdrop_rect = {.xmin = main_line_rect.xmin - string_pixel_size[0] - pad.x, + .xmax = main_line_rect.xmax + pad.x, + .ymin = pad.y, + .ymax = region_y_size - pad.y}; + UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg); +} + +/* Draw an on screen Slider for a Pose Slide Operator. */ +static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg) +{ + tPoseSlideOp *pso = arg; + + /* Only draw in region from which the Operator was started. */ + if (region != pso->region) { + return; + } + + uint8_t color_text[4]; + uint8_t color_line[4]; + uint8_t color_handle[4]; + uint8_t color_overshoot[4]; + float color_bg[4]; + + /* Get theme colors. */ + UI_GetThemeColor4ubv(TH_TEXT, color_text); + UI_GetThemeColor4ubv(TH_TEXT, color_line); + UI_GetThemeColor4ubv(TH_TEXT, color_overshoot); + UI_GetThemeColor4ubv(TH_ACTIVE, color_handle); + UI_GetThemeColor3fv(TH_BACK, color_bg); + + color_bg[3] = 0.5f; + color_overshoot[0] = color_overshoot[0] * 0.7; + color_overshoot[1] = color_overshoot[1] * 0.7; + color_overshoot[2] = color_overshoot[2] * 0.7; + + /* Get the default font. */ + const uiStyle *style = UI_style_get(); + const uiFontStyle *fstyle = &style->widget; + const int fontid = fstyle->uifont_id; + BLF_color3ubv(fontid, color_text); + BLF_rotation(fontid, 0.0f); + + const float line_width = 1.5 * U.pixelsize; + const float base_tick_height = 12.0 * U.pixelsize; + const float line_y = region->winy / 2; + + struct rctf main_line_rect = {.xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2), + .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2), + .ymin = line_y - line_width / 2, + .ymax = line_y + line_width / 2}; + float line_start_percentage = 0; + int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->percentage; + + if (pso->overshoot) { + main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; + main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; + line_start_percentage = pso->percentage - 0.5f - OVERSHOOT_RANGE_DELTA; + handle_pos_x = region->winx / 2; + } + + draw_backdrop(fontid, main_line_rect, color_bg, pso->region->winy, base_tick_height); + + draw_main_line(main_line_rect, pso->percentage, pso->overshoot, color_overshoot, color_line); + + const float percentage_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1; + const struct vec2f line_start_position = {.x = main_line_rect.xmin, .y = line_y}; + draw_ticks(line_start_percentage, + line_start_percentage + percentage_range, + line_start_position, + base_tick_height, + line_width, + color_overshoot, + color_line); + + /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100% + * range.*/ + if (pso->overshoot) { + if (pso->percentage > 1 + OVERSHOOT_RANGE_DELTA + 0.5) { + draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y); + } + if (pso->percentage < 0 - OVERSHOOT_RANGE_DELTA - 0.5) { + draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y); + } + } + + char percentage_string[256]; + + /* Draw handle indicating current percentage. */ + const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width), + .xmax = handle_pos_x + (line_width), + .ymin = line_y - (base_tick_height / 2), + .ymax = line_y + (base_tick_height / 2)}; + + UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255); + BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100); + + /* Draw percentage string. */ + float percentage_pixel_size[2]; + BLF_width_and_height(fontid, + percentage_string, + sizeof(percentage_string), + &percentage_pixel_size[0], + &percentage_pixel_size[1]); + + BLF_position(fontid, + main_line_rect.xmin - 24.0 * U.pixelsize - percentage_pixel_size[0] / 2, + (region->winy / 2) - percentage_pixel_size[1] / 2, + 0.0f); + BLF_draw(fontid, percentage_string, sizeof(percentage_string)); +} + /* operator init */ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) { @@ -205,6 +475,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) /* set range info from property values - these may get overridden for the invoke() */ pso->percentage = RNA_float_get(op->ptr, "percentage"); + pso->raw_percentage = pso->percentage; pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); @@ -257,6 +528,14 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) pso->num.val_flag[0] |= NUM_NO_NEGATIVE; pso->num.unit_type[0] = B_UNIT_NONE; /* percentages don't have any units... */ + /* Register UI drawing callback. */ + ARegion *region_header = BKE_area_find_region_type(pso->area, RGN_TYPE_HEADER); + if (region_header != NULL) { + pso->region = region_header; + pso->draw_handle = ED_region_draw_cb_activate( + region_header->type, pose_slide_draw_2d_slider, pso, REGION_DRAW_POST_PIXEL); + } + /* return status is whether we've got all the data we were requested to get */ return 1; } @@ -266,6 +545,13 @@ static void pose_slide_exit(wmOperator *op) { tPoseSlideOp *pso = op->customdata; + /* Hide Bone Overlay. */ + View3D *v3d = pso->area->spacedata.first; + v3d->overlay.flag = pso->overlay_flag; + + /* Remove UI drawing callback. */ + ED_region_draw_cb_exit(pso->region->type, pso->draw_handle); + /* if data exists, clear its data and exit */ if (pso) { /* free the temp pchan links and their data */ @@ -602,7 +888,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value) { - /* We only slide to the rest pose. So only use the default rest pose value */ + /* We only slide to the rest pose. So only use the default rest pose value. */ const int lock = pso->axislock; for (int idx = 0; idx < 3; idx++) { if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || @@ -621,7 +907,7 @@ static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], flo static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat) { - /* We only slide to the rest pose. So only use the default rest pose value */ + /* We only slide to the rest pose. So only use the default rest pose value. */ float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f}; if (!quat) { /* Axis Angle */ @@ -789,14 +1075,18 @@ static void pose_slide_reset(tPoseSlideOp *pso) /* ------------------------------------ */ -/* draw percentage indicator in header */ +/* Draw percentage indicator in workspace footer. */ /* TODO: Include hints about locks here... */ -static void pose_slide_draw_status(tPoseSlideOp *pso) +static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso) { char status_str[UI_MAX_DRAW_STR]; char limits_str[UI_MAX_DRAW_STR]; char axis_str[50]; char mode_str[32]; + char overshoot_str[50]; + char precision_str[50]; + char increments_str[50]; + char bone_vis_str[50]; switch (pso->mode) { case POSESLIDE_PUSH: @@ -871,25 +1161,51 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) break; } + if (pso->overshoot) { + BLI_strncpy(overshoot_str, TIP_("[E] - Disable overshoot"), sizeof(overshoot_str)); + } + else { + BLI_strncpy(overshoot_str, TIP_("E - Enable overshoot"), sizeof(overshoot_str)); + } + + if (pso->precision) { + BLI_strncpy(precision_str, TIP_("[Shift] - Precision active"), sizeof(precision_str)); + } + else { + BLI_strncpy(precision_str, TIP_("Shift - Hold for precision"), sizeof(precision_str)); + } + + if (pso->increments) { + BLI_strncpy(increments_str, TIP_("[Ctrl] - Increments active"), sizeof(increments_str)); + } + else { + BLI_strncpy(increments_str, TIP_("Ctrl - Hold for 10% increments"), sizeof(increments_str)); + } + + BLI_strncpy(bone_vis_str, TIP_("[H] - Toggle bone visibility"), sizeof(increments_str)); + if (hasNumInput(&pso->num)) { Scene *scene = pso->scene; - char str_ofs[NUM_STR_REP_LEN]; + char str_offs[NUM_STR_REP_LEN]; - outputNumInput(&pso->num, str_ofs, &scene->unit); + outputNumInput(&pso->num, str_offs, &scene->unit); - BLI_snprintf( - status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str); } else { BLI_snprintf(status_str, sizeof(status_str), - "%s: %d %% | %s", + "%s: %s | %s | %s | %s | %s", mode_str, - (int)(pso->percentage * 100.0f), - limits_str); + limits_str, + overshoot_str, + precision_str, + increments_str, + bone_vis_str); } - ED_area_status_text(pso->area, status_str); + ED_workspace_status_text(C, status_str); + ED_area_status_text(pso->area, ""); } /* common code for invoke() methods */ @@ -975,21 +1291,40 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); /* header print */ - pose_slide_draw_status(pso); + pose_slide_draw_status(C, pso); /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); + + /* Hide Bone Overlay. */ + View3D *v3d = pso->area->spacedata.first; + pso->overlay_flag = v3d->overlay.flag; + v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES; + return OPERATOR_RUNNING_MODAL; } -/* calculate percentage based on position of mouse (we only use x-axis for now. - * since this is more convenient for users to do), and store new percentage value +/* Calculate percentage based on mouse movement, clamp or round to increments if + * enabled by the user. Store the new percentage value. */ static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event) { - pso->percentage = (event->x - pso->region->winrct.xmin) / ((float)pso->region->winx); + const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE)); + /* Reduced percentage delta in precision mode (shift held). */ + pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta; + pso->percentage = pso->raw_percentage; + pso->last_cursor_x = event->x; + + if (!pso->overshoot) { + pso->percentage = clamp_f(pso->percentage, 0, 1); + } + + if (pso->increments) { + pso->percentage = round(pso->percentage * 10) / 10; + } + RNA_float_set(op->ptr, "percentage", pso->percentage); } @@ -1056,9 +1391,13 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case EVT_PADENTER: { if (event->val == KM_PRESS) { /* return to normal cursor and header status */ + ED_workspace_status_text(C, NULL); ED_area_status_text(pso->area, NULL); WM_cursor_modal_restore(win); + /* Depsgraph updates + redraws. Redraw needed to remove UI. */ + pose_slide_refresh(C, pso); + /* insert keyframes as required... */ pose_slide_autoKeyframe(C, pso); pose_slide_exit(op); @@ -1073,13 +1412,14 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) case RIGHTMOUSE: { if (event->val == KM_PRESS) { /* return to normal cursor and header status */ + ED_workspace_status_text(C, NULL); ED_area_status_text(pso->area, NULL); WM_cursor_modal_restore(win); /* reset transforms back to original state */ pose_slide_reset(pso); - /* depsgraph updates + redraws */ + /* Depsgraph updates + redraws.*/ pose_slide_refresh(C, pso); /* clean up temp data */ @@ -1178,10 +1518,58 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } + /* Overshoot. */ + case EVT_EKEY: { + pso->overshoot = !pso->overshoot; + do_pose_update = true; + break; + } + + /* Precision mode. */ + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: { + pso->precision = true; + do_pose_update = true; + break; + } + + /* Increments mode. */ + case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: { + pso->increments = true; + do_pose_update = true; + break; + } + + /* Toggle Bone visibility. */ + case EVT_HKEY: { + View3D *v3d = pso->area->spacedata.first; + v3d->overlay.flag ^= V3D_OVERLAY_HIDE_BONES; + } + default: /* Some other unhandled key... */ break; } } + /* Precision and stepping only active while button is held. */ + else if (event->val == KM_RELEASE) { + switch (event->type) { + case EVT_LEFTSHIFTKEY: + case EVT_RIGHTSHIFTKEY: { + pso->precision = false; + do_pose_update = true; + break; + } + case EVT_LEFTCTRLKEY: + case EVT_RIGHTCTRLKEY: { + pso->increments = false; + do_pose_update = true; + break; + } + default: + break; + } + } else { /* unhandled event - maybe it was some view manipulation? */ /* allow to pass through */ @@ -1193,8 +1581,10 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Perform pose updates - in response to some user action * (e.g. pressing a key or moving the mouse). */ if (do_pose_update) { + pose_slide_mouse_update_percentage(pso, op, event); + /* update percentage indicator in header */ - pose_slide_draw_status(pso); + pose_slide_draw_status(C, pso); /* reset transforms (to avoid accumulation errors) */ pose_slide_reset(pso); @@ -1247,11 +1637,11 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) PropertyRNA *prop; prop = RNA_def_float_factor(ot->srna, - "factor", + "percentage", 0.5f, 0.0f, 1.0f, - "Factor", + "Percentage", "Weighting factor for which keyframe is favored more", 0.0, 1.0); @@ -1310,6 +1700,8 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *ev pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1349,7 +1741,7 @@ void POSE_OT_push(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1370,6 +1762,8 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *e pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1409,7 +1803,7 @@ void POSE_OT_relax(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1429,6 +1823,8 @@ static int pose_slide_push_rest_invoke(bContext *C, wmOperator *op, const wmEven pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1468,7 +1864,7 @@ void POSE_OT_push_rest(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1489,6 +1885,8 @@ static int pose_slide_relax_rest_invoke(bContext *C, wmOperator *op, const wmEve pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1528,7 +1926,7 @@ void POSE_OT_relax_rest(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); @@ -1549,6 +1947,8 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven pso = op->customdata; + pso->last_cursor_x = event->x; + /* Initialize percentage so that it won't pop on first mouse move. */ pose_slide_mouse_update_percentage(pso, op, event); @@ -1588,7 +1988,7 @@ void POSE_OT_breakdown(wmOperatorType *ot) ot->poll = ED_operator_posemode; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; /* Properties */ pose_slide_opdef_properties(ot); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 5c40bc8e418..c155587e95a 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1548,7 +1548,7 @@ static void annotation_paint_initstroke(tGPsdata *p, if (p->gpl == NULL) { /* tag for annotations */ p->gpd->flag |= GP_DATA_ANNOTATIONS; - p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true); + p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true, false); if (p->custom_color[3]) { copy_v3_v3(p->gpl->color, p->custom_color); diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c index 3bd61d5c88a..3aa16e54597 100644 --- a/source/blender/editors/gpencil/gpencil_add_blank.c +++ b/source/blender/editors/gpencil/gpencil_add_blank.c @@ -90,7 +90,7 @@ void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4])) ob->actcol = color_black + 1; /* layers */ - bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true); + bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false); /* frames */ BKE_gpencil_frame_addnew(layer, CFRA); diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c index 6b28c6ec13e..ac0da0ad1db 100644 --- a/source/blender/editors/gpencil/gpencil_add_lineart.c +++ b/source/blender/editors/gpencil/gpencil_add_lineart.c @@ -96,7 +96,7 @@ void ED_gpencil_create_lineart(bContext *C, Object *ob) ob->actcol = color_black + 1; /* layers */ - bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true); + bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false); /* frames */ BKE_gpencil_frame_addnew(lines, 0); diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 4497d963c6d..d8734c4ae6b 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -837,8 +837,8 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) /* layers */ /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */ - bGPDlayer *Fills = BKE_gpencil_layer_addnew(gpd, "Fills", false); - bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true); + bGPDlayer *Fills = BKE_gpencil_layer_addnew(gpd, "Fills", false, false); + bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false); /* frames */ /* NOTE: No need to check for existing, as this will take care of it for us */ diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 26237636526..e95496b51ee 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -225,8 +225,8 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) ob->actcol = color_black + 1; /* layers */ - bGPDlayer *colors = BKE_gpencil_layer_addnew(gpd, "Colors", false); - bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true); + bGPDlayer *colors = BKE_gpencil_layer_addnew(gpd, "Colors", false, false); + bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false); /* frames */ bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, CFRA); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index ac75ae44c8a..8ab413e907c 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1857,7 +1857,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Add layer and frame. */ bGPdata *gpd = (bGPdata *)ob->data; - bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true); + bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true, false); bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA); done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c93fcb9eb8c..d9a807d17ab 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -129,7 +129,7 @@ static int gpencil_data_add_exec(bContext *C, wmOperator *op) gpd->flag |= GP_DATA_ANNOTATIONS; /* add new layer (i.e. a "note") */ - BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true); + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true, false); /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); @@ -231,7 +231,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op) /* mark as annotation */ (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS; - BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true); + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true, false); gpd = *gpd_ptr; } else { @@ -239,7 +239,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); if ((ob != NULL) && (ob->type == OB_GPENCIL)) { gpd = (bGPdata *)ob->data; - bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); + bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false); /* Add a new frame to make it visible in Dopesheet. */ if (gpl != NULL) { gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); @@ -524,7 +524,6 @@ enum { static bool gpencil_layer_duplicate_object_poll(bContext *C) { - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = CTX_data_active_object(C); if ((ob == NULL) || (ob->type != OB_GPENCIL)) { return false; @@ -537,90 +536,75 @@ static bool gpencil_layer_duplicate_object_poll(bContext *C) return false; } - /* check there are more grease pencil objects */ - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - if ((base->object != ob) && (base->object->type == OB_GPENCIL)) { - return true; - } - } - - return false; + return true; } static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - char name[MAX_ID_NAME - 2]; - RNA_string_get(op->ptr, "object", name); - - if (name[0] == '\0') { - return OPERATOR_CANCELLED; - } - - Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name); - - int mode = RNA_enum_get(op->ptr, "mode"); + const bool only_active = RNA_boolean_get(op->ptr, "only_active"); + const int mode = RNA_enum_get(op->ptr, "mode"); Object *ob_src = CTX_data_active_object(C); bGPdata *gpd_src = (bGPdata *)ob_src->data; - bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src); - - /* Sanity checks. */ - if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) { - return OPERATOR_CANCELLED; - } - /* Cannot copy itself and check destination type. */ - if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) { - return OPERATOR_CANCELLED; - } - - bGPdata *gpd_dst = (bGPdata *)ob_dst->data; + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd_src); - /* Create new layer. */ - bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true); - /* Need to copy some variables (not all). */ - gpl_dst->onion_flag = gpl_src->onion_flag; - gpl_dst->thickness = gpl_src->thickness; - gpl_dst->line_change = gpl_src->line_change; - copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor); - gpl_dst->opacity = gpl_src->opacity; - - /* Create all frames. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - - if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) { + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if ((ob == ob_src) || (ob->type != OB_GPENCIL)) { continue; } + bGPdata *gpd_dst = (bGPdata *)ob->data; + LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl_src, &gpd_src->layers) { + if ((only_active) && (gpl_src != gpl_active)) { + continue; + } + /* Create new layer (adding at head of the list). */ + bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true, true); + /* Need to copy some variables (not all). */ + gpl_dst->onion_flag = gpl_src->onion_flag; + gpl_dst->thickness = gpl_src->thickness; + gpl_dst->line_change = gpl_src->line_change; + copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor); + gpl_dst->opacity = gpl_src->opacity; + + /* Create all frames. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + + if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) { + continue; + } - /* Create new frame. */ - bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); + /* Create new frame. */ + bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); - /* Copy strokes. */ - LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { + /* Copy strokes. */ + LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { - /* Make copy of source stroke. */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); + /* Make copy of source stroke. */ + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true); - /* Check if material is in destination object, - * otherwise add the slot with the material. */ - Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1); - if (ma_src != NULL) { - int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src); + /* Check if material is in destination object, + * otherwise add the slot with the material. */ + Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1); + if (ma_src != NULL) { + int idx = BKE_gpencil_object_material_ensure(bmain, ob, ma_src); - /* Reassign the stroke material to the right slot in destination object. */ - gps_dst->mat_nr = idx; - } + /* Reassign the stroke material to the right slot in destination object. */ + gps_dst->mat_nr = idx; + } - /* Add new stroke to frame. */ - BLI_addtail(&gpf_dst->strokes, gps_dst); + /* Add new stroke to frame. */ + BLI_addtail(&gpf_dst->strokes, gps_dst); + } + } } + /* notifiers */ + DEG_id_tag_update(&gpd_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); } + CTX_DATA_END; - /* notifiers */ - DEG_id_tag_update(&gpd_dst->id, - ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); - DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -628,6 +612,8 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) { + PropertyRNA *prop; + static const EnumPropertyItem copy_mode[] = { {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""}, {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""}, @@ -637,7 +623,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) /* identifiers */ ot->name = "Duplicate Layer to New Object"; ot->idname = "GPENCIL_OT_layer_duplicate_object"; - ot->description = "Make a copy of the active Grease Pencil layer to new object"; + ot->description = "Make a copy of the active Grease Pencil layer to selected object"; /* callbacks */ ot->exec = gpencil_layer_duplicate_object_exec; @@ -646,11 +632,14 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_string( - ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object"); - RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + ot->prop = RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", ""); - RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", ""); + prop = RNA_def_boolean(ot->srna, + "only_active", + true, + "Only Active", + "Copy only active Layer, uncheck to append all layers"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /* ********************* Duplicate Frame ************************** */ @@ -1443,7 +1432,7 @@ static int gpencil_layer_change_exec(bContext *C, wmOperator *op) /* Get layer or create new one */ if (layer_num == -1) { /* Create layer */ - gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); + gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false); } else { /* Try to get layer */ @@ -3589,6 +3578,79 @@ void GPENCIL_OT_set_active_material(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************* Append Materials in a new object ************************** */ +static bool gpencil_materials_copy_to_object_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + return false; + } + short *totcolp = BKE_object_material_len_p(ob); + if (*totcolp == 0) { + return false; + } + + return true; +} + +static int gpencil_materials_copy_to_object_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + const bool only_active = RNA_boolean_get(op->ptr, "only_active"); + Object *ob_src = CTX_data_active_object(C); + Material *ma_active = BKE_gpencil_material(ob_src, ob_src->actcol); + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + if ((ob == ob_src) || (ob->type != OB_GPENCIL)) { + continue; + } + /* Duplicate materials. */ + for (int i = 0; i < ob_src->totcol; i++) { + Material *ma_src = BKE_object_material_get(ob_src, i + 1); + if (only_active && ma_src != ma_active) { + continue; + } + + if (ma_src != NULL) { + BKE_gpencil_object_material_ensure(bmain, ob, ma_src); + } + } + + /* notifiers */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + } + CTX_DATA_END; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Copy Materials to Selected Object"; + ot->idname = "GPENCIL_OT_materials_copy_to_object"; + ot->description = "Append Materials of the active Grease Pencil to other object"; + + /* callbacks */ + ot->exec = gpencil_materials_copy_to_object_exec; + ot->poll = gpencil_materials_copy_to_object_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_boolean(ot->srna, + "only_active", + true, + "Only Active", + "Append only active material, uncheck to append all materials"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + /* Parent GPencil object to Lattice */ bool ED_gpencil_add_lattice_modifier(const bContext *C, ReportList *reports, diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index d90f74fbf4f..e65afa1abff 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1677,7 +1677,7 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op) if (gpl == NULL) { /* no active layer - let's just create one */ - gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); + gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false); } else if ((BKE_gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) { BKE_report( @@ -1835,7 +1835,7 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) } else { /* Create a new layer. */ - target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true); + target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false); } if (target_layer == NULL) { @@ -4544,6 +4544,9 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src); + const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd_src); + /* sanity checks */ if (ELEM(NULL, gpd_src)) { return OPERATOR_CANCELLED; @@ -4554,8 +4557,22 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src); - const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd_src); + /* Cancel if nothing selected. */ + if (ELEM(mode, GP_SEPARATE_POINT, GP_SEPARATE_STROKE)) { + bool has_selected = false; + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + if (ED_gpencil_layer_has_selected_stroke(gpl, is_multiedit)) { + has_selected = true; + break; + } + } + CTX_DATA_END; + + if (!has_selected) { + BKE_report(op->reports, RPT_ERROR, "Nothing selected"); + return OPERATOR_CANCELLED; + } + } /* Create a new object. */ /* Take into account user preferences for duplicating actions. */ @@ -4600,7 +4617,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { /* add layer if not created before */ if (gpl_dst == NULL) { - gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false); + gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false, false); } /* add frame if not created before */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 62d64c67b08..f74e211dd65 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1689,7 +1689,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op) tgpf->gpd = gpd; tgpf->gpl = BKE_gpencil_layer_active_get(gpd); if (tgpf->gpl == NULL) { - tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true); + tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true, false); } tgpf->lock_axis = ts->gp_sculpt.lock_axis; diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 09200125cb7..9f48c81c8f1 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -538,6 +538,7 @@ void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot); void GPENCIL_OT_material_select(struct wmOperatorType *ot); void GPENCIL_OT_material_set(struct wmOperatorType *ot); void GPENCIL_OT_set_active_material(struct wmOperatorType *ot); +void GPENCIL_OT_materials_copy_to_object(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 7d454eb3be1..698d784c3b0 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -651,6 +651,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_material_to_vertex_color); WM_operatortype_append(GPENCIL_OT_extract_palette_vertex); + WM_operatortype_append(GPENCIL_OT_materials_copy_to_object); WM_operatortype_append(GPENCIL_OT_transform_fill); WM_operatortype_append(GPENCIL_OT_reset_transform_fill); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index d072d8a35df..30d85b09974 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2120,7 +2120,7 @@ static void gpencil_paint_initstroke(tGPsdata *p, /* get active layer (or add a new one if non-existent) */ p->gpl = BKE_gpencil_layer_active_get(p->gpd); if (p->gpl == NULL) { - p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true); + p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true, false); changed = true; if (p->custom_color[3]) { copy_v3_v3(p->gpl->color, p->custom_color); @@ -3677,14 +3677,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * is essential for ensuring that they can quickly return to that view */ } - else if ((event->type == EVT_BKEY) && (event->val == KM_RELEASE)) { - /* Add Blank Frame - * - Since this operator is non-modal, we can just call it here, and keep going... - * - This operator is especially useful when animating - */ - WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL); - estate = OPERATOR_RUNNING_MODAL; - } else if ((!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP))) { gpencil_guide_event_handling(C, op, event, p); estate = OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 3d20e32ed49..1b0a40b1be1 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -314,7 +314,7 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) /* if layer doesn't exist, create a new one */ if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true); + gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true, false); } tgpi->gpl = gpl; diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c index d2e5fa3db32..cd75f9313ad 100644 --- a/source/blender/editors/gpencil/gpencil_trace_ops.c +++ b/source/blender/editors/gpencil/gpencil_trace_ops.c @@ -207,7 +207,7 @@ static void trace_initialize_job_data(TraceJob *trace_job) trace_job->gpd = (bGPdata *)trace_job->ob_gpencil->data; trace_job->gpl = BKE_gpencil_layer_active_get(trace_job->gpd); if (trace_job->gpl == NULL) { - trace_job->gpl = BKE_gpencil_layer_addnew(trace_job->gpd, DATA_("Trace"), true); + trace_job->gpl = BKE_gpencil_layer_addnew(trace_job->gpd, DATA_("Trace"), true, false); } } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 8d42024a518..04764587ebe 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -543,6 +543,38 @@ bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, } /* ******************************************************** */ +/* Selection Validity Testing */ + +bool ED_gpencil_frame_has_selected_stroke(const bGPDframe *gpf) +{ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_SELECT) { + return true; + } + } + + return false; +} + +bool ED_gpencil_layer_has_selected_stroke(const bGPDlayer *gpl, const bool is_multiedit) +{ + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (ED_gpencil_frame_has_selected_stroke(gpf)) { + return true; + } + } + /* If not multiedit, exit loop. */ + if (!is_multiedit) { + break; + } + } + + return false; +} + +/* ******************************************************** */ /* Stroke Validity Testing */ /* Check whether given stroke can be edited given the supplied context */ @@ -1244,7 +1276,6 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, } else { /* Geometry - Snap to surfaces of visible geometry */ - float ray_start[3]; float ray_normal[3]; /* magic value for initial depth copied from the default * value of Python's Scene.ray_cast function @@ -1253,13 +1284,14 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, float location[3] = {0.0f, 0.0f, 0.0f}; float normal[3] = {0.0f, 0.0f, 0.0f}; - ED_view3d_win_to_ray(region, xy, &ray_start[0], &ray_normal[0]); + ED_view3d_win_to_vector(region, xy, &ray_normal[0]); + BLI_assert(gps->flag & GP_STROKE_3DSPACE); if (ED_transform_snap_object_project_ray(sctx, depsgraph, &(const struct SnapObjectParams){ .snap_select = SNAP_ALL, }, - &ray_start[0], + &pt2.x, &ray_normal[0], &depth, &location[0], diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 1df3d993c39..bad080e1609 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -144,6 +144,8 @@ bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr); bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra); /* ----------- Stroke Editing Utilities ---------------- */ +bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf); +bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit); bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps); bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 8279268bfd0..6f88ab4253a 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -247,6 +247,7 @@ void ED_object_texture_paint_mode_enter(struct bContext *C); void ED_object_texture_paint_mode_exit_ex(struct Main *bmain, struct Scene *scene, Object *ob); void ED_object_texture_paint_mode_exit(struct bContext *C); +bool ED_object_particle_edit_mode_supported(const Object *ob); void ED_object_particle_edit_mode_enter_ex(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index c46f0f78eb5..bdd7ec571dc 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -200,8 +200,6 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area); /* screens */ void ED_screens_init(struct Main *bmain, struct wmWindowManager *wm); void ED_screen_draw_edges(struct wmWindow *win); -void ED_screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2); -void ED_screen_draw_split_preview(struct ScrArea *area, 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, @@ -450,10 +448,10 @@ enum { }; /* SCREEN_OT_space_context_cycle direction */ -enum { +typedef enum eScreenCycle { SPACE_CONTEXT_CYCLE_PREV, SPACE_CONTEXT_CYCLE_NEXT, -}; +} eScreenCycle; #ifdef __cplusplus } diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 90d604b3190..a31efefd99c 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2327,6 +2327,14 @@ bool ui_but_is_float(const uiBut *but) return false; } +PropertyScaleType ui_but_scale_type(const uiBut *but) +{ + if (but->rnaprop) { + return RNA_property_ui_scale(but->rnaprop); + } + return PROP_SCALE_LINEAR; +} + bool ui_but_is_bool(const uiBut *but) { if (ELEM(but->type, diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 178f663ff58..e4f502950ab 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -130,14 +130,19 @@ void eyedropper_draw_cursor_text_region(const struct bContext *C, const char *name) { wmWindow *win = CTX_wm_window(C); - const int x = win->eventstate->x - region->winrct.xmin; - const int y = win->eventstate->y - region->winrct.ymin; + const int x = win->eventstate->x; + const int y = win->eventstate->y; if ((name[0] == '\0') || (BLI_rcti_isect_pt(®ion->winrct, x, y) == false)) { return; } - eyedropper_draw_cursor_text_ex(x, y, name); + const int mval[2] = { + x - region->winrct.xmin, + y - region->winrct.ymin, + }; + + eyedropper_draw_cursor_text_ex(mval[0], mval[1], name); } /** diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5a254db0eec..282d470c7ea 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -126,6 +126,24 @@ #define UI_MAX_PASSWORD_STR 128 /** + * This is a lower limit on the soft minimum of the range. + * Usually the derived lower limit from the visible precision is higher, + * so this number is the backup minimum. + * + * Logarithmic scale does not work with a minimum value of zero, + * but we want to support it anyway. It is set to 0.5e... for + * correct rounding since when the tweaked value is lower than + * the log minimum (lower limit), it will snap to 0. + */ +#define UI_PROP_SCALE_LOG_MIN 0.5e-8f +/** + * This constant defines an offset for the precision change in + * snap rounding, when going to higher values. It is set to + * `0.5 - log10(3) = 0.03` to make the switch at `0.3` values. + */ +#define UI_PROP_SCALE_LOG_SNAP_OFFSET 0.03f + +/** * When #USER_CONTINUOUS_MOUSE is disabled or tablet input is used, * Use this as a maximum soft range for mapping cursor motion to the value. * Otherwise min/max of #FLT_MAX, #INT_MAX cause small adjustments to jump to large numbers. @@ -477,6 +495,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C, static void ui_do_but_extra_operator_icons_mousemove(uiBut *but, uiHandleButtonData *data, const wmEvent *event); +static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data); #ifdef USE_DRAG_MULTINUM static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block); @@ -3361,6 +3380,8 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) if (is_num_but) { BLI_assert(data->is_str_dynamic == false); ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen); + + ui_numedit_begin_set_values(but, data); } /* won't change from now on */ @@ -3897,6 +3918,14 @@ static void ui_do_but_textedit_select( /** \name Button Number Editing (various types) * \{ */ +static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data) +{ + data->startvalue = ui_but_value_get(but); + data->origvalue = data->startvalue; + data->value = data->origvalue; + but->editval = &data->value; +} + static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) { if (but->type == UI_BTYPE_CURVE) { @@ -3922,19 +3951,21 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) but->editvec = data->vec; } else { - float softrange, softmin, softmax; + ui_numedit_begin_set_values(but, data); - data->startvalue = ui_but_value_get(but); - data->origvalue = data->startvalue; - data->value = data->origvalue; - but->editval = &data->value; + float softmin = but->softmin; + float softmax = but->softmax; + float softrange = softmax - softmin; + const PropertyScaleType scale_type = ui_but_scale_type(but); - softmin = but->softmin; - softmax = but->softmax; - softrange = softmax - softmin; + float log_min = (scale_type == PROP_SCALE_LOG) ? max_ff(softmin, UI_PROP_SCALE_LOG_MIN) : 0.0f; if ((but->type == UI_BTYPE_NUM) && (ui_but_is_cursor_warp(but) == false)) { uiButNumber *number_but = (uiButNumber *)but; + + if (scale_type == PROP_SCALE_LOG) { + log_min = max_ff(log_min, powf(10, -number_but->precision) * 0.5f); + } /* Use a minimum so we have a predictable range, * otherwise some float buttons get a large range. */ const float value_step_float_min = 0.1f; @@ -3983,7 +4014,31 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) } } - data->dragfstart = (softrange == 0.0f) ? 0.0f : ((float)data->value - softmin) / softrange; + if (softrange == 0.0f) { + data->dragfstart = 0.0f; + } + else { + switch (scale_type) { + case PROP_SCALE_LINEAR: { + data->dragfstart = ((float)data->value - softmin) / softrange; + break; + } + case PROP_SCALE_LOG: { + BLI_assert(log_min != 0.0f); + const float base = softmax / log_min; + data->dragfstart = logf((float)data->value / log_min) / logf(base); + break; + } + case PROP_SCALE_CUBIC: { + const float cubic_min = cube_f(softmin); + const float cubic_max = cube_f(softmax); + const float cubic_range = cubic_max - cubic_min; + const float f = ((float)data->value - softmin) * cubic_range / softrange + cubic_min; + data->dragfstart = (cbrtf(f) - softmin) / softrange; + break; + } + } + } data->dragf = data->dragfstart; data->drag_map_soft_min = softmin; @@ -4701,6 +4756,7 @@ static float ui_numedit_apply_snapf( /* pass */ } else { + const PropertyScaleType scale_type = ui_but_scale_type(but); float softrange = softmax - softmin; float fac = 1.0f; @@ -4738,31 +4794,30 @@ static float ui_numedit_apply_snapf( } } - if (snap == SNAP_ON) { - if (softrange < 2.10f) { - tempf = roundf(tempf * 10.0f) * 0.1f; - } - else if (softrange < 21.0f) { - tempf = roundf(tempf); - } - else { - tempf = roundf(tempf * 0.1f) * 10.0f; - } - } - else if (snap == SNAP_ON_SMALL) { - if (softrange < 2.10f) { - tempf = roundf(tempf * 100.0f) * 0.01f; - } - else if (softrange < 21.0f) { - tempf = roundf(tempf * 10.0f) * 0.1f; + BLI_assert(ELEM(snap, SNAP_ON, SNAP_ON_SMALL)); + switch (scale_type) { + case PROP_SCALE_LINEAR: + case PROP_SCALE_CUBIC: { + const float snap_fac = (snap == SNAP_ON_SMALL ? 0.1f : 1.0f); + if (softrange < 2.10f) { + tempf = roundf(tempf * 10.0f / snap_fac) * 0.1f * snap_fac; + } + else if (softrange < 21.0f) { + tempf = roundf(tempf / snap_fac) * snap_fac; + } + else { + tempf = roundf(tempf * 0.1f / snap_fac) * 10.0f * snap_fac; + } + break; } - else { - tempf = roundf(tempf); + case PROP_SCALE_LOG: { + const float snap_fac = powf(10.0f, + roundf(log10f(tempf) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - + (snap == SNAP_ON_SMALL ? 2.0f : 1.0f)); + tempf = roundf(tempf / snap_fac) * snap_fac; + break; } } - else { - BLI_assert(0); - } if (fac != 1.0f) { tempf *= fac; @@ -4807,6 +4862,7 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, int lvalue, temp; bool changed = false; const bool is_float = ui_but_is_float(but); + const PropertyScaleType scale_type = ui_but_scale_type(but); /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ if ((is_motion || data->draglock) && (ui_but_dragedit_update_mval(data, mx) == false)) { @@ -4818,21 +4874,74 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, const float softmax = but->softmax; const float softrange = softmax - softmin; + const float log_min = (scale_type == PROP_SCALE_LOG) ? + max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), + powf(10, -number_but->precision) * 0.5f) : + 0; + /* Mouse location isn't screen clamped to the screen so use a linear mapping * 2px == 1-int, or 1px == 1-ClickStep */ if (is_float) { fac *= 0.01f * number_but->step_size; - tempf = (float)data->startvalue + ((float)(mx - data->dragstartx) * fac); + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = (float)data->startvalue + (float)(mx - data->dragstartx) * fac; + break; + } + case PROP_SCALE_LOG: { + const float startvalue = max_ff((float)data->startvalue, log_min); + tempf = expf((float)(mx - data->dragstartx) * fac) * startvalue; + if (tempf <= log_min) { + tempf = 0.0f; + } + break; + } + case PROP_SCALE_CUBIC: { + tempf = cbrtf((float)data->startvalue) + (float)(mx - data->dragstartx) * fac; + tempf *= tempf * tempf; + break; + } + } + tempf = ui_numedit_apply_snapf(but, tempf, softmin, softmax, snap); #if 1 /* fake moving the click start, nicer for dragging back after passing the limit */ - if (tempf < softmin) { - data->dragstartx -= (softmin - tempf) / fac; - tempf = softmin; - } - else if (tempf > softmax) { - data->dragstartx += (tempf - softmax) / fac; - tempf = softmax; + switch (scale_type) { + case PROP_SCALE_LINEAR: { + if (tempf < softmin) { + data->dragstartx -= (softmin - tempf) / fac; + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx -= (softmax - tempf) / fac; + tempf = softmax; + } + break; + } + case PROP_SCALE_LOG: { + if (tempf < log_min) { + data->dragstartx -= logf(log_min / (float)data->startvalue) / fac - + (float)(mx - data->dragstartx); + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx -= logf(softmax / (float)data->startvalue) / fac - + (float)(mx - data->dragstartx); + tempf = softmax; + } + break; + } + case PROP_SCALE_CUBIC: { + if (tempf < softmin) { + data->dragstartx = mx - (int)((cbrtf(softmin) - cbrtf((float)data->startvalue)) / fac); + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx = mx - (int)((cbrtf(softmax) - cbrtf((float)data->startvalue)) / fac); + tempf = softmax; + } + break; + } } #else CLAMP(tempf, softmin, softmax); @@ -4939,7 +5048,31 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, } data->draglastx = mx; - tempf = (softmin + data->dragf * softrange); + + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = (softmin + data->dragf * softrange); + break; + } + case PROP_SCALE_LOG: { + const float log_min = max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), + powf(10.0f, -number_but->precision) * 0.5f); + const float base = softmax / log_min; + tempf = powf(base, data->dragf) * log_min; + if (tempf <= log_min) { + tempf = 0.0f; + } + break; + } + case PROP_SCALE_CUBIC: { + tempf = (softmin + data->dragf * softrange); + tempf *= tempf * tempf; + float cubic_min = softmin * softmin * softmin; + float cubic_max = softmax * softmax * softmax; + tempf = (tempf - cubic_min) / (cubic_max - cubic_min) * softrange + softmin; + break; + } + } if (!is_float) { temp = round_fl_to_int(tempf); @@ -5186,9 +5319,19 @@ static int ui_do_but_NUM( else { /* Float Value. */ if (but->drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT)) { + const PropertyScaleType scale_type = ui_but_scale_type(but); + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - const double value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + double value_step; + if (scale_type == PROP_SCALE_LOG) { + value_step = powf(10.0f, + (roundf(log10f(data->value) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - 1.0f) + + log10f(number_but->step_size)); + } + else { + value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + } BLI_assert(value_step > 0.0f); const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ? (double)max_ff(but->softmin, @@ -5236,6 +5379,8 @@ static bool ui_numedit_but_SLI(uiBut *but, return changed; } + const PropertyScaleType scale_type = ui_but_scale_type(but); + softmin = but->softmin; softmax = but->softmax; softrange = softmax - softmin; @@ -5277,7 +5422,24 @@ static bool ui_numedit_but_SLI(uiBut *but, #endif /* done correcting mouse */ - tempf = softmin + f * softrange; + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = softmin + f * softrange; + break; + } + case PROP_SCALE_LOG: { + tempf = powf(softmax / softmin, f) * softmin; + break; + } + case PROP_SCALE_CUBIC: { + const float cubicmin = cube_f(softmin); + const float cubicmax = cube_f(softmax); + const float cubicrange = cubicmax - cubicmin; + tempf = cube_f(softmin + f * softrange); + tempf = (tempf - cubicmin) / cubicrange * softrange + softmin; + break; + } + } temp = round_fl_to_int(tempf); if (snap) { @@ -5471,6 +5633,8 @@ static int ui_do_but_SLI( if (click) { if (click == 2) { + const PropertyScaleType scale_type = ui_but_scale_type(but); + /* nudge slider to the left or right */ float f, tempf, softmin, softmax, softrange; int temp; @@ -5495,14 +5659,20 @@ static int ui_do_but_SLI( f = (float)(mx - but->rect.xmin) / (BLI_rctf_size_x(&but->rect)); } - f = softmin + f * softrange; + if (scale_type == PROP_SCALE_LOG) { + f = powf(softmax / softmin, f) * softmin; + } + else { + f = softmin + f * softrange; + } if (!ui_but_is_float(but)) { + int value_step = 1; if (f < temp) { - temp--; + temp -= value_step; } else { - temp++; + temp += value_step; } if (temp >= softmin && temp <= softmax) { @@ -5513,14 +5683,23 @@ static int ui_do_but_SLI( } } else { - if (f < tempf) { - tempf -= 0.01f; - } - else { - tempf += 0.01f; - } - if (tempf >= softmin && tempf <= softmax) { + float value_step; + if (scale_type == PROP_SCALE_LOG) { + value_step = powf(10.0f, roundf(log10f(tempf) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - 1.0f); + } + else { + value_step = 0.01f; + } + + if (f < tempf) { + tempf -= value_step; + } + else { + tempf += value_step; + } + + CLAMP(tempf, softmin, softmax); data->value = tempf; } else { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 333dc1beb22..40a3f0d330f 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -660,6 +660,7 @@ bool ui_but_context_poll_operator(struct bContext *C, struct wmOperatorType *ot, extern void ui_but_update(uiBut *but); extern void ui_but_update_edited(uiBut *but); +extern PropertyScaleType ui_but_scale_type(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index c9c1f56dc98..d2e6165a20f 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3752,12 +3752,35 @@ static void widget_numslider( float factor, factor_ui; float factor_discard = 1.0f; /* No discard. */ const float value = (float)ui_but_value_get(but); - - if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) { - factor = value / but->softmax; - } - else { - factor = (value - but->softmin) / (but->softmax - but->softmin); + const float softmin = but->softmin; + const float softmax = but->softmax; + const float softrange = softmax - softmin; + const PropertyScaleType scale_type = ui_but_scale_type(but); + + switch (scale_type) { + case PROP_SCALE_LINEAR: { + if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) { + factor = value / softmax; + } + else { + factor = (value - softmin) / softrange; + } + break; + } + case PROP_SCALE_LOG: { + const float logmin = fmaxf(softmin, 0.5e-8f); + const float base = softmax / logmin; + factor = logf(value / logmin) / logf(base); + break; + } + case PROP_SCALE_CUBIC: { + const float cubicmin = cube_f(softmin); + const float cubicmax = cube_f(softmax); + const float cubicrange = cubicmax - cubicmin; + const float f = (value - softmin) * cubicrange / softrange + cubicmin; + factor = (cbrtf(f) - softmin) / softrange; + break; + } } const float width = (float)BLI_rcti_size_x(rect); diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 592467c2a85..28838d677f0 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -121,6 +121,7 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op) .uvs = RNA_boolean_get(op->ptr, "uvs"), .normals = RNA_boolean_get(op->ptr, "normals"), .vcolors = RNA_boolean_get(op->ptr, "vcolors"), + .orcos = RNA_boolean_get(op->ptr, "orcos"), .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"), .curves_as_mesh = RNA_boolean_get(op->ptr, "curves_as_mesh"), .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"), @@ -210,6 +211,7 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) uiItemR(col, imfptr, "normals", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "vcolors", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "orcos", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "face_sets", 0, NULL, ICON_NONE); uiItemR(col, imfptr, "curves_as_mesh", 0, NULL, ICON_NONE); @@ -378,6 +380,12 @@ void WM_OT_alembic_export(wmOperatorType *ot) RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors"); + RNA_def_boolean(ot->srna, + "orcos", + true, + "Generated Coordinates", + "Export undeformed mesh vertex coordinates"); + RNA_def_boolean( ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments"); diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 77b5379ddd4..4338b043fc9 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -87,7 +87,7 @@ if(WITH_INTERNATIONAL) endif() if(WITH_EXPERIMENTAL_FEATURES) - add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_SIMULATION_DATABLOCK) add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ce441e7b551..8cf7d60e6c4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1311,6 +1311,8 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL; const int type = RNA_enum_get(op->ptr, "type"); + const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front"); + const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order"); ushort local_view_bits; float loc[3], rot[3]; @@ -1338,6 +1340,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) break; } case GP_LRT_OBJECT: + case GP_LRT_SCENE: case GP_LRT_COLLECTION: { ob_name = "Line Art"; break; @@ -1430,7 +1433,15 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) } /* Stroke object is drawn in front of meshes by default. */ - ob->dtx |= OB_DRAW_IN_FRONT; + if (use_in_front) { + ob->dtx |= OB_DRAW_IN_FRONT; + } + else { + if (stroke_depth_order == GP_DRAWMODE_3D) { + gpd->draw_mode = GP_DRAWMODE_3D; + } + } + break; } default: @@ -1449,6 +1460,38 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static void object_add_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, op->ptr, "radius", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "align", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "location", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "rotation", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "type", 0, NULL, ICON_NONE); + + int type = RNA_enum_get(op->ptr, "type"); + if (type == GP_LRT_COLLECTION || type == GP_LRT_OBJECT || type == GP_LRT_SCENE) { + uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE); + bool in_front = RNA_boolean_get(op->ptr, "use_in_front"); + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, !in_front); + uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE); + } +} + +static EnumPropertyItem rna_enum_gpencil_add_stroke_depth_order_items[] = { + {GP_DRAWMODE_2D, + "2D", + 0, + "2D Layers", + "Display strokes using grease pencil layers to define order"}, + {GP_DRAWMODE_3D, "3D", 0, "3D Location", "Display strokes using real 3D position in 3D space"}, + {0, NULL, 0, NULL, NULL}, +}; + void OBJECT_OT_gpencil_add(wmOperatorType *ot) { /* identifiers */ @@ -1464,11 +1507,26 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* ui */ + ot->ui = object_add_ui; + /* properties */ ED_object_add_unit_props_radius(ot); ED_object_add_generic_props(ot, false); ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); + RNA_def_boolean(ot->srna, + "use_in_front", + false, + "In Front", + "Show line art grease pencil in front of everything"); + RNA_def_enum( + ot->srna, + "stroke_depth_order", + rna_enum_gpencil_add_stroke_depth_order_items, + GP_DRAWMODE_3D, + "Stroke Depth Order", + "Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'"); } /** \} */ @@ -2841,6 +2899,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) me_eval = BKE_mesh_copy_for_eval(me_eval, false); /* Full (edge-angle based) draw calculation should ideally be performed. */ BKE_mesh_edges_set_draw_render(me_eval); + BKE_object_material_from_eval_data(bmain, newob, &me_eval->id); BKE_mesh_nomain_to_mesh(me_eval, newob->data, newob, &CD_MASK_MESH, true); BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */ } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index f651f5bc3fd..3370476d466 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -669,9 +669,11 @@ static void bake_targets_clear(Main *bmain, const bool is_tangent) } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Object *object) +static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, + Object *object, + const bool preserve_origindex) { - Mesh *me = BKE_mesh_new_from_object(NULL, object, false); + Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -961,10 +963,39 @@ static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, Re return true; } +static int find_original_loop(const Mesh *me_orig, + const int *vert_origindex, + const int *poly_origindex, + const int poly_eval, + const int vert_eval) +{ + /* Get original vertex and polygon index. There is currently no loop mapping + * in modifier stack evaluation. */ + const int vert_orig = vert_origindex[vert_eval]; + const int poly_orig = poly_origindex[poly_eval]; + + if (vert_orig == ORIGINDEX_NONE || poly_orig == ORIGINDEX_NONE) { + return ORIGINDEX_NONE; + } + + /* Find matching loop with original vertex in original polygon. */ + MPoly *mpoly_orig = me_orig->mpoly + poly_orig; + MLoop *mloop_orig = me_orig->mloop + mpoly_orig->loopstart; + for (int j = 0; j < mpoly_orig->totloop; ++j, ++mloop_orig) { + if (mloop_orig->v == vert_orig) { + return mpoly_orig->loopstart + j; + } + } + + return ORIGINDEX_NONE; +} + static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets, - Mesh *me, + Object *ob, + Mesh *me_eval, BakePixel *pixel_array) { + Mesh *me = ob->data; const int num_pixels = targets->num_pixels; /* Initialize blank pixels. */ @@ -983,16 +1014,31 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets, } /* Populate through adjacent triangles, first triangle wins. */ - const int tottri = poly_to_tri_count(me->totpoly, me->totloop); + const int tottri = poly_to_tri_count(me_eval->totpoly, me_eval->totloop); MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); - BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); + BKE_mesh_recalc_looptri( + me_eval->mloop, me_eval->mpoly, me_eval->mvert, me_eval->totloop, me_eval->totpoly, looptri); + + /* For mapping back to original mesh in case there are modifiers. */ + const int *vert_origindex = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); + const int *poly_origindex = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX); for (int i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; for (int j = 0; j < 3; j++) { - const unsigned int l = lt->tri[j]; + unsigned int l = lt->tri[j]; + unsigned int v = me_eval->mloop[l].v; + + /* Map back to original loop if there are modifiers. */ + if (vert_origindex != NULL && poly_origindex != NULL) { + l = find_original_loop(me, vert_origindex, poly_origindex, lt->poly, v); + if (l == ORIGINDEX_NONE || l >= me->totloop) { + continue; + } + } + BakePixel *pixel = &pixel_array[l]; if (pixel->primitive_id != -1) { @@ -1004,7 +1050,7 @@ static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets, /* Seed is the vertex, so that sampling noise is coherent for the same * vertex, but different corners can still have different normals, * materials and UVs. */ - pixel->seed = me->mloop[l].v; + pixel->seed = v; /* Barycentric coordinates, nudged a bit to avoid precision issues that * may happen when exactly at the vertex coordinate. */ @@ -1043,7 +1089,7 @@ static void bake_result_add_to_rgba(float rgba[4], const float *result, const in } } -static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, Mesh *me_split) +static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob) { Mesh *me = ob->data; MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR); @@ -1052,11 +1098,6 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, const int num_channels = targets->num_channels; const float *result = targets->result; - /* We bake using a mesh with additional vertices for split normals, but the - * number of loops must match to be able to transfer the vertex colors. */ - BLI_assert(me->totloop == me_split->totloop); - UNUSED_VARS_NDEBUG(me_split); - if (mcol_valid) { const int totvert = me->totvert; const int totloop = me->totloop; @@ -1111,16 +1152,17 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob, static bool bake_targets_init(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, + Object *ob_eval, ReportList *reports) { if (bkr->target == R_BAKE_TARGET_IMAGE_TEXTURES) { if (bkr->save_mode == R_BAKE_SAVE_INTERNAL) { - if (!bake_targets_init_internal(bkr, targets, ob, reports)) { + if (!bake_targets_init_internal(bkr, targets, ob_eval, reports)) { return false; } } else if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) { - if (!bake_targets_init_external(bkr, targets, ob, reports)) { + if (!bake_targets_init_external(bkr, targets, ob_eval, reports)) { return false; } } @@ -1145,14 +1187,15 @@ static bool bake_targets_init(const BakeAPIRender *bkr, static void bake_targets_populate_pixels(const BakeAPIRender *bkr, BakeTargets *targets, - Mesh *me, + Object *ob, + Mesh *me_eval, BakePixel *pixel_array) { if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) { - bake_targets_populate_pixels_vertex_colors(targets, me, pixel_array); + bake_targets_populate_pixels_vertex_colors(targets, ob, me_eval, pixel_array); } else { - RE_bake_pixels_populate(me, pixel_array, targets->num_pixels, targets, bkr->uv_layer); + RE_bake_pixels_populate(me_eval, pixel_array, targets->num_pixels, targets, bkr->uv_layer); } } @@ -1160,7 +1203,7 @@ static bool bake_targets_output(const BakeAPIRender *bkr, BakeTargets *targets, Object *ob, Object *ob_eval, - Mesh *me, + Mesh *me_eval, BakePixel *pixel_array, ReportList *reports) { @@ -1169,11 +1212,12 @@ static bool bake_targets_output(const BakeAPIRender *bkr, return bake_targets_output_internal(bkr, targets, ob, pixel_array, reports); } if (bkr->save_mode == R_BAKE_SAVE_EXTERNAL) { - return bake_targets_output_external(bkr, targets, ob, ob_eval, me, pixel_array, reports); + return bake_targets_output_external( + bkr, targets, ob, ob_eval, me_eval, pixel_array, reports); } } else if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) { - return bake_targets_output_vertex_colors(targets, ob, me); + return bake_targets_output_vertex_colors(targets, ob); } return false; @@ -1213,8 +1257,8 @@ static int bake(const BakeAPIRender *bkr, BakeHighPolyData *highpoly = NULL; int tot_highpoly = 0; - Mesh *me_low = NULL; - Mesh *me_cage = NULL; + Mesh *me_low_eval = NULL; + Mesh *me_cage_eval = NULL; MultiresModifierData *mmd_low = NULL; int mmd_flags_low = 0; @@ -1224,6 +1268,8 @@ static int bake(const BakeAPIRender *bkr, BakeTargets targets = {NULL}; + const bool preserve_origindex = (bkr->target == R_BAKE_TARGET_VERTEX_COLORS); + RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { @@ -1287,10 +1333,10 @@ static int bake(const BakeAPIRender *bkr, ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(ob_low_eval); + me_low_eval = bake_mesh_new_from_object(depsgraph, ob_low_eval, preserve_origindex); /* Initialize bake targets. */ - if (!bake_targets_init(bkr, &targets, ob_low_eval, reports)) { + if (!bake_targets_init(bkr, &targets, ob_low, ob_low_eval, reports)) { goto cleanup; } @@ -1298,7 +1344,7 @@ static int bake(const BakeAPIRender *bkr, * it is populated later with the cage mesh (smoothed version of the mesh). */ pixel_array_low = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels, "bake pixels low poly"); if ((bkr->is_selected_to_active && (ob_cage == NULL) && bkr->is_cage) == false) { - bake_targets_populate_pixels(bkr, &targets, me_low, pixel_array_low); + bake_targets_populate_pixels(bkr, &targets, ob_low, me_low_eval, pixel_array_low); } if (bkr->is_selected_to_active) { @@ -1307,8 +1353,9 @@ static int bake(const BakeAPIRender *bkr, /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(ob_cage_eval); - if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { + me_cage_eval = bake_mesh_new_from_object(depsgraph, ob_cage_eval, preserve_origindex); + if ((me_low_eval->totpoly != me_cage_eval->totpoly) || + (me_low_eval->totloop != me_cage_eval->totloop)) { BKE_report(reports, RPT_ERROR, "Invalid cage object, the cage mesh must have the same number " @@ -1348,8 +1395,8 @@ static int bake(const BakeAPIRender *bkr, BKE_object_handle_data_update(depsgraph, scene, ob_low_eval); } - me_cage = BKE_mesh_new_from_object(NULL, ob_low_eval, false); - bake_targets_populate_pixels(bkr, &targets, me_cage, pixel_array_low); + me_cage_eval = BKE_mesh_new_from_object(NULL, ob_low_eval, false, preserve_origindex); + bake_targets_populate_pixels(bkr, &targets, ob_low, me_cage_eval, pixel_array_low); } highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects"); @@ -1367,7 +1414,7 @@ static int bake(const BakeAPIRender *bkr, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER); - highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false); + highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false, false); /* Low-poly to high-poly transformation matrix. */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1391,7 +1438,7 @@ static int bake(const BakeAPIRender *bkr, pixel_array_high = MEM_mallocN(sizeof(BakePixel) * targets.num_pixels, "bake pixels high poly"); - if (!RE_bake_pixels_populate_from_objects(me_low, + if (!RE_bake_pixels_populate_from_objects(me_low_eval, pixel_array_low, pixel_array_high, highpoly, @@ -1402,7 +1449,7 @@ static int bake(const BakeAPIRender *bkr, bkr->max_ray_distance, ob_low_eval->obmat, (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), - me_cage)) { + me_cage_eval)) { BKE_report(reports, RPT_ERROR, "Error handling selected objects"); goto cleanup; } @@ -1478,7 +1525,7 @@ static int bake(const BakeAPIRender *bkr, targets.num_pixels, targets.num_channels, targets.result, - me_low, + me_low_eval, bkr->normal_swizzle, ob_low_eval->obmat); } @@ -1497,8 +1544,8 @@ static int bake(const BakeAPIRender *bkr, } /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false); - bake_targets_populate_pixels(bkr, &targets, me_nores, pixel_array_low); + me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false, false); + bake_targets_populate_pixels(bkr, &targets, ob_low, me_nores, pixel_array_low); RE_bake_normal_world_to_tangent(pixel_array_low, targets.num_pixels, @@ -1527,7 +1574,7 @@ static int bake(const BakeAPIRender *bkr, else { /* save the results */ if (bake_targets_output( - bkr, &targets, ob_low, ob_low_eval, me_low, pixel_array_low, reports)) { + bkr, &targets, ob_low, ob_low_eval, me_low_eval, pixel_array_low, reports)) { op_result = OPERATOR_FINISHED; } else { @@ -1562,12 +1609,12 @@ cleanup: bake_targets_free(&targets); - if (me_low != NULL) { - BKE_id_free(NULL, &me_low->id); + if (me_low_eval != NULL) { + BKE_id_free(NULL, &me_low_eval->id); } - if (me_cage != NULL) { - BKE_id_free(NULL, &me_cage->id); + if (me_cage_eval != NULL) { + BKE_id_free(NULL, &me_cage_eval->id); } DEG_graph_free(depsgraph); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 07c8e7725e3..5be572baec5 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1590,30 +1590,10 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, return rna_enum_object_mode_items; } - Object *ob = CTX_data_active_object(C); + const Object *ob = CTX_data_active_object(C); if (ob) { - const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) || - (ob->soft != NULL) || - (BKE_modifiers_findby_type(ob, eModifierType_Cloth) != - NULL); while (input->identifier) { - if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || - (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || - (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || - (ELEM(input->value, - OB_MODE_SCULPT, - OB_MODE_VERTEX_PAINT, - OB_MODE_WEIGHT_PAINT, - OB_MODE_TEXTURE_PAINT) && - (ob->type == OB_MESH)) || - (ELEM(input->value, - OB_MODE_EDIT_GPENCIL, - OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, - OB_MODE_WEIGHT_GPENCIL, - OB_MODE_VERTEX_GPENCIL) && - (ob->type == OB_GPENCIL)) || - (input->value == OB_MODE_OBJECT)) { + if (ED_object_mode_compat_test(ob, input->value)) { RNA_enum_item_add(&item, &totitem, input); } input++; diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index ff1855cafc5..dcb294bcb12 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -115,43 +115,46 @@ static const char *object_mode_op_string(eObjectMode mode) */ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) { - if (ob) { - if (mode == OB_MODE_OBJECT) { - return true; - } + if (mode == OB_MODE_OBJECT) { + return true; + } - switch (ob->type) { - case OB_MESH: - if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | - OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) { - return true; - } - break; - case OB_CURVE: - case OB_SURF: - case OB_FONT: - case OB_MBALL: - if (mode & OB_MODE_EDIT) { - return true; - } - break; - case OB_LATTICE: - if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) { - return true; - } - break; - case OB_ARMATURE: - if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) { - return true; - } - break; - case OB_GPENCIL: - if (mode & (OB_MODE_EDIT | OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL | - OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)) { + switch (ob->type) { + case OB_MESH: + if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | + OB_MODE_TEXTURE_PAINT)) { + return true; + } + if (mode & OB_MODE_PARTICLE_EDIT) { + if (ED_object_particle_edit_mode_supported(ob)) { return true; } - break; - } + } + break; + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_MBALL: + if (mode & OB_MODE_EDIT) { + return true; + } + break; + case OB_LATTICE: + if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) { + return true; + } + break; + case OB_ARMATURE: + if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) { + return true; + } + break; + case OB_GPENCIL: + if (mode & (OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL | OB_MODE_SCULPT_GPENCIL | + OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)) { + return true; + } + break; } return false; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 0d896f14888..e14e5cbd44b 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -63,6 +63,7 @@ #include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" @@ -210,7 +211,7 @@ ModifierData *ED_object_modifier_add( /* special cases */ if (type == eModifierType_Softbody) { if (!ob->soft) { - ob->soft = sbNew(scene); + ob->soft = sbNew(); ob->softflag |= OB_SB_GOAL | OB_SB_EDGES; } } @@ -772,6 +773,8 @@ static bool modifier_apply_obdata( return false; } + Main *bmain = DEG_get_bmain(depsgraph); + BKE_object_material_from_eval_data(bmain, ob, &mesh_applied->id); BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true); if (md_eval->type == eModifierType_Multires) { diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a7308002e76..b685a93f27b 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -801,7 +801,7 @@ bool ED_object_parent_set(ReportList *reports, * so we check this by assuming that the parent is selected too. */ /* XXX currently this should only happen for meshes, curves, surfaces, - * and lattices - this stuff isn't available for metas yet */ + * and lattices - this stuff isn't available for meta-balls yet. */ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { ModifierData *md; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index de4ad913d6d..5b545784e5b 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -5375,8 +5375,7 @@ static bool particle_edit_toggle_poll(bContext *C) return 0; } - return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) || - BKE_modifiers_findby_type(ob, eModifierType_Softbody)); + return ED_object_particle_edit_mode_supported(ob); } static void free_all_psys_edit(Object *object) @@ -5391,6 +5390,12 @@ static void free_all_psys_edit(Object *object) } } +bool ED_object_particle_edit_mode_supported(const Object *ob) +{ + return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) || + BKE_modifiers_findby_type(ob, eModifierType_Softbody)); +} + void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob) { /* Needed so #ParticleSystemModifierData.mesh_final is set. */ diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 81a8b57776b..fca3b5817b0 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -520,6 +520,26 @@ static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +static bool mass_calculate_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + + /* Disable density input when not using the 'Custom' preset. */ + if (STREQ(prop_id, "density")) { + int material = RNA_enum_get(op->ptr, "material"); + if (material >= 0) { + RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE); + } + else { + RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE); + } + } + + return true; +} + void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot) { PropertyRNA *prop; @@ -533,6 +553,7 @@ void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot) ot->invoke = WM_menu_invoke; /* XXX */ ot->exec = rigidbody_objects_calc_mass_exec; ot->poll = ED_operator_rigidbody_active_poll; + ot->poll_property = mass_calculate_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -554,7 +575,7 @@ void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot) FLT_MIN, FLT_MAX, "Density", - "Custom density value (kg/m^3) to use instead of material preset", + "Density value (kg/m^3), allows custom value if the 'Custom' preset is used", 1.0f, 2500.0f); } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 157f2b3ecb4..e28fe8a5d04 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -70,6 +70,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_texture.h" #include "BKE_world.h" @@ -776,16 +777,21 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview U.pixelsize = 2.0f; + View3DShading shading; + BKE_screen_view3d_shading_init(&shading); + /* Enable shadows, makes it a bit easier to see the shape. */ + shading.flag |= V3D_SHADING_SHADOW; + ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple( depsgraph, DEG_get_evaluated_scene(depsgraph), - NULL, - OB_SOLID, + &shading, + OB_TEXTURE, DEG_get_evaluated_object(depsgraph, scene->camera), preview_sized->sizex, preview_sized->sizey, IB_rect, - V3D_OFSDRAW_NONE, + V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS, R_ALPHAPREMUL, NULL, NULL, diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index bd2b1c4c553..b83eccdcfdd 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1172,12 +1172,12 @@ static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *reg } /* dir is direction to check, not the splitting edge direction! */ -static int rct_fits(const rcti *rect, char dir, int size) +static int rct_fits(const rcti *rect, const eScreenAxis dir_axis, int size) { - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { return BLI_rcti_size_x(rect) + 1 - size; } - /* 'v' */ + /* Vertical. */ return BLI_rcti_size_y(rect) + 1 - size; } @@ -1398,7 +1398,8 @@ static void region_rect_recursive( region->flag |= RGN_FLAG_TOO_SMALL; } } - else if (rct_fits(remainder, 'v', 1) < 0 || rct_fits(remainder, 'h', 1) < 0) { + else if (rct_fits(remainder, SCREEN_AXIS_V, 1) < 0 || + rct_fits(remainder, SCREEN_AXIS_H, 1) < 0) { /* remainder is too small for any usage */ region->flag |= RGN_FLAG_TOO_SMALL; } @@ -1410,11 +1411,11 @@ static void region_rect_recursive( else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) { rcti *winrct = (region->overlap) ? overlap_remainder : remainder; - if ((prefsizey == 0) || (rct_fits(winrct, 'v', prefsizey) < 0)) { + if ((prefsizey == 0) || (rct_fits(winrct, SCREEN_AXIS_V, prefsizey) < 0)) { region->flag |= RGN_FLAG_TOO_SMALL; } else { - int fac = rct_fits(winrct, 'v', prefsizey); + int fac = rct_fits(winrct, SCREEN_AXIS_V, prefsizey); if (fac < 0) { prefsizey += fac; @@ -1436,11 +1437,11 @@ static void region_rect_recursive( else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) { rcti *winrct = (region->overlap) ? overlap_remainder : remainder; - if ((prefsizex == 0) || (rct_fits(winrct, 'h', prefsizex) < 0)) { + if ((prefsizex == 0) || (rct_fits(winrct, SCREEN_AXIS_H, prefsizex) < 0)) { region->flag |= RGN_FLAG_TOO_SMALL; } else { - int fac = rct_fits(winrct, 'h', prefsizex); + int fac = rct_fits(winrct, SCREEN_AXIS_H, prefsizex); if (fac < 0) { prefsizex += fac; @@ -1464,7 +1465,7 @@ static void region_rect_recursive( region->winrct = *remainder; if (alignment == RGN_ALIGN_HSPLIT) { - if (rct_fits(remainder, 'h', prefsizex) > 4) { + if (rct_fits(remainder, SCREEN_AXIS_H, prefsizex) > 4) { region->winrct.xmax = BLI_rcti_cent_x(remainder); remainder->xmin = region->winrct.xmax + 1; } @@ -1473,7 +1474,7 @@ static void region_rect_recursive( } } else { - if (rct_fits(remainder, 'v', prefsizey) > 4) { + if (rct_fits(remainder, SCREEN_AXIS_V, prefsizey) > 4) { region->winrct.ymax = BLI_rcti_cent_y(remainder); remainder->ymin = region->winrct.ymax + 1; } diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 6d1409a9044..2c45524ef94 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -237,23 +237,25 @@ void ED_screen_draw_edges(wmWindow *win) * \param sa1: Area from which the resultant originates. * \param sa2: Target area that will be replaced. */ -void ED_screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2) +void screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2) { - int dir = area_getorientation(sa1, sa2); - if (dir == -1) { + const eScreenDir dir = area_getorientation(sa1, sa2); + if (dir == SCREEN_DIR_NONE) { return; } /* Rect of the combined areas.*/ - bool vertical = ELEM(dir, 1, 3); - rctf combined = {.xmin = vertical ? MAX2(sa1->totrct.xmin, sa2->totrct.xmin) : - MIN2(sa1->totrct.xmin, sa2->totrct.xmin), - .xmax = vertical ? MIN2(sa1->totrct.xmax, sa2->totrct.xmax) : - MAX2(sa1->totrct.xmax, sa2->totrct.xmax), - .ymin = vertical ? MIN2(sa1->totrct.ymin, sa2->totrct.ymin) : - MAX2(sa1->totrct.ymin, sa2->totrct.ymin), - .ymax = vertical ? MAX2(sa1->totrct.ymax, sa2->totrct.ymax) : - MIN2(sa1->totrct.ymax, sa2->totrct.ymax)}; + const bool vertical = SCREEN_DIR_IS_VERTICAL(dir); + const rctf combined = { + .xmin = vertical ? MAX2(sa1->totrct.xmin, sa2->totrct.xmin) : + MIN2(sa1->totrct.xmin, sa2->totrct.xmin), + .xmax = vertical ? MIN2(sa1->totrct.xmax, sa2->totrct.xmax) : + MAX2(sa1->totrct.xmax, sa2->totrct.xmax), + .ymin = vertical ? MIN2(sa1->totrct.ymin, sa2->totrct.ymin) : + MAX2(sa1->totrct.ymin, sa2->totrct.ymin), + .ymax = vertical ? MAX2(sa1->totrct.ymax, sa2->totrct.ymax) : + MIN2(sa1->totrct.ymax, sa2->totrct.ymax), + }; uint pos_id = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -320,7 +322,7 @@ void ED_screen_draw_join_highlight(ScrArea *sa1, ScrArea *sa2) UI_draw_roundbox_4fv(&combined, false, 7 * U.pixelsize, (float[4]){1.0f, 1.0f, 1.0f, 0.8f}); } -void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac) +void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float fac) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -332,7 +334,7 @@ void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac) immBegin(GPU_PRIM_LINES, 2); - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { const float y = (1 - fac) * area->totrct.ymin + fac * area->totrct.ymax; immVertex2f(pos, area->totrct.xmin, y); @@ -350,7 +352,7 @@ void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac) immEnd(); } else { - BLI_assert(dir == 'v'); + BLI_assert(dir_axis == SCREEN_AXIS_V); const float x = (1 - fac) * area->totrct.xmin + fac * area->totrct.xmax; immVertex2f(pos, x, area->totrct.ymin); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 75aa709a5d1..6fb5f33d836 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -104,8 +104,12 @@ static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area) MEM_freeN(area); } -ScrArea *area_split( - const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge) +ScrArea *area_split(const wmWindow *win, + bScreen *screen, + ScrArea *area, + const eScreenAxis dir_axis, + const float fac, + const bool merge) { ScrArea *newa = NULL; @@ -116,7 +120,7 @@ ScrArea *area_split( rcti window_rect; WM_window_rect_calc(win, &window_rect); - short split = screen_geom_find_area_split_point(area, &window_rect, dir, fac); + short split = screen_geom_find_area_split_point(area, &window_rect, dir_axis, fac); if (split == 0) { return NULL; } @@ -125,7 +129,7 @@ ScrArea *area_split( * normally it shouldn't matter which is used since the copy should match the original * however with viewport rendering and python console this isn't the case. - campbell */ - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { /* new vertices */ ScrVert *sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split); ScrVert *sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split); @@ -284,10 +288,10 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new) * -1 = not valid check. * used with join operator. */ -int area_getorientation(ScrArea *sa_a, ScrArea *sa_b) +eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b) { if (sa_a == NULL || sa_b == NULL || sa_a == sa_b) { - return -1; + return SCREEN_DIR_NONE; } const vec2s *sa_bl = &sa_a->v1->vec; @@ -327,29 +331,31 @@ int area_getorientation(ScrArea *sa_a, ScrArea *sa_b) /** * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation(). */ -void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const int dir, int *r_offset1, int *r_offset2) +void area_getoffsets( + ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2) { if (sa_a == NULL || sa_b == NULL) { *r_offset1 = INT_MAX; *r_offset2 = INT_MAX; } - else if (dir == 0) { /* West: sa on right and sa_b to the left. */ + else if (dir == SCREEN_DIR_W) { /* West: sa on right and sa_b to the left. */ *r_offset1 = sa_b->v3->vec.y - sa_a->v2->vec.y; *r_offset2 = sa_b->v4->vec.y - sa_a->v1->vec.y; } - else if (dir == 1) { /* North: sa below and sa_b above. */ + else if (dir == SCREEN_DIR_N) { /* North: sa below and sa_b above. */ *r_offset1 = sa_a->v2->vec.x - sa_b->v1->vec.x; *r_offset2 = sa_a->v3->vec.x - sa_b->v4->vec.x; } - else if (dir == 2) { /* East: sa on left and sa_b to the right. */ + else if (dir == SCREEN_DIR_E) { /* East: sa on left and sa_b to the right. */ *r_offset1 = sa_b->v2->vec.y - sa_a->v3->vec.y; *r_offset2 = sa_b->v1->vec.y - sa_a->v4->vec.y; } - else if (dir == 3) { /* South: sa above and sa_b below. */ + else if (dir == SCREEN_DIR_S) { /* South: sa above and sa_b below. */ *r_offset1 = sa_a->v1->vec.x - sa_b->v2->vec.x; *r_offset2 = sa_a->v4->vec.x - sa_b->v3->vec.x; } else { + BLI_assert(dir == SCREEN_DIR_NONE); *r_offset1 = INT_MAX; *r_offset2 = INT_MAX; } @@ -386,11 +392,11 @@ static void screen_verts_valign(const wmWindow *win, /* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation(). */ static void screen_areas_align( - bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir) + bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const eScreenDir dir) { wmWindow *win = CTX_wm_window(C); - if (ELEM(dir, 0, 2)) { + if (SCREEN_DIR_IS_HORIZONTAL(dir)) { /* horizontal join, use average for new top and bottom. */ int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2; int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2; @@ -421,8 +427,8 @@ static void screen_areas_align( /* Simple join of two areas without any splitting. Will return false if not possible. */ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2) { - int dir = area_getorientation(sa1, sa2); - if (dir == -1) { + const eScreenDir dir = area_getorientation(sa1, sa2); + if (dir == SCREEN_DIR_NONE) { return false; } @@ -430,7 +436,7 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, int offset2; area_getoffsets(sa1, sa2, dir, &offset1, &offset2); - int tolerance = ELEM(dir, 0, 2) ? AREAJOINTOLERANCEY : AREAJOINTOLERANCEX; + int tolerance = SCREEN_DIR_IS_HORIZONTAL(dir) ? AREAJOINTOLERANCEY : AREAJOINTOLERANCEX; if ((abs(offset1) >= tolerance) || (abs(offset2) >= tolerance)) { return false; } @@ -438,27 +444,27 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, /* Align areas if they are not. */ screen_areas_align(C, screen, sa1, sa2, dir); - if (dir == 0) { /* sa1 to right of sa2 = W */ - sa1->v1 = sa2->v1; /* BL */ - sa1->v2 = sa2->v2; /* TL */ + if (dir == SCREEN_DIR_W) { /* sa1 to right of sa2 = West. */ + sa1->v1 = sa2->v1; /* BL */ + sa1->v2 = sa2->v2; /* TL */ screen_geom_edge_add(screen, sa1->v2, sa1->v3); screen_geom_edge_add(screen, sa1->v1, sa1->v4); } - else if (dir == 1) { /* sa1 to bottom of sa2 = N */ - sa1->v2 = sa2->v2; /* TL */ - sa1->v3 = sa2->v3; /* TR */ + else if (dir == SCREEN_DIR_N) { /* sa1 to bottom of sa2 = North. */ + sa1->v2 = sa2->v2; /* TL */ + sa1->v3 = sa2->v3; /* TR */ screen_geom_edge_add(screen, sa1->v1, sa1->v2); screen_geom_edge_add(screen, sa1->v3, sa1->v4); } - else if (dir == 2) { /* sa1 to left of sa2 = E */ - sa1->v3 = sa2->v3; /* TR */ - sa1->v4 = sa2->v4; /* BR */ + else if (dir == SCREEN_DIR_E) { /* sa1 to left of sa2 = East. */ + sa1->v3 = sa2->v3; /* TR */ + sa1->v4 = sa2->v4; /* BR */ screen_geom_edge_add(screen, sa1->v2, sa1->v3); screen_geom_edge_add(screen, sa1->v1, sa1->v4); } - else if (dir == 3) { /* sa1 on top of sa2 = S */ - sa1->v1 = sa2->v1; /* BL */ - sa1->v4 = sa2->v4; /* BR */ + else if (dir == SCREEN_DIR_S) { /* sa1 on top of sa2 = South. */ + sa1->v1 = sa2->v1; /* BL */ + sa1->v4 = sa2->v4; /* BR */ screen_geom_edge_add(screen, sa1->v1, sa1->v2); screen_geom_edge_add(screen, sa1->v3, sa1->v4); } @@ -473,9 +479,9 @@ static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, /* Slice off and return new area. "Reverse" gives right/bottom, rather than left/top. */ static ScrArea *screen_area_trim( - bContext *C, bScreen *screen, ScrArea **area, int size, int dir, bool reverse) + bContext *C, bScreen *screen, ScrArea **area, int size, eScreenDir dir, bool reverse) { - bool vertical = ELEM(dir, 1, 3); + const bool vertical = SCREEN_DIR_IS_VERTICAL(dir); if (abs(size) < (vertical ? AREAJOINTOLERANCEX : AREAJOINTOLERANCEY)) { return NULL; } @@ -484,7 +490,8 @@ static ScrArea *screen_area_trim( float fac = abs(size) / (float)(vertical ? ((*area)->v3->vec.x - (*area)->v1->vec.x) : ((*area)->v3->vec.y - (*area)->v1->vec.y)); fac = (reverse == vertical) ? 1.0f - fac : fac; - ScrArea *newsa = area_split(CTX_wm_window(C), screen, *area, vertical ? 'v' : 'h', fac, 1); + ScrArea *newsa = area_split( + CTX_wm_window(C), screen, *area, vertical ? SCREEN_AXIS_V : SCREEN_AXIS_H, fac, true); /* area_split always returns smallest of the two areas, so might have to swap. */ if (((fac > 0.5f) == vertical) != reverse) { @@ -500,8 +507,8 @@ static ScrArea *screen_area_trim( static bool screen_area_join_ex( bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, bool close_all_remainders) { - int dir = area_getorientation(sa1, sa2); - if (dir == -1) { + const eScreenDir dir = area_getorientation(sa1, sa2); + if (dir == SCREEN_DIR_NONE) { return false; } @@ -534,7 +541,7 @@ int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2) return screen_area_join_ex(C, screen, sa1, sa2, false); } -/* Close a screen area, allowing any neighbor to take its place. */ +/* Close a screen area, allowing most-aligned neighbor to take its place. */ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area) { if (area == NULL) { @@ -542,32 +549,28 @@ bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area) } ScrArea *sa2 = NULL; - - /* Find the most-aligned joinable area. Larger size breaks ties. */ - int min_alignment = INT_MAX; - int max_size = 0; - LISTBASE_FOREACH (ScrArea *, ar, &screen->areabase) { - int dir = area_getorientation(area, ar); - if (dir != -1) { - int offset1; - int offset2; - area_getoffsets(area, ar, dir, &offset1, &offset2); - int area_alignment = abs(offset1) + abs(offset2); - if (area_alignment < min_alignment) { - min_alignment = area_alignment; - max_size = ar->winx * ar->winy; - sa2 = ar; - } - else if (area_alignment == min_alignment) { - int area_size = ar->winx * ar->winy; - if (area_size > max_size) { - max_size = area_size; - sa2 = ar; - } + float best_alignment = 0.0f; + + LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) { + const eScreenDir dir = area_getorientation(area, neighbor); + /* Must at least partially share an edge and not be a global area. */ + if ((dir != SCREEN_DIR_NONE) && (neighbor->global == NULL)) { + /* Winx/Winy might not be updated yet, so get lengths from verts. */ + const bool vertical = SCREEN_DIR_IS_VERTICAL(dir); + const int area_length = vertical ? (area->v3->vec.x - area->v1->vec.x) : + (area->v3->vec.y - area->v1->vec.y); + const int ar_length = vertical ? (neighbor->v3->vec.x - neighbor->v1->vec.x) : + (neighbor->v3->vec.y - neighbor->v1->vec.y); + /* Calculate the ratio of the lengths of the shared edges. */ + float alignment = MIN2(area_length, ar_length) / (float)MAX2(area_length, ar_length); + if (alignment > best_alignment) { + best_alignment = alignment; + sa2 = neighbor; } } } + /* Join from neighbor into this area to close it. */ return screen_area_join_ex(C, screen, sa2, area, true); } diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c index ac159f4d633..51edad0332b 100644 --- a/source/blender/editors/screen/screen_geometry.c +++ b/source/blender/editors/screen/screen_geometry.c @@ -304,7 +304,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen) */ short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, - char dir, + const eScreenAxis dir_axis, float fac) { const int cur_area_width = screen_geom_area_width(area); @@ -313,17 +313,21 @@ short screen_geom_find_area_split_point(const ScrArea *area, const short area_min_y = ED_area_headersize(); /* area big enough? */ - if ((dir == 'v') && (cur_area_width <= 2 * area_min_x)) { - return 0; + if (dir_axis == SCREEN_AXIS_V) { + if (cur_area_width <= 2 * area_min_x) { + return 0; + } } - if ((dir == 'h') && (cur_area_height <= 2 * area_min_y)) { - return 0; + else if (dir_axis == SCREEN_AXIS_H) { + if (cur_area_height <= 2 * area_min_y) { + return 0; + } } /* to be sure */ CLAMP(fac, 0.0f, 1.0f); - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { short y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height); int area_min = area_min_y; @@ -373,13 +377,13 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge) { bScreen *screen = WM_window_get_active_screen(win); - /* 'dir' is the direction of EDGE */ - char dir; + /* 'dir_axis' is the direction of EDGE */ + eScreenAxis dir_axis; if (edge->v1->vec.x == edge->v2->vec.x) { - dir = 'v'; + dir_axis = SCREEN_AXIS_V; } else { - dir = 'h'; + dir_axis = SCREEN_AXIS_H; } ED_screen_verts_iter(win, screen, sv) @@ -396,13 +400,13 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge) oneselected = false; LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) { if (se->v1->flag + se->v2->flag == 1) { - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { if (se->v1->vec.y == se->v2->vec.y) { se->v1->flag = se->v2->flag = 1; oneselected = true; } } - if (dir == 'v') { + else if (dir_axis == SCREEN_AXIS_V) { if (se->v1->vec.x == se->v2->vec.x) { se->v1->flag = se->v2->flag = 1; oneselected = true; diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index dd196f9621b..683f2844371 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -29,6 +29,29 @@ struct bContextDataResult; /* internal exports only */ +typedef enum eScreenDir { + /** This can mean unset, unknown or invalid. */ + SCREEN_DIR_NONE = -1, + /** West/Left. */ + SCREEN_DIR_W = 0, + /** North/Up. */ + SCREEN_DIR_N = 1, + /** East/Right. */ + SCREEN_DIR_E = 2, + /** South/Down. */ + SCREEN_DIR_S = 3, +} eScreenDir; + +#define SCREEN_DIR_IS_VERTICAL(dir) (ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S)) +#define SCREEN_DIR_IS_HORIZONTAL(dir) (ELEM(dir, SCREEN_DIR_W, SCREEN_DIR_E)) + +typedef enum eScreenAxis { + /** Horizontal. */ + SCREEN_AXIS_H = 'h', + /** Vertical. */ + SCREEN_AXIS_V = 'v', +} eScreenAxis; + #define AZONESPOTW UI_HEADER_OFFSET /* width of corner #AZone - max */ #define AZONESPOTH (0.6f * U.widget_unit) /* height of corner #AZone */ #define AZONEFADEIN (5.0f * U.widget_unit) /* when #AZone is totally visible */ @@ -46,6 +69,10 @@ void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free) void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src); void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade); +/* screen_draw.c */ +void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2); +void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac); + /* screen_edit.c */ bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect); void screen_data_copy(bScreen *to, bScreen *from); @@ -56,11 +83,16 @@ void screen_change_prepare(bScreen *screen_old, struct Main *bmain, struct bContext *C, wmWindow *win); -ScrArea *area_split( - const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge); +ScrArea *area_split(const wmWindow *win, + bScreen *screen, + ScrArea *area, + const eScreenAxis dir_axis, + const float fac, + const bool merge); int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2); -int area_getorientation(ScrArea *sa_a, ScrArea *sa_b); -void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const int dir, int *r_offset1, int *r_offset2); +eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b); +void area_getoffsets( + ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2); bool screen_area_close(struct bContext *C, bScreen *screen, ScrArea *area); struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]); @@ -83,7 +115,7 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win, void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen); short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, - char dir, + const eScreenAxis dir_axis, float fac); void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index eadc18de443..6b8d4e73f12 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -694,7 +694,9 @@ static bool screen_active_editable(bContext *C) typedef struct sActionzoneData { ScrArea *sa1, *sa2; AZone *az; - int x, y, gesture_dir, modifier; + int x, y; + eScreenDir gesture_dir; + int modifier; } sActionzoneData; /* quick poll to save operators to be created and handled */ @@ -1045,16 +1047,16 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Calculate gesture cardinal direction. */ if (delta_y > abs(delta_x)) { - sad->gesture_dir = 'n'; + sad->gesture_dir = SCREEN_DIR_N; } else if (delta_x >= abs(delta_y)) { - sad->gesture_dir = 'e'; + sad->gesture_dir = SCREEN_DIR_E; } else if (delta_y < -abs(delta_x)) { - sad->gesture_dir = 's'; + sad->gesture_dir = SCREEN_DIR_S; } else { - sad->gesture_dir = 'w'; + sad->gesture_dir = SCREEN_DIR_W; } bool is_gesture; @@ -1071,22 +1073,24 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Are we still in same area? */ if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) { /* Same area, so possible split. */ - WM_cursor_set( - win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); + WM_cursor_set(win, + SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT : + WM_CURSOR_V_SPLIT); is_gesture = (delta_max > split_threshold); } else { /* Different area, so possible join. */ - if (sad->gesture_dir == 'n') { + if (sad->gesture_dir == SCREEN_DIR_N) { WM_cursor_set(win, WM_CURSOR_N_ARROW); } - else if (sad->gesture_dir == 's') { + else if (sad->gesture_dir == SCREEN_DIR_S) { WM_cursor_set(win, WM_CURSOR_S_ARROW); } - else if (sad->gesture_dir == 'e') { + else if (sad->gesture_dir == SCREEN_DIR_E) { WM_cursor_set(win, WM_CURSOR_E_ARROW); } else { + BLI_assert(sad->gesture_dir == SCREEN_DIR_W); WM_cursor_set(win, WM_CURSOR_W_ARROW); } is_gesture = (delta_max > join_threshold); @@ -1480,7 +1484,7 @@ static void SCREEN_OT_area_close(wmOperatorType *ot) typedef struct sAreaMoveData { int bigger, smaller, origval, step; - char dir; + eScreenAxis dir_axis; enum AreaMoveSnapType { /* Snapping disabled */ SNAP_NONE = 0, @@ -1499,7 +1503,7 @@ typedef struct sAreaMoveData { * need window bounds in order to get correct limits */ static void area_move_set_limits(wmWindow *win, bScreen *screen, - int dir, + const eScreenAxis dir_axis, int *bigger, int *smaller, bool *use_bigger_smaller_snap) @@ -1552,7 +1556,7 @@ static void area_move_set_limits(wmWindow *win, WM_window_rect_calc(win, &window_rect); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { int areamin = ED_area_headersize(); if (area->v1->vec.y > window_rect.ymin) { @@ -1615,8 +1619,8 @@ static bool area_move_init(bContext *C, wmOperator *op) sAreaMoveData *md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData"); op->customdata = md; - md->dir = screen_geom_edge_is_horizontal(actedge) ? 'h' : 'v'; - if (md->dir == 'h') { + md->dir_axis = screen_geom_edge_is_horizontal(actedge) ? SCREEN_AXIS_H : SCREEN_AXIS_V; + if (md->dir_axis == SCREEN_AXIS_H) { md->origval = actedge->v1->vec.y; } else { @@ -1631,7 +1635,8 @@ static bool area_move_init(bContext *C, wmOperator *op) } bool use_bigger_smaller_snap = false; - area_move_set_limits(win, screen, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap); + area_move_set_limits( + win, screen, md->dir_axis, &md->bigger, &md->smaller, &use_bigger_smaller_snap); md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID; @@ -1642,7 +1647,7 @@ static int area_snap_calc_location(const bScreen *screen, const enum AreaMoveSnapType snap_type, const int delta, const int origval, - const int dir, + const eScreenAxis dir_axis, const int bigger, const int smaller) { @@ -1667,7 +1672,7 @@ static int area_snap_calc_location(const bScreen *screen, break; case SNAP_FRACTION_AND_ADJACENT: { - const int axis = (dir == 'v') ? 0 : 1; + const int axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1; int snap_dist_best = INT_MAX; { const float div_array[] = { @@ -1735,7 +1740,7 @@ static int area_snap_calc_location(const bScreen *screen, static void area_move_apply_do(const bContext *C, int delta, const int origval, - const int dir, + const eScreenAxis dir_axis, const int bigger, const int smaller, const enum AreaMoveSnapType snap_type) @@ -1753,11 +1758,12 @@ static void area_move_apply_do(const bContext *C, final_loc = origval + delta; } else { - final_loc = area_snap_calc_location(screen, snap_type, delta, origval, dir, bigger, smaller); + final_loc = area_snap_calc_location( + screen, snap_type, delta, origval, dir_axis, bigger, smaller); } BLI_assert(final_loc != -1); - short axis = (dir == 'v') ? 0 : 1; + short axis = (dir_axis == SCREEN_AXIS_V) ? 0 : 1; ED_screen_verts_iter(win, screen, v1) { @@ -1813,7 +1819,7 @@ static void area_move_apply(bContext *C, wmOperator *op) sAreaMoveData *md = op->customdata; int delta = RNA_int_get(op->ptr, "delta"); - area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->snap_type); + area_move_apply_do(C, delta, md->origval, md->dir_axis, md->bigger, md->smaller, md->snap_type); } static void area_move_exit(bContext *C, wmOperator *op) @@ -1878,7 +1884,7 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) int x = RNA_int_get(op->ptr, "x"); int y = RNA_int_get(op->ptr, "y"); - int delta = (md->dir == 'v') ? event->x - x : event->y - y; + const int delta = (md->dir_axis == SCREEN_AXIS_V) ? event->x - x : event->y - y; RNA_int_set(op->ptr, "delta", delta); area_move_apply(C, op); @@ -1944,7 +1950,7 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) /* * operator state vars: * fac spit point - * dir direction 'v' or 'h' + * dir direction #SCREEN_AXIS_V or #SCREEN_AXIS_H * * operator customdata: * area pointer to (active) area @@ -1981,7 +1987,7 @@ typedef struct sAreaSplitData { 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` */ + void *draw_callback; /* call `screen_draw_split_preview` */ bool do_snap; ScrEdge *nedge; /* new edge */ @@ -1996,10 +2002,10 @@ static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdat sAreaSplitData *sd = op->customdata; if (sd->sarea) { - int dir = RNA_enum_get(op->ptr, "direction"); + const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); float fac = RNA_float_get(op->ptr, "factor"); - ED_screen_draw_split_preview(sd->sarea, dir, fac); + screen_draw_split_preview(sd->sarea, dir_axis, fac); } } @@ -2026,14 +2032,18 @@ static bool area_split_init(bContext *C, wmOperator *op) } /* required properties */ - int dir = RNA_enum_get(op->ptr, "direction"); + const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); /* minimal size */ - if (dir == 'v' && area->winx < 2 * AREAMINX) { - return false; + if (dir_axis == SCREEN_AXIS_V) { + if (area->winx < 2 * AREAMINX) { + return false; + } } - if (dir == 'h' && area->winy < 2 * ED_area_headersize()) { - return false; + else { + if (area->winy < 2 * ED_area_headersize()) { + return false; + } } /* custom data */ @@ -2041,7 +2051,7 @@ static bool area_split_init(bContext *C, wmOperator *op) op->customdata = sd; sd->sarea = area; - if (dir == 'v') { + if (dir_axis == SCREEN_AXIS_V) { sd->origmin = area->v1->vec.x; sd->origsize = area->v4->vec.x - sd->origmin; } @@ -2090,9 +2100,9 @@ static bool area_split_apply(bContext *C, wmOperator *op) sAreaSplitData *sd = (sAreaSplitData *)op->customdata; float fac = RNA_float_get(op->ptr, "factor"); - int dir = RNA_enum_get(op->ptr, "direction"); + const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); - sd->narea = area_split(win, screen, sd->sarea, dir, fac, 0); /* 0 = no merge */ + sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */ if (sd->narea == NULL) { return false; @@ -2109,7 +2119,7 @@ static bool area_split_apply(bContext *C, wmOperator *op) sd->nedge->v1->editflag = 1; sd->nedge->v2->editflag = 1; - if (dir == 'h') { + if (dir_axis == SCREEN_AXIS_H) { sd->origval = sd->nedge->v1->vec.y; } else { @@ -2158,8 +2168,8 @@ static void area_split_exit(bContext *C, wmOperator *op) 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 == 'h' ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); + const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); + WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); } /* UI callback, adds new handler */ @@ -2175,7 +2185,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor"); PropertyRNA *prop_cursor = RNA_struct_find_property(op->ptr, "cursor"); - int dir; + eScreenAxis dir_axis; if (event->type == EVT_ACTIONZONE_AREA) { sActionzoneData *sad = event->customdata; @@ -2203,12 +2213,12 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) float factor; /* Prepare operator state vars. */ - if (ELEM(sad->gesture_dir, 'n', 's')) { - dir = 'h'; + if (SCREEN_DIR_IS_VERTICAL(sad->gesture_dir)) { + dir_axis = SCREEN_AXIS_H; factor = factor_h; } else { - dir = 'v'; + dir_axis = SCREEN_AXIS_V; factor = factor_v; } @@ -2218,7 +2228,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_property_float_set(op->ptr, prop_factor, factor); - RNA_property_enum_set(op->ptr, prop_dir, dir); + RNA_property_enum_set(op->ptr, prop_dir, dir_axis); /* general init, also non-UI case, adds customdata, sets area and defaults */ if (!area_split_init(C, op)) { @@ -2230,8 +2240,8 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (area == NULL) { return OPERATOR_CANCELLED; } - dir = RNA_property_enum_get(op->ptr, prop_dir); - if (dir == 'h') { + dir_axis = RNA_property_enum_get(op->ptr, prop_dir); + if (dir_axis == SCREEN_AXIS_H) { RNA_property_float_set( op->ptr, prop_factor, ((float)(event->x - area->v1->vec.x)) / (float)area->winx); } @@ -2264,9 +2274,9 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - dir = screen_geom_edge_is_horizontal(actedge) ? 'v' : 'h'; + dir_axis = screen_geom_edge_is_horizontal(actedge) ? SCREEN_AXIS_V : SCREEN_AXIS_H; - RNA_property_enum_set(op->ptr, prop_dir, dir); + RNA_property_enum_set(op->ptr, prop_dir, dir_axis); /* special case, adds customdata, sets defaults */ if (!area_split_menu_init(C, op)) { @@ -2279,7 +2289,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (event->type == EVT_ACTIONZONE_AREA) { /* do the split */ if (area_split_apply(C, op)) { - area_move_set_limits(win, screen, dir, &sd->bigger, &sd->smaller, NULL); + area_move_set_limits(win, screen, dir_axis, &sd->bigger, &sd->smaller, NULL); /* add temp handler for edge move or cancel */ G.moving |= G_TRANSFORM_WM; @@ -2367,8 +2377,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) else { if (event->val == KM_PRESS) { if (sd->sarea) { - int dir = RNA_property_enum_get(op->ptr, prop_dir); - RNA_property_enum_set(op->ptr, prop_dir, (dir == 'v') ? 'h' : 'v'); + const eScreenAxis dir_axis = RNA_property_enum_get(op->ptr, prop_dir); + RNA_property_enum_set( + op->ptr, prop_dir, (dir_axis == SCREEN_AXIS_V) ? SCREEN_AXIS_H : SCREEN_AXIS_V); area_split_preview_update_cursor(C, op); update_factor = true; } @@ -2389,9 +2400,9 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (update_factor) { - const int dir = RNA_property_enum_get(op->ptr, prop_dir); + const eScreenAxis dir_axis = RNA_property_enum_get(op->ptr, prop_dir); - sd->delta = (dir == 'v') ? event->x - sd->origval : event->y - sd->origval; + sd->delta = (dir_axis == SCREEN_AXIS_V) ? event->x - sd->origval : event->y - sd->origval; if (sd->previewmode == 0) { if (sd->do_snap) { @@ -2399,12 +2410,12 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) SNAP_FRACTION_AND_ADJACENT, sd->delta, sd->origval, - dir, + dir_axis, sd->bigger, sd->smaller); sd->delta = snap_loc - sd->origval; } - area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, SNAP_NONE); + area_move_apply_do(C, sd->delta, sd->origval, dir_axis, sd->bigger, sd->smaller, SNAP_NONE); } else { if (sd->sarea) { @@ -2415,7 +2426,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) if (sd->sarea) { ScrArea *area = sd->sarea; - if (dir == 'v') { + if (dir_axis == SCREEN_AXIS_V) { sd->origmin = area->v1->vec.x; sd->origsize = area->v4->vec.x - sd->origmin; } @@ -2431,7 +2442,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) SNAP_FRACTION_AND_ADJACENT, sd->delta, sd->origval, - dir, + dir_axis, sd->origmin + sd->origsize, -sd->origmin); @@ -2453,8 +2464,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) } static const EnumPropertyItem prop_direction_items[] = { - {'h', "HORIZONTAL", 0, "Horizontal", ""}, - {'v', "VERTICAL", 0, "Vertical", ""}, + {SCREEN_AXIS_H, "HORIZONTAL", 0, "Horizontal", ""}, + {SCREEN_AXIS_V, "VERTICAL", 0, "Vertical", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2475,7 +2486,7 @@ static void SCREEN_OT_area_split(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; /* rna */ - RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", ""); + RNA_def_enum(ot->srna, "direction", prop_direction_items, SCREEN_AXIS_H, "Direction", ""); RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0); RNA_def_int_vector( ot->srna, "cursor", 2, NULL, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX); @@ -3272,8 +3283,8 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) typedef struct sAreaJoinData { ScrArea *sa1; /* Potential source area (kept). */ ScrArea *sa2; /* Potential target area (removed or reduced). */ - int dir; /* Direction of potential join. */ - void *draw_callback; /* call 'ED_screen_draw_join_highlight' */ + eScreenDir dir; /* Direction of potential join. */ + void *draw_callback; /* call #screen_draw_join_highlight */ } sAreaJoinData; @@ -3282,8 +3293,8 @@ 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 && (sd->dir != -1)) { - ED_screen_draw_join_highlight(sd->sa1, sd->sa2); + if (sd->sa1 && sd->sa2 && (sd->dir != SCREEN_DIR_NONE)) { + screen_draw_join_highlight(sd->sa1, sd->sa2); } } @@ -3305,7 +3316,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s jd->sa1 = sa1; jd->sa2 = sa2; - jd->dir = -1; + jd->dir = SCREEN_DIR_NONE; op->customdata = jd; @@ -3318,7 +3329,7 @@ static bool area_join_init(bContext *C, wmOperator *op, ScrArea *sa1, ScrArea *s static bool area_join_apply(bContext *C, wmOperator *op) { sAreaJoinData *jd = (sAreaJoinData *)op->customdata; - if (!jd || (jd->dir == -1)) { + if (!jd || (jd->dir == SCREEN_DIR_NONE)) { return false; } @@ -3429,21 +3440,21 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) jd->dir = area_getorientation(jd->sa1, jd->sa2); } else if (area != jd->sa2) { - jd->dir = -1; + jd->dir = SCREEN_DIR_NONE; } WM_event_add_notifier(C, NC_WINDOW, NULL); - if (jd->dir == 1) { + if (jd->dir == SCREEN_DIR_N) { WM_cursor_set(win, WM_CURSOR_N_ARROW); } - else if (jd->dir == 3) { + else if (jd->dir == SCREEN_DIR_S) { WM_cursor_set(win, WM_CURSOR_S_ARROW); } - else if (jd->dir == 2) { + else if (jd->dir == SCREEN_DIR_E) { WM_cursor_set(win, WM_CURSOR_E_ARROW); } - else if (jd->dir == 0) { + else if (jd->dir == SCREEN_DIR_W) { WM_cursor_set(win, WM_CURSOR_W_ARROW); } else { @@ -3454,7 +3465,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) } case LEFTMOUSE: if (event->val == KM_RELEASE) { - if (jd->dir == -1) { + if (jd->dir == SCREEN_DIR_NONE) { area_join_cancel(C, op); return OPERATOR_CANCELLED; } @@ -3528,7 +3539,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent &ptr); /* store initial mouse cursor position. */ RNA_int_set_array(&ptr, "cursor", &event->x); - RNA_enum_set(&ptr, "direction", 'v'); + RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V); /* Horizontal Split */ uiItemFullO(layout, @@ -3541,7 +3552,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent &ptr); /* store initial mouse cursor position. */ RNA_int_set_array(&ptr, "cursor", &event->x); - RNA_enum_set(&ptr, "direction", 'h'); + RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H); if (sa1 && sa2) { uiItemS(layout); @@ -4126,7 +4137,7 @@ static void screen_area_menu_items(ScrArea *area, uiLayout *layout) &ptr); RNA_int_set_array(&ptr, "cursor", loc); - RNA_enum_set(&ptr, "direction", 'v'); + RNA_enum_set(&ptr, "direction", SCREEN_AXIS_V); /* Horizontal Split */ uiItemFullO(layout, @@ -4139,7 +4150,7 @@ static void screen_area_menu_items(ScrArea *area, uiLayout *layout) &ptr); RNA_int_set_array(&ptr, "cursor", &loc[0]); - RNA_enum_set(&ptr, "direction", 'h'); + RNA_enum_set(&ptr, "direction", SCREEN_AXIS_H); uiItemS(layout); @@ -5420,7 +5431,7 @@ static void context_cycle_prop_get(bScreen *screen, static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - const int direction = RNA_enum_get(op->ptr, "direction"); + const eScreenCycle direction = RNA_enum_get(op->ptr, "direction"); PointerRNA ptr; PropertyRNA *prop; @@ -5469,7 +5480,7 @@ static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEve } Main *bmain = CTX_data_main(C); - const int direction = RNA_enum_get(op->ptr, "direction"); + const eScreenCycle direction = RNA_enum_get(op->ptr, "direction"); WorkSpace *workspace_src = WM_window_get_active_workspace(win); WorkSpace *workspace_dst = NULL; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 7740fb42c37..3829aeebbeb 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1324,6 +1324,13 @@ static bool paint_cursor_context_init(bContext *C, copy_v3_fl(pcontext->outline_col, 0.8f); } + const bool is_brush_tool = PAINT_brush_tool_poll(C); + if (!is_brush_tool) { + /* Use a default color for tools that are not brushes. */ + pcontext->outline_alpha = 0.8f; + copy_v3_fl(pcontext->outline_col, 0.8f); + } + pcontext->is_stroke_active = pcontext->ups->stroke_active; return true; @@ -1610,9 +1617,11 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * pcontext->radius); } + const bool is_brush_tool = PAINT_brush_tool_poll(pcontext->C); + /* Pose brush updates and rotation origins. */ - if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_POSE) { /* Just after switching to the Pose Brush, the active vertex can be the same and the * cursor won't be tagged to update, so always initialize the preview chain if it is * null before drawing it. */ @@ -1645,7 +1654,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * 2); } - if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { paint_cursor_preview_boundary_data_update(pcontext, update_previews); paint_cursor_preview_boundary_data_pivot_draw(pcontext); } @@ -1666,17 +1675,18 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * GPU_matrix_mul(pcontext->vc.obact->obmat); /* Drawing Cursor overlays in 3D object space. */ - if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_GRAB && + (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX)) { SCULPT_geometry_preview_lines_update(pcontext->C, pcontext->ss, pcontext->radius); sculpt_geometry_preview_lines_draw( pcontext->pos, pcontext->brush, pcontext->is_multires, pcontext->ss); } - if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_POSE) { paint_cursor_pose_brush_segments_draw(pcontext); } - if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { SCULPT_boundary_edges_preview_draw( pcontext->pos, pcontext->ss, pcontext->outline_col, pcontext->outline_alpha); SCULPT_boundary_pivot_line_preview_draw(pcontext->pos, pcontext->ss); @@ -1692,7 +1702,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * paint_cursor_draw_main_inactive_cursor(pcontext); /* Cloth brush local simulation areas. */ - if (brush->sculpt_tool == SCULPT_TOOL_CLOTH && + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_CLOTH && brush->cloth_simulation_area_type != BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) { const float white[3] = {1.0f, 1.0f, 1.0f}; const float zero_v[3] = {0.0f}; @@ -1704,7 +1714,7 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * } /* Layer brush height. */ - if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { + if (is_brush_tool && brush->sculpt_tool == SCULPT_TOOL_LAYER) { SCULPT_layer_brush_height_preview_draw(pcontext->pos, brush, pcontext->radius, diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 3ca0d853d6a..3f5093222e9 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -87,7 +87,7 @@ struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); void *paint_stroke_mode_data(struct PaintStroke *stroke); float paint_stroke_distance_get(struct PaintStroke *stroke); void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); -bool paint_poll(struct bContext *C); +bool PAINT_brush_tool_poll(struct bContext *C); void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C)); void paint_cursor_delete_textures(void); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index e1dc8fa30b9..fed89e02e8f 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -139,13 +139,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + const bool is_gpencil = (brush && brush->gpencil_settings != NULL); // Object *ob = CTX_data_active_object(C); float scalar = RNA_float_get(op->ptr, "scalar"); if (brush) { /* pixel radius */ { - const int old_size = BKE_brush_size_get(scene, brush); + const int old_size = (!is_gpencil) ? BKE_brush_size_get(scene, brush) : brush->size; int size = (int)(scalar * old_size); if (abs(old_size - size) < U.pixelsize) { @@ -156,6 +157,12 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op) size -= U.pixelsize; } } + /* Grease Pencil does not use unified size. */ + if (is_gpencil) { + brush->size = max_ii(size, 1); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); + return OPERATOR_FINISHED; + } BKE_brush_size_set(scene, brush, size); } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 49ddf2f82d8..b093f07226e 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -1462,7 +1462,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (paint_supports_smooth_stroke(br, mode)) { stroke->stroke_cursor = WM_paint_cursor_activate( - SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke); + SPACE_TYPE_ANY, RGN_TYPE_ANY, PAINT_brush_tool_poll, paint_draw_smooth_cursor, stroke); } stroke->stroke_init = true; @@ -1489,7 +1489,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (br->flag & BRUSH_LINE) { stroke->stroke_cursor = WM_paint_cursor_activate( - SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke); + SPACE_TYPE_ANY, RGN_TYPE_ANY, PAINT_brush_tool_poll, paint_draw_line_cursor, stroke); } first_dab = true; @@ -1659,7 +1659,7 @@ void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) stroke->mode_data = mode_data; } -bool paint_poll(bContext *C) +bool PAINT_brush_tool_poll(bContext *C) { Paint *p = BKE_paint_get_active_from_context(C); Object *ob = CTX_data_active_object(C); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 964e5bdaa90..2e1dd928f96 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -780,6 +780,10 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, iter->neighbors = iter->neighbors_fixed; for (int i = 0; i < ss->pmap[index].count; i++) { + if (ss->face_sets[vert_map->indices[i]] < 0) { + /* Skip connectivity from hidden faces. */ + continue; + } const MPoly *p = &ss->mpoly[vert_map->indices[i]]; uint f_adj_v[2]; if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) { @@ -6602,7 +6606,7 @@ bool SCULPT_poll_view3d(bContext *C) bool SCULPT_poll(bContext *C) { - return SCULPT_mode_poll(C) && paint_poll(C); + return SCULPT_mode_poll(C) && PAINT_brush_tool_poll(C); } static const char *sculpt_tool_name(Sculpt *sd) diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 8b8ed42a694..40874375772 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -273,7 +273,7 @@ static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache */ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_cache, const int f) { - if (ss->face_sets[f] <= 0) { + if (expand_cache->original_face_sets[f] <= 0) { return false; } @@ -1398,6 +1398,13 @@ static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expa { const int totfaces = ss->totfaces; for (int i = 0; i < totfaces; i++) { + if (expand_cache->original_face_sets[i] <= 0) { + /* Do not modify hidden Face Sets, even when restoring the IDs state. */ + continue; + } + if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) { + continue; + } ss->face_sets[i] = expand_cache->initial_face_sets[i]; } } @@ -1892,13 +1899,22 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event * The faces that were using the `delete_id` Face Set are filled * using the content from their neighbors. */ -static void sculpt_expand_delete_face_set_id( - int *r_face_sets, Mesh *mesh, MeshElemMap *pmap, const int totface, const int delete_id) +static void sculpt_expand_delete_face_set_id(int *r_face_sets, + SculptSession *ss, + ExpandCache *expand_cache, + Mesh *mesh, + const int delete_id) { + const int totface = ss->totfaces; + MeshElemMap *pmap = ss->pmap; + /* Check that all the face sets IDs in the mesh are not equal to `delete_id` * before attempting to delete it. */ bool all_same_id = true; for (int i = 0; i < totface; i++) { + if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) { + continue; + } if (r_face_sets[i] != delete_id) { all_same_id = false; break; @@ -1921,6 +1937,7 @@ static void sculpt_expand_delete_face_set_id( } while (BLI_LINKSTACK_SIZE(queue)) { + bool any_updated = false; while (BLI_LINKSTACK_SIZE(queue)) { const int f_index = POINTER_AS_INT(BLI_LINKSTACK_POP(queue)); int other_id = delete_id; @@ -1931,6 +1948,10 @@ static void sculpt_expand_delete_face_set_id( for (int i = 0; i < vert_map->count; i++) { const int neighbor_face_index = vert_map->indices[i]; + if (expand_cache->original_face_sets[neighbor_face_index] <= 0) { + /* Skip picking IDs from hidden Face Sets. */ + continue; + } if (r_face_sets[neighbor_face_index] != delete_id) { other_id = r_face_sets[neighbor_face_index]; } @@ -1938,18 +1959,36 @@ static void sculpt_expand_delete_face_set_id( } if (other_id != delete_id) { + any_updated = true; r_face_sets[f_index] = other_id; } else { BLI_LINKSTACK_PUSH(queue_next, POINTER_FROM_INT(f_index)); } } + if (!any_updated) { + /* No Face Sets where updated in this iteration, which means that no more content to keep + * filling the polys of the deleted Face Set was found. Break to avoid entering an infinite + * loop trying to search for those polys again. */ + break; + } BLI_LINKSTACK_SWAP(queue, queue_next); } BLI_LINKSTACK_FREE(queue); BLI_LINKSTACK_FREE(queue_next); + + /* Ensure that the visibility state of the modified Face Sets is the same as the original ones. + */ + for (int i = 0; i < totface; i++) { + if (expand_cache->original_face_sets[i] >= 0) { + r_face_sets[i] = abs(r_face_sets[i]); + } + else { + r_face_sets[i] = -abs(r_face_sets[i]); + } + } } static void sculpt_expand_cache_initial_config_set(bContext *C, @@ -2070,9 +2109,9 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even if (ss->expand_cache->modify_active_face_set) { sculpt_expand_delete_face_set_id(ss->expand_cache->initial_face_sets, + ss, + ss->expand_cache, ob->data, - ss->pmap, - ss->totfaces, ss->expand_cache->next_face_set); } diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index c71e5e49d8d..b5f6874fcfc 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -50,7 +50,7 @@ if(WITH_FREESTYLE) endif() if(WITH_EXPERIMENTAL_FEATURES) - add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_SIMULATION_DATABLOCK) add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 1699e704a4d..aeb2c04656e 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -975,7 +975,8 @@ int /*eContextResult*/ buttons_context(const bContext *C, if (matnr < 0) { matnr = 0; } - CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, &ob->mat[matnr]); + /* Keep aligned with rna_Object_material_slots_get. */ + CTX_data_pointer_set(result, &ob->id, &RNA_MaterialSlot, POINTER_FROM_INT(matnr + 1)); } } diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 74e7bc11c26..7564fa4b930 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -35,6 +35,7 @@ struct bContext; struct bContextDataResult; struct bNode; struct bNodeTree; +struct bNodeSocket; struct wmOperatorType; struct SpaceProperties_Runtime { @@ -66,6 +67,7 @@ typedef struct ButsTextureUser { struct bNodeTree *ntree; struct bNode *node; + struct bNodeSocket *socket; const char *category; int icon; diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 43128ed00fa..97e3cb750c1 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -75,15 +75,16 @@ static SpaceProperties *find_space_properties(const bContext *C); /************************* Texture User **************************/ -static void buttons_texture_user_node_property_add(ListBase *users, - ID *id, - PointerRNA ptr, - PropertyRNA *prop, - bNodeTree *ntree, - bNode *node, - const char *category, - int icon, - const char *name) +static void buttons_texture_user_socket_property_add(ListBase *users, + ID *id, + PointerRNA ptr, + PropertyRNA *prop, + bNodeTree *ntree, + bNode *node, + bNodeSocket *socket, + const char *category, + int icon, + const char *name) { ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser"); @@ -92,6 +93,7 @@ static void buttons_texture_user_node_property_add(ListBase *users, user->prop = prop; user->ntree = ntree; user->node = node; + user->socket = socket; user->category = category; user->icon = icon; user->name = name; @@ -181,25 +183,29 @@ static void buttons_texture_modifier_geonodes_users_add(Object *ob, /* Recurse into the node group */ buttons_texture_modifier_geonodes_users_add(ob, nmd, (bNodeTree *)node->id, users); } - else if (node->type == GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE) { - RNA_pointer_create(&node_tree->id, &RNA_Node, node, &ptr); - prop = RNA_struct_find_property(&ptr, "texture"); - if (prop == NULL) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + if (socket->flag & SOCK_UNAVAIL) { + continue; + } + if (socket->type != SOCK_TEXTURE) { continue; } + RNA_pointer_create(&node_tree->id, &RNA_NodeSocket, socket, &ptr); + prop = RNA_struct_find_property(&ptr, "default_value"); PointerRNA texptr = RNA_property_pointer_get(&ptr, prop); Tex *tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? (Tex *)texptr.data : NULL; if (tex != NULL) { - buttons_texture_user_node_property_add(users, - &ob->id, - ptr, - prop, - node_tree, - node, - N_("Geometry Nodes"), - RNA_struct_ui_icon(ptr.type), - nmd->modifier.name); + buttons_texture_user_socket_property_add(users, + &ob->id, + ptr, + prop, + node_tree, + node, + socket, + N_("Geometry Nodes"), + RNA_struct_ui_icon(ptr.type), + nmd->modifier.name); } } } diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c index 9882304d97d..0a99d1020f6 100644 --- a/source/blender/editors/space_clip/tracking_ops_track.c +++ b/source/blender/editors/space_clip/tracking_ops_track.c @@ -24,8 +24,11 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" @@ -398,6 +401,28 @@ static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEven return OPERATOR_PASS_THROUGH; } +static char *track_markers_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr) +{ + const bool backwards = RNA_boolean_get(ptr, "backwards"); + const bool sequence = RNA_boolean_get(ptr, "sequence"); + + if (backwards && sequence) { + return BLI_strdup(TIP_("Track the selected markers backward for the entire clip")); + } + if (backwards && !sequence) { + return BLI_strdup(TIP_("Track the selected markers backward by one frame")); + } + if (!backwards && sequence) { + return BLI_strdup(TIP_("Track the selected markers forward for the entire clip")); + } + if (!backwards && !sequence) { + return BLI_strdup(TIP_("Track the selected markers forward by one frame")); + } + + /* Use default description. */ + return NULL; +} + void CLIP_OT_track_markers(wmOperatorType *ot) { /* identifiers */ @@ -410,6 +435,7 @@ void CLIP_OT_track_markers(wmOperatorType *ot) ot->invoke = track_markers_invoke; ot->modal = track_markers_modal; ot->poll = ED_space_clip_tracking_poll; + ot->get_description = track_markers_desc; /* flags */ ot->flag = OPTYPE_UNDO; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index c1dcf2e56d3..189b9b4c874 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -323,6 +323,7 @@ static void file_draw_preview(uiBlock *block, int ex, ey; bool show_outline = !is_icon && (file->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); + const bool is_offline = (file->attributes & FILE_ATTR_OFFLINE); BLI_assert(imb != NULL); @@ -419,14 +420,14 @@ static void file_draw_preview(uiBlock *block, icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); } - if (is_link) { - /* Arrow icon to indicate it is a shortcut, link, or alias. */ + if (is_link || is_offline) { + /* Icon at bottom to indicate it is a shortcut, link, alias, or offline. */ float icon_x, icon_y; icon_x = xco + (2.0f * UI_DPI_FAC); icon_y = yco + (2.0f * UI_DPI_FAC); - const int arrow = ICON_LOOP_FORWARDS; + const int arrow = is_link ? ICON_LOOP_FORWARDS : ICON_URL; if (!is_icon) { - /* Arrow at very bottom-left if preview style. */ + /* At very bottom-left if preview style. */ const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index c2b3a7ac0ee..37a32164cfc 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1601,37 +1601,51 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); - if (!entry->preview_icon_id && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && - (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | - FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { - FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); - FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; + if (!entry->preview_icon_id && (entry->attributes & FILE_ATTR_OFFLINE)) { + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + return; + } - if (entry->redirection_path) { - BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); - } - else { - BLI_join_dirfile( - preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); - } + if (entry->preview_icon_id) { + return; + } - preview->index = index; - preview->flags = entry->typeflag; - preview->in_memory_preview = intern_entry->local_data.preview_image; - preview->icon_id = 0; - // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + if (entry->flags & FILE_ENTRY_INVALID_PREVIEW) { + return; + } + + if (!(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | + FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { + return; + } - filelist_cache_preview_ensure_running(cache); + FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; - FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), - __func__); - preview_taskdata->preview = preview; - BLI_task_pool_push(cache->previews_pool, - filelist_cache_preview_runf, - preview_taskdata, - true, - filelist_cache_preview_freef); + if (entry->redirection_path) { + BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); + } + else { + BLI_join_dirfile( + preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); } + + preview->index = index; + preview->flags = entry->typeflag; + preview->in_memory_preview = intern_entry->local_data.preview_image; + preview->icon_id = 0; + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + + filelist_cache_preview_ensure_running(cache); + + FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), + __func__); + preview_taskdata->preview = preview; + BLI_task_pool_push(cache->previews_pool, + filelist_cache_preview_runf, + preview_taskdata, + true, + filelist_cache_preview_freef); } static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) @@ -2360,17 +2374,19 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index) // printf("Re-queueing previews...\n"); - /* Note we try to preview first images around given index - i.e. assumed visible ones. */ if (cache->flags & FLC_PREVIEWS_ACTIVE) { - for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) { - if ((index - i) >= start_index) { - const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i); - } - if ((index + i) < end_index) { - const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size; - filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i); - } + /* Note we try to preview first images around given index - i.e. assumed visible ones. */ + int block_index = cache->block_cursor + (index - start_index); + int offs_max = max_ii(end_index - index, index - start_index); + for (i = 0; i <= offs_max; i++) { + int offs = i; + do { + int offs_idx = index + offs; + if (start_index <= offs_idx && offs_idx < end_index) { + int offs_block_idx = (block_index + offs) % (int)cache_size; + filelist_cache_previews_push(filelist, cache->block_entries[offs_block_idx], offs_idx); + } + } while ((offs = -offs) < 0); /* Switch between negative and positive offset. */ } } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 8bf6f2698e0..7d4011e0812 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -266,7 +266,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col } else if (strip->type == NLASTRIP_TYPE_META) { /* Meta Clip */ - /* TODO: should temporary metas get different colors too? */ + /* TODO: should temporary meta-strips get different colors too? */ if (strip->flag & NLASTRIP_FLAG_SELECT) { /* selected - use a bold purple color */ UI_GetThemeColor3fv(TH_NLA_META_SEL, color); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 5110c14ef4d..6b4366b2966 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -456,7 +456,9 @@ static void node_draw_frame(const bContext *C, } /* label */ - node_draw_frame_label(ntree, node, snode->runtime->aspect); + if (node->label[0] != '\0') { + node_draw_frame_label(ntree, node, snode->runtime->aspect); + } UI_block_end(C, node->block); UI_block_draw(C, node->block); @@ -3332,12 +3334,14 @@ static const float std_node_socket_colors[][4] = { {0.39, 0.78, 0.39, 1.0}, /* SOCK_SHADER */ {0.80, 0.65, 0.84, 1.0}, /* SOCK_BOOLEAN */ {0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */ - {0.25, 0.75, 0.26, 1.0}, /* SOCK_INT */ + {0.35, 0.55, 0.36, 1.0}, /* SOCK_INT */ {0.44, 0.70, 1.00, 1.0}, /* SOCK_STRING */ {0.93, 0.62, 0.36, 1.0}, /* SOCK_OBJECT */ - {0.89, 0.76, 0.43, 1.0}, /* SOCK_IMAGE */ + {0.39, 0.22, 0.39, 1.0}, /* SOCK_IMAGE */ {0.00, 0.84, 0.64, 1.0}, /* SOCK_GEOMETRY */ {0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */ + {0.62, 0.31, 0.64, 1.0}, /* SOCK_TEXTURE */ + {0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */ }; /* common color callbacks for standard types */ @@ -3478,6 +3482,14 @@ static void std_node_socket_draw( uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } + case SOCK_TEXTURE: { + uiTemplateID(layout, C, ptr, "default_value", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); + break; + } + case SOCK_MATERIAL: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); + break; + } default: node_socket_button_label(C, layout, ptr, node_ptr, text); break; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index d4780534a83..50fa8b28468 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1713,8 +1713,6 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) } } - do_tag_update |= ED_node_is_geometry(snode); - snode_notify(C, snode); if (do_tag_update) { snode_dag_update(C, snode); @@ -1755,8 +1753,6 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) } } - do_tag_update |= ED_node_is_geometry(snode); - ntreeUpdateTree(CTX_data_main(C), snode->edittree); snode_notify(C, snode); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 91fe8f5ec89..28c660b0632 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -852,8 +852,6 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) } ntree->is_updating = false; - do_tag_update |= ED_node_is_geometry(snode); - ntreeUpdateTree(bmain, ntree); snode_notify(C, snode); if (do_tag_update) { @@ -1291,8 +1289,6 @@ static int cut_links_exec(bContext *C, wmOperator *op) } } - do_tag_update |= ED_node_is_geometry(snode); - if (found) { ntreeUpdateTree(CTX_data_main(C), snode->edittree); snode_notify(C, snode); @@ -1399,8 +1395,6 @@ static int mute_links_exec(bContext *C, wmOperator *op) link->flag &= ~NODE_LINK_TEST; } - do_tag_update |= ED_node_is_geometry(snode); - ntreeUpdateTree(CTX_data_main(C), snode->edittree); snode_notify(C, snode); if (do_tag_update) { @@ -1882,28 +1876,63 @@ void ED_node_link_intersect_test(ScrArea *area, int test) } } -/* assumes sockets in list */ -static bNodeSocket *socket_best_match(ListBase *sockets) -{ - /* find type range */ - int maxtype = 0; +static int get_main_socket_priority(const bNodeSocket *socket) +{ + switch ((eNodeSocketDatatype)socket->type) { + case __SOCK_MESH: + case SOCK_CUSTOM: + return -1; + case SOCK_BOOLEAN: + return 0; + case SOCK_INT: + return 1; + case SOCK_FLOAT: + return 2; + case SOCK_VECTOR: + return 3; + case SOCK_RGBA: + return 4; + case SOCK_STRING: + case SOCK_SHADER: + case SOCK_OBJECT: + case SOCK_IMAGE: + case SOCK_GEOMETRY: + case SOCK_COLLECTION: + case SOCK_TEXTURE: + case SOCK_MATERIAL: + return 5; + } + return -1; +} + +/** Get the "main" socket of a socket list using a heuristic based on socket types. */ +static bNodeSocket *get_main_socket(ListBase *sockets) +{ + /* find priority range */ + int maxpriority = -1; LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - maxtype = max_ii(sock->type, maxtype); + if (sock->flag & SOCK_UNAVAIL) { + continue; + } + maxpriority = max_ii(get_main_socket_priority(sock), maxpriority); } - /* try all types, starting from 'highest' (i.e. colors, vectors, values) */ - for (int type = maxtype; type >= 0; type--) { + /* try all priorities, starting from 'highest' */ + for (int priority = maxpriority; priority >= 0; priority--) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - if (!nodeSocketIsHidden(sock) && type == sock->type) { + if (!nodeSocketIsHidden(sock) && priority == get_main_socket_priority(sock)) { return sock; } } } - /* no visible sockets, unhide first of highest type */ - for (int type = maxtype; type >= 0; type--) { + /* no visible sockets, unhide first of highest priority */ + for (int priority = maxpriority; priority >= 0; priority--) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - if (type == sock->type) { + if (sock->flag & SOCK_UNAVAIL) { + continue; + } + if (priority == get_main_socket_priority(sock)) { sock->flag &= ~SOCK_HIDDEN; return sock; } @@ -2248,8 +2277,8 @@ void ED_node_link_insert(Main *bmain, ScrArea *area) } if (link) { - bNodeSocket *best_input = socket_best_match(&select->inputs); - bNodeSocket *best_output = socket_best_match(&select->outputs); + bNodeSocket *best_input = get_main_socket(&select->inputs); + bNodeSocket *best_output = get_main_socket(&select->outputs); if (best_input && best_output) { bNode *node = link->tonode; diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 456c2079f27..c532dd8accd 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -902,7 +902,7 @@ static void id_override_library_reset_fn(bContext *C, } static void id_override_library_resync_fn(bContext *C, - ReportList *UNUSED(reports), + ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), @@ -931,7 +931,7 @@ static void id_override_library_resync_fn(bContext *C, } BKE_lib_override_library_resync( - bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true); + bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true, reports); WM_event_add_notifier(C, NC_WINDOW, NULL); } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 7beb61e48d2..b55c8035fa3 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -885,10 +885,12 @@ static void draw_seq_background(Scene *scene, immUniformColor4ubv(col); if (seq->startstill) { - immRectf(pos, seq->startdisp, y1, (float)(seq->start), y2); + const float content_start = min_ff(seq->enddisp, seq->start); + immRectf(pos, seq->startdisp, y1, content_start, y2); } if (seq->endstill) { - immRectf(pos, (float)(seq->start + seq->len), y1, seq->enddisp, y2); + const float content_end = max_ff(seq->startdisp, seq->start + seq->len); + immRectf(pos, content_end, y1, seq->enddisp, y2); } } @@ -1105,6 +1107,10 @@ static void draw_seq_strip(const bContext *C, x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; y2 = seq->machine + SEQ_STRIP_OFSTOP; + /* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */ + x1 = min_ff(x1, seq->enddisp); + x2 = max_ff(x2, seq->startdisp); + float text_margin_y; bool y_threshold; if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) || @@ -1522,10 +1528,10 @@ static void *sequencer_OCIO_transform_ibuf(const bContext *C, ImBuf *ibuf, bool *r_glsl_used, eGPUTextureFormat *r_format, - eGPUDataFormat *r_data) + eGPUDataFormat *r_data, + void **r_buffer_cache_handle) { void *display_buffer; - void *cache_handle = NULL; bool force_fallback = false; *r_glsl_used = false; force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL); @@ -1578,13 +1584,10 @@ static void *sequencer_OCIO_transform_ibuf(const bContext *C, /* There is data to be displayed, but GLSL is not initialized * properly, in this case we fallback to CPU-based display transform. */ if ((ibuf->rect || ibuf->rect_float) && !*r_glsl_used) { - display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); + display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, r_buffer_cache_handle); *r_format = GPU_RGBA8; *r_data = GPU_DATA_UBYTE; } - if (cache_handle) { - IMB_display_buffer_release(cache_handle); - } return display_buffer; } @@ -1658,6 +1661,7 @@ static void sequencer_draw_display_buffer(const bContext *C, bool draw_backdrop) { void *display_buffer; + void *buffer_cache_handle = NULL; if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { GPU_blend(GPU_BLEND_ALPHA); @@ -1685,7 +1689,8 @@ static void sequencer_draw_display_buffer(const bContext *C, data = GPU_DATA_UBYTE; } else { - display_buffer = sequencer_OCIO_transform_ibuf(C, ibuf, &glsl_used, &format, &data); + display_buffer = sequencer_OCIO_transform_ibuf( + C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle); } if (draw_backdrop) { @@ -1745,6 +1750,10 @@ static void sequencer_draw_display_buffer(const bContext *C, IMB_colormanagement_finish_glsl_draw(); } + if (buffer_cache_handle) { + IMB_display_buffer_release(buffer_cache_handle); + } + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) { GPU_blend(GPU_BLEND_NONE); } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 9c204373ffc..ebd4c0090b4 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -290,7 +290,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) snap_frame = RNA_int_get(op->ptr, "frame"); - /* Check metas. */ + /* Check meta-strips. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) && SEQ_transform_sequence_can_be_translated(seq)) { @@ -348,7 +348,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) } } - SEQ_sort(scene); + SEQ_sort(SEQ_active_seqbase_get(ed)); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1443,7 +1443,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } } - SEQ_sort(scene); + SEQ_sort(SEQ_active_seqbase_get(ed)); } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1577,17 +1577,6 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot) /** \name Duplicate Strips Operator * \{ */ -static int apply_unique_name_fn(Sequence *seq, void *arg_pt) -{ - Scene *scene = (Scene *)arg_pt; - char name[sizeof(seq->name) - 2]; - - BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); - SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); - SEQ_dupe_animdata(scene, name, seq->name + 2); - return 1; -} - static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -1608,7 +1597,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) BLI_movelisttolist(ed->seqbasep, &nseqbase); for (; seq; seq = seq->next) { - SEQ_recursive_apply(seq, apply_unique_name_fn, scene); + SEQ_ensure_unique_name(seq, scene); } WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1829,7 +1818,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } } - SEQ_sort(scene); + SEQ_sort(SEQ_active_seqbase_get(ed)); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1867,13 +1856,13 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) Sequence *active_seq = SEQ_select_active_get(scene); if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) { - /* Enter metastrip. */ + /* Enter meta-strip. */ SEQ_meta_stack_alloc(ed, active_seq); SEQ_seqbase_active_set(ed, &active_seq->seqbase); SEQ_select_active_set(scene, NULL); } else { - /* Exit metastrip if possible. */ + /* Exit meta-strip if possible. */ if (BLI_listbase_is_empty(&ed->metastack)) { return OPERATOR_CANCELLED; } @@ -1895,7 +1884,7 @@ void SEQUENCER_OT_meta_toggle(wmOperatorType *ot) /* Identifiers. */ ot->name = "Toggle Meta Strip"; ot->idname = "SEQUENCER_OT_meta_toggle"; - ot->description = "Toggle a metastrip (to edit enclosed strips)"; + ot->description = "Toggle a meta-strip (to edit enclosed strips)"; /* Api callbacks. */ ot->exec = sequencer_meta_toggle_exec; @@ -1963,7 +1952,7 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot) /* Identifiers. */ ot->name = "Make Meta Strip"; ot->idname = "SEQUENCER_OT_meta_make"; - ot->description = "Group selected strips into a metastrip"; + ot->description = "Group selected strips into a meta-strip"; /* Api callbacks. */ ot->exec = sequencer_meta_make_exec; @@ -2014,7 +2003,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) } } - SEQ_sort(scene); + SEQ_sort(active_seqbase); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2026,7 +2015,7 @@ void SEQUENCER_OT_meta_separate(wmOperatorType *ot) /* Identifiers. */ ot->name = "UnMeta Strip"; ot->idname = "SEQUENCER_OT_meta_separate"; - ot->description = "Put the contents of a metastrip back in the sequencer"; + ot->description = "Put the contents of a meta-strip back in the sequencer"; /* Api callbacks. */ ot->exec = sequencer_meta_separate_exec; @@ -2237,7 +2226,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) } } - SEQ_sort(scene); + SEQ_sort(SEQ_active_seqbase_get(ed)); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2465,7 +2454,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) for (iseq = iseq_first; iseq; iseq = iseq->next) { /* Make sure, that pasted strips have unique names. */ - SEQ_recursive_apply(iseq, apply_unique_name_fn, scene); + SEQ_ensure_unique_name(iseq, scene); /* Translate after name has been changed, otherwise this will affect animdata of original * strip. */ SEQ_transform_translate_sequence(scene, iseq, ofs); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index a9f8a70d61e..e386a48ed7e 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -26,7 +26,6 @@ #include <string.h> #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -1187,7 +1186,7 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) case 1: test = (timeline_frame <= seq->startdisp); break; - case 0: + case 2: test = (timeline_frame <= seq->enddisp) && (timeline_frame >= seq->startdisp); break; } @@ -1210,6 +1209,7 @@ void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot) static const EnumPropertyItem sequencer_select_left_right_types[] = { {-1, "LEFT", 0, "Left", "Select to the left of the current frame"}, {1, "RIGHT", 0, "Right", "Select to the right of the current frame"}, + {2, "CURRENT", 0, "Current frame", "Select intersecting with the current frame"}, {0, NULL, 0, NULL, NULL}, }; @@ -1622,64 +1622,47 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq) return changed; } -static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel) +/* Query strips that are in lower channel and intersect in time with seq_reference. */ +static void query_lower_channel_strips(Sequence *seq_reference, + ListBase *seqbase, + SeqCollection *collection) { - bool changed = false; - const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq)); - int startdisp = actseq->startdisp; - int enddisp = actseq->enddisp; - int machine = actseq->machine; - SeqIterator iter; - - LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { - seq->tmp = NULL; - } - - actseq->tmp = POINTER_FROM_INT(true); - - Sequence *seq = NULL; - for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) { - seq = iter.seq; - - /* Ignore all seqs already selected. */ - /* Ignore all seqs not sharing some time with active one. */ - /* Ignore all seqs of incompatible types (audio vs video). */ - if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) || - (seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) || - (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) { - continue; + LISTBASE_FOREACH (Sequence *, seq_test, seqbase) { + if (seq_test->machine > seq_reference->machine) { + continue; /* Not lower channel. */ } + if (seq_test->enddisp <= seq_reference->startdisp || + seq_test->startdisp >= seq_reference->enddisp) { + continue; /* Not intersecting in time. */ + } + SEQ_collection_append_strip(seq_test, collection); + } +} - /* If the seq is an effect one, we need extra checking. */ - if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) || - (seq->seq3 && seq->seq3->tmp))) { - if (startdisp > seq->startdisp) { - startdisp = seq->startdisp; - } - if (enddisp < seq->enddisp) { - enddisp = seq->enddisp; - } - if (machine < seq->machine) { - machine = seq->machine; - } - - seq->tmp = POINTER_FROM_INT(true); +/* Select all strips within time range and with lower channel of initial selection. Then select + * effect chains of these strips. */ +static bool select_grouped_effect_link(Editing *ed, + Sequence *UNUSED(actseq), + const int UNUSED(channel)) +{ + ListBase *seqbase = SEQ_active_seqbase_get(ed); - seq->flag |= SELECT; - changed = true; + /* Get collection of strips. */ + SeqCollection *collection = SEQ_query_selected_strips(seqbase); + const int selected_strip_count = BLI_gset_len(collection->set); + SEQ_collection_expand(seqbase, collection, query_lower_channel_strips); + SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain); - /* Unfortunately, we must restart checks from the beginning. */ - SEQ_iterator_end(&iter); - SEQ_iterator_begin(ed, &iter, true); - } + /* Check if other strips will be affected. */ + const bool changed = BLI_gset_len(collection->set) > selected_strip_count; - /* Video strips below active one, or any strip for audio (order doesn't matter here). */ - else if (seq->machine < machine || is_audio) { - seq->flag |= SELECT; - changed = true; - } + /* Actual logic. */ + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, collection) { + seq->flag |= SELECT; } - SEQ_iterator_end(&iter); + + SEQ_collection_free(collection); return changed; } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index e6916c34a88..b5274c2357e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1595,7 +1595,6 @@ static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area)) } const char *view3d_context_dir[] = { - "active_base", "active_object", NULL, }; @@ -1608,20 +1607,6 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (CTX_data_dir(member)) { CTX_data_dir_set(result, view3d_context_dir); } - else if (CTX_data_equals(member, "active_base")) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - if (view_layer->basact) { - Object *ob = view_layer->basact->object; - /* if hidden but in edit mode, we still display, can happen with animation */ - if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || - (ob->mode != OB_MODE_OBJECT)) { - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); - } - } - - return 1; - } else if (CTX_data_equals(member, "active_object")) { /* In most cases the active object is the `view_layer->basact->object`. * For the 3D view however it can be NULL when hidden. diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index f3a279ee12b..0a89b7d0292 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1288,6 +1288,11 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y name_array[name_array_len++] = IFACE_(" (Local)"); } + /* Indicate that clipping region is enabled. */ + if (rv3d->rflag & RV3D_CLIPPING) { + name_array[name_array_len++] = IFACE_(" (Clipped)"); + } + if (name_array_len > 1) { BLI_string_join_array(tmpstr, sizeof(tmpstr), name_array, name_array_len); name = tmpstr; @@ -2017,7 +2022,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, source_shading_settings = shading_override; } memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading)); - v3d.shading.type = drawtype; if (drawtype == OB_MATERIAL) { v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS; @@ -2027,6 +2031,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, v3d.shading.flag = V3D_SHADING_SCENE_WORLD_RENDER | V3D_SHADING_SCENE_LIGHTS_RENDER; v3d.shading.render_pass = SCE_PASS_COMBINED; } + else if (drawtype == OB_TEXTURE) { + drawtype = OB_SOLID; + v3d.shading.light = V3D_LIGHTING_STUDIO; + v3d.shading.color_type = V3D_SHADING_TEXTURE_COLOR; + } + v3d.shading.type = drawtype; v3d.flag2 = V3D_HIDE_OVERLAYS; @@ -2067,7 +2077,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, return ED_view3d_draw_offscreen_imbuf(depsgraph, scene, - drawtype, + v3d.shading.type, &v3d, ®ion, width, diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 3134553c159..0d568363b00 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -446,7 +446,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) gpl = view3d_ruler_layer_get(gpd); if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); + gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false, false); copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER; diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index bb3afd77dba..ba8e5c1e2c6 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -782,7 +782,7 @@ static bool transform_event_modal_constraint(TransInfo *t, short modal_type) } else { short orient_index = 1; - if (t->orient_curr == 0 || ELEM(constraint_curr, -1, constraint_new)) { + if (t->orient_curr == O_DEFAULT || ELEM(constraint_curr, -1, constraint_new)) { /* Successive presses on existing axis, cycle orientation modes. */ orient_index = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); } @@ -1412,25 +1412,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); PropertyRNA *prop; - if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && - ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { - /* When redoing these modes the first time, it's more convenient to save - * in the Global orientation. */ - if (t->mode == TFM_TRANSLATION) { - mul_m3_v3(t->spacemtx, t->values_final); - } - else { - float tmat[3][3], sizemat[3][3]; - size_to_mat3(sizemat, t->values_final); - mul_m3_m3m3(tmat, t->spacemtx, sizemat); - mat3_to_size(t->values_final, tmat); - } - - BLI_assert(t->orient_curr == 0); - unit_m3(t->spacemtx); - t->orient[0].type = V3D_ORIENT_GLOBAL; - } - /* Save back mode in case we're in the generic operator */ if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { RNA_property_enum_set(op->ptr, prop, t->mode); @@ -1638,7 +1619,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2]) /** * \note caller needs to free 't' on a 0 return - * \warning \a event might be NULL (when tweaking from redo panel) + * \warning \a event might be NULL (when tweaking from redo panel) * \see #saveTransform which writes these values back. */ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 090b8b83dcc..a10a53b2983 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -596,11 +596,18 @@ typedef struct TransInfo { * mouse button then.) */ bool is_launch_event_tweak; + bool is_orient_set; + struct { short type; float matrix[3][3]; } orient[3]; - short orient_curr; + + enum { + O_DEFAULT = 0, + O_SCENE, + O_SET, + } orient_curr; /** backup from view3d, to restore on end. */ short gizmo_flag; diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 2037981e655..615467932a7 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -953,9 +953,8 @@ void startConstraint(TransInfo *t) void stopConstraint(TransInfo *t) { - if (t->orient_curr != 0) { - t->orient_curr = 0; - transform_orientations_current_set(t, t->orient_curr); + if (t->orient_curr != O_DEFAULT) { + transform_orientations_current_set(t, O_DEFAULT); } t->con.mode &= ~(CON_APPLY | CON_SELECT); @@ -971,8 +970,8 @@ void stopConstraint(TransInfo *t) void initSelectConstraint(TransInfo *t) { - if (t->orient_curr == 0) { - transform_orientations_current_set(t, 1); + if (t->orient_curr == O_DEFAULT) { + transform_orientations_current_set(t, O_SCENE); } setUserConstraint(t, CON_APPLY | CON_SELECT, "%s"); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 98db27c83f7..b4175faacf4 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -37,6 +37,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" +#include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -505,9 +506,27 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) bool clipx = true, clipy = true; float min[2], max[2]; - min[0] = min[1] = 0.0f; - max[0] = t->aspect[0]; - max[1] = t->aspect[1]; + /* Check if the current image in UV editor is a tiled image or not. */ + const SpaceImage *sima = t->area->spacedata.first; + const Image *image = sima->image; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + /* Stores the coordinates of the closest UDIM tile. + * Also acts as an offset to the tile from the origin of UV space. */ + float base_offset[2] = {0.0f, 0.0f}; + + /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */ + if (is_tiled_image) { + int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global); + if (nearest_tile_index != -1) { + nearest_tile_index -= 1001; + /* Getting coordinates of nearest tile from the tile index. */ + base_offset[0] = nearest_tile_index % 10; + base_offset[1] = nearest_tile_index / 10; + } + } + + min[0] = min[1] = FLT_MAX; + max[0] = max[1] = FLT_MIN; FOREACH_TRANS_DATA_CONTAINER (t, tc) { @@ -520,42 +539,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) } if (resize) { - if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) { - vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); + if (min[0] < base_offset[0] && t->center_global[0] > base_offset[0] && + t->center_global[0] < base_offset[0] + (t->aspect[0] * 0.5f)) { + vec[0] *= (t->center_global[0] - base_offset[0]) / (t->center_global[0] - min[0]); } - else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { - vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); + else if (max[0] > (base_offset[0] + t->aspect[0]) && + t->center_global[0] < (base_offset[0] + t->aspect[0])) { + vec[0] *= (t->center_global[0] - (base_offset[0] + t->aspect[0])) / + (t->center_global[0] - max[0]); } else { clipx = 0; } - if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) { - vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); + if (min[1] < base_offset[1] && t->center_global[1] > base_offset[1] && + t->center_global[1] < base_offset[1] + (t->aspect[1] * 0.5f)) { + vec[1] *= (t->center_global[1] - base_offset[1]) / (t->center_global[1] - min[1]); } - else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { - vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); + else if (max[1] > (base_offset[1] + t->aspect[1]) && + t->center_global[1] < (base_offset[1] + t->aspect[1])) { + vec[1] *= (t->center_global[1] - (base_offset[1] + t->aspect[1])) / + (t->center_global[1] - max[1]); } else { clipy = 0; } } else { - if (min[0] < 0.0f) { - vec[0] -= min[0]; + if (min[0] < base_offset[0]) { + vec[0] += base_offset[0] - min[0]; } - else if (max[0] > t->aspect[0]) { - vec[0] -= max[0] - t->aspect[0]; + else if (max[0] > base_offset[0] + t->aspect[0]) { + vec[0] -= max[0] - base_offset[0] - t->aspect[0]; } else { clipx = 0; } - if (min[1] < 0.0f) { - vec[1] -= min[1]; + if (min[1] < base_offset[1]) { + vec[1] += base_offset[1] - min[1]; } - else if (max[1] > t->aspect[1]) { - vec[1] -= max[1] - t->aspect[1]; + else if (max[1] > base_offset[1] + t->aspect[1]) { + vec[1] -= max[1] - base_offset[1] - t->aspect[1]; } else { clipy = 0; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 30418471d6d..34be89e5ed9 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -491,7 +491,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - SEQ_sort(t->scene); + SEQ_sort(seqbasep); } else { /* Canceled, need to update the strips display */ @@ -707,7 +707,7 @@ static void flushTransSeq(TransInfo *t) /* originally TFM_TIME_EXTEND, transform changes */ if (ELEM(t->mode, TFM_SEQ_SLIDE, TFM_TIME_TRANSLATE)) { - /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */ + /* Special annoying case here, need to calc meta-strips with TFM_TIME_EXTEND only */ /* calc all meta's then effects T27953. */ for (seq = seqbasep->first; seq; seq = seq->next) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index c9b6bef5904..71c91221fbb 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -414,8 +414,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve int orient_type_set = -1; int orient_type_matrix_set = -1; - bool use_orient_axis = false; - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; orient_type_scene = orient_slot->type; @@ -435,7 +433,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { t->orient_axis = RNA_property_enum_get(op->ptr, prop); - use_orient_axis = true; } if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { @@ -457,28 +454,23 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (orient_type_set != -1) { orient_type_default = orient_type_set; + t->is_orient_set = true; } else if (orient_type_matrix_set != -1) { orient_type_default = orient_type_set = orient_type_matrix_set; + t->is_orient_set = true; } else if (t->con.mode & CON_APPLY) { orient_type_default = orient_type_set = orient_type_scene; } else { + orient_type_default = orient_type_scene; if (orient_type_scene == V3D_ORIENT_GLOBAL) { orient_type_set = V3D_ORIENT_LOCAL; } else { orient_type_set = V3D_ORIENT_GLOBAL; } - - if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && - (t->mode != TFM_ALIGN)) { - orient_type_default = V3D_ORIENT_VIEW; - } - else { - orient_type_default = orient_type_scene; - } } BLI_assert(!ELEM(-1, orient_type_default, orient_type_set)); @@ -487,9 +479,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve orient_type_set = V3D_ORIENT_CUSTOM_MATRIX; } - orient_types[0] = (short)orient_type_default; - orient_types[1] = (short)orient_type_scene; - orient_types[2] = (short)orient_type_set; + orient_types[O_DEFAULT] = (short)orient_type_default; + orient_types[O_SCENE] = (short)orient_type_scene; + orient_types[O_SET] = (short)orient_type_set; for (int i = 0; i < 3; i++) { /* For efficiency, avoid calculating the same orientation twice. */ @@ -506,9 +498,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - /* Set orient_curr to -1 in order to force the update in - * `transform_orientations_current_set`. */ - t->orient_curr = -1; transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0); } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index 867a6cc4291..d61e7bb867c 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -45,6 +45,7 @@ #include "transform.h" #include "transform_convert.h" +#include "transform_orientations.h" #include "transform_snap.h" /* Own include. */ @@ -1271,4 +1272,38 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) * BLI_assert(t->mode == mode); */ } +/** + * When in modal and not set, initializes a default orientation for the mode. + */ +void transform_mode_default_modal_orientation_set(TransInfo *t, int type) +{ + /* Currently only these types are supported. */ + BLI_assert(ELEM(type, V3D_ORIENT_GLOBAL, V3D_ORIENT_VIEW)); + + if (t->is_orient_set) { + return; + } + + if (!(t->flag & T_MODAL)) { + return; + } + + if (t->orient[O_DEFAULT].type == type) { + return; + } + + RegionView3D *rv3d = NULL; + if ((type == V3D_ORIENT_VIEW) && (t->spacetype == SPACE_VIEW3D) && t->region && + (t->region->regiontype == RGN_TYPE_WINDOW)) { + rv3d = t->region->regiondata; + } + + t->orient[O_DEFAULT].type = ED_transform_calc_orientation_from_type_ex( + NULL, t->orient[O_DEFAULT].matrix, NULL, rv3d, NULL, NULL, type, 0); + + if (t->orient_curr == O_DEFAULT) { + /* Update Orientation. */ + transform_orientations_current_set(t, O_DEFAULT); + } +} /** \} */ diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6d7a0b528ae..106dc68c9ee 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -61,6 +61,7 @@ short getAnimEdit_SnapMode(TransInfo *t); void doAnimEdit_SnapFrame( TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap); void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); +void transform_mode_default_modal_orientation_set(TransInfo *t, int type); /* transform_mode_align.c */ void initAlign(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index c78115561b2..b7b3de69731 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -148,5 +148,7 @@ void initNormalRotation(TransInfo *t) storeCustomLNorValue(tc, bm); } + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c index fcdc57a98e2..0d7d0be3c0e 100644 --- a/source/blender/editors/transform/transform_mode_resize.c +++ b/source/blender/editors/transform/transform_mode_resize.c @@ -193,5 +193,7 @@ void initResize(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->num.unit_type[1] = B_UNIT_NONE; t->num.unit_type[2] = B_UNIT_NONE; + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 8d8594d5775..0fdbfb25989 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -249,5 +249,7 @@ void initRotation(TransInfo *t) if (t->flag & T_2D_EDIT) { t->flag |= T_NO_CONSTRAINT; } + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index a41c49710b9..23ee55bf6c5 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -232,5 +232,7 @@ void initShear(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */ t->flag |= T_NO_CONSTRAINT; + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_VIEW); } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 41fc6ee0aaf..0bef6364214 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -470,5 +470,7 @@ void initTranslation(TransInfo *t) t->num.unit_type[1] = B_UNIT_NONE; t->num.unit_type[2] = B_UNIT_NONE; } + + transform_mode_default_modal_orientation_set(t, V3D_ORIENT_GLOBAL); } /** \} */ diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 5a5f478fc2b..b3ed294845d 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -671,10 +671,6 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien void transform_orientations_current_set(TransInfo *t, const short orient_index) { - if (t->orient_curr == orient_index) { - return; - } - const short orientation = t->orient[orient_index].type; const char *spacename = transform_orientations_spacename_get(t, orientation); |