Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/armature/pose_lib_2.c
| Show All 35 Lines | |||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "ED_armature.h" | #include "ED_armature.h" | ||||
| #include "ED_asset.h" | #include "ED_asset.h" | ||||
| #include "ED_keyframing.h" | #include "ED_keyframing.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_util.h" | |||||
| #include "armature_intern.h" | #include "armature_intern.h" | ||||
| typedef enum ePoseBlendState { | typedef enum ePoseBlendState { | ||||
| POSE_BLEND_INIT, | POSE_BLEND_INIT, | ||||
| POSE_BLEND_BLENDING, | POSE_BLEND_BLENDING, | ||||
| POSE_BLEND_ORIGINAL, | POSE_BLEND_ORIGINAL, | ||||
| POSE_BLEND_CONFIRM, | POSE_BLEND_CONFIRM, | ||||
| POSE_BLEND_CANCEL, | POSE_BLEND_CANCEL, | ||||
| } ePoseBlendState; | } ePoseBlendState; | ||||
| typedef struct PoseBlendData { | typedef struct PoseBlendData { | ||||
| ePoseBlendState state; | ePoseBlendState state; | ||||
| bool needs_redraw; | bool needs_redraw; | ||||
| struct { | struct { | ||||
| bool use_release_confirm; | bool use_release_confirm; | ||||
| int drag_start_xy[2]; | |||||
| int init_event_type; | int init_event_type; | ||||
| bool cursor_wrap_enabled; | |||||
| } release_confirm_info; | } release_confirm_info; | ||||
| /* For temp-loading the Action from the pose library. */ | /* For temp-loading the Action from the pose library. */ | ||||
| AssetTempIDConsumer *temp_id_consumer; | AssetTempIDConsumer *temp_id_consumer; | ||||
| /* Blend factor, interval [0, 1] for interpolating between current and given pose. */ | /* Blend factor, interval [0, 1] for interpolating between current and given pose. */ | ||||
| float blend_factor; | float blend_factor; | ||||
| struct PoseBackup *pose_backup; | struct PoseBackup *pose_backup; | ||||
| Object *ob; /* Object to work on. */ | Object *ob; /* Object to work on. */ | ||||
| bAction *act; /* Pose to blend into the current pose. */ | bAction *act; /* Pose to blend into the current pose. */ | ||||
| bool free_action; | bool free_action; | ||||
| Scene *scene; /* For auto-keying. */ | Scene *scene; /* For auto-keying. */ | ||||
| ScrArea *area; /* For drawing status text. */ | ScrArea *area; /* For drawing status text. */ | ||||
| struct tSlider *slider; /* Slider UI and event handling. */ | |||||
| /** Info-text to print in header. */ | /** Info-text to print in header. */ | ||||
| char headerstr[UI_MAX_DRAW_STR]; | char headerstr[UI_MAX_DRAW_STR]; | ||||
| } PoseBlendData; | } PoseBlendData; | ||||
| /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */ | /* Makes a copy of the current pose for restoration purposes - doesn't do constraints currently */ | ||||
| static void poselib_backup_posecopy(PoseBlendData *pbd) | static void poselib_backup_posecopy(PoseBlendData *pbd) | ||||
| { | { | ||||
| pbd->pose_backup = ED_pose_backup_create_selected_bones(pbd->ob, pbd->act); | pbd->pose_backup = ED_pose_backup_create_selected_bones(pbd->ob, pbd->act); | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd) | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); | ||||
| } | } | ||||
| /* Apply the relevant changes to the pose */ | /* Apply the relevant changes to the pose */ | ||||
| static void poselib_blend_apply(bContext *C, wmOperator *op) | static void poselib_blend_apply(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| PoseBlendData *pbd = (PoseBlendData *)op->customdata; | PoseBlendData *pbd = (PoseBlendData *)op->customdata; | ||||
| if (pbd->state == POSE_BLEND_BLENDING) { | |||||
| BLI_snprintf(pbd->headerstr, | |||||
| sizeof(pbd->headerstr), | |||||
| TIP_("PoseLib blending: \"%s\" at %3.0f%%"), | |||||
| pbd->act->id.name + 2, | |||||
| pbd->blend_factor * 100); | |||||
| ED_area_status_text(pbd->area, pbd->headerstr); | |||||
| ED_workspace_status_text( | |||||
| C, TIP_("Tab: show original pose; Horizontal mouse movement: change blend percentage")); | |||||
| } | |||||
| else { | |||||
| ED_area_status_text(pbd->area, TIP_("PoseLib showing original pose")); | |||||
| ED_workspace_status_text(C, TIP_("Tab: show blended pose")); | |||||
| } | |||||
| if (!pbd->needs_redraw) { | if (!pbd->needs_redraw) { | ||||
| return; | return; | ||||
| } | } | ||||
| pbd->needs_redraw = false; | pbd->needs_redraw = false; | ||||
| ED_pose_backup_restore(pbd->pose_backup); | ED_pose_backup_restore(pbd->pose_backup); | ||||
| /* The pose needs updating, whether it's for restoring the original pose or for showing the | /* The pose needs updating, whether it's for restoring the original pose or for showing the | ||||
| Show All 14 Lines | |||||
| /* ---------------------------- */ | /* ---------------------------- */ | ||||
| static void poselib_blend_set_factor(PoseBlendData *pbd, const float new_factor) | static void poselib_blend_set_factor(PoseBlendData *pbd, const float new_factor) | ||||
| { | { | ||||
| pbd->blend_factor = CLAMPIS(new_factor, 0.0f, 1.0f); | pbd->blend_factor = CLAMPIS(new_factor, 0.0f, 1.0f); | ||||
| pbd->needs_redraw = true; | pbd->needs_redraw = true; | ||||
| } | } | ||||
| static void poselib_slide_mouse_update_blendfactor(PoseBlendData *pbd, const wmEvent *event) | |||||
| { | |||||
| if (pbd->release_confirm_info.use_release_confirm) { | |||||
| /* Release confirm calculates factor based on where the dragging was started from. */ | |||||
| const float range = 300 * U.pixelsize; | |||||
| const float new_factor = (event->xy[0] - pbd->release_confirm_info.drag_start_xy[0]) / range; | |||||
| poselib_blend_set_factor(pbd, new_factor); | |||||
| } | |||||
| else { | |||||
| const float new_factor = (event->xy[0] - pbd->area->v1->vec.x) / ((float)pbd->area->winx); | |||||
| poselib_blend_set_factor(pbd, new_factor); | |||||
| } | |||||
| } | |||||
| /* Return operator return value. */ | /* Return operator return value. */ | ||||
| static int poselib_blend_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event) | static int poselib_blend_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| PoseBlendData *pbd = op->customdata; | PoseBlendData *pbd = op->customdata; | ||||
| ED_slider_modal(pbd->slider, event); | |||||
sybren: The execution order is pretty clear from the source code, as it's just top-to-bottom. | |||||
| const float factor = ED_slider_factor_get(pbd->slider); | |||||
| poselib_blend_set_factor(pbd, factor); | |||||
| if (event->type == MOUSEMOVE) { | if (event->type == MOUSEMOVE) { | ||||
| poselib_slide_mouse_update_blendfactor(pbd, event); | |||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| /* Handle the release confirm event directly, it has priority over others. */ | /* Handle the release confirm event directly, it has priority over others. */ | ||||
| if (pbd->release_confirm_info.use_release_confirm && | if (pbd->release_confirm_info.use_release_confirm && | ||||
| (event->type == pbd->release_confirm_info.init_event_type) && (event->val == KM_RELEASE)) { | (event->type == pbd->release_confirm_info.init_event_type) && (event->val == KM_RELEASE)) { | ||||
| pbd->state = POSE_BLEND_CONFIRM; | pbd->state = POSE_BLEND_CONFIRM; | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| Show All 28 Lines | case EVT_TABKEY: | ||||
| break; | break; | ||||
| /* TODO(Sybren): use better UI for slider. */ | /* TODO(Sybren): use better UI for slider. */ | ||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| static void poselib_blend_cursor_update(bContext *C, wmOperator *op) | |||||
| { | |||||
| PoseBlendData *pbd = op->customdata; | |||||
| /* Ensure cursor-grab (continuous grabbing) is enabled when using release-confirm. */ | |||||
| if (pbd->release_confirm_info.use_release_confirm && | |||||
| !pbd->release_confirm_info.cursor_wrap_enabled) { | |||||
| WM_cursor_grab_enable(CTX_wm_window(C), WM_CURSOR_WRAP_XY, true, NULL); | |||||
| pbd->release_confirm_info.cursor_wrap_enabled = true; | |||||
| } | |||||
| } | |||||
| /* ---------------------------- */ | /* ---------------------------- */ | ||||
| static Object *get_poselib_object(bContext *C) | static Object *get_poselib_object(bContext *C) | ||||
| { | { | ||||
| if (C == NULL) { | if (C == NULL) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return BKE_object_pose_armature_get(CTX_data_active_object(C)); | return BKE_object_pose_armature_get(CTX_data_active_object(C)); | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | static bool poselib_blend_init_data(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| pbd->state = POSE_BLEND_INIT; | pbd->state = POSE_BLEND_INIT; | ||||
| pbd->needs_redraw = true; | pbd->needs_redraw = true; | ||||
| pbd->blend_factor = RNA_float_get(op->ptr, "blend_factor"); | pbd->blend_factor = RNA_float_get(op->ptr, "blend_factor"); | ||||
| /* Just to avoid a clang-analyzer warning (false positive), it's set properly below. */ | /* Just to avoid a clang-analyzer warning (false positive), it's set properly below. */ | ||||
| pbd->release_confirm_info.use_release_confirm = false; | pbd->release_confirm_info.use_release_confirm = false; | ||||
| /* Release confirm data. Only available if there's an event to work with. */ | /* Release confirm data. Only available if there's an event to work with. */ | ||||
| if (event != NULL) { | if (event != NULL) { | ||||
Done Inline ActionsThis will cause a crash when event is NULL, which happens when applying a pose, instead of blending one. The slider should only be created when blending, and not when applying a pose. Other slider-related code should only run when pbd->slider != NULL. sybren: This will cause a crash when `event` is `NULL`, which happens when applying a pose, instead of… | |||||
Done Inline ActionsI haven't checked for null in the modal or handle event functions since they don't run when using pose apply (unless I'm being silly) abstanton: I haven't checked for null in the modal or handle event functions since they don't run when… | |||||
| PropertyRNA *release_confirm_prop = RNA_struct_find_property(op->ptr, "release_confirm"); | PropertyRNA *release_confirm_prop = RNA_struct_find_property(op->ptr, "release_confirm"); | ||||
| pbd->release_confirm_info.use_release_confirm = (release_confirm_prop != NULL) && | pbd->release_confirm_info.use_release_confirm = (release_confirm_prop != NULL) && | ||||
| RNA_property_boolean_get(op->ptr, | RNA_property_boolean_get(op->ptr, | ||||
| release_confirm_prop); | release_confirm_prop); | ||||
| pbd->slider = ED_slider_create(C); | |||||
| ED_slider_init(pbd->slider, event); | |||||
| ED_slider_factor_set(pbd->slider, pbd->blend_factor); | |||||
| ED_slider_allow_overshoot_set(pbd->slider, false); | |||||
| } | } | ||||
| if (pbd->release_confirm_info.use_release_confirm) { | if (pbd->release_confirm_info.use_release_confirm) { | ||||
| BLI_assert(event != NULL); | BLI_assert(event != NULL); | ||||
| copy_v2_v2_int(pbd->release_confirm_info.drag_start_xy, event->xy); | |||||
| pbd->release_confirm_info.init_event_type = WM_userdef_event_type_from_keymap_type( | pbd->release_confirm_info.init_event_type = WM_userdef_event_type_from_keymap_type( | ||||
| event->type); | event->type); | ||||
| } | } | ||||
| /* Make backups for blending and restoring the pose. */ | /* Make backups for blending and restoring the pose. */ | ||||
| poselib_backup_posecopy(pbd); | poselib_backup_posecopy(pbd); | ||||
| /* Set pose flags to ensure the depsgraph evaluation doesn't overwrite it. */ | /* Set pose flags to ensure the depsgraph evaluation doesn't overwrite it. */ | ||||
| pbd->ob->pose->flag &= ~POSE_DO_UNLOCK; | pbd->ob->pose->flag &= ~POSE_DO_UNLOCK; | ||||
| pbd->ob->pose->flag |= POSE_LOCKED; | pbd->ob->pose->flag |= POSE_LOCKED; | ||||
| return true; | return true; | ||||
| } | } | ||||
| static void poselib_blend_cleanup(bContext *C, wmOperator *op) | static void poselib_blend_cleanup(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| PoseBlendData *pbd = op->customdata; | PoseBlendData *pbd = op->customdata; | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| /* Redraw the header so that it doesn't show any of our stuff anymore. */ | /* Redraw the header so that it doesn't show any of our stuff anymore. */ | ||||
| ED_area_status_text(pbd->area, NULL); | ED_area_status_text(pbd->area, NULL); | ||||
| ED_workspace_status_text(C, NULL); | ED_workspace_status_text(C, NULL); | ||||
| if (pbd->slider) { | |||||
| ED_slider_destroy(C, pbd->slider); | |||||
| } | |||||
| /* This signals the depsgraph to unlock and reevaluate the pose on the next evaluation. */ | /* This signals the depsgraph to unlock and reevaluate the pose on the next evaluation. */ | ||||
| bPose *pose = pbd->ob->pose; | bPose *pose = pbd->ob->pose; | ||||
| pose->flag |= POSE_DO_UNLOCK; | pose->flag |= POSE_DO_UNLOCK; | ||||
| switch (pbd->state) { | switch (pbd->state) { | ||||
| case POSE_BLEND_CONFIRM: { | case POSE_BLEND_CONFIRM: { | ||||
| Scene *scene = pbd->scene; | Scene *scene = pbd->scene; | ||||
| poselib_keytag_pose(C, scene, pbd); | poselib_keytag_pose(C, scene, pbd); | ||||
| Show All 10 Lines | case POSE_BLEND_ORIGINAL: | ||||
| BLI_assert_msg(0, "poselib_blend_cleanup: unexpected pose blend state"); | BLI_assert_msg(0, "poselib_blend_cleanup: unexpected pose blend state"); | ||||
| BKE_report(op->reports, RPT_ERROR, "Internal pose library error, canceling operator"); | BKE_report(op->reports, RPT_ERROR, "Internal pose library error, canceling operator"); | ||||
| ATTR_FALLTHROUGH; | ATTR_FALLTHROUGH; | ||||
| case POSE_BLEND_CANCEL: | case POSE_BLEND_CANCEL: | ||||
| ED_pose_backup_restore(pbd->pose_backup); | ED_pose_backup_restore(pbd->pose_backup); | ||||
| break; | break; | ||||
| } | } | ||||
| if (pbd->release_confirm_info.cursor_wrap_enabled) { | |||||
| WM_cursor_grab_disable(win, pbd->release_confirm_info.drag_start_xy); | |||||
| pbd->release_confirm_info.cursor_wrap_enabled = false; | |||||
| } | |||||
| DEG_id_tag_update(&pbd->ob->id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&pbd->ob->id, ID_RECALC_GEOMETRY); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pbd->ob); | WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pbd->ob); | ||||
| /* Update mouse-hover highlights. */ | /* Update mouse-hover highlights. */ | ||||
| WM_event_add_mousemove(win); | WM_event_add_mousemove(win); | ||||
| } | } | ||||
| static void poselib_blend_free(wmOperator *op) | static void poselib_blend_free(wmOperator *op) | ||||
| { | { | ||||
| PoseBlendData *pbd = op->customdata; | PoseBlendData *pbd = op->customdata; | ||||
| if (pbd == NULL) { | if (pbd == NULL) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (pbd->free_action) { | if (pbd->free_action) { | ||||
| /* Run before #poselib_tempload_exit to avoid any problems from indirectly | /* Run before #poselib_tempload_exit to avoid any problems from indirectly | ||||
| * referenced ID pointers. */ | * referenced ID pointers. */ | ||||
| BKE_id_free(NULL, pbd->act); | BKE_id_free(NULL, pbd->act); | ||||
| } | } | ||||
| poselib_tempload_exit(pbd); | poselib_tempload_exit(pbd); | ||||
| /* Must have been dealt with before! */ | |||||
| BLI_assert(pbd->release_confirm_info.cursor_wrap_enabled == false); | |||||
| /* Free temp data for operator */ | /* Free temp data for operator */ | ||||
| ED_pose_backup_free(pbd->pose_backup); | ED_pose_backup_free(pbd->pose_backup); | ||||
| pbd->pose_backup = NULL; | pbd->pose_backup = NULL; | ||||
| MEM_SAFE_FREE(op->customdata); | MEM_SAFE_FREE(op->customdata); | ||||
| } | } | ||||
| static int poselib_blend_exit(bContext *C, wmOperator *op) | static int poselib_blend_exit(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| PoseBlendData *pbd = op->customdata; | PoseBlendData *pbd = op->customdata; | ||||
| const ePoseBlendState exit_state = pbd->state; | const ePoseBlendState exit_state = pbd->state; | ||||
| poselib_blend_cleanup(C, op); | poselib_blend_cleanup(C, op); | ||||
| poselib_blend_free(op); | poselib_blend_free(op); | ||||
| wmWindow *win = CTX_wm_window(C); | |||||
| WM_cursor_modal_restore(win); | |||||
| if (exit_state == POSE_BLEND_CANCEL) { | if (exit_state == POSE_BLEND_CANCEL) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* Cancel previewing operation (called when exiting Blender) */ | /* Cancel previewing operation (called when exiting Blender) */ | ||||
| static void poselib_blend_cancel(bContext *C, wmOperator *op) | static void poselib_blend_cancel(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| PoseBlendData *pbd = op->customdata; | PoseBlendData *pbd = op->customdata; | ||||
| pbd->state = POSE_BLEND_CANCEL; | pbd->state = POSE_BLEND_CANCEL; | ||||
| poselib_blend_exit(C, op); | poselib_blend_exit(C, op); | ||||
| } | } | ||||
| /* Main modal status check. */ | /* Main modal status check. */ | ||||
| static int poselib_blend_modal(bContext *C, wmOperator *op, const wmEvent *event) | static int poselib_blend_modal(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| const int operator_result = poselib_blend_handle_event(C, op, event); | const int operator_result = poselib_blend_handle_event(C, op, event); | ||||
| poselib_blend_cursor_update(C, op); | |||||
| const PoseBlendData *pbd = op->customdata; | const PoseBlendData *pbd = op->customdata; | ||||
| if (ELEM(pbd->state, POSE_BLEND_CONFIRM, POSE_BLEND_CANCEL)) { | if (ELEM(pbd->state, POSE_BLEND_CONFIRM, POSE_BLEND_CANCEL)) { | ||||
| return poselib_blend_exit(C, op); | return poselib_blend_exit(C, op); | ||||
| } | } | ||||
| if (pbd->needs_redraw) { | if (pbd->needs_redraw) { | ||||
| char status_string[UI_MAX_DRAW_STR]; | |||||
| char slider_string[UI_MAX_DRAW_STR]; | |||||
| char tab_string[50]; | |||||
| ED_slider_status_string_get(pbd->slider, slider_string, sizeof(slider_string)); | |||||
| if (pbd->state == POSE_BLEND_BLENDING) { | |||||
| strcpy(tab_string, TIP_("[Tab] - Show original pose")); | |||||
| } | |||||
| else { | |||||
| strcpy(tab_string, TIP_("[Tab] - Show blended pose")); | |||||
| } | |||||
| BLI_snprintf(status_string, sizeof(status_string), "%s | %s", tab_string, slider_string); | |||||
| ED_workspace_status_text(C, status_string); | |||||
| poselib_blend_apply(C, op); | poselib_blend_apply(C, op); | ||||
| } | } | ||||
| return operator_result; | return operator_result; | ||||
| } | } | ||||
| /* Modal Operator init. */ | /* Modal Operator init. */ | ||||
| static int poselib_blend_invoke(bContext *C, wmOperator *op, const wmEvent *event) | static int poselib_blend_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| if (!poselib_blend_init_data(C, op, event)) { | if (!poselib_blend_init_data(C, op, event)) { | ||||
| poselib_blend_free(op); | poselib_blend_free(op); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| wmWindow *win = CTX_wm_window(C); | |||||
| WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); | |||||
Done Inline ActionsNo need to have this comment here, it's clear what the code does. sybren: No need to have this comment here, it's clear what the code does. | |||||
| /* Do initial apply to have something to look at. */ | /* Do initial apply to have something to look at. */ | ||||
| poselib_blend_apply(C, op); | poselib_blend_apply(C, op); | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| /* Single-shot apply. */ | /* Single-shot apply. */ | ||||
| ▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | void POSELIB_OT_blend_pose_asset(wmOperatorType *ot) | ||||
| /* Callbacks: */ | /* Callbacks: */ | ||||
| ot->invoke = poselib_blend_invoke; | ot->invoke = poselib_blend_invoke; | ||||
| ot->modal = poselib_blend_modal; | ot->modal = poselib_blend_modal; | ||||
| ot->cancel = poselib_blend_cancel; | ot->cancel = poselib_blend_cancel; | ||||
| ot->exec = poselib_blend_exec; | ot->exec = poselib_blend_exec; | ||||
| ot->poll = poselib_blend_poll; | ot->poll = poselib_blend_poll; | ||||
| /* Flags: */ | /* Flags: */ | ||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; | ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X; | ||||
| /* Properties: */ | /* Properties: */ | ||||
| prop = RNA_def_float_factor(ot->srna, | prop = RNA_def_float_factor(ot->srna, | ||||
| "blend_factor", | "blend_factor", | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| 1.0f, | 1.0f, | ||||
| "Blend Factor", | "Blend Factor", | ||||
| Show All 20 Lines | |||||
The execution order is pretty clear from the source code, as it's just top-to-bottom. Personally I'd only add a "First" if there is a concrete need to explain why this code has to be executed first (sometimes such things can be hard to understand, and then a comment helps).
In this case I'd just remove the "First" though.