WIP: Onion Skinning Prototype #107641
|
@ -1056,6 +1056,7 @@ def km_time_scrub(_params):
|
|||
|
||||
items.extend([
|
||||
("anim.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
||||
("anim.change_onion_skin_range", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -395,6 +395,153 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* Set the new frame number */
|
||||
static void change_onion_skin_range_apply(bContext *C, wmOperator *op, const bool always_update)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const int left = RNA_int_get(op->ptr, "left");
|
||||
const int right = RNA_int_get(op->ptr, "right");
|
||||
|
||||
scene->onion_skin_cache.relative_left = left;
|
||||
scene->onion_skin_cache.relative_right = right;
|
||||
|
||||
/* do updates */
|
||||
if (always_update) {
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static void change_onion_skin_range_cancel(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
screen->scrubbing = false;
|
||||
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if (sseq != NULL) {
|
||||
change_frame_seq_preview_end(sseq);
|
||||
}
|
||||
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal event handling of frame changing */
|
||||
static int change_onion_skin_range_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
/* execute the events */
|
||||
switch (event->type) {
|
||||
case EVT_ESCKEY:
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
|
||||
case MOUSEMOVE:
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const int clicked_frame = roundf(frame_from_event(C, event));
|
||||
const int current_scene_frame = BKE_scene_ctime_get(scene);
|
||||
if (clicked_frame > current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "right", clicked_frame);
|
||||
}
|
||||
else if (clicked_frame < current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "left", clicked_frame);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
change_onion_skin_range_apply(C, op, false);
|
||||
break;
|
||||
|
||||
case LEFTMOUSE:
|
||||
case RIGHTMOUSE:
|
||||
case MIDDLEMOUSE:
|
||||
/* We check for either mouse-button to end, to work with all user keymaps. */
|
||||
if (event->val == KM_RELEASE) {
|
||||
ret = OPERATOR_FINISHED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != OPERATOR_RUNNING_MODAL) {
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
screen->scrubbing = false;
|
||||
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if (sseq != NULL) {
|
||||
change_frame_seq_preview_end(sseq);
|
||||
}
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Modal Operator init */
|
||||
static int change_onion_skin_range_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
if (CTX_wm_space_seq(C) != NULL && region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RNA_int_set(op->ptr, "right", scene->onion_skin_cache.relative_right);
|
||||
RNA_int_set(op->ptr, "left", scene->onion_skin_cache.relative_left);
|
||||
|
||||
const int clicked_frame = roundf(frame_from_event(C, event));
|
||||
const int current_scene_frame = BKE_scene_ctime_get(scene);
|
||||
if (clicked_frame > current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "right", clicked_frame);
|
||||
}
|
||||
else if (clicked_frame < current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "left", clicked_frame);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
screen->scrubbing = true;
|
||||
|
||||
change_onion_skin_range_apply(C, op, true);
|
||||
|
||||
/* add temp handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int change_onion_skin_range_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
change_onion_skin_range_apply(C, op, true);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ANIM_OT_change_onion_skin_range(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Change Onion Skin Range";
|
||||
ot->idname = "ANIM_OT_change_onion_skin_range";
|
||||
ot->description = "Interactively change the amount of onion skins shown";
|
||||
|
||||
ot->exec = change_onion_skin_range_exec;
|
||||
ot->poll = change_frame_poll;
|
||||
ot->invoke = change_onion_skin_range_invoke;
|
||||
ot->modal = change_onion_skin_range_modal;
|
||||
ot->cancel = change_onion_skin_range_cancel;
|
||||
|
||||
/* rna */
|
||||
ot->prop = RNA_def_int(
|
||||
ot->srna, "left", 0, MINAFRAME, MAXFRAME, "Left", "", MINAFRAME, MAXFRAME);
|
||||
ot->prop = RNA_def_int(
|
||||
ot->srna, "right", 0, MINAFRAME, MAXFRAME, "Right", "", MINAFRAME, MAXFRAME);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Start/End Frame Operators
|
||||
* \{ */
|
||||
|
@ -652,6 +799,7 @@ void ED_operatortypes_anim(void)
|
|||
{
|
||||
/* Animation Editors only -------------------------- */
|
||||
WM_operatortype_append(ANIM_OT_change_frame);
|
||||
WM_operatortype_append(ANIM_OT_change_onion_skin_range);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_start_frame_set);
|
||||
WM_operatortype_append(ANIM_OT_end_frame_set);
|
||||
|
|
|
@ -136,6 +136,41 @@ static void draw_current_frame(const Scene *scene,
|
|||
U.pixelsize,
|
||||
4 * UI_SCALE_FAC);
|
||||
|
||||
if (scene->onion_skin_cache.relative_left != 0) {
|
||||
const int frame_relative_left = UI_view2d_view_to_region_x(
|
||||
v2d, current_frame - scene->onion_skin_cache.relative_left);
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_relative_left - box_width / 4 + U.pixelsize / 2,
|
||||
.xmax = frame_relative_left + box_width / 4 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
bg_color,
|
||||
NULL,
|
||||
1.0f,
|
||||
outline_color,
|
||||
U.pixelsize,
|
||||
4 * UI_SCALE_FAC);
|
||||
}
|
||||
if (scene->onion_skin_cache.relative_right != 0) {
|
||||
const int frame_relative_right = UI_view2d_view_to_region_x(
|
||||
v2d, current_frame - scene->onion_skin_cache.relative_right);
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_relative_right - box_width / 4 + U.pixelsize / 2,
|
||||
.xmax = frame_relative_right + box_width / 4 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
bg_color,
|
||||
NULL,
|
||||
1.0f,
|
||||
outline_color,
|
||||
U.pixelsize,
|
||||
4 * UI_SCALE_FAC);
|
||||
}
|
||||
|
||||
uchar text_color[4];
|
||||
UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color);
|
||||
UI_fontstyle_draw_simple(fstyle,
|
||||
|
|
|
@ -1866,6 +1866,7 @@ typedef struct OnionSkinMeshLink {
|
|||
typedef struct SceneOnionSkin {
|
||||
float color[3];
|
||||
float alpha;
|
||||
int relative_left, relative_right;
|
||||
ListBase objects /* OnionSkinMeshLink */;
|
||||
} SceneOnionSkin;
|
||||
|
||||
|
|
Loading…
Reference in New Issue