Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/armature/pose_slide.c
| Show First 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | typedef struct tPoseSlideOp { | ||||
| /** which transforms/channels are affected (ePoseSlide_Channels) */ | /** which transforms/channels are affected (ePoseSlide_Channels) */ | ||||
| short channels; | short channels; | ||||
| /** axis-limits for transforms (ePoseSlide_AxisLock) */ | /** axis-limits for transforms (ePoseSlide_AxisLock) */ | ||||
| short axislock; | short axislock; | ||||
| /* Allow overshoot or clamp between 0% and 100%. */ | /* Allow overshoot or clamp between 0% and 100%. */ | ||||
| bool overshoot; | bool overshoot; | ||||
| /* Reduces percentage delta from mouse movement. */ | /* Reduces factor delta from mouse movement. */ | ||||
| bool precision; | bool precision; | ||||
| /* Move percentage in 10% steps. */ | /* Move factor in 10% steps. */ | ||||
| bool increments; | bool increments; | ||||
| /* Draw callback handler. */ | /* Draw callback handler. */ | ||||
| void *draw_handle; | void *draw_handle; | ||||
| /* Accumulative, unclamped and unrounded percentage. */ | /* Accumulative, unclamped and unrounded factor. */ | ||||
| float raw_percentage; | float raw_factor; | ||||
| /* 0-1 value for determining the influence of whatever is relevant. */ | /* 0-1 value for determining the influence of whatever is relevant. */ | ||||
| float percentage; | float factor; | ||||
| /* Last cursor position in screen space used for mouse movement delta calculation. */ | /* Last cursor position in screen space used for mouse movement delta calculation. */ | ||||
| int last_cursor_x; | int last_cursor_x; | ||||
| /* Numeric input. */ | /* Numeric input. */ | ||||
| NumInput num; | NumInput num; | ||||
| struct tPoseSlideObject *ob_data_array; | struct tPoseSlideObject *ob_data_array; | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | static void draw_overshoot_triangle(const uint8_t color[4], | ||||
| 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(); | immEnd(); | ||||
| GPU_polygon_smooth(false); | GPU_polygon_smooth(false); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| static void draw_ticks(const float start_percentage, | static void draw_ticks(const float start_factor, | ||||
| const float end_percentage, | const float end_factor, | ||||
| const struct vec2f line_start, | const struct vec2f line_start, | ||||
| const float base_tick_height, | const float base_tick_height, | ||||
| const float line_width, | const float line_width, | ||||
| const uint8_t color_overshoot[4], | const uint8_t color_overshoot[4], | ||||
| const uint8_t color_line[4]) | const uint8_t color_line[4]) | ||||
| { | { | ||||
| /* Use percentage represented as 0-100 int to avoid floating point precision problems. */ | /* Use factor represented as 0-100 int to avoid floating point precision problems. */ | ||||
| const int tick_increment = 10; | const int tick_increment = 10; | ||||
| /* Round initial_tick_percentage up to the next tick_increment. */ | /* Round initial_tick_factor up to the next tick_increment. */ | ||||
| int tick_percentage = ceil((start_percentage * 100) / tick_increment) * tick_increment; | int tick_percentage = ceil((start_factor * 100) / tick_increment) * tick_increment; | ||||
| float tick_height = base_tick_height; | float tick_height = base_tick_height; | ||||
| while (tick_percentage <= (int)(end_percentage * 100)) { | while (tick_percentage <= (int)(end_factor * 100)) { | ||||
| /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit | /* Different ticks have different heights. Multiples of 100% are the tallest, 50% is a bit | ||||
| * smaller and the rest is the minimum size. */ | * smaller and the rest is the minimum size. */ | ||||
| if (tick_percentage % 100 == 0) { | if (tick_percentage % 100 == 0) { | ||||
| tick_height = base_tick_height; | tick_height = base_tick_height; | ||||
| } | } | ||||
| else if (tick_percentage % 50 == 0) { | else if (tick_percentage % 50 == 0) { | ||||
| tick_height = base_tick_height * 0.8; | tick_height = base_tick_height * 0.8; | ||||
| } | } | ||||
| else { | else { | ||||
| tick_height = base_tick_height * 0.5; | tick_height = base_tick_height * 0.5; | ||||
| } | } | ||||
| const float x = line_start.x + | const float x = line_start.x + | ||||
| (((float)tick_percentage / 100) - start_percentage) * SLIDE_PIXEL_DISTANCE; | (((float)tick_percentage / 100) - start_factor) * SLIDE_PIXEL_DISTANCE; | ||||
| const struct rctf tick_rect = {.xmin = x - (line_width / 2), | const struct rctf tick_rect = {.xmin = x - (line_width / 2), | ||||
| .xmax = x + (line_width / 2), | .xmax = x + (line_width / 2), | ||||
| .ymin = line_start.y - (tick_height / 2), | .ymin = line_start.y - (tick_height / 2), | ||||
| .ymax = line_start.y + (tick_height / 2)}; | .ymax = line_start.y + (tick_height / 2)}; | ||||
| if (tick_percentage < 0 || tick_percentage > 100) { | if (tick_percentage < 0 || tick_percentage > 100) { | ||||
| UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255); | UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_overshoot, 255); | ||||
| } | } | ||||
| else { | else { | ||||
| UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); | UI_draw_roundbox_3ub_alpha(&tick_rect, true, 1, color_line, 255); | ||||
| } | } | ||||
| tick_percentage += tick_increment; | tick_percentage += tick_increment; | ||||
| } | } | ||||
| } | } | ||||
| static void draw_main_line(const struct rctf main_line_rect, | static void draw_main_line(const struct rctf main_line_rect, | ||||
| const float percentage, | const float factor, | ||||
| const bool overshoot, | const bool overshoot, | ||||
| const uint8_t color_overshoot[4], | const uint8_t color_overshoot[4], | ||||
| const uint8_t color_line[4]) | const uint8_t color_line[4]) | ||||
| { | { | ||||
| if (overshoot) { | if (overshoot) { | ||||
| /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */ | /* In overshoot mode, draw the 0-100% range differently to provide a visual reference. */ | ||||
| const float line_zero_percent = main_line_rect.xmin - | const float line_zero_percent = main_line_rect.xmin - | ||||
| ((percentage - 0.5f - OVERSHOOT_RANGE_DELTA) * | ((factor - 0.5f - OVERSHOOT_RANGE_DELTA) * | ||||
| SLIDE_PIXEL_DISTANCE); | SLIDE_PIXEL_DISTANCE); | ||||
| const float clamped_line_zero_percent = clamp_f( | const float clamped_line_zero_percent = clamp_f( | ||||
| line_zero_percent, main_line_rect.xmin, main_line_rect.xmax); | line_zero_percent, main_line_rect.xmin, main_line_rect.xmax); | ||||
| const float clamped_line_hundred_percent = clamp_f( | const float clamped_line_hundred_percent = clamp_f( | ||||
| line_zero_percent + SLIDE_PIXEL_DISTANCE, main_line_rect.xmin, main_line_rect.xmax); | 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, | const struct rctf left_overshoot_line_rect = {.xmin = main_line_rect.xmin, | ||||
| Show All 20 Lines | |||||
| static void draw_backdrop(const int fontid, | static void draw_backdrop(const int fontid, | ||||
| const struct rctf main_line_rect, | const struct rctf main_line_rect, | ||||
| const float color_bg[4], | const float color_bg[4], | ||||
| const short region_y_size, | const short region_y_size, | ||||
| const float base_tick_height) | const float base_tick_height) | ||||
| { | { | ||||
| float string_pixel_size[2]; | float string_pixel_size[2]; | ||||
| const char *percentage_placeholder = "000%%"; | const char *percentage_string_placeholder = "000%%"; | ||||
| BLF_width_and_height(fontid, | BLF_width_and_height(fontid, | ||||
| percentage_placeholder, | percentage_string_placeholder, | ||||
| sizeof(percentage_placeholder), | sizeof(percentage_string_placeholder), | ||||
| &string_pixel_size[0], | &string_pixel_size[0], | ||||
| &string_pixel_size[1]); | &string_pixel_size[1]); | ||||
| const struct vec2f pad = {.x = (region_y_size - base_tick_height) / 2, .y = 2.0f * U.pixelsize}; | 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, | const struct rctf backdrop_rect = {.xmin = main_line_rect.xmin - string_pixel_size[0] - pad.x, | ||||
| .xmax = main_line_rect.xmax + pad.x, | .xmax = main_line_rect.xmax + pad.x, | ||||
| .ymin = pad.y, | .ymin = pad.y, | ||||
| .ymax = region_y_size - pad.y}; | .ymax = region_y_size - pad.y}; | ||||
| UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg); | UI_draw_roundbox_aa(&backdrop_rect, true, 4.0f, color_bg); | ||||
| Show All 37 Lines | static void pose_slide_draw_2d_slider(const struct bContext *UNUSED(C), ARegion *region, void *arg) | ||||
| const float line_width = 1.5 * U.pixelsize; | const float line_width = 1.5 * U.pixelsize; | ||||
| const float base_tick_height = 12.0 * U.pixelsize; | const float base_tick_height = 12.0 * U.pixelsize; | ||||
| const float line_y = region->winy / 2; | const float line_y = region->winy / 2; | ||||
| struct rctf main_line_rect = {.xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2), | struct rctf main_line_rect = {.xmin = (region->winx / 2) - (SLIDE_PIXEL_DISTANCE / 2), | ||||
| .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2), | .xmax = (region->winx / 2) + (SLIDE_PIXEL_DISTANCE / 2), | ||||
| .ymin = line_y - line_width / 2, | .ymin = line_y - line_width / 2, | ||||
| .ymax = line_y + line_width / 2}; | .ymax = line_y + line_width / 2}; | ||||
| float line_start_percentage = 0; | float line_start_factor = 0; | ||||
| int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->percentage; | int handle_pos_x = main_line_rect.xmin + SLIDE_PIXEL_DISTANCE * pso->factor; | ||||
| if (pso->overshoot) { | if (pso->overshoot) { | ||||
| main_line_rect.xmin = main_line_rect.xmin - SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; | 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; | main_line_rect.xmax = main_line_rect.xmax + SLIDE_PIXEL_DISTANCE * OVERSHOOT_RANGE_DELTA; | ||||
| line_start_percentage = pso->percentage - 0.5f - OVERSHOOT_RANGE_DELTA; | line_start_factor = pso->factor - 0.5f - OVERSHOOT_RANGE_DELTA; | ||||
| handle_pos_x = region->winx / 2; | handle_pos_x = region->winx / 2; | ||||
| } | } | ||||
| draw_backdrop(fontid, main_line_rect, color_bg, pso->region->winy, base_tick_height); | 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); | draw_main_line(main_line_rect, pso->factor, pso->overshoot, color_overshoot, color_line); | ||||
| const float percentage_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1; | const float factor_range = pso->overshoot ? 1 + OVERSHOOT_RANGE_DELTA * 2 : 1; | ||||
| const struct vec2f line_start_position = {.x = main_line_rect.xmin, .y = line_y}; | const struct vec2f line_start_position = {.x = main_line_rect.xmin, .y = line_y}; | ||||
| draw_ticks(line_start_percentage, | draw_ticks(line_start_factor, | ||||
| line_start_percentage + percentage_range, | line_start_factor + factor_range, | ||||
| line_start_position, | line_start_position, | ||||
| base_tick_height, | base_tick_height, | ||||
| line_width, | line_width, | ||||
| color_overshoot, | color_overshoot, | ||||
| color_line); | color_line); | ||||
| /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100% | /* Draw triangles at the ends of the line in overshoot mode to indicate direction of 0-100% | ||||
| * range.*/ | * range.*/ | ||||
| if (pso->overshoot) { | if (pso->overshoot) { | ||||
| if (pso->percentage > 1 + OVERSHOOT_RANGE_DELTA + 0.5) { | if (pso->factor > 1 + OVERSHOOT_RANGE_DELTA + 0.5) { | ||||
| draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y); | draw_overshoot_triangle(color_line, false, main_line_rect.xmin, line_y); | ||||
| } | } | ||||
| if (pso->percentage < 0 - OVERSHOOT_RANGE_DELTA - 0.5) { | if (pso->factor < 0 - OVERSHOOT_RANGE_DELTA - 0.5) { | ||||
| draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y); | draw_overshoot_triangle(color_line, true, main_line_rect.xmax, line_y); | ||||
| } | } | ||||
| } | } | ||||
| char percentage_string[256]; | char percentage_string[256]; | ||||
| /* Draw handle indicating current percentage. */ | /* Draw handle indicating current factor. */ | ||||
| const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width), | const struct rctf handle_rect = {.xmin = handle_pos_x - (line_width), | ||||
| .xmax = handle_pos_x + (line_width), | .xmax = handle_pos_x + (line_width), | ||||
| .ymin = line_y - (base_tick_height / 2), | .ymin = line_y - (base_tick_height / 2), | ||||
| .ymax = 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); | UI_draw_roundbox_3ub_alpha(&handle_rect, true, 1, color_handle, 255); | ||||
| BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->percentage * 100); | BLI_snprintf(percentage_string, sizeof(percentage_string), "%.0f%%", pso->factor * 100); | ||||
| /* Draw percentage string. */ | /* Draw percentage string. */ | ||||
| float percentage_pixel_size[2]; | float percentage_string_pixel_size[2]; | ||||
| BLF_width_and_height(fontid, | BLF_width_and_height(fontid, | ||||
| percentage_string, | percentage_string, | ||||
| sizeof(percentage_string), | sizeof(percentage_string), | ||||
| &percentage_pixel_size[0], | &percentage_string_pixel_size[0], | ||||
| &percentage_pixel_size[1]); | &percentage_string_pixel_size[1]); | ||||
| BLF_position(fontid, | BLF_position(fontid, | ||||
| main_line_rect.xmin - 24.0 * U.pixelsize - percentage_pixel_size[0] / 2, | main_line_rect.xmin - 24.0 * U.pixelsize - percentage_string_pixel_size[0] / 2, | ||||
| (region->winy / 2) - percentage_pixel_size[1] / 2, | (region->winy / 2) - percentage_string_pixel_size[1] / 2, | ||||
| 0.0f); | 0.0f); | ||||
| BLF_draw(fontid, percentage_string, sizeof(percentage_string)); | BLF_draw(fontid, percentage_string, sizeof(percentage_string)); | ||||
| } | } | ||||
| /* operator init */ | /* operator init */ | ||||
| static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) | static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode) | ||||
| { | { | ||||
| tPoseSlideOp *pso; | tPoseSlideOp *pso; | ||||
| /* init slide-op data */ | /* init slide-op data */ | ||||
| pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp"); | pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp"); | ||||
| /* get info from context */ | /* get info from context */ | ||||
| pso->scene = CTX_data_scene(C); | pso->scene = CTX_data_scene(C); | ||||
| pso->area = CTX_wm_area(C); /* only really needed when doing modal() */ | pso->area = CTX_wm_area(C); /* only really needed when doing modal() */ | ||||
| pso->region = CTX_wm_region(C); /* only really needed when doing modal() */ | pso->region = CTX_wm_region(C); /* only really needed when doing modal() */ | ||||
| pso->cframe = pso->scene->r.cfra; | pso->cframe = pso->scene->r.cfra; | ||||
| pso->mode = mode; | pso->mode = mode; | ||||
| /* set range info from property values - these may get overridden for the invoke() */ | /* set range info from property values - these may get overridden for the invoke() */ | ||||
| pso->percentage = RNA_float_get(op->ptr, "percentage"); | pso->factor = RNA_float_get(op->ptr, "factor"); | ||||
| pso->raw_percentage = pso->percentage; | pso->raw_factor = pso->factor; | ||||
| pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); | pso->prevFrame = RNA_int_get(op->ptr, "prev_frame"); | ||||
| pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); | pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); | ||||
| /* get the set of properties/axes that can be operated on */ | /* get the set of properties/axes that can be operated on */ | ||||
| pso->channels = RNA_enum_get(op->ptr, "channels"); | pso->channels = RNA_enum_get(op->ptr, "channels"); | ||||
| pso->axislock = RNA_enum_get(op->ptr, "axis_lock"); | pso->axislock = RNA_enum_get(op->ptr, "axis_lock"); | ||||
| /* for each Pose-Channel which gets affected, get the F-Curves for that channel | /* for each Pose-Channel which gets affected, get the F-Curves for that channel | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val) | ||||
| /* get keyframe values for endpoint poses to blend with */ | /* get keyframe values for endpoint poses to blend with */ | ||||
| /* previous/start */ | /* previous/start */ | ||||
| sVal = evaluate_fcurve(fcu, prevFrameF); | sVal = evaluate_fcurve(fcu, prevFrameF); | ||||
| /* next/end */ | /* next/end */ | ||||
| eVal = evaluate_fcurve(fcu, nextFrameF); | eVal = evaluate_fcurve(fcu, nextFrameF); | ||||
| /* calculate the relative weights of the endpoints */ | /* calculate the relative weights of the endpoints */ | ||||
| if (pso->mode == POSESLIDE_BREAKDOWN) { | if (pso->mode == POSESLIDE_BREAKDOWN) { | ||||
| /* get weights from the percentage control */ | /* get weights from the factor control */ | ||||
| w1 = pso->percentage; /* this must come second */ | w1 = pso->factor; /* this must come second */ | ||||
| w2 = 1.0f - w1; /* this must come first */ | w2 = 1.0f - w1; /* this must come first */ | ||||
| } | } | ||||
| else { | else { | ||||
| /* - these weights are derived from the relative distance of these | /* - these weights are derived from the relative distance of these | ||||
| * poses from the current frame | * poses from the current frame | ||||
| * - they then get normalized so that they only sum up to 1 | * - they then get normalized so that they only sum up to 1 | ||||
| */ | */ | ||||
| float wtot; | float wtot; | ||||
| Show All 9 Lines | static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, float *val) | ||||
| * - In all of these, the start+end values are multiplied by w2 and w1 (respectively), | * - In all of these, the start+end values are multiplied by w2 and w1 (respectively), | ||||
| * since multiplication in another order would decrease | * since multiplication in another order would decrease | ||||
| * the value the current frame is closer to. | * the value the current frame is closer to. | ||||
| */ | */ | ||||
| switch (pso->mode) { | switch (pso->mode) { | ||||
| case POSESLIDE_PUSH: /* make the current pose more pronounced */ | case POSESLIDE_PUSH: /* make the current pose more pronounced */ | ||||
| { | { | ||||
| /* Slide the pose away from the breakdown pose in the timeline */ | /* Slide the pose away from the breakdown pose in the timeline */ | ||||
| (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; | (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor; | ||||
| break; | break; | ||||
| } | } | ||||
| case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ | case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */ | ||||
| { | { | ||||
| /* Slide the pose towards the breakdown pose in the timeline */ | /* Slide the pose towards the breakdown pose in the timeline */ | ||||
| (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage; | (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->factor; | ||||
| break; | break; | ||||
| } | } | ||||
| case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ | case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */ | ||||
| { | { | ||||
| /* Perform simple linear interpolation - | /* Perform simple linear interpolation - | ||||
| * coefficient for start must come from pso->percentage. */ | * coefficient for start must come from pso->factor. */ | ||||
| /* TODO: make this use some kind of spline interpolation instead? */ | /* TODO: make this use some kind of spline interpolation instead? */ | ||||
| (*val) = ((sVal * w2) + (eVal * w1)); | (*val) = ((sVal * w2) + (eVal * w1)); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* helper for apply() - perform sliding for some 3-element vector */ | /* helper for apply() - perform sliding for some 3-element vector */ | ||||
| ▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) | ||||
| /* only if all channels exist, proceed */ | /* only if all channels exist, proceed */ | ||||
| if (fcu_w && fcu_x && fcu_y && fcu_z) { | if (fcu_w && fcu_x && fcu_y && fcu_z) { | ||||
| float quat_final[4]; | float quat_final[4]; | ||||
| /* perform blending */ | /* perform blending */ | ||||
| if (pso->mode == POSESLIDE_BREAKDOWN) { | if (pso->mode == POSESLIDE_BREAKDOWN) { | ||||
| /* Just perform the interpolation between quat_prev and | /* Just perform the interpolation between quat_prev and | ||||
| * quat_next using pso->percentage as a guide. */ | * quat_next using pso->factor as a guide. */ | ||||
| float quat_prev[4]; | float quat_prev[4]; | ||||
| float quat_next[4]; | float quat_next[4]; | ||||
| quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF); | quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF); | ||||
| quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF); | quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF); | ||||
| quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF); | quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF); | ||||
| quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF); | quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF); | ||||
| quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF); | quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF); | ||||
| quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF); | quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF); | ||||
| quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF); | quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF); | ||||
| quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF); | quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF); | ||||
| normalize_qt(quat_prev); | normalize_qt(quat_prev); | ||||
| normalize_qt(quat_next); | normalize_qt(quat_next); | ||||
| interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage); | interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->factor); | ||||
| } | } | ||||
| else { | else { | ||||
| /* POSESLIDE_PUSH and POSESLIDE_RELAX. */ | /* POSESLIDE_PUSH and POSESLIDE_RELAX. */ | ||||
| float quat_breakdown[4]; | float quat_breakdown[4]; | ||||
| float quat_curr[4]; | float quat_curr[4]; | ||||
| copy_qt_qt(quat_curr, pchan->quat); | copy_qt_qt(quat_curr, pchan->quat); | ||||
| quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe); | quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe); | ||||
| quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe); | quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe); | ||||
| quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe); | quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe); | ||||
| quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe); | quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe); | ||||
| normalize_qt(quat_breakdown); | normalize_qt(quat_breakdown); | ||||
| normalize_qt(quat_curr); | normalize_qt(quat_curr); | ||||
| if (pso->mode == POSESLIDE_PUSH) { | if (pso->mode == POSESLIDE_PUSH) { | ||||
| interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage); | interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->factor); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(pso->mode == POSESLIDE_RELAX); | BLI_assert(pso->mode == POSESLIDE_RELAX); | ||||
| interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage); | interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->factor); | ||||
| } | } | ||||
| } | } | ||||
| /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */ | /* Apply final to the pose bone, keeping compatible for similar keyframe positions. */ | ||||
| quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat); | quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat); | ||||
| } | } | ||||
| /* free the path now */ | /* free the path now */ | ||||
| MEM_freeN(path); | MEM_freeN(path); | ||||
| } | } | ||||
| static void pose_slide_rest_pose_apply_vec3(tPoseSlideOp *pso, float vec[3], float default_value) | 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; | const int lock = pso->axislock; | ||||
| for (int idx = 0; idx < 3; idx++) { | for (int idx = 0; idx < 3; idx++) { | ||||
| if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || | if ((lock == 0) || ((lock & PS_LOCK_X) && (idx == 0)) || ((lock & PS_LOCK_Y) && (idx == 1)) || | ||||
| ((lock & PS_LOCK_Z) && (idx == 2))) { | ((lock & PS_LOCK_Z) && (idx == 2))) { | ||||
| float diff_val = default_value - vec[idx]; | float diff_val = default_value - vec[idx]; | ||||
| if (pso->mode == POSESLIDE_RELAX_REST) { | if (pso->mode == POSESLIDE_RELAX_REST) { | ||||
| vec[idx] += pso->percentage * diff_val; | vec[idx] += pso->factor * diff_val; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Push */ | /* Push */ | ||||
| vec[idx] -= pso->percentage * diff_val; | vec[idx] -= pso->factor * diff_val; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void pose_slide_rest_pose_apply_other_rot(tPoseSlideOp *pso, float vec[4], bool quat) | 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}; | float default_values[] = {1.0f, 0.0f, 0.0f, 0.0f}; | ||||
| if (!quat) { | if (!quat) { | ||||
| /* Axis Angle */ | /* Axis Angle */ | ||||
| default_values[0] = 0.0f; | default_values[0] = 0.0f; | ||||
| default_values[2] = 1.0f; | default_values[2] = 1.0f; | ||||
| } | } | ||||
| for (int idx = 0; idx < 4; idx++) { | for (int idx = 0; idx < 4; idx++) { | ||||
| float diff_val = default_values[idx] - vec[idx]; | float diff_val = default_values[idx] - vec[idx]; | ||||
| if (pso->mode == POSESLIDE_RELAX_REST) { | if (pso->mode == POSESLIDE_RELAX_REST) { | ||||
| vec[idx] += pso->percentage * diff_val; | vec[idx] += pso->factor * diff_val; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Push */ | /* Push */ | ||||
| vec[idx] -= pso->percentage * diff_val; | vec[idx] -= pso->factor * diff_val; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* apply() - perform the pose sliding between the current pose and the rest pose */ | /* apply() - perform the pose sliding between the current pose and the rest pose */ | ||||
| static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso) | static void pose_slide_rest_pose_apply(bContext *C, tPoseSlideOp *pso) | ||||
| { | { | ||||
| tPChanFCurveLink *pfl; | tPChanFCurveLink *pfl; | ||||
| ▲ Show 20 Lines • Show All 338 Lines • ▼ Show 20 Lines | static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso) | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between"); | BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between"); | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* initial apply for operator... */ | /* initial apply for operator... */ | ||||
| /* TODO: need to calculate percentage for initial round too... */ | /* TODO: need to calculate factor for initial round too... */ | ||||
| if (!ELEM(pso->mode, POSESLIDE_PUSH_REST, POSESLIDE_RELAX_REST)) { | if (!ELEM(pso->mode, POSESLIDE_PUSH_REST, POSESLIDE_RELAX_REST)) { | ||||
| pose_slide_apply(C, pso); | pose_slide_apply(C, pso); | ||||
| } | } | ||||
| else { | else { | ||||
| pose_slide_rest_pose_apply(C, pso); | pose_slide_rest_pose_apply(C, pso); | ||||
| } | } | ||||
| /* depsgraph updates + redraws */ | /* depsgraph updates + redraws */ | ||||
| Show All 11 Lines | static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso) | ||||
| /* Hide Bone Overlay. */ | /* Hide Bone Overlay. */ | ||||
| View3D *v3d = pso->area->spacedata.first; | View3D *v3d = pso->area->spacedata.first; | ||||
| pso->overlay_flag = v3d->overlay.flag; | pso->overlay_flag = v3d->overlay.flag; | ||||
| v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES; | v3d->overlay.flag |= V3D_OVERLAY_HIDE_BONES; | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| /* Calculate percentage based on mouse movement, clamp or round to increments if | /* Calculate factor based on mouse movement, clamp or round to increments if | ||||
| * enabled by the user. Store the new percentage value. | * enabled by the user. Store the new factor value. | ||||
| */ | */ | ||||
| static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, | static void pose_slide_mouse_update_factor(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event) | ||||
| wmOperator *op, | { | ||||
| const wmEvent *event) | const float factor_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE)); | ||||
| { | /* Reduced factor delta in precision mode (shift held). */ | ||||
| const float percentage_delta = (event->x - pso->last_cursor_x) / ((float)(SLIDE_PIXEL_DISTANCE)); | pso->raw_factor += pso->precision ? (factor_delta / 8) : factor_delta; | ||||
| /* Reduced percentage delta in precision mode (shift held). */ | pso->factor = pso->raw_factor; | ||||
| pso->raw_percentage += pso->precision ? (percentage_delta / 8) : percentage_delta; | |||||
| pso->percentage = pso->raw_percentage; | |||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| if (!pso->overshoot) { | if (!pso->overshoot) { | ||||
| pso->percentage = clamp_f(pso->percentage, 0, 1); | pso->factor = clamp_f(pso->factor, 0, 1); | ||||
| } | } | ||||
| if (pso->increments) { | if (pso->increments) { | ||||
| pso->percentage = round(pso->percentage * 10) / 10; | pso->factor = round(pso->factor * 10) / 10; | ||||
| } | } | ||||
| RNA_float_set(op->ptr, "percentage", pso->percentage); | RNA_float_set(op->ptr, "factor", pso->factor); | ||||
| } | } | ||||
| /* handle an event to toggle channels mode */ | /* handle an event to toggle channels mode */ | ||||
| static void pose_slide_toggle_channels_mode(wmOperator *op, | static void pose_slide_toggle_channels_mode(wmOperator *op, | ||||
| tPoseSlideOp *pso, | tPoseSlideOp *pso, | ||||
| ePoseSlide_Channels channel) | ePoseSlide_Channels channel) | ||||
| { | { | ||||
| /* Turn channel on or off? */ | /* Turn channel on or off? */ | ||||
| ▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | case RIGHTMOUSE: { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| /* canceled! */ | /* canceled! */ | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| /* Percentage Change... */ | /* Factor Change... */ | ||||
| case MOUSEMOVE: /* calculate new position */ | case MOUSEMOVE: /* calculate new position */ | ||||
| { | { | ||||
| /* only handle mousemove if not doing numinput */ | /* only handle mousemove if not doing numinput */ | ||||
| if (has_numinput == false) { | if (has_numinput == false) { | ||||
| /* update percentage based on position of mouse */ | /* update factor based on position of mouse */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* update pose to reflect the new values (see below) */ | /* update pose to reflect the new values (see below) */ | ||||
| do_pose_update = true; | do_pose_update = true; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| default: { | default: { | ||||
| if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) { | if ((event->val == KM_PRESS) && handleNumInput(C, &pso->num, event)) { | ||||
| float value; | float value; | ||||
| /* Grab percentage from numeric input, and store this new value for redo | /* Grab percentage from numeric input, and store this new value for redo | ||||
| * NOTE: users see ints, while internally we use a 0-1 float | * NOTE: users see ints, while internally we use a 0-1 float | ||||
| */ | */ | ||||
| value = pso->percentage * 100.0f; | value = pso->factor * 100.0f; | ||||
| applyNumInput(&pso->num, &value); | applyNumInput(&pso->num, &value); | ||||
| pso->percentage = value / 100.0f; | pso->factor = value / 100.0f; | ||||
| CLAMP(pso->percentage, 0.0f, 1.0f); | CLAMP(pso->factor, 0.0f, 1.0f); | ||||
| RNA_float_set(op->ptr, "percentage", pso->percentage); | RNA_float_set(op->ptr, "factor", pso->factor); | ||||
| /* Update pose to reflect the new values (see below) */ | /* Update pose to reflect the new values (see below) */ | ||||
| do_pose_update = true; | do_pose_update = true; | ||||
| break; | break; | ||||
| } | } | ||||
| if (event->val == KM_PRESS) { | if (event->val == KM_PRESS) { | ||||
| switch (event->type) { | switch (event->type) { | ||||
| /* Transform Channel Limits */ | /* Transform Channel Limits */ | ||||
| ▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * Common code for defining RNA properties. | * Common code for defining RNA properties. | ||||
| */ | */ | ||||
| static void pose_slide_opdef_properties(wmOperatorType *ot) | static void pose_slide_opdef_properties(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| prop = RNA_def_float_factor(ot->srna, | prop = RNA_def_float_factor(ot->srna, | ||||
| "percentage", | "factor", | ||||
| 0.5f, | 0.5f, | ||||
| 0.0f, | 0.0f, | ||||
| 1.0f, | 1.0f, | ||||
| "Percentage", | "Factor", | ||||
| "Weighting factor for which keyframe is favored more", | "Weighting factor for which keyframe is favored more", | ||||
| 0.0, | 0.0, | ||||
| 1.0); | 1.0); | ||||
| RNA_def_property_flag(prop, PROP_SKIP_SAVE); | RNA_def_property_flag(prop, PROP_SKIP_SAVE); | ||||
| prop = RNA_def_int(ot->srna, | prop = RNA_def_int(ot->srna, | ||||
| "prev_frame", | "prev_frame", | ||||
| 0, | 0, | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (pose_slide_init(C, op, POSESLIDE_PUSH) == 0) { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| pso = op->customdata; | pso = op->customdata; | ||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| /* Initialize percentage so that it won't pop on first mouse move. */ | /* Initialize factor so that it won't pop on first mouse move. */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* do common setup work */ | /* do common setup work */ | ||||
| return pose_slide_invoke_common(C, op, pso); | return pose_slide_invoke_common(C, op, pso); | ||||
| } | } | ||||
| /* exec() - for push */ | /* exec() - for push */ | ||||
| static int pose_slide_push_exec(bContext *C, wmOperator *op) | static int pose_slide_push_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (pose_slide_init(C, op, POSESLIDE_RELAX) == 0) { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| pso = op->customdata; | pso = op->customdata; | ||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| /* Initialize percentage so that it won't pop on first mouse move. */ | /* Initialize factor so that it won't pop on first mouse move. */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* do common setup work */ | /* do common setup work */ | ||||
| return pose_slide_invoke_common(C, op, pso); | return pose_slide_invoke_common(C, op, pso); | ||||
| } | } | ||||
| /* exec() - for relax */ | /* exec() - for relax */ | ||||
| static int pose_slide_relax_exec(bContext *C, wmOperator *op) | static int pose_slide_relax_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (pose_slide_init(C, op, POSESLIDE_PUSH_REST) == 0) { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| pso = op->customdata; | pso = op->customdata; | ||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| /* Initialize percentage so that it won't pop on first mouse move. */ | /* Initialize factor so that it won't pop on first mouse move. */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* do common setup work */ | /* do common setup work */ | ||||
| return pose_slide_invoke_common(C, op, pso); | return pose_slide_invoke_common(C, op, pso); | ||||
| } | } | ||||
| /* exec() - for push */ | /* exec() - for push */ | ||||
| static int pose_slide_push_rest_exec(bContext *C, wmOperator *op) | static int pose_slide_push_rest_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (pose_slide_init(C, op, POSESLIDE_RELAX_REST) == 0) { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| pso = op->customdata; | pso = op->customdata; | ||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| /* Initialize percentage so that it won't pop on first mouse move. */ | /* Initialize factor so that it won't pop on first mouse move. */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* do common setup work */ | /* do common setup work */ | ||||
| return pose_slide_invoke_common(C, op, pso); | return pose_slide_invoke_common(C, op, pso); | ||||
| } | } | ||||
| /* exec() - for relax */ | /* exec() - for relax */ | ||||
| static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op) | static int pose_slide_relax_rest_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (pose_slide_init(C, op, POSESLIDE_BREAKDOWN) == 0) { | ||||
| pose_slide_exit(op); | pose_slide_exit(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| pso = op->customdata; | pso = op->customdata; | ||||
| pso->last_cursor_x = event->x; | pso->last_cursor_x = event->x; | ||||
| /* Initialize percentage so that it won't pop on first mouse move. */ | /* Initialize factor so that it won't pop on first mouse move. */ | ||||
| pose_slide_mouse_update_percentage(pso, op, event); | pose_slide_mouse_update_factor(pso, op, event); | ||||
| /* do common setup work */ | /* do common setup work */ | ||||
| return pose_slide_invoke_common(C, op, pso); | return pose_slide_invoke_common(C, op, pso); | ||||
| } | } | ||||
| /* exec() - for breakdown */ | /* exec() - for breakdown */ | ||||
| static int pose_slide_breakdown_exec(bContext *C, wmOperator *op) | static int pose_slide_breakdown_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 456 Lines • Show Last 20 Lines | |||||