diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-03-18 04:48:59 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-03-18 04:48:59 +0400 |
commit | c1ceab1281ccf061f03f8000bf190a082a5385d8 (patch) | |
tree | 01b9a9cfca80432d316bdad6c18c74eb025e9eb0 /source/blender/editors | |
parent | 0d9c98c4bbfbc8c70c4772086dd09a51d01921ef (diff) | |
parent | 66a35e089a64d27bfc09c2225a530069eca05875 (diff) |
Merged changes in the trunk up to revision 55357.
Resolved conflicts:
release/datafiles/startup.blend
source/blender/editors/space_nla/nla_buttons.c
Also updated source/blender/blenkernel/intern/linestyle.c as a follow-up of
recent changes for the use of bool.
Diffstat (limited to 'source/blender/editors')
230 files changed, 11328 insertions, 8282 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 533420ad641..d6188720cdf 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -384,6 +384,10 @@ static short acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListEle case ACHANNEL_SETTING_MUTE: return ((ac) && (ac->spacetype == SPACE_NLA)); + /* select is ok for most "ds*" channels (e.g. dsmat) */ + case ACHANNEL_SETTING_SELECT: + return 1; + /* other flags are never supported */ default: return 0; @@ -425,7 +429,7 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) { if (name) - BLI_strncpy(name, "DopeSheet Summary", ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("DopeSheet Summary"), ANIM_CHAN_NAME_SIZE); } // FIXME: this is really a temp icon I think @@ -896,6 +900,27 @@ static void acf_fcurve_name(bAnimListElem *ale, char *name) getname_anim_fcurve(name, ale->id, ale->data); } +/* "name" property for fcurve entries */ +static short acf_fcurve_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) +{ + FCurve *fcu = (FCurve *)ale->data; + + /* Ctrl-Click Usability Convenience Hack: + * For disabled F-Curves, allow access to the RNA Path + * as our "name" so that user can perform quick fixes + */ + if (fcu->flag & FCURVE_DISABLED) { + RNA_pointer_create(ale->id, &RNA_FCurve, ale->data, ptr); + *prop = RNA_struct_find_property(ptr, "data_path"); + } + else { + /* for "normal" F-Curves - no editable name, but *prop may not be set properly yet... */ + *prop = NULL; + } + + return (*prop != NULL); +} + /* check if some setting exists for this channel */ static short acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, int setting) { @@ -967,7 +992,7 @@ static bAnimChannelType ACF_FCURVE = acf_generic_group_offset, /* offset */ acf_fcurve_name, /* name */ - NULL, /* name prop */ + acf_fcurve_name_prop, /* name prop */ NULL, /* icon */ acf_fcurve_setting_valid, /* has setting */ @@ -1070,7 +1095,7 @@ static int acf_filldrivers_icon(bAnimListElem *UNUSED(ale)) static void acf_filldrivers_name(bAnimListElem *UNUSED(ale), char *name) { - BLI_strncpy(name, "Drivers", ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE); } /* check if some setting exists for this channel */ @@ -2338,7 +2363,7 @@ static void acf_shapekey_name(bAnimListElem *ale, char *name) if (kb->name[0]) BLI_strncpy(name, kb->name, ANIM_CHAN_NAME_SIZE); else - BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, "Key %d", ale->index); + BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, IFACE_("Key %d"), ale->index); } } @@ -3490,10 +3515,13 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale /* if rename index matches, add widget for this */ if (ac->ads->renameIndex == channel_index + 1) { - PointerRNA ptr; - PropertyRNA *prop; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; - /* draw renaming widget if we can get RNA pointer for it */ + /* draw renaming widget if we can get RNA pointer for it + * NOTE: property may only be available in some cases, even if we have + * a callback available (e.g. broken F-Curve rename) + */ if (acf->name_prop(ale, &ptr, &prop)) { uiBut *but; diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 15a8222dec2..dd18d07732d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2272,7 +2272,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index) ED_region_tag_redraw(ac->ar); } -static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *evt) +static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { bAnimContext ac; ARegion *ar; @@ -2293,7 +2293,7 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEve * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use * ACHANNEL_HEIGHT_HALF. */ - UI_view2d_region_to_view(v2d, evt->mval[0], evt->mval[1], &x, &y); + UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); if (ac.datatype == ANIMCONT_NLA) { SpaceNla *snla = (SpaceNla *)ac.sl; @@ -2609,7 +2609,7 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in /* ------------------- */ /* handle clicking */ -static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; ARegion *ar; @@ -2667,7 +2667,7 @@ static void ANIM_OT_channels_click(wmOperatorType *ot) ot->poll = animedit_poll_channels_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ /* NOTE: don't save settings, otherwise, can end up with some weird behaviour (sticky extend) */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 3480db2c5d8..7648d998216 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -449,7 +449,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) if (ANIMDATA_HAS_NLA(id)) { \ nlaOk \ } \ - else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) { \ + else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \ nlaOk \ } \ } \ @@ -1001,22 +1001,39 @@ static short skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id) /* Check if F-Curve has errors and/or is disabled * > returns: (bool) True if F-Curve has errors/is disabled */ -static short fcurve_has_errors(FCurve *fcu) +static bool fcurve_has_errors(FCurve *fcu) { /* F-Curve disabled - path eval error */ if (fcu->flag & FCURVE_DISABLED) { - return 1; + return true; } /* driver? */ if (fcu->driver) { - /* for now, just check if the entire thing got disabled... */ - if (fcu->driver->flag & DRIVER_FLAG_INVALID) - return 1; + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + /* error flag on driver usually means that there is an error + * BUT this may not hold with PyDrivers as this flag gets cleared + * if no critical errors prevent the driver from working... + */ + if (driver->flag & DRIVER_FLAG_INVALID) + return true; + + /* check variables for other things that need linting... */ + // TODO: maybe it would be more efficient just to have a quick flag for this? + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER(dvar) + { + if (dtar->flag & DTAR_FLAG_INVALID) + return true; + } + DRIVER_TARGETS_LOOPER_END + } } /* no errors found */ - return 0; + return false; } /* find the next F-Curve that is usable for inclusion */ @@ -1060,7 +1077,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro /* error-based filtering... */ if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) { /* skip if no errors... */ - if (fcurve_has_errors(fcu) == 0) + if (fcurve_has_errors(fcu) == false) continue; } @@ -1297,7 +1314,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope ANIMDATA_FILTER_CASES(iat, { /* AnimData */ /* specifically filter animdata block */ - ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id); + if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt)) ) { + ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id); + } }, { /* NLA */ items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); @@ -1347,7 +1366,9 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke // TODO: somehow manage to pass dopesheet info down here too? if (key->adt) { if (filter_mode & ANIMFILTER_ANIMDATA) { - ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key); + if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt)) ) { + ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key); + } } else if (key->adt->action) { items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key); diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index b6d24e21057..2352cad0cbc 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -42,6 +42,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "DNA_anim_types.h" #include "RNA_access.h" @@ -63,9 +65,9 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) return icon; else if (ELEM3(NULL, id, fcu, fcu->rna_path)) { if (fcu == NULL) - strcpy(name, "<invalid>"); + strcpy(name, IFACE_("<invalid>")); else if (fcu->rna_path == NULL) - strcpy(name, "<no path>"); + strcpy(name, IFACE_("<no path>")); else /* id == NULL */ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 62725cb6c70..7a3fc3a8d9b 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -28,7 +28,6 @@ * \ingroup edanimation */ - #include <math.h> #include "MEM_guardedalloc.h" @@ -36,10 +35,6 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - #include "BLI_blenlib.h" #include "BLI_math_base.h" #include "BLI_utildefines.h" @@ -51,6 +46,10 @@ #include "BKE_scene.h" #include "BKE_screen.h" +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + #include "WM_api.h" #include "WM_types.h" @@ -277,7 +276,9 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only ce->sel = marker->flag; return; } - else if (ce->cfra > marker->frame) break; + else if (ce->cfra > marker->frame) { + break; + } } cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); @@ -513,8 +514,8 @@ static int ed_markers_poll_markers_exist(bContext *C) * that operator would otherwise have used. If NULL, the operator's standard * exec() callback will be called instead in the appropriate places. */ -static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt, - int (*invoke_func)(bContext *, wmOperator *, wmEvent *)) +static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event, + int (*invoke_func)(bContext *, wmOperator *, const wmEvent *)) { ScrArea *sa = CTX_wm_area(C); int retval = OPERATOR_PASS_THROUGH; @@ -523,7 +524,7 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent /* allow operator to run now */ if (invoke_func) - retval = invoke_func(C, op, evt); + retval = invoke_func(C, op, event); else if (op->type->exec) retval = op->type->exec(C, op); else @@ -544,9 +545,9 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent * though will need to implement their own wrapper which calls the second-tier callback themselves * (passing through the custom invoke function they use) */ -static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, NULL); + return ed_markers_opwrap_invoke_custom(C, op, event, NULL); } /* ************************** add markers *************************** */ @@ -684,14 +685,14 @@ static void ed_marker_move_exit(bContext *C, wmOperator *op) ED_area_headerprint(CTX_wm_area(C), NULL); } -static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (ed_marker_move_init(C, op)) { MarkerMove *mm = op->customdata; - mm->evtx = evt->x; - mm->firstx = evt->x; - mm->event_type = evt->type; + mm->evtx = event->x; + mm->firstx = event->x; + mm->event_type = event->type; /* add temp handler */ WM_event_add_modal_handler(C, op); @@ -705,9 +706,9 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_CANCELLED; } -static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_move_invoke); } /* note, init has to be called succesfully */ @@ -756,7 +757,7 @@ static int ed_marker_move_cancel(bContext *C, wmOperator *op) -static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); MarkerMove *mm = op->customdata; @@ -765,14 +766,14 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) float dx, fac; char str[256]; - switch (evt->type) { + switch (event->type) { case ESCKEY: ed_marker_move_cancel(C, op); return OPERATOR_CANCELLED; case RIGHTMOUSE: /* press = user manually demands transform to be canceled */ - if (evt->val == KM_PRESS) { + if (event->val == KM_PRESS) { ed_marker_move_cancel(C, op); return OPERATOR_CANCELLED; } @@ -782,7 +783,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) case PADENTER: case LEFTMOUSE: case MIDDLEMOUSE: - if (WM_modal_tweak_exit(evt, mm->event_type)) { + if (WM_modal_tweak_exit(event, mm->event_type)) { ed_marker_move_exit(C, op); WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); @@ -795,17 +796,17 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); - if (evt->x != mm->evtx) { /* XXX maybe init for first time */ + if (event->x != mm->evtx) { /* XXX maybe init for first time */ int a, offs, totmark = 0; - mm->evtx = evt->x; + mm->evtx = event->x; - fac = ((float)(evt->x - mm->firstx) * dx); + fac = ((float)(event->x - mm->firstx) * dx); if (mm->slink->spacetype == SPACE_TIME) - apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0); + apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0); else - apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/); + apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/); offs = (int)fac; RNA_int_set(op->ptr, "frames", offs); @@ -864,8 +865,8 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt) } } - if (evt->val == KM_PRESS) { - if (handleNumInput(&mm->num, evt)) { + if (event->val == KM_PRESS) { + if (handleNumInput(&mm->num, event)) { char str_tx[NUM_STR_REP_LEN]; float value = RNA_int_get(op->ptr, "frames"); applyNumInput(&mm->num, &value); @@ -981,15 +982,15 @@ static int ed_marker_duplicate_exec(bContext *C, wmOperator *op) } -static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ed_marker_duplicate_apply(C); - return ed_marker_move_invoke(C, op, evt); + return ed_marker_move_invoke(C, op, event); } -static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_duplicate_invoke); } static void MARKER_OT_duplicate(wmOperatorType *ot) @@ -1036,7 +1037,7 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned } } -static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera) +static int ed_marker_select(bContext *C, const wmEvent *event, int extend, int camera) { ListBase *markers = ED_context_get_markers(C); ARegion *ar = CTX_wm_region(C); @@ -1047,8 +1048,8 @@ static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera) if (markers == NULL) return OPERATOR_PASS_THROUGH; - x = evt->x - ar->winrct.xmin; - y = evt->y - ar->winrct.ymin; + x = event->x - ar->winrct.xmin; + y = event->y - ar->winrct.ymin; UI_view2d_region_to_view(v2d, x, y, &viewx, NULL); @@ -1103,19 +1104,19 @@ static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera) return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } -static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { short extend = RNA_boolean_get(op->ptr, "extend"); short camera = 0; #ifdef DURIAN_CAMERA_SWITCH camera = RNA_boolean_get(op->ptr, "camera"); #endif - return ed_marker_select(C, evt, extend, camera); + return ed_marker_select(C, event, extend, camera); } -static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_select_invoke); } static void MARKER_OT_select(wmOperatorType *ot) @@ -1200,9 +1201,9 @@ static int ed_marker_border_select_exec(bContext *C, wmOperator *op) return 1; } -static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_border_select_invoke); } static void MARKER_OT_select_border(wmOperatorType *ot) @@ -1309,10 +1310,10 @@ static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { // XXX: must we keep these confirmations? - return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_confirm); } static void MARKER_OT_delete(wmOperatorType *ot) @@ -1352,7 +1353,7 @@ static int ed_marker_rename_exec(bContext *C, wmOperator *op) } } -static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { /* must initialize the marker name first if there is a marker selected */ TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C)); @@ -1360,7 +1361,7 @@ static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent RNA_string_set(op->ptr, "name", marker->name); /* now see if the operator is usable */ - return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_props_popup); } static void MARKER_OT_rename(wmOperatorType *ot) @@ -1414,9 +1415,9 @@ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt) +static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, evt, WM_menu_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_menu_invoke); } static void MARKER_OT_make_links_scene(wmOperatorType *ot) diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 6687cce88cd..b9a3daa4e51 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -115,7 +115,7 @@ static int change_frame_exec(bContext *C, wmOperator *op) /* ---- */ /* Get frame from mouse coordinates */ -static int frame_from_event(bContext *C, wmEvent *event) +static int frame_from_event(bContext *C, const wmEvent *event) { ARegion *region = CTX_wm_region(C); float viewx; @@ -128,7 +128,7 @@ static int frame_from_event(bContext *C, wmEvent *event) } /* Modal Operator init */ -static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* Change to frame that mouse is over before adding modal handler, * as user could click on a single frame (jump to frame) as well as @@ -145,7 +145,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* Modal event handling of frame changing */ -static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) +static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) { /* execute the events */ switch (event->type) { diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 6d1e6eab26b..ed8398b7c8b 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -714,7 +714,6 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i else if (ptr->type == &RNA_PoseBone) { Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */ bPoseChannel *pchan = (bPoseChannel *)ptr->data; - float tmat[4][4]; /* Although it is not strictly required for this particular space conversion, * arg1 must not be null, as there is a null check for the other conversions to @@ -1298,7 +1297,7 @@ void ANIM_OT_keyframe_insert(wmOperatorType *ot) * then calls the menu if necessary before */ -static int insert_key_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); @@ -1308,7 +1307,7 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(e uiLayout *layout; /* call the menu, which will call this operator again, hence the canceled */ - pup = uiPupMenuBegin(C, op->type->name, ICON_NONE); + pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); layout = uiPupMenuLayout(pup); uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); uiPupMenuEnd(C, pup); @@ -1624,17 +1623,21 @@ static int insert_key_button_exec(bContext *C, wmOperator *op) success += insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0); } else { - if (G.debug & G_DEBUG) - printf("Button Insert-Key: no path to property\n"); - BKE_report(op->reports, RPT_WARNING, "Failed to resolve path to property, try using a keying set instead"); + BKE_report(op->reports, RPT_WARNING, + "Failed to resolve path to property, try manually specifying this using a Keying Set instead"); } } - else if (G.debug & G_DEBUG) { - printf("ptr.data = %p, prop = %p,", (void *)ptr.data, (void *)prop); - if (prop) - printf("animatable = %d\n", RNA_property_animateable(&ptr, prop)); - else - printf("animatable = NULL\n"); + else { + if (prop && !RNA_property_animateable(&ptr, prop)) { + BKE_reportf(op->reports, RPT_WARNING, + "\"%s\" property cannot be animated", + RNA_property_identifier(prop)); + } + else { + BKE_reportf(op->reports, RPT_WARNING, + "Button doesn't appear to have any property information attached (ptr.data = %p, prop = %p)", + (void *)ptr.data, (void *)prop); + } } if (success) { diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 4e8d7bdafe5..ad09fcb5966 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -468,7 +468,7 @@ void ANIM_OT_keyingset_button_remove(wmOperatorType *ot) /* Change Active KeyingSet Operator ------------------------ */ /* This operator checks if a menu should be shown for choosing the KeyingSet to make the active one */ -static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -879,7 +879,7 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks) if (ksi == NULL) return MODIFYKEY_MISSING_TYPEINFO; /* TODO: check for missing callbacks! */ - + /* check if it can be used in the current context */ if (ksi->poll(ksi, C)) { /* if a list of data sources are provided, run a special iterator over them, diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 531c0551c87..28fb74f0cdd 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -214,7 +214,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* TODO most of this code is copied from set3dcursor_invoke, * it would be better to reuse code in set3dcursor_invoke */ @@ -320,8 +320,8 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj bConstraint *curcon; ListBase *conlist; - if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) { - if ( (conlist = &pchan->constraints) ) { + if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) { + if ((conlist = &pchan->constraints)) { for (curcon = conlist->first; curcon; curcon = curcon->next) { /* does this constraint have a subtarget in * this armature? diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 6417a795712..561e196bf41 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -72,7 +72,7 @@ EditBone *editbone_name_exists(ListBase *edbo, const char *name) } /* note: there's a unique_bone_name() too! */ -static int editbone_unique_check(void *arg, const char *name) +static bool editbone_unique_check(void *arg, const char *name) { struct {ListBase *lb; void *bone; } *data = arg; EditBone *dupli = editbone_name_exists(data->lb, name); @@ -91,7 +91,7 @@ void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone) /* ************************************************** */ /* Bone Renaming - API */ -static int bone_unique_check(void *arg, const char *name) +static bool bone_unique_check(void *arg, const char *name) { return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL; } @@ -152,7 +152,9 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n unique_editbone_name(arm->edbo, newname, NULL); BLI_strncpy(eBone->name, newname, MAXBONENAME); } - else return; + else { + return; + } } else { Bone *bone = BKE_armature_find_bone_name(arm, oldname); @@ -161,7 +163,9 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n unique_bone_name(arm, newname); BLI_strncpy(bone->name, newname, MAXBONENAME); } - else return; + else { + return; + } } /* do entire dbase - objects */ diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index c64bb5c4683..3a4dc31c82d 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -671,7 +671,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { EditBone *actbone = CTX_data_active_bone(C); uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index b7a436cc209..7ff318bb6b6 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -166,7 +166,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y) /* called in space.c */ /* previously "selectconnected_armature" */ -static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bArmature *arm; EditBone *bone, *curBone, *next; @@ -323,7 +323,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], else dep = 2; } - else dep = 2; + else { + dep = 2; + } } else { /* bone found */ @@ -333,7 +335,9 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], else dep = 3; } - else dep = 3; + else { + dep = 3; + } } if (ebone == ebone_next_act) { @@ -390,8 +394,10 @@ void ED_armature_deselect_all(Object *obedit, int toggle) // } } } - else sel = toggle; - + else { + sel = toggle; + } + /* Set the flags */ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (sel == 2) { diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 05f48ad73f4..4120be08b46 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -147,6 +147,15 @@ void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone) bone_free(arm, exBone); } +bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child) +{ + for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) { + if (ebone_child == ebone_parent) + return true; + } + return false; +} + /* *************************************************************** */ /* Mirroring */ diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c index 89772d38e8f..bade93af8c1 100644 --- a/source/blender/editors/armature/editarmature_generate.c +++ b/source/blender/editors/armature/editarmature_generate.c @@ -263,7 +263,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U parent = ED_armature_edit_bone_add(arm, "Bone"); copy_v3_v3(parent->head, iter->p); - if (iter->size > 0) { + if (iter->size > FLT_EPSILON) { parent->rad_head = iter->size * size_buffer; } @@ -278,7 +278,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U child->parent = parent; child->flag |= BONE_CONNECTED; - if (iter->size > 0) { + if (iter->size > FLT_EPSILON) { child->rad_head = iter->size * size_buffer; parent->rad_tail = iter->size * size_buffer; } @@ -299,7 +299,7 @@ EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *U iter->tail(iter); copy_v3_v3(parent->tail, iter->p); - if (iter->size > 0) { + if (iter->size > FLT_EPSILON) { parent->rad_tail = iter->size * size_buffer; } diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 62cce6b2c1e..536c5ff1f7c 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -409,11 +409,11 @@ static void renameTemplateBone(char *name, char *template_name, ListBase *editbo for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) { if (template_name[i] == '&') { if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') { - j += sprintf(name + j, "%s", side_string); + j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME); i++; } else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') { - j += sprintf(name + j, "%s", num_string); + j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME); i++; } else { @@ -896,7 +896,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* look on deform bones first */ BLI_ghashIterator_init(&ghi, rg->bones_map); - for (; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi)) { + for (; BLI_ghashIterator_notDone(&ghi); BLI_ghashIterator_step(&ghi)) { EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi); /* don't link with parent */ diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index ec96c574f75..a3515e0983d 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -28,9 +28,6 @@ #include "DNA_scene_types.h" #include "DNA_armature_types.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "BLI_blenlib.h" #include "BLI_math.h" @@ -39,6 +36,9 @@ #include "BKE_context.h" #include "BKE_sketch.h" +#include "RNA_define.h" +#include "RNA_access.h" + #include "ED_view3d.h" #include "ED_screen.h" @@ -170,20 +170,20 @@ const char *BIF_listTemplates(const bContext *UNUSED(C)) GHashIterator ghi; const char *menu_header = IFACE_("Template %t|None %x0|"); char *p; + const size_t template_size = (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30); if (TEMPLATES_MENU != NULL) { MEM_freeN(TEMPLATES_MENU); } - TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu"); + TEMPLATES_MENU = MEM_callocN(sizeof(char) * template_size, "skeleton template menu"); p = TEMPLATES_MENU; - - p += sprintf(TEMPLATES_MENU, "%s", menu_header); + p += BLI_strncpy_rlen(p, menu_header, template_size); BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); - while (!BLI_ghashIterator_isDone(&ghi)) { + while (BLI_ghashIterator_notDone(&ghi)) { Object *ob = BLI_ghashIterator_getValue(&ghi); int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); @@ -203,7 +203,7 @@ int BIF_currentTemplate(const bContext *C) GHashIterator ghi; BLI_ghashIterator_init(&ghi, TEMPLATES_HASH); - while (!BLI_ghashIterator_isDone(&ghi)) { + while (BLI_ghashIterator_notDone(&ghi)) { Object *ob = BLI_ghashIterator_getValue(&ghi); int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi)); @@ -922,17 +922,18 @@ static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_Dr float fp[3] = {0, 0, 0}; float dvec[3]; float mval_f[2]; + float zfac; if (last != NULL) { copy_v3_v3(fp, last->p); } - initgrabz(ar->regiondata, fp[0], fp[1], fp[2]); + zfac = ED_view3d_calc_zfac(ar->regiondata, fp, NULL); /* method taken from editview.c - mouse_cursor() */ if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { VECSUB2D(mval_f, cval, dd->mval); - ED_view3d_win_to_delta(ar, mval_f, dvec); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); sub_v3_v3v3(vec, fp, dvec); } else { @@ -2231,7 +2232,7 @@ void BDR_drawSketch(const bContext *C) } } -static int sketch_delete(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { SK_Sketch *sketch = contextSketch(C, 0); if (sketch) { @@ -2328,7 +2329,7 @@ SK_Sketch *viewcontextSketch(ViewContext *vc, int create) return sketch; } -static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int sketch_convert(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { SK_Sketch *sketch = contextSketch(C, 0); if (sketch != NULL) { @@ -2338,7 +2339,7 @@ static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(e return OPERATOR_FINISHED; } -static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { SK_Sketch *sketch = contextSketch(C, 0); if (sketch != NULL) { @@ -2349,7 +2350,7 @@ static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(ev return OPERATOR_PASS_THROUGH; } -static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int sketch_finish(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { SK_Sketch *sketch = contextSketch(C, 0); if (sketch != NULL) { @@ -2361,7 +2362,7 @@ static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(ev return OPERATOR_PASS_THROUGH; } -static int sketch_select(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int sketch_select(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { SK_Sketch *sketch = contextSketch(C, 0); if (sketch) { @@ -2381,7 +2382,7 @@ static int sketch_draw_stroke_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event) +static int sketch_draw_stroke(bContext *C, wmOperator *op, const wmEvent *event) { short snap = RNA_boolean_get(op->ptr, "snap"); SK_DrawData *dd; @@ -2407,7 +2408,7 @@ static int sketch_draw_gesture_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event) +static int sketch_draw_gesture(bContext *C, wmOperator *op, const wmEvent *event) { short snap = RNA_boolean_get(op->ptr, "snap"); SK_DrawData *dd; @@ -2425,7 +2426,7 @@ static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short gesture, SK_Stroke *stk) +static int sketch_draw_modal(bContext *C, wmOperator *op, const wmEvent *event, short gesture, SK_Stroke *stk) { short snap = RNA_boolean_get(op->ptr, "snap"); SK_DrawData *dd = op->customdata; @@ -2483,19 +2484,19 @@ static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short return retval; } -static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ return sketch_draw_modal(C, op, event, 0, sketch->active_stroke); } -static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, wmEvent *event) +static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, const wmEvent *event) { SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */ return sketch_draw_modal(C, op, event, 1, sketch->gesture); } -static int sketch_draw_preview(bContext *C, wmOperator *op, wmEvent *event) +static int sketch_draw_preview(bContext *C, wmOperator *op, const wmEvent *event) { short snap = RNA_boolean_get(op->ptr, "snap"); SK_Sketch *sketch = contextSketch(C, 0); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 3d1d5d2f6ba..40b96132699 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -201,7 +201,7 @@ void ED_pose_recalculate_paths(Scene *scene, Object *ob) /* show popup to determine settings */ -static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); @@ -793,7 +793,7 @@ void ARMATURE_OT_layers_show_all(wmOperatorType *ot) /* ------------------- */ /* Present a popup to get the layers that should be used */ -static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int pose_armature_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm = (ob) ? ob->data : NULL; @@ -810,7 +810,7 @@ static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt RNA_boolean_set_array(op->ptr, "layers", layers); /* part to sync with other similar operators... */ - return WM_operator_props_popup(C, op, evt); + return WM_operator_props_popup(C, op, event); } /* Set the visible layers for the active armature (edit and pose modes) */ @@ -879,7 +879,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot) /* ------------------- */ /* Present a popup to get the layers that should be used */ -static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -900,7 +900,7 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt) RNA_boolean_set_array(op->ptr, "layers", layers); /* part to sync with other similar operators... */ - return WM_operator_props_popup(C, op, evt); + return WM_operator_props_popup(C, op, event); } /* Set the visible layers for the active armature (edit and pose modes) */ @@ -954,7 +954,7 @@ void POSE_OT_bone_layers(wmOperatorType *ot) /* ------------------- */ /* Present a popup to get the layers that should be used */ -static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */ @@ -975,7 +975,7 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt RNA_boolean_set_array(op->ptr, "layers", layers); /* part to sync with other similar operators... */ - return WM_operator_props_popup(C, op, evt); + return WM_operator_props_popup(C, op, event); } /* Set the visible layers for the active armature (edit and pose modes) */ diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 06a88f013d7..99f54de134a 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -126,7 +126,7 @@ void POSE_OT_group_remove(wmOperatorType *ot) /* ------------ */ /* invoke callback which presents a list of bone-groups for the user to choose from */ -static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = ED_pose_object_from_context(C); bPose *pose; diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 457874c7ae6..09c0f7e9647 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -389,7 +389,7 @@ static void poselib_add_menu_invoke__replacemenu(bContext *C, uiLayout *layout, } } -static int poselib_add_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); Object *ob = get_poselib_object(C); @@ -613,7 +613,7 @@ void POSELIB_OT_pose_remove(wmOperatorType *ot) ot->prop = prop; } -static int poselib_rename_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int poselib_rename_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = get_poselib_object(C); bAction *act = (ob) ? ob->poselib : NULL; @@ -638,7 +638,7 @@ static int poselib_rename_invoke(bContext *C, wmOperator *op, wmEvent *evt) } /* part to sync with other similar operators... */ - return WM_operator_props_popup(C, op, evt); + return WM_operator_props_popup(C, op, event); } static int poselib_rename_exec(bContext *C, wmOperator *op) @@ -1185,7 +1185,7 @@ static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, unsigned sh } /* handle events for poselib_preview_poses */ -static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, wmEvent *event) +static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, const wmEvent *event) { tPoseLib_PreviewData *pld = op->customdata; int ret = OPERATOR_RUNNING_MODAL; @@ -1539,7 +1539,7 @@ static int poselib_preview_cancel(bContext *C, wmOperator *op) } /* main modal status check */ -static int poselib_preview_modal(bContext *C, wmOperator *op, wmEvent *event) +static int poselib_preview_modal(bContext *C, wmOperator *op, const wmEvent *event) { tPoseLib_PreviewData *pld = op->customdata; int ret; @@ -1559,7 +1559,7 @@ static int poselib_preview_modal(bContext *C, wmOperator *op, wmEvent *event) } /* Modal Operator init */ -static int poselib_preview_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int poselib_preview_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { tPoseLib_PreviewData *pld; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 186c7a1fe89..4fa1389426d 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -208,7 +208,7 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend) /* within active object context */ /* previously known as "selectconnected_posearmature" */ -static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm = (bArmature *)ob->data; diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index fee37a9c0fb..4d6f8f520f5 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -614,12 +614,12 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p } /* common code for modal() */ -static int pose_slide_modal(bContext *C, wmOperator *op, wmEvent *evt) +static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { tPoseSlideOp *pso = op->customdata; wmWindow *win = CTX_wm_window(C); - switch (evt->type) { + switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: { @@ -660,7 +660,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, wmEvent *evt) /* 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 */ - pso->percentage = (evt->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); + pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx); RNA_float_set(op->ptr, "percentage", pso->percentage); /* update percentage indicator in header */ @@ -717,7 +717,7 @@ static void pose_slide_opdef_properties(wmOperatorType *ot) /* ------------------------------------ */ /* invoke() - for 'push' mode */ -static int pose_slide_push_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { tPoseSlideOp *pso; @@ -774,7 +774,7 @@ void POSE_OT_push(wmOperatorType *ot) /* ........................ */ /* invoke() - for 'relax' mode */ -static int pose_slide_relax_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { tPoseSlideOp *pso; @@ -831,7 +831,7 @@ void POSE_OT_relax(wmOperatorType *ot) /* ........................ */ /* invoke() - for 'breakdown' mode */ -static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { tPoseSlideOp *pso; diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index 454b0f0bceb..d04938fd59b 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -1659,7 +1659,7 @@ int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold)) float avg_vec[3] = {0, 0, 0}; for (BLI_ghashIterator_init(&ghi, arc->faces); - !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_notDone(&ghi); BLI_ghashIterator_step(&ghi)) { EditFace *efa = BLI_ghashIterator_getValue(&ghi); @@ -2045,7 +2045,7 @@ void mergeArcFaces(ReebGraph *UNUSED(rg), ReebArc *aDst, ReebArc *aSrc) GHashIterator ghi; for (BLI_ghashIterator_init(&ghi, aSrc->faces); - !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_notDone(&ghi); BLI_ghashIterator_step(&ghi)) { EditFace *efa = BLI_ghashIterator_getValue(&ghi); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index d01e5c5d9bf..e134507600e 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -626,7 +626,9 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu) bezt++; } } - else fp += a * 12; + else { + fp += a * 12; + } } else { BPoint *bp = nu->bp; @@ -640,7 +642,9 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu) bp++; } } - else fp += a * 4; + else { + fp += a * 4; + } } nu = nu->next; @@ -672,7 +676,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex) gh = BLI_ghash_ptr_new("dupli_keyIndex gh"); for (hashIter = BLI_ghashIterator_new(keyindex); - !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_notDone(hashIter); BLI_ghashIterator_step(hashIter)) { void *cv = BLI_ghashIterator_getKey(hashIter); @@ -1473,7 +1477,9 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) if (*u == -1) *u = b; else return 0; } - else if (sel > 1) return 0; /* because sel == 1 is still ok */ + else if (sel > 1) { + return 0; /* because sel == 1 is still ok */ + } } for (a = 0; a < nu->pntsu; a++) { @@ -1486,7 +1492,9 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) if (*v == -1) *v = a; else return 0; } - else if (sel > 1) return 0; + else if (sel > 1) { + return 0; + } } if (*u == -1 && *v > -1) return 1; @@ -1781,7 +1789,7 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) else { /* which row or column is selected */ - if (isNurbselUV(nu, &u, &v, flag) ) { + if (isNurbselUV(nu, &u, &v, flag)) { /* deselect all */ bp = nu->bp; @@ -1872,7 +1880,7 @@ static void adduplicateflagNurb(Object *obedit, short flag) for (a = 0; a < nu->pntsu; a++) { enda = -1; starta = a; - while ( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) { + while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) { select_beztriple(bezt, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; @@ -2431,12 +2439,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short BezTriple *bezt; BPoint *bp; int a; - short lastsel = 0; + short lastsel = false; if (next == 0) return; for (nu = editnurb->first; nu; nu = nu->next) { - lastsel = 0; + lastsel = false; if (nu->type == CU_BEZIER) { a = nu->pntsu; bezt = nu->bezt; @@ -2447,12 +2455,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short bezt += next; if (!(bezt->f2 & SELECT) || (selstatus == 0)) { short sel = select_beztriple(bezt, selstatus, 1, VISIBLE); - if ((sel == 1) && (cont == 0)) lastsel = 1; + if ((sel == 1) && (cont == 0)) lastsel = true; } } else { bezt += next; - lastsel = 0; + lastsel = false; } /* move around in zigzag way so that we go through each */ bezt -= (next - next / abs(next)); @@ -2468,12 +2476,12 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short bp += next; if (!(bp->f1 & SELECT) || (selstatus == 0)) { short sel = select_bpoint(bp, selstatus, 1, VISIBLE); - if ((sel == 1) && (cont == 0)) lastsel = 1; + if ((sel == 1) && (cont == 0)) lastsel = true; } } else { bp += next; - lastsel = 0; + lastsel = false; } /* move around in zigzag way so that we go through each */ bp -= (next - next / abs(next)); @@ -2878,7 +2886,7 @@ static void subdividenurb(Object *obedit, int number_cuts) keyIndex_updateBezt(editnurb, prevbezt, beztn, 1); beztn++; - if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt)) { float prevvec[3][3]; memcpy(prevvec, prevbezt->vec, sizeof(float) * 9); @@ -3062,7 +3070,7 @@ static void subdividenurb(Object *obedit, int number_cuts) bp++; } } - if (sel == (nu->pntsu * nu->pntsv) ) { /* subdivide entire nurb */ + if (sel == (nu->pntsu * nu->pntsv)) { /* subdivide entire nurb */ /* Global subdivision is a special case of partial * subdivision. Strange it is considered separately... */ @@ -3332,7 +3340,7 @@ static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt bezt1 = nu1->bezt; a = nu1->pntsu; while (a--) { - if ( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) { + if ((bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT)) { if (*nu != NULL && *nu != nu1) { *nu = NULL; *bp = NULL; @@ -3803,7 +3811,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu /* first nurbs: u = resolu-1 selected */ - if (is_u_selected(nu1, nu1->pntsu - 1) ) { + if (is_u_selected(nu1, nu1->pntsu - 1)) { /* pass */ } else { @@ -3835,7 +3843,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu } /* 2nd nurbs: u = 0 selected */ - if (is_u_selected(nu2, 0) ) { + if (is_u_selected(nu2, 0)) { /* pass */ } else { @@ -4041,9 +4049,11 @@ static int make_segment_exec(bContext *C, wmOperator *op) if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */ if (nu->type == CU_BEZIER) { if (nu1 == NULL) { - if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) nu1 = nu; + if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt)) { + nu1 = nu; + } else { - if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1])) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) { nu1 = nu; BKE_nurb_direction_switch(nu); keyData_switchDirectionNurb(cu, nu); @@ -4051,23 +4061,27 @@ static int make_segment_exec(bContext *C, wmOperator *op) } } else if (nu2 == NULL) { - if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, nu->bezt)) { nu2 = nu; BKE_nurb_direction_switch(nu); keyData_switchDirectionNurb(cu, nu); } else { - if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1])) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) { nu2 = nu; } } } - else break; + else { + break; + } } else if (nu->pntsv == 1) { bp = nu->bp; if (nu1 == NULL) { - if (bp->f1 & SELECT) nu1 = nu; + if (bp->f1 & SELECT) { + nu1 = nu; + } else { bp = bp + (nu->pntsu - 1); if (bp->f1 & SELECT) { @@ -4090,7 +4104,9 @@ static int make_segment_exec(bContext *C, wmOperator *op) } } } - else break; + else { + break; + } } } } @@ -4421,7 +4437,7 @@ static int spin_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4495,7 +4511,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3]) newnu->resolu = cu->resolu; newnu->flag |= CU_SMOOTH; } - else memcpy(newnu, nu, sizeof(Nurb)); + else { + memcpy(newnu, nu, sizeof(Nurb)); + } BLI_addtail(&editnurb->nurbs, newnu); set_actNurb(obedit, newnu); @@ -4609,7 +4627,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3]) bezt = newbezt; ok = 1; } - else bezt = NULL; + else { + bezt = NULL; + } if (bezt) { if (!newnu) nu->pntsu++; @@ -4687,7 +4707,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3]) bp = newbp; ok = 1; } - else bp = NULL; + else { + bp = NULL; + } if (bp) { if (mode == 'e') { @@ -4705,7 +4727,9 @@ static int addvert_Nurb(bContext *C, short mode, float location[3]) nu->pntsu++; BKE_nurb_knot_calc_u(nu); } - else BKE_nurb_knot_calc_u(newnu); + else { + BKE_nurb_knot_calc_u(newnu); + } } } @@ -4732,7 +4756,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op) return addvert_Nurb(C, 0, location); } -static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -4761,7 +4785,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event) copy_v3_v3(location, give_cursor(vc.scene, vc.v3d)); } - view3d_get_view_aligned_coordinate(&vc, location, event->mval, TRUE); + view3d_get_view_aligned_coordinate(vc.ar, location, event->mval, true); RNA_float_set_array(op->ptr, "location", location); } @@ -4864,7 +4888,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op) a = nu->pntsu; bezt = nu->bezt; while (a--) { - if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { nu->flagu ^= CU_NURB_CYCLIC; break; } @@ -4915,7 +4939,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int toggle_cyclic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *obedit = CTX_data_edit_object(C); ListBase *editnurb = object_editcurve_get(obedit); @@ -4983,7 +5007,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) bezt = nu->bezt; a = nu->pntsu; while (a--) { - if ( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) { + if ((bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT)) { a = nu->pntsu; bezt = nu->bezt; while (a--) { @@ -5018,7 +5042,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return select_linked_exec(C, op); } @@ -5044,7 +5068,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot) /***************** select linked pick operator ******************/ -static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); ViewContext vc; @@ -5333,7 +5357,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) BPoint *bp; BezTriple *bezt; int a; - short sel = 0, lastsel = 0; + short sel = 0, lastsel = false; short *selbpoints; if (obedit->type == OB_SURF) { @@ -5344,44 +5368,54 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) while (a--) { if ((bp->hide == 0) && (bp->f1 & SELECT)) { sel = 0; - + /* check if neighbors have been selected */ /* edges of surface are an exception */ - if ((a + 1) % nu->pntsu == 0) sel++; + if ((a + 1) % nu->pntsu == 0) { + sel++; + } else { bp--; if ((selbpoints[a + 1] == 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++; bp++; } - if ((a + 1) % nu->pntsu == 1) sel++; + if ((a + 1) % nu->pntsu == 1) { + sel++; + } else { bp++; if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; bp--; } - if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) sel++; + if (a + 1 > nu->pntsu * nu->pntsv - nu->pntsu) { + sel++; + } else { bp -= nu->pntsu; if ((selbpoints[a + nu->pntsu] == 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++; bp += nu->pntsu; } - - if (a < nu->pntsu) sel++; + + if (a < nu->pntsu) { + sel++; + } else { bp += nu->pntsu; if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; bp -= nu->pntsu; } - + if (sel != 4) { select_bpoint(bp, DESELECT, 1, VISIBLE); selbpoints[a] = 1; } } - else lastsel = 0; - + else { + lastsel = false; + } + bp++; } @@ -5390,26 +5424,29 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } else { for (nu = editnurb->first; nu; nu = nu->next) { - lastsel = 0; + lastsel = false; /* check what type of curve/nurb it is */ if (nu->type == CU_BEZIER) { a = nu->pntsu; bezt = nu->bezt; while (a--) { if ((bezt->hide == 0) && (bezt->f2 & SELECT)) { - if (lastsel == 1) sel = 1; - else sel = 0; - + sel = (lastsel == 1); + /* check if neighbors have been selected */ /* first and last are exceptions */ - if (a == nu->pntsu - 1) sel++; + if (a == nu->pntsu - 1) { + sel++; + } else { bezt--; if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++; bezt++; } - if (a == 0) sel++; + if (a == 0) { + sel++; + } else { bezt++; if ((bezt->hide == 0) && (bezt->f2 & SELECT)) sel++; @@ -5418,12 +5455,16 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) if (sel != 2) { select_beztriple(bezt, DESELECT, 1, VISIBLE); - lastsel = 1; + lastsel = true; + } + else { + lastsel = false; } - else lastsel = 0; } - else lastsel = 0; - + else { + lastsel = false; + } + bezt++; } } @@ -5436,28 +5477,36 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) else sel = 0; /* first and last are exceptions */ - if (a == nu->pntsu * nu->pntsv - 1) sel++; + if (a == nu->pntsu * nu->pntsv - 1) { + sel++; + } else { bp--; if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; bp++; } - if (a == 0) sel++; + if (a == 0) { + sel++; + } else { bp++; if ((bp->hide == 0) && (bp->f1 & SELECT)) sel++; bp--; } - + if (sel != 2) { select_bpoint(bp, DESELECT, 1, VISIBLE); - lastsel = 1; + lastsel = true; + } + else { + lastsel = false; } - else lastsel = 0; } - else lastsel = 0; - + else { + lastsel = false; + } + bp++; } } @@ -5820,7 +5869,7 @@ static int delete_exec(bContext *C, wmOperator *op) int delta = 0; bezt = nu->bezt; for (a = 0; a < nu->pntsu; a++) { - if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple)); keyIndex_delBezt(editnurb, bezt + delta); keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1); @@ -5829,7 +5878,9 @@ static int delete_exec(bContext *C, wmOperator *op) type = 1; delta++; } - else bezt++; + else { + bezt++; + } } if (type) { bezt1 = (BezTriple *)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb"); @@ -5889,16 +5940,16 @@ static int delete_exec(bContext *C, wmOperator *op) if (nu->type == CU_BEZIER) { bezt = nu->bezt; for (a = 0; a < nu->pntsu - 1; a++) { - if (BEZSELECTED_HIDDENHANDLES(cu, bezt) ) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { bezt1 = bezt; bezt2 = bezt + 1; if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { /* pass */ } else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) ) { + if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { bezt2 = bezt + (nu->pntsu - 1); - if ( (bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT) ) { + if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { nu->flagu &= ~CU_NURB_CYCLIC; BKE_nurb_handles_calc(nu); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); @@ -5925,7 +5976,7 @@ static int delete_exec(bContext *C, wmOperator *op) /* pass */ } else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC) ) { + if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { bp2 = bp + (nu->pntsu - 1); if (bp2->f1 & SELECT) { nu->flagu &= ~CU_NURB_CYCLIC; @@ -6046,7 +6097,7 @@ static int delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *obedit = CTX_data_edit_object(C); uiPopupMenu *pup; @@ -6187,10 +6238,12 @@ int join_curve_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->totcol) { /* TODO, merge material lists */ CLAMP(newnu->mat_nr, 0, ob->totcol - 1); } - else newnu->mat_nr = 0; + else { + newnu->mat_nr = 0; + } BLI_addtail(&tempbase, newnu); - if ( (bezt = newnu->bezt) ) { + if ((bezt = newnu->bezt)) { a = newnu->pntsu; while (a--) { mul_m4_v3(cmat, bezt->vec[0]); @@ -6200,7 +6253,7 @@ int join_curve_exec(bContext *C, wmOperator *UNUSED(op)) } BKE_nurb_handles_calc(newnu); } - if ( (bp = newnu->bp) ) { + if ((bp = newnu->bp)) { a = newnu->pntsu * nu->pntsv; while (a--) { mul_m4_v3(cmat, bp->vec); @@ -6653,14 +6706,18 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) if (type & CU_PRIM_PATH) cu->flag |= CU_PATH | CU_3D; } - else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + else { + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } } else { /* adding surface */ if (obedit == NULL || obedit->type != OB_SURF) { obedit = ED_object_add_type(C, OB_SURF, loc, rot, TRUE, layer); newob = 1; } - else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + else { + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } } /* rename here, the undo stack checks name for valid undo pushes */ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index af6b90a9958..63444c5c17e 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -405,7 +405,7 @@ static int paste_file_exec(bContext *C, wmOperator *op) return retval; } -static int paste_file_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int paste_file_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (RNA_struct_property_is_set(op->ptr, "filepath")) return paste_file_exec(C, op); @@ -1221,16 +1221,16 @@ static int insert_text_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditFont *ef = cu->editfont; static int accentcode = 0; - uintptr_t ascii = evt->ascii; - int alt = evt->alt, shift = evt->shift, ctrl = evt->ctrl; - int event = evt->type, val = evt->val; + uintptr_t ascii = event->ascii; + int alt = event->alt, shift = event->shift, ctrl = event->ctrl; + int event_type = event->type, event_val = event->val; wchar_t inserted_text[2] = {0}; if (RNA_struct_property_is_set(op->ptr, "text")) @@ -1243,26 +1243,26 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt) } /* tab should exit editmode, but we allow it to be typed using modifier keys */ - if (event == TABKEY) { + if (event_type == TABKEY) { if ((alt || ctrl || shift) == 0) return OPERATOR_PASS_THROUGH; else ascii = 9; } - if (event == BACKSPACEKEY) { + if (event_type == BACKSPACEKEY) { if (alt && cu->len != 0 && cu->pos > 0) accentcode = 1; return OPERATOR_PASS_THROUGH; } - if (val && (ascii || evt->utf8_buf[0])) { + if (event_val && (ascii || event->utf8_buf[0])) { /* handle case like TAB (== 9) */ if ( (ascii > 31 && ascii < 254 && ascii != 127) || (ascii == 13) || (ascii == 10) || (ascii == 8) || - (evt->utf8_buf[0])) + (event->utf8_buf[0])) { if (accentcode) { @@ -1272,8 +1272,8 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt) } accentcode = 0; } - else if (evt->utf8_buf[0]) { - BLI_strncpy_wchar_from_utf8(inserted_text, evt->utf8_buf, 1); + else if (event->utf8_buf[0]) { + BLI_strncpy_wchar_from_utf8(inserted_text, event->utf8_buf, 1); ascii = inserted_text[0]; insert_into_textbuf(obedit, ascii); accentcode = 0; @@ -1307,7 +1307,7 @@ static int insert_text_invoke(bContext *C, wmOperator *op, wmEvent *evt) } /* reset property? */ - if (val == 0) + if (event_val == 0) accentcode = 0; return OPERATOR_FINISHED; @@ -1643,7 +1643,7 @@ static int font_open_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { VFont *vfont = NULL; char *path; diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript index c17ab386fe6..d4e6ed4aff8 100644 --- a/source/blender/editors/datafiles/SConscript +++ b/source/blender/editors/datafiles/SConscript @@ -35,75 +35,75 @@ incs = "" # generated data files import os sources.extend(( - os.path.join(env['DATA_SOURCES'], "bfont.pfb.c"), - os.path.join(env['DATA_SOURCES'], "bfont.ttf.c"), - os.path.join(env['DATA_SOURCES'], "bmonofont.ttf.c"), + os.path.join(env['DATA_SOURCES'], "bfont.pfb.c"), + os.path.join(env['DATA_SOURCES'], "bfont.ttf.c"), + os.path.join(env['DATA_SOURCES'], "bmonofont.ttf.c"), - os.path.join(env['DATA_SOURCES'], "splash.png.c"), - os.path.join(env['DATA_SOURCES'], "blender_icons16.png.c"), - os.path.join(env['DATA_SOURCES'], "blender_icons32.png.c"), - os.path.join(env['DATA_SOURCES'], "prvicons.png.c"), + os.path.join(env['DATA_SOURCES'], "splash.png.c"), + os.path.join(env['DATA_SOURCES'], "blender_icons16.png.c"), + os.path.join(env['DATA_SOURCES'], "blender_icons32.png.c"), + os.path.join(env['DATA_SOURCES'], "prvicons.png.c"), - os.path.join(env['DATA_SOURCES'], "startup.blend.c"), - os.path.join(env['DATA_SOURCES'], "preview.blend.c"), - os.path.join(env['DATA_SOURCES'], "preview_cycles.blend.c"), - - os.path.join(env['DATA_SOURCES'], "add.png.c"), - os.path.join(env['DATA_SOURCES'], "blob.png.c"), - os.path.join(env['DATA_SOURCES'], "blur.png.c"), - os.path.join(env['DATA_SOURCES'], "clay.png.c"), - os.path.join(env['DATA_SOURCES'], "claystrips.png.c"), - os.path.join(env['DATA_SOURCES'], "clone.png.c"), - os.path.join(env['DATA_SOURCES'], "crease.png.c"), - os.path.join(env['DATA_SOURCES'], "darken.png.c"), - os.path.join(env['DATA_SOURCES'], "draw.png.c"), - os.path.join(env['DATA_SOURCES'], "fill.png.c"), - os.path.join(env['DATA_SOURCES'], "flatten.png.c"), - os.path.join(env['DATA_SOURCES'], "grab.png.c"), - os.path.join(env['DATA_SOURCES'], "inflate.png.c"), - os.path.join(env['DATA_SOURCES'], "layer.png.c"), - os.path.join(env['DATA_SOURCES'], "lighten.png.c"), - os.path.join(env['DATA_SOURCES'], "mask.png.c"), - os.path.join(env['DATA_SOURCES'], "mix.png.c"), - os.path.join(env['DATA_SOURCES'], "multiply.png.c"), - os.path.join(env['DATA_SOURCES'], "nudge.png.c"), - os.path.join(env['DATA_SOURCES'], "pinch.png.c"), - os.path.join(env['DATA_SOURCES'], "scrape.png.c"), - os.path.join(env['DATA_SOURCES'], "smear.png.c"), - os.path.join(env['DATA_SOURCES'], "smooth.png.c"), - os.path.join(env['DATA_SOURCES'], "snake_hook.png.c"), - os.path.join(env['DATA_SOURCES'], "soften.png.c"), - os.path.join(env['DATA_SOURCES'], "subtract.png.c"), - os.path.join(env['DATA_SOURCES'], "texdraw.png.c"), - os.path.join(env['DATA_SOURCES'], "thumb.png.c"), - os.path.join(env['DATA_SOURCES'], "twist.png.c"), - os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"), - - os.path.join(env['DATA_SOURCES'], "mc01.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc02.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc03.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc04.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc05.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc06.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc07.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc08.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc09.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc10.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc11.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc12.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc13.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc14.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc15.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc16.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc17.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc18.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc19.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc20.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc21.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc22.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc23.jpg.c"), - os.path.join(env['DATA_SOURCES'], "mc24.jpg.c"), + os.path.join(env['DATA_SOURCES'], "startup.blend.c"), + os.path.join(env['DATA_SOURCES'], "preview.blend.c"), + os.path.join(env['DATA_SOURCES'], "preview_cycles.blend.c"), - )) + os.path.join(env['DATA_SOURCES'], "add.png.c"), + os.path.join(env['DATA_SOURCES'], "blob.png.c"), + os.path.join(env['DATA_SOURCES'], "blur.png.c"), + os.path.join(env['DATA_SOURCES'], "clay.png.c"), + os.path.join(env['DATA_SOURCES'], "claystrips.png.c"), + os.path.join(env['DATA_SOURCES'], "clone.png.c"), + os.path.join(env['DATA_SOURCES'], "crease.png.c"), + os.path.join(env['DATA_SOURCES'], "darken.png.c"), + os.path.join(env['DATA_SOURCES'], "draw.png.c"), + os.path.join(env['DATA_SOURCES'], "fill.png.c"), + os.path.join(env['DATA_SOURCES'], "flatten.png.c"), + os.path.join(env['DATA_SOURCES'], "grab.png.c"), + os.path.join(env['DATA_SOURCES'], "inflate.png.c"), + os.path.join(env['DATA_SOURCES'], "layer.png.c"), + os.path.join(env['DATA_SOURCES'], "lighten.png.c"), + os.path.join(env['DATA_SOURCES'], "mask.png.c"), + os.path.join(env['DATA_SOURCES'], "mix.png.c"), + os.path.join(env['DATA_SOURCES'], "multiply.png.c"), + os.path.join(env['DATA_SOURCES'], "nudge.png.c"), + os.path.join(env['DATA_SOURCES'], "pinch.png.c"), + os.path.join(env['DATA_SOURCES'], "scrape.png.c"), + os.path.join(env['DATA_SOURCES'], "smear.png.c"), + os.path.join(env['DATA_SOURCES'], "smooth.png.c"), + os.path.join(env['DATA_SOURCES'], "snake_hook.png.c"), + os.path.join(env['DATA_SOURCES'], "soften.png.c"), + os.path.join(env['DATA_SOURCES'], "subtract.png.c"), + os.path.join(env['DATA_SOURCES'], "texdraw.png.c"), + os.path.join(env['DATA_SOURCES'], "thumb.png.c"), + os.path.join(env['DATA_SOURCES'], "twist.png.c"), + os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"), + + os.path.join(env['DATA_SOURCES'], "mc01.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc02.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc03.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc04.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc05.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc06.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc07.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc08.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc09.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc10.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc11.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc12.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc13.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc14.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc15.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc16.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc17.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc18.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc19.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc20.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc21.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc22.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc23.jpg.c"), + os.path.join(env['DATA_SOURCES'], "mc24.jpg.c"), + + )) env.BlenderLib ( 'bf_editor_datafiles', sources, Split(incs), [], libtype=['core', 'player'], priority=[235, 30] ) diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c index 0aa109a0aef..19c1bc34f5c 100644 --- a/source/blender/editors/gpencil/gpencil_buttons.c +++ b/source/blender/editors/gpencil/gpencil_buttons.c @@ -86,6 +86,29 @@ static void gp_ui_dellayer_cb(bContext *C, void *gpd, void *gpl) WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } +/* move layer up */ +static void gp_ui_layer_up_cb(bContext *C, void *gpd_v, void *gpl_v) +{ + bGPdata *gpd = gpd_v; + bGPDlayer *gpl = gpl_v; + + BLI_remlink(&gpd->layers, gpl); + BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); +} + +/* move layer down */ +static void gp_ui_layer_down_cb(bContext *C, void *gpd_v, void *gpl_v) +{ + bGPdata *gpd = gpd_v; + bGPDlayer *gpl = gpl_v; + + BLI_remlink(&gpd->layers, gpl); + BLI_insertlinkafter(&gpd->layers, gpl->next, gpl); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); +} /* ------- Drawing Code ------- */ @@ -174,6 +197,18 @@ static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, cons /* name */ uiItemR(sub, &ptr, "info", 0, "", ICON_NONE); + /* move up/down */ + if (gpl->prev) { + but = uiDefIconBut(block, BUT, 0, ICON_TRIA_UP, 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer up")); + uiButSetFunc(but, gp_ui_layer_up_cb, gpd, gpl); + } + if (gpl->next) { + but = uiDefIconBut(block, BUT, 0, ICON_TRIA_DOWN, 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Move layer down")); + uiButSetFunc(but, gp_ui_layer_down_cb, gpd, gpl); + } + /* delete 'button' */ uiBlockSetEmboss(block, UI_EMBOSSN); /* right-align ............................... */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 46815450bf2..bc68ad8869a 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -277,6 +277,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] int mval_prj[2]; float rvec[3], dvec[3]; float mval_f[2]; + float zfac; /* Current method just converts each point in screen-coordinates to * 3D-coordinates using the 3D-cursor as reference. In general, this @@ -288,12 +289,13 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] */ gp_get_3d_reference(p, rvec); + zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL); /* method taken from editview.c - mouse_cursor() */ /* TODO, use ED_view3d_project_float_global */ if (ED_view3d_project_int_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { VECSUB2D(mval_f, mval_prj, mval); - ED_view3d_win_to_delta(p->ar, mval_f, dvec); + ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac); sub_v3_v3v3(out, rvec, dvec); } else { @@ -1237,13 +1239,6 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode) switch (p->sa->spacetype) { case SPACE_VIEW3D: { - RegionView3D *rv3d = p->ar->regiondata; - float rvec[3]; - - /* get reference point for 3d space placement */ - gp_get_3d_reference(p, rvec); - initgrabz(rv3d, rvec[0], rvec[1], rvec[2]); - p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE; } break; @@ -1551,7 +1546,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) } /* handle draw event */ -static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event) +static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -1689,7 +1684,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* ------------------------------- */ /* start of interactive drawing part of operator */ -static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = NULL; wmWindow *win = CTX_wm_window(C); @@ -1800,7 +1795,7 @@ static void gpencil_stroke_end(wmOperator *op) } /* events handling during interactive drawing part of operator */ -static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) +static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = op->customdata; int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */ diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 31f89063f05..39d1e283f54 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -129,7 +129,7 @@ void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect); /** - * Functions like a limited glDrawPixels, but actually draws the + * glaDrawPixelsTex - Functions like a limited glDrawPixels, but actually draws the * image using textures, which can be tremendously faster on low-end * cards, and also avoids problems with the raster position being * clipped when offscreen. The routine respects the glPixelZoom values, @@ -141,9 +141,17 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo * 1-to-1 mapping to screen space. */ -void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect); +void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect); -void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY); +/** + * glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef. + * only RGBA + * needs glaDefine2DArea to be set. + */ +void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect); + + +void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect, float scaleX, float scaleY); /* 2D Drawing Assistance */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 414d2075bf6..625ef27f4f7 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -298,11 +298,14 @@ typedef enum eAnimFilter_Flags { #define SEL_MASKLAY(masklay) (masklay->flag & SELECT) - /* NLA only */ #define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED) #define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED) == 0) + +/* AnimData - NLA mostly... */ +#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED) + /* -------------- Channel Defines -------------- */ /* channel heights */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 30ac360cab6..310b60f13e8 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -61,7 +61,7 @@ typedef struct EditBone { * normal bones when leaving editmode. */ void *temp; /* Used to store temporary data */ - char name[64]; /* MAX_NAME */ + char name[64]; /* MAXBONENAME */ float roll; /* Roll along axis. We'll ultimately use the axis/angle method * for determining the transformation matrix of the bone. The axis * is tail-head while roll provides the angle. Refer to Graphics @@ -135,6 +135,7 @@ void ED_armature_validate_active(struct bArmature *arm); void add_primitive_bone(struct Scene *scene, struct View3D *v3d, struct RegionView3D *rv3d); struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name); void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone); +bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child); void transform_armature_mirror_update(struct Object *obedit); void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index d66cc49a5d0..66c1798f507 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -63,8 +63,6 @@ void load_editNurb(struct Object *obedit); void make_editNurb(struct Object *obedit); void free_editNurb(struct Object *obedit); -void BKE_curve_editNurb_free(struct Curve *cu); - int mouse_nurb(struct bContext *C, const int mval[2], int extend, int deselect, int toggle); struct Nurb *add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob); diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index d45504b3325..b7d9f811349 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -31,10 +31,11 @@ #ifndef __ED_FILESELECT_H__ #define __ED_FILESELECT_H__ -struct SpaceFile; struct ARegion; struct FileSelectParams; +struct SpaceFile; struct bContext; +struct wmWindowManager; #define FILE_LAYOUT_HOR 1 #define FILE_LAYOUT_VER 2 @@ -99,9 +100,9 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y); void ED_operatormacros_file(void); -void ED_fileselect_clear(struct bContext *C, struct SpaceFile *sfile); +void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile); -void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile); +void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile); int ED_file_extension_icon(const char *relname); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index d3de2593b9d..e704b8f0bf3 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -172,17 +172,10 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* renam extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; - /* mesh_ops.c */ void ED_operatortypes_mesh(void); void ED_operatormacros_mesh(void); void ED_keymap_mesh(struct wmKeyConfig *keyconf); -void ED_keymap_mesh(struct wmKeyConfig *keyconf); - - -/* spacetypes.c */ -void ED_spacetypes_init(void); - /* editmesh_tools.c (could be moved) */ void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEditMesh *em); @@ -193,13 +186,14 @@ void paintface_flush_flags(struct Object *ob); int paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], int extend, int deselect, int toggle); int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int select, int extend); void paintface_deselect_all_visible(struct Object *ob, int action, short flush_flags); -void paintface_select_linked(struct bContext *C, struct Object *ob, int mval[2], int mode); +void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], int mode); int paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); void paintface_hide(struct Object *ob, const int unselected); void paintface_reveal(struct Object *ob); void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags); +void paintvert_select_ungrouped(struct Object *ob, short extend, short flush_flags); void paintvert_flush_flags(struct Object *ob); /* mirrtopo */ diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h index 126ea13f0b2..e7d80d96f89 100644 --- a/source/blender/editors/include/ED_numinput.h +++ b/source/blender/editors/include/ED_numinput.h @@ -61,7 +61,7 @@ void initNumInput(NumInput *n); void outputNumInput(NumInput *n, char *str); short hasNumInput(NumInput *n); void applyNumInput(NumInput *n, float *vec); -char handleNumInput(NumInput *n, struct wmEvent *event); +char handleNumInput(NumInput *n, const struct wmEvent *event); #define NUM_MODAL_INCREMENT_UP 18 #define NUM_MODAL_INCREMENT_DOWN 19 diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 72208a8e93d..d073eaa5607 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -71,7 +71,6 @@ void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect); /* spaces */ -void ED_spacetypes_init(void); void ED_spacetypes_keymap(struct wmKeyConfig *keyconf); int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco); int ED_area_header_standardbuttons(const struct bContext *C, struct uiBlock *block, int yco); diff --git a/source/blender/editors/include/ED_sequencer.h b/source/blender/editors/include/ED_sequencer.h index 23d173aebdc..21477a72014 100644 --- a/source/blender/editors/include/ED_sequencer.h +++ b/source/blender/editors/include/ED_sequencer.h @@ -31,7 +31,7 @@ struct Scene; struct Sequence; struct SpaceSeq; -void ED_sequencer_select_sequence_single(struct Scene *scene, struct Sequence *seq, int deselect_all); +void ED_sequencer_select_sequence_single(struct Scene *scene, struct Sequence *seq, bool deselect_all); void ED_sequencer_deselect_all(struct Scene *scene); int ED_space_sequencer_maskedit_mask_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index c8521cb194a..a40cf90f7ad 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -34,6 +34,8 @@ struct ARegionType; struct bContext; +void ED_spacetypes_init(void); + /* the pluginnable API for export to editors */ /* calls for registering default spaces */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index a41aaca15bd..6101d03b946 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -151,7 +151,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags); /* view3d manipulators */ -int BIF_do_manipulator(struct bContext *C, struct wmEvent *event, struct wmOperator *op); +int BIF_do_manipulator(struct bContext *C, const struct wmEvent *event, struct wmOperator *op); void BIF_draw_manipulator(const struct bContext *C); /* Snapping */ @@ -177,12 +177,12 @@ typedef enum SnapMode { #define SNAP_MIN_DISTANCE 30 -int peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode); -int peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode); -int snapObjectsTransform(struct TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode); -int snapObjectsContext(struct bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode); -int snapNodesTransform(struct TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode); -int snapNodesContext(struct bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode); +bool peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode); +bool peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode); +bool snapObjectsTransform(struct TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode); +bool snapObjectsContext(struct bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode); +bool snapNodesTransform(struct TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode); +bool snapNodesContext(struct bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode); #endif diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index d89d66dd62c..470bbe616cf 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -39,7 +39,6 @@ struct BMVert; struct BPoint; struct Base; struct BezTriple; -struct BezTriple; struct BoundBox; struct EditBone; struct ImBuf; @@ -47,7 +46,6 @@ struct MVert; struct Main; struct MetaElem; struct Nurb; -struct Nurb; struct Object; struct RegionView3D; struct Scene; @@ -174,52 +172,58 @@ void pose_foreachScreenBone( /* view3d_project.c */ -void ED_view3d_project_float_v2_m4(const struct ARegion *a, const float co[3], float r_co[2], float mat[4][4]); -void ED_view3d_project_float_v3_m4(struct ARegion *a, const float co[3], float r_co[3], float mat[4][4]); +void ED_view3d_project_float_v2_m4(const struct ARegion *ar, const float co[3], float r_co[2], float mat[4][4]); +void ED_view3d_project_float_v3_m4(const struct ARegion *ar, const float co[3], float r_co[3], float mat[4][4]); -eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base); +eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base); /* *** short *** */ -eV3DProjStatus ED_view3d_project_short_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], short r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_short_global(struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_short_object(struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag); /* *** int *** */ -eV3DProjStatus ED_view3d_project_int_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], int r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_int_global(struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_int_object(struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag); /* *** float *** */ -eV3DProjStatus ED_view3d_project_float_ex(struct ARegion *ar, float perspmat[4][4], const int is_local, - const float co[3], float r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_float_global(struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); -eV3DProjStatus ED_view3d_project_float_object(struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); - -int initgrabz(struct RegionView3D *rv3d, float x, float y, float z); -void ED_view3d_win_to_ray(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]); -void ED_view3d_global_to_vector(struct RegionView3D *rv3d, const float coord[3], float vec[3]); -void ED_view3d_win_to_3d(struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); -void ED_view3d_win_to_delta(struct ARegion *ar, const float mval[2], float out[3]); -void ED_view3d_win_to_vector(struct ARegion *ar, const float mval[2], float out[3]); -void ED_view3d_win_to_segment(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]); -int ED_view3d_win_to_segment_clip(struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]); -void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); +eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *ar, float perspmat[4][4], const bool is_local, + const float co[3], float r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); +eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); + +float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); +void ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]); +void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); +void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); +void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); +void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); +void ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]); +int ED_view3d_win_to_segment_clip(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]); +void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z); /* end */ -int ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, float *clipsta, float *clipend); -int ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *viewplane, float *clipsta, float *clipend); -void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, struct rctf *viewborder_r, short no_shift); -void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, float size_r[2]); +bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, + float *r_clipsta, float *r_clipend, const bool use_ortho_factor); +bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, + struct rctf *r_viewplane, float *r_clipsta, float *r_clipend); +void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, + struct View3D *v3d, struct RegionView3D *rv3d, + struct rctf *viewborder_r, const bool no_shift); +void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, + struct View3D *v3d, struct RegionView3D *rv3d, + float r_size[2]); void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect); void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]); -int ED_view3d_clipping_test(struct RegionView3D *rv3d, const float vec[3], const int is_local); +int ED_view3d_clipping_test(struct RegionView3D *rv3d, const float co[3], const bool is_local); void ED_view3d_clipping_set(struct RegionView3D *rv3d); void ED_view3d_clipping_enable(void); void ED_view3d_clipping_disable(void); @@ -255,7 +259,8 @@ short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigne void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc); void view3d_operator_needs_opengl(const struct bContext *C); void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar); -int view3d_get_view_aligned_coordinate(struct ViewContext *vc, float fp[3], const int mval[2], const short do_fallback); +bool view3d_get_view_aligned_coordinate(struct ARegion *ar, float fp[3], const int mval[2], const bool do_fallback); +void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data); void view3d_get_transformation(const struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats); /* XXX should move to BLI_math */ @@ -285,7 +290,7 @@ void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]); struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, short do_clip); void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]); -int ED_view3d_lock(struct RegionView3D *rv3d); +bool ED_view3d_lock(struct RegionView3D *rv3d); uint64_t ED_view3d_datamask(struct Scene *scene, struct View3D *v3d); uint64_t ED_view3d_screen_datamask(struct bScreen *screen); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 450d97eb20e..2ac66fb1919 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -87,6 +87,7 @@ enum { TH_TRANSFORM, TH_VERTEX, TH_VERTEX_SELECT, + TH_VERTEX_UNREFERENCED, TH_VERTEX_SIZE, TH_OUTLINE_WIDTH, TH_EDGE, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 2c17a629ed4..4f0d788d733 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -231,7 +231,9 @@ static void ui_text_bounds_block(uiBlock *block, float offset) nextcol = 1; col++; } - else nextcol = 0; + else { + nextcol = 0; + } bt->rect.xmin = x1addval; bt->rect.xmax = bt->rect.xmin + i + block->bounds; @@ -1461,6 +1463,8 @@ double ui_get_but_val(uiBut *but) if (but->rnaprop) { prop = but->rnaprop; + BLI_assert(but->rnaindex != -1); + switch (RNA_property_type(prop)) { case PROP_BOOLEAN: if (RNA_property_array_check(prop)) @@ -1642,6 +1646,9 @@ static double ui_get_but_scale_unit(uiBut *but, double value) if (unit_type == PROP_UNIT_LENGTH) { return value * (double)unit->scale_length; } + else if (unit_type == PROP_UNIT_CAMERA) { + return value * (double)unit->scale_length; + } else if (unit_type == PROP_UNIT_AREA) { return value * pow(unit->scale_length, 2); } @@ -1674,18 +1681,28 @@ void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) } } -static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad) +/** + * \param float_precision Override the button precision. + */ +static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad, int float_precision) { UnitSettings *unit = but->block->unit; int do_split = unit->flag & USER_UNIT_OPT_SPLIT; int unit_type = uiButGetUnitType(but); - int precision = but->a2; + int precision; if (unit->scale_length < 0.0001f) unit->scale_length = 1.0f; // XXX do_versions - /* Sanity checks */ - if (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX; - else if (precision == 0) precision = 2; + /* Use precision override? */ + if (float_precision == -1) { + /* Sanity checks */ + precision = (int)but->a2; + if (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX; + else if (precision == 0) precision = 2; + } + else { + precision = float_precision; + } bUnit_AsString(str, len_max, ui_get_but_scale_unit(but, value), precision, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type), do_split, pad); @@ -1706,8 +1723,10 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) } } - -void ui_get_but_string(uiBut *but, char *str, size_t maxlen) +/** + * \param float_precision For number buttons the precission to use or -1 to fallback to the button default. + */ +void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) { if (but->rnaprop && ELEM4(but->type, TEX, IDPOIN, SEARCH_MENU, SEARCH_MENU_UNLINK)) { PropertyType type; @@ -1779,10 +1798,10 @@ void ui_get_but_string(uiBut *but, char *str, size_t maxlen) if (ui_is_but_float(but)) { if (ui_is_but_unit(but)) { - ui_get_but_string_unit(but, str, maxlen, value, 0); + ui_get_but_string_unit(but, str, maxlen, value, 0, float_precision); } else { - const int prec = ui_but_float_precision(but, value); + const int prec = (float_precision == -1) ? ui_but_float_precision(but, value) : float_precision; BLI_snprintf(str, maxlen, "%.*f", prec, value); } } @@ -1790,6 +1809,10 @@ void ui_get_but_string(uiBut *but, char *str, size_t maxlen) BLI_snprintf(str, maxlen, "%d", (int)value); } } +void ui_get_but_string(uiBut *but, char *str, const size_t maxlen) +{ + ui_get_but_string_ex(but, str, maxlen, -1); +} #ifdef WITH_PYTHON @@ -1984,7 +2007,8 @@ static double soft_range_round_down(double value, double max) return newmax; } -void ui_set_but_soft_range(uiBut *but, double value) +/* note: this could be split up into functions which handle arrays and not */ +static void ui_set_but_soft_range(uiBut *but) { /* ideally we would not limit this but practically, its more then * enough worst case is very long vectors wont use a smart soft-range @@ -1993,14 +2017,14 @@ void ui_set_but_soft_range(uiBut *but, double value) if (but->rnaprop) { const PropertyType type = RNA_property_type(but->rnaprop); double softmin, softmax /*, step, precision*/; - double value_min = value; - double value_max = value; + double value_min; + double value_max; /* clamp button range to something reasonable in case * we get -inf/inf from RNA properties */ if (type == PROP_INT) { + const bool is_array = RNA_property_array_check(but->rnaprop); int imin, imax, istep; - const int array_len = RNA_property_array_length(&but->rnapoin, but->rnaprop); RNA_property_int_ui_range(&but->rnapoin, but->rnaprop, &imin, &imax, &istep); softmin = (imin == INT_MIN) ? -1e4 : imin; @@ -2008,16 +2032,19 @@ void ui_set_but_soft_range(uiBut *but, double value) /*step = istep;*/ /*UNUSED*/ /*precision = 1;*/ /*UNUSED*/ - if (array_len >= 2) { + if (is_array) { int value_range[2]; RNA_property_int_get_array_range(&but->rnapoin, but->rnaprop, value_range); value_min = (double)value_range[0]; value_max = (double)value_range[1]; } + else { + value_min = value_max = (double)RNA_property_int_get(&but->rnapoin, but->rnaprop); + } } else if (type == PROP_FLOAT) { + const bool is_array = RNA_property_array_check(but->rnaprop); float fmin, fmax, fstep, fprecision; - const int array_len = RNA_property_array_length(&but->rnapoin, but->rnaprop); RNA_property_float_ui_range(&but->rnapoin, but->rnaprop, &fmin, &fmax, &fstep, &fprecision); softmin = (fmin == -FLT_MAX) ? (float)-1e4 : fmin; @@ -2025,15 +2052,19 @@ void ui_set_but_soft_range(uiBut *but, double value) /*step = fstep;*/ /*UNUSED*/ /*precision = fprecision;*/ /*UNUSED*/ - if (array_len >= 2) { + if (is_array) { float value_range[2]; RNA_property_float_get_array_range(&but->rnapoin, but->rnaprop, value_range); value_min = (double)value_range[0]; value_max = (double)value_range[1]; } + else { + value_min = value_max = (double)RNA_property_float_get(&but->rnapoin, but->rnaprop); + } } - else + else { return; + } /* if the value goes out of the soft/max range, adapt the range */ if (value_min + 1e-10 < softmin) { @@ -2260,8 +2291,7 @@ void ui_check_but(uiBut *but) /* only update soft range while not editing */ if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) { - UI_GET_BUT_VALUE_INIT(but, value); - ui_set_but_soft_range(but, value); + ui_set_but_soft_range(but); } /* test for min and max, icon sliders, etc */ @@ -2345,7 +2375,7 @@ void ui_check_but(uiBut *but) /* support length type buttons */ else if (ui_is_but_unit(but)) { char new_str[sizeof(but->drawstr)]; - ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE); + ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE, -1); BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, new_str); } else { @@ -2530,7 +2560,9 @@ static void ui_block_do_align_but(uiBut *first, short nr) else flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT; } - else flag = UI_BUT_ALIGN_TOP; + else { + flag = UI_BUT_ALIGN_TOP; + } } } else if (buts_are_horiz(but, next)) { @@ -2550,7 +2582,9 @@ static void ui_block_do_align_but(uiBut *first, short nr) if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT; } } - else flag |= UI_BUT_ALIGN_LEFT; + else { + flag |= UI_BUT_ALIGN_LEFT; + } } else { if (cols == 0) { @@ -2712,8 +2746,8 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, but->retval = retval; slen = strlen(str); - if (slen >= UI_MAX_NAME_STR - 1) { - but->str = MEM_mallocN(slen + 2, "ui_def_but str"); /* why +2 ? */ + if (slen >= UI_MAX_NAME_STR) { + but->str = MEM_mallocN(slen + 1, "ui_def_but str"); } else { but->str = but->strdata; @@ -3016,7 +3050,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType * } #if 0 /* UNUSED */ -static uiBut *UNUSED_FUNCTION(ui_def_but_operator) (uiBlock * block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip) +static uiBut *UNUSED_FUNCTION(ui_def_but_operator) (uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip) { wmOperatorType *ot = WM_operatortype_find(opname, 0); if (str == NULL && ot == NULL) str = opname; diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index e19e89af5da..5486e12c6bf 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -97,7 +97,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r } glVertex2f(maxx, miny + rad); } - else glVertex2f(maxx, miny); + else { + glVertex2f(maxx, miny); + } /* corner right-top */ if (roundboxtype & UI_CNR_TOP_RIGHT) { @@ -107,7 +109,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r } glVertex2f(maxx - rad, maxy); } - else glVertex2f(maxx, maxy); + else { + glVertex2f(maxx, maxy); + } /* corner left-top */ if (roundboxtype & UI_CNR_TOP_LEFT) { @@ -117,7 +121,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r } glVertex2f(minx, maxy - rad); } - else glVertex2f(minx, maxy); + else { + glVertex2f(minx, maxy); + } /* corner left-bottom */ if (roundboxtype & UI_CNR_BOTTOM_LEFT) { @@ -127,7 +133,9 @@ void uiDrawBox(int mode, float minx, float miny, float maxx, float maxy, float r } glVertex2f(minx + rad, miny); } - else glVertex2f(minx, miny); + else { + glVertex2f(minx, miny); + } glEnd(); } @@ -381,16 +389,7 @@ void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad) /* (old, used in outliner) plain antialiased filled box */ void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad) { - float color[4]; - - if (roundboxtype & UI_RB_ALPHA) { - glGetFloatv(GL_CURRENT_COLOR, color); - color[3] = 0.5; - glColor4fv(color); - glEnable(GL_BLEND); - } - - ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad); + ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA); } @@ -454,8 +453,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w float facy = (float)h / (float)ibuf->y; glPixelZoom(facx, facy); } - glaDrawPixelsSafe((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); - //glaDrawPixelsTex((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect); + glaDrawPixelsAuto((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect); glPixelZoom(1.0f, 1.0f); @@ -1301,8 +1299,10 @@ void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, rcti *rect) glEndList(); } - else glCallList(displist); - + else { + glCallList(displist); + } + /* restore */ glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); @@ -1602,7 +1602,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc tmpibuf = BKE_tracking_sample_pattern(scopes->frame_width, scopes->frame_height, scopes->track_search, scopes->track, - &scopes->undist_marker, scopes->use_track_mask, + &scopes->undist_marker, TRUE, scopes->use_track_mask, width, height, scopes->track_pos); if (tmpibuf) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e0d6c293be5..12a6343c7e7 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -235,14 +235,13 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val) BLI_assert(*type == MOUSEPAN); /* sign differs, reset */ - if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0)) + if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0)) { lastdy = dy; + } else { lastdy += dy; if (ABS(lastdy) > (int)UI_UNIT_Y) { - int dy = event->prevy - event->y; - if (U.uiflag2 & USER_TRACKPAD_NATURAL) dy = -dy; @@ -804,8 +803,6 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const * button we mouse over is X or Y aligned, then lock the mouse to that axis after. */ if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) { - ARegion *ar = CTX_wm_region(C); - /* first store the buttons original coords */ uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]); if (but) { @@ -1402,7 +1399,11 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, /* pass */ } else if (mode == 'c') { - ui_get_but_string(but, buf, sizeof(buf)); + /* Get many decimal places, then strip trailing zeros. + * note: too high values start to give strange results (6 or so is ok) */ + ui_get_but_string_ex(but, buf, sizeof(buf), 6); + BLI_str_rstrip_float_zero(buf, '\0'); + WM_clipboard_text_set(buf, 0); } else { @@ -1984,6 +1985,10 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str"); ui_get_but_string(but, data->str, data->maxlen); + if (ui_is_but_float(but) && !ui_is_but_unit(but)) { + BLI_str_rstrip_float_zero(data->str, '\0'); + } + if (ELEM3(but->type, NUM, NUMABS, NUMSLI)) { ui_convert_to_unit_alt_name(but, data->str, data->maxlen); } @@ -2327,7 +2332,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) data->coba = (ColorBand *)but->poin; but->editcoba = data->coba; } - else if (ELEM3(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE)) { + else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) { ui_get_but_vectorf(but, data->origvec); copy_v3_v3(data->vec, data->origvec); but->editvec = data->vec; @@ -3149,9 +3154,6 @@ static bool ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data, BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval); } #endif - if (is_horizontal == false) { - mx_fl = my_fl; - } /* done correcting mouse */ @@ -5013,7 +5015,7 @@ static int ui_but_menu(bContext *C, uiBut *but) uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); if (but->rnapoin.data && but->rnaprop) { - short is_anim = RNA_property_animateable(&but->rnapoin, but->rnaprop); + bool is_anim = RNA_property_animateable(&but->rnapoin, but->rnaprop); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -6294,7 +6296,7 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) { uiHandleButtonData *data = but->active; - const uiButtonActivateType state_orig = data->state; + const uiHandleButtonState state_orig = data->state; uiBlock *block; ARegion *ar; int retval; @@ -6466,9 +6468,9 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) * This is needed to make sure if a button was active, * it stays active while the mouse is over it. * This avoids adding mousemoves, see: [#33466] */ - if (ELEM(state_orig, BUTTON_ACTIVATE, BUTTON_ACTIVATE_OVER)) { + if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) { if (ui_but_find_mouse_over(ar, event->x, event->y) == but) { - button_activate_init(C, ar, but, state_orig); + button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); } } } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 086e9dad895..09686d7b416 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -47,6 +47,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_fileops_types.h" #include "DNA_brush_types.h" #include "DNA_dynamicpaint_types.h" @@ -703,10 +704,8 @@ static void init_iconfile_list(struct ListBase *list) { IconFile *ifile; struct direntry *dir; - int restoredir = 1; /* restore to current directory */ int totfile, i, index = 1; const char *icondir; - char olddir[FILE_MAX]; list->first = list->last = NULL; icondir = BLI_get_folder(BLENDER_DATAFILES, "icons"); @@ -714,12 +713,7 @@ static void init_iconfile_list(struct ListBase *list) if (icondir == NULL) return; - /* since BLI_dir_contents changes the current working directory, restore it - * back to old value afterwards */ - if (!BLI_current_working_dir(olddir, sizeof(olddir))) - restoredir = 0; totfile = BLI_dir_contents(icondir, &dir); - if (restoredir && !chdir(olddir)) {} /* fix warning about checking return value */ for (i = 0; i < totfile; i++) { if ((dir[i].type & S_IFREG)) { @@ -766,18 +760,8 @@ static void init_iconfile_list(struct ListBase *list) } } } - - /* free temporary direntry structure that's been created by BLI_dir_contents() */ - i = totfile - 1; - - for (; i >= 0; i--) { - MEM_freeN(dir[i].relname); - MEM_freeN(dir[i].path); - if (dir[i].string) { - MEM_freeN(dir[i].string); - } - } - free(dir); + + BLI_free_filelist(dir, totfile); dir = NULL; } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 9093e8f8d30..6065fcfe574 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -394,7 +394,8 @@ extern void ui_set_but_vectorf(uiBut *but, const float vec[3]); extern void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect, const float mx, const float my); -extern void ui_get_but_string(uiBut *but, char *str, size_t maxlen); +extern void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision); +extern void ui_get_but_string(uiBut *but, char *str, const size_t maxlen); extern void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen); extern int ui_set_but_string(struct bContext *C, uiBut *but, const char *str); extern int ui_get_but_string_max_length(uiBut *but); @@ -402,8 +403,6 @@ extern int ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char extern void ui_set_but_default(struct bContext *C, short all); -extern void ui_set_but_soft_range(uiBut *but, double value); - extern void ui_check_but(uiBut *but); extern int ui_is_but_float(uiBut *but); extern int ui_is_but_bool(uiBut *but); @@ -523,7 +522,7 @@ extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiB /* interface_widgets.c */ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad); +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha); void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect); uiWidgetColors *ui_tooltip_get_theme(void); void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock * block, rcti * rect); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 1e95b4df762..2ca26ae5317 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1567,7 +1567,7 @@ void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const } if (!name) { - name = IFACE_(mt->label); + name = CTX_IFACE_(mt->translation_context, mt->label); } if (layout->root->type == UI_LAYOUT_MENU && !icon) @@ -2369,6 +2369,7 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, int align) litem->active = 1; litem->enabled = 1; litem->context = layout->context; + litem->redalert = layout->redalert; BLI_addtail(&layout->items, litem); uiBlockSetCurLayout(layout->root->block, litem); @@ -2396,6 +2397,7 @@ uiLayout *uiLayoutOverlap(uiLayout *layout) litem->active = 1; litem->enabled = 1; litem->context = layout->context; + litem->redalert = layout->redalert; BLI_addtail(&layout->items, litem); uiBlockSetCurLayout(layout->root->block, litem); @@ -2415,6 +2417,7 @@ uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align) split->litem.enabled = 1; split->litem.context = layout->context; split->litem.space = layout->root->style->columnspace; + split->litem.redalert = layout->redalert; split->litem.w = layout->w; split->percentage = percentage; BLI_addtail(&layout->items, split); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 3298859ee0c..145deb35667 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -239,7 +239,7 @@ static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, } /* main modal status check */ -static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event) +static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) { Eyedropper *eye = (Eyedropper *)op->customdata; @@ -285,7 +285,7 @@ static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event) } /* Modal Operator init */ -static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { /* init */ if (eyedropper_init(C, op)) { @@ -853,7 +853,7 @@ static int editsource_exec(bContext *C, wmOperator *op) ED_region_do_draw(C, ar); for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash); - !BLI_ghashIterator_isDone(&ghi); + BLI_ghashIterator_notDone(&ghi); BLI_ghashIterator_step(&ghi)) { uiBut *but_key = BLI_ghashIterator_getKey(&ghi); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index e466c481151..a741ea432a5 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -191,7 +191,7 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar) Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, int *open) { Panel *pa, *patab, *palast, *panext; - char *drawname = pt->label; + const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); char *idname = pt->idname; char *tabname = pt->idname; char *hookname = NULL; @@ -469,7 +469,7 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, rcti *r Panel *panel = block->panel; rcti hrect; int pnl_icons; - const char *activename = IFACE_(panel->drawname[0] ? panel->drawname : panel->panelname); + const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname; /* + 0.001f to avoid flirting with float inaccuracy */ if (panel->control & UI_PNL_CLOSE) pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 03c127f33c8..febd1820e5c 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -663,9 +663,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) /* since the text has beens caled already, the size of tooltips is defined now */ /* here we try to figure out the right location */ if (butregion) { - float ofsx = rect_fl.xmin, ofsy = rect_fl.ymax; - ui_block_to_window_fl(butregion, but->block, &ofsx, &ofsy); - BLI_rctf_translate(&rect_fl, ofsx - rect_fl.xmin, ofsy - rect_fl.ymax); + float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax; + ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl); + BLI_rctf_translate(&rect_fl, ofsx_fl - rect_fl.xmin, ofsy_fl - rect_fl.ymax); } BLI_rcti_rctf_copy(&rect_i, &rect_fl); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index ef24ea951e3..dd4886a7243 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -216,7 +216,7 @@ void uiStyleFontDrawRotated(uiFontStyle *fs, rcti *rect, const char *str) /* rotate counter-clockwise for now (assumes left-to-right language)*/ xofs += height; yofs = BLF_width(fs->uifont_id, str) + 5; - angle = 90.0f; + angle = (float)M_PI / 2.0f; /* translate rect to vertical */ txtrect.xmin = rect->xmin - BLI_rcti_size_y(rect); @@ -330,6 +330,8 @@ void uiStyleInit(void) { uiFont *font = U.uifonts.first; uiStyle *style = U.uistyles.first; + int monofont_size = datatoc_bmonofont_ttf_size; + unsigned char *monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf; /* recover from uninitialized dpi */ if (U.dpi == 0) @@ -400,15 +402,33 @@ void uiStyleInit(void) ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); } +#ifdef WITH_INTERNATIONAL + /* use unicode font for text editor and interactive console */ + if (U.transopts & USER_DOTRANSLATE) { + monofont_ttf = BLF_get_unifont_mono(&monofont_size); + + if (!monofont_ttf) { + /* fall back if not found */ + monofont_size = datatoc_bmonofont_ttf_size; + monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf; + } + } + + /* reload */ + BLF_unload("monospace"); + blf_mono_font = -1; + blf_mono_font_render = -1; +#endif + /* XXX, this should be moved into a style, but for now best only load the monospaced font once. */ if (blf_mono_font == -1) - blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size); + blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); BLF_size(blf_mono_font, 12 * U.pixelsize, 72); /* second for rendering else we get threading problems */ if (blf_mono_font_render == -1) - blf_mono_font_render = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size); + blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72 ); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 83540cef9fc..afb44101910 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -281,11 +281,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) if (id->flag & LIB_FAKEUSER) id_us_plus(id); else id_us_min(id); } - else return; + else { + return; + } break; case UI_ID_LOCAL: if (id) { - if (id_make_local(id, 0)) { + if (id_make_local(id, false)) { /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); @@ -465,7 +467,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str else { but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local")); - if (!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib)) + if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib)) uiButSetFlag(but, UI_BUT_DISABLED); } @@ -483,7 +485,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE)); if (/* test only */ - (id_copy(id, NULL, 1) == FALSE) || + (id_copy(id, NULL, true) == false) || (idfrom && idfrom->lib) || (editable == FALSE) || /* object in editmode - don't change data */ @@ -676,7 +678,7 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co const char *text) { PropertyRNA *propID, *propType; - uiLayout *row; + uiLayout *split, *row, *sub; /* get properties... */ propID = RNA_struct_find_property(ptr, propname); @@ -692,22 +694,34 @@ void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, co } /* Start drawing UI Elements using standard defines */ - row = uiLayoutRow(layout, TRUE); + split = uiLayoutSplit(layout, 0.33f, FALSE); /* NOTE: split amount here needs to be synced with normal labels */ + + /* FIRST PART ................................................ */ + row = uiLayoutRow(split, FALSE); /* Label - either use the provided text, or will become "ID-Block:" */ if (text) { if (text[0]) uiItemL(row, text, ICON_NONE); } - else + else { uiItemL(row, IFACE_("ID-Block:"), ICON_NONE); + } + + /* SECOND PART ................................................ */ + row = uiLayoutRow(split, TRUE); /* ID-Type Selector - just have a menu of icons */ - /* FIXME: the icon-only setting doesn't work when we supply a blank name */ - uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + sub = uiLayoutRow(row, TRUE); /* HACK: special group just for the enum, otherwise we */ + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); /* we get ugly layout with text included too... */ + + uiItemFullR(sub, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* ID-Block Selector - just use pointer widget... */ - uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NONE); + sub = uiLayoutRow(row, TRUE); /* HACK: special group to counteract the effects of the previous */ + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_EXPAND); /* enum, which now pushes everything too far right */ + + uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE); } /********************* RNA Path Builder Template ********************/ @@ -2135,10 +2149,10 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe uiLayoutRow(layout, TRUE); uiBlockSetNFunc(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap); - bt = uiDefButF(block, NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, - &cmp->x, bounds.xmin, bounds.xmax, 1, 5, ""); - bt = uiDefButF(block, NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, - &cmp->y, bounds.ymin, bounds.ymax, 1, 5, ""); + uiDefButF(block, NUM, 0, "X", 0, 2 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, + &cmp->x, bounds.xmin, bounds.xmax, 1, 5, ""); + uiDefButF(block, NUM, 0, "Y", 0, 1 * UI_UNIT_Y, UI_UNIT_X * 10, UI_UNIT_Y, + &cmp->y, bounds.ymin, bounds.ymax, 1, 5, ""); } /* black/white levels */ @@ -2727,7 +2741,7 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char { GHashIterator *iter = WM_operatortype_iter(); - for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) { wmOperatorType *ot = BLI_ghashIterator_getValue(iter); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index dd7b1d0ee06..78b6d2541fd 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -218,13 +218,16 @@ void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y glDisable(GL_BLEND); } -void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad) +void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha) { float color[4]; int j; glEnable(GL_BLEND); glGetFloatv(GL_CURRENT_COLOR, color); + if (use_alpha) { + color[3] = 0.5f; + } color[3] *= 0.125f; glColor4fv(color); @@ -1289,7 +1292,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) { ui_text_clip_left(fstyle, but, rect); } - else but->ofs = 0; + else { + but->ofs = 0; + } /* check for button text label */ if (but->type == ICONTEXTROW) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index acea6e133f4..09122737373 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -279,6 +279,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->vertex; break; case TH_VERTEX_SELECT: cp = ts->vertex_select; break; + case TH_VERTEX_UNREFERENCED: + cp = ts->vertex_unreferenced; break; case TH_VERTEX_SIZE: cp = &ts->vertex_size; break; case TH_OUTLINE_WIDTH: @@ -445,7 +447,6 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_HANDLE_VERTEX_SIZE: cp = &ts->handle_vertex_size; break; - case TH_DOPESHEET_CHANNELOB: cp = ts->ds_channel; break; @@ -718,6 +719,8 @@ void ui_theme_init_default(void) /* space view3d */ btheme->tv3d.panelcolors.show_back = FALSE; btheme->tv3d.panelcolors.show_header = FALSE; + rgba_char_args_set_fl(btheme->tv3d.panelcolors.back, 0.45, 0.45, 0.45, 0.5); + rgba_char_args_set_fl(btheme->tv3d.panelcolors.header, 0, 0, 0, 0.01); rgba_char_args_set_fl(btheme->tv3d.back, 0.225, 0.225, 0.225, 1.0); rgba_char_args_set(btheme->tv3d.text, 0, 0, 0, 255); rgba_char_args_set(btheme->tv3d.text_hi, 255, 255, 255, 255); @@ -742,6 +745,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255); rgba_char_args_set(btheme->tv3d.vertex, 0, 0, 0, 255); rgba_char_args_set(btheme->tv3d.vertex_select, 255, 133, 0, 255); + rgba_char_args_set(btheme->tv3d.vertex_unreferenced, 0, 0, 0, 255); btheme->tv3d.vertex_size = 3; btheme->tv3d.outline_width = 1; rgba_char_args_set(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255); @@ -1376,7 +1380,7 @@ void init_userdef_do_versions(void) /* signal for derivedmesh to use colorband */ /* run in case this was on and is now off in the user prefs [#28096] */ - vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL); + vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL, UI_GetTheme()->tv3d.vertex_unreferenced); if (bmain->versionfile <= 191) { strcpy(U.sounddir, "/"); diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index ad6428c7e80..8a6de9a549b 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -457,8 +457,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ if (ABS(winx - v2d->oldwinx) > ABS(winy - v2d->oldwiny)) do_y = FALSE; else do_x = FALSE; } - else if (winRatio > 1.0f) do_x = FALSE; - else do_x = TRUE; + else if (winRatio > 1.0f) { + do_x = FALSE; + } + else { + do_x = TRUE; + } } do_cur = do_x; /* do_win = do_y; */ /* UNUSED */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index daa78957231..e283bd1351a 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -187,7 +187,7 @@ static int view_pan_exec(bContext *C, wmOperator *op) } /* set up modal operator and relevant settings */ -static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); v2dViewPanData *vpd; @@ -231,7 +231,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */ -static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) +static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) { v2dViewPanData *vpd = op->customdata; @@ -700,7 +700,7 @@ static int view_zoomin_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_zoomin_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event) { v2dViewZoomData *vzd; @@ -769,7 +769,7 @@ static int view_zoomout_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_zoomout_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event) { v2dViewZoomData *vzd; @@ -924,7 +924,7 @@ static int view_zoomdrag_exec(bContext *C, wmOperator *op) } /* set up modal operator and relevant settings */ -static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); v2dViewZoomData *vzd; @@ -1005,7 +1005,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */ -static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event) { v2dViewZoomData *vzd = op->customdata; View2D *v2d = vzd->v2d; @@ -1328,7 +1328,7 @@ void UI_view2d_smooth_view(bContext *C, ARegion *ar, } /* only meant for timer usage */ -static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; @@ -1488,7 +1488,7 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_ } /* initialize customdata for scroller manipulation operator */ -static void scroller_activate_init(bContext *C, wmOperator *op, wmEvent *event, short in_scroller) +static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, short in_scroller) { v2dScrollerMove *vsm; View2DScrollers *scrollers; @@ -1637,7 +1637,7 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) } /* handle user input for scrollers - calculations of mouse-movement need to be done here, not in the apply callback! */ -static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) +static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *event) { v2dScrollerMove *vsm = op->customdata; @@ -1707,7 +1707,7 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, wmEvent *event) /* a click (or click drag in progress) should have occurred, so check if it happened in scrollbar */ -static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 4908c101a7c..c673e0fb2b0 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -56,7 +56,7 @@ #include "io_collada.h" -static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!RNA_struct_property_is_set(op->ptr, "filepath")) { char filepath[FILE_MAX]; @@ -95,6 +95,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int triangulate; int use_object_instantiation; int sort_by_name; + int export_transformation_type; int second_life; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { @@ -115,14 +116,15 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only"); include_uv_textures = RNA_boolean_get(op->ptr, "include_uv_textures"); - include_material_textures= RNA_boolean_get(op->ptr, "include_material_textures"); + include_material_textures = RNA_boolean_get(op->ptr, "include_material_textures"); use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies"); active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only"); - triangulate = RNA_boolean_get(op->ptr, "triangulate"); - use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); - sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name"); - second_life = RNA_boolean_get(op->ptr, "second_life"); + triangulate = RNA_boolean_get(op->ptr, "triangulate"); + use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); + sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name"); + export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection"); + second_life = RNA_boolean_get(op->ptr, "second_life"); /* get editmode results */ ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */ @@ -145,6 +147,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) triangulate, use_object_instantiation, sort_by_name, + export_transformation_type, second_life)) { return OPERATOR_FINISHED; @@ -224,6 +227,12 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE); row = uiLayoutRow(box, FALSE); uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE); + + row = uiLayoutRow(box, FALSE); + split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT); + uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); + uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE); + row = uiLayoutRow(box, FALSE); uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE); @@ -245,6 +254,13 @@ void WM_OT_collada_export(wmOperatorType *ot) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_bc_export_transformation_type[] = { + {BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use <matrix> to specify transformations"}, + {BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use <translate>, <rotate>, <scale> to specify transformations"}, + {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use <matrix> AND <translate>, <rotate>, <scale> to specify transformations"}, + {0, NULL, 0, NULL, NULL} + }; + ot->name = "Export COLLADA"; ot->description = "Save a Collada file"; ot->idname = "WM_OT_collada_export"; @@ -308,6 +324,12 @@ void WM_OT_collada_export(wmOperatorType *ot) RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); + RNA_def_int(ot->srna, "export_transformation_type", 0, INT_MIN, INT_MAX, + "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX); + + RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0, + "Transform", "Transformation type for translation, scale and rotation"); + RNA_def_boolean(ot->srna, "second_life", 0, "Export for Second Life", "Compatibility mode for Second Life"); } diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 77abe43bba7..33a6aa2d43d 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -629,7 +629,7 @@ static int add_vertex_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int add_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -703,7 +703,7 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int add_feather_vertex_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 0a996c11f14..ff8e27ac264 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -438,7 +438,7 @@ static int slide_point_check_initial_feather(MaskSpline *spline) return TRUE; } -static void *slide_point_customdata(bContext *C, wmOperator *op, wmEvent *event) +static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -525,7 +525,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, wmEvent *event) return customdata; } -static int slide_point_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SlidePointData *slidedata = slide_point_customdata(C, op, event); @@ -634,7 +634,7 @@ static void free_slide_point_data(SlidePointData *data) MEM_freeN(data); } -static int slide_point_modal(bContext *C, wmOperator *op, wmEvent *event) +static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) { SlidePointData *data = (SlidePointData *)op->customdata; BezTriple *bezt = &data->point->bezt; diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index cd1a47754f8..ccc2fad5f52 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -361,7 +361,7 @@ static int select_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH; } -static int select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); @@ -689,7 +689,7 @@ void MASK_OT_select_circle(wmOperatorType *ot) RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); } -static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index b51d55aaf0e..a76872d6e30 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenlib ../../blenloader ../../bmesh + ../../gpu ../../imbuf ../../makesdna ../../makesrna @@ -43,6 +44,7 @@ set(SRC editmesh_add.c editmesh_bvh.c editmesh_knife.c + editmesh_knife_project.c editmesh_loopcut.c editmesh_rip.c editmesh_select.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 7ddf2b54a88..260d01d726a 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -294,7 +294,7 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind MEM_freeN(linkflag); } -void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2]), int mode) +void paintface_select_linked(bContext *UNUSED(C), Object *ob, const int UNUSED(mval[2]), int mode) { Mesh *me; unsigned int index = 0; @@ -525,7 +525,9 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in else mpoly_sel->flag |= ME_FACE_SEL; } - else mpoly_sel->flag |= ME_FACE_SEL; + else { + mpoly_sel->flag |= ME_FACE_SEL; + } /* image window redraw */ @@ -568,7 +570,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); rt = ibuf->rect; - glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); a = sx * sy; @@ -710,6 +712,37 @@ void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags) } } +void paintvert_select_ungrouped(Object *ob, short extend, short flush_flags) +{ + Mesh *me = BKE_mesh_from_object(ob); + MVert *mv; + MDeformVert *dv; + int a, tot; + + if (me == NULL || me->dvert == NULL) { + return; + } + + if (!extend) { + paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); + } + + dv = me->dvert; + tot = me->totvert; + + for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) { + if ((mv->flag & ME_HIDE) == 0) { + if (dv->dw == NULL) { + /* if null weight then not grouped */ + mv->flag |= SELECT; + } + } + } + + if (flush_flags) { + paintvert_flush_flags(ob); + } +} /* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ /* note, this is not the best place for the function to be but moved diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index a356f9fca7f..174715495f6 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -32,15 +32,14 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "BLI_math.h" #include "BKE_context.h" #include "BKE_library.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index d7dbe3506b1..b5b6a92cbf5 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_array.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_smallhash.h" #include "BLI_memarena.h" @@ -90,7 +91,8 @@ typedef struct KnifeVert { ListBase faces; float co[3], cageco[3], sco[3]; /* sco is screen coordinates for cageco */ - short flag, draw, isface, inspace; + bool is_face, in_space; + bool draw; } KnifeVert; typedef struct Ref { @@ -102,9 +104,9 @@ typedef struct KnifeEdge { KnifeVert *v1, *v2; BMFace *basef; /* face to restrict face fill to */ ListBase faces; - int draw; - BMEdge *e, *oe; /* non-NULL if this is an original edge */ + BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */ + bool draw; } KnifeEdge; typedef struct BMEdgeHit { @@ -128,7 +130,7 @@ typedef struct KnifePosData { KnifeVert *vert; KnifeEdge *edge; BMFace *bmface; - int is_space; + bool is_space; float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */ } KnifePosData; @@ -137,7 +139,8 @@ typedef struct KnifePosData { typedef struct KnifeTool_OpData { ARegion *ar; /* region that knifetool was activated in */ void *draw_handle; /* for drawing preview loop */ - ViewContext vc; + ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */ + float mval[2]; /* mouse value with snapping applied */ //bContext *C; Object *ob; @@ -173,12 +176,15 @@ typedef struct KnifeTool_OpData { KnifeColors colors; + /* run by the UI or not */ + bool is_interactive; + /* operatpr options */ - char cut_through; /* preference, can be modified at runtime (that feature may go) */ - char only_select; /* set on initialization */ - char select_result; /* set on initialization */ + bool cut_through; /* preference, can be modified at runtime (that feature may go) */ + bool only_select; /* set on initialization */ + bool select_result; /* set on initialization */ - short is_ortho; + bool is_ortho; float ortho_extent; float clipsta, clipend; @@ -189,8 +195,10 @@ typedef struct KnifeTool_OpData { MODE_PANNING } mode; - int snap_midpoints, prevmode, extend; - int ignore_edge_snapping, ignore_vert_snapping; + int prevmode; + bool snap_midpoints, extend; + bool ignore_edge_snapping; + bool ignore_vert_snapping; enum { ANGLE_FREE, @@ -228,14 +236,16 @@ static void knife_update_header(bContext *C, KnifeTool_OpData *kcd) ED_area_headerprint(CTX_wm_area(C), header); } +#if 0 BLI_INLINE int round_ftoi(float x) { return x > 0.0f ? (int)(x + 0.5f) : (int)(x - 0.5f); } +#endif -static void knife_project_v3(KnifeTool_OpData *kcd, const float co[3], float sco[3]) +static void knife_project_v3(const KnifeTool_OpData *kcd, const float co[3], float sco[3]) { - ED_view3d_project_float_v3_m4(kcd->ar, co, sco, kcd->projmat); + ED_view3d_project_float_v3_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat); } static void knife_pos_data_clear(KnifePosData *kpd) @@ -245,8 +255,7 @@ static void knife_pos_data_clear(KnifePosData *kpd) kpd->vert = NULL; kpd->edge = NULL; kpd->bmface = NULL; - kpd->mval[0] = 0.0f; - kpd->mval[1] = 0.0f; + zero_v2(kpd->mval); } static ListBase *knife_empty_list(KnifeTool_OpData *kcd) @@ -494,7 +503,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge) return; - kfe->draw = 1; + kfe->draw = true; if (kcd->prev.vert) { kfe->v1 = kcd->prev.vert; @@ -505,9 +514,9 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) else { kfe->v1 = new_knife_vert(kcd, kcd->prev.co, kcd->prev.co); kfe->v1->draw = kfe->draw = !kcd->prev.is_space; - kfe->v1->inspace = kcd->prev.is_space; + kfe->v1->in_space = kcd->prev.is_space; kfe->draw = !kcd->prev.is_space; - kfe->v1->isface = 1; + kfe->v1->is_face = true; if (kfe->v1->draw && kcd->prev.bmface) knife_append_list(kcd, &kfe->v1->faces, kcd->prev.bmface); } @@ -522,13 +531,13 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) else { kfe->v2 = new_knife_vert(kcd, kcd->curr.co, kcd->curr.co); kfe->v2->draw = !kcd->curr.is_space; - kfe->v2->isface = 1; - kfe->v2->inspace = kcd->curr.is_space; + kfe->v2->is_face = true; + kfe->v2->in_space = kcd->curr.is_space; if (kfe->v2->draw && kcd->curr.bmface) knife_append_list(kcd, &kfe->v2->faces, kcd->curr.bmface); if (kcd->curr.is_space) - kfe->draw = 0; + kfe->draw = false; kcd->curr.vert = kfe->v2; } @@ -632,11 +641,10 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K KnifeEdge *kfenew; kfenew = new_knife_edge(kcd); - kfenew->draw = 1; kfenew->basef = f; kfenew->v1 = v1; kfenew->v2 = v2; - kfenew->draw = 1; + kfenew->draw = true; knife_add_to_vert_edges(kcd, kfenew); @@ -650,7 +658,7 @@ static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace * BMFace *f; Ref *r; - if (kfv->isface && facef) { + if (kfv->is_face && facef) { knife_append_list(kcd, lst, facef); } else if (kfv->v) { @@ -689,7 +697,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd) ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL}; Ref *r, *r2; KnifeEdge **splitkfe; - int i, j, found; + int i, j; if (!kcd->totlinehit) { /* if no linehits then no interesting back face stuff to do */ @@ -727,15 +735,15 @@ static void knife_cut_through(KnifeTool_OpData *kcd) /* For each face incident to firstv, * find the first following linehit (if any) sharing that face and connect */ for (r = firstfaces.first; r; r = r->next) { + bool found = false; f = r->ref; - found = 0; for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) { kfe2 = lh2->kfe; for (r2 = kfe2->faces.first; r2; r2 = r2->next) { if (r2->ref == f) { v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); knife_add_single_cut_through(kcd, firstv, v2, f); - found = 1; + found = true; break; } } @@ -757,8 +765,8 @@ static void knife_cut_through(KnifeTool_OpData *kcd) /* For each face attached to edge for this linehit, * find the first following linehit (if any) sharing that face and connect */ for (r = kfe->faces.first; r; r = r->next) { + bool found = false; f = r->ref; - found = 0; for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) { kfe2 = lh2->kfe; for (r2 = kfe2->faces.first; r2; r2 = r2->next) { @@ -766,7 +774,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd) v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); knife_add_single_cut_through(kcd, v1, v2, f); - found = 1; + found = true; break; } } @@ -890,7 +898,7 @@ static void knife_finish_cut(KnifeTool_OpData *UNUSED(kcd)) } -static void knifetool_draw_angle_snapping(KnifeTool_OpData *kcd) +static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) { bglMats mats; double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy; @@ -1006,7 +1014,7 @@ static void knife_init_colors(KnifeColors *colors) static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) { View3D *v3d = CTX_wm_view3d(C); - KnifeTool_OpData *kcd = arg; + const KnifeTool_OpData *kcd = arg; if (v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -1062,7 +1070,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (kcd->totlinehit > 0) { const float vthresh4 = kcd->vthresh / 4.0f; - const float vthresh4_squared = vthresh4 * vthresh4; + const float vthresh4_sq = vthresh4 * vthresh4; BMEdgeHit *lh; int i; @@ -1082,12 +1090,12 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) knife_project_v3(kcd, lh->kfe->v2->cageco, sv2); knife_project_v3(kcd, lh->cagehit, lh->schit); - if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) { + if (len_squared_v2v2(lh->schit, sv1) < vthresh4_sq) { copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v1; } - else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) { + else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_sq) { copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v2; @@ -1179,7 +1187,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ const float depsilon = (FLT_EPSILON / 2.0f) * len_v3_tri_side_max(v1, v2, v3); - const float depsilon_squared = depsilon * depsilon; + const float depsilon_sq = depsilon * depsilon; copy_v3_v3(cos + 0, v1); copy_v3_v3(cos + 3, v2); @@ -1213,14 +1221,14 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda); - if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_squared) { + if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) { continue; } - if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared) { + if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_sq) { continue; } - if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared || - len_squared_v3v3(kcd->curr.cage, p) < depsilon_squared) + if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_sq || + len_squared_v3v3(kcd->curr.cage, p) < depsilon_sq) { continue; } @@ -1266,8 +1274,8 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) { BMEdgeHit hit; - if (len_squared_v3v3(p, kcd->curr.co) < depsilon_squared || - len_squared_v3v3(p, kcd->prev.co) < depsilon_squared) + if (len_squared_v3v3(p, kcd->curr.co) < depsilon_sq || + len_squared_v3v3(p, kcd->prev.co) < depsilon_sq) { continue; } @@ -1381,7 +1389,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) knife_project_v3(kcd, v1, s1); knife_project_v3(kcd, v2, s2); - if (len_v2v2(s1, s2) < 1) + if (len_squared_v2v2(s1, s2) < 1) return; /* unproject screen line */ @@ -1481,7 +1489,7 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], mul_m4_v3(kcd->ob->imat, r_origin_ofs); } -static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], int *is_space) +static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], bool *is_space) { BMFace *f; float dist = KMAXDIST; @@ -1499,13 +1507,15 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float *is_space = !f; if (!f) { - /* try to use backbuffer selection method if ray casting failed */ - f = EDBM_face_find_nearest(&kcd->vc, &dist); + if (kcd->is_interactive) { + /* try to use backbuffer selection method if ray casting failed */ + f = EDBM_face_find_nearest(&kcd->vc, &dist); - /* cheat for now; just put in the origin instead - * of a true coordinate on the face. - * This just puts a point 1.0f infront of the view. */ - add_v3_v3v3(co, origin, ray); + /* cheat for now; just put in the origin instead + * of a true coordinate on the face. + * This just puts a point 1.0f infront of the view. */ + add_v3_v3v3(co, origin, ray); + } } return f; @@ -1513,18 +1523,21 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float /* find the 2d screen space density of vertices within a radius. used to scale snapping * distance for picking edges/verts.*/ -static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) +static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius) { BMFace *f; - int is_space; + bool is_space; float co[3], cageco[3], sco[3]; + BLI_assert(kcd->is_interactive == true); + f = knife_find_closest_face(kcd, co, cageco, &is_space); if (f && !is_space) { + const float radius_sq = radius * radius; ListBase *lst; Ref *ref; - float dis; + float dis_sq; int c = 0; knife_project_v3(kcd, cageco, sco); @@ -1539,8 +1552,8 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) knife_project_v3(kcd, kfv->cageco, kfv->sco); - dis = len_v2v2(kfv->sco, sco); - if (dis < radius) { + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < radius_sq) { if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) { c++; @@ -1563,7 +1576,14 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) * surrounding mesh (in screen space)*/ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) { - float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + float density; + + if (kcd->is_interactive) { + density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + } + else { + density = 1.0f; + } if (density < 1.0f) density = 1.0f; @@ -1572,7 +1592,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) } /* p is closest point on edge to the mouse cursor */ -static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, int *is_space) +static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space) { BMFace *f; float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh); @@ -1668,7 +1688,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo /* find a vertex near the mouse cursor, if it exists */ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, - int *is_space) + bool *is_space) { BMFace *f; float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh); @@ -1684,10 +1704,11 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo kcd->curr.bmface = f; if (f) { + const float maxdist_sq = maxdist * maxdist; ListBase *lst; Ref *ref; KnifeVert *curv = NULL; - float dis, curdis = FLT_MAX; + float dis_sq, curdis_sq = FLT_MAX; knife_project_v3(kcd, cageco, sco); @@ -1701,17 +1722,17 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo knife_project_v3(kcd, kfv->cageco, kfv->sco); - dis = len_v2v2(kfv->sco, sco); - if (dis < curdis && dis < maxdist) { + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) { curv = kfv; - curdis = dis; + curdis_sq = dis_sq; } } else { curv = kfv; - curdis = dis; + curdis_sq = dis_sq; } } } @@ -1747,7 +1768,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo return NULL; } -/* update both kcd->curr.mval and kcd->vc.mval to snap to required angle */ +/* update both kcd->curr.mval and kcd->mval to snap to required angle */ static void knife_snap_angle(KnifeTool_OpData *kcd) { float dx, dy; @@ -1784,16 +1805,14 @@ static void knife_snap_angle(KnifeTool_OpData *kcd) kcd->curr.mval[0] = kcd->prev.mval[0]; } - kcd->vc.mval[0] = round_ftoi(kcd->curr.mval[0]); - kcd->vc.mval[1] = round_ftoi(kcd->curr.mval[1]); + copy_v2_v2(kcd->mval, kcd->curr.mval); } /* update active knife edge/vert pointers */ static int knife_update_active(KnifeTool_OpData *kcd) { knife_pos_data_clear(&kcd->curr); - kcd->curr.mval[0] = (float)kcd->vc.mval[0]; - kcd->curr.mval[1] = (float)kcd->vc.mval[1]; + copy_v2_v2(kcd->curr.mval, kcd->mval); if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) knife_snap_angle(kcd); @@ -1994,14 +2013,14 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) i++; if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) { - kfe->oe = kfe->e; + kfe->e_old = kfe->e; continue; } j++; if (kfe->e) { - kfe->oe = kfe->e; + kfe->e_old = kfe->e; BMO_elem_flag_enable(bm, kfe->e, DEL); BMO_elem_flag_disable(bm, kfe->e, BOUNDARY); @@ -2027,13 +2046,13 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace) continue; - if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2)) + if (!(kfe->e_old && kfe->v1->v == kfe->e_old->v1 && kfe->v2->v == kfe->e_old->v2)) continue; k++; BMO_elem_flag_enable(bm, kfe->e, BOUNDARY); - kfe->oe = kfe->e; + kfe->e_old = kfe->e; for (ref = kfe->faces.first; ref; ref = ref->next) { f = ref->ref; @@ -2096,7 +2115,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) if (sf_vert->poly_nr > 1 && sf_vert_last->poly_nr > 1) { ScanFillEdge *sf_edge; sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); - if (entry->kfe->oe) + if (entry->kfe->e_old) sf_edge->f = SF_EDGE_BOUNDARY; /* mark as original boundary edge */ BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL); @@ -2239,15 +2258,15 @@ static void sort_by_frac_along(ListBase *lst, BMEdge *e) /* The chain so far goes from an instantiated vertex to kfv (some may be reversed). * If possible, complete the chain to another instantiated vertex and return 1, else return 0. * The visited hash says which KnifeVert's have already been tried, not including kfv. */ -static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited, - ListBase *chain) +static bool find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited, + ListBase *chain) { Ref *r; KnifeEdge *kfe; KnifeVert *kfv_other; if (kfv->v) - return TRUE; + return true; BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL); /* Try all possible next edges. Could either go through fedges @@ -2264,22 +2283,22 @@ static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fe if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) { knife_append_list(kcd, chain, kfe); if (find_chain_search(kcd, kfv_other, fedges, visited, chain)) - return TRUE; + return true; BLI_remlink(chain, chain->last); } } - return FALSE; + return false; } static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges) { SmallHash visited_, *visited = &visited_; ListBase *ans; - int found; + bool found; ans = knife_empty_list(kcd); knife_append_list(kcd, ans, kfe); - found = 0; + found = false; BLI_smallhash_init(visited); if (kfe->v1->v == v) { BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL); @@ -2340,15 +2359,15 @@ static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges) /* The hole so far goes from kfvfirst to kfv (some may be reversed). * If possible, complete the hole back to kfvfirst and return 1, else return 0. * The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */ -static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges, - SmallHash *visited, ListBase *hole) +static bool find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges, + SmallHash *visited, ListBase *hole) { Ref *r; KnifeEdge *kfe, *kfelast; KnifeVert *kfv_other; if (kfv == kfvfirst) - return TRUE; + return true; BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL); kfelast = ((Ref *)hole->last)->ref; @@ -2366,11 +2385,11 @@ static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVer if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) { knife_append_list(kcd, hole, kfe); if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole)) - return TRUE; + return true; BLI_remlink(hole, hole->last); } } - return FALSE; + return false; } /* Find a hole (simple cycle with no instantiated vertices). @@ -2381,10 +2400,10 @@ static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges) Ref *r, *ref; KnifeEdge *kfe; SmallHash visited_, *visited = &visited_; - int found; + bool found; ans = NULL; - found = FALSE; + found = false; for (r = fedges->first; r && !found; r = r->next) { kfe = r->ref; @@ -2853,10 +2872,8 @@ static void knife_make_cuts(KnifeTool_OpData *kcd) #endif /* called on tool confirmation */ -static void knifetool_finish(wmOperator *op) +static void knifetool_finish_ex(KnifeTool_OpData *kcd) { - KnifeTool_OpData *kcd = op->customdata; - #if SCANFILL_CUTS knifenet_fill_faces(kcd); #else @@ -2866,19 +2883,10 @@ static void knifetool_finish(wmOperator *op) EDBM_mesh_normals_update(kcd->em); EDBM_update_generic(kcd->em, TRUE, TRUE); } - -/* copied from paint_image.c */ -static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) +static void knifetool_finish(wmOperator *op) { - int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); - - if (orth) { /* only needed for ortho */ - float fac = 2.0f / ((*clipend) - (*clipsta)); - *clipsta *= fac; - *clipend *= fac; - } - - return orth; + KnifeTool_OpData *kcd = op->customdata; + knifetool_finish_ex(kcd); } static void knife_recalc_projmat(KnifeTool_OpData *kcd) @@ -2887,22 +2895,22 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd) ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat); //mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat); - kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d, - &kcd->clipsta, &kcd->clipend); + kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d, + &kcd->clipsta, &kcd->clipend, true); } /* called when modal loop selection is done... */ -static void knifetool_exit(bContext *C, wmOperator *op) +static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) { - KnifeTool_OpData *kcd = op->customdata; - if (!kcd) return; - WM_cursor_restore(CTX_wm_window(C)); + if (kcd->is_interactive) { + WM_cursor_restore(CTX_wm_window(C)); - /* deactivate the extra drawing stuff in 3D-View */ - ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + } /* free the custom data */ BLI_mempool_destroy(kcd->refs); @@ -2927,6 +2935,11 @@ static void knifetool_exit(bContext *C, wmOperator *op) /* destroy kcd itself */ MEM_freeN(kcd); +} +static void knifetool_exit(bContext *C, wmOperator *op) +{ + KnifeTool_OpData *kcd = op->customdata; + knifetool_exit_ex(C, kcd); op->customdata = NULL; } @@ -2944,35 +2957,36 @@ static void cage_mapped_verts_callback(void *userData, int index, const float co } } -static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval_i[2]) +static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2]) { knife_recalc_projmat(kcd); - kcd->vc.mval[0] = mval_i[0]; - kcd->vc.mval[1] = mval_i[1]; + copy_v2_v2(kcd->mval, mval); if (knife_update_active(kcd)) { ED_region_tag_redraw(kcd->ar); } } +static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2]) +{ + float mval[2] = {UNPACK2(mval_i)}; + knifetool_update_mval(kcd, mval); +} + /* called when modal loop selection gets set up... */ -static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) +static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, + const bool only_select, const bool cut_through, const bool is_interactive) { - KnifeTool_OpData *kcd; Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); DerivedMesh *cage, *final; SmallHash shash; void *data[3]; - const short only_select = RNA_boolean_get(op->ptr, "only_selected"); - - /* alloc new customdata */ - kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), "knifetool Modal Op Data"); /* assign the drawing handle for drawing preview line... */ kcd->ob = obedit; kcd->ar = CTX_wm_region(C); - kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); + em_setup_viewcontext(C, &kcd->vc); kcd->em = BMEdit_FromObject(kcd->ob); @@ -2998,7 +3012,7 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) kcd->vthresh = KMAXDIST - 1; kcd->ethresh = KMAXDIST; - kcd->extend = 1; + kcd->extend = true; knife_recalc_projmat(kcd); @@ -3013,7 +3027,8 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) kcd->kedgefacemap = BLI_ghash_ptr_new("knife origvertmap"); /* cut all the way through the mesh if use_occlude_geometry button not pushed */ - kcd->cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + kcd->is_interactive = is_interactive; + kcd->cut_through = cut_through; kcd->only_select = only_select; /* can't usefully select resulting edges in face mode */ @@ -3022,9 +3037,11 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) knife_pos_data_clear(&kcd->curr); knife_pos_data_clear(&kcd->prev); - knife_init_colors(&kcd->colors); + if (is_interactive) { + kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); - return 1; + knife_init_colors(&kcd->colors); + } } static int knifetool_cancel(bContext *C, wmOperator *op) @@ -3034,21 +3051,25 @@ static int knifetool_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int knifetool_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); + const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + KnifeTool_OpData *kcd; view3d_operator_needs_opengl(C); - if (!knifetool_init(C, op, 0)) - return OPERATOR_CANCELLED; + /* alloc new customdata */ + kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through, true); /* add a modal handler for this operator - handles loop selection */ WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR); WM_event_add_modal_handler(C, op); - kcd = op->customdata; - knifetool_update_mval(kcd, evt->mval); + knifetool_update_mval_i(kcd, event->mval); knife_update_header(C, kcd); @@ -3119,11 +3140,11 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) +static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); KnifeTool_OpData *kcd = op->customdata; - int do_refresh = FALSE; + bool do_refresh = false; if (!obedit || obedit->type != OB_MESH || BMEdit_FromObject(obedit) != kcd->em) { knifetool_exit(C, op); @@ -3158,7 +3179,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_FINISHED; case KNF_MODAL_MIDPOINT_ON: - kcd->snap_midpoints = 1; + kcd->snap_midpoints = true; knife_recalc_projmat(kcd); knife_update_active(kcd); @@ -3167,7 +3188,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) do_refresh = TRUE; break; case KNF_MODAL_MIDPOINT_OFF: - kcd->snap_midpoints = 0; + kcd->snap_midpoints = false; knife_recalc_projmat(kcd); knife_update_active(kcd); @@ -3177,13 +3198,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) break; case KNF_MODEL_IGNORE_SNAP_ON: ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1; + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true; knife_update_header(C, kcd); do_refresh = TRUE; break; case KNF_MODEL_IGNORE_SNAP_OFF: ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0; + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false; knife_update_header(C, kcd); do_refresh = TRUE; break; @@ -3241,7 +3262,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) case MOUSEMOVE: /* mouse moved somewhere to select another loop */ if (kcd->mode != MODE_PANNING) { - knifetool_update_mval(kcd, event->mval); + knifetool_update_mval_i(kcd, event->mval); } break; @@ -3251,7 +3272,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) if (do_refresh) { /* we don't really need to update mval, * but this happens to be the best way to refresh at the moment */ - knifetool_update_mval(kcd, event->mval); + knifetool_update_mval_i(kcd, event->mval); } /* keep going until the user confirms */ @@ -3277,3 +3298,229 @@ void MESH_OT_knife_tool(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry"); RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry"); } + + +/* -------------------------------------------------------------------- */ +/* Knife tool as a utility function + * that can be used for internal slicing operations */ + +/** + * Return a point inside the face. + * + * tessellation here seems way overkill, + * but without this its very hard to know of a point is inside the face + */ +static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3]) +{ + int tottri = f->len - 2; + BMLoop **loops = BLI_array_alloca(loops, f->len); + int (*index)[3] = BLI_array_alloca(index, tottri); + int j; + + float const *best_co[3] = {NULL}; + float best_area = -1.0f; + bool ok = false; + + tottri = BM_face_calc_tessellation(f, loops, index); + BLI_assert(tottri <= f->len - 2); + + for (j = 0; j < tottri; j++) { + const float *p1 = loops[index[j][0]]->v->co; + const float *p2 = loops[index[j][1]]->v->co; + const float *p3 = loops[index[j][2]]->v->co; + float area; + + float cross[3]; + cross_v3_v3v3(cross, p2, p3); + area = fabsf(dot_v3v3(p1, cross)); + if (area > best_area) { + best_co[0] = p1; + best_co[1] = p2; + best_co[2] = p3; + best_area = area; + ok = true; + } + } + + if (ok) { + mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]); + } + else { + mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co); + } +} + +static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4]) +{ + float cent_ss[2]; + float cent[3]; + + edvm_mesh_knife_face_point(f, cent); + + ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat); + + /* check */ + { + LinkNode *p = polys; + int isect = 0; + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1); + p = p->next; + } + + if (isect % 2) { + return true; + } + } + + return false; +} + +/** + * \param use_tag When set, tag all faces inside the polylines. + */ +void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag) +{ + KnifeTool_OpData *kcd; + + view3d_operator_needs_opengl(C); + + /* init */ + { + const bool only_select = false; + const bool cut_through = false; + const bool is_interactive = false; /* can enable for testing */ + + kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through, is_interactive); + + kcd->ignore_edge_snapping = true; + kcd->ignore_vert_snapping = true; + + if (use_tag) { + BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); + } + } + + /* execute */ + { + LinkNode *p = polys; + + knife_recalc_projmat(kcd); + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + int i; + + for (i = 0; i < mval_tot; i++) { + knifetool_update_mval(kcd, mval_fl[i]); + if (i == 0) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + else { + knife_add_cut(kcd); + } + } + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + p = p->next; + } + } + + /* finish */ + { + knifetool_finish_ex(kcd); + + /* tag faces inside! */ + if (use_tag) { + BMesh *bm = kcd->em->bm; + float projmat[4][4]; + + BMEdge *e; + BMIter iter; + + bool keep_search; + + ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat); + + /* use face-loop tag to store if we have intersected */ +#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) +#define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) +#define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) + { + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + F_ISECT_SET_UNKNOWN(f); + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + } + + /* tag all faces linked to cut edges */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check are we tagged?, then we are an original face */ + if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { + BMFace *f; + BMIter fiter; + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + } + } + } + + /* expand tags for faces which are not cut, but are inside the polys */ + do { + BMFace *f; + keep_search = false; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) { + /* am I connected to a tagged face via an un-tagged edge (ie, not across a cut) */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + bool found = false; + + do { + if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { + /* now check if the adjacent faces is tagged */ + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + found = true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && (found == false)); + } + } + } while ((l_iter = l_iter->next) != l_first && (found == false)); + + if (found) { + if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + keep_search = true; + } + else { + /* don't loose time on this face again, set it as outside */ + F_ISECT_SET_OUTSIDE(f); + } + } + } + } + } while (keep_search); + +#undef F_ISECT_IS_UNKNOWN +#undef F_ISECT_SET_UNKNOWN +#undef F_ISECT_SET_OUTSIDE + + } + + knifetool_exit_ex(C, kcd); + kcd = NULL; + } +} diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c new file mode 100644 index 00000000000..c581ce5a2e8 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -0,0 +1,168 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_knife_project.c + * \ingroup edmesh + */ + +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" + +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_tessmesh.h" +#include "BKE_report.h" + +#include "MEM_guardedalloc.h" + +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "mesh_intern.h" + + +static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys) +{ + DerivedMesh *dm; + bool dm_needsFree; + + if (ob->type == OB_MESH || ob->derivedFinal) { + dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + dm_needsFree = false; + } + else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + dm = CDDM_from_curve(ob); + dm_needsFree = true; + } + else { + dm = NULL; + } + + if (dm) { + ListBase nurbslist = {NULL, NULL}; + float projmat[4][4]; + + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */ + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */ + + ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); + + if (nurbslist.first) { + Nurb *nu; + for (nu = nurbslist.first; nu; nu = nu->next) { + if (nu->bp) { + int a; + BPoint *bp; + bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; + float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); + + for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { + ED_view3d_project_float_v3_m4(ar, bp->vec, mval[a], projmat); + } + if (is_cyclic) { + copy_v2_v2(mval[a], mval[0]); + } + + BLI_linklist_prepend(&polys, mval); + } + } + } + + BKE_nurbList_free(&nurbslist); + + if (dm_needsFree) { + dm->release(dm); + } + } + + + return polys; +} + +static int knifeproject_exec(bContext *C, wmOperator *op) +{ + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + + LinkNode *polys = NULL; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + if (ob != obedit) { + polys = knifeproject_poly_from_object(ar, scene, ob, polys); + } + } + CTX_DATA_END; + + if (polys) { + EDBM_mesh_knife(C, polys, true); + + /* select only tagged faces */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG); + + BM_mesh_select_mode_flush(em->bm); + + BLI_linklist_freeN(polys); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection"); + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_knife_project(wmOperatorType *ot) +{ + /* description */ + ot->name = "Knife Project"; + ot->idname = "MESH_OT_knife_project"; + ot->description = "Use other objects outlines & boundaries to project knife cuts"; + + /* callbacks */ + ot->exec = knifeproject_exec; + ot->poll = ED_operator_editmesh_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; +} + diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 83542915ec2..5b9864ca239 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -385,7 +385,7 @@ static int ringcut_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); Object *obedit = CTX_data_edit_object(C); @@ -405,8 +405,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) WM_event_add_modal_handler(C, op); lcd = op->customdata; - lcd->vc.mval[0] = evt->mval[0]; - lcd->vc.mval[1] = evt->mval[1]; + copy_v2_v2_int(lcd->vc.mval, event->mval); edge = EDBM_edge_find_nearest(&lcd->vc, &dist); if (edge != lcd->eed) { @@ -419,7 +418,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_RUNNING_MODAL; } -static int loopcut_modal(bContext *C, wmOperator *op, wmEvent *event) +static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) { float smoothness = RNA_float_get(op->ptr, "smoothness"); int cuts = RNA_int_get(op->ptr, "number_cuts"); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 6cbf5e88cee..8198e088e5a 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -33,9 +33,6 @@ #include "DNA_object_types.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "BLI_math.h" #include "BLI_array.h" @@ -43,6 +40,9 @@ #include "BKE_report.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" + #include "WM_types.h" #include "ED_mesh.h" @@ -499,16 +499,9 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); } else { - if (v_shared == f_verts[0]) { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); - } - else { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); - } + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); } } @@ -538,7 +531,7 @@ static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op) /** * This is the main vert ripping function (rip when one vertex is selected) */ -static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event) { const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; @@ -860,7 +853,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) /** * This is the main edge ripping function */ -static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event) { const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; @@ -988,7 +981,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) } /* based on mouse cursor position, it defines how is being ripped */ -static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 1016c08e1c4..a1c302c6a63 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -66,6 +66,8 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "GPU_extensions.h" + #include "mesh_intern.h" #include "UI_resources.h" @@ -253,6 +255,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short dr = buf->rect; + if (vc->rv3d->gpuoffscreen) + GPU_offscreen_bind(vc->rv3d->gpuoffscreen); + /* draw the mask */ glDisable(GL_DEPTH_TEST); @@ -270,6 +275,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short glFinish(); /* to be sure readpixels sees mask */ + if (vc->rv3d->gpuoffscreen) + GPU_offscreen_unbind(vc->rv3d->gpuoffscreen); + /* grab mask */ bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); @@ -308,8 +316,10 @@ int EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) return 0; } } - else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) return 0; - + else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) { + return 0; + } + xmin = xs - rads; xmax = xs + rads; ymin = ys - rads; ymax = ys + rads; buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); @@ -932,7 +942,7 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op) } } -static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* detecting these options based on shift/ctrl here is weak, but it's done * to make this work when clicking buttons or menus */ @@ -1084,7 +1094,7 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) /* ***************** loop select (non modal) ************** */ -static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short deselect, short toggle, short ring) +static void mouse_mesh_loop(bContext *C, const int mval[2], short extend, short deselect, short toggle, short ring) { ViewContext vc; BMEditMesh *em; @@ -1171,7 +1181,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele /* Select the face of eed which is the nearest of mouse. */ BMFace *f, *efa = NULL; BMIter iterf; - float best_dist = MAXFLOAT; + float best_dist = FLT_MAX; /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); @@ -1203,7 +1213,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele } } -static int edbm_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { view3d_operator_needs_opengl(C); @@ -1754,7 +1764,7 @@ static int mouse_mesh_shortest_path_face(ViewContext *vc) /* ******************* operator for edge and face tag ****************** */ -static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ViewContext vc; BMEditMesh *em; @@ -2252,7 +2262,7 @@ static void linked_limit_default(bContext *C, wmOperator *op) } } -static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); ViewContext vc; @@ -2995,6 +3005,59 @@ void MESH_OT_select_random(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + BMVert *eve; + BMIter iter; + + if (!em->selectmode == SCE_SELECT_VERTEX) { + BKE_report(op->reports, RPT_ERROR, "Does not work out of vertex selection mode"); + return OPERATOR_CANCELLED; + } + + if (obedit->defbase.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object"); + return OPERATOR_CANCELLED; + } + + if (!RNA_boolean_get(op->ptr, "extend")) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + /* no dv or dv set with no weight */ + if (dv == NULL || (dv && dv->dw == NULL)) { + BM_vert_select_set(em->bm, eve, true); + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_ungrouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Ungrouped"; + ot->idname = "MESH_OT_select_ungrouped"; + ot->description = "Select vertices without a group"; + + /* api callbacks */ + ot->exec = edbm_select_ungrouped_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); +} + static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index c35f942cf33..36a1d30c85e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -39,10 +39,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "RNA_define.h" -#include "RNA_access.h" -#include "RNA_enum_types.h" - #include "BLI_blenlib.h" #include "BLI_noise.h" #include "BLI_math.h" @@ -59,6 +55,10 @@ #include "BKE_main.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" +#include "RNA_enum_types.h" + #include "WM_api.h" #include "WM_types.h" @@ -77,6 +77,8 @@ #include "mesh_intern.h" +#define USE_FACE_CREATE_SEL_EXTEND + #define MVAL_PIXEL_MARGIN 5.0f /* allow accumulated normals to form a new direction but don't @@ -333,10 +335,7 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, mult_m4_m4m4(mtx, imtx, obedit->obmat); } - for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); - edge; - edge = BM_iter_step(&iter)) - { + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(edge, hflag) && BM_edge_is_boundary(edge) && BM_elem_flag_test(edge->l->f, hflag)) @@ -779,7 +778,7 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) } /* *************** add-click-mesh (extrude) operator ************** */ -static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; BMVert *v1; @@ -863,7 +862,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); /* view space */ - view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); + view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, true); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); @@ -912,7 +911,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent BMOIter oiter; copy_v3_v3(min, curs); - view3d_get_view_aligned_coordinate(&vc, min, event->mval, FALSE); + view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, false); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); mul_m4_v3(vc.obedit->imat, min); // back in object space @@ -1099,6 +1098,140 @@ static int edbm_add_edge_face__smooth_get(BMesh *bm) return (vote_on_smooth[0] < vote_on_smooth[1]); } +#ifdef USE_FACE_CREATE_SEL_EXTEND +/** + * Function used to get a fixed number of edges linked to a vertex that passes a test function. + * This is used so we can request all boundary edges connected to a vertex for eg. + */ +static int edbm_add_edge_face_exec__vert_edge_lookup(BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, + bool (* func)(BMEdge *)) +{ + BMIter iter; + BMEdge *e_iter; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) { + if ((e_used == NULL) || (e_used != e_iter)) { + if (func(e_iter)) { + e_arr[i++] = e_iter; + if (i >= e_arr_len) { + break; + } + } + } + } + } + return i; +} + +static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm) +{ + BMIter iter; + bool found = false; + + if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMVert *v; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + found = true; + break; + } + } + + if (found) { + BMEdge *ed_pair[3]; + if ( + ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) + ) + { + BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v), + BM_edge_other_vert(ed_pair[1], v)); + BM_edge_select_set(bm, ed_pair[0], true); + BM_edge_select_set(bm, ed_pair[1], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)v; + } + } + } + else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + found = true; + break; + } + } + if (found) { + BMEdge *ed_pair_v1[2]; + BMEdge *ed_pair_v2[2]; + if ( + ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) + ) + { + BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1); + BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2); + BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL; + BM_edge_select_set(bm, ed_pair_v1[0], true); + BM_edge_select_set(bm, ed_pair_v2[0], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)e; + } + } + } + + return NULL; +} +static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f) +{ + /* now we need to find the edge that isnt connected to this element */ + BM_select_history_clear(bm); + + if (ele_desel->head.htype == BM_VERT) { + BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel); + BLI_assert(f->len == 3); + BM_face_select_set(bm, f, false); + BM_vert_select_set(bm, (BMVert *)ele_desel, false); + + BM_edge_select_set(bm, l->next->e, true); + BM_select_history_store(bm, l->next->e); + } + else { + BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel); + BLI_assert(f->len == 4 || f->len == 3); + BM_face_select_set(bm, f, false); + BM_edge_select_set(bm, (BMEdge *)ele_desel, false); + if (f->len == 4) { + BM_edge_select_set(bm, l->next->next->e, true); + BM_select_history_store(bm, l->next->next->e); + } + else { + BM_vert_select_set(bm, l->next->next->v, true); + BM_select_history_store(bm, l->next->next->v); + } + } +} +#endif /* USE_FACE_CREATE_SEL_EXTEND */ + static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) { BMOperator bmop; @@ -1107,6 +1240,15 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); /* when this is used to dissolve we could avoid this, but checking isnt too slow */ +#ifdef USE_FACE_CREATE_SEL_EXTEND + BMElem *ele_desel; + BMFace *ele_desel_face; + + /* be extra clever, figure out if a partial selection should be extended so we can create geometry + * with single vert or single edge selection */ + ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm); +#endif + if (!EDBM_op_init(em, &bmop, op, "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", BM_ELEM_SELECT, em->mat_nr, use_smooth)) @@ -1115,8 +1257,22 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) } BMO_op_exec(em->bm, &bmop); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, TRUE); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, TRUE); + +#ifdef USE_FACE_CREATE_SEL_EXTEND + /* normally we would want to leave the new geometry selected, + * but being able to press F many times to add geometry is too useful! */ + if (ele_desel && + (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) && + (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) + { + edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face); + } + else +#endif + { + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + } if (!EDBM_op_finish(em, &bmop, op, TRUE)) { return OPERATOR_CANCELLED; @@ -1355,7 +1511,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { WM_cursor_wait(1); edbm_duplicate_exec(C, op); @@ -2005,12 +2161,22 @@ static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *w BMVert *mergevert; BMEditSelection *ese; + /* operator could be called directly from shortcut or python, + * so do extra check for data here + */ + /* do sanity check in mergemenu in edit.c ?*/ if (first == 0) { + if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) + return OPERATOR_CANCELLED; + ese = em->bm->selected.last; mergevert = (BMVert *)ese->ele; } else { + if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) + return OPERATOR_CANCELLED; + ese = em->bm->selected.first; mergevert = (BMVert *)ese->ele; } @@ -2293,8 +2459,12 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) continue; - if (svert == NULL) svert = eve; - else if (evert == NULL) evert = eve; + if (svert == NULL) { + svert = eve; + } + else if (evert == NULL) { + evert = eve; + } else { /* more than two vertices are selected, * show warning message and cancel operator */ @@ -3225,6 +3395,16 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) Base *base = CTX_data_active_base(C); BMEditMesh *em = BMEdit_FromObject(base->object); + if (type == 0) { + if ((em->bm->totvertsel == 0) && + (em->bm->totedgesel == 0) && + (em->bm->totfacesel == 0)) + { + BKE_report(op->reports, RPT_ERROR, "Nothing selected"); + return OPERATOR_CANCELLED; + } + } + /* editmode separate */ if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm); else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm); @@ -3689,7 +3869,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) } /* get center and axis, in global coords */ -static int edbm_spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -3759,9 +3939,10 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) /* find two vertices with valence count == 1, more or less is wrong */ v1 = NULL; v2 = NULL; - for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter)) { + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { valence = 0; - for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve); eed; eed = BM_iter_step(&eiter)) { + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { valence++; } @@ -3812,7 +3993,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) } /* get center and axis, in global coords */ -static int edbm_screw_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4505,7 +4686,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop int action = RNA_enum_get(ptr, "type"); /* Only show seed for randomize action! */ - if (strcmp(prop_id, "seed") == 0) { + if (STREQ(prop_id, "seed")) { if (action == SRT_RANDOMIZE) return TRUE; else @@ -4513,7 +4694,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop } /* Hide seed for reverse and randomize actions! */ - if (strcmp(prop_id, "reverse") == 0) { + if (STREQ(prop_id, "reverse")) { if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) return FALSE; else @@ -4804,7 +4985,7 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* TODO make modal keymap (see fly mode) */ RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -4841,7 +5022,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) +static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int use_dist = TRUE; @@ -4880,7 +5061,7 @@ static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) return factor; } -static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int segments = RNA_int_get(op->ptr, "segments"); @@ -5186,7 +5367,7 @@ static int edbm_inset_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); InsetData *opdata; @@ -5216,7 +5397,7 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int edbm_inset_modal(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) { InsetData *opdata = op->customdata; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 0c9a5aab537..99f526f95f3 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -36,6 +36,7 @@ #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "BLI_utildefines.h" #include "BLI_path_util.h" #include "BLI_array.h" #include "BLI_math.h" @@ -570,7 +571,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -884,7 +885,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface) } if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) - BKE_mesh_calc_edges(mesh, calc_edges); + BKE_mesh_calc_edges(mesh, calc_edges, true); if (calc_tessface) { if (tessface_input == FALSE) { diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index fe4917acdac..5dab022dd2f 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -48,6 +48,7 @@ struct wmKeyConfig; struct wmKeyMap; struct wmOperator; struct wmOperatorType; +struct LinkNode; /* ******************** editmesh_utils.c */ @@ -77,7 +78,6 @@ int EDBM_op_init(struct BMEditMesh *em, struct BMOperator *bmop, int EDBM_op_finish(struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const int report); -void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); void EDBM_stats_update(struct BMEditMesh *em); /* ******************** editface.c */ @@ -128,6 +128,7 @@ void MESH_OT_select_shortest_path(struct wmOperatorType *ot); void MESH_OT_select_similar(struct wmOperatorType *ot); void MESH_OT_select_mode(struct wmOperatorType *ot); void MESH_OT_select_random(struct wmOperatorType *ot); +void MESH_OT_select_ungrouped(struct wmOperatorType *ot); void MESH_OT_loop_multi_select(struct wmOperatorType *ot); void MESH_OT_mark_seam(struct wmOperatorType *ot); void MESH_OT_mark_sharp(struct wmOperatorType *ot); @@ -211,6 +212,8 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); void MESH_OT_knife_tool(struct wmOperatorType *ot); +void MESH_OT_knife_project(wmOperatorType *ot); + void MESH_OT_bevel(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); @@ -228,4 +231,6 @@ void MESH_OT_navmesh_face_add(struct wmOperatorType *ot); void MESH_OT_navmesh_reset(struct wmOperatorType *ot); void MESH_OT_navmesh_clear(struct wmOperatorType *ot); +void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag); + #endif /* __MESH_INTERN_H__ */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 140681304b2..cf3877a8d93 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -59,6 +59,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_linked); WM_operatortype_append(MESH_OT_select_linked_pick); WM_operatortype_append(MESH_OT_select_random); + WM_operatortype_append(MESH_OT_select_ungrouped); WM_operatortype_append(MESH_OT_hide); WM_operatortype_append(MESH_OT_reveal); WM_operatortype_append(MESH_OT_select_face_by_sides); @@ -155,6 +156,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); WM_operatortype_append(MESH_OT_knife_tool); + WM_operatortype_append(MESH_OT_knife_project); WM_operatortype_append(MESH_OT_bevel); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 378f6374336..3d4d204299f 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -789,7 +789,9 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, const float c return (*bt)->index[a]; } } - else return -1; + else { + return -1; + } } if ( (*bt)->next) return mesh_octree_find_index(&(*bt)->next, mvert, co); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 6c056df5a38..6781624aec6 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -254,7 +254,7 @@ static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int duplicate_metaelems_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { int retv = duplicate_metaelems_exec(C, op); diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index f91d57424a1..8c705aac0d2 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -28,17 +28,17 @@ * \ingroup edmeta */ +#include "BLI_utildefines.h" + #include "RNA_access.h" +#include "WM_api.h" +#include "WM_types.h" + #include "ED_mball.h" #include "ED_screen.h" #include "ED_object.h" -#include "BLI_utildefines.h" - -#include "WM_api.h" -#include "WM_types.h" - #include "mball_intern.h" void ED_operatortypes_metaball(void) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 997cbb71683..dbb0d55a2b1 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -49,11 +49,13 @@ #include "DNA_vfont_types.h" #include "DNA_actuator_types.h" +#include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" -#include "BLI_utildefines.h" + +#include "BLF_translation.h" #include "BKE_anim.h" #include "BKE_animsys.h" @@ -662,7 +664,9 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) ED_object_enter_editmode(C, 0); newob = 1; } - else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + else { + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } if (obedit == NULL) { BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature"); @@ -736,7 +740,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot) ED_object_add_generic_props(ot, FALSE); } -static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Base *base = NULL; Image *ima = NULL; @@ -872,6 +876,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", ""); + RNA_def_property_translation_context(ot->prop, BLF_I18NCONTEXT_ID_LAMP); ED_object_add_generic_props(ot, FALSE); } @@ -1482,7 +1487,7 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; } - BKE_mesh_from_curve(scene, newob); + BKE_mesh_to_curve(scene, newob); if (newob->type == OB_CURVE) BKE_object_free_modifiers(newob); /* after derivedmesh calls! */ diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index a680230fb32..dc54207b4e6 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -138,7 +138,9 @@ static int multiresbake_check(bContext *C, wmOperator *op) } } } - else ok = 0; + else { + ok = 0; + } if (!ok) { BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object"); @@ -696,7 +698,7 @@ static void bake_freejob(void *bkv) } /* catch esc */ -static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { /* no running blender, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE_TEXTURE)) @@ -719,7 +721,7 @@ static int is_multires_bake(Scene *scene) return 0; } -static int objects_bake_render_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(_event)) +static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(_event)) { Scene *scene = CTX_data_scene(C); int result = OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 1bed7d7dd11..8e2a87c7c64 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -435,7 +435,9 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) curcon->flag |= CONSTRAINT_DISABLE; } } - else curcon->flag |= CONSTRAINT_DISABLE; + else { + curcon->flag |= CONSTRAINT_DISABLE; + } } } else if (curcon->type == CONSTRAINT_TYPE_CAMERASOLVER) { @@ -645,7 +647,7 @@ static int stretchto_reset_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int stretchto_reset_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int stretchto_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return stretchto_reset_exec(C, op); @@ -691,7 +693,7 @@ static int limitdistance_reset_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int limitdistance_reset_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int limitdistance_reset_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return limitdistance_reset_exec(C, op); @@ -827,7 +829,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int childof_set_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int childof_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return childof_set_inverse_exec(C, op); @@ -874,7 +876,7 @@ static int childof_clear_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int childof_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return childof_clear_inverse_exec(C, op); @@ -991,7 +993,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int followpath_path_animate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { /* hook up invoke properties for figuring out which constraint we're dealing with */ if (edit_constraint_invoke_properties(C, op)) { @@ -1049,7 +1051,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int objectsolver_set_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return objectsolver_set_inverse_exec(C, op); @@ -1095,7 +1097,7 @@ static int objectsolver_clear_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int objectsolver_clear_inverse_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return objectsolver_clear_inverse_exec(C, op); @@ -1231,7 +1233,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int constraint_move_down_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int constraint_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return constraint_move_down_exec(C, op); @@ -1280,7 +1282,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int constraint_move_up_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int constraint_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_constraint_invoke_properties(C, op)) return constraint_move_up_exec(C, op); @@ -1848,7 +1850,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) // TODO: should these be here, or back in editors/armature/poseobject.c again? /* present menu with options + validation for targets to use */ -static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bPoseChannel *pchan = BKE_pose_channel_active(ob); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index b94c9e940dc..ca57ab76c57 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1012,7 +1012,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) DAG_relations_tag_update(bmain); } -static void UNUSED_FUNCTION(copy_attr_menu) (Main * bmain, Scene * scene, View3D * v3d) +static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D *v3d) { Object *ob; short event; @@ -1132,7 +1132,7 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene) /* show popup to determine settings */ -static int object_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = CTX_data_active_object(C); @@ -1358,7 +1358,7 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) /* ********************** */ -static void UNUSED_FUNCTION(image_aspect) (Scene * scene, View3D * v3d) +static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) { /* all selected objects with an image map: scale in image aspect */ Base *base; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index a302aa65fd0..163a869613b 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -138,6 +138,7 @@ void OBJECT_OT_hook_recenter(struct wmOperatorType *ot); /* object_lattice.c */ void LATTICE_OT_select_all(struct wmOperatorType *ot); +void LATTICE_OT_select_ungrouped(struct wmOperatorType *ot); void LATTICE_OT_make_regular(struct wmOperatorType *ot); void LATTICE_OT_flip(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index c9eae776ac7..053f1ffabd0 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -53,6 +53,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_deform.h" +#include "BKE_report.h" #include "ED_lattice.h" #include "ED_object.h" @@ -255,6 +256,58 @@ void LATTICE_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } +/************************** Select Ungrouped Verts Operator *************************/ + +static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt; + MDeformVert *dv; + BPoint *bp; + int a, tot; + + if (obedit->defbase.first == NULL || lt->dvert == NULL) { + BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object"); + return OPERATOR_CANCELLED; + } + + if (!RNA_boolean_get(op->ptr, "extend")) { + ED_setflagsLatt(obedit, 0); + } + + dv = lt->dvert; + tot = lt->pntsu * lt->pntsv * lt->pntsw; + + for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) { + if (bp->hide == 0) { + if (dv->dw == NULL) { + bp->f1 |= SELECT; + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void LATTICE_OT_select_ungrouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Ungrouped"; + ot->idname = "LATTICE_OT_select_ungrouped"; + ot->description = "Select vertices without a group"; + + /* api callbacks */ + ot->exec = lattice_select_ungrouped_exec; + ot->poll = ED_operator_editlattice; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); +} + /************************** Make Regular Operator *************************/ static int make_regular_poll(bContext *C) diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 8d29813e2ac..d66620c2ff6 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -892,7 +892,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_remove_exec(C, op); @@ -931,7 +931,7 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_up_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_move_up_exec(C, op); @@ -970,7 +970,7 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_down_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_move_down_exec(C, op); @@ -1012,7 +1012,7 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_apply_exec(C, op); @@ -1061,7 +1061,7 @@ static int modifier_convert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_convert_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_convert_exec(C, op); @@ -1100,7 +1100,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_copy_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return modifier_copy_exec(C, op); @@ -1149,7 +1149,7 @@ static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return multires_higher_levels_delete_exec(C, op); @@ -1199,7 +1199,7 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int multires_subdivide_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return multires_subdivide_exec(C, op); @@ -1263,7 +1263,7 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int multires_reshape_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return multires_reshape_exec(C, op); @@ -1314,7 +1314,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int multires_external_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int multires_external_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = ED_object_active_context(C); MultiresModifierData *mmd; @@ -1410,7 +1410,7 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int multires_base_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return multires_base_apply_exec(C, op); @@ -1834,7 +1834,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int skin_armature_create_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int skin_armature_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return skin_armature_create_exec(C, op); @@ -1927,7 +1927,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int meshdeform_bind_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int meshdeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return meshdeform_bind_exec(C, op); @@ -1975,7 +1975,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int explode_refresh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int explode_refresh_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return explode_refresh_exec(C, op); @@ -2191,7 +2191,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int ocean_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int ocean_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_modifier_invoke_properties(C, op)) return ocean_bake_exec(C, op); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index e5aaaffade8..594dfd6e271 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -211,6 +211,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shape_key_move); WM_operatortype_append(LATTICE_OT_select_all); + WM_operatortype_append(LATTICE_OT_select_ungrouped); WM_operatortype_append(LATTICE_OT_make_regular); WM_operatortype_append(LATTICE_OT_flip); @@ -364,7 +365,7 @@ void ED_keymap_object(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "use_global", TRUE); - WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "use_global", FALSE); kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "use_global", TRUE); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index f9dde043607..6039ff6d34b 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -215,7 +215,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) } } - if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3)) ) { + if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) { BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to"); return OPERATOR_CANCELLED; } @@ -286,7 +286,7 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot) /********************** Make Proxy Operator *************************/ /* set the object to proxify */ -static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); @@ -299,7 +299,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt) if (ob->dup_group && ob->dup_group->id.lib) { /* gives menu with list of objects in group */ //proxy_group_objects_menu(C, op, ob, ob->dup_group); - WM_enum_search_invoke(C, op, evt); + WM_enum_search_invoke(C, op, event); return OPERATOR_CANCELLED; } @@ -608,8 +608,10 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object cu->flag |= CU_PATH | CU_FOLLOW; BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */ } - else cu->flag |= CU_FOLLOW; - + else { + cu->flag |= CU_FOLLOW; + } + /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ if (partype == PAR_FOLLOW) { /* get or create F-Curve */ @@ -797,7 +799,7 @@ static int parent_set_exec(bContext *C, wmOperator *op) } -static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { Object *ob = ED_object_active_context(C); uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE); @@ -1227,7 +1229,7 @@ static unsigned int move_to_layer_init(bContext *C, wmOperator *op) return lay; } -static int move_to_layer_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); if (v3d && v3d->localvd) { @@ -1541,6 +1543,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_OBJECT, NULL); return OPERATOR_FINISHED; } @@ -1928,11 +1931,11 @@ static void make_local_makelocalmaterial(Material *ma) AnimData *adt; int b; - id_make_local(&ma->id, 0); + id_make_local(&ma->id, false); for (b = 0; b < MAX_MTEX; b++) if (ma->mtex[b] && ma->mtex[b]->tex) - id_make_local(&ma->mtex[b]->tex->id, 0); + id_make_local(&ma->mtex[b]->tex->id, false); adt = BKE_animdata_from_id(&ma->id); if (adt) BKE_animdata_make_local(adt); @@ -1958,7 +1961,7 @@ static int make_local_exec(bContext *C, wmOperator *op) int a, b, mode = RNA_enum_get(op->ptr, "type"); if (mode == MAKE_LOCAL_ALL) { - BKE_library_make_local(bmain, NULL, 0); /* NULL is all libs */ + BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */ WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } @@ -1968,7 +1971,7 @@ static int make_local_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if (ob->id.lib) - id_make_local(&ob->id, 0); + id_make_local(&ob->id, false); } CTX_DATA_END; @@ -1986,7 +1989,7 @@ static int make_local_exec(bContext *C, wmOperator *op) id = ob->data; if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) { - id_make_local(id, 0); + id_make_local(id, false); adt = BKE_animdata_from_id(id); if (adt) BKE_animdata_make_local(adt); @@ -2002,7 +2005,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } for (psys = ob->particlesystem.first; psys; psys = psys->next) - id_make_local(&psys->part->id, 0); + id_make_local(&psys->part->id, false); adt = BKE_animdata_from_id(&ob->id); if (adt) BKE_animdata_make_local(adt); @@ -2017,7 +2020,7 @@ static int make_local_exec(bContext *C, wmOperator *op) for (b = 0; b < MAX_MTEX; b++) if (la->mtex[b] && la->mtex[b]->tex) - id_make_local(&la->mtex[b]->tex->id, 0); + id_make_local(&la->mtex[b]->tex->id, false); } else { for (a = 0; a < ob->totcol; a++) { @@ -2130,7 +2133,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object"); } -static int drop_named_material_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Base *base = ED_view3d_give_base_under_cursor(C, event->mval); Material *ma; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 3fa6c301fcb..80d494a6a07 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -795,8 +795,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (centermode == ORIGIN_TO_CURSOR) { /* done */ } else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); } - else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); } - else { BKE_mesh_center_bounds(me, cent); } + else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); } + else { BKE_mesh_center_bounds(me, cent); } negate_v3_v3(cent_neg, cent); BKE_mesh_translate(me, cent_neg, 1); @@ -808,9 +808,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } else if (around == V3D_CENTROID) { BKE_curve_center_median(cu, cent); } - else { BKE_curve_center_bounds(cu, cent); } + else { BKE_curve_center_bounds(cu, cent); } /* don't allow Z change if curve is 2D */ if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) @@ -889,9 +889,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } else if (around == V3D_CENTROID) { BKE_mball_center_median(mb, cent); } - else { BKE_mball_center_bounds(mb, cent); } + else { BKE_mball_center_bounds(mb, cent); } negate_v3_v3(cent_neg, cent); BKE_mball_translate(mb, cent_neg); @@ -910,9 +910,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } else if (around == V3D_CENTROID) { BKE_lattice_center_median(lt, cent); } - else { BKE_lattice_center_bounds(lt, cent); } + else { BKE_lattice_center_bounds(lt, cent); } negate_v3_v3(cent_neg, cent); BKE_lattice_translate(lt, cent_neg, 1); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index ef882b2486b..5abbb7124c0 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -1037,7 +1037,7 @@ static void vgroup_duplicate(Object *ob) BLI_snprintf(name, sizeof(name), "%s_copy", dg->name); } else { - BLI_snprintf(name, sizeof(name), "%s", dg->name); + BLI_strncpy(name, dg->name, sizeof(name)); } cdg = defgroup_duplicate(dg); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 31079de275e..329f1f67c4a 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -430,15 +430,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2 gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection, (GLint *)data->mats.viewport, &ux, &uy, &uz); -#if 0 /* works well but too slow on some systems [#23118] */ - screen_co[0] += (short)data->vc.ar->winrct.xmin; - screen_co[1] += (short)data->vc.ar->winrct.ymin; - - /* PE_set_view3d_data calls this. no need to call here */ - /* view3d_validate_backbuf(&data->vc); */ - glReadPixels(screen_co[0], screen_co[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); -#else /* faster to use depths, these are calculated in PE_set_view3d_data */ - /* check if screen_co is within bounds because brush_cut uses out of screen coords */ if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) { BLI_assert(vd && vd->depths); @@ -447,7 +438,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2 } else return 0; -#endif if ((float)uz - 0.00001f > depth) return 0; @@ -1555,7 +1545,7 @@ static int select_linked_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RNA_int_set_array(op->ptr, "location", event->mval); return select_linked_exec(C, op); @@ -3476,6 +3466,7 @@ typedef struct BrushEdit { int first; int lastmouse[2]; + float zfac; /* optional cached view settings to avoid setting on every mousemove */ PEData data; @@ -3498,7 +3489,6 @@ static int brush_edit_init(bContext *C, wmOperator *op) INIT_MINMAX(min, max); PE_minmax(scene, min, max); mid_v3_v3v3(min, min, max); - initgrabz(ar->regiondata, min[0], min[1], min[2]); bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit"); bedit->first= 1; @@ -3508,6 +3498,8 @@ static int brush_edit_init(bContext *C, wmOperator *op) bedit->ob= ob; bedit->edit= edit; + bedit->zfac = ED_view3d_calc_zfac(ar->regiondata, min, NULL); + /* cache view depths and settings for re-use */ PE_set_view3d_data(C, &bedit->data); @@ -3587,7 +3579,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) invert_m4_m4(ob->imat, ob->obmat); - ED_view3d_win_to_delta(ar, mval_f, vec); + ED_view3d_win_to_delta(ar, mval_f, vec, bedit->zfac); data.dvec= vec; foreach_mouse_hit_key(&data, brush_comb, selected); @@ -3757,7 +3749,7 @@ static int brush_edit_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event) +static void brush_edit_apply_event(bContext *C, wmOperator *op, const wmEvent *event) { PointerRNA itemptr; float mouse[2]; @@ -3774,7 +3766,7 @@ static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event) brush_edit_apply(C, op, &itemptr); } -static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int brush_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!brush_edit_init(C, op)) return OPERATOR_CANCELLED; @@ -3786,7 +3778,7 @@ static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event) +static int brush_edit_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index fc55b2b5915..df723b06259 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -679,18 +679,15 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF if (fileCfg) { dirExist = 1; fclose(fileCfg); // remove cfg dummy from directory test - BLI_delete(targetFile, 0, 0); + BLI_delete(targetFile, false, false); } if (targetDir[0] == '\0' || (!dirExist)) { - char blendDir[FILE_MAX]; char blendFile[FILE_MAX]; // invalid dir, reset to current/previous - BLI_strncpy(blendDir, G.main->name, FILE_MAX); - BLI_splitdirstring(blendDir, blendFile); + BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile)); BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */ - BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); @@ -852,9 +849,9 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *r curFrame++; if ((exists = BLI_exists(targetFile))) { - BLI_delete(targetFile, 0, 0); - BLI_delete(targetFileVel, 0, 0); - BLI_delete(previewFile, 0, 0); + BLI_delete(targetFile, false, false); + BLI_delete(targetFileVel, false, false); + BLI_delete(previewFile, false, false); } } while (exists); @@ -1130,7 +1127,7 @@ static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object /***************************** Operators ******************************/ -static int fluid_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { /* only one bake job at a time */ if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 51a66886c6e..2ede7047b74 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -27,9 +27,9 @@ * \ingroup edphys */ - #include <stdlib.h> +#include "BLI_utildefines.h" #include "RNA_access.h" @@ -39,8 +39,6 @@ #include "ED_physics.h" #include "ED_object.h" -#include "BLI_utildefines.h" - #include "physics_intern.h" // own include diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index 6bcdf6e07aa..9c03c6173a5 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -44,6 +44,8 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" @@ -374,61 +376,61 @@ typedef struct rbMaterialDensityItem { * 3) http://www.avlandesign.com/density_metal.htm */ static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = { - {"Air", 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */ - {"Acrylic", 1400.0f}, - {"Asphalt (Crushed)", 721.0f}, - {"Bark", 240.0f}, - {"Beans (Cocoa)", 593.0f}, - {"Beans (Soy)", 721.0f}, - {"Brick (Pressed)", 2400.0f}, - {"Brick (Common)", 2000.0f}, - {"Brick (Soft)", 1600.0f}, - {"Brass", 8216.0f}, - {"Bronze", 8860.0f}, - {"Carbon (Solid)", 2146.0f}, - {"Cardboard", 689.0f}, - {"Cast Iron", 7150.0f}, - //{"Cement", 1442.0f}, - {"Chalk (Solid)", 2499.0f}, - //{"Coffee (Fresh/Roast)", ~500}, - {"Concrete", 2320.0f}, - {"Charcoal", 208.0f}, - {"Cork", 240.0f}, - {"Copper", 8933.0f}, - {"Garbage", 481.0f}, - {"Glass (Broken)", 1940.0f}, - {"Glass (Solid)", 2190.0f}, - {"Gold", 19282.0f}, - {"Granite (Broken)", 1650.0f}, - {"Granite (Solid)", 2691.0f}, - {"Gravel", 2780.0f}, - {"Ice (Crushed)", 593.0f}, - {"Ice (Solid)", 919.0f}, - {"Iron", 7874.0f}, - {"Lead", 11342.0f}, - {"Limestone (Broken)", 1554.0f}, - {"Limestone (Solid)", 2611.0f}, - {"Marble (Broken)", 1570.0f}, - {"Marble (Solid)", 2563.0f}, - {"Paper", 1201.0f}, - {"Peanuts (Shelled)", 641.0f}, - {"Peanuts (Not Shelled)", 272.0f}, - {"Plaster", 849.0f}, - {"Plastic", 1200.0f}, - {"Polystyrene", 1050.0f}, - {"Rubber", 1522.0f}, - {"Silver", 10501.0f}, - {"Steel", 7860.0f}, - {"Stone", 2515.0f}, - {"Stone (Crushed)", 1602.0f}, - {"Timber", 610.0f} + {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */ + {N_("Acrylic"), 1400.0f}, + {N_("Asphalt (Crushed)"), 721.0f}, + {N_("Bark"), 240.0f}, + {N_("Beans (Cocoa)"), 593.0f}, + {N_("Beans (Soy)"), 721.0f}, + {N_("Brick (Pressed)"), 2400.0f}, + {N_("Brick (Common)"), 2000.0f}, + {N_("Brick (Soft)"), 1600.0f}, + {N_("Brass"), 8216.0f}, + {N_("Bronze"), 8860.0f}, + {N_("Carbon (Solid)"), 2146.0f}, + {N_("Cardboard"), 689.0f}, + {N_("Cast Iron"), 7150.0f}, + /* {N_("Cement"), 1442.0f}, */ + {N_("Chalk (Solid)"), 2499.0f}, + /* {N_("Coffee (Fresh/Roast)"), ~500}, */ + {N_("Concrete"), 2320.0f}, + {N_("Charcoal"), 208.0f}, + {N_("Cork"), 240.0f}, + {N_("Copper"), 8933.0f}, + {N_("Garbage"), 481.0f}, + {N_("Glass (Broken)"), 1940.0f}, + {N_("Glass (Solid)"), 2190.0f}, + {N_("Gold"), 19282.0f}, + {N_("Granite (Broken)"), 1650.0f}, + {N_("Granite (Solid)"), 2691.0f}, + {N_("Gravel"), 2780.0f}, + {N_("Ice (Crushed)"), 593.0f}, + {N_("Ice (Solid)"), 919.0f}, + {N_("Iron"), 7874.0f}, + {N_("Lead"), 11342.0f}, + {N_("Limestone (Broken)"), 1554.0f}, + {N_("Limestone (Solid)"), 2611.0f}, + {N_("Marble (Broken)"), 1570.0f}, + {N_("Marble (Solid)"), 2563.0f}, + {N_("Paper"), 1201.0f}, + {N_("Peanuts (Shelled)"), 641.0f}, + {N_("Peanuts (Not Shelled)"), 272.0f}, + {N_("Plaster"), 849.0f}, + {N_("Plastic"), 1200.0f}, + {N_("Polystyrene"), 1050.0f}, + {N_("Rubber"), 1522.0f}, + {N_("Silver"), 10501.0f}, + {N_("Steel"), 7860.0f}, + {N_("Stone"), 2515.0f}, + {N_("Stone (Crushed)"), 1602.0f}, + {N_("Timber"), 610.0f} }; static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) / sizeof(rbMaterialDensityItem); /* dynamically generate list of items * - Although there is a runtime cost, this has a lower maintenance cost - * in the long run than other two-list solutions... + * in the long run than other two-list solutions... */ static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { @@ -441,14 +443,16 @@ static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerR for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) { rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i]; - item_tmp.identifier = item_tmp.name = preset->name; + item_tmp.identifier = preset->name; + item_tmp.name = IFACE_(preset->name); item_tmp.value = i; RNA_enum_item_add(&item, &totitem, &item_tmp); } /* add special "custom" entry to the end of the list */ { - item_tmp.identifier = item_tmp.name = "Custom"; + item_tmp.identifier = "Custom"; + item_tmp.name = IFACE_("Custom"); item_tmp.value = -1; RNA_enum_item_add(&item, &totitem, &item_tmp); } diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c index babe32c74b2..b7430cb8a95 100644 --- a/source/blender/editors/physics/rigidbody_world.c +++ b/source/blender/editors/physics/rigidbody_world.c @@ -175,7 +175,7 @@ static int rigidbody_world_export_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int rigidbody_world_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt)) +static int rigidbody_world_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!RNA_struct_property_is_set(op->ptr, "relative_path")) RNA_boolean_set(op->ptr, "relative_path", (U.flag & USER_RELPATHS)); diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript index 9d1de2fc700..25af8080d51 100644 --- a/source/blender/editors/render/SConscript +++ b/source/blender/editors/render/SConscript @@ -33,7 +33,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../gpu' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' -incs += ' ../../blenloader ../../bmesh' +incs += ' ../../blenloader ../../bmesh ../../blenfont' if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index deb6eaf2c22..b138bc63a68 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -39,6 +39,8 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "DNA_scene_types.h" #include "BKE_blender.h" @@ -281,38 +283,39 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str) megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); if (scene->lay & 0xFF000000) - spos += sprintf(spos, "Localview | "); + spos += sprintf(spos, IFACE_("Localview | ")); else if (scene->r.scemode & R_SINGLE_LAYER) - spos += sprintf(spos, "Single Layer | "); + spos += sprintf(spos, IFACE_("Single Layer | ")); - spos += sprintf(spos, "Frame:%d ", (scene->r.cfra)); + spos += sprintf(spos, IFACE_("Frame:%d "), (scene->r.cfra)); if (rs->statstr) { spos += sprintf(spos, "| %s ", rs->statstr); } else { - if (rs->totvert) spos += sprintf(spos, "Ve:%d ", rs->totvert); - if (rs->totface) spos += sprintf(spos, "Fa:%d ", rs->totface); - if (rs->tothalo) spos += sprintf(spos, "Ha:%d ", rs->tothalo); - if (rs->totstrand) spos += sprintf(spos, "St:%d ", rs->totstrand); - if (rs->totlamp) spos += sprintf(spos, "La:%d ", rs->totlamp); + if (rs->totvert) spos += sprintf(spos, IFACE_("Ve:%d "), rs->totvert); + if (rs->totface) spos += sprintf(spos, IFACE_("Fa:%d "), rs->totface); + if (rs->tothalo) spos += sprintf(spos, IFACE_("Ha:%d "), rs->tothalo); + if (rs->totstrand) spos += sprintf(spos, IFACE_("St:%d "), rs->totstrand); + if (rs->totlamp) spos += sprintf(spos, IFACE_("La:%d "), rs->totlamp); if (rs->mem_peak == 0.0f) - spos += sprintf(spos, "Mem:%.2fM (%.2fM, peak %.2fM) ", megs_used_memory, mmap_used_memory, megs_peak_memory); + spos += sprintf(spos, IFACE_("Mem:%.2fM (%.2fM, Peak %.2fM) "), + megs_used_memory, mmap_used_memory, megs_peak_memory); else - spos += sprintf(spos, "Mem:%.2fM, Peak: %.2fM ", rs->mem_used, rs->mem_peak); + spos += sprintf(spos, IFACE_("Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak); if (rs->curfield) - spos += sprintf(spos, "Field %d ", rs->curfield); + spos += sprintf(spos, IFACE_("Field %d "), rs->curfield); if (rs->curblur) - spos += sprintf(spos, "Blur %d ", rs->curblur); + spos += sprintf(spos, IFACE_("Blur %d "), rs->curblur); } BLI_timestr(rs->lastframetime, info_time_str); - spos += sprintf(spos, "Time:%s ", info_time_str); + spos += sprintf(spos, IFACE_("Time:%s "), info_time_str); if (rs->curfsa) - spos += sprintf(spos, "| Full Sample %d ", rs->curfsa); + spos += sprintf(spos, IFACE_("| Full Sample %d "), rs->curfsa); if (rs->infostr && rs->infostr[0]) spos += sprintf(spos, "| %s ", rs->infostr); @@ -462,7 +465,7 @@ static void render_drawlock(void *UNUSED(rjv), int lock) } /* catch esc */ -static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event) +static int screen_render_modal(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = (Scene *) op->customdata; @@ -481,7 +484,7 @@ static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event) } /* using context, starts job */ -static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* new render clears all callbacks */ Main *mainp; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index ea18f2c8fbb..f47d737beca 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -638,7 +638,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) } -static int screen_opengl_render_modal(bContext *C, wmOperator *op, wmEvent *event) +static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event) { OGLRender *oglrender = op->customdata; int anim = RNA_boolean_get(op->ptr, "animation"); @@ -677,7 +677,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, wmEvent *even return OPERATOR_RUNNING_MODAL; } -static int screen_opengl_render_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { OGLRender *oglrender; int anim = RNA_boolean_get(op->ptr, "animation"); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index dfc80e4cf51..7802e5460ff 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -110,7 +110,7 @@ ImBuf *get_brush_icon(Brush *brush) static const int flags = IB_rect | IB_multilayer | IB_metadata; char path[FILE_MAX]; - char *folder; + const char *folder; if (!(brush->icon_imbuf)) { if (brush->flag & BRUSH_CUSTOM_ICON) { @@ -188,8 +188,8 @@ typedef struct IconPreview { /* *************************** Preview for buttons *********************** */ -static Main *pr_main = NULL; -static Main *pr_main_cycles = NULL; +static Main *G_pr_main = NULL; +static Main *G_pr_main_cycles = NULL; #ifndef WITH_HEADLESS static Main *load_main_from_memory(char *blend, int blend_size) @@ -214,18 +214,18 @@ static Main *load_main_from_memory(char *blend, int blend_size) void ED_preview_init_dbase(void) { #ifndef WITH_HEADLESS - pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size); - pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size); + G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size); + G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size); #endif } void ED_preview_free_dbase(void) { - if (pr_main) - free_main(pr_main); + if (G_pr_main) + free_main(G_pr_main); - if (pr_main_cycles) - free_main(pr_main_cycles); + if (G_pr_main_cycles) + free_main(G_pr_main_cycles); } static int preview_mat_has_sss(Material *mat, bNodeTree *ntree) @@ -425,15 +425,16 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre if (tex && sp->slot) mat->mtex[0]->which_output = sp->slot->which_output; - + + mat->mtex[0]->mapto &= ~MAP_ALPHA; + mat->alpha = 1.0f; + /* show alpha in this case */ if (tex == NULL || (tex->flag & TEX_PRV_ALPHA)) { - mat->mtex[0]->mapto |= MAP_ALPHA; - mat->alpha = 0.0f; - } - else { - mat->mtex[0]->mapto &= ~MAP_ALPHA; - mat->alpha = 1.0f; + if (!(tex && tex->type == TEX_IMAGE && (tex->imaflag & (TEX_USEALPHA | TEX_CALCALPHA)) == 0)) { + mat->mtex[0]->mapto |= MAP_ALPHA; + mat->alpha = 0.0f; + } } } } @@ -670,8 +671,10 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs if (first) sizex = sp->sizex / 2; else sizex = sp->sizex - sp->sizex / 2; } - else sizex = sp->sizex; - + else { + sizex = sp->sizex; + } + /* we have to set preview variables first */ sce = preview_get_scene(pr_main); if (sce) { @@ -1025,7 +1028,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short sp->pr_method = PR_ICON_RENDER; sp->pr_rect = cur_size->rect; sp->id = ip->id; - sp->pr_main = pr_main; + sp->pr_main = G_pr_main; common_preview_startjob(sp, stop, do_update, progress); shader_preview_free(sp); @@ -1128,9 +1131,9 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M /* hardcoded preview .blend for cycles/internal, this should be solved * once with custom preview .blend path for external engines */ if (BKE_scene_use_new_shading_nodes(scene)) - sp->pr_main = pr_main_cycles; + sp->pr_main = G_pr_main_cycles; else - sp->pr_main = pr_main; + sp->pr_main = G_pr_main; if (ob && ob->totcol) copy_v4_v4(sp->col, ob->col); else sp->col[0] = sp->col[1] = sp->col[2] = sp->col[3] = 1.0f; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index aa1edb1c1b1..decc5b131ae 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1327,7 +1327,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int envmap_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int envmap_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { //Scene *scene= CTX_data_scene(C); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 16d7923baff..a467b053443 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -394,8 +394,6 @@ static void texture_changed(Main *bmain, Tex *tex) if (dm && totmaterial && material) { for (a = 0; a < *totmaterial; a++) { - Material *ma; - if (ob->matbits && ob->matbits[a]) ma = ob->mat[a]; else diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index 8b2ac740e47..186d0d20623 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -275,7 +275,7 @@ void RENDER_OT_view_cancel(struct wmOperatorType *ot) /************************* show render viewer *****************/ -static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { wmWindow *wincur = CTX_wm_window(C); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 1b7cd4a6d20..2d6e8d0ada0 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -67,6 +67,8 @@ #include "screen_intern.h" +extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */ + /* general area and region code */ static void region_draw_emboss(ARegion *ar, rcti *scirct) @@ -245,8 +247,6 @@ static void draw_azone_plus(float x1, float y1, float x2, float y2) static void region_draw_azone_tab_plus(AZone *az) { - extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */ - glEnable(GL_BLEND); /* add code to draw region hidden as 'too small' */ @@ -321,8 +321,6 @@ static void region_draw_azone_tab(AZone *az) static void region_draw_azone_tria(AZone *az) { - extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */ - glEnable(GL_BLEND); //UI_GetThemeColor3fv(TH_HEADER, col); glColor4f(0.0f, 0.0f, 0.0f, 0.35f); @@ -590,7 +588,7 @@ static void area_azone_initialize(bScreen *screen, ScrArea *sa) BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2); } -#define AZONEPAD_EDGE (0.2f * U.widget_unit) +#define AZONEPAD_EDGE (0.1f * U.widget_unit) #define AZONEPAD_ICON (0.45f * U.widget_unit) static void region_azone_edge(AZone *az, ARegion *ar) { @@ -599,22 +597,22 @@ static void region_azone_edge(AZone *az, ARegion *ar) az->x1 = ar->winrct.xmin; az->y1 = ar->winrct.ymax - AZONEPAD_EDGE; az->x2 = ar->winrct.xmax; - az->y2 = ar->winrct.ymax; + az->y2 = ar->winrct.ymax + AZONEPAD_EDGE; break; case AE_BOTTOM_TO_TOPLEFT: az->x1 = ar->winrct.xmin; az->y1 = ar->winrct.ymin + AZONEPAD_EDGE; az->x2 = ar->winrct.xmax; - az->y2 = ar->winrct.ymin; + az->y2 = ar->winrct.ymin - AZONEPAD_EDGE; break; case AE_LEFT_TO_TOPRIGHT: - az->x1 = ar->winrct.xmin; + az->x1 = ar->winrct.xmin - AZONEPAD_EDGE; az->y1 = ar->winrct.ymin; az->x2 = ar->winrct.xmin + AZONEPAD_EDGE; az->y2 = ar->winrct.ymax; break; case AE_RIGHT_TO_TOPLEFT: - az->x1 = ar->winrct.xmax; + az->x1 = ar->winrct.xmax + AZONEPAD_EDGE; az->y1 = ar->winrct.ymin; az->x2 = ar->winrct.xmax - AZONEPAD_EDGE; az->y2 = ar->winrct.ymax; @@ -1071,7 +1069,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti if (G.debug & G_DEBUG) printf("region quadsplit failed\n"); } - else quad = 1; + else { + quad = 1; + } } if (quad) { if (quad == 1) { /* left bottom */ @@ -1746,7 +1746,9 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * /* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur)); break; */ } - else break; + else { + break; + } } diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 105c2dc88d1..8501b53afae 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -482,7 +482,7 @@ static int get_cached_work_texture(int *w_r, int *h_r) return texid; } -void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, void *rect, float scaleX, float scaleY) +void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect, float scaleX, float scaleY) { unsigned char *uc_rect = (unsigned char *) rect; float *f_rect = (float *)rect; @@ -503,6 +503,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, /* don't want nasty border artifacts */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); #ifdef __APPLE__ /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */ @@ -560,10 +561,10 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h); - glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * xzoom); + glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom); glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h); - glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * xzoom); + glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom); glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h); glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); @@ -585,9 +586,9 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, #endif } -void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect) +void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect) { - glaDrawPixelsTexScaled(x, y, img_w, img_h, format, rect, 1.0f, 1.0f); + glaDrawPixelsTexScaled(x, y, img_w, img_h, format, zoomfilter, rect, 1.0f, 1.0f); } void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect) @@ -669,6 +670,22 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo } } +/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */ +void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int zoomfilter, void *rect) +{ + if (U.image_gpubuffer_limit) { + /* Megapixels, use float math to prevent overflow */ + float img_size = ((float)img_w * (float)img_h) / (1024.0f * 1024.0f); + + if (U.image_gpubuffer_limit > (int)img_size) { + glColor4f(1.0, 1.0, 1.0, 1.0); + glaDrawPixelsTex(x, y, img_w, img_h, format, zoomfilter, rect); + return; + } + } + glaDrawPixelsSafe(x, y, img_w, img_h, img_w, GL_RGBA, format, rect); +} + /* 2D Drawing Assistance */ void glaDefine2DArea(rcti *screen_rect) @@ -807,7 +824,9 @@ void bglBegin(int mode) pointhack = floor(value[0] + 0.5f); if (pointhack > 4) pointhack = 4; } - else glBegin(mode); + else { + glBegin(mode); + } } } @@ -835,7 +854,9 @@ void bglVertex3fv(const float vec[3]) glRasterPos3fv(vec); glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot); } - else glVertex3fv(vec); + else { + glVertex3fv(vec); + } break; } } @@ -848,7 +869,9 @@ void bglVertex3f(float x, float y, float z) glRasterPos3f(x, y, z); glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot); } - else glVertex3f(x, y, z); + else { + glVertex3f(x, y, z); + } break; } } @@ -861,7 +884,9 @@ void bglVertex2fv(const float vec[2]) glRasterPos2fv(vec); glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot); } - else glVertex2fv(vec); + else { + glVertex2fv(vec); + } break; } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 7c22dff1b01..6045bdfebfe 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -194,7 +194,9 @@ void removenotused_scrverts(bScreen *sc) BLI_remlink(&sc->vertbase, sv); MEM_freeN(sv); } - else sv->flag = 0; + else { + sv->flag = 0; + } sv = svn; } } @@ -250,7 +252,9 @@ void removenotused_scredges(bScreen *sc) BLI_remlink(&sc->edgebase, se); MEM_freeN(se); } - else se->flag = 0; + else { + se->flag = 0; + } se = sen; } } @@ -1133,8 +1137,12 @@ void ED_screens_initialize(wmWindowManager *wm) void ED_region_exit(bContext *C, ARegion *ar) { + wmWindowManager *wm = CTX_wm_manager(C); ARegion *prevar = CTX_wm_region(C); + if (ar->type && ar->type->exit) + ar->type->exit(wm, ar); + CTX_wm_region_set(C, ar); WM_event_remove_handlers(C, &ar->handlers); if (ar->swinid) @@ -1153,18 +1161,12 @@ void ED_region_exit(bContext *C, ARegion *ar) void ED_area_exit(bContext *C, ScrArea *sa) { + wmWindowManager *wm = CTX_wm_manager(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *ar; - if (sa->spacetype == SPACE_FILE) { - SpaceLink *sl = sa->spacedata.first; - if (sl && sl->spacetype == SPACE_FILE) { - ED_fileselect_exit(C, (SpaceFile *)sl); - } - } - else if (sa->spacetype == SPACE_VIEW3D) { - ED_render_engine_area_exit(sa); - } + if (sa->type && sa->type->exit) + sa->type->exit(wm, sa); CTX_wm_area_set(C, sa); for (ar = sa->regionbase.first; ar; ar = ar->next) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index fcd0968d52f..1906a3259a9 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -644,7 +644,7 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type) wm_event_add(win, &event); } -static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event) { AZone *az = is_in_area_actionzone(CTX_wm_area(C), &event->x); sActionzoneData *sad; @@ -674,7 +674,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event) } -static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event) +static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) { sActionzoneData *sad = op->customdata; int deltax, deltay; @@ -769,7 +769,7 @@ typedef struct sAreaSwapData { ScrArea *sa1, *sa2; } sAreaSwapData; -static int area_swap_init(wmOperator *op, wmEvent *event) +static int area_swap_init(wmOperator *op, const wmEvent *event) { sAreaSwapData *sd = NULL; sActionzoneData *sad = event->customdata; @@ -800,7 +800,7 @@ static int area_swap_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!area_swap_init(op, event)) @@ -814,7 +814,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event) } -static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event) +static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event) { sActionzoneData *sad = op->customdata; @@ -866,7 +866,7 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot) /* *********** Duplicate area as new window operator ****************** */ /* operator callback */ -static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *newwin, *win; bScreen *newsc, *sc; @@ -1100,7 +1100,7 @@ static int area_move_exec(bContext *C, wmOperator *op) } /* interaction callback */ -static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RNA_int_set(op->ptr, "x", event->x); RNA_int_set(op->ptr, "y", event->y); @@ -1125,7 +1125,7 @@ static int area_move_cancel(bContext *C, wmOperator *op) } /* modal callback for while moving edges */ -static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event) +static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event) { sAreaMoveData *md = op->customdata; int delta, x, y; @@ -1382,7 +1382,7 @@ static void area_split_exit(bContext *C, wmOperator *op) /* UI callback, adds new handler */ -static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) { sAreaSplitData *sd; int dir; @@ -1514,7 +1514,7 @@ static int area_split_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event) +static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) { sAreaSplitData *sd = (sAreaSplitData *)op->customdata; float fac; @@ -1697,7 +1697,7 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge) return dist; } -static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event) { sActionzoneData *sad = event->customdata; AZone *az; @@ -1795,7 +1795,7 @@ static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd) region_scale_validate_size(rmd); } -static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event) +static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) { RegionMoveData *rmd = op->customdata; int delta; @@ -2318,7 +2318,7 @@ static int area_join_exec(bContext *C, wmOperator *op) } /* interaction callback */ -static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type == EVT_ACTIONZONE_AREA) { @@ -2374,7 +2374,7 @@ static int area_join_cancel(bContext *C, wmOperator *op) } /* modal callback while selecting area (space) that will be removed */ -static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event) +static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) { bScreen *sc = CTX_wm_screen(C); sAreaJoinData *jd = (sAreaJoinData *)op->customdata; @@ -2490,7 +2490,7 @@ static void SCREEN_OT_area_join(wmOperatorType *ot) /* ******************************* */ -static int screen_area_options_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event) { uiPopupMenu *pup; uiLayout *layout; @@ -2604,7 +2604,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) } -static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int repeat_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindowManager *wm = CTX_wm_manager(C); wmOperator *lastop; @@ -2661,7 +2661,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) /* ********************** redo operator ***************************** */ -static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { wmOperator *lastop = WM_operator_last_redo(C); @@ -2958,7 +2958,7 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN } } -static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -3071,7 +3071,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws) return 0; } -static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); @@ -3421,7 +3421,7 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) /* *********** show user pref window ****** */ -static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { wmWindow *win = CTX_wm_window(C); rcti rect; @@ -3696,7 +3696,7 @@ void region_blend_start(bContext *C, ScrArea *sa, ARegion *ar) } /* timer runs in win->handlers, so it cannot use context to find area/region */ -static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { RegionAlphaInfo *rgi; wmTimer *timer = event->customdata; @@ -3820,7 +3820,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf) } -static int open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) { if (drag->icon == ICON_FILE_BLEND) diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 9cde62e8302..0fbb4c25e78 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -204,7 +204,7 @@ static int screenshot_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (screenshot_data_create(C, op)) { if (RNA_struct_property_is_set(op->ptr, "filepath")) diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 5bed31e2e52..0899fb97a2a 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../uvedit ../../blenkernel ../../blenlib + ../../blenfont ../../blenloader ../../bmesh ../../gpu @@ -43,6 +44,7 @@ set(SRC paint_hide.c paint_image.c paint_image_2d.c + paint_image_proj.c paint_mask.c paint_ops.c paint_stroke.c @@ -57,4 +59,8 @@ set(SRC sculpt_intern.h ) +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript index 6767e06f65b..d10666de637 100644 --- a/source/blender/editors/sculpt_paint/SConscript +++ b/source/blender/editors/sculpt_paint/SConscript @@ -31,7 +31,7 @@ sources = env.Glob('*.c') defs = [] -incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' +incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include' incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh ../uvedit' @@ -47,4 +47,7 @@ if env['OURPLATFORM'] == 'linuxcross': if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] +if env['WITH_BF_INTERNATIONAL']: + defs.append('WITH_INTERNATIONAL') + env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] ) diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index ffea5af74a3..8d9cbbbcf11 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -207,14 +207,14 @@ static int load_tex(Brush *br, ViewContext *vc) x = (float)i / size; y = (float)j / size; - x -= 0.5f; - y -= 0.5f; - if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) { x *= vc->ar->winx / radius; y *= vc->ar->winy / radius; } else { + x -= 0.5f; + y -= 0.5f; + x *= 2; y *= 2; } @@ -345,14 +345,14 @@ static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc, { Scene *scene = CTX_data_scene(C); Paint *paint = paint_get_active_from_context(C); - float window[2]; + float mouse[2]; int hit; - window[0] = x + vc->ar->winrct.xmin; - window[1] = y + vc->ar->winrct.ymin; + mouse[0] = x; + mouse[1] = y; if (vc->obact->sculpt && vc->obact->sculpt->pbvh && - sculpt_stroke_get_location(C, location, window)) + sculpt_stroke_get_location(C, location, mouse)) { Brush *brush = paint_brush(paint); *pixel_radius = @@ -420,8 +420,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { /* brush rotation */ glTranslatef(0.5, 0.5, 0); - glRotatef((double)RAD2DEGF((brush->flag & BRUSH_RAKE) ? - ups->last_angle : ups->special_rotation), + glRotatef((double)RAD2DEGF(ups->brush_rotation), 0.0, 0.0, 1.0); glTranslatef(-0.5f, -0.5f, 0); @@ -434,11 +433,10 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, if (ups->draw_anchored) { const float *aim = ups->anchored_initial_mouse; - const rcti *win = &vc->ar->winrct; - quad.xmin = aim[0] - ups->anchored_size - win->xmin; - quad.ymin = aim[1] - ups->anchored_size - win->ymin; - quad.xmax = aim[0] + ups->anchored_size - win->xmin; - quad.ymax = aim[1] + ups->anchored_size - win->ymin; + quad.xmin = aim[0] - ups->anchored_size; + quad.ymin = aim[1] - ups->anchored_size; + quad.xmax = aim[0] + ups->anchored_size; + quad.ymax = aim[1] + ups->anchored_size; } else { const int radius = BKE_brush_size_get(vc->scene, brush); @@ -537,38 +535,22 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) * mouse over too, not just during a stroke */ view3d_set_viewcontext(C, &vc); + if (brush->flag & BRUSH_RAKE) + /* here, translation contains the mouse coordinates. */ + paint_calculate_rake_rotation(ups, translation); + + /* draw overlay */ + paint_draw_alpha_overlay(ups, brush, &vc, x, y); + /* TODO: as sculpt and other paint modes are unified, this * special mode of drawing will go away */ if (vc.obact->sculpt) { float location[3]; int pixel_radius, hit; - /* this is probably here so that rake takes into - * account the brush movements before the stroke - * starts, but this doesn't really belong in draw code - * TODO) */ - { - const float u = 0.5f; - const float v = 1 - u; - const float r = 20; - - const float dx = ups->last_x - x; - const float dy = ups->last_y - y; - - if (dx * dx + dy * dy >= r * r) { - ups->last_angle = atan2(dx, dy); - - ups->last_x = u * ups->last_x + v * x; - ups->last_y = u * ups->last_y + v * y; - } - } - /* test if brush is over the mesh */ hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location); - /* draw overlay */ - paint_draw_alpha_overlay(ups, brush, &vc, x, y); - if (BKE_brush_use_locked_size(scene, brush)) BKE_brush_size_set(scene, brush, pixel_radius); @@ -590,8 +572,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) if (ups->draw_anchored) { final_radius = ups->anchored_size; - translation[0] = ups->anchored_initial_mouse[0] - vc.ar->winrct.xmin; - translation[1] = ups->anchored_initial_mouse[1] - vc.ar->winrct.ymin; + translation[0] = ups->anchored_initial_mouse[0]; + translation[1] = ups->anchored_initial_mouse[1]; } } diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index d50261a3b98..14eb358f20f 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -424,7 +424,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int hide_show_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int hide_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) { PartialVisArea area = RNA_enum_get(op->ptr, "area"); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index edeb66d9281..144dfa948d0 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -101,298 +101,8 @@ #include "paint_intern.h" -/* Defines and Structs */ -/* FTOCHAR as inline function */ -BLI_INLINE unsigned char f_to_char(const float val) -{ - return FTOCHAR(val); -} - - -#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f) - -#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \ - (c)[0] = f_to_char((f)[0]); \ - (c)[1] = f_to_char((f)[1]); \ - (c)[2] = f_to_char((f)[2]); \ -} (void)0 -#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \ - (c)[0] = f_to_char((f)[0]); \ - (c)[1] = f_to_char((f)[1]); \ - (c)[2] = f_to_char((f)[2]); \ - (c)[3] = f_to_char((f)[3]); \ -} (void)0 -#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { \ - (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \ - (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \ - (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \ -} (void)0 -#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \ - (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \ - (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \ - (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \ - (f)[3] = IMAPAINT_CHAR_TO_FLOAT((c)[3]); \ -} (void)0 - -#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b) - #define IMAPAINT_TILE_BITS 6 #define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) -#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) - -static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint); - - -typedef struct ImagePaintState { - SpaceImage *sima; - View2D *v2d; - Scene *scene; - bScreen *screen; - - Brush *brush; - short tool, blend; - Image *image; - ImBuf *canvas; - ImBuf *clonecanvas; - char *warnpackedfile; - char *warnmultifile; - - /* viewport texture paint only, but _not_ project paint */ - Object *ob; - int faceindex; - float uv[2]; - int do_facesel; - - DerivedMesh *dm; - int dm_totface; - int dm_release; - - MFace *dm_mface; - MTFace *dm_mtface; -} ImagePaintState; - -typedef struct ImagePaintPartialRedraw { - int x1, y1, x2, y2; /* XXX, could use 'rcti' */ - int enabled; -} ImagePaintPartialRedraw; - -typedef struct ImagePaintRegion { - int destx, desty; - int srcx, srcy; - int width, height; -} ImagePaintRegion; - -/* ProjectionPaint defines */ - -/* approx the number of buckets to have under the brush, - * used with the brush size to set the ps->buckets_x and ps->buckets_y value. - * - * When 3 - a brush should have ~9 buckets under it at once - * ...this helps for threading while painting as well as - * avoiding initializing pixels that wont touch the brush */ -#define PROJ_BUCKET_BRUSH_DIV 4 - -#define PROJ_BUCKET_RECT_MIN 4 -#define PROJ_BUCKET_RECT_MAX 256 - -#define PROJ_BOUNDBOX_DIV 8 -#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV) - -//#define PROJ_DEBUG_PAINT 1 -//#define PROJ_DEBUG_NOSEAMBLEED 1 -//#define PROJ_DEBUG_PRINT_CLIP 1 -#define PROJ_DEBUG_WINCLIP 1 - -/* projectFaceSeamFlags options */ -//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */ -//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */ -#define PROJ_FACE_SEAM1 (1 << 0) /* If this face has a seam on any of its edges */ -#define PROJ_FACE_SEAM2 (1 << 1) -#define PROJ_FACE_SEAM3 (1 << 2) -#define PROJ_FACE_SEAM4 (1 << 3) - -#define PROJ_FACE_NOSEAM1 (1 << 4) -#define PROJ_FACE_NOSEAM2 (1 << 5) -#define PROJ_FACE_NOSEAM3 (1 << 6) -#define PROJ_FACE_NOSEAM4 (1 << 7) - -#define PROJ_SRC_VIEW 1 -#define PROJ_SRC_IMAGE_CAM 2 -#define PROJ_SRC_IMAGE_VIEW 3 - -#define PROJ_VIEW_DATA_ID "view_data" -#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */ - - -/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams - * as this number approaches 1.0f the likelihood increases of float precision errors where - * it is occluded by an adjacent face */ -#define PROJ_FACE_SCALE_SEAM 0.99f - -#define PROJ_BUCKET_NULL 0 -#define PROJ_BUCKET_INIT (1 << 0) -// #define PROJ_BUCKET_CLONE_INIT (1<<1) - -/* used for testing doubles, if a point is on a line etc */ -#define PROJ_GEOM_TOLERANCE 0.00075f - -/* vert flags */ -#define PROJ_VERT_CULL 1 - -/* This is mainly a convenience struct used so we can keep an array of images we use - * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread - * because 'partRedrawRect' and 'touch' values would not be thread safe */ -typedef struct ProjPaintImage { - Image *ima; - ImBuf *ibuf; - ImagePaintPartialRedraw *partRedrawRect; - void **undoRect; /* only used to build undo tiles after painting */ - int touch; -} ProjPaintImage; - -/* Main projection painting struct passed to all projection painting functions */ -typedef struct ProjPaintState { - View3D *v3d; - RegionView3D *rv3d; - ARegion *ar; - Scene *scene; - int source; /* PROJ_SRC_**** */ - - Brush *brush; - short tool, blend; - Object *ob; - /* end similarities with ImagePaintState */ - - DerivedMesh *dm; - int dm_totface; - int dm_totvert; - int dm_release; - - MVert *dm_mvert; - MFace *dm_mface; - MTFace *dm_mtface; - MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */ - MTFace *dm_mtface_stencil; - - /* projection painting only */ - MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */ - LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */ - LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */ - unsigned char *bucketFlags; /* store if the bucks have been initialized */ -#ifndef PROJ_DEBUG_NOSEAMBLEED - char *faceSeamFlags; /* store info about faces, if they are initialized etc*/ - float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */ - LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */ -#endif - char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */ - int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */ - int buckets_y; - - ProjPaintImage *projImages; - - int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */ - - int image_tot; /* size of projectImages array */ - - float (*screenCoords)[4]; /* verts projected into floating point screen space */ - - float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */ - float screenMax[2]; - float screen_width; /* Calculated from screenMin & screenMax */ - float screen_height; - int winx, winy; /* from the carea or from the projection render */ - - /* options for projection painting */ - int do_layer_clone; - int do_layer_stencil; - int do_layer_stencil_inv; - - short do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ - short do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ - short do_mask_normal; /* mask out pixels based on their normals */ - short do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */ - float normal_angle; /* what angle to mask at*/ - float normal_angle_inner; - float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */ - - short is_ortho; - bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */ - short is_texbrush; /* only to avoid running */ -#ifndef PROJ_DEBUG_NOSEAMBLEED - float seam_bleed_px; -#endif - /* clone vars */ - float cloneOffset[2]; - - float projectMat[4][4]; /* Projection matrix, use for getting screen coords */ - float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */ - float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */ - float clipsta, clipend; - - /* reproject vars */ - Image *reproject_image; - ImBuf *reproject_ibuf; - - - /* threads */ - int thread_tot; - int bucketMin[2]; - int bucketMax[2]; - int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */ -} ProjPaintState; - -typedef union pixelPointer { - float *f_pt; /* float buffer */ - unsigned int *uint_pt; /* 2 ways to access a char buffer */ - unsigned char *ch_pt; -} PixelPointer; - -typedef union pixelStore { - unsigned char ch[4]; - unsigned int uint; - float f[4]; -} PixelStore; - -typedef struct ProjPixel { - float projCoSS[2]; /* the floating point screen projection of this pixel */ - float worldCoSS[3]; - /* Only used when the airbrush is disabled. - * Store the max mask value to avoid painting over an area with a lower opacity - * with an advantage that we can avoid touching the pixel at all, if the - * new mask value is lower then mask_max */ - unsigned short mask_max; - - /* for various reasons we may want to mask out painting onto this pixel */ - unsigned short mask; - - short x_px, y_px; - - PixelStore origColor; - PixelStore newColor; - PixelPointer pixel; - - short image_index; /* if anyone wants to paint onto more then 32768 images they can bite me */ - unsigned char bb_cell_index; -} ProjPixel; - -typedef struct ProjPixelClone { - struct ProjPixel __pp; - PixelStore clonepx; -} ProjPixelClone; - -/* blur, store surrounding colors */ -#define PROJ_PIXEL_SOFTEN_TOT 4 -/* blur picking offset (in screenspace) */ -#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f - -static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = { - {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, - { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX}, - { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX}, - { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, -}; - -/* Finish projection painting structs */ typedef struct UndoImageTile { struct UndoImageTile *next, *prev; @@ -411,8 +121,21 @@ typedef struct UndoImageTile { char gen_type; } UndoImageTile; +/* this is a static resource for non-globality, + * Maybe it should be exposed as part of the + * paint operation, but for now just give a public interface */ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; +ImagePaintPartialRedraw *get_imapaintpartial(void) +{ + return &imapaintpartial; +} + +void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) +{ + imapaintpartial = *ippr; +} + /* UNDO */ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore) @@ -433,7 +156,7 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); } -static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile) +void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; @@ -472,7 +195,7 @@ static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int return tile->rect.pt; } -static void image_undo_restore(bContext *C, ListBase *lb) +void image_undo_restore(bContext *C, ListBase *lb) { Main *bmain = CTX_data_main(C); Image *ima = NULL; @@ -481,7 +204,7 @@ static void image_undo_restore(bContext *C, ListBase *lb) tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); - + for (tile = lb->first; tile; tile = tile->next) { short use_float; @@ -538,7 +261,7 @@ static void image_undo_restore(bContext *C, ListBase *lb) IMB_freeImBuf(tmpibuf); } -static void image_undo_free(ListBase *lb) +void image_undo_free(ListBase *lb) { UndoImageTile *tile; @@ -546,3839 +269,14 @@ static void image_undo_free(ListBase *lb) MEM_freeN(tile->rect.pt); } -/* get active image for face depending on old/new shading system */ - -static Image *imapaint_face_image(const ImagePaintState *s, int face_index) -{ - Image *ima; - - if (BKE_scene_use_new_shading_nodes(s->scene)) { - MFace *mf = &s->dm_mface[face_index]; - ED_object_get_active_image(s->ob, mf->mat_nr + 1, &ima, NULL, NULL); - } - else { - MTFace *tf = &s->dm_mtface[face_index]; - ima = tf->tpage; - } - - return ima; -} - -static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index) -{ - Image *ima; - - if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */ - MFace *mf = ps->dm_mface + face_index; - ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL); - } - else { - ima = dm_mtface[face_index].tpage; - } - - return ima; -} - -/* fast projection bucket array lookup, use the safe version for bound checking */ -static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2]) -{ - /* If we were not dealing with screenspace 2D coords we could simple do... - * ps->bucketRect[x + (y*ps->buckets_y)] */ - - /* please explain? - * projCoSS[0] - ps->screenMin[0] : zero origin - * ... / ps->screen_width : range from 0.0 to 1.0 - * ... * ps->buckets_x : use as a bucket index - * - * Second multiplication does similar but for vertical offset - */ - return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) + - (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x); -} - -static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2]) -{ - int bucket_index = project_bucket_offset(ps, projCoSS); - - if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) { - return -1; - } - else { - return bucket_index; - } -} - -/* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */ -static void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]) -{ - float wtot_inv, wtot; - - w[0] = area_tri_signed_v2(v2, v3, co) / v1[3]; - w[1] = area_tri_signed_v2(v3, v1, co) / v2[3]; - w[2] = area_tri_signed_v2(v1, v2, co) / v3[3]; - wtot = w[0] + w[1] + w[2]; - - if (wtot != 0.0f) { - wtot_inv = 1.0f / wtot; - - w[0] = w[0] * wtot_inv; - w[1] = w[1] * wtot_inv; - w[2] = w[2] * wtot_inv; - } - else /* dummy values for zero area face */ - w[0] = w[1] = w[2] = 1.0f / 3.0f; -} - -static float VecZDepthOrtho(const float pt[2], - const float v1[3], const float v2[3], const float v3[3], - float w[3]) -{ - barycentric_weights_v2(v1, v2, v3, pt, w); - return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]); -} - -static float VecZDepthPersp(const float pt[2], - const float v1[4], const float v2[4], const float v3[4], - float w[3]) -{ - float wtot_inv, wtot; - float w_tmp[3]; - - barycentric_weights_v2_persp(v1, v2, v3, pt, w); - /* for the depth we need the weights to match what - * barycentric_weights_v2 would return, in this case its easiest just to - * undo the 4th axis division and make it unit-sum - * - * don't call barycentric_weights_v2() because our callers expect 'w' - * to be weighted from the perspective */ - w_tmp[0] = w[0] * v1[3]; - w_tmp[1] = w[1] * v2[3]; - w_tmp[2] = w[2] * v3[3]; - - wtot = w_tmp[0] + w_tmp[1] + w_tmp[2]; - - if (wtot != 0.0f) { - wtot_inv = 1.0f / wtot; - - w_tmp[0] = w_tmp[0] * wtot_inv; - w_tmp[1] = w_tmp[1] * wtot_inv; - w_tmp[2] = w_tmp[2] * wtot_inv; - } - else /* dummy values for zero area face */ - w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f; - /* done mimicing barycentric_weights_v2() */ - - return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]); -} - - -/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */ -static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w[3], int *side) -{ - LinkNode *node; - float w_tmp[3]; - float *v1, *v2, *v3, *v4; - int bucket_index; - int face_index; - int best_side = -1; - int best_face_index = -1; - float z_depth_best = FLT_MAX, z_depth; - MFace *mf; - - bucket_index = project_bucket_offset_safe(ps, pt); - if (bucket_index == -1) - return -1; - - - - /* we could return 0 for 1 face buckets, as long as this function assumes - * that the point its testing is only every originated from an existing face */ - - for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { - face_index = GET_INT_FROM_POINTER(node->link); - mf = ps->dm_mface + face_index; - - v1 = ps->screenCoords[mf->v1]; - v2 = ps->screenCoords[mf->v2]; - v3 = ps->screenCoords[mf->v3]; - - if (isect_point_tri_v2(pt, v1, v2, v3)) { - if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v2, v3, w_tmp); - else z_depth = VecZDepthPersp(pt, v1, v2, v3, w_tmp); - - if (z_depth < z_depth_best) { - best_face_index = face_index; - best_side = 0; - z_depth_best = z_depth; - copy_v3_v3(w, w_tmp); - } - } - else if (mf->v4) { - v4 = ps->screenCoords[mf->v4]; - - if (isect_point_tri_v2(pt, v1, v3, v4)) { - if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v3, v4, w_tmp); - else z_depth = VecZDepthPersp(pt, v1, v3, v4, w_tmp); - - if (z_depth < z_depth_best) { - best_face_index = face_index; - best_side = 1; - z_depth_best = z_depth; - copy_v3_v3(w, w_tmp); - } - } - } - } - - *side = best_side; - return best_face_index; /* will be -1 or a valid face */ -} - -/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */ -static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) -{ - /* use */ - *x = (float)fmodf(uv[0], 1.0f); - *y = (float)fmodf(uv[1], 1.0f); - - if (*x < 0.0f) *x += 1.0f; - if (*y < 0.0f) *y += 1.0f; - - *x = *x * ibuf_x - 0.5f; - *y = *y * ibuf_y - 0.5f; -} - -/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */ -static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float *rgba_fp, unsigned char *rgba, const int interp) -{ - float w[3], uv[2]; - int side; - int face_index; - MTFace *tf; - Image *ima; - ImBuf *ibuf; - int xi, yi; - - - face_index = project_paint_PickFace(ps, pt, w, &side); - - if (face_index == -1) - return 0; - - tf = ps->dm_mtface + face_index; - - if (side == 0) { - interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); - } - else { /* QUAD */ - interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); - } - - ima = project_paint_face_image(ps, ps->dm_mtface, face_index); - ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */ - if (!ibuf) return 0; - - if (interp) { - float x, y; - uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y); - - if (ibuf->rect_float) { - if (rgba_fp) { - bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y); - } - else { - float rgba_tmp_f[4]; - bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y); - IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f); - } - } - else { - if (rgba) { - bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y); - } - else { - unsigned char rgba_tmp[4]; - bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y); - IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp); - } - } - } - else { - //xi = (int)((uv[0]*ibuf->x) + 0.5f); - //yi = (int)((uv[1]*ibuf->y) + 0.5f); - //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0; - - /* wrap */ - xi = ((int)(uv[0] * ibuf->x)) % ibuf->x; - if (xi < 0) xi += ibuf->x; - yi = ((int)(uv[1] * ibuf->y)) % ibuf->y; - if (yi < 0) yi += ibuf->y; - - - if (rgba) { - if (ibuf->rect_float) { - float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4); - IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp); - } - else { - *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4)); - } - } - - if (rgba_fp) { - if (ibuf->rect_float) { - copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4))); - } - else { - char *tmp_ch = ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4); - IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch); - } - } - } - return 1; -} - -/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test) - * return... - * 0 : no occlusion - * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad) - * 1 : occluded - * 2 : occluded with w[3] weights set (need to know in some cases) */ - -static int project_paint_occlude_ptv(float pt[3], float v1[4], float v2[4], float v3[4], float w[3], int is_ortho) -{ - /* if all are behind us, return false */ - if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) - return 0; - - /* do a 2D point in try intersection */ - if (!isect_point_tri_v2(pt, v1, v2, v3)) - return 0; /* we know there is */ - - - /* From here on we know there IS an intersection */ - /* if ALL of the verts are infront of us then we know it intersects ? */ - if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) { - return 1; - } - else { - /* we intersect? - find the exact depth at the point of intersection */ - /* Is this point is occluded by another face? */ - if (is_ortho) { - if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2; - } - else { - if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2; - } - } - return -1; -} - - -static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf, - float pt[3], float v1[4], float v2[4], float v3[4], - const int side) -{ - float w[3], wco[3]; - int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho); - - if (ret <= 0) - return ret; - - if (ret == 1) { /* weights not calculated */ - if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w); - else barycentric_weights_v2_persp(v1, v2, v3, pt, w); - } - - /* Test if we're in the clipped area, */ - if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); - else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); - - if (!ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { - return 1; - } - - return -1; -} - - -/* Check if a screenspace location is occluded by any other faces - * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison - * and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */ -static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4]) -{ - MFace *mf; - int face_index; - int isect_ret; - float w[3]; /* not needed when clipping */ - const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; - - /* we could return 0 for 1 face buckets, as long as this function assumes - * that the point its testing is only every originated from an existing face */ - - for (; bucketFace; bucketFace = bucketFace->next) { - face_index = GET_INT_FROM_POINTER(bucketFace->link); - - if (orig_face != face_index) { - mf = ps->dm_mface + face_index; - if (do_clip) - isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0); - else - isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho); - - /* Note, if (isect_ret == -1) then we don't want to test the other side of the quad */ - if (isect_ret == 0 && mf->v4) { - if (do_clip) - isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1); - else - isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho); - } - if (isect_ret >= 1) { - /* TODO - we may want to cache the first hit, - * it is not possible to swap the face order in the list anymore */ - return 1; - } - } - } - return 0; -} - -/* basic line intersection, could move to math_geom.c, 2 points with a horiz line - * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */ -#define ISECT_TRUE 1 -#define ISECT_TRUE_P1 2 -#define ISECT_TRUE_P2 3 -static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect) -{ - float y_diff; - - if (y_level == p1[1]) { /* are we touching the first point? - no interpolation needed */ - *x_isect = p1[0]; - return ISECT_TRUE_P1; - } - if (y_level == p2[1]) { /* are we touching the second point? - no interpolation needed */ - *x_isect = p2[0]; - return ISECT_TRUE_P2; - } - - y_diff = fabsf(p1[1] - p2[1]); /* yuck, horizontal line, we cant do much here */ - - if (y_diff < 0.000001f) { - *x_isect = (p1[0] + p2[0]) * 0.5f; - return ISECT_TRUE; - } - - if (p1[1] > y_level && p2[1] < y_level) { - *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/ - return ISECT_TRUE; - } - else if (p1[1] < y_level && p2[1] > y_level) { - *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/ - return ISECT_TRUE; - } - else { - return 0; - } -} - -static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect) -{ - float x_diff; - - if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */ - *y_isect = p1[1]; - return ISECT_TRUE_P1; - } - if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */ - *y_isect = p2[1]; - return ISECT_TRUE_P2; - } - - x_diff = fabsf(p1[0] - p2[0]); /* yuck, horizontal line, we cant do much here */ - - if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here */ - *y_isect = (p1[0] + p2[0]) * 0.5f; - return ISECT_TRUE; - } - - if (p1[0] > x_level && p2[0] < x_level) { - *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/ - return ISECT_TRUE; - } - else if (p1[0] < x_level && p2[0] > x_level) { - *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/ - return ISECT_TRUE; - } - else { - return 0; - } -} - -/* simple func use for comparing UV locations to check if there are seams. - * Its possible this gives incorrect results, when the UVs for 1 face go into the next - * tile, but do not do this for the adjacent face, it could return a false positive. - * This is so unlikely that Id not worry about it. */ -#ifndef PROJ_DEBUG_NOSEAMBLEED -static int cmp_uv(const float vec2a[2], const float vec2b[2]) -{ - /* if the UV's are not between 0.0 and 1.0 */ - float xa = (float)fmodf(vec2a[0], 1.0f); - float ya = (float)fmodf(vec2a[1], 1.0f); - - float xb = (float)fmodf(vec2b[0], 1.0f); - float yb = (float)fmodf(vec2b[1], 1.0f); - - if (xa < 0.0f) xa += 1.0f; - if (ya < 0.0f) ya += 1.0f; - - if (xb < 0.0f) xb += 1.0f; - if (yb < 0.0f) yb += 1.0f; - - return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 : 0; -} -#endif - -/* set min_px and max_px to the image space bounds of the UV coords - * return zero if there is no area in the returned rectangle */ -#ifndef PROJ_DEBUG_NOSEAMBLEED -static int pixel_bounds_uv( - const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2], - rcti *bounds_px, - const int ibuf_x, const int ibuf_y, - int is_quad - ) -{ - float min_uv[2], max_uv[2]; /* UV bounds */ - - INIT_MINMAX2(min_uv, max_uv); - - minmax_v2v2_v2(min_uv, max_uv, uv1); - minmax_v2v2_v2(min_uv, max_uv, uv2); - minmax_v2v2_v2(min_uv, max_uv, uv3); - if (is_quad) - minmax_v2v2_v2(min_uv, max_uv, uv4); - - bounds_px->xmin = (int)(ibuf_x * min_uv[0]); - bounds_px->ymin = (int)(ibuf_y * min_uv[1]); - - bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1; - bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1; - - /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ - - /* face uses no UV area when quantized to pixels? */ - return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; -} -#endif - -static int pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot) -{ - float min_uv[2], max_uv[2]; /* UV bounds */ - - if (tot == 0) { - return 0; - } - - INIT_MINMAX2(min_uv, max_uv); - - while (tot--) { - minmax_v2v2_v2(min_uv, max_uv, (*uv)); - uv++; - } - - bounds_px->xmin = (int)(ibuf_x * min_uv[0]); - bounds_px->ymin = (int)(ibuf_y * min_uv[1]); - - bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1; - bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1; - - /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ - - /* face uses no UV area when quantized to pixels? */ - return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; -} - -#ifndef PROJ_DEBUG_NOSEAMBLEED - -/* This function returns 1 if this face has a seam along the 2 face-vert indices - * 'orig_i1_fidx' and 'orig_i2_fidx' */ -static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx) -{ - LinkNode *node; - int face_index; - unsigned int i1, i2; - int i1_fidx = -1, i2_fidx = -1; /* index in face */ - MFace *mf; - MTFace *tf; - const MFace *orig_mf = ps->dm_mface + orig_face; - const MTFace *orig_tf = ps->dm_mtface + orig_face; - - /* vert indices from face vert order indices */ - i1 = (*(&orig_mf->v1 + orig_i1_fidx)); - i2 = (*(&orig_mf->v1 + orig_i2_fidx)); - - for (node = ps->vertFaces[i1]; node; node = node->next) { - face_index = GET_INT_FROM_POINTER(node->link); - - if (face_index != orig_face) { - mf = ps->dm_mface + face_index; - /* could check if the 2 faces images match here, - * but then there wouldn't be a way to return the opposite face's info */ - - - /* We need to know the order of the verts in the adjacent face - * set the i1_fidx and i2_fidx to (0,1,2,3) */ - if (mf->v1 == i1) i1_fidx = 0; - else if (mf->v2 == i1) i1_fidx = 1; - else if (mf->v3 == i1) i1_fidx = 2; - else if (mf->v4 && mf->v4 == i1) i1_fidx = 3; - - if (mf->v1 == i2) i2_fidx = 0; - else if (mf->v2 == i2) i2_fidx = 1; - else if (mf->v3 == i2) i2_fidx = 2; - else if (mf->v4 && mf->v4 == i2) i2_fidx = 3; - - /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */ - if (i2_fidx != -1) { - Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face); - - /* This IS an adjacent face!, now lets check if the UVs are ok */ - tf = ps->dm_mtface + face_index; - - /* set up the other face */ - *other_face = face_index; - *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx; - - /* first test if they have the same image */ - if ((orig_tpage == tpage) && - cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) && - cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) ) - { - // printf("SEAM (NONE)\n"); - return 0; - - } - else { - // printf("SEAM (UV GAP)\n"); - return 1; - } - } - } - } - // printf("SEAM (NO FACE)\n"); - *other_face = -1; - return 1; -} - -/* Calculate outset UV's, this is not the same as simply scaling the UVs, - * since the outset coords are a margin that keep an even distance from the original UV's, - * note that the image aspect is taken into account */ -static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, const int ibuf_x, const int ibuf_y, const int is_quad) -{ - float a1, a2, a3, a4 = 0.0f; - float puv[4][2]; /* pixelspace uv's */ - float no1[2], no2[2], no3[2], no4[2]; /* normals */ - float dir1[2], dir2[2], dir3[2], dir4[2]; - float ibuf_inv[2]; - - ibuf_inv[0] = 1.0f / (float)ibuf_x; - ibuf_inv[1] = 1.0f / (float)ibuf_y; - - /* make UV's in pixel space so we can */ - puv[0][0] = orig_uv[0][0] * ibuf_x; - puv[0][1] = orig_uv[0][1] * ibuf_y; - - puv[1][0] = orig_uv[1][0] * ibuf_x; - puv[1][1] = orig_uv[1][1] * ibuf_y; - - puv[2][0] = orig_uv[2][0] * ibuf_x; - puv[2][1] = orig_uv[2][1] * ibuf_y; - - if (is_quad) { - puv[3][0] = orig_uv[3][0] * ibuf_x; - puv[3][1] = orig_uv[3][1] * ibuf_y; - } - - /* face edge directions */ - sub_v2_v2v2(dir1, puv[1], puv[0]); - sub_v2_v2v2(dir2, puv[2], puv[1]); - normalize_v2(dir1); - normalize_v2(dir2); - - if (is_quad) { - sub_v2_v2v2(dir3, puv[3], puv[2]); - sub_v2_v2v2(dir4, puv[0], puv[3]); - normalize_v2(dir3); - normalize_v2(dir4); - } - else { - sub_v2_v2v2(dir3, puv[0], puv[2]); - normalize_v2(dir3); - } - - /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f) - * This is incorrect. Its already given radians but without it wont work. - * need to look into a fix - campbell */ - if (is_quad) { - a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI / 180.0f)); - a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f)); - a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f)); - a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI / 180.0f)); - } - else { - a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI / 180.0f)); - a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f)); - a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f)); - } - - if (is_quad) { - sub_v2_v2v2(no1, dir4, dir1); - sub_v2_v2v2(no2, dir1, dir2); - sub_v2_v2v2(no3, dir2, dir3); - sub_v2_v2v2(no4, dir3, dir4); - normalize_v2(no1); - normalize_v2(no2); - normalize_v2(no3); - normalize_v2(no4); - mul_v2_fl(no1, a1 * scaler); - mul_v2_fl(no2, a2 * scaler); - mul_v2_fl(no3, a3 * scaler); - mul_v2_fl(no4, a4 * scaler); - add_v2_v2v2(outset_uv[0], puv[0], no1); - add_v2_v2v2(outset_uv[1], puv[1], no2); - add_v2_v2v2(outset_uv[2], puv[2], no3); - add_v2_v2v2(outset_uv[3], puv[3], no4); - mul_v2_v2(outset_uv[0], ibuf_inv); - mul_v2_v2(outset_uv[1], ibuf_inv); - mul_v2_v2(outset_uv[2], ibuf_inv); - mul_v2_v2(outset_uv[3], ibuf_inv); - } - else { - sub_v2_v2v2(no1, dir3, dir1); - sub_v2_v2v2(no2, dir1, dir2); - sub_v2_v2v2(no3, dir2, dir3); - normalize_v2(no1); - normalize_v2(no2); - normalize_v2(no3); - mul_v2_fl(no1, a1 * scaler); - mul_v2_fl(no2, a2 * scaler); - mul_v2_fl(no3, a3 * scaler); - add_v2_v2v2(outset_uv[0], puv[0], no1); - add_v2_v2v2(outset_uv[1], puv[1], no2); - add_v2_v2v2(outset_uv[2], puv[2], no3); - - mul_v2_v2(outset_uv[0], ibuf_inv); - mul_v2_v2(outset_uv[1], ibuf_inv); - mul_v2_v2(outset_uv[2], ibuf_inv); - } -} - -/* - * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4 - * 1<<i - where i is (0-3) - * - * If we're multithreadng, make sure threads are locked when this is called - */ -static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad) -{ - int other_face, other_fidx; /* vars for the other face, we also set its flag */ - int fidx1 = is_quad ? 3 : 2; - int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */ - - do { - if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) { - if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) { - ps->faceSeamFlags[face_index] |= 1 << fidx1; - if (other_face != -1) - ps->faceSeamFlags[other_face] |= 1 << other_fidx; - } - else { - ps->faceSeamFlags[face_index] |= 16 << fidx1; - if (other_face != -1) - ps->faceSeamFlags[other_face] |= 16 << other_fidx; /* second 4 bits for disabled */ - } - } - - fidx2 = fidx1; - } while (fidx1--); -} -#endif // PROJ_DEBUG_NOSEAMBLEED - - -/* Converts a UV location to a 3D screenspace location - * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo - * - * This is used for finding a pixels location in screenspace for painting */ -static void screen_px_from_ortho( - float uv[2], - float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */ - float uv1co[2], float uv2co[2], float uv3co[2], - float pixelScreenCo[4], - float w[3]) -{ - barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); - interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); -} - -/* same as screen_px_from_ortho except we need to take into account - * the perspective W coord for each vert */ -static void screen_px_from_persp( - float uv[2], - float v1co[4], float v2co[4], float v3co[4], /* screenspace coords */ - float uv1co[2], float uv2co[2], float uv3co[2], - float pixelScreenCo[4], - float w[3]) -{ - - float wtot_inv, wtot; - barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); - - /* re-weight from the 4th coord of each screen vert */ - w[0] *= v1co[3]; - w[1] *= v2co[3]; - w[2] *= v3co[3]; - - wtot = w[0] + w[1] + w[2]; - - if (wtot > 0.0f) { - wtot_inv = 1.0f / wtot; - w[0] *= wtot_inv; - w[1] *= wtot_inv; - w[2] *= wtot_inv; - } - else { - w[0] = w[1] = w[2] = 1.0f / 3.0f; /* dummy values for zero area face */ - } - /* done re-weighting */ - - interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); -} - -static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], int side, unsigned char rgba_ub[4], float rgba_f[4]) -{ - float *uvCo1, *uvCo2, *uvCo3; - float uv_other[2], x, y; - - uvCo1 = (float *)tf_other->uv[0]; - if (side == 1) { - uvCo2 = (float *)tf_other->uv[2]; - uvCo3 = (float *)tf_other->uv[3]; - } - else { - uvCo2 = (float *)tf_other->uv[1]; - uvCo3 = (float *)tf_other->uv[2]; - } - - interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w); - - /* use */ - uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y); - - - if (ibuf_other->rect_float) { /* from float to float */ - bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y); - } - else { /* from char to float */ - bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y); - } - -} - -/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */ -static float project_paint_uvpixel_mask( - const ProjPaintState *ps, - const int face_index, - const int side, - const float w[3]) -{ - float mask; - - /* Image Mask */ - if (ps->do_layer_stencil) { - /* another UV maps image is masking this one's */ - ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index); - const MTFace *tf_other = ps->dm_mtface_stencil + face_index; - - if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { - /* BKE_image_acquire_ibuf - TODO - this may be slow */ - unsigned char rgba_ub[4]; - float rgba_f[4]; - - project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f); - - if (ibuf_other->rect_float) { /* from float to float */ - mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) / 3.0f) * rgba_f[3]; - } - else { /* from char to float */ - mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) / (256 * 3.0f)) * (rgba_ub[3] / 256.0f); - } - - BKE_image_release_ibuf(other_tpage, ibuf_other, NULL); - - if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */ - mask = (1.0f - mask); - - if (mask == 0.0f) { - return 0.0f; - } - } - else { - return 0.0f; - } - } - else { - mask = 1.0f; - } - - /* calculate mask */ - if (ps->do_mask_normal) { - MFace *mf = &ps->dm_mface[face_index]; - float no[3], angle; - if (mf->flag & ME_SMOOTH) { - short *no1, *no2, *no3; - no1 = ps->dm_mvert[mf->v1].no; - if (side == 1) { - no2 = ps->dm_mvert[mf->v3].no; - no3 = ps->dm_mvert[mf->v4].no; - } - else { - no2 = ps->dm_mvert[mf->v2].no; - no3 = ps->dm_mvert[mf->v3].no; - } - - no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0]; - no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1]; - no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2]; - normalize_v3(no); - } - else { - /* incase the */ -#if 1 - /* normalizing per pixel isn't optimal, we could cache or check ps->*/ - if (mf->v4) - normal_quad_v3(no, - ps->dm_mvert[mf->v1].co, - ps->dm_mvert[mf->v2].co, - ps->dm_mvert[mf->v3].co, - ps->dm_mvert[mf->v4].co); - else - normal_tri_v3(no, - ps->dm_mvert[mf->v1].co, - ps->dm_mvert[mf->v2].co, - ps->dm_mvert[mf->v3].co); -#else - /* don't use because some modifiers dont have normal data (subsurf for eg) */ - copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, face_index, CD_NORMAL)); -#endif - } - - /* now we can use the normal as a mask */ - if (ps->is_ortho) { - angle = angle_normalized_v3v3((float *)ps->viewDir, no); - } - else { - /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */ - float viewDirPersp[3]; - float *co1, *co2, *co3; - co1 = ps->dm_mvert[mf->v1].co; - if (side == 1) { - co2 = ps->dm_mvert[mf->v3].co; - co3 = ps->dm_mvert[mf->v4].co; - } - else { - co2 = ps->dm_mvert[mf->v2].co; - co3 = ps->dm_mvert[mf->v3].co; - } - - /* Get the direction from the viewPoint to the pixel and normalize */ - viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0])); - viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1])); - viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2])); - normalize_v3(viewDirPersp); - - angle = angle_normalized_v3v3(viewDirPersp, no); - } - - if (angle >= ps->normal_angle) { - return 0.0f; /* outsize the normal limit*/ - } - else if (angle > ps->normal_angle_inner) { - mask *= (ps->normal_angle - angle) / ps->normal_angle_range; - } /* otherwise no mask normal is needed, were within the limit */ - } - - /* This only works when the opacity dosnt change while painting, stylus pressure messes with this - * so don't use it. */ - // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush); - - return mask; -} - -static int project_paint_pixel_sizeof(const short tool) -{ - if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) { - return sizeof(ProjPixelClone); - } - else { - return sizeof(ProjPixel); - } -} - - -/* run this function when we know a bucket's, face's pixel can be initialized, - * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ -static ProjPixel *project_paint_uvpixel_init( - const ProjPaintState *ps, - MemArena *arena, - const ImBuf *ibuf, - short x_px, short y_px, - const float mask, - const int face_index, - const int image_index, - const float pixelScreenCo[4], - const float world_spaceCo[3], - const int side, - const float w[3]) -{ - ProjPixel *projPixel; - - /* wrap pixel location */ - x_px = x_px % ibuf->x; - if (x_px < 0) x_px += ibuf->x; - y_px = y_px % ibuf->y; - if (y_px < 0) y_px += ibuf->y; - - BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool)); - projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof); - //memset(projPixel, 0, size); - - if (ibuf->rect_float) { - projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4); - projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0]; - projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1]; - projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2]; - projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3]; - } - else { - projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4)); - projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt; - } - - /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */ - if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { - copy_v3_v3(projPixel->worldCoSS, world_spaceCo); - } - - copy_v2_v2(projPixel->projCoSS, pixelScreenCo); - - projPixel->x_px = x_px; - projPixel->y_px = y_px; - - projPixel->mask = (unsigned short)(mask * 65535); - projPixel->mask_max = 0; - - /* which bounding box cell are we in?, needed for undo */ - projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + - ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV; - - /* done with view3d_project_float inline */ - if (ps->tool == PAINT_TOOL_CLONE) { - if (ps->dm_mtface_clone) { - ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index); - const MTFace *tf_other = ps->dm_mtface_clone + face_index; - - if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { - /* BKE_image_acquire_ibuf - TODO - this may be slow */ - - if (ibuf->rect_float) { - if (ibuf_other->rect_float) { /* from float to float */ - project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f); - } - else { /* from char to float */ - unsigned char rgba_ub[4]; - project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL); - IMAPAINT_CHAR_RGBA_TO_FLOAT(((ProjPixelClone *)projPixel)->clonepx.f, rgba_ub); - } - } - else { - if (ibuf_other->rect_float) { /* float to char */ - float rgba[4]; - project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba); - IMAPAINT_FLOAT_RGBA_TO_CHAR(((ProjPixelClone *)projPixel)->clonepx.ch, rgba); - } - else { /* char to char */ - project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL); - } - } - - BKE_image_release_ibuf(other_tpage, ibuf_other, NULL); - } - else { - if (ibuf->rect_float) { - ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; - } - else { - ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; - } - } - - } - else { - float co[2]; - sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset); - - /* no need to initialize the bucket, we're only checking buckets faces and for this - * the faces are already initialized in project_paint_delayed_face_init(...) */ - if (ibuf->rect_float) { - if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) { - ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */ - } - } - else { - if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) { - ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */ - } - } - } - } - -#ifdef PROJ_DEBUG_PAINT - if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; - else projPixel->pixel.ch_pt[0] = 0; -#endif - projPixel->image_index = image_index; - - return projPixel; -} - -static int line_clip_rect2f( - rctf *rect, - const float l1[2], const float l2[2], - float l1_clip[2], float l2_clip[2]) -{ - /* first account for horizontal, then vertical lines */ - /* horiz */ - if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { - /* is the line out of range on its Y axis? */ - if (l1[1] < rect->ymin || l1[1] > rect->ymax) { - return 0; - } - /* line is out of range on its X axis */ - if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) { - return 0; - } - - - if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ - if (BLI_rctf_isect_pt_v(rect, l1)) { - copy_v2_v2(l1_clip, l1); - copy_v2_v2(l2_clip, l2); - return 1; - } - else { - return 0; - } - } - - copy_v2_v2(l1_clip, l1); - copy_v2_v2(l2_clip, l2); - CLAMP(l1_clip[0], rect->xmin, rect->xmax); - CLAMP(l2_clip[0], rect->xmin, rect->xmax); - return 1; - } - else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { - /* is the line out of range on its X axis? */ - if (l1[0] < rect->xmin || l1[0] > rect->xmax) { - return 0; - } - - /* line is out of range on its Y axis */ - if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) { - return 0; - } - - if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ - if (BLI_rctf_isect_pt_v(rect, l1)) { - copy_v2_v2(l1_clip, l1); - copy_v2_v2(l2_clip, l2); - return 1; - } - else { - return 0; - } - } - - copy_v2_v2(l1_clip, l1); - copy_v2_v2(l2_clip, l2); - CLAMP(l1_clip[1], rect->ymin, rect->ymax); - CLAMP(l2_clip[1], rect->ymin, rect->ymax); - return 1; - } - else { - float isect; - short ok1 = 0; - short ok2 = 0; - - /* Done with vertical lines */ - - /* are either of the points inside the rectangle ? */ - if (BLI_rctf_isect_pt_v(rect, l1)) { - copy_v2_v2(l1_clip, l1); - ok1 = 1; - } - - if (BLI_rctf_isect_pt_v(rect, l2)) { - copy_v2_v2(l2_clip, l2); - ok2 = 1; - } - - /* line inside rect */ - if (ok1 && ok2) return 1; - - /* top/bottom */ - if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { - if (l1[1] < l2[1]) { /* line 1 is outside */ - l1_clip[0] = isect; - l1_clip[1] = rect->ymin; - ok1 = 1; - } - else { - l2_clip[0] = isect; - l2_clip[1] = rect->ymin; - ok2 = 2; - } - } - - if (ok1 && ok2) return 1; - - if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { - if (l1[1] > l2[1]) { /* line 1 is outside */ - l1_clip[0] = isect; - l1_clip[1] = rect->ymax; - ok1 = 1; - } - else { - l2_clip[0] = isect; - l2_clip[1] = rect->ymax; - ok2 = 2; - } - } - - if (ok1 && ok2) return 1; - - /* left/right */ - if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { - if (l1[0] < l2[0]) { /* line 1 is outside */ - l1_clip[0] = rect->xmin; - l1_clip[1] = isect; - ok1 = 1; - } - else { - l2_clip[0] = rect->xmin; - l2_clip[1] = isect; - ok2 = 2; - } - } - - if (ok1 && ok2) return 1; - - if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { - if (l1[0] > l2[0]) { /* line 1 is outside */ - l1_clip[0] = rect->xmax; - l1_clip[1] = isect; - ok1 = 1; - } - else { - l2_clip[0] = rect->xmax; - l2_clip[1] = isect; - ok2 = 2; - } - } - - if (ok1 && ok2) { - return 1; - } - else { - return 0; - } - } -} - - - -/* scale the quad & tri about its center - * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the - * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces */ -#ifndef PROJ_DEBUG_NOSEAMBLEED -static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset) -{ - float cent[3]; - cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f; - cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f; - cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f; - - sub_v3_v3v3(insetCos[0], origCos[0], cent); - sub_v3_v3v3(insetCos[1], origCos[1], cent); - sub_v3_v3v3(insetCos[2], origCos[2], cent); - sub_v3_v3v3(insetCos[3], origCos[3], cent); - - mul_v3_fl(insetCos[0], inset); - mul_v3_fl(insetCos[1], inset); - mul_v3_fl(insetCos[2], inset); - mul_v3_fl(insetCos[3], inset); - - add_v3_v3(insetCos[0], cent); - add_v3_v3(insetCos[1], cent); - add_v3_v3(insetCos[2], cent); - add_v3_v3(insetCos[3], cent); -} - - -static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset) -{ - float cent[3]; - cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f; - cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f; - cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f; - - sub_v3_v3v3(insetCos[0], origCos[0], cent); - sub_v3_v3v3(insetCos[1], origCos[1], cent); - sub_v3_v3v3(insetCos[2], origCos[2], cent); - - mul_v3_fl(insetCos[0], inset); - mul_v3_fl(insetCos[1], inset); - mul_v3_fl(insetCos[2], inset); - - add_v3_v3(insetCos[0], cent); - add_v3_v3(insetCos[1], cent); - add_v3_v3(insetCos[2], cent); -} -#endif //PROJ_DEBUG_NOSEAMBLEED - -static float len_squared_v2v2_alt(const float *v1, const float v2_1, const float v2_2) -{ - float x, y; - - x = v1[0] - v2_1; - y = v1[1] - v2_2; - return x * x + y * y; -} - -/* note, use a squared value so we can use len_squared_v2v2 - * be sure that you have done a bounds check first or this may fail */ -/* only give bucket_bounds as an arg because we need it elsewhere */ -static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds) -{ - - /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect - * so we only need to test if the center is inside the vertical or horizontal bounds on either axis, - * this is even less work then an intersection test - */ -#if 0 - if (BLI_rctf_isect_pt_v(bucket_bounds, cent)) - return 1; -#endif - - if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) || - (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1])) - { - return 1; - } - - /* out of bounds left */ - if (cent[0] < bucket_bounds->xmin) { - /* lower left out of radius test */ - if (cent[1] < bucket_bounds->ymin) { - return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0; - } - /* top left test */ - else if (cent[1] > bucket_bounds->ymax) { - return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0; - } - } - else if (cent[0] > bucket_bounds->xmax) { - /* lower right out of radius test */ - if (cent[1] < bucket_bounds->ymin) { - return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0; - } - /* top right test */ - else if (cent[1] > bucket_bounds->ymax) { - return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0; - } - } - - return 0; -} - - - -/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp() - * in ortho view this function gives good results when bucket_bounds are outside the triangle - * however in some cases, perspective view will mess up with faces that have minimal screenspace area - * (viewed from the side) - * - * for this reason its not reliable in this case so we'll use the Simple Barycentric' - * funcs that only account for points inside the triangle. - * however switching back to this for ortho is always an option */ - -static void rect_to_uvspace_ortho( - rctf *bucket_bounds, - float *v1coSS, float *v2coSS, float *v3coSS, - float *uv1co, float *uv2co, float *uv3co, - float bucket_bounds_uv[4][2], - const int flip) -{ - float uv[2]; - float w[3]; - - /* get the UV space bounding box */ - uv[0] = bucket_bounds->xmax; - uv[1] = bucket_bounds->ymin; - barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w); - - //uv[0] = bucket_bounds->xmax; // set above - uv[1] = bucket_bounds->ymax; - barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w); - - uv[0] = bucket_bounds->xmin; - //uv[1] = bucket_bounds->ymax; // set above - barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w); - - //uv[0] = bucket_bounds->xmin; // set above - uv[1] = bucket_bounds->ymin; - barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w); -} - -/* same as above but use barycentric_weights_v2_persp */ -static void rect_to_uvspace_persp( - rctf *bucket_bounds, - float *v1coSS, float *v2coSS, float *v3coSS, - float *uv1co, float *uv2co, float *uv3co, - float bucket_bounds_uv[4][2], - const int flip - ) -{ - float uv[2]; - float w[3]; - - /* get the UV space bounding box */ - uv[0] = bucket_bounds->xmax; - uv[1] = bucket_bounds->ymin; - barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w); - - //uv[0] = bucket_bounds->xmax; // set above - uv[1] = bucket_bounds->ymax; - barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w); - - uv[0] = bucket_bounds->xmin; - //uv[1] = bucket_bounds->ymax; // set above - barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w); - - //uv[0] = bucket_bounds->xmin; // set above - uv[1] = bucket_bounds->ymin; - barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); - interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w); -} - -/* This works as we need it to but we can save a few steps and not use it */ - -#if 0 -static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2]) -{ - float v1[2], v2[2]; - - v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1]; - v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1]; - - return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]); -} -#endif - -#define ISECT_1 (1) -#define ISECT_2 (1 << 1) -#define ISECT_3 (1 << 2) -#define ISECT_4 (1 << 3) -#define ISECT_ALL3 ((1 << 3) - 1) -#define ISECT_ALL4 ((1 << 4) - 1) - -/* limit must be a fraction over 1.0f */ -static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit) -{ - return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) / (area_tri_v2(v1, v2, v3))) < limit; -} - -/* Clip the face by a bucket and set the uv-space bucket_bounds_uv - * so we have the clipped UV's to do pixel intersection tests with - * */ -static int float_z_sort_flip(const void *p1, const void *p2) -{ - return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1); -} - -static int float_z_sort(const void *p1, const void *p2) -{ - return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1); -} - -static void project_bucket_clip_face( - const int is_ortho, - rctf *bucket_bounds, - float *v1coSS, float *v2coSS, float *v3coSS, - float *uv1co, float *uv2co, float *uv3co, - float bucket_bounds_uv[8][2], - int *tot) -{ - int inside_bucket_flag = 0; - int inside_face_flag = 0; - const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); - - float bucket_bounds_ss[4][2]; - - /* get the UV space bounding box */ - inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS); - inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1; - inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2; - - if (inside_bucket_flag == ISECT_ALL3) { - /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */ - if (flip) { /* facing the back? */ - copy_v2_v2(bucket_bounds_uv[0], uv3co); - copy_v2_v2(bucket_bounds_uv[1], uv2co); - copy_v2_v2(bucket_bounds_uv[2], uv1co); - } - else { - copy_v2_v2(bucket_bounds_uv[0], uv1co); - copy_v2_v2(bucket_bounds_uv[1], uv2co); - copy_v2_v2(bucket_bounds_uv[2], uv3co); - } - - *tot = 3; - return; - } - - /* get the UV space bounding box */ - /* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */ - bucket_bounds_ss[0][0] = bucket_bounds->xmax; - bucket_bounds_ss[0][1] = bucket_bounds->ymin; - inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0); - - bucket_bounds_ss[1][0] = bucket_bounds->xmax; - bucket_bounds_ss[1][1] = bucket_bounds->ymax; - inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0); - - bucket_bounds_ss[2][0] = bucket_bounds->xmin; - bucket_bounds_ss[2][1] = bucket_bounds->ymax; - inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0); - - bucket_bounds_ss[3][0] = bucket_bounds->xmin; - bucket_bounds_ss[3][1] = bucket_bounds->ymin; - inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0); - - if (inside_face_flag == ISECT_ALL4) { - /* bucket is totally inside the screenspace face, we can safely use weights */ - - if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); - else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); - - *tot = 4; - return; - } - else { - /* The Complicated Case! - * - * The 2 cases above are where the face is inside the bucket or the bucket is inside the face. - * - * we need to make a convex polyline from the intersection between the screenspace face - * and the bucket bounds. - * - * There are a number of ways this could be done, currently it just collects all intersecting verts, - * and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to - * do a correct clipping on both shapes. */ - - - /* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */ - - - - /* Maximum possible 6 intersections when using a rectangle and triangle */ - float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */ - float v1_clipSS[2], v2_clipSS[2]; - float w[3]; - - /* calc center */ - float cent[2] = {0.0f, 0.0f}; - /*float up[2] = {0.0f, 1.0f};*/ - int i; - short doubles; - - (*tot) = 0; - - if (inside_face_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; } - if (inside_face_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; } - if (inside_face_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; } - if (inside_face_flag & ISECT_4) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; } - - if (inside_bucket_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], v1coSS); (*tot)++; } - if (inside_bucket_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], v2coSS); (*tot)++; } - if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; } - - if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) { - if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) { - if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } - if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } - } - } - - if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) { - if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) { - if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } - if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } - } - } - - if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) { - if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) { - if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } - if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } - } - } - - - if ((*tot) < 3) { /* no intersections to speak of */ - *tot = 0; - return; - } - - /* now we have all points we need, collect their angles and sort them clockwise */ - - for (i = 0; i < (*tot); i++) { - cent[0] += isectVCosSS[i][0]; - cent[1] += isectVCosSS[i][1]; - } - cent[0] = cent[0] / (float)(*tot); - cent[1] = cent[1] / (float)(*tot); - - - - /* Collect angles for every point around the center point */ - - -#if 0 /* uses a few more cycles then the above loop */ - for (i = 0; i < (*tot); i++) { - isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]); - } -#endif - - v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */ - v1_clipSS[1] = cent[1] + 1.0f; - - for (i = 0; i < (*tot); i++) { - v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; - v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; - isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]); - } - - if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip); - else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort); - - /* remove doubles */ - /* first/last check */ - if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_GEOM_TOLERANCE && - fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_GEOM_TOLERANCE) - { - (*tot)--; - } - - /* its possible there is only a few left after remove doubles */ - if ((*tot) < 3) { - // printf("removed too many doubles A\n"); - *tot = 0; - return; - } - - doubles = TRUE; - while (doubles == TRUE) { - doubles = FALSE; - for (i = 1; i < (*tot); i++) { - if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE && - fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE) - { - int j; - for (j = i + 1; j < (*tot); j++) { - isectVCosSS[j - 1][0] = isectVCosSS[j][0]; - isectVCosSS[j - 1][1] = isectVCosSS[j][1]; - } - doubles = TRUE; /* keep looking for more doubles */ - (*tot)--; - } - } - } - - /* its possible there is only a few left after remove doubles */ - if ((*tot) < 3) { - // printf("removed too many doubles B\n"); - *tot = 0; - return; - } - - - if (is_ortho) { - for (i = 0; i < (*tot); i++) { - barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); - interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); - } - } - else { - for (i = 0; i < (*tot); i++) { - barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); - interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); - } - } - } - -#ifdef PROJ_DEBUG_PRINT_CLIP - /* include this at the bottom of the above function to debug the output */ - - { - /* If there are ever any problems, */ - float test_uv[4][2]; - int i; - if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); - else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); - printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]); - - printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]); - - printf("["); - for (i = 0; i < (*tot); i++) { - printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]); - } - printf("]),\\\n"); - } -#endif -} - -/* - * # This script creates faces in a blender scene from printed data above. - * - * project_ls = [ - * ...(output from above block)... - * ] - * - * from Blender import Scene, Mesh, Window, sys, Mathutils - * - * import bpy - * - * V = Mathutils.Vector - * - * def main(): - * sce = bpy.data.scenes.active - * - * for item in project_ls: - * bb = item[0] - * uv = item[1] - * poly = item[2] - * - * me = bpy.data.meshes.new() - * ob = sce.objects.new(me) - * - * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz]) - * me.faces.extend([(0,1,2,3),]) - * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz]) - * me.faces.extend([(4,5,6),]) - * - * vs = [V(p).xyz for p in poly] - * print len(vs) - * l = len(me.verts) - * me.verts.extend(vs) - * - * i = l - * while i < len(me.verts): - * ii = i + 1 - * if ii == len(me.verts): - * ii = l - * me.edges.extend([i, ii]) - * i += 1 - * - * if __name__ == '__main__': - * main() - */ - - -#undef ISECT_1 -#undef ISECT_2 -#undef ISECT_3 -#undef ISECT_4 -#undef ISECT_ALL3 -#undef ISECT_ALL4 - - -/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise - * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */ -static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) -{ - int i; - if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f) - return 0; - - for (i = 1; i < tot; i++) { - if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f) - return 0; - - } - - return 1; -} -static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot) -{ - int i; - int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f); - - for (i = 1; i < tot; i++) { - if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side) - return 0; - - } - - return 1; -} - -/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket. - * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ -static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v) -{ - /* Projection vars, to get the 3D locations into screen space */ - MemArena *arena = ps->arena_mt[thread_index]; - LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; - LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; - - const MFace *mf = ps->dm_mface + face_index; - const MTFace *tf = ps->dm_mtface + face_index; - - /* UV/pixel seeking data */ - int x; /* Image X-Pixel */ - int y; /* Image Y-Pixel */ - float mask; - float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */ - - int side; - float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */ - - float *vCo[4]; /* vertex screenspace coords */ - - float w[3], wco[3]; - - float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */ - float pixelScreenCo[4]; - bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D; - - rcti bounds_px; /* ispace bounds */ - /* vars for getting uvspace bounds */ - - float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */ - float xhalfpx, yhalfpx; - const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y; - - int has_x_isect = 0, has_isect = 0; /* for early loop exit */ - - int i1, i2, i3; - - float uv_clip[8][2]; - int uv_clip_tot; - const short is_ortho = ps->is_ortho; - const short do_backfacecull = ps->do_backfacecull; - const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; - - vCo[0] = ps->dm_mvert[mf->v1].co; - vCo[1] = ps->dm_mvert[mf->v2].co; - vCo[2] = ps->dm_mvert[mf->v3].co; - - - /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel - * this is done so we can avoid offsetting all the pixels by 0.5 which causes - * problems when wrapping negative coords */ - xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 3.0f)) / ibuf_xf; - yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 4.0f)) / ibuf_yf; - - /* Note about (PROJ_GEOM_TOLERANCE/x) above... - * Needed to add this offset since UV coords are often quads aligned to pixels. - * In this case pixels can be exactly between 2 triangles causing nasty - * artifacts. - * - * This workaround can be removed and painting will still work on most cases - * but since the first thing most people try is painting onto a quad- better make it work. - */ - - - - tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx; - tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx; - - tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx; - tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx; - - tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx; - tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx; - - if (mf->v4) { - vCo[3] = ps->dm_mvert[mf->v4].co; - - tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx; - tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx; - side = 1; - } - else { - side = 0; - } - - do { - if (side == 1) { - i1 = 0; i2 = 2; i3 = 3; - } - else { - i1 = 0; i2 = 1; i3 = 2; - } - - uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1]; - uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2]; - uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3]; - - v1coSS = ps->screenCoords[(*(&mf->v1 + i1))]; - v2coSS = ps->screenCoords[(*(&mf->v1 + i2))]; - v3coSS = ps->screenCoords[(*(&mf->v1 + i3))]; - - /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/ - project_bucket_clip_face( - is_ortho, bucket_bounds, - v1coSS, v2coSS, v3coSS, - uv1co, uv2co, uv3co, - uv_clip, &uv_clip_tot - ); - - /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */ -#if 0 - if (uv_clip_tot > 6) { - printf("this should never happen! %d\n", uv_clip_tot); - } -#endif - - if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) { - - if (clamp_u) { - CLAMP(bounds_px.xmin, 0, ibuf->x); - CLAMP(bounds_px.xmax, 0, ibuf->x); - } - - if (clamp_v) { - CLAMP(bounds_px.ymin, 0, ibuf->y); - CLAMP(bounds_px.ymax, 0, ibuf->y); - } - - /* clip face and */ - - has_isect = 0; - for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { - //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; - uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */ - - has_x_isect = 0; - for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { - //uv[0] = (((float)x) + 0.5f) / ibuf->x; - uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */ - - /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work, - * could check the poly direction but better to do this */ - if ((do_backfacecull == TRUE && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) || - (do_backfacecull == FALSE && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) - { - - has_x_isect = has_isect = 1; - - if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); - else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); - - /* a pity we need to get the worldspace pixel location here */ - if (do_clip || do_3d_mapping) { - interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w); - if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { - continue; /* Watch out that no code below this needs to run */ - } - } - - /* Is this UV visible from the view? - raytrace */ - /* project_paint_PickFace is less complex, use for testing */ - //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) { - if ((ps->do_occlude == FALSE) || - !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) - { - mask = project_paint_uvpixel_mask(ps, face_index, side, w); - - if (mask > 0.0f) { - BLI_linklist_prepend_arena( - bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, - image_index, pixelScreenCo, wco, side, w), - arena - ); - } - } - - } -//#if 0 - else if (has_x_isect) { - /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ - break; - } -//#endif - } - - -#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ - /* no intersection for this entire row, after some intersection above means we can quit now */ - if (has_x_isect == 0 && has_isect) { - break; - } -#endif - } - } - } while (side--); - - - -#ifndef PROJ_DEBUG_NOSEAMBLEED - if (ps->seam_bleed_px > 0.0f) { - int face_seam_flag; - - if (ps->thread_tot > 1) - BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ - - face_seam_flag = ps->faceSeamFlags[face_index]; - - /* are any of our edges un-initialized? */ - if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_NOSEAM1)) == 0 || - (face_seam_flag & (PROJ_FACE_SEAM2 | PROJ_FACE_NOSEAM2)) == 0 || - (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0 || - (face_seam_flag & (PROJ_FACE_SEAM4 | PROJ_FACE_NOSEAM4)) == 0) - { - project_face_seams_init(ps, face_index, mf->v4); - face_seam_flag = ps->faceSeamFlags[face_index]; - //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4); - } - - if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) { - - if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ - - } - else { - /* we have a seam - deal with it! */ - - /* Now create new UV's for the seam face */ - float (*outset_uv)[2] = ps->faceSeamUVs[face_index]; - float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */ - - float *vCoSS[4]; /* vertex screenspace coords */ - - float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */ - float edge_verts_inset_clip[2][3]; - int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */ - - float seam_subsection[4][2]; - float fac1, fac2, ftot; - - - if (outset_uv[0][0] == FLT_MAX) /* first time initialize */ - uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4); - - /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ - if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ - - vCoSS[0] = ps->screenCoords[mf->v1]; - vCoSS[1] = ps->screenCoords[mf->v2]; - vCoSS[2] = ps->screenCoords[mf->v3]; - if (mf->v4) - vCoSS[3] = ps->screenCoords[mf->v4]; - - /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */ - if (is_ortho) { - if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); - else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); - } - else { - if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM); - else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM); - } - - side = 0; /* for triangles this wont need to change */ - - for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) { - if (mf->v4) fidx2 = (fidx1 == 3) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */ - else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */ - - if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */ - line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])) - { - - ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */ - - if (ftot > 0.0f) { /* avoid div by zero */ - if (mf->v4) { - if (fidx1 == 2 || fidx2 == 2) side = 1; - else side = 0; - } - - fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot; - fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot; - - interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1); - interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2); - - interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2); - interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1); - - /* if the bucket_clip_edges values Z values was kept we could avoid this - * Inset needs to be added so occlusion tests wont hit adjacent faces */ - interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1); - interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2); - - - if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) { - /* bounds between the seam rect and the uvspace bucket pixels */ - - has_isect = 0; - for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { - // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; - uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */ - - has_x_isect = 0; - for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { - //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x; - uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */ - - /* test we're inside uvspace bucket and triangle bounds */ - if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) { - float fac; - - /* We need to find the closest point along the face edge, - * getting the screen_px_from_*** wont work because our actual location - * is not relevant, since we are outside the face, Use VecLerpf to find - * our location on the side of the face's UV */ -#if 0 - if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); - else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); -#endif - - /* Since this is a seam we need to work out where on the line this pixel is */ - //fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]); - - fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]); - if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); } - else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); } - else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); } - - if (!is_ortho) { - pixelScreenCo[3] = 1.0f; - mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */ - pixelScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * pixelScreenCo[0] / pixelScreenCo[3]; - pixelScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * pixelScreenCo[1] / pixelScreenCo[3]; - pixelScreenCo[2] = pixelScreenCo[2] / pixelScreenCo[3]; /* Use the depth for bucket point occlusion */ - } - - if ((ps->do_occlude == FALSE) || - !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) - { - /* Only bother calculating the weights if we intersect */ - if (ps->do_mask_normal || ps->dm_mtface_clone) { -#if 1 - /* get the UV on the line since we want to copy the pixels from there for bleeding */ - float uv_close[2]; - float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]); - if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]); - else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]); - - if (side) { - barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w); - } - else { - barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w); - } -#else /* this is buggy with quads, don't use for now */ - - /* Cheat, we know where we are along the edge so work out the weights from that */ - uv_fac = fac1 + (uv_fac * (fac2 - fac1)); - - w[0] = w[1] = w[2] = 0.0; - if (side) { - w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac; - w[fidx2 ? fidx2 - 1 : 0] = uv_fac; - } - else { - w[fidx1] = 1.0f - uv_fac; - w[fidx2] = uv_fac; - } -#endif - } - - /* a pity we need to get the worldspace pixel location here */ - if (do_clip || do_3d_mapping) { - if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); - else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); - - if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { - continue; /* Watch out that no code below this needs to run */ - } - } - - mask = project_paint_uvpixel_mask(ps, face_index, side, w); - - if (mask > 0.0f) { - BLI_linklist_prepend_arena( - bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w), - arena - ); - } - - } - } - else if (has_x_isect) { - /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ - break; - } - } - -#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ - /* no intersection for this entire row, after some intersection above means we can quit now */ - if (has_x_isect == 0 && has_isect) { - break; - } -#endif - } - } - } - } - } - } - } -#endif // PROJ_DEBUG_NOSEAMBLEED -} - - -/* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */ -static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2]) -{ - /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */ - /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */ - bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */ - bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f); - - bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f); - bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f); - - /* in case the rect is outside the mesh 2d bounds */ - CLAMP(bucketMin[0], 0, ps->buckets_x); - CLAMP(bucketMin[1], 0, ps->buckets_y); - - CLAMP(bucketMax[0], 0, ps->buckets_x); - CLAMP(bucketMax[1], 0, ps->buckets_y); -} - -/* set bucket_bounds to a screen space-aligned floating point bound-box */ -static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds) -{ - bucket_bounds->xmin = ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)); /* left */ - bucket_bounds->xmax = ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)); /* right */ - - bucket_bounds->ymin = ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)); /* bottom */ - bucket_bounds->ymax = ps->screenMin[1] + ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)); /* top */ -} - -/* Fill this bucket with pixels from the faces that intersect it. - * - * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */ -static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds) -{ - LinkNode *node; - int face_index, image_index = 0; - ImBuf *ibuf = NULL; - Image *tpage_last = NULL, *tpage; - Image *ima = NULL; - - if (ps->image_tot == 1) { - /* Simple loop, no context switching */ - ibuf = ps->projImages[0].ibuf; - ima = ps->projImages[0].ima; - - for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { - project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); - } - } - else { - - /* More complicated loop, switch between images */ - for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { - face_index = GET_INT_FROM_POINTER(node->link); - - /* Image context switching */ - tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - if (tpage_last != tpage) { - tpage_last = tpage; - - for (image_index = 0; image_index < ps->image_tot; image_index++) { - if (ps->projImages[image_index].ima == tpage_last) { - ibuf = ps->projImages[image_index].ibuf; - ima = ps->projImages[image_index].ima; - break; - } - } - } - /* context switching done */ - - project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); - } - } - - ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; -} - - -/* We want to know if a bucket and a face overlap in screen-space - * - * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels - * calculated when it might not be needed later, (at the moment at least) - * obviously it shouldn't have bugs though */ - -static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf) -{ - /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */ - rctf bucket_bounds; - float p1[2], p2[2], p3[2], p4[2]; - float *v, *v1, *v2, *v3, *v4 = NULL; - int fidx; - - project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds); - - /* Is one of the faces verts in the bucket bounds? */ - - fidx = mf->v4 ? 3 : 2; - do { - v = ps->screenCoords[(*(&mf->v1 + fidx))]; - if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) { - return 1; - } - } while (fidx--); - - v1 = ps->screenCoords[mf->v1]; - v2 = ps->screenCoords[mf->v2]; - v3 = ps->screenCoords[mf->v3]; - if (mf->v4) { - v4 = ps->screenCoords[mf->v4]; - } - - p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin; - p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax; - p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax; - p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin; - - if (mf->v4) { - if (isect_point_quad_v2(p1, v1, v2, v3, v4) || - isect_point_quad_v2(p2, v1, v2, v3, v4) || - isect_point_quad_v2(p3, v1, v2, v3, v4) || - isect_point_quad_v2(p4, v1, v2, v3, v4) || - - /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ - (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) || - (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) || - (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) || - (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4))) - { - return 1; - } - } - else { - if (isect_point_tri_v2(p1, v1, v2, v3) || - isect_point_tri_v2(p2, v1, v2, v3) || - isect_point_tri_v2(p3, v1, v2, v3) || - isect_point_tri_v2(p4, v1, v2, v3) || - /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ - (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) || - (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) || - (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) || - (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3))) - { - return 1; - } - } - - return 0; -} - -/* Add faces to the bucket but don't initialize its pixels - * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */ -static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index) -{ - float min[2], max[2], *vCoSS; - int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */ - int fidx, bucket_x, bucket_y; - int has_x_isect = -1, has_isect = 0; /* for early loop exit */ - MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */ - - INIT_MINMAX2(min, max); - - fidx = mf->v4 ? 3 : 2; - do { - vCoSS = ps->screenCoords[*(&mf->v1 + fidx)]; - minmax_v2v2_v2(min, max, vCoSS); - } while (fidx--); - - project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax); - - for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) { - has_x_isect = 0; - for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) { - if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) { - int bucket_index = bucket_x + (bucket_y * ps->buckets_x); - BLI_linklist_prepend_arena( - &ps->bucketFaces[bucket_index], - SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */ - arena - ); - - has_x_isect = has_isect = 1; - } - else if (has_x_isect) { - /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ - break; - } - } - - /* no intersection for this entire row, after some intersection above means we can quit now */ - if (has_x_isect == 0 && has_isect) { - break; - } - } - -#ifndef PROJ_DEBUG_NOSEAMBLEED - if (ps->seam_bleed_px > 0.0f) { - if (!mf->v4) { - ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */ - } - **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */ - } -#endif -} - -static int project_paint_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) -{ - int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); - - if (orth) { /* only needed for ortho */ - float fac = 2.0f / ((*clipend) - (*clipsta)); - *clipsta *= fac; - *clipend *= fac; - } - - return orth; -} - -/* run once per stroke before projection painting */ -static void project_paint_begin(ProjPaintState *ps) -{ - /* Viewport vars */ - float mat[3][3]; - - float no[3]; - - float *projScreenCo; /* Note, we could have 4D vectors are only needed for */ - float projMargin; - - /* Image Vars - keep track of images we have used */ - LinkNode *image_LinkList = NULL; - LinkNode *node; - - ProjPaintImage *projIma; - Image *tpage_last = NULL, *tpage; - - /* Face vars */ - MFace *mf; - MTFace *tf; - - int a, i; /* generic looping vars */ - int image_index = -1, face_index; - MVert *mv; - - MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ - - const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); - - /* ---- end defines ---- */ - - if (ps->source == PROJ_SRC_VIEW) - ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ - - /* paint onto the derived mesh */ - - /* Workaround for subsurf selection, try the display mesh first */ - if (ps->source == PROJ_SRC_IMAGE_CAM) { - /* using render mesh, assume only camera was rendered from */ - ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); - ps->dm_release = TRUE; - } - else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) { - ps->dm = ps->ob->derivedFinal; - ps->dm_release = FALSE; - } - else { - ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); - ps->dm_release = TRUE; - } - - if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) { - - if (ps->dm_release) - ps->dm->release(ps->dm); - - ps->dm = NULL; - return; - } - - ps->dm_mvert = ps->dm->getVertArray(ps->dm); - ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); - ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); - - ps->dm_totvert = ps->dm->getNumVerts(ps->dm); - ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); - - /* use clone mtface? */ - - - /* Note, use the original mesh for getting the clone and mask layer index - * this avoids re-generating the derived mesh just to get the new index */ - if (ps->do_layer_clone) { - //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE); - int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); - if (layer_num != -1) - ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - - if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) { - ps->do_layer_clone = FALSE; - ps->dm_mtface_clone = NULL; - printf("ACK!\n"); - } - } - - if (ps->do_layer_stencil) { - //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE); - int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); - if (layer_num != -1) - ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - - if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) { - ps->do_layer_stencil = FALSE; - ps->dm_mtface_stencil = NULL; - } - } - - /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ - if (ps->dm->type != DM_TYPE_CDDM) { - ps->dm_mvert = MEM_dupallocN(ps->dm_mvert); - ps->dm_mface = MEM_dupallocN(ps->dm_mface); - /* looks like these are ok for now.*/ -#if 0 - ps->dm_mtface = MEM_dupallocN(ps->dm_mtface); - ps->dm_mtface_clone = MEM_dupallocN(ps->dm_mtface_clone); - ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil); -#endif - } - - ps->viewDir[0] = 0.0f; - ps->viewDir[1] = 0.0f; - ps->viewDir[2] = 1.0f; - - { - float viewmat[4][4]; - float viewinv[4][4]; - - invert_m4_m4(ps->ob->imat, ps->ob->obmat); - - if (ps->source == PROJ_SRC_VIEW) { - /* normal drawing */ - ps->winx = ps->ar->winx; - ps->winy = ps->ar->winy; - - copy_m4_m4(viewmat, ps->rv3d->viewmat); - copy_m4_m4(viewinv, ps->rv3d->viewinv); - - ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat); - - ps->is_ortho = project_paint_view_clip(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend); - } - else { - /* re-projection */ - float winmat[4][4]; - float vmat[4][4]; - - ps->winx = ps->reproject_ibuf->x; - ps->winy = ps->reproject_ibuf->y; - - if (ps->source == PROJ_SRC_IMAGE_VIEW) { - /* image stores camera data, tricky */ - IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0); - IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); - - float *array = (float *)IDP_Array(view_data); - - /* use image array, written when creating image */ - memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float); - memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float); - ps->clipsta = array[0]; - ps->clipend = array[1]; - ps->is_ortho = array[2] ? 1 : 0; - - invert_m4_m4(viewinv, viewmat); - } - else if (ps->source == PROJ_SRC_IMAGE_CAM) { - Object *cam_ob = ps->scene->camera; - CameraParams params; - - /* viewmat & viewinv */ - copy_m4_m4(viewinv, cam_ob->obmat); - normalize_m4(viewinv); - invert_m4_m4(viewmat, viewinv); - - /* window matrix, clipping and ortho */ - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, cam_ob); - BKE_camera_params_compute_viewplane(¶ms, ps->winx, ps->winy, 1.0f, 1.0f); - BKE_camera_params_compute_matrix(¶ms); - - copy_m4_m4(winmat, params.winmat); - ps->clipsta = params.clipsta; - ps->clipend = params.clipend; - ps->is_ortho = params.is_ortho; - } - - /* same as #ED_view3d_ob_project_mat_get */ - mult_m4_m4m4(vmat, viewmat, ps->ob->obmat); - mult_m4_m4m4(ps->projectMat, winmat, vmat); - } - - - /* viewDir - object relative */ - invert_m4_m4(ps->ob->imat, ps->ob->obmat); - copy_m3_m4(mat, viewinv); - mul_m3_v3(mat, ps->viewDir); - copy_m3_m4(mat, ps->ob->imat); - mul_m3_v3(mat, ps->viewDir); - normalize_v3(ps->viewDir); - - /* viewPos - object relative */ - copy_v3_v3(ps->viewPos, viewinv[3]); - copy_m3_m4(mat, ps->ob->imat); - mul_m3_v3(mat, ps->viewPos); - add_v3_v3(ps->viewPos, ps->ob->imat[3]); - } - - /* calculate vert screen coords - * run this early so we can calculate the x/y resolution of our bucket rect */ - INIT_MINMAX2(ps->screenMin, ps->screenMax); - - ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts"); - projScreenCo = *ps->screenCoords; - - if (ps->is_ortho) { - for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) { - mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co); - - /* screen space, not clamped */ - projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0]; - projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1]; - minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo); - } - } - else { - for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) { - copy_v3_v3(projScreenCo, mv->co); - projScreenCo[3] = 1.0f; - - mul_m4_v4(ps->projectMat, projScreenCo); - - if (projScreenCo[3] > ps->clipsta) { - /* screen space, not clamped */ - projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0] / projScreenCo[3]; - projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1] / projScreenCo[3]; - projScreenCo[2] = projScreenCo[2] / projScreenCo[3]; /* Use the depth for bucket point occlusion */ - minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo); - } - else { - /* TODO - deal with cases where 1 side of a face goes behind the view ? - * - * After some research this is actually very tricky, only option is to - * clip the derived mesh before painting, which is a Pain */ - projScreenCo[0] = FLT_MAX; - } - } - } - - /* If this border is not added we get artifacts for faces that - * have a parallel edge and at the bounds of the the 2D projected verts eg - * - a single screen aligned quad */ - projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f; - ps->screenMax[0] += projMargin; - ps->screenMin[0] -= projMargin; - projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f; - ps->screenMax[1] += projMargin; - ps->screenMin[1] -= projMargin; - - if (ps->source == PROJ_SRC_VIEW) { -#ifdef PROJ_DEBUG_WINCLIP - CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter)); - CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter)); - - CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter)); - CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter)); -#endif - } - else { /* re-projection, use bounds */ - ps->screenMin[0] = 0; - ps->screenMax[0] = (float)(ps->winx); - - ps->screenMin[1] = 0; - ps->screenMax[1] = (float)(ps->winy); - } - - /* only for convenience */ - ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; - ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; - - ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); - ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); - - /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ - - /* really high values could cause problems since it has to allocate a few - * (ps->buckets_x*ps->buckets_y) sized arrays */ - CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); - CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); - - ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect"); - ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); - - ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); -#ifndef PROJ_DEBUG_NOSEAMBLEED - if (ps->seam_bleed_px > 0.0f) { - ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces"); - ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags"); - ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs"); - } -#endif - - /* Thread stuff - * - * very small brushes run a lot slower multithreaded since the advantage with - * threads is being able to fill in multiple buckets at once. - * Only use threads for bigger brushes. */ - - if (ps->scene->r.mode & R_FIXED_THREADS) { - ps->thread_tot = ps->scene->r.threads; - } - else { - ps->thread_tot = BLI_system_thread_count(); - } - for (a = 0; a < ps->thread_tot; a++) { - ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena"); - } - - arena = ps->arena_mt[0]; - - if (ps->do_backfacecull && ps->do_mask_normal) { - float viewDirPersp[3]; - - ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags"); - - for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) { - normal_short_to_float_v3(no, mv->no); - - if (ps->is_ortho) { - if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ - ps->vertFlags[a] |= PROJ_VERT_CULL; - } - } - else { - sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co); - normalize_v3(viewDirPersp); - if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ - ps->vertFlags[a] |= PROJ_VERT_CULL; - } - } - } - } - - - for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { - -#ifndef PROJ_DEBUG_NOSEAMBLEED - /* add face user if we have bleed enabled, set the UV seam flags later */ - /* annoying but we need to add all faces even ones we never use elsewhere */ - if (ps->seam_bleed_px > 0.0f) { - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena); - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena); - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena); - if (mf->v4) { - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena); - } - } -#endif - - tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - - if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) { - - float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; - - v1coSS = ps->screenCoords[mf->v1]; - v2coSS = ps->screenCoords[mf->v2]; - v3coSS = ps->screenCoords[mf->v3]; - if (mf->v4) { - v4coSS = ps->screenCoords[mf->v4]; - } - - - if (!ps->is_ortho) { - if (v1coSS[0] == FLT_MAX || - v2coSS[0] == FLT_MAX || - v3coSS[0] == FLT_MAX || - (mf->v4 && v4coSS[0] == FLT_MAX)) - { - continue; - } - } - -#ifdef PROJ_DEBUG_WINCLIP - /* ignore faces outside the view */ - if ( - (v1coSS[0] < ps->screenMin[0] && - v2coSS[0] < ps->screenMin[0] && - v3coSS[0] < ps->screenMin[0] && - (mf->v4 && v4coSS[0] < ps->screenMin[0])) || - - (v1coSS[0] > ps->screenMax[0] && - v2coSS[0] > ps->screenMax[0] && - v3coSS[0] > ps->screenMax[0] && - (mf->v4 && v4coSS[0] > ps->screenMax[0])) || - - (v1coSS[1] < ps->screenMin[1] && - v2coSS[1] < ps->screenMin[1] && - v3coSS[1] < ps->screenMin[1] && - (mf->v4 && v4coSS[1] < ps->screenMin[1])) || - - (v1coSS[1] > ps->screenMax[1] && - v2coSS[1] > ps->screenMax[1] && - v3coSS[1] > ps->screenMax[1] && - (mf->v4 && v4coSS[1] > ps->screenMax[1])) - ) - { - continue; - } - -#endif //PROJ_DEBUG_WINCLIP - - - if (ps->do_backfacecull) { - if (ps->do_mask_normal) { - /* Since we are interpolating the normals of faces, we want to make - * sure all the verts are pointing away from the view, - * not just the face */ - if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) && - (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) && - (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) && - (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL) - ) - { - continue; - } - } - else { - if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) { - continue; - } - - } - } - - if (tpage_last != tpage) { - - image_index = BLI_linklist_index(image_LinkList, tpage); - - if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */ - BLI_linklist_append(&image_LinkList, tpage); - image_index = ps->image_tot; - ps->image_tot++; - } - - tpage_last = tpage; - } - - if (image_index != -1) { - /* Initialize the faces screen pixels */ - /* Add this to a list to initialize later */ - project_paint_delayed_face_init(ps, mf, face_index); - } - } - } - - /* build an array of images we use*/ - projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot); - - for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) { - projIma->ima = node->link; - projIma->touch = 0; - projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); - projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - } - - /* we have built the array, discard the linked list */ - BLI_linklist_free(image_LinkList, NULL); -} - -static void project_paint_begin_clone(ProjPaintState *ps, int mouse[2]) -{ - /* setup clone offset */ - if (ps->tool == PAINT_TOOL_CLONE) { - float projCo[4]; - copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d)); - mul_m4_v3(ps->ob->imat, projCo); - - projCo[3] = 1.0f; - mul_m4_v4(ps->projectMat, projCo); - ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projCo[0] / projCo[3]); - ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projCo[1] / projCo[3]); - } -} - -static void project_paint_end(ProjPaintState *ps) -{ - int a; - ProjPaintImage *projIma; - - /* build undo data from original pixel colors */ - if (U.uiflag & USER_GLOBALUNDO) { - ProjPixel *projPixel; - ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; - LinkNode *pixel_node; - void *tilerect; - MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */ - - int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */ - int bucket_index; - int tile_index; - int x_round, y_round; - int x_tile, y_tile; - int is_float = -1; - - /* context */ - ProjPaintImage *last_projIma; - int last_image_index = -1; - int last_tile_width = 0; - - for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) { - int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); - last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size); - memset(last_projIma->undoRect, 0, size); - last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; - } - - for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { - /* loop through all pixels */ - for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) { - - /* ok we have a pixel, was it modified? */ - projPixel = (ProjPixel *)pixel_node->link; - - if (last_image_index != projPixel->image_index) { - /* set the context */ - last_image_index = projPixel->image_index; - last_projIma = ps->projImages + last_image_index; - last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x); - is_float = last_projIma->ibuf->rect_float ? 1 : 0; - } - - - if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) || - (is_float == 1 && - (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] || - projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] || - projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] || - projPixel->origColor.f[3] != projPixel->pixel.f_pt[3])) - ) - { - - x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS; - y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS; - - x_round = x_tile * IMAPAINT_TILE_SIZE; - y_round = y_tile * IMAPAINT_TILE_SIZE; - - tile_index = x_tile + y_tile * last_tile_width; - - if (last_projIma->undoRect[tile_index] == NULL) { - /* add the undo tile from the modified image, then write the original colors back into it */ - tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile); - } - else { - tilerect = last_projIma->undoRect[tile_index]; - } - - /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color - * because allocating the tiles along the way slows down painting */ - - if (is_float) { - float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4; - copy_v4_v4(rgba_fp, projPixel->origColor.f); - } - else { - ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint; - } - } - } - } - - if (tmpibuf) IMB_freeImBuf(tmpibuf); - if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); - } - /* done calculating undo data */ - - /* dereference used image buffers */ - for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { - BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL); - } - - BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL); - - MEM_freeN(ps->screenCoords); - MEM_freeN(ps->bucketRect); - MEM_freeN(ps->bucketFaces); - MEM_freeN(ps->bucketFlags); - -#ifndef PROJ_DEBUG_NOSEAMBLEED - if (ps->seam_bleed_px > 0.0f) { - MEM_freeN(ps->vertFaces); - MEM_freeN(ps->faceSeamFlags); - MEM_freeN(ps->faceSeamUVs); - } -#endif - - if (ps->vertFlags) MEM_freeN(ps->vertFlags); - - for (a = 0; a < ps->thread_tot; a++) { - BLI_memarena_free(ps->arena_mt[a]); - } - - /* copy for subsurf/multires, so throw away */ - if (ps->dm->type != DM_TYPE_CDDM) { - if (ps->dm_mvert) MEM_freeN(ps->dm_mvert); - if (ps->dm_mface) MEM_freeN(ps->dm_mface); - /* looks like these don't need copying */ -#if 0 - if (ps->dm_mtface) MEM_freeN(ps->dm_mtface); - if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone); - if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil); -#endif - } - - if (ps->dm_release) - ps->dm->release(ps->dm); -} - -/* 1 = an undo, -1 is a redo. */ -static void partial_redraw_array_init(ImagePaintPartialRedraw *pr) -{ - int tot = PROJ_BOUNDBOX_SQUARED; - while (tot--) { - pr->x1 = 10000000; - pr->y1 = 10000000; - - pr->x2 = -1; - pr->y2 = -1; - - pr->enabled = 1; - - pr++; - } -} - - -static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot) -{ - int touch = 0; - while (tot--) { - pr->x1 = min_ii(pr->x1, pr_other->x1); - pr->y1 = min_ii(pr->y1, pr_other->y1); - - pr->x2 = max_ii(pr->x2, pr_other->x2); - pr->y2 = max_ii(pr->y2, pr_other->y2); - - if (pr->x2 != -1) - touch = 1; - - pr++; pr_other++; - } - - return touch; -} - -/* Loop over all images on this mesh and update any we have touched */ -static int project_image_refresh_tagged(ProjPaintState *ps) -{ - ImagePaintPartialRedraw *pr; - ProjPaintImage *projIma; - int a, i; - int redraw = 0; - - - for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { - if (projIma->touch) { - /* look over each bound cell */ - for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) { - pr = &(projIma->partRedrawRect[i]); - if (pr->x2 != -1) { /* TODO - use 'enabled' ? */ - imapaintpartial = *pr; - imapaint_image_update(NULL, projIma->ima, projIma->ibuf, 1); /*last 1 is for texpaint*/ - redraw = 1; - } - } - - projIma->touch = 0; /* clear for reuse */ - } - } - - return redraw; -} - -/* run this per painting onto each mouse location */ -static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) -{ - if (ps->source == PROJ_SRC_VIEW) { - float min_brush[2], max_brush[2]; - const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush); - - /* so we don't have a bucket bounds that is way too small to paint into */ - // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ - - min_brush[0] = mval_f[0] - radius; - min_brush[1] = mval_f[1] - radius; - - max_brush[0] = mval_f[0] + radius; - max_brush[1] = mval_f[1] + radius; - - /* offset to make this a valid bucket index */ - project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax); - - /* mouse outside the model areas? */ - if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) { - return 0; - } - - ps->context_bucket_x = ps->bucketMin[0]; - ps->context_bucket_y = ps->bucketMin[1]; - } - else { /* reproject: PROJ_SRC_* */ - ps->bucketMin[0] = 0; - ps->bucketMin[1] = 0; - - ps->bucketMax[0] = ps->buckets_x; - ps->bucketMax[1] = ps->buckets_y; - - ps->context_bucket_x = 0; - ps->context_bucket_y = 0; - } - return 1; -} - - -static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2]) -{ - const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); - - if (ps->thread_tot > 1) - BLI_lock_thread(LOCK_CUSTOM1); - - //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y); - - for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) { - for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) { - - /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/ - project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds); - - if ((ps->source != PROJ_SRC_VIEW) || - project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds)) - { - *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x); - ps->context_bucket_x++; - - if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); - - return 1; - } - } - ps->context_bucket_x = ps->bucketMin[0]; - } - - if (ps->thread_tot > 1) - BLI_unlock_thread(LOCK_CUSTOM1); - return 0; -} - -/* Each thread gets one of these, also used as an argument to pass to project_paint_op */ -typedef struct ProjectHandle { - /* args */ - ProjPaintState *ps; - float prevmval[2]; - float mval[2]; - - /* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */ - ProjPaintImage *projImages; /* array of partial redraws */ - - /* thread settings */ - int thread_index; - - struct ImagePool *pool; -} ProjectHandle; - -static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac) -{ - /* this and other blending modes previously used >>8 instead of /255. both - * are not equivalent (>>8 is /256), and the former results in rounding - * errors that can turn colors black fast after repeated blending */ - const int mfac = 255 - fac; - - cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255; - cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255; - cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255; - cp[3] = (mfac * cp1[3] + fac * cp2[3]) / 255; -} - -static void blend_color_mix_float(float cp[4], const float cp1[4], const float cp2[4], const float fac) -{ - const float mfac = 1.0f - fac; - cp[0] = mfac * cp1[0] + fac * cp2[0]; - cp[1] = mfac * cp1[1] + fac * cp2[1]; - cp[2] = mfac * cp1[2] + fac * cp2[2]; - cp[3] = mfac * cp1[3] + fac * cp2[3]; -} - -static void blend_color_mix_accum(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac) -{ - /* this and other blending modes previously used >>8 instead of /255. both - * are not equivalent (>>8 is /256), and the former results in rounding - * errors that can turn colors black fast after repeated blending */ - const int mfac = 255 - fac; - const int alpha = cp1[3] + ((fac * cp2[3]) / 255); - - cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255; - cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255; - cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255; - cp[3] = alpha > 255 ? 255 : alpha; -} -static void blend_color_mix_accum_float(float cp[4], const float cp1[4], const unsigned char cp2[4], const float fac) -{ - const float mfac = 1.0f - fac; - const float alpha = cp1[3] + (fac * (cp2[3] / 255.0f)); - - cp[0] = (mfac * cp1[0] + (fac * (cp2[0] / 255.0f))); - cp[1] = (mfac * cp1[1] + (fac * (cp2[1] / 255.0f))); - cp[2] = (mfac * cp1[2] + (fac * (cp2[2] / 255.0f))); - cp[3] = alpha > 1.0f ? 1.0f : alpha; -} - - -static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) -{ - if (ps->do_masking && mask < 1.0f) { - projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend); - blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255)); - } - else { - *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * mask * 255), ps->blend); - } -} - -static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) -{ - if (ps->do_masking && mask < 1.0f) { - IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend); - blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); - } - else { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha * mask, ps->blend); - } -} - -/* do_projectpaint_smear* - * - * note, mask is used to modify the alpha here, this is not correct since it allows - * accumulation of color greater then 'projPixel->mask' however in the case of smear its not - * really that important to be correct as it is with clone and painting - */ -static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2]) -{ - unsigned char rgba_ub[4]; - - if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) - return; - /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ - blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255)); - BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); -} - -static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2]) -{ - float rgba[4]; - - if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0) - return; - - /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ - blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask); - BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); -} - -/* do_projectpaint_soften for float & byte - */ -static float inv_pow2(float f) -{ - f = 1.0f - f; - f = f * f; - return 1.0f - f; -} - -static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *softenArena, LinkNode **softenPixels) -{ - unsigned int accum_tot = 0; - unsigned int i; - - float *rgba = projPixel->newColor.f; - - /* sigh, alpha values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - alpha = inv_pow2(alpha); - - /* rather then painting, accumulate surrounding colors */ - zero_v4(rgba); - - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; - } - } - - if (LIKELY(accum_tot != 0)) { - mul_v4_fl(rgba, 1.0f / (float)accum_tot); - blend_color_mix_float(rgba, projPixel->pixel.f_pt, rgba, alpha); - if (mask < 1.0f) blend_color_mix_float(rgba, projPixel->origColor.f, rgba, mask); - BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); - } -} - -static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *softenArena, LinkNode **softenPixels) -{ - unsigned int accum_tot = 0; - unsigned int i; - - float rgba[4]; /* convert to byte after */ - - /* sigh, alpha values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - alpha = inv_pow2(alpha); - - /* rather then painting, accumulate surrounding colors */ - zero_v4(rgba); - - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; - } - } - - if (LIKELY(accum_tot != 0)) { - unsigned char *rgba_ub = projPixel->newColor.ch; - - mul_v4_fl(rgba, 1.0f / (float)accum_tot); - IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_ub, rgba); - - blend_color_mix(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255)); - if (mask != 1.0f) blend_color_mix(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255)); - BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); - } -} - -BLI_INLINE void rgba_float_to_uchar__mul_v3(unsigned char rgba_ub[4], const float rgba[4], const float rgb[3]) -{ - rgba_ub[0] = f_to_char(rgba[0] * rgb[0]); - rgba_ub[1] = f_to_char(rgba[1] * rgb[1]); - rgba_ub[2] = f_to_char(rgba[2] * rgb[2]); - rgba_ub[3] = f_to_char(rgba[3]); -} - -static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgba[4], float alpha, float mask) -{ - unsigned char rgba_ub[4]; - - if (ps->is_texbrush) { - rgba_float_to_uchar__mul_v3(rgba_ub, rgba, ps->brush->rgb); - } - else { - IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb); - rgba_ub[3] = 255; - } - - if (ps->do_masking && mask < 1.0f) { - projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend); - blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255)); - } - else { - *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha * mask * 255), ps->blend); - } -} - -static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float rgba[4], float alpha, float mask, int use_color_correction) -{ - if (ps->is_texbrush) { - /* rgba already holds a texture result here from higher level function */ - if (use_color_correction) { - float rgba_br[3]; - srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb); - mul_v3_v3(rgba, rgba_br); - } - else { - mul_v3_v3(rgba, ps->brush->rgb); - } - } - else { - if (use_color_correction) { - srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb); - } - else { - copy_v3_v3(rgba, ps->brush->rgb); - } - rgba[3] = 1.0; - } - - if (ps->do_masking && mask < 1.0f) { - IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend); - blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); - } - else { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha * mask, ps->blend); - } -} - - - -/* run this for single and multithreaded painting */ -static void *do_projectpaint_thread(void *ph_v) -{ - /* First unpack args from the struct */ - ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; - ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages; - const float *lastpos = ((ProjectHandle *)ph_v)->prevmval; - const float *pos = ((ProjectHandle *)ph_v)->mval; - const int thread_index = ((ProjectHandle *)ph_v)->thread_index; - struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool; - /* Done with args from ProjectHandle */ - - LinkNode *node; - ProjPixel *projPixel; - Brush *brush = ps->brush; - - int last_index = -1; - ProjPaintImage *last_projIma = NULL; - ImagePaintPartialRedraw *last_partial_redraw_cell; - - float rgba[4], alpha, dist_nosqrt, dist; - - float falloff; - int bucket_index; - int is_floatbuf = 0; - int use_color_correction = FALSE; - const short tool = ps->tool; - rctf bucket_bounds; - - /* for smear only */ - float pos_ofs[2] = {0}; - float co[2]; - float mask = 1.0f; /* airbrush wont use mask */ - unsigned short mask_short; - const float radius = (float)BKE_brush_size_get(ps->scene, brush); - const float radius_squared = radius * radius; /* avoid a square root with every dist comparison */ - - short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA; - - LinkNode *smearPixels = NULL; - LinkNode *smearPixels_f = NULL; - MemArena *smearArena = NULL; /* mem arena for this brush projection only */ - - LinkNode *softenPixels = NULL; - LinkNode *softenPixels_f = NULL; - MemArena *softenArena = NULL; /* mem arena for this brush projection only */ - - if (tool == PAINT_TOOL_SMEAR) { - pos_ofs[0] = pos[0] - lastpos[0]; - pos_ofs[1] = pos[1] - lastpos[1]; - - smearArena = BLI_memarena_new(1 << 16, "paint smear arena"); - } - else if (tool == PAINT_TOOL_SOFTEN) { - softenArena = BLI_memarena_new(1 << 16, "paint soften arena"); - } - - /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */ - - while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) { - - /* Check this bucket and its faces are initialized */ - if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) { - /* No pixels initialized */ - project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds); - } - - if (ps->source != PROJ_SRC_VIEW) { - - /* Re-Projection, simple, no brushes! */ - - for (node = ps->bucketRect[bucket_index]; node; node = node->next) { - projPixel = (ProjPixel *)node->link; - - /* copy of code below */ - if (last_index != projPixel->image_index) { - last_index = projPixel->image_index; - last_projIma = projImages + last_index; - - last_projIma->touch = 1; - is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; - use_color_correction = TRUE; - } - /* end copy */ - - if (is_floatbuf) { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - mask = ((float)projPixel->mask) / 65535.0f; - blend_color_mix_accum_float(projPixel->pixel.f_pt, projPixel->origColor.f, - projPixel->newColor.ch, (mask * (projPixel->newColor.ch[3] / 255.0f))); - } - } - else { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - mask = ((float)projPixel->mask) / 65535.0f; - blend_color_mix_accum(projPixel->pixel.ch_pt, projPixel->origColor.ch, - projPixel->newColor.ch, (int)(mask * projPixel->newColor.ch[3])); - } - } - } - } - else { - /* Normal brush painting */ - - for (node = ps->bucketRect[bucket_index]; node; node = node->next) { - - projPixel = (ProjPixel *)node->link; - - dist_nosqrt = len_squared_v2v2(projPixel->projCoSS, pos); - - /*if (dist < radius) {*/ /* correct but uses a sqrtf */ - if (dist_nosqrt <= radius_squared) { - float samplecos[3]; - dist = sqrtf(dist_nosqrt); - - falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius); - - if (ps->is_texbrush) { - MTex *mtex = &brush->mtex; - if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { - sub_v2_v2v2(samplecos, projPixel->projCoSS, pos); - } - /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */ - else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) - copy_v3_v3(samplecos, projPixel->worldCoSS); - else - copy_v3_v3(samplecos, projPixel->projCoSS); - } - - if (falloff > 0.0f) { - if (ps->is_texbrush) { - /* note, for clone and smear, we only use the alpha, could be a special function */ - BKE_brush_sample_tex(ps->scene, brush, samplecos, rgba, thread_index, pool); - alpha = rgba[3]; - } - else { - alpha = 1.0f; - } - - if (!ps->do_masking) { - /* for an aurbrush there is no real mask, so just multiply the alpha by it */ - alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush); - mask = ((float)projPixel->mask) / 65535.0f; - } - else { - /* This brush dosnt accumulate so add some curve to the brushes falloff */ - falloff = 1.0f - falloff; - falloff = 1.0f - (falloff * falloff); - - mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff)); - if (mask_short > projPixel->mask_max) { - mask = ((float)mask_short) / 65535.0f; - projPixel->mask_max = mask_short; - } - else { - /*mask = ((float)projPixel->mask_max)/65535.0f;*/ - - /* Go onto the next pixel */ - continue; - } - } - - if (alpha > 0.0f) { - - /* copy of code above */ - if (last_index != projPixel->image_index) { - last_index = projPixel->image_index; - last_projIma = projImages + last_index; - - last_projIma->touch = 1; - is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; - use_color_correction = TRUE; - } - /* end copy */ - - last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; - last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); - last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); - - last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1); - last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1); - - - switch (tool) { - case PAINT_TOOL_CLONE: - if (is_floatbuf) { - if (((ProjPixelClone *)projPixel)->clonepx.f[3]) { - do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */ - } - } - else { - if (((ProjPixelClone *)projPixel)->clonepx.ch[3]) { - do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */ - } - } - break; - case PAINT_TOOL_SMEAR: - sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs); - - if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co); - else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co); - break; - case PAINT_TOOL_SOFTEN: - if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, alpha, mask, softenArena, &softenPixels_f); - else do_projectpaint_soften(ps, projPixel, alpha, mask, softenArena, &softenPixels); - break; - default: - if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask, use_color_correction); - else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask); - break; - } - } - - if (lock_alpha) { - if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3]; - else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3]; - } - - /* done painting */ - } - } - } - } - } - - - if (tool == PAINT_TOOL_SMEAR) { - - for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */ - projPixel = node->link; - *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint; - } - - for (node = smearPixels_f; node; node = node->next) { - projPixel = node->link; - copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f); - } - - BLI_memarena_free(smearArena); - } - else if (tool == PAINT_TOOL_SOFTEN) { - - for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */ - projPixel = node->link; - *projPixel->pixel.uint_pt = projPixel->newColor.uint; - } - - for (node = softenPixels_f; node; node = node->next) { - projPixel = node->link; - copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f); - } - - BLI_memarena_free(softenArena); - } - - return NULL; -} - -static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), const float lastpos[2], const float pos[2]) -{ - /* First unpack args from the struct */ - ProjPaintState *ps = (ProjPaintState *)state; - int touch_any = 0; - - ProjectHandle handles[BLENDER_MAX_THREADS]; - ListBase threads; - int a, i; - - struct ImagePool *pool; - - if (!project_bucket_iter_init(ps, pos)) { - return 0; - } - - if (ps->thread_tot > 1) - BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot); - - pool = BKE_image_pool_new(); - - /* get the threads running */ - for (a = 0; a < ps->thread_tot; a++) { - - /* set defaults in handles */ - //memset(&handles[a], 0, sizeof(BakeShade)); - - handles[a].ps = ps; - copy_v2_v2(handles[a].mval, pos); - copy_v2_v2(handles[a].prevmval, lastpos); - - /* thread specific */ - handles[a].thread_index = a; - - handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); - - memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage)); - - /* image bounds */ - for (i = 0; i < ps->image_tot; i++) { - handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - } - - handles[a].pool = pool; - - if (ps->thread_tot > 1) - BLI_insert_thread(&threads, &handles[a]); - } - - if (ps->thread_tot > 1) /* wait for everything to be done */ - BLI_end_threads(&threads); - else - do_projectpaint_thread(&handles[0]); - - - BKE_image_pool_free(pool); - - /* move threaded bounds back into ps->projectPartialRedraws */ - for (i = 0; i < ps->image_tot; i++) { - int touch = 0; - for (a = 0; a < ps->thread_tot; a++) { - touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED); - } - - if (touch) { - ps->projImages[i].touch = 1; - touch_any = 1; - } - } - - return touch_any; -} - - -static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, const int UNUSED(prevmval_i[2]), const int mval_i[2], double time, float pressure) -{ - - /* Use mouse coords as floats for projection painting */ - float pos[2]; - - pos[0] = (float)(mval_i[0]); - pos[1] = (float)(mval_i[1]); - - // we may want to use this later - // BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0); - - if (BKE_brush_painter_paint(painter, project_paint_op, pos, time, pressure, ps, 0)) { - return 1; - } - else return 0; -} - - -static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, const int prevmval_i[2], const int mval_i[2], double time, float pressure) -{ - int a, redraw; - - for (a = 0; a < ps->image_tot; a++) - partial_redraw_array_init(ps->projImages[a].partRedrawRect); - - redraw = project_paint_sub_stroke(ps, painter, prevmval_i, mval_i, time, pressure); - - if (project_image_refresh_tagged(ps)) - return redraw; - - return 0; -} - /* Imagepaint Partial Redraw & Dirty Region */ -static void imapaint_clear_partial_redraw(void) +void imapaint_clear_partial_redraw(void) { memset(&imapaintpartial, 0, sizeof(imapaintpartial)); } -static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h) +void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h) { ImBuf *tmpibuf = NULL; int srcx = 0, srcy = 0, origx; @@ -4417,7 +315,7 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, IMB_freeImBuf(tmpibuf); } -static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint) +void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint) { if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) @@ -4438,447 +336,6 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s } } -/* Image Paint Operations */ - -/* keep these functions in sync */ -static void imapaint_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3]) -{ - if (is_torus) { - x %= ibuf->x; - if (x < 0) x += ibuf->x; - y %= ibuf->y; - if (y < 0) y += ibuf->y; - } - - if (ibuf->rect_float) { - float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4; - IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf); - } - else { - char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4; - IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb); - } -} -static void imapaint_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3]) -{ - if (is_torus) { - x %= ibuf->x; - if (x < 0) x += ibuf->x; - y %= ibuf->y; - if (y < 0) y += ibuf->y; - } - - if (ibuf->rect_float) { - float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4; - IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb); - } - else { - char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4; - IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb); - } -} - -static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) -{ - float inrgb[3]; - - // XXX: signed unsigned mismatch - if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) { - if (torus) imapaint_ibuf_rgb_get(ibuf, x, y, 1, inrgb); - else return 0; - } - else { - imapaint_ibuf_rgb_get(ibuf, x, y, 0, inrgb); - } - - outrgb[0] += inrgb[0]; - outrgb[1] += inrgb[1]; - outrgb[2] += inrgb[2]; - - return 1; -} - -static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus) -{ - int x, y, count, xi, yi, xo, yo; - int out_off[2], in_off[2], dim[2]; - float outrgb[3]; - - dim[0] = ibufb->x; - dim[1] = ibufb->y; - in_off[0] = pos[0]; - in_off[1] = pos[1]; - out_off[0] = out_off[1] = 0; - - if (!is_torus) { - IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], - &out_off[1], &dim[0], &dim[1]); - - if ((dim[0] == 0) || (dim[1] == 0)) - return; - } - - for (y = 0; y < dim[1]; y++) { - for (x = 0; x < dim[0]; x++) { - /* get input pixel */ - xi = in_off[0] + x; - yi = in_off[1] + y; - - count = 1; - imapaint_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb); - - count += imapaint_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus); - count += imapaint_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus); - count += imapaint_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus); - - count += imapaint_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus); - count += imapaint_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus); - - count += imapaint_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus); - count += imapaint_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus); - count += imapaint_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus); - - mul_v3_fl(outrgb, 1.0f / (float)count); - - /* write into brush buffer */ - xo = out_off[0] + x; - yo = out_off[1] + y; - imapaint_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb); - } - } -} - -static void imapaint_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height) -{ - region->destx = destx; - region->desty = desty; - region->srcx = srcx; - region->srcy = srcy; - region->width = width; - region->height = height; -} - -static int imapaint_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf) -{ - int destx = region->destx; - int desty = region->desty; - int srcx = region->srcx; - int srcy = region->srcy; - int width = region->width; - int height = region->height; - int origw, origh, w, h, tot = 0; - - /* convert destination and source coordinates to be within image */ - destx = destx % dbuf->x; - if (destx < 0) destx += dbuf->x; - desty = desty % dbuf->y; - if (desty < 0) desty += dbuf->y; - srcx = srcx % sbuf->x; - if (srcx < 0) srcx += sbuf->x; - srcy = srcy % sbuf->y; - if (srcy < 0) srcy += sbuf->y; - - /* clip width of blending area to destination imbuf, to avoid writing the - * same pixel twice */ - origw = w = (width > dbuf->x) ? dbuf->x : width; - origh = h = (height > dbuf->y) ? dbuf->y : height; - - /* clip within image */ - IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); - imapaint_set_region(®ion[tot++], destx, desty, srcx, srcy, w, h); - - /* do 3 other rects if needed */ - if (w < origw) - imapaint_set_region(®ion[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h); - if (h < origh) - imapaint_set_region(®ion[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h); - if ((w < origw) && (h < origh)) - imapaint_set_region(®ion[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h); - - return tot; -} - -static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) -{ - ImagePaintRegion region[4]; - int a, tot; - - imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y); - tot = imapaint_torus_split_region(region, ibufb, ibuf); - - for (a = 0; a < tot; a++) - IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, IMB_BLEND_COPY_RGB); -} - -static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) -{ - /* note: allocImbuf returns zero'd memory, so regions outside image will - * have zero alpha, and hence not be blended onto the image */ - int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1]; - ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags); - - IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); - IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, - IMB_BLEND_COPY_RGB); - IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h, - IMB_BLEND_COPY_ALPHA); - - return clonebuf; -} - -static void imapaint_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2]) -{ - ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f); - ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f); -} - -/* dosnt run for projection painting - * only the old style painting in the 3d view */ -static int imapaint_paint_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2]) -{ - ImagePaintState *s = ((ImagePaintState *)state); - ImBuf *clonebuf = NULL, *frombuf; - ImagePaintRegion region[4]; - short torus = s->brush->flag & BRUSH_TORUS; - short blend = s->blend; - float *offset = s->brush->clone.offset; - float liftpos[2]; - int bpos[2], blastpos[2], bliftpos[2]; - int a, tot; - - imapaint_convert_brushco(ibufb, pos, bpos); - - /* lift from canvas */ - if (s->tool == PAINT_TOOL_SOFTEN) { - imapaint_lift_soften(s->canvas, ibufb, bpos, torus); - } - else if (s->tool == PAINT_TOOL_SMEAR) { - if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) - return 0; - - imapaint_convert_brushco(ibufb, lastpos, blastpos); - imapaint_lift_smear(s->canvas, ibufb, blastpos); - } - else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { - liftpos[0] = pos[0] - offset[0] * s->canvas->x; - liftpos[1] = pos[1] - offset[1] * s->canvas->y; - - imapaint_convert_brushco(ibufb, liftpos, bliftpos); - clonebuf = imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos); - } - - frombuf = (clonebuf) ? clonebuf : ibufb; - - if (torus) { - imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); - tot = imapaint_torus_split_region(region, s->canvas, frombuf); - } - else { - imapaint_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); - tot = 1; - } - - /* blend into canvas */ - for (a = 0; a < tot; a++) { - imapaint_dirty_region(s->image, s->canvas, - region[a].destx, region[a].desty, - region[a].width, region[a].height); - - IMB_rectblend(s->canvas, frombuf, - region[a].destx, region[a].desty, - region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend); - } - - if (clonebuf) IMB_freeImBuf(clonebuf); - - return 1; -} - -/* 3D TexturePaint */ - -static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv) -{ - float d1[2], d2[2]; - float mismatch = len_v2v2(fwuv, uv); - float len1 = len_v2v2(prevuv, fwuv); - float len2 = len_v2v2(bkuv, uv); - - sub_v2_v2v2(d1, fwuv, prevuv); - sub_v2_v2v2(d2, uv, bkuv); - - return ((dot_v2v2(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2) * 2)); -} - -/* ImagePaint Common */ - -static int imapaint_canvas_set(ImagePaintState *s, Image *ima) -{ - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL); - - /* verify that we can paint and set canvas */ - if (ima == NULL) { - return 0; - } - else if (ima->packedfile && ima->rr) { - s->warnpackedfile = ima->id.name + 2; - return 0; - } - else if (ibuf && ibuf->channels != 4) { - s->warnmultifile = ima->id.name + 2; - return 0; - } - else if (!ibuf || !(ibuf->rect || ibuf->rect_float)) - return 0; - - s->image = ima; - s->canvas = ibuf; - - /* set clone canvas */ - if (s->tool == PAINT_TOOL_CLONE) { - ima = s->brush->clone.image; - ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL); - - if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { - BKE_image_release_ibuf(ima, ibuf, NULL); - BKE_image_release_ibuf(s->image, s->canvas, NULL); - return 0; - } - - s->clonecanvas = ibuf; - - /* temporarily add float rect for cloning */ - if (s->canvas->rect_float && !s->clonecanvas->rect_float) { - IMB_float_from_rect(s->clonecanvas); - } - else if (!s->canvas->rect_float && !s->clonecanvas->rect) - IMB_rect_from_float(s->clonecanvas); - } - - return 1; -} - -static void imapaint_canvas_free(ImagePaintState *s) -{ - BKE_image_release_ibuf(s->image, s->canvas, NULL); - BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL); -} - -static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update, float pressure) -{ - ImBuf *ibuf = BKE_image_acquire_ibuf(image, s->sima ? &s->sima->iuser : NULL, NULL); - float pos[2]; - int is_data; - - if (!ibuf) - return 0; - - is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; - - pos[0] = uv[0] * ibuf->x; - pos[1] = uv[1] * ibuf->y; - - BKE_brush_painter_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0); - - /* OCIO_TODO: float buffers are now always linear, so always use color correction - * this should probably be changed when texture painting color space is supported - */ - if (BKE_brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s, is_data == FALSE)) { - if (update) - imapaint_image_update(s->sima, image, ibuf, texpaint); - BKE_image_release_ibuf(image, ibuf, NULL); - return 1; - } - else { - BKE_image_release_ibuf(image, ibuf, NULL); - return 0; - } -} - -static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPainter *painter, short texpaint, const int prevmval[2], const int mval[2], double time, float pressure) -{ - Image *newimage = NULL; - float fwuv[2], bkuv[2], newuv[2]; - unsigned int newfaceindex; - int breakstroke = 0, redraw = 0; - - if (texpaint) { - /* pick new face and image */ - if (imapaint_pick_face(vc, mval, &newfaceindex, s->dm_totface) && - ((s->do_facesel == FALSE) || (s->dm_mface[newfaceindex].flag & ME_FACE_SEL))) - { - ImBuf *ibuf; - - newimage = imapaint_face_image(s, newfaceindex); - ibuf = BKE_image_acquire_ibuf(newimage, s->sima ? &s->sima->iuser : NULL, NULL); - - if (ibuf && ibuf->rect) - imapaint_pick_uv(s->scene, s->ob, newfaceindex, mval, newuv); - else { - newimage = NULL; - newuv[0] = newuv[1] = 0.0f; - } - - BKE_image_release_ibuf(newimage, ibuf, NULL); - } - else - newuv[0] = newuv[1] = 0.0f; - - /* see if stroke is broken, and if so finish painting in old position */ - if (s->image) { - imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); - imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval, bkuv); - - if (newimage == s->image) - breakstroke = texpaint_break_stroke(s->uv, fwuv, bkuv, newuv); - else - breakstroke = 1; - } - else - fwuv[0] = fwuv[1] = 0.0f; - - if (breakstroke) { - imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); - redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, - fwuv, time, 1, pressure); - imapaint_clear_partial_redraw(); - BKE_brush_painter_break_stroke(painter); - } - - /* set new canvas */ - if (newimage && (newimage != s->image)) - if (!imapaint_canvas_set(s, newimage)) - newimage = NULL; - - /* paint in new image */ - if (newimage) { - if (breakstroke) - redraw |= imapaint_paint_sub_stroke(s, painter, newimage, - texpaint, bkuv, time, 0, pressure); - redraw |= imapaint_paint_sub_stroke(s, painter, newimage, texpaint, - newuv, time, 1, pressure); - } - - /* update state */ - s->image = newimage; - s->faceindex = newfaceindex; - s->uv[0] = newuv[0]; - s->uv[1] = newuv[1]; - } - else { - UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]); - redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, newuv, - time, 1, pressure); - } - - if (redraw) - imapaint_clear_partial_redraw(); - - return redraw; -} - /************************ image paint poll ************************/ static Brush *image_paint_brush(bContext *C) @@ -4889,16 +346,6 @@ static Brush *image_paint_brush(bContext *C) return paint_brush(&settings->imapaint.paint); } -static Brush *uv_sculpt_brush(bContext *C) -{ - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - - if (!settings->uvsculpt) - return NULL; - return paint_brush(&settings->uvsculpt->paint); -} - static int image_paint_poll(bContext *C) { Object *obact = CTX_data_active_object(C); @@ -4924,38 +371,6 @@ static int image_paint_poll(bContext *C) return 0; } -static int uv_sculpt_brush_poll(bContext *C) -{ - BMEditMesh *em; - int ret; - Object *obedit = CTX_data_edit_object(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *toolsettings = scene->toolsettings; - - if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH) - return 0; - - em = BMEdit_FromObject(obedit); - ret = EDBM_mtexpoly_check(em); - - if (ret && sima) { - ARegion *ar = CTX_wm_region(C); - if ((toolsettings->use_uv_sculpt) && ar->regiontype == RGN_TYPE_WINDOW) - return 1; - } - - return 0; -} - -static int image_paint_3d_poll(bContext *C) -{ - if (CTX_wm_region_view3d(C)) - return image_paint_poll(C); - - return 0; -} - static int image_paint_2d_clone_poll(bContext *C) { Brush *brush = image_paint_brush(C); @@ -4969,339 +384,173 @@ static int image_paint_2d_clone_poll(bContext *C) } /************************ paint operator ************************/ - -typedef enum PaintMode { +typedef enum TexPaintMode { PAINT_MODE_2D, - PAINT_MODE_3D, PAINT_MODE_3D_PROJECT -} PaintMode; +} TexPaintMode; typedef struct PaintOperation { - PaintMode mode; + TexPaintMode mode; - BrushPainter *painter; - ImagePaintState s; - ProjPaintState ps; + void *custom_paint; - int first; int prevmouse[2]; - int orig_brush_size; double starttime; ViewContext vc; wmTimer *timer; - - short restore_projection; } PaintOperation; -static void paint_redraw(bContext *C, ImagePaintState *s, int texpaint, int final) +void paint_brush_init_tex(Brush *brush) { - if (final) { - if (s->image && !(texpaint || (s->sima && s->sima->lock))) - GPU_free_image(s->image); - - /* compositor listener deals with updating */ - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); - } - else { - if (!s->sima || !s->sima->lock) - ED_region_tag_redraw(CTX_wm_region(C)); - else - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); + /* init mtex nodes */ + if (brush) { + MTex *mtex = &brush->mtex; + if (mtex->tex && mtex->tex->nodetree) + ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */ } } -/* initialize project paint settings from context */ -static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps) +void paint_brush_exit_tex(Brush *brush) { - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - - /* brush */ - ps->brush = paint_brush(&settings->imapaint.paint); - if (ps->brush) { - Brush *brush = ps->brush; - ps->tool = brush->imagepaint_tool; - ps->blend = brush->blend; - - /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */ - ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW || - brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true; - ps->is_texbrush = (brush->mtex.tex) ? 1 : 0; - } - else { - /* brush may be NULL*/ - ps->do_masking = false; - ps->is_texbrush = false; + if (brush) { + MTex *mtex = &brush->mtex; + if (mtex->tex && mtex->tex->nodetree) + ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1); } +} - /* sizeof(ProjPixel), since we alloc this a _lot_ */ - ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool); - BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel)); - - /* these can be NULL */ - ps->v3d = CTX_wm_view3d(C); - ps->rv3d = CTX_wm_region_view3d(C); - ps->ar = CTX_wm_region(C); - - ps->scene = scene; - ps->ob = ob; /* allow override of active object */ - - /* setup projection painting data */ - ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; - ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; - ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1; - ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */ - - if (ps->tool == PAINT_TOOL_CLONE) - ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE); - - ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0; - ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0; - - -#ifndef PROJ_DEBUG_NOSEAMBLEED - ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */ -#endif - if (ps->do_mask_normal) { - ps->normal_angle_inner = settings->imapaint.normal_angle; - ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f; +static void paint_redraw(const bContext *C, PaintOperation *pop, int final) +{ + if (pop->mode == PAINT_MODE_2D) { + paint_2d_redraw(C, pop->custom_paint, final); } else { - ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle; - } - - ps->normal_angle_inner *= (float)(M_PI_2 / 90); - ps->normal_angle *= (float)(M_PI_2 / 90); - ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner; - - if (ps->normal_angle_range <= 0.0f) - ps->do_mask_normal = FALSE; /* no need to do blending */ -} - -static void paint_brush_init_tex(Brush *brush) -{ - /* init mtex nodes */ - if (brush) { - MTex *mtex = &brush->mtex; - if (mtex->tex && mtex->tex->nodetree) - ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */ + if (final) { + /* compositor listener deals with updating */ + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, NULL); + } + else { + ED_region_tag_redraw(CTX_wm_region(C)); + } } - } -static int texture_paint_init(bContext *C, wmOperator *op) +static PaintOperation * texture_paint_init(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; - Brush *brush = paint_brush(&settings->imapaint.paint); PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ + int mode = RNA_enum_get(op->ptr, "mode"); + view3d_set_viewcontext(C, &pop->vc); + + /* TODO Should avoid putting this here. Instead, last position should be requested + * from stroke system. */ + pop->prevmouse[0] = event->mval[0]; + pop->prevmouse[1] = event->mval[1]; - pop->first = 1; - op->customdata = pop; /* initialize from context */ if (CTX_wm_region_view3d(C)) { - pop->mode = PAINT_MODE_3D; - - if (!(settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE)) - pop->mode = PAINT_MODE_3D_PROJECT; - else - view3d_set_viewcontext(C, &pop->vc); + pop->mode = PAINT_MODE_3D_PROJECT; + pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode); } else { - pop->s.sima = CTX_wm_space_image(C); - pop->s.v2d = &CTX_wm_region(C)->v2d; + pop->mode = PAINT_MODE_2D; + pop->custom_paint = paint_2d_new_stroke(C, op); } - pop->s.scene = scene; - pop->s.screen = CTX_wm_screen(C); - - pop->s.brush = brush; - pop->s.tool = brush->imagepaint_tool; - if (pop->mode == PAINT_MODE_3D && (pop->s.tool == PAINT_TOOL_CLONE)) - pop->s.tool = PAINT_TOOL_DRAW; - pop->s.blend = brush->blend; - pop->orig_brush_size = BKE_brush_size_get(scene, brush); - - if (pop->mode != PAINT_MODE_2D) { - Object *ob = OBACT; - Mesh *me = BKE_mesh_from_object(ob); - - if (!me) { - return 0; - } - - pop->s.ob = ob; - pop->s.do_facesel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - /* for non prohect paint we need */ - /* fill in derived mesh */ - if (ob->derivedFinal && CustomData_has_layer(&ob->derivedFinal->faceData, CD_MTFACE)) { - pop->s.dm = ob->derivedFinal; - pop->s.dm_release = FALSE; - } - else { - pop->s.dm = mesh_get_derived_final(pop->s.scene, ob, pop->s.scene->customdata_mask | CD_MASK_MTFACE); - pop->s.dm_release = TRUE; - } - - if (!CustomData_has_layer(&pop->s.dm->faceData, CD_MTFACE)) { - - if (pop->s.dm_release) - pop->s.dm->release(pop->s.dm); - - pop->s.dm = NULL; - return 0; - } - - pop->s.dm_mface = pop->s.dm->getTessFaceArray(pop->s.dm); - pop->s.dm_mtface = pop->s.dm->getTessFaceDataArray(pop->s.dm, CD_MTFACE); - pop->s.dm_totface = pop->s.dm->getNumTessFaces(pop->s.dm); - } - else { - pop->s.image = pop->s.sima->image; - - if (!imapaint_canvas_set(&pop->s, pop->s.image)) { - if (pop->s.warnmultifile) - BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint"); - if (pop->s.warnpackedfile) - BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted"); - - return 0; - } + if (!pop->custom_paint) { + MEM_freeN(pop); + return NULL; } - /* note, if we have no UVs on the derived mesh, then we must return here */ - if (pop->mode == PAINT_MODE_3D_PROJECT) { - - /* initialize all data from the context */ - project_state_init(C, OBACT, &pop->ps); - - /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ - curvemapping_initialize(pop->ps.brush->curve); - - paint_brush_init_tex(pop->ps.brush); - - pop->ps.source = PROJ_SRC_VIEW; - - if (pop->ps.ob == NULL || !(pop->ps.ob->lay & pop->ps.v3d->lay)) - return 0; - - /* Don't allow brush size below 2 */ - if (BKE_brush_size_get(scene, brush) < 2) - BKE_brush_size_set(scene, brush, 2); - - /* allocate and initialize spatial data structures */ - project_paint_begin(&pop->ps); - - if (pop->ps.dm == NULL) - return 0; - } - else { - paint_brush_init_tex(pop->s.brush); - } - settings->imapaint.flag |= IMAGEPAINT_DRAWING; undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, image_undo_restore, image_undo_free); - /* create painter */ - pop->painter = BKE_brush_painter_new(scene, pop->s.brush); - { UnifiedPaintSettings *ups = &settings->unified_paint_settings; ups->draw_pressure = true; } - return 1; + return pop; } -static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) +static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { - PaintOperation *pop = op->customdata; - float time, mousef[2]; + PaintOperation *pop = paint_stroke_mode_data(stroke); + Scene *scene = CTX_data_scene(C); + Brush *brush = paint_brush(&scene->toolsettings->imapaint.paint); + + /* initial brush values. Maybe it should be considered moving these to stroke system */ + float startsize = BKE_brush_size_get(scene, brush); + float startalpha = BKE_brush_alpha_get(scene, brush); + + float mousef[2]; float pressure; - int mouse[2], redraw; + int mouse[2], redraw, eraser; RNA_float_get_array(itemptr, "mouse", mousef); mouse[0] = (int)(mousef[0]); mouse[1] = (int)(mousef[1]); - time = RNA_float_get(itemptr, "time"); pressure = RNA_float_get(itemptr, "pressure"); + eraser = RNA_boolean_get(itemptr, "pen_flip"); - if (pop->first) - project_paint_begin_clone(&pop->ps, mouse); - - if (pop->mode == PAINT_MODE_3D) - view3d_operator_needs_opengl(C); + if (BKE_brush_use_alpha_pressure(scene, brush)) + BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure)); + if (BKE_brush_use_size_pressure(scene, brush)) + BKE_brush_size_set(scene, brush, max_ff(1.0f, startsize * pressure)); if (pop->mode == PAINT_MODE_3D_PROJECT) { - redraw = project_paint_stroke(&pop->ps, pop->painter, pop->prevmouse, mouse, time, pressure); - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; - + redraw = paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse); } else { - redraw = imapaint_paint_stroke(&pop->vc, &pop->s, pop->painter, pop->mode == PAINT_MODE_3D, pop->prevmouse, mouse, time, pressure); - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; + redraw = paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser); } - if (redraw) - paint_redraw(C, &pop->s, pop->mode == PAINT_MODE_3D, 0); + pop->prevmouse[0] = mouse[0]; + pop->prevmouse[1] = mouse[1]; - pop->first = 0; -} + /* restore brush values */ + BKE_brush_alpha_set(scene, brush, startalpha); + BKE_brush_size_set(scene, brush, startsize); + + + if (redraw) + paint_redraw(C, pop, 0); -static void paint_brush_exit_tex(Brush *brush) -{ - if (brush) { - MTex *mtex = &brush->mtex; - if (mtex->tex && mtex->tex->nodetree) - ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1); - } } -static void paint_exit(bContext *C, wmOperator *op) +static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; - PaintOperation *pop = op->customdata; + PaintOperation *pop = paint_stroke_mode_data(stroke); + + paint_redraw(C, pop, 1); if (pop->timer) WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer); - if (pop->restore_projection) - settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; - settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; - imapaint_canvas_free(&pop->s); - BKE_brush_painter_free(pop->painter); if (pop->mode == PAINT_MODE_3D_PROJECT) { - BKE_brush_size_set(scene, pop->ps.brush, pop->orig_brush_size); - paint_brush_exit_tex(pop->ps.brush); - - project_paint_end(&pop->ps); + paint_proj_stroke_done(pop->custom_paint); } else { - paint_brush_exit_tex(pop->s.brush); - - /* non projection 3d paint, could move into own function of more needs adding */ - if (pop->s.dm_release) - pop->s.dm->release(pop->s.dm); + paint_2d_stroke_done(pop->custom_paint); } - - paint_redraw(C, &pop->s, pop->mode == PAINT_MODE_3D, 1); + undo_paint_push_end(UNDO_PAINT_IMAGE); - + + /* duplicate warning, see texpaint_init if (pop->s.warnmultifile) BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile); if (pop->s.warnpackedfile) BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile); - + */ MEM_freeN(pop); { @@ -5310,159 +559,69 @@ static void paint_exit(bContext *C, wmOperator *op) } } -static int paint_exec(bContext *C, wmOperator *op) +static int paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2])) { - if (!texture_paint_init(C, op)) { - MEM_freeN(op->customdata); - return OPERATOR_CANCELLED; - } - - RNA_BEGIN (op->ptr, itemptr, "stroke") - { - paint_apply(C, op, &itemptr); - } - RNA_END; - - paint_exit(C, op); - - return OPERATOR_FINISHED; + return true; } -static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event) -{ - const Scene *scene = CTX_data_scene(C); - PaintOperation *pop = op->customdata; - PointerRNA itemptr; - float pressure, mousef[2]; - double time; - int tablet; - - time = PIL_check_seconds_timer(); - - tablet = 0; - pop->s.blend = pop->s.brush->blend; - - if (event->tablet_data) { - wmTabletData *wmtab = event->tablet_data; - - tablet = (wmtab->Active != EVT_TABLET_NONE); - pressure = wmtab->Pressure; - if (wmtab->Active == EVT_TABLET_ERASER) - pop->s.blend = IMB_BLEND_ERASE_ALPHA; - } - else { - BLI_assert(fabsf(WM_cursor_pressure(CTX_wm_window(C))) == 1.0f); - pressure = 1.0f; - } - - if (pop->first) { - pop->prevmouse[0] = event->mval[0]; - pop->prevmouse[1] = event->mval[1]; - pop->starttime = time; - - /* special exception here for too high pressure values on first touch in - * windows for some tablets, then we just skip first touch .. */ - if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush))) - return; - - /* This can be removed once fixed properly in - * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) - * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */ - if (tablet && (pressure < 0.0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush))) - return; - - } - - /* fill in stroke */ - RNA_collection_add(op->ptr, "stroke", &itemptr); - - mousef[0] = (float)(event->mval[0]); - mousef[1] = (float)(event->mval[1]); - RNA_float_set_array(&itemptr, "mouse", mousef); - RNA_float_set(&itemptr, "time", (float)(time - pop->starttime)); - RNA_float_set(&itemptr, "pressure", pressure); - - /* apply */ - paint_apply(C, op, &itemptr); - - { - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - ups->pressure_value = pressure; - } -} -static int paint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { PaintOperation *pop; + struct PaintStroke *stroke; + int retval; - if (!texture_paint_init(C, op)) { - MEM_freeN(op->customdata); + if (!(pop = texture_paint_init(C, op, event))) { return OPERATOR_CANCELLED; } - paint_apply_event(C, op, event); - - pop = op->customdata; + stroke = op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, + paint_stroke_update_step, + paint_stroke_done, event->type); + paint_stroke_set_mode_data(stroke, pop); + /* add modal handler */ WM_event_add_modal_handler(C, op); - if (pop->s.brush->flag & BRUSH_AIRBRUSH) - pop->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); + retval = op->type->modal(C, op, event); + OPERATOR_RETVAL_CHECK(retval); + BLI_assert(retval == OPERATOR_RUNNING_MODAL); return OPERATOR_RUNNING_MODAL; } -static int paint_modal(bContext *C, wmOperator *op, wmEvent *event) -{ - PaintOperation *pop = op->customdata; - - switch (event->type) { - case LEFTMOUSE: - case MIDDLEMOUSE: - case RIGHTMOUSE: // XXX hardcoded - paint_exit(C, op); - return OPERATOR_FINISHED; - case MOUSEMOVE: - case INBETWEEN_MOUSEMOVE: - paint_apply_event(C, op, event); - break; - case TIMER: - if (event->customdata == pop->timer) - paint_apply_event(C, op, event); - break; - } - - return OPERATOR_RUNNING_MODAL; -} - -static int paint_cancel(bContext *C, wmOperator *op) -{ - paint_exit(C, op); - - return OPERATOR_CANCELLED; -} void PAINT_OT_image_paint(wmOperatorType *ot) { + static EnumPropertyItem stroke_mode_items[] = { + {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"}, + {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"}, + {0} + }; + /* identifiers */ ot->name = "Image Paint"; ot->idname = "PAINT_OT_image_paint"; ot->description = "Paint a stroke into the image"; - + /* api callbacks */ - ot->exec = paint_exec; ot->invoke = paint_invoke; - ot->modal = paint_modal; - ot->cancel = paint_cancel; + ot->modal = paint_stroke_modal; + /* ot->exec = paint_exec; <-- needs stroke property */ ot->poll = image_paint_poll; + ot->cancel = paint_stroke_cancel; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, + "Paint Stroke Mode", + "Action taken when a paint stroke is made"); - /* properties */ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } -static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) + +int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -5484,7 +643,7 @@ static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) /************************ cursor drawing *******************************/ -static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) +void brush_drawcursor_texpaint_uvsculpt(bContext *C, int x, int y, void *UNUSED(customdata)) { #define PX_SIZE_FADE_MAX 12.0f #define PX_SIZE_FADE_MIN 4.0f @@ -5560,7 +719,8 @@ static void toggle_paint_cursor(bContext *C, int enable) settings->imapaint.paintcursor = NULL; } else if (enable) - settings->imapaint.paintcursor = WM_paint_cursor_activate(wm, image_paint_poll, brush_drawcursor, NULL); + settings->imapaint.paintcursor = + WM_paint_cursor_activate(wm, image_paint_poll, brush_drawcursor_texpaint_uvsculpt, NULL); } /* enable the paint cursor if it isn't already. @@ -5587,32 +747,11 @@ void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) if (!imapaint->paintcursor) { imapaint->paintcursor = WM_paint_cursor_activate(wm, image_paint_poll, - brush_drawcursor, NULL); + brush_drawcursor_texpaint_uvsculpt, NULL); } } } - -void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings) -{ - if (settings->use_uv_sculpt) { - if (!settings->uvsculpt) { - settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint"); - settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB; - settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS; - settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN; - } - - BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); - - WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, - brush_drawcursor, NULL); - } - else { - if (settings->uvsculpt) - settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH; - } -} /************************ grab clone operator ************************/ typedef struct GrabClone { @@ -5637,7 +776,7 @@ static int grab_clone_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int grab_clone_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Brush *brush = image_paint_brush(C); GrabClone *cmv; @@ -5653,7 +792,7 @@ static int grab_clone_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event) +static int grab_clone_modal(bContext *C, wmOperator *op, const wmEvent *event) { Brush *brush = image_paint_brush(C); ARegion *ar = CTX_wm_region(C); @@ -5728,7 +867,7 @@ static int sample_color_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RNA_int_set_array(op->ptr, "location", event->mval); sample_color_exec(C, op); @@ -5738,7 +877,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int sample_color_modal(bContext *C, wmOperator *op, wmEvent *event) +static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: @@ -5793,57 +932,6 @@ void PAINT_OT_sample_color(wmOperatorType *ot) RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384); } -/******************** set clone cursor operator ********************/ - -static int set_clone_cursor_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - float *cursor = give_cursor(scene, v3d); - - RNA_float_get_array(op->ptr, "location", cursor); - - ED_area_tag_redraw(CTX_wm_area(C)); - - return OPERATOR_FINISHED; -} - -static int set_clone_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - float location[3]; - - view3d_operator_needs_opengl(C); - - if (!ED_view3d_autodist(scene, ar, v3d, event->mval, location)) - return OPERATOR_CANCELLED; - - RNA_float_set_array(op->ptr, "location", location); - - return set_clone_cursor_exec(C, op); -} - -void PAINT_OT_clone_cursor_set(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Set Clone Cursor"; - ot->idname = "PAINT_OT_clone_cursor_set"; - ot->description = "Set the location of the clone cursor"; - - /* api callbacks */ - ot->exec = set_clone_cursor_exec; - ot->invoke = set_clone_cursor_invoke; - ot->poll = image_paint_3d_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_float_vector(ot->srna, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in world space coordinates", -10000.0f, 10000.0f); -} - /******************** texture paint toggle operator ********************/ static int texture_paint_toggle_poll(bContext *C) @@ -5937,11 +1025,6 @@ int image_texture_paint_poll(bContext *C) return (texture_paint_poll(C) || image_paint_poll(C)); } -int uv_sculpt_poll(bContext *C) -{ - return uv_sculpt_brush_poll(C); -} - int facemask_paint_poll(bContext *C) { return paint_facesel_test(CTX_data_active_object(C)); @@ -5956,201 +1039,4 @@ int mask_paint_poll(bContext *C) { return paint_facesel_test(CTX_data_active_object(C)) || paint_vertsel_test(CTX_data_active_object(C)); } -/* use project paint to re-apply an image */ -static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) -{ - Image *image = BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image")); - Scene *scene = CTX_data_scene(C); - ProjPaintState ps = {NULL}; - int orig_brush_size; - IDProperty *idgroup; - IDProperty *view_data = NULL; - - project_state_init(C, OBACT, &ps); - - if (ps.ob == NULL || ps.ob->type != OB_MESH) { - BKE_report(op->reports, RPT_ERROR, "No active mesh object"); - return OPERATOR_CANCELLED; - } - - if (image == NULL) { - BKE_report(op->reports, RPT_ERROR, "Image could not be found"); - return OPERATOR_CANCELLED; - } - - ps.reproject_image = image; - ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); - - if (ps.reproject_ibuf == NULL || ps.reproject_ibuf->rect == NULL) { - BKE_report(op->reports, RPT_ERROR, "Image data could not be found"); - return OPERATOR_CANCELLED; - } - - idgroup = IDP_GetProperties(&image->id, 0); - - if (idgroup) { - view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY); - - /* type check to make sure its ok */ - if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) { - BKE_report(op->reports, RPT_ERROR, "Image project data invalid"); - return OPERATOR_CANCELLED; - } - } - - if (view_data) { - /* image has stored view projection info */ - ps.source = PROJ_SRC_IMAGE_VIEW; - } - else { - ps.source = PROJ_SRC_IMAGE_CAM; - - if (scene->camera == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active camera set"); - return OPERATOR_CANCELLED; - } - } - - /* override */ - ps.is_texbrush = 0; - ps.do_masking = false; - orig_brush_size = BKE_brush_size_get(scene, ps.brush); - BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */ - - ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */ - - scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; - - undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - image_undo_restore, image_undo_free); - - /* allocate and initialize spatial data structures */ - project_paint_begin(&ps); - - if (ps.dm == NULL) { - BKE_brush_size_set(scene, ps.brush, orig_brush_size); - return OPERATOR_CANCELLED; - } - else { - float pos[2] = {0.0, 0.0}; - float lastpos[2] = {0.0, 0.0}; - int a; - - for (a = 0; a < ps.image_tot; a++) - partial_redraw_array_init(ps.projImages[a].partRedrawRect); - - project_paint_op(&ps, NULL, lastpos, pos); - - project_image_refresh_tagged(&ps); - - for (a = 0; a < ps.image_tot; a++) { - GPU_free_image(ps.projImages[a].ima); - WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima); - } - } - - project_paint_end(&ps); - - scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; - BKE_brush_size_set(scene, ps.brush, orig_brush_size); - - return OPERATOR_FINISHED; -} - -void PAINT_OT_project_image(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Project Image"; - ot->idname = "PAINT_OT_project_image"; - ot->description = "Project an edited render from the active camera back onto the object"; - - /* api callbacks */ - ot->invoke = WM_enum_search_invoke; - ot->exec = texture_paint_camera_project_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", ""); - RNA_def_enum_funcs(prop, RNA_image_itemf); - ot->prop = prop; -} - -static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) -{ - Image *image; - ImBuf *ibuf; - char filename[FILE_MAX]; - - Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; - int w = settings->imapaint.screen_grab_size[0]; - int h = settings->imapaint.screen_grab_size[1]; - int maxsize; - char err_out[256] = "unknown"; - - RNA_string_get(op->ptr, "filepath", filename); - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); - if (w > maxsize) w = maxsize; - if (h > maxsize) h = maxsize; - - ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, R_ALPHAPREMUL, err_out); - if (!ibuf) { - /* Mostly happens when OpenGL offscreen buffer was failed to create, */ - /* but could be other reasons. Should be handled in the future. nazgul */ - BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out); - return OPERATOR_CANCELLED; - } - - image = BKE_image_add_from_imbuf(ibuf); - - if (image) { - /* now for the trickyness. store the view projection here! - * re-projection will reuse this */ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - - IDPropertyTemplate val; - IDProperty *idgroup = IDP_GetProperties(&image->id, 1); - IDProperty *view_data; - int orth; - float *array; - - val.array.len = PROJ_VIEW_DATA_SIZE; - val.array.type = IDP_FLOAT; - view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID); - - array = (float *)IDP_Array(view_data); - memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float); - memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float); - orth = project_paint_view_clip(v3d, rv3d, &array[0], &array[1]); - array[2] = orth ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */ - - IDP_AddToGroup(idgroup, view_data); - - rename_id(&image->id, "image_view"); - } - - return OPERATOR_FINISHED; -} - -void PAINT_OT_image_from_view(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Image from View"; - ot->idname = "PAINT_OT_image_from_view"; - ot->description = "Make an image from the current 3D view for re-projection"; - - /* api callbacks */ - ot->exec = texture_paint_image_from_view_exec; - ot->poll = ED_operator_region_view3d_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER; - - RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file"); -} diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 84250853f38..ed1b25d1b4e 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -35,17 +35,56 @@ #include "DNA_brush_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_object_types.h" +#include "BLI_math.h" + +#include "BKE_context.h" #include "BKE_brush.h" +#include "BKE_main.h" +#include "BKE_image.h" +#include "BKE_paint.h" +#include "BKE_report.h" -#include "BLI_math.h" +#include "ED_screen.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_view2d.h" #include "RE_shader_ext.h" - /* Brush Painting for 2D image editor */ +#include "GPU_draw.h" + +#include "paint_intern.h" + +/* Brush Painting for 2D image editor */ + +/* Defines and Structs */ +/* FTOCHAR as inline function */ +BLI_INLINE unsigned char f_to_char(const float val) +{ + return FTOCHAR(val); +} +#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \ + (c)[0] = f_to_char((f)[0]); \ + (c)[1] = f_to_char((f)[1]); \ + (c)[2] = f_to_char((f)[2]); \ +} (void)0 + +#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { \ + (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \ + (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \ + (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \ +} (void)0 + +#define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b) typedef struct BrushPainterCache { short enabled; @@ -57,38 +96,55 @@ typedef struct BrushPainterCache { int lastsize; float lastalpha; float lastjitter; + float last_rotation; ImBuf *ibuf; ImBuf *texibuf; ImBuf *maskibuf; } BrushPainterCache; -struct BrushPainter { +typedef struct BrushPainter { Scene *scene; Brush *brush; - float lastmousepos[2]; /* mouse position of last paint call */ - - float accumdistance; /* accumulated distance of brush since last paint op */ float lastpaintpos[2]; /* position of last paint op */ float startpaintpos[2]; /* position of first paint */ - double accumtime; /* accumulated time since last paint op (airbrush) */ - double lasttime; /* time of last update */ - - float lastpressure; - short firsttouch; /* first paint op */ - float startsize; - float startalpha; - float startjitter; - float startspacing; - BrushPainterCache cache; -}; +} BrushPainter; + +typedef struct ImagePaintRegion { + int destx, desty; + int srcx, srcy; + int width, height; +} ImagePaintRegion; + +typedef struct ImagePaintState { + BrushPainter *painter; + SpaceImage *sima; + View2D *v2d; + Scene *scene; + bScreen *screen; -BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) + Brush *brush; + short tool, blend; + Image *image; + ImBuf *canvas; + ImBuf *clonecanvas; + char *warnpackedfile; + char *warnmultifile; + + /* viewport texture paint only, but _not_ project paint */ + Object *ob; + int faceindex; + float uv[2]; + int do_facesel; +} ImagePaintState; + + +static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush) { BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); @@ -97,29 +153,11 @@ BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) painter->firsttouch = 1; painter->cache.lastsize = -1; /* force ibuf create in refresh */ - painter->startsize = BKE_brush_size_get(scene, brush); - painter->startalpha = BKE_brush_alpha_get(scene, brush); - painter->startjitter = brush->jitter; - painter->startspacing = brush->spacing; - return painter; } -static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure) -{ - if (BKE_brush_use_alpha_pressure(painter->scene, brush)) - BKE_brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure)); - if (BKE_brush_use_size_pressure(painter->scene, brush)) - BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure)); - if (brush->flag & BRUSH_JITTER_PRESSURE) - brush->jitter = max_ff(0.0f, painter->startjitter * pressure); - if (brush->flag & BRUSH_SPACING_PRESSURE) - brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure)); -} - - -void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) +static void brush_painter_2d_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) { if ((painter->cache.flt != flt) || (painter->cache.size != size) || ((painter->cache.texonly != texonly) && texonly)) @@ -142,22 +180,15 @@ void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short tex painter->cache.enabled = 1; } -void BKE_brush_painter_free(BrushPainter *painter) +static void brush_painter_2d_free(BrushPainter *painter) { - Brush *brush = painter->brush; - - BKE_brush_size_set(painter->scene, brush, painter->startsize); - BKE_brush_alpha_set(painter->scene, brush, painter->startalpha); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; - if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); MEM_freeN(painter); } -static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, +static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, int x, int y, int w, int h, int xt, int yt, const float pos[2]) { @@ -204,7 +235,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, xy[0] = x + xoff; xy[1] = y + yoff; - BKE_brush_sample_tex_2D(scene, brush, xy, tf, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, tf, NULL); } bf[0] = tf[0] * mf[0]; @@ -235,7 +266,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, xy[0] = x + xoff; xy[1] = y + yoff; - BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0); + BKE_brush_sample_tex_2D(scene, brush, xy, rgba, NULL); rgba_float_to_uchar(t, rgba); } @@ -248,7 +279,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, } } -static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const float pos[2]) +static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, const float pos[2]) { const Scene *scene = painter->scene; Brush *brush = painter->brush; @@ -286,25 +317,26 @@ static void brush_painter_tiled_tex_partial_update(BrushPainter *painter, const /* blend existing texture in new position */ if ((x1 < x2) && (y1 < y2)) - brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); + brush_painter_2d_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); if (oldtexibuf) IMB_freeImBuf(oldtexibuf); /* sample texture in new areas */ if ((0 < x1) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); + brush_painter_2d_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); if ((x2 < ibuf->x) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); + brush_painter_2d_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); if ((x1 < x2) && (0 < y1)) - brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); + brush_painter_2d_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); if ((x1 < x2) && (y2 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); + brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); } -static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) +static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) { const Scene *scene = painter->scene; + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; MTex *mtex = &brush->mtex; @@ -313,10 +345,16 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2 const int diameter = 2 * BKE_brush_size_get(scene, brush); const float alpha = BKE_brush_alpha_get(scene, brush); const bool do_tiled = ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_3D); + float rotation = -mtex->rot; + + if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { + rotation += ups->brush_rotation; + } if (diameter != cache->lastsize || alpha != cache->lastalpha || - brush->jitter != cache->lastjitter) + brush->jitter != cache->lastjitter || + rotation != cache->last_rotation) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); @@ -332,7 +370,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2 if (do_tiled) { BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction); - brush_painter_tiled_tex_partial_update(painter, pos); + brush_painter_2d_tiled_tex_partial_update(painter, pos); } else BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction); @@ -340,221 +378,447 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2 cache->lastsize = diameter; cache->lastalpha = alpha; cache->lastjitter = brush->jitter; + cache->last_rotation = rotation; } else if (do_tiled && mtex && mtex->tex) { int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; if ((dx != 0) || (dy != 0)) - brush_painter_tiled_tex_partial_update(painter, pos); + brush_painter_2d_tiled_tex_partial_update(painter, pos); } } -void BKE_brush_painter_break_stroke(BrushPainter *painter) +/* keep these functions in sync */ +static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const short is_torus, float r_rgb[3]) { - painter->firsttouch = 1; + if (is_torus) { + x %= ibuf->x; + if (x < 0) x += ibuf->x; + y %= ibuf->y; + if (y < 0) y += ibuf->y; + } + + if (ibuf->rect_float) { + float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4; + IMAPAINT_FLOAT_RGB_COPY(r_rgb, rrgbf); + } + else { + char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4; + IMAPAINT_CHAR_RGB_TO_FLOAT(r_rgb, rrgb); + } } +static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const short is_torus, const float rgb[3]) +{ + if (is_torus) { + x %= ibuf->x; + if (x < 0) x += ibuf->x; + y %= ibuf->y; + if (y < 0) y += ibuf->y; + } + if (ibuf->rect_float) { + float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4; + IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb); + } + else { + char *rrgb = (char *)ibuf->rect + (ibuf->x * y + x) * 4; + IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb); + } +} -int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure, - void *user, int use_color_correction) +static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) { - Scene *scene = painter->scene; - Brush *brush = painter->brush; - int totpaintops = 0; + float inrgb[3]; - if (pressure == 0.0f) { - if (painter->lastpressure) // XXX - hack, operator misses - pressure = painter->lastpressure; - else - pressure = 1.0f; /* zero pressure == not using tablet */ - } - if (painter->firsttouch) { - /* paint exactly once on first touch */ - painter->startpaintpos[0] = pos[0]; - painter->startpaintpos[1] = pos[1]; - - brush_pressure_apply(painter, brush, pressure); - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, pos, use_color_correction); - totpaintops += func(user, painter->cache.ibuf, pos, pos); - - painter->lasttime = time; - painter->firsttouch = 0; - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - } -#if 0 - else if (painter->brush->flag & BRUSH_AIRBRUSH) { - float spacing, step, paintpos[2], dmousepos[2], len; - double starttime, curtime = time; - - /* compute brush spacing adapted to brush size */ - spacing = brush->rate; //radius*brush->spacing * 0.01f; - - /* setup starting time, direction vector and accumulated time */ - starttime = painter->accumtime; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumtime += curtime - painter->lasttime; - - /* do paint op over unpainted time distance */ - while (painter->accumtime >= spacing) { - step = (spacing - starttime) * len; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter); - totpaintops += func(user, painter->cache.ibuf, - painter->lastpaintpos, paintpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumtime -= spacing; - starttime -= spacing; - } - - painter->lasttime = curtime; + // XXX: signed unsigned mismatch + if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) { + if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb); + else return 0; } -#endif else { - float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; - float t, len, press; - const int radius = BKE_brush_size_get(scene, brush); - - /* compute brush spacing adapted to brush radius, spacing may depend - * on pressure, so update it */ - brush_pressure_apply(painter, brush, painter->lastpressure); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - /* setup starting distance, direction vector and accumulated distance */ - startdistance = painter->accumdistance; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumdistance += len; - - if (brush->flag & BRUSH_SPACE) { - /* do paint op over unpainted distance */ - while ((len > 0.0f) && (painter->accumdistance >= spacing)) { - step = spacing - startdistance; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - t = step / len; - press = (1.0f - t) * painter->lastpressure + t * pressure; - brush_pressure_apply(painter, brush, press); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - BKE_brush_jitter_pos(scene, brush, paintpos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += - func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumdistance -= spacing; - startdistance -= spacing; - } - } - else { - BKE_brush_jitter_pos(scene, brush, pos, finalpos); + paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb); + } - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); + outrgb[0] += inrgb[0]; + outrgb[1] += inrgb[1]; + outrgb[2] += inrgb[2]; - totpaintops += func(user, painter->cache.ibuf, pos, finalpos); + return 1; +} - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - painter->accumdistance = 0; - } +static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus) +{ + int x, y, count, xi, yi, xo, yo; + int out_off[2], in_off[2], dim[2]; + float outrgb[3]; + + dim[0] = ibufb->x; + dim[1] = ibufb->y; + in_off[0] = pos[0]; + in_off[1] = pos[1]; + out_off[0] = out_off[1] = 0; + + if (!is_torus) { + IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], + &out_off[1], &dim[0], &dim[1]); + + if ((dim[0] == 0) || (dim[1] == 0)) + return; + } - /* do airbrush paint ops, based on the number of paint ops left over - * from regular painting. this is a temporary solution until we have - * accurate time stamps for mouse move events */ - if (brush->flag & BRUSH_AIRBRUSH) { - double curtime = time; - double painttime = brush->rate * totpaintops; + for (y = 0; y < dim[1]; y++) { + for (x = 0; x < dim[0]; x++) { + /* get input pixel */ + xi = in_off[0] + x; + yi = in_off[1] + y; - painter->accumtime += curtime - painter->lasttime; - if (painter->accumtime <= painttime) - painter->accumtime = 0.0; - else - painter->accumtime -= painttime; + count = 1; + paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb); - while (painter->accumtime >= (double)brush->rate) { - brush_pressure_apply(painter, brush, pressure); + count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus); + count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus); + count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus); - BKE_brush_jitter_pos(scene, brush, pos, finalpos); + count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus); + count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus); - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); + count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus); + count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus); + count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus); - totpaintops += - func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); - painter->accumtime -= (double)brush->rate; - } + mul_v3_fl(outrgb, 1.0f / (float)count); - painter->lasttime = curtime; + /* write into brush buffer */ + xo = out_off[0] + x; + yo = out_off[1] + y; + paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb); } } +} - painter->lastmousepos[0] = pos[0]; - painter->lastmousepos[1] = pos[1]; - painter->lastpressure = pressure; +static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height) +{ + region->destx = destx; + region->desty = desty; + region->srcx = srcx; + region->srcy = srcy; + region->width = width; + region->height = height; +} + +static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf) +{ + int destx = region->destx; + int desty = region->desty; + int srcx = region->srcx; + int srcy = region->srcy; + int width = region->width; + int height = region->height; + int origw, origh, w, h, tot = 0; + + /* convert destination and source coordinates to be within image */ + destx = destx % dbuf->x; + if (destx < 0) destx += dbuf->x; + desty = desty % dbuf->y; + if (desty < 0) desty += dbuf->y; + srcx = srcx % sbuf->x; + if (srcx < 0) srcx += sbuf->x; + srcy = srcy % sbuf->y; + if (srcy < 0) srcy += sbuf->y; + + /* clip width of blending area to destination imbuf, to avoid writing the + * same pixel twice */ + origw = w = (width > dbuf->x) ? dbuf->x : width; + origh = h = (height > dbuf->y) ? dbuf->y : height; + + /* clip within image */ + IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h); + paint_2d_set_region(®ion[tot++], destx, desty, srcx, srcy, w, h); + + /* do 3 other rects if needed */ + if (w < origw) + paint_2d_set_region(®ion[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h); + if (h < origh) + paint_2d_set_region(®ion[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h); + if ((w < origw) && (h < origh)) + paint_2d_set_region(®ion[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h); + + return tot; +} - BKE_brush_alpha_set(scene, brush, painter->startalpha); - BKE_brush_size_set(scene, brush, painter->startsize); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; +static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) +{ + ImagePaintRegion region[4]; + int a, tot; + + paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y); + tot = paint_2d_torus_split_region(region, ibufb, ibuf); + + for (a = 0; a < tot; a++) + IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty, + region[a].srcx, region[a].srcy, + region[a].width, region[a].height, IMB_BLEND_COPY_RGB); +} - return totpaintops; +static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) +{ + /* note: allocImbuf returns zero'd memory, so regions outside image will + * have zero alpha, and hence not be blended onto the image */ + int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1]; + ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags); + + IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); + IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, + IMB_BLEND_COPY_RGB); + IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h, + IMB_BLEND_COPY_ALPHA); + + return clonebuf; } +static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2]) +{ + ipos[0] = (int)floorf((pos[0] - ibufb->x / 2) + 1.0f); + ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f); +} -/* TODO: should probably be unified with BrushPainter stuff? */ -unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) +static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2]) { - unsigned int *texcache = NULL; - MTex *mtex = &br->mtex; - TexResult texres = {0}; - int hasrgb, ix, iy; - int side = half_side * 2; - - if (mtex->tex) { - float x, y, step = 2.0 / side, co[3]; - - texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); - - /*do normalized cannonical view coords for texture*/ - for (y = -1.0, iy = 0; iy < side; iy++, y += step) { - for (x = -1.0, ix = 0; ix < side; ix++, x += step) { - co[0] = x; - co[1] = y; - co[2] = 0.0f; - - /* This is copied from displace modifier code */ - hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres, NULL); - - /* if the texture gave an RGB value, we assume it didn't give a valid - * intensity, so calculate one (formula from do_material_tex). - * if the texture didn't give an RGB value, copy the intensity across - */ - if (hasrgb & TEX_RGB) - texres.tin = rgb_to_grayscale(&texres.tr); - - ((char *)texcache)[(iy * side + ix) * 4] = - ((char *)texcache)[(iy * side + ix) * 4 + 1] = - ((char *)texcache)[(iy * side + ix) * 4 + 2] = - ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); - } + ImagePaintState *s = ((ImagePaintState *)state); + ImBuf *clonebuf = NULL, *frombuf; + ImagePaintRegion region[4]; + short torus = s->brush->flag & BRUSH_TORUS; + short blend = s->blend; + float *offset = s->brush->clone.offset; + float liftpos[2]; + int bpos[2], blastpos[2], bliftpos[2]; + int a, tot; + + paint_2d_convert_brushco(ibufb, pos, bpos); + + /* lift from canvas */ + if (s->tool == PAINT_TOOL_SOFTEN) { + paint_2d_lift_soften(s->canvas, ibufb, bpos, torus); + } + else if (s->tool == PAINT_TOOL_SMEAR) { + if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) + return 0; + + paint_2d_convert_brushco(ibufb, lastpos, blastpos); + paint_2d_lift_smear(s->canvas, ibufb, blastpos); + } + else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) { + liftpos[0] = pos[0] - offset[0] * s->canvas->x; + liftpos[1] = pos[1] - offset[1] * s->canvas->y; + + paint_2d_convert_brushco(ibufb, liftpos, bliftpos); + clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos); + } + + frombuf = (clonebuf) ? clonebuf : ibufb; + + if (torus) { + paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); + tot = paint_2d_torus_split_region(region, s->canvas, frombuf); + } + else { + paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); + tot = 1; + } + + /* blend into canvas */ + for (a = 0; a < tot; a++) { + imapaint_dirty_region(s->image, s->canvas, + region[a].destx, region[a].desty, + region[a].width, region[a].height); + + IMB_rectblend(s->canvas, frombuf, + region[a].destx, region[a].desty, + region[a].srcx, region[a].srcy, + region[a].width, region[a].height, blend); + } + + if (clonebuf) IMB_freeImBuf(clonebuf); + + return 1; +} + + +static int paint_2d_canvas_set(ImagePaintState *s, Image *ima) +{ + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL); + + /* verify that we can paint and set canvas */ + if (ima == NULL) { + return 0; + } + else if (ima->packedfile && ima->rr) { + s->warnpackedfile = ima->id.name + 2; + return 0; + } + else if (ibuf && ibuf->channels != 4) { + s->warnmultifile = ima->id.name + 2; + return 0; + } + else if (!ibuf || !(ibuf->rect || ibuf->rect_float)) + return 0; + + s->image = ima; + s->canvas = ibuf; + + /* set clone canvas */ + if (s->tool == PAINT_TOOL_CLONE) { + ima = s->brush->clone.image; + ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL); + + if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) { + BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_release_ibuf(s->image, s->canvas, NULL); + return 0; + } + + s->clonecanvas = ibuf; + + /* temporarily add float rect for cloning */ + if (s->canvas->rect_float && !s->clonecanvas->rect_float) { + IMB_float_from_rect(s->clonecanvas); } + else if (!s->canvas->rect_float && !s->clonecanvas->rect) + IMB_rect_from_float(s->clonecanvas); } - return texcache; + return 1; } +static void paint_2d_canvas_free(ImagePaintState *s) +{ + BKE_image_release_ibuf(s->image, s->canvas, NULL); + BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL); +} + +int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser) +{ + float newuv[2], olduv[2]; + int redraw = 0; + ImagePaintState *s = ps; + BrushPainter *painter = s->painter; + ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL); + const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA); + + if (!ibuf) + return 0; + + s->blend = s->brush->blend; + if (eraser) + s->blend = IMB_BLEND_ERASE_ALPHA; + + UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]); + UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]); + + newuv[0] *= ibuf->x; + newuv[1] *= ibuf->y; + + olduv[0] *= ibuf->x; + olduv[1] *= ibuf->y; + + if (painter->firsttouch) { + /* paint exactly once on first touch */ + painter->startpaintpos[0] = newuv[0]; + painter->startpaintpos[1] = newuv[1]; + + painter->firsttouch = 0; + copy_v2_v2(painter->lastpaintpos, newuv); + } + else { + copy_v2_v2(painter->lastpaintpos, olduv); + } + /* OCIO_TODO: float buffers are now always linear, so always use color correction + * this should probably be changed when texture painting color space is supported + */ + brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0, 0); + + if (painter->cache.enabled) + brush_painter_2d_refresh_cache(painter, newuv, is_data == false); + + if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) { + imapaint_image_update(s->sima, s->image, ibuf, false); + BKE_image_release_ibuf(s->image, ibuf, NULL); + redraw |= 1; + } + else { + BKE_image_release_ibuf(s->image, ibuf, NULL); + } + + if (redraw) + imapaint_clear_partial_redraw(); + + return redraw; +} + +void *paint_2d_new_stroke(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; + Brush *brush = paint_brush(&settings->imapaint.paint); + + ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState"); + + s->sima = CTX_wm_space_image(C); + s->v2d = &CTX_wm_region(C)->v2d; + s->scene = scene; + s->screen = CTX_wm_screen(C); + + s->brush = brush; + s->tool = brush->imagepaint_tool; + s->blend = brush->blend; + + s->image = s->sima->image; + + if (!paint_2d_canvas_set(s, s->image)) { + if (s->warnmultifile) + BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint"); + if (s->warnpackedfile) + BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted"); + + MEM_freeN(s); + return NULL; + } + + paint_brush_init_tex(s->brush); + + /* create painter */ + s->painter = brush_painter_2d_new(scene, s->brush); + + return s; +} + +void paint_2d_redraw (const bContext *C, void *ps, int final) +{ + ImagePaintState *s = ps; + + if (final) { + if (s->image && !(s->sima && s->sima->lock)) + GPU_free_image(s->image); + + /* compositor listener deals with updating */ + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); + } + else { + if (!s->sima || !s->sima->lock) + ED_region_tag_redraw(CTX_wm_region(C)); + else + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); + } +} + +void paint_2d_stroke_done(void *ps) +{ + ImagePaintState *s = ps; + + paint_2d_canvas_free(s); + brush_painter_2d_free(s->painter); + paint_brush_exit_tex(s->brush); + + MEM_freeN(s); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c new file mode 100644 index 00000000000..96916236279 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -0,0 +1,4465 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: some of this file. + * + * Contributor(s): Jens Ole Wund (bjornmose), Campbell Barton (ideasman42) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_image_proj.c + * \ingroup edsculpt + * \brief Functions to paint images in 2D and 3D. + */ + +#include <float.h> +#include <string.h> +#include <stdio.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#ifdef WIN32 +# include "BLI_winstuff.h" +#endif + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_memarena.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "PIL_time.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" + +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_idprop.h" +#include "BKE_brush.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_colortools.h" + +#include "BKE_tessmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_view2d.h" + +#include "ED_image.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_uvedit.h" +#include "ED_view3d.h" +#include "ED_mesh.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "GPU_draw.h" + +#include "IMB_colormanagement.h" + +#include "paint_intern.h" + +/* Defines and Structs */ +/* FTOCHAR as inline function */ +BLI_INLINE unsigned char f_to_char(const float val) +{ + return FTOCHAR(val); +} + +#define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \ + (c)[0] = f_to_char((f)[0]); \ + (c)[1] = f_to_char((f)[1]); \ + (c)[2] = f_to_char((f)[2]); \ + (c)[3] = f_to_char((f)[3]); \ +} (void)0 + +#define IMAPAINT_CHAR_RGBA_TO_FLOAT(f, c) { \ + (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \ + (f)[1] = IMAPAINT_CHAR_TO_FLOAT((c)[1]); \ + (f)[2] = IMAPAINT_CHAR_TO_FLOAT((c)[2]); \ + (f)[3] = IMAPAINT_CHAR_TO_FLOAT((c)[3]); \ +} (void)0 + +#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \ + (c)[0] = f_to_char((f)[0]); \ + (c)[1] = f_to_char((f)[1]); \ + (c)[2] = f_to_char((f)[2]); \ +} (void)0 + +/* ProjectionPaint defines */ + +/* approx the number of buckets to have under the brush, + * used with the brush size to set the ps->buckets_x and ps->buckets_y value. + * + * When 3 - a brush should have ~9 buckets under it at once + * ...this helps for threading while painting as well as + * avoiding initializing pixels that wont touch the brush */ +#define PROJ_BUCKET_BRUSH_DIV 4 + +#define PROJ_BUCKET_RECT_MIN 4 +#define PROJ_BUCKET_RECT_MAX 256 + +#define PROJ_BOUNDBOX_DIV 8 +#define PROJ_BOUNDBOX_SQUARED (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV) + +//#define PROJ_DEBUG_PAINT 1 +//#define PROJ_DEBUG_NOSEAMBLEED 1 +//#define PROJ_DEBUG_PRINT_CLIP 1 +#define PROJ_DEBUG_WINCLIP 1 + +/* projectFaceSeamFlags options */ +//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */ +//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */ +#define PROJ_FACE_SEAM1 (1 << 0) /* If this face has a seam on any of its edges */ +#define PROJ_FACE_SEAM2 (1 << 1) +#define PROJ_FACE_SEAM3 (1 << 2) +#define PROJ_FACE_SEAM4 (1 << 3) + +#define PROJ_FACE_NOSEAM1 (1 << 4) +#define PROJ_FACE_NOSEAM2 (1 << 5) +#define PROJ_FACE_NOSEAM3 (1 << 6) +#define PROJ_FACE_NOSEAM4 (1 << 7) + +#define PROJ_SRC_VIEW 1 +#define PROJ_SRC_IMAGE_CAM 2 +#define PROJ_SRC_IMAGE_VIEW 3 + +#define PROJ_VIEW_DATA_ID "view_data" +#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */ + + +/* a slightly scaled down face is used to get fake 3D location for edge pixels in the seams + * as this number approaches 1.0f the likelihood increases of float precision errors where + * it is occluded by an adjacent face */ +#define PROJ_FACE_SCALE_SEAM 0.99f + +#define PROJ_BUCKET_NULL 0 +#define PROJ_BUCKET_INIT (1 << 0) +// #define PROJ_BUCKET_CLONE_INIT (1<<1) + +/* used for testing doubles, if a point is on a line etc */ +#define PROJ_GEOM_TOLERANCE 0.00075f + +/* vert flags */ +#define PROJ_VERT_CULL 1 + +/* This is mainly a convenience struct used so we can keep an array of images we use + * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread + * because 'partRedrawRect' and 'touch' values would not be thread safe */ +typedef struct ProjPaintImage { + Image *ima; + ImBuf *ibuf; + ImagePaintPartialRedraw *partRedrawRect; + void **undoRect; /* only used to build undo tiles after painting */ + int touch; +} ProjPaintImage; + +/* Main projection painting struct passed to all projection painting functions */ +typedef struct ProjPaintState { + View3D *v3d; + RegionView3D *rv3d; + ARegion *ar; + Scene *scene; + int source; /* PROJ_SRC_**** */ + + Brush *brush; + short tool, blend, mode; + int orig_brush_size; + Object *ob; + /* end similarities with ImagePaintState */ + + DerivedMesh *dm; + int dm_totface; + int dm_totvert; + int dm_release; + + MVert *dm_mvert; + MFace *dm_mface; + MTFace *dm_mtface; + MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */ + MTFace *dm_mtface_stencil; + + /* projection painting only */ + MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */ + LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */ + LinkNode **bucketFaces; /* bucketRect aligned array linkList of faces overlapping each bucket */ + unsigned char *bucketFlags; /* store if the bucks have been initialized */ +#ifndef PROJ_DEBUG_NOSEAMBLEED + char *faceSeamFlags; /* store info about faces, if they are initialized etc*/ + float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */ + LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */ +#endif + char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */ + int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */ + int buckets_y; + + ProjPaintImage *projImages; + + int pixel_sizeof; /* result of project_paint_pixel_sizeof(), constant per stroke */ + + int image_tot; /* size of projectImages array */ + + float (*screenCoords)[4]; /* verts projected into floating point screen space */ + + float screenMin[2]; /* 2D bounds for mesh verts on the screen's plane (screenspace) */ + float screenMax[2]; + float screen_width; /* Calculated from screenMin & screenMax */ + float screen_height; + int winx, winy; /* from the carea or from the projection render */ + + /* options for projection painting */ + int do_layer_clone; + int do_layer_stencil; + int do_layer_stencil_inv; + + short do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ + short do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ + short do_mask_normal; /* mask out pixels based on their normals */ + short do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */ + float normal_angle; /* what angle to mask at*/ + float normal_angle_inner; + float normal_angle_range; /* difference between normal_angle and normal_angle_inner, for easy access */ + + short is_ortho; + bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */ + short is_texbrush; /* only to avoid running */ +#ifndef PROJ_DEBUG_NOSEAMBLEED + float seam_bleed_px; +#endif + /* clone vars */ + float cloneOffset[2]; + + float projectMat[4][4]; /* Projection matrix, use for getting screen coords */ + float viewDir[3]; /* View vector, use for do_backfacecull and for ray casting with an ortho viewport */ + float viewPos[3]; /* View location in object relative 3D space, so can compare to verts */ + float clipsta, clipend; + + /* reproject vars */ + Image *reproject_image; + ImBuf *reproject_ibuf; + + + /* threads */ + int thread_tot; + int bucketMin[2]; + int bucketMax[2]; + int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */ +} ProjPaintState; + +typedef union pixelPointer { + float *f_pt; /* float buffer */ + unsigned int *uint_pt; /* 2 ways to access a char buffer */ + unsigned char *ch_pt; +} PixelPointer; + +typedef union pixelStore { + unsigned char ch[4]; + unsigned int uint; + float f[4]; +} PixelStore; + +typedef struct ProjPixel { + float projCoSS[2]; /* the floating point screen projection of this pixel */ + float worldCoSS[3]; + /* Only used when the airbrush is disabled. + * Store the max mask value to avoid painting over an area with a lower opacity + * with an advantage that we can avoid touching the pixel at all, if the + * new mask value is lower then mask_max */ + unsigned short mask_max; + + /* for various reasons we may want to mask out painting onto this pixel */ + unsigned short mask; + + short x_px, y_px; + + PixelStore origColor; + PixelStore newColor; + PixelPointer pixel; + + short image_index; /* if anyone wants to paint onto more then 32768 images they can bite me */ + unsigned char bb_cell_index; +} ProjPixel; + +typedef struct ProjPixelClone { + struct ProjPixel __pp; + PixelStore clonepx; +} ProjPixelClone; + +/* blur, store surrounding colors */ +#define PROJ_PIXEL_SOFTEN_TOT 4 +/* blur picking offset (in screenspace) */ +#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f + +static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = { + {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, + { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX}, + { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX}, + { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, +}; + +/* Finish projection painting structs */ + +static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index) +{ + Image *ima; + + if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */ + MFace *mf = ps->dm_mface + face_index; + ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL); + } + else { + ima = dm_mtface[face_index].tpage; + } + + return ima; +} + +/* fast projection bucket array lookup, use the safe version for bound checking */ +static int project_bucket_offset(const ProjPaintState *ps, const float projCoSS[2]) +{ + /* If we were not dealing with screenspace 2D coords we could simple do... + * ps->bucketRect[x + (y*ps->buckets_y)] */ + + /* please explain? + * projCoSS[0] - ps->screenMin[0] : zero origin + * ... / ps->screen_width : range from 0.0 to 1.0 + * ... * ps->buckets_x : use as a bucket index + * + * Second multiplication does similar but for vertical offset + */ + return ( (int)(((projCoSS[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x)) + + (((int)(((projCoSS[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y)) * ps->buckets_x); +} + +static int project_bucket_offset_safe(const ProjPaintState *ps, const float projCoSS[2]) +{ + int bucket_index = project_bucket_offset(ps, projCoSS); + + if (bucket_index < 0 || bucket_index >= ps->buckets_x * ps->buckets_y) { + return -1; + } + else { + return bucket_index; + } +} + +/* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */ +static void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]) +{ + float wtot_inv, wtot; + + w[0] = area_tri_signed_v2(v2, v3, co) / v1[3]; + w[1] = area_tri_signed_v2(v3, v1, co) / v2[3]; + w[2] = area_tri_signed_v2(v1, v2, co) / v3[3]; + wtot = w[0] + w[1] + w[2]; + + if (wtot != 0.0f) { + wtot_inv = 1.0f / wtot; + + w[0] = w[0] * wtot_inv; + w[1] = w[1] * wtot_inv; + w[2] = w[2] * wtot_inv; + } + else /* dummy values for zero area face */ + w[0] = w[1] = w[2] = 1.0f / 3.0f; +} + +static float VecZDepthOrtho(const float pt[2], + const float v1[3], const float v2[3], const float v3[3], + float w[3]) +{ + barycentric_weights_v2(v1, v2, v3, pt, w); + return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]); +} + +static float VecZDepthPersp(const float pt[2], + const float v1[4], const float v2[4], const float v3[4], + float w[3]) +{ + float wtot_inv, wtot; + float w_tmp[3]; + + barycentric_weights_v2_persp(v1, v2, v3, pt, w); + /* for the depth we need the weights to match what + * barycentric_weights_v2 would return, in this case its easiest just to + * undo the 4th axis division and make it unit-sum + * + * don't call barycentric_weights_v2() because our callers expect 'w' + * to be weighted from the perspective */ + w_tmp[0] = w[0] * v1[3]; + w_tmp[1] = w[1] * v2[3]; + w_tmp[2] = w[2] * v3[3]; + + wtot = w_tmp[0] + w_tmp[1] + w_tmp[2]; + + if (wtot != 0.0f) { + wtot_inv = 1.0f / wtot; + + w_tmp[0] = w_tmp[0] * wtot_inv; + w_tmp[1] = w_tmp[1] * wtot_inv; + w_tmp[2] = w_tmp[2] * wtot_inv; + } + else /* dummy values for zero area face */ + w_tmp[0] = w_tmp[1] = w_tmp[2] = 1.0f / 3.0f; + /* done mimicing barycentric_weights_v2() */ + + return (v1[2] * w_tmp[0]) + (v2[2] * w_tmp[1]) + (v3[2] * w_tmp[2]); +} + + +/* Return the top-most face index that the screen space coord 'pt' touches (or -1) */ +static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], float w[3], int *side) +{ + LinkNode *node; + float w_tmp[3]; + float *v1, *v2, *v3, *v4; + int bucket_index; + int face_index; + int best_side = -1; + int best_face_index = -1; + float z_depth_best = FLT_MAX, z_depth; + MFace *mf; + + bucket_index = project_bucket_offset_safe(ps, pt); + if (bucket_index == -1) + return -1; + + + + /* we could return 0 for 1 face buckets, as long as this function assumes + * that the point its testing is only every originated from an existing face */ + + for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { + face_index = GET_INT_FROM_POINTER(node->link); + mf = ps->dm_mface + face_index; + + v1 = ps->screenCoords[mf->v1]; + v2 = ps->screenCoords[mf->v2]; + v3 = ps->screenCoords[mf->v3]; + + if (isect_point_tri_v2(pt, v1, v2, v3)) { + if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v2, v3, w_tmp); + else z_depth = VecZDepthPersp(pt, v1, v2, v3, w_tmp); + + if (z_depth < z_depth_best) { + best_face_index = face_index; + best_side = 0; + z_depth_best = z_depth; + copy_v3_v3(w, w_tmp); + } + } + else if (mf->v4) { + v4 = ps->screenCoords[mf->v4]; + + if (isect_point_tri_v2(pt, v1, v3, v4)) { + if (ps->is_ortho) z_depth = VecZDepthOrtho(pt, v1, v3, v4, w_tmp); + else z_depth = VecZDepthPersp(pt, v1, v3, v4, w_tmp); + + if (z_depth < z_depth_best) { + best_face_index = face_index; + best_side = 1; + z_depth_best = z_depth; + copy_v3_v3(w, w_tmp); + } + } + } + } + + *side = best_side; + return best_face_index; /* will be -1 or a valid face */ +} + +/* Converts a uv coord into a pixel location wrapping if the uv is outside 0-1 range */ +static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) +{ + /* use */ + *x = (float)fmodf(uv[0], 1.0f); + *y = (float)fmodf(uv[1], 1.0f); + + if (*x < 0.0f) *x += 1.0f; + if (*y < 0.0f) *y += 1.0f; + + *x = *x * ibuf_x - 0.5f; + *y = *y * ibuf_y - 0.5f; +} + +/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */ +static int project_paint_PickColor(const ProjPaintState *ps, const float pt[2], + float *rgba_fp, unsigned char *rgba, const int interp) +{ + float w[3], uv[2]; + int side; + int face_index; + MTFace *tf; + Image *ima; + ImBuf *ibuf; + int xi, yi; + + + face_index = project_paint_PickFace(ps, pt, w, &side); + + if (face_index == -1) + return 0; + + tf = ps->dm_mtface + face_index; + + if (side == 0) { + interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); + } + else { /* QUAD */ + interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); + } + + ima = project_paint_face_image(ps, ps->dm_mtface, face_index); + ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */ + if (!ibuf) return 0; + + if (interp) { + float x, y; + uvco_to_wrapped_pxco(uv, ibuf->x, ibuf->y, &x, &y); + + if (ibuf->rect_float) { + if (rgba_fp) { + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y); + } + else { + float rgba_tmp_f[4]; + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y); + IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f); + } + } + else { + if (rgba) { + bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y); + } + else { + unsigned char rgba_tmp[4]; + bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y); + IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp); + } + } + } + else { + //xi = (int)((uv[0]*ibuf->x) + 0.5f); + //yi = (int)((uv[1]*ibuf->y) + 0.5f); + //if (xi < 0 || xi >= ibuf->x || yi < 0 || yi >= ibuf->y) return 0; + + /* wrap */ + xi = ((int)(uv[0] * ibuf->x)) % ibuf->x; + if (xi < 0) xi += ibuf->x; + yi = ((int)(uv[1] * ibuf->y)) % ibuf->y; + if (yi < 0) yi += ibuf->y; + + + if (rgba) { + if (ibuf->rect_float) { + float *rgba_tmp_fp = ibuf->rect_float + (xi + yi * ibuf->x * 4); + IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_fp); + } + else { + *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4)); + } + } + + if (rgba_fp) { + if (ibuf->rect_float) { + copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4))); + } + else { + char *tmp_ch = ((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4); + IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, tmp_ch); + } + } + } + return 1; +} + +/* Check if 'pt' is infront of the 3 verts on the Z axis (used for screenspace occlusuion test) + * return... + * 0 : no occlusion + * -1 : no occlusion but 2D intersection is true (avoid testing the other half of a quad) + * 1 : occluded + * 2 : occluded with w[3] weights set (need to know in some cases) */ + +static int project_paint_occlude_ptv(float pt[3], float v1[4], float v2[4], float v3[4], float w[3], int is_ortho) +{ + /* if all are behind us, return false */ + if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) + return 0; + + /* do a 2D point in try intersection */ + if (!isect_point_tri_v2(pt, v1, v2, v3)) + return 0; /* we know there is */ + + + /* From here on we know there IS an intersection */ + /* if ALL of the verts are infront of us then we know it intersects ? */ + if (v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) { + return 1; + } + else { + /* we intersect? - find the exact depth at the point of intersection */ + /* Is this point is occluded by another face? */ + if (is_ortho) { + if (VecZDepthOrtho(pt, v1, v2, v3, w) < pt[2]) return 2; + } + else { + if (VecZDepthPersp(pt, v1, v2, v3, w) < pt[2]) return 2; + } + } + return -1; +} + + +static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf, + float pt[3], float v1[4], float v2[4], float v3[4], + const int side) +{ + float w[3], wco[3]; + int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho); + + if (ret <= 0) + return ret; + + if (ret == 1) { /* weights not calculated */ + if (ps->is_ortho) barycentric_weights_v2(v1, v2, v3, pt, w); + else barycentric_weights_v2_persp(v1, v2, v3, pt, w); + } + + /* Test if we're in the clipped area, */ + if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); + else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); + + if (!ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { + return 1; + } + + return -1; +} + + +/* Check if a screenspace location is occluded by any other faces + * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison + * and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */ +static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, const int orig_face, float pixelScreenCo[4]) +{ + MFace *mf; + int face_index; + int isect_ret; + float w[3]; /* not needed when clipping */ + const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; + + /* we could return 0 for 1 face buckets, as long as this function assumes + * that the point its testing is only every originated from an existing face */ + + for (; bucketFace; bucketFace = bucketFace->next) { + face_index = GET_INT_FROM_POINTER(bucketFace->link); + + if (orig_face != face_index) { + mf = ps->dm_mface + face_index; + if (do_clip) + isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], 0); + else + isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v2], ps->screenCoords[mf->v3], w, ps->is_ortho); + + /* Note, if (isect_ret == -1) then we don't want to test the other side of the quad */ + if (isect_ret == 0 && mf->v4) { + if (do_clip) + isect_ret = project_paint_occlude_ptv_clip(ps, mf, pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], 1); + else + isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho); + } + if (isect_ret >= 1) { + /* TODO - we may want to cache the first hit, + * it is not possible to swap the face order in the list anymore */ + return 1; + } + } + } + return 0; +} + +/* basic line intersection, could move to math_geom.c, 2 points with a horiz line + * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */ +#define ISECT_TRUE 1 +#define ISECT_TRUE_P1 2 +#define ISECT_TRUE_P2 3 +static int line_isect_y(const float p1[2], const float p2[2], const float y_level, float *x_isect) +{ + float y_diff; + + if (y_level == p1[1]) { /* are we touching the first point? - no interpolation needed */ + *x_isect = p1[0]; + return ISECT_TRUE_P1; + } + if (y_level == p2[1]) { /* are we touching the second point? - no interpolation needed */ + *x_isect = p2[0]; + return ISECT_TRUE_P2; + } + + y_diff = fabsf(p1[1] - p2[1]); /* yuck, horizontal line, we cant do much here */ + + if (y_diff < 0.000001f) { + *x_isect = (p1[0] + p2[0]) * 0.5f; + return ISECT_TRUE; + } + + if (p1[1] > y_level && p2[1] < y_level) { + *x_isect = (p2[0] * (p1[1] - y_level) + p1[0] * (y_level - p2[1])) / y_diff; /*(p1[1]-p2[1]);*/ + return ISECT_TRUE; + } + else if (p1[1] < y_level && p2[1] > y_level) { + *x_isect = (p2[0] * (y_level - p1[1]) + p1[0] * (p2[1] - y_level)) / y_diff; /*(p2[1]-p1[1]);*/ + return ISECT_TRUE; + } + else { + return 0; + } +} + +static int line_isect_x(const float p1[2], const float p2[2], const float x_level, float *y_isect) +{ + float x_diff; + + if (x_level == p1[0]) { /* are we touching the first point? - no interpolation needed */ + *y_isect = p1[1]; + return ISECT_TRUE_P1; + } + if (x_level == p2[0]) { /* are we touching the second point? - no interpolation needed */ + *y_isect = p2[1]; + return ISECT_TRUE_P2; + } + + x_diff = fabsf(p1[0] - p2[0]); /* yuck, horizontal line, we cant do much here */ + + if (x_diff < 0.000001f) { /* yuck, vertical line, we cant do much here */ + *y_isect = (p1[0] + p2[0]) * 0.5f; + return ISECT_TRUE; + } + + if (p1[0] > x_level && p2[0] < x_level) { + *y_isect = (p2[1] * (p1[0] - x_level) + p1[1] * (x_level - p2[0])) / x_diff; /*(p1[0]-p2[0]);*/ + return ISECT_TRUE; + } + else if (p1[0] < x_level && p2[0] > x_level) { + *y_isect = (p2[1] * (x_level - p1[0]) + p1[1] * (p2[0] - x_level)) / x_diff; /*(p2[0]-p1[0]);*/ + return ISECT_TRUE; + } + else { + return 0; + } +} + +/* simple func use for comparing UV locations to check if there are seams. + * Its possible this gives incorrect results, when the UVs for 1 face go into the next + * tile, but do not do this for the adjacent face, it could return a false positive. + * This is so unlikely that Id not worry about it. */ +#ifndef PROJ_DEBUG_NOSEAMBLEED +static int cmp_uv(const float vec2a[2], const float vec2b[2]) +{ + /* if the UV's are not between 0.0 and 1.0 */ + float xa = (float)fmodf(vec2a[0], 1.0f); + float ya = (float)fmodf(vec2a[1], 1.0f); + + float xb = (float)fmodf(vec2b[0], 1.0f); + float yb = (float)fmodf(vec2b[1], 1.0f); + + if (xa < 0.0f) xa += 1.0f; + if (ya < 0.0f) ya += 1.0f; + + if (xb < 0.0f) xb += 1.0f; + if (yb < 0.0f) yb += 1.0f; + + return ((fabsf(xa - xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya - yb) < PROJ_GEOM_TOLERANCE)) ? 1 : 0; +} +#endif + +/* set min_px and max_px to the image space bounds of the UV coords + * return zero if there is no area in the returned rectangle */ +#ifndef PROJ_DEBUG_NOSEAMBLEED +static int pixel_bounds_uv( + const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2], + rcti *bounds_px, + const int ibuf_x, const int ibuf_y, + int is_quad + ) +{ + float min_uv[2], max_uv[2]; /* UV bounds */ + + INIT_MINMAX2(min_uv, max_uv); + + minmax_v2v2_v2(min_uv, max_uv, uv1); + minmax_v2v2_v2(min_uv, max_uv, uv2); + minmax_v2v2_v2(min_uv, max_uv, uv3); + if (is_quad) + minmax_v2v2_v2(min_uv, max_uv, uv4); + + bounds_px->xmin = (int)(ibuf_x * min_uv[0]); + bounds_px->ymin = (int)(ibuf_y * min_uv[1]); + + bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1; + bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1; + + /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ + + /* face uses no UV area when quantized to pixels? */ + return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; +} +#endif + +static int pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot) +{ + float min_uv[2], max_uv[2]; /* UV bounds */ + + if (tot == 0) { + return 0; + } + + INIT_MINMAX2(min_uv, max_uv); + + while (tot--) { + minmax_v2v2_v2(min_uv, max_uv, (*uv)); + uv++; + } + + bounds_px->xmin = (int)(ibuf_x * min_uv[0]); + bounds_px->ymin = (int)(ibuf_y * min_uv[1]); + + bounds_px->xmax = (int)(ibuf_x * max_uv[0]) + 1; + bounds_px->ymax = (int)(ibuf_y * max_uv[1]) + 1; + + /*printf("%d %d %d %d\n", min_px[0], min_px[1], max_px[0], max_px[1]);*/ + + /* face uses no UV area when quantized to pixels? */ + return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; +} + +#ifndef PROJ_DEBUG_NOSEAMBLEED + +/* This function returns 1 if this face has a seam along the 2 face-vert indices + * 'orig_i1_fidx' and 'orig_i2_fidx' */ +static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx) +{ + LinkNode *node; + int face_index; + unsigned int i1, i2; + int i1_fidx = -1, i2_fidx = -1; /* index in face */ + MFace *mf; + MTFace *tf; + const MFace *orig_mf = ps->dm_mface + orig_face; + const MTFace *orig_tf = ps->dm_mtface + orig_face; + + /* vert indices from face vert order indices */ + i1 = (*(&orig_mf->v1 + orig_i1_fidx)); + i2 = (*(&orig_mf->v1 + orig_i2_fidx)); + + for (node = ps->vertFaces[i1]; node; node = node->next) { + face_index = GET_INT_FROM_POINTER(node->link); + + if (face_index != orig_face) { + mf = ps->dm_mface + face_index; + /* could check if the 2 faces images match here, + * but then there wouldn't be a way to return the opposite face's info */ + + + /* We need to know the order of the verts in the adjacent face + * set the i1_fidx and i2_fidx to (0,1,2,3) */ + if (mf->v1 == i1) i1_fidx = 0; + else if (mf->v2 == i1) i1_fidx = 1; + else if (mf->v3 == i1) i1_fidx = 2; + else if (mf->v4 && mf->v4 == i1) i1_fidx = 3; + + if (mf->v1 == i2) i2_fidx = 0; + else if (mf->v2 == i2) i2_fidx = 1; + else if (mf->v3 == i2) i2_fidx = 2; + else if (mf->v4 && mf->v4 == i2) i2_fidx = 3; + + /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */ + if (i2_fidx != -1) { + Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); + Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face); + + /* This IS an adjacent face!, now lets check if the UVs are ok */ + tf = ps->dm_mtface + face_index; + + /* set up the other face */ + *other_face = face_index; + *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx; + + /* first test if they have the same image */ + if ((orig_tpage == tpage) && + cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) && + cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) ) + { + // printf("SEAM (NONE)\n"); + return 0; + + } + else { + // printf("SEAM (UV GAP)\n"); + return 1; + } + } + } + } + // printf("SEAM (NO FACE)\n"); + *other_face = -1; + return 1; +} + +/* Calculate outset UV's, this is not the same as simply scaling the UVs, + * since the outset coords are a margin that keep an even distance from the original UV's, + * note that the image aspect is taken into account */ +static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, + const int ibuf_x, const int ibuf_y, const int is_quad) +{ + float a1, a2, a3, a4 = 0.0f; + float puv[4][2]; /* pixelspace uv's */ + float no1[2], no2[2], no3[2], no4[2]; /* normals */ + float dir1[2], dir2[2], dir3[2], dir4[2]; + float ibuf_inv[2]; + + ibuf_inv[0] = 1.0f / (float)ibuf_x; + ibuf_inv[1] = 1.0f / (float)ibuf_y; + + /* make UV's in pixel space so we can */ + puv[0][0] = orig_uv[0][0] * ibuf_x; + puv[0][1] = orig_uv[0][1] * ibuf_y; + + puv[1][0] = orig_uv[1][0] * ibuf_x; + puv[1][1] = orig_uv[1][1] * ibuf_y; + + puv[2][0] = orig_uv[2][0] * ibuf_x; + puv[2][1] = orig_uv[2][1] * ibuf_y; + + if (is_quad) { + puv[3][0] = orig_uv[3][0] * ibuf_x; + puv[3][1] = orig_uv[3][1] * ibuf_y; + } + + /* face edge directions */ + sub_v2_v2v2(dir1, puv[1], puv[0]); + sub_v2_v2v2(dir2, puv[2], puv[1]); + normalize_v2(dir1); + normalize_v2(dir2); + + if (is_quad) { + sub_v2_v2v2(dir3, puv[3], puv[2]); + sub_v2_v2v2(dir4, puv[0], puv[3]); + normalize_v2(dir3); + normalize_v2(dir4); + } + else { + sub_v2_v2v2(dir3, puv[0], puv[2]); + normalize_v2(dir3); + } + + /* TODO - angle_normalized_v2v2(...) * (M_PI/180.0f) + * This is incorrect. Its already given radians but without it wont work. + * need to look into a fix - campbell */ + if (is_quad) { + a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI / 180.0f)); + a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f)); + a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f)); + a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI / 180.0f)); + } + else { + a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI / 180.0f)); + a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI / 180.0f)); + a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI / 180.0f)); + } + + if (is_quad) { + sub_v2_v2v2(no1, dir4, dir1); + sub_v2_v2v2(no2, dir1, dir2); + sub_v2_v2v2(no3, dir2, dir3); + sub_v2_v2v2(no4, dir3, dir4); + normalize_v2(no1); + normalize_v2(no2); + normalize_v2(no3); + normalize_v2(no4); + mul_v2_fl(no1, a1 * scaler); + mul_v2_fl(no2, a2 * scaler); + mul_v2_fl(no3, a3 * scaler); + mul_v2_fl(no4, a4 * scaler); + add_v2_v2v2(outset_uv[0], puv[0], no1); + add_v2_v2v2(outset_uv[1], puv[1], no2); + add_v2_v2v2(outset_uv[2], puv[2], no3); + add_v2_v2v2(outset_uv[3], puv[3], no4); + mul_v2_v2(outset_uv[0], ibuf_inv); + mul_v2_v2(outset_uv[1], ibuf_inv); + mul_v2_v2(outset_uv[2], ibuf_inv); + mul_v2_v2(outset_uv[3], ibuf_inv); + } + else { + sub_v2_v2v2(no1, dir3, dir1); + sub_v2_v2v2(no2, dir1, dir2); + sub_v2_v2v2(no3, dir2, dir3); + normalize_v2(no1); + normalize_v2(no2); + normalize_v2(no3); + mul_v2_fl(no1, a1 * scaler); + mul_v2_fl(no2, a2 * scaler); + mul_v2_fl(no3, a3 * scaler); + add_v2_v2v2(outset_uv[0], puv[0], no1); + add_v2_v2v2(outset_uv[1], puv[1], no2); + add_v2_v2v2(outset_uv[2], puv[2], no3); + + mul_v2_v2(outset_uv[0], ibuf_inv); + mul_v2_v2(outset_uv[1], ibuf_inv); + mul_v2_v2(outset_uv[2], ibuf_inv); + } +} + +/* + * Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4 + * 1<<i - where i is (0-3) + * + * If we're multithreadng, make sure threads are locked when this is called + */ +static void project_face_seams_init(const ProjPaintState *ps, const int face_index, const int is_quad) +{ + int other_face, other_fidx; /* vars for the other face, we also set its flag */ + int fidx1 = is_quad ? 3 : 2; + int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */ + + do { + if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) { + if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) { + ps->faceSeamFlags[face_index] |= 1 << fidx1; + if (other_face != -1) + ps->faceSeamFlags[other_face] |= 1 << other_fidx; + } + else { + ps->faceSeamFlags[face_index] |= 16 << fidx1; + if (other_face != -1) + ps->faceSeamFlags[other_face] |= 16 << other_fidx; /* second 4 bits for disabled */ + } + } + + fidx2 = fidx1; + } while (fidx1--); +} +#endif // PROJ_DEBUG_NOSEAMBLEED + + +/* Converts a UV location to a 3D screenspace location + * Takes a 'uv' and 3 UV coords, and sets the values of pixelScreenCo + * + * This is used for finding a pixels location in screenspace for painting */ +static void screen_px_from_ortho( + float uv[2], + float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */ + float uv1co[2], float uv2co[2], float uv3co[2], + float pixelScreenCo[4], + float w[3]) +{ + barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); + interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); +} + +/* same as screen_px_from_ortho except we need to take into account + * the perspective W coord for each vert */ +static void screen_px_from_persp( + float uv[2], + float v1co[4], float v2co[4], float v3co[4], /* screenspace coords */ + float uv1co[2], float uv2co[2], float uv3co[2], + float pixelScreenCo[4], + float w[3]) +{ + + float wtot_inv, wtot; + barycentric_weights_v2(uv1co, uv2co, uv3co, uv, w); + + /* re-weight from the 4th coord of each screen vert */ + w[0] *= v1co[3]; + w[1] *= v2co[3]; + w[2] *= v3co[3]; + + wtot = w[0] + w[1] + w[2]; + + if (wtot > 0.0f) { + wtot_inv = 1.0f / wtot; + w[0] *= wtot_inv; + w[1] *= wtot_inv; + w[2] *= wtot_inv; + } + else { + w[0] = w[1] = w[2] = 1.0f / 3.0f; /* dummy values for zero area face */ + } + /* done re-weighting */ + + interp_v3_v3v3v3(pixelScreenCo, v1co, v2co, v3co, w); +} + +static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], + int side, unsigned char rgba_ub[4], float rgba_f[4]) +{ + float *uvCo1, *uvCo2, *uvCo3; + float uv_other[2], x, y; + + uvCo1 = (float *)tf_other->uv[0]; + if (side == 1) { + uvCo2 = (float *)tf_other->uv[2]; + uvCo3 = (float *)tf_other->uv[3]; + } + else { + uvCo2 = (float *)tf_other->uv[1]; + uvCo3 = (float *)tf_other->uv[2]; + } + + interp_v2_v2v2v2(uv_other, uvCo1, uvCo2, uvCo3, (float *)w); + + /* use */ + uvco_to_wrapped_pxco(uv_other, ibuf_other->x, ibuf_other->y, &x, &y); + + + if (ibuf_other->rect_float) { /* from float to float */ + bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y); + } + else { /* from char to float */ + bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y); + } + +} + +/* run this outside project_paint_uvpixel_init since pixels with mask 0 don't need init */ +static float project_paint_uvpixel_mask( + const ProjPaintState *ps, + const int face_index, + const int side, + const float w[3]) +{ + float mask; + + /* Image Mask */ + if (ps->do_layer_stencil) { + /* another UV maps image is masking this one's */ + ImBuf *ibuf_other; + Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index); + const MTFace *tf_other = ps->dm_mtface_stencil + face_index; + + if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { + /* BKE_image_acquire_ibuf - TODO - this may be slow */ + unsigned char rgba_ub[4]; + float rgba_f[4]; + + project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, rgba_f); + + if (ibuf_other->rect_float) { /* from float to float */ + mask = ((rgba_f[0] + rgba_f[1] + rgba_f[2]) / 3.0f) * rgba_f[3]; + } + else { /* from char to float */ + mask = ((rgba_ub[0] + rgba_ub[1] + rgba_ub[2]) / (256 * 3.0f)) * (rgba_ub[3] / 256.0f); + } + + BKE_image_release_ibuf(other_tpage, ibuf_other, NULL); + + if (!ps->do_layer_stencil_inv) /* matching the gimps layer mask black/white rules, white==full opacity */ + mask = (1.0f - mask); + + if (mask == 0.0f) { + return 0.0f; + } + } + else { + return 0.0f; + } + } + else { + mask = 1.0f; + } + + /* calculate mask */ + if (ps->do_mask_normal) { + MFace *mf = &ps->dm_mface[face_index]; + float no[3], angle; + if (mf->flag & ME_SMOOTH) { + short *no1, *no2, *no3; + no1 = ps->dm_mvert[mf->v1].no; + if (side == 1) { + no2 = ps->dm_mvert[mf->v3].no; + no3 = ps->dm_mvert[mf->v4].no; + } + else { + no2 = ps->dm_mvert[mf->v2].no; + no3 = ps->dm_mvert[mf->v3].no; + } + + no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0]; + no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1]; + no[2] = w[0] * no1[2] + w[1] * no2[2] + w[2] * no3[2]; + normalize_v3(no); + } + else { + /* incase the */ +#if 1 + /* normalizing per pixel isn't optimal, we could cache or check ps->*/ + if (mf->v4) + normal_quad_v3(no, + ps->dm_mvert[mf->v1].co, + ps->dm_mvert[mf->v2].co, + ps->dm_mvert[mf->v3].co, + ps->dm_mvert[mf->v4].co); + else + normal_tri_v3(no, + ps->dm_mvert[mf->v1].co, + ps->dm_mvert[mf->v2].co, + ps->dm_mvert[mf->v3].co); +#else + /* don't use because some modifiers dont have normal data (subsurf for eg) */ + copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, face_index, CD_NORMAL)); +#endif + } + + /* now we can use the normal as a mask */ + if (ps->is_ortho) { + angle = angle_normalized_v3v3((float *)ps->viewDir, no); + } + else { + /* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */ + float viewDirPersp[3]; + float *co1, *co2, *co3; + co1 = ps->dm_mvert[mf->v1].co; + if (side == 1) { + co2 = ps->dm_mvert[mf->v3].co; + co3 = ps->dm_mvert[mf->v4].co; + } + else { + co2 = ps->dm_mvert[mf->v2].co; + co3 = ps->dm_mvert[mf->v3].co; + } + + /* Get the direction from the viewPoint to the pixel and normalize */ + viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0])); + viewDirPersp[1] = (ps->viewPos[1] - (w[0] * co1[1] + w[1] * co2[1] + w[2] * co3[1])); + viewDirPersp[2] = (ps->viewPos[2] - (w[0] * co1[2] + w[1] * co2[2] + w[2] * co3[2])); + normalize_v3(viewDirPersp); + + angle = angle_normalized_v3v3(viewDirPersp, no); + } + + if (angle >= ps->normal_angle) { + return 0.0f; /* outsize the normal limit*/ + } + else if (angle > ps->normal_angle_inner) { + mask *= (ps->normal_angle - angle) / ps->normal_angle_range; + } /* otherwise no mask normal is needed, were within the limit */ + } + + /* This only works when the opacity dosnt change while painting, stylus pressure messes with this + * so don't use it. */ + // if (ps->is_airbrush == 0) mask *= BKE_brush_alpha_get(ps->brush); + + return mask; +} + +static int project_paint_pixel_sizeof(const short tool) +{ + if ((tool == PAINT_TOOL_CLONE) || (tool == PAINT_TOOL_SMEAR)) { + return sizeof(ProjPixelClone); + } + else { + return sizeof(ProjPixel); + } +} + + +/* run this function when we know a bucket's, face's pixel can be initialized, + * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ +static ProjPixel *project_paint_uvpixel_init( + const ProjPaintState *ps, + MemArena *arena, + const ImBuf *ibuf, + short x_px, short y_px, + const float mask, + const int face_index, + const int image_index, + const float pixelScreenCo[4], + const float world_spaceCo[3], + const int side, + const float w[3]) +{ + ProjPixel *projPixel; + + /* wrap pixel location */ + x_px = x_px % ibuf->x; + if (x_px < 0) x_px += ibuf->x; + y_px = y_px % ibuf->y; + if (y_px < 0) y_px += ibuf->y; + + BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool)); + projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof); + //memset(projPixel, 0, size); + + if (ibuf->rect_float) { + projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4); + projPixel->origColor.f[0] = projPixel->newColor.f[0] = projPixel->pixel.f_pt[0]; + projPixel->origColor.f[1] = projPixel->newColor.f[1] = projPixel->pixel.f_pt[1]; + projPixel->origColor.f[2] = projPixel->newColor.f[2] = projPixel->pixel.f_pt[2]; + projPixel->origColor.f[3] = projPixel->newColor.f[3] = projPixel->pixel.f_pt[3]; + } + else { + projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4)); + projPixel->origColor.uint = projPixel->newColor.uint = *projPixel->pixel.uint_pt; + } + + /* screenspace unclamped, we could keep its z and w values but don't need them at the moment */ + if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { + copy_v3_v3(projPixel->worldCoSS, world_spaceCo); + } + + copy_v2_v2(projPixel->projCoSS, pixelScreenCo); + + projPixel->x_px = x_px; + projPixel->y_px = y_px; + + projPixel->mask = (unsigned short)(mask * 65535); + projPixel->mask_max = 0; + + /* which bounding box cell are we in?, needed for undo */ + projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + + ((int)(((float)y_px / (float)ibuf->y) * PROJ_BOUNDBOX_DIV)) * PROJ_BOUNDBOX_DIV; + + /* done with view3d_project_float inline */ + if (ps->tool == PAINT_TOOL_CLONE) { + if (ps->dm_mtface_clone) { + ImBuf *ibuf_other; + Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index); + const MTFace *tf_other = ps->dm_mtface_clone + face_index; + + if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { + /* BKE_image_acquire_ibuf - TODO - this may be slow */ + + if (ibuf->rect_float) { + if (ibuf_other->rect_float) { /* from float to float */ + project_face_pixel(tf_other, ibuf_other, w, side, NULL, ((ProjPixelClone *)projPixel)->clonepx.f); + } + else { /* from char to float */ + unsigned char rgba_ub[4]; + float rgba[4]; + project_face_pixel(tf_other, ibuf_other, w, side, rgba_ub, NULL); + srgb_to_linearrgb_uchar4(rgba, rgba_ub); + straight_to_premul_v4_v4(((ProjPixelClone *)projPixel)->clonepx.f, rgba); + } + } + else { + if (ibuf_other->rect_float) { /* float to char */ + float rgba[4]; + project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba); + premul_to_straight_v4(rgba); + linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba); + } + else { /* char to char */ + project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL); + } + } + + BKE_image_release_ibuf(other_tpage, ibuf_other, NULL); + } + else { + if (ibuf->rect_float) { + ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; + } + else { + ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; + } + } + + } + else { + float co[2]; + sub_v2_v2v2(co, projPixel->projCoSS, (float *)ps->cloneOffset); + + /* no need to initialize the bucket, we're only checking buckets faces and for this + * the faces are already initialized in project_paint_delayed_face_init(...) */ + if (ibuf->rect_float) { + if (!project_paint_PickColor(ps, co, ((ProjPixelClone *)projPixel)->clonepx.f, NULL, 1)) { + ((ProjPixelClone *)projPixel)->clonepx.f[3] = 0; /* zero alpha - ignore */ + } + } + else { + if (!project_paint_PickColor(ps, co, NULL, ((ProjPixelClone *)projPixel)->clonepx.ch, 1)) { + ((ProjPixelClone *)projPixel)->clonepx.ch[3] = 0; /* zero alpha - ignore */ + } + } + } + } + +#ifdef PROJ_DEBUG_PAINT + if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; + else projPixel->pixel.ch_pt[0] = 0; +#endif + projPixel->image_index = image_index; + + return projPixel; +} + +static int line_clip_rect2f( + rctf *rect, + const float l1[2], const float l2[2], + float l1_clip[2], float l2_clip[2]) +{ + /* first account for horizontal, then vertical lines */ + /* horiz */ + if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { + /* is the line out of range on its Y axis? */ + if (l1[1] < rect->ymin || l1[1] > rect->ymax) { + return 0; + } + /* line is out of range on its X axis */ + if ((l1[0] < rect->xmin && l2[0] < rect->xmin) || (l1[0] > rect->xmax && l2[0] > rect->xmax)) { + return 0; + } + + + if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ + if (BLI_rctf_isect_pt_v(rect, l1)) { + copy_v2_v2(l1_clip, l1); + copy_v2_v2(l2_clip, l2); + return 1; + } + else { + return 0; + } + } + + copy_v2_v2(l1_clip, l1); + copy_v2_v2(l2_clip, l2); + CLAMP(l1_clip[0], rect->xmin, rect->xmax); + CLAMP(l2_clip[0], rect->xmin, rect->xmax); + return 1; + } + else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { + /* is the line out of range on its X axis? */ + if (l1[0] < rect->xmin || l1[0] > rect->xmax) { + return 0; + } + + /* line is out of range on its Y axis */ + if ((l1[1] < rect->ymin && l2[1] < rect->ymin) || (l1[1] > rect->ymax && l2[1] > rect->ymax)) { + return 0; + } + + if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ + if (BLI_rctf_isect_pt_v(rect, l1)) { + copy_v2_v2(l1_clip, l1); + copy_v2_v2(l2_clip, l2); + return 1; + } + else { + return 0; + } + } + + copy_v2_v2(l1_clip, l1); + copy_v2_v2(l2_clip, l2); + CLAMP(l1_clip[1], rect->ymin, rect->ymax); + CLAMP(l2_clip[1], rect->ymin, rect->ymax); + return 1; + } + else { + float isect; + short ok1 = 0; + short ok2 = 0; + + /* Done with vertical lines */ + + /* are either of the points inside the rectangle ? */ + if (BLI_rctf_isect_pt_v(rect, l1)) { + copy_v2_v2(l1_clip, l1); + ok1 = 1; + } + + if (BLI_rctf_isect_pt_v(rect, l2)) { + copy_v2_v2(l2_clip, l2); + ok2 = 1; + } + + /* line inside rect */ + if (ok1 && ok2) return 1; + + /* top/bottom */ + if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { + if (l1[1] < l2[1]) { /* line 1 is outside */ + l1_clip[0] = isect; + l1_clip[1] = rect->ymin; + ok1 = 1; + } + else { + l2_clip[0] = isect; + l2_clip[1] = rect->ymin; + ok2 = 2; + } + } + + if (ok1 && ok2) return 1; + + if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) { + if (l1[1] > l2[1]) { /* line 1 is outside */ + l1_clip[0] = isect; + l1_clip[1] = rect->ymax; + ok1 = 1; + } + else { + l2_clip[0] = isect; + l2_clip[1] = rect->ymax; + ok2 = 2; + } + } + + if (ok1 && ok2) return 1; + + /* left/right */ + if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { + if (l1[0] < l2[0]) { /* line 1 is outside */ + l1_clip[0] = rect->xmin; + l1_clip[1] = isect; + ok1 = 1; + } + else { + l2_clip[0] = rect->xmin; + l2_clip[1] = isect; + ok2 = 2; + } + } + + if (ok1 && ok2) return 1; + + if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) { + if (l1[0] > l2[0]) { /* line 1 is outside */ + l1_clip[0] = rect->xmax; + l1_clip[1] = isect; + ok1 = 1; + } + else { + l2_clip[0] = rect->xmax; + l2_clip[1] = isect; + ok2 = 2; + } + } + + if (ok1 && ok2) { + return 1; + } + else { + return 0; + } + } +} + + + +/* scale the quad & tri about its center + * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the + * edge of the face but slightly inside it occlusion tests don't return hits on adjacent faces */ +#ifndef PROJ_DEBUG_NOSEAMBLEED +static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset) +{ + float cent[3]; + cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0] + origCos[3][0]) / 4.0f; + cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1] + origCos[3][1]) / 4.0f; + cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2] + origCos[3][2]) / 4.0f; + + sub_v3_v3v3(insetCos[0], origCos[0], cent); + sub_v3_v3v3(insetCos[1], origCos[1], cent); + sub_v3_v3v3(insetCos[2], origCos[2], cent); + sub_v3_v3v3(insetCos[3], origCos[3], cent); + + mul_v3_fl(insetCos[0], inset); + mul_v3_fl(insetCos[1], inset); + mul_v3_fl(insetCos[2], inset); + mul_v3_fl(insetCos[3], inset); + + add_v3_v3(insetCos[0], cent); + add_v3_v3(insetCos[1], cent); + add_v3_v3(insetCos[2], cent); + add_v3_v3(insetCos[3], cent); +} + + +static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset) +{ + float cent[3]; + cent[0] = (origCos[0][0] + origCos[1][0] + origCos[2][0]) / 3.0f; + cent[1] = (origCos[0][1] + origCos[1][1] + origCos[2][1]) / 3.0f; + cent[2] = (origCos[0][2] + origCos[1][2] + origCos[2][2]) / 3.0f; + + sub_v3_v3v3(insetCos[0], origCos[0], cent); + sub_v3_v3v3(insetCos[1], origCos[1], cent); + sub_v3_v3v3(insetCos[2], origCos[2], cent); + + mul_v3_fl(insetCos[0], inset); + mul_v3_fl(insetCos[1], inset); + mul_v3_fl(insetCos[2], inset); + + add_v3_v3(insetCos[0], cent); + add_v3_v3(insetCos[1], cent); + add_v3_v3(insetCos[2], cent); +} +#endif //PROJ_DEBUG_NOSEAMBLEED + +static float len_squared_v2v2_alt(const float *v1, const float v2_1, const float v2_2) +{ + float x, y; + + x = v1[0] - v2_1; + y = v1[1] - v2_2; + return x * x + y * y; +} + +/* note, use a squared value so we can use len_squared_v2v2 + * be sure that you have done a bounds check first or this may fail */ +/* only give bucket_bounds as an arg because we need it elsewhere */ +static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds) +{ + + /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect + * so we only need to test if the center is inside the vertical or horizontal bounds on either axis, + * this is even less work then an intersection test + */ +#if 0 + if (BLI_rctf_isect_pt_v(bucket_bounds, cent)) + return 1; +#endif + + if ((bucket_bounds->xmin <= cent[0] && bucket_bounds->xmax >= cent[0]) || + (bucket_bounds->ymin <= cent[1] && bucket_bounds->ymax >= cent[1])) + { + return 1; + } + + /* out of bounds left */ + if (cent[0] < bucket_bounds->xmin) { + /* lower left out of radius test */ + if (cent[1] < bucket_bounds->ymin) { + return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymin) < radius_squared) ? 1 : 0; + } + /* top left test */ + else if (cent[1] > bucket_bounds->ymax) { + return (len_squared_v2v2_alt(cent, bucket_bounds->xmin, bucket_bounds->ymax) < radius_squared) ? 1 : 0; + } + } + else if (cent[0] > bucket_bounds->xmax) { + /* lower right out of radius test */ + if (cent[1] < bucket_bounds->ymin) { + return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymin) < radius_squared) ? 1 : 0; + } + /* top right test */ + else if (cent[1] > bucket_bounds->ymax) { + return (len_squared_v2v2_alt(cent, bucket_bounds->xmax, bucket_bounds->ymax) < radius_squared) ? 1 : 0; + } + } + + return 0; +} + + + +/* Note for rect_to_uvspace_ortho() and rect_to_uvspace_persp() + * in ortho view this function gives good results when bucket_bounds are outside the triangle + * however in some cases, perspective view will mess up with faces that have minimal screenspace area + * (viewed from the side) + * + * for this reason its not reliable in this case so we'll use the Simple Barycentric' + * funcs that only account for points inside the triangle. + * however switching back to this for ortho is always an option */ + +static void rect_to_uvspace_ortho( + rctf *bucket_bounds, + float *v1coSS, float *v2coSS, float *v3coSS, + float *uv1co, float *uv2co, float *uv3co, + float bucket_bounds_uv[4][2], + const int flip) +{ + float uv[2]; + float w[3]; + + /* get the UV space bounding box */ + uv[0] = bucket_bounds->xmax; + uv[1] = bucket_bounds->ymin; + barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w); + + //uv[0] = bucket_bounds->xmax; // set above + uv[1] = bucket_bounds->ymax; + barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w); + + uv[0] = bucket_bounds->xmin; + //uv[1] = bucket_bounds->ymax; // set above + barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w); + + //uv[0] = bucket_bounds->xmin; // set above + uv[1] = bucket_bounds->ymin; + barycentric_weights_v2(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w); +} + +/* same as above but use barycentric_weights_v2_persp */ +static void rect_to_uvspace_persp( + rctf *bucket_bounds, + float *v1coSS, float *v2coSS, float *v3coSS, + float *uv1co, float *uv2co, float *uv3co, + float bucket_bounds_uv[4][2], + const int flip + ) +{ + float uv[2]; + float w[3]; + + /* get the UV space bounding box */ + uv[0] = bucket_bounds->xmax; + uv[1] = bucket_bounds->ymin; + barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 3 : 0], uv1co, uv2co, uv3co, w); + + //uv[0] = bucket_bounds->xmax; // set above + uv[1] = bucket_bounds->ymax; + barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 2 : 1], uv1co, uv2co, uv3co, w); + + uv[0] = bucket_bounds->xmin; + //uv[1] = bucket_bounds->ymax; // set above + barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 1 : 2], uv1co, uv2co, uv3co, w); + + //uv[0] = bucket_bounds->xmin; // set above + uv[1] = bucket_bounds->ymin; + barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, uv, w); + interp_v2_v2v2v2(bucket_bounds_uv[flip ? 0 : 3], uv1co, uv2co, uv3co, w); +} + +/* This works as we need it to but we can save a few steps and not use it */ + +#if 0 +static float angle_2d_clockwise(const float p1[2], const float p2[2], const float p3[2]) +{ + float v1[2], v2[2]; + + v1[0] = p1[0] - p2[0]; v1[1] = p1[1] - p2[1]; + v2[0] = p3[0] - p2[0]; v2[1] = p3[1] - p2[1]; + + return -atan2(v1[0] * v2[1] - v1[1] * v2[0], v1[0] * v2[0] + v1[1] * v2[1]); +} +#endif + +#define ISECT_1 (1) +#define ISECT_2 (1 << 1) +#define ISECT_3 (1 << 2) +#define ISECT_4 (1 << 3) +#define ISECT_ALL3 ((1 << 3) - 1) +#define ISECT_ALL4 ((1 << 4) - 1) + +/* limit must be a fraction over 1.0f */ +static int IsectPT2Df_limit(float pt[2], float v1[2], float v2[2], float v3[2], float limit) +{ + return ((area_tri_v2(pt, v1, v2) + area_tri_v2(pt, v2, v3) + area_tri_v2(pt, v3, v1)) / (area_tri_v2(v1, v2, v3))) < limit; +} + +/* Clip the face by a bucket and set the uv-space bucket_bounds_uv + * so we have the clipped UV's to do pixel intersection tests with + * */ +static int float_z_sort_flip(const void *p1, const void *p2) +{ + return (((float *)p1)[2] < ((float *)p2)[2] ? 1 : -1); +} + +static int float_z_sort(const void *p1, const void *p2) +{ + return (((float *)p1)[2] < ((float *)p2)[2] ? -1 : 1); +} + +static void project_bucket_clip_face( + const int is_ortho, + rctf *bucket_bounds, + float *v1coSS, float *v2coSS, float *v3coSS, + float *uv1co, float *uv2co, float *uv3co, + float bucket_bounds_uv[8][2], + int *tot) +{ + int inside_bucket_flag = 0; + int inside_face_flag = 0; + const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); + + float bucket_bounds_ss[4][2]; + + /* get the UV space bounding box */ + inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v1coSS); + inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v2coSS) << 1; + inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2; + + if (inside_bucket_flag == ISECT_ALL3) { + /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */ + if (flip) { /* facing the back? */ + copy_v2_v2(bucket_bounds_uv[0], uv3co); + copy_v2_v2(bucket_bounds_uv[1], uv2co); + copy_v2_v2(bucket_bounds_uv[2], uv1co); + } + else { + copy_v2_v2(bucket_bounds_uv[0], uv1co); + copy_v2_v2(bucket_bounds_uv[1], uv2co); + copy_v2_v2(bucket_bounds_uv[2], uv3co); + } + + *tot = 3; + return; + } + + /* get the UV space bounding box */ + /* use IsectPT2Df_limit here so we catch points are are touching the tri edge (or a small fraction over) */ + bucket_bounds_ss[0][0] = bucket_bounds->xmax; + bucket_bounds_ss[0][1] = bucket_bounds->ymin; + inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[0], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_1 : 0); + + bucket_bounds_ss[1][0] = bucket_bounds->xmax; + bucket_bounds_ss[1][1] = bucket_bounds->ymax; + inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[1], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_2 : 0); + + bucket_bounds_ss[2][0] = bucket_bounds->xmin; + bucket_bounds_ss[2][1] = bucket_bounds->ymax; + inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[2], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_3 : 0); + + bucket_bounds_ss[3][0] = bucket_bounds->xmin; + bucket_bounds_ss[3][1] = bucket_bounds->ymin; + inside_face_flag |= (IsectPT2Df_limit(bucket_bounds_ss[3], v1coSS, v2coSS, v3coSS, 1 + PROJ_GEOM_TOLERANCE) ? ISECT_4 : 0); + + if (inside_face_flag == ISECT_ALL4) { + /* bucket is totally inside the screenspace face, we can safely use weights */ + + if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); + else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv, flip); + + *tot = 4; + return; + } + else { + /* The Complicated Case! + * + * The 2 cases above are where the face is inside the bucket or the bucket is inside the face. + * + * we need to make a convex polyline from the intersection between the screenspace face + * and the bucket bounds. + * + * There are a number of ways this could be done, currently it just collects all intersecting verts, + * and line intersections, then sorts them clockwise, this is a lot easier then evaluating the geometry to + * do a correct clipping on both shapes. */ + + + /* add a bunch of points, we know must make up the convex hull which is the clipped rect and triangle */ + + + + /* Maximum possible 6 intersections when using a rectangle and triangle */ + float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */ + float v1_clipSS[2], v2_clipSS[2]; + float w[3]; + + /* calc center */ + float cent[2] = {0.0f, 0.0f}; + /*float up[2] = {0.0f, 1.0f};*/ + int i; + short doubles; + + (*tot) = 0; + + if (inside_face_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[0]); (*tot)++; } + if (inside_face_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[1]); (*tot)++; } + if (inside_face_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[2]); (*tot)++; } + if (inside_face_flag & ISECT_4) { copy_v2_v2(isectVCosSS[*tot], bucket_bounds_ss[3]); (*tot)++; } + + if (inside_bucket_flag & ISECT_1) { copy_v2_v2(isectVCosSS[*tot], v1coSS); (*tot)++; } + if (inside_bucket_flag & ISECT_2) { copy_v2_v2(isectVCosSS[*tot], v2coSS); (*tot)++; } + if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; } + + if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) { + if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) { + if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } + if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } + } + } + + if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) { + if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) { + if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } + if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } + } + } + + if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) { + if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) { + if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; } + if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; } + } + } + + + if ((*tot) < 3) { /* no intersections to speak of */ + *tot = 0; + return; + } + + /* now we have all points we need, collect their angles and sort them clockwise */ + + for (i = 0; i < (*tot); i++) { + cent[0] += isectVCosSS[i][0]; + cent[1] += isectVCosSS[i][1]; + } + cent[0] = cent[0] / (float)(*tot); + cent[1] = cent[1] / (float)(*tot); + + + + /* Collect angles for every point around the center point */ + + +#if 0 /* uses a few more cycles then the above loop */ + for (i = 0; i < (*tot); i++) { + isectVCosSS[i][2] = angle_2d_clockwise(up, cent, isectVCosSS[i]); + } +#endif + + v1_clipSS[0] = cent[0]; /* Abuse this var for the loop below */ + v1_clipSS[1] = cent[1] + 1.0f; + + for (i = 0; i < (*tot); i++) { + v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; + v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; + isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]); + } + + if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip); + else qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort); + + /* remove doubles */ + /* first/last check */ + if (fabsf(isectVCosSS[0][0] - isectVCosSS[(*tot) - 1][0]) < PROJ_GEOM_TOLERANCE && + fabsf(isectVCosSS[0][1] - isectVCosSS[(*tot) - 1][1]) < PROJ_GEOM_TOLERANCE) + { + (*tot)--; + } + + /* its possible there is only a few left after remove doubles */ + if ((*tot) < 3) { + // printf("removed too many doubles A\n"); + *tot = 0; + return; + } + + doubles = TRUE; + while (doubles == TRUE) { + doubles = FALSE; + for (i = 1; i < (*tot); i++) { + if (fabsf(isectVCosSS[i - 1][0] - isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE && + fabsf(isectVCosSS[i - 1][1] - isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE) + { + int j; + for (j = i + 1; j < (*tot); j++) { + isectVCosSS[j - 1][0] = isectVCosSS[j][0]; + isectVCosSS[j - 1][1] = isectVCosSS[j][1]; + } + doubles = TRUE; /* keep looking for more doubles */ + (*tot)--; + } + } + } + + /* its possible there is only a few left after remove doubles */ + if ((*tot) < 3) { + // printf("removed too many doubles B\n"); + *tot = 0; + return; + } + + + if (is_ortho) { + for (i = 0; i < (*tot); i++) { + barycentric_weights_v2(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); + interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); + } + } + else { + for (i = 0; i < (*tot); i++) { + barycentric_weights_v2_persp(v1coSS, v2coSS, v3coSS, isectVCosSS[i], w); + interp_v2_v2v2v2(bucket_bounds_uv[i], uv1co, uv2co, uv3co, w); + } + } + } + +#ifdef PROJ_DEBUG_PRINT_CLIP + /* include this at the bottom of the above function to debug the output */ + + { + /* If there are ever any problems, */ + float test_uv[4][2]; + int i; + if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); + else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); + printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]); + + printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]); + + printf("["); + for (i = 0; i < (*tot); i++) { + printf("(%f, %f),", bucket_bounds_uv[i][0], bucket_bounds_uv[i][1]); + } + printf("]),\\\n"); + } +#endif +} + +/* + * # This script creates faces in a blender scene from printed data above. + * + * project_ls = [ + * ...(output from above block)... + * ] + * + * from Blender import Scene, Mesh, Window, sys, Mathutils + * + * import bpy + * + * V = Mathutils.Vector + * + * def main(): + * sce = bpy.data.scenes.active + * + * for item in project_ls: + * bb = item[0] + * uv = item[1] + * poly = item[2] + * + * me = bpy.data.meshes.new() + * ob = sce.objects.new(me) + * + * me.verts.extend([V(bb[0]).xyz, V(bb[1]).xyz, V(bb[2]).xyz, V(bb[3]).xyz]) + * me.faces.extend([(0,1,2,3),]) + * me.verts.extend([V(uv[0]).xyz, V(uv[1]).xyz, V(uv[2]).xyz]) + * me.faces.extend([(4,5,6),]) + * + * vs = [V(p).xyz for p in poly] + * print len(vs) + * l = len(me.verts) + * me.verts.extend(vs) + * + * i = l + * while i < len(me.verts): + * ii = i + 1 + * if ii == len(me.verts): + * ii = l + * me.edges.extend([i, ii]) + * i += 1 + * + * if __name__ == '__main__': + * main() + */ + + +#undef ISECT_1 +#undef ISECT_2 +#undef ISECT_3 +#undef ISECT_4 +#undef ISECT_ALL3 +#undef ISECT_ALL4 + + +/* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise + * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */ +static int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) +{ + int i; + if (line_point_side_v2(uv[tot - 1], uv[0], pt) < 0.0f) + return 0; + + for (i = 1; i < tot; i++) { + if (line_point_side_v2(uv[i - 1], uv[i], pt) < 0.0f) + return 0; + + } + + return 1; +} +static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot) +{ + int i; + int side = (line_point_side_v2(uv[tot - 1], uv[0], pt) > 0.0f); + + for (i = 1; i < tot; i++) { + if ((line_point_side_v2(uv[i - 1], uv[i], pt) > 0.0f) != side) + return 0; + + } + + return 1; +} + +/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket. + * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ +static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v) +{ + /* Projection vars, to get the 3D locations into screen space */ + MemArena *arena = ps->arena_mt[thread_index]; + LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; + LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; + + const MFace *mf = ps->dm_mface + face_index; + const MTFace *tf = ps->dm_mtface + face_index; + + /* UV/pixel seeking data */ + int x; /* Image X-Pixel */ + int y; /* Image Y-Pixel */ + float mask; + float uv[2]; /* Image floating point UV - same as x, y but from 0.0-1.0 */ + + int side; + float *v1coSS, *v2coSS, *v3coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */ + + float *vCo[4]; /* vertex screenspace coords */ + + float w[3], wco[3]; + + float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */ + float pixelScreenCo[4]; + bool do_3d_mapping = ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D; + + rcti bounds_px; /* ispace bounds */ + /* vars for getting uvspace bounds */ + + float tf_uv_pxoffset[4][2]; /* bucket bounds in UV space so we can init pixels only for this face, */ + float xhalfpx, yhalfpx; + const float ibuf_xf = (float)ibuf->x, ibuf_yf = (float)ibuf->y; + + int has_x_isect = 0, has_isect = 0; /* for early loop exit */ + + int i1, i2, i3; + + float uv_clip[8][2]; + int uv_clip_tot; + const short is_ortho = ps->is_ortho; + const short do_backfacecull = ps->do_backfacecull; + const short do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; + + vCo[0] = ps->dm_mvert[mf->v1].co; + vCo[1] = ps->dm_mvert[mf->v2].co; + vCo[2] = ps->dm_mvert[mf->v3].co; + + + /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel + * this is done so we can avoid offsetting all the pixels by 0.5 which causes + * problems when wrapping negative coords */ + xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 3.0f)) / ibuf_xf; + yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE / 4.0f)) / ibuf_yf; + + /* Note about (PROJ_GEOM_TOLERANCE/x) above... + * Needed to add this offset since UV coords are often quads aligned to pixels. + * In this case pixels can be exactly between 2 triangles causing nasty + * artifacts. + * + * This workaround can be removed and painting will still work on most cases + * but since the first thing most people try is painting onto a quad- better make it work. + */ + + + + tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx; + tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx; + + tf_uv_pxoffset[1][0] = tf->uv[1][0] - xhalfpx; + tf_uv_pxoffset[1][1] = tf->uv[1][1] - yhalfpx; + + tf_uv_pxoffset[2][0] = tf->uv[2][0] - xhalfpx; + tf_uv_pxoffset[2][1] = tf->uv[2][1] - yhalfpx; + + if (mf->v4) { + vCo[3] = ps->dm_mvert[mf->v4].co; + + tf_uv_pxoffset[3][0] = tf->uv[3][0] - xhalfpx; + tf_uv_pxoffset[3][1] = tf->uv[3][1] - yhalfpx; + side = 1; + } + else { + side = 0; + } + + do { + if (side == 1) { + i1 = 0; i2 = 2; i3 = 3; + } + else { + i1 = 0; i2 = 1; i3 = 2; + } + + uv1co = tf_uv_pxoffset[i1]; // was tf->uv[i1]; + uv2co = tf_uv_pxoffset[i2]; // was tf->uv[i2]; + uv3co = tf_uv_pxoffset[i3]; // was tf->uv[i3]; + + v1coSS = ps->screenCoords[(*(&mf->v1 + i1))]; + v2coSS = ps->screenCoords[(*(&mf->v1 + i2))]; + v3coSS = ps->screenCoords[(*(&mf->v1 + i3))]; + + /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/ + project_bucket_clip_face( + is_ortho, bucket_bounds, + v1coSS, v2coSS, v3coSS, + uv1co, uv2co, uv3co, + uv_clip, &uv_clip_tot + ); + + /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */ +#if 0 + if (uv_clip_tot > 6) { + printf("this should never happen! %d\n", uv_clip_tot); + } +#endif + + if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) { + + if (clamp_u) { + CLAMP(bounds_px.xmin, 0, ibuf->x); + CLAMP(bounds_px.xmax, 0, ibuf->x); + } + + if (clamp_v) { + CLAMP(bounds_px.ymin, 0, ibuf->y); + CLAMP(bounds_px.ymax, 0, ibuf->y); + } + + /* clip face and */ + + has_isect = 0; + for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { + //uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; + uv[1] = (float)y / ibuf_yf; /* use pixel offset UV coords instead */ + + has_x_isect = 0; + for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { + //uv[0] = (((float)x) + 0.5f) / ibuf->x; + uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */ + + /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work, + * could check the poly direction but better to do this */ + if ((do_backfacecull == TRUE && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) || + (do_backfacecull == FALSE && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) + { + + has_x_isect = has_isect = 1; + + if (is_ortho) screen_px_from_ortho(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); + else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); + + /* a pity we need to get the worldspace pixel location here */ + if (do_clip || do_3d_mapping) { + interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w); + if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { + continue; /* Watch out that no code below this needs to run */ + } + } + + /* Is this UV visible from the view? - raytrace */ + /* project_paint_PickFace is less complex, use for testing */ + //if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == face_index) { + if ((ps->do_occlude == FALSE) || + !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) + { + mask = project_paint_uvpixel_mask(ps, face_index, side, w); + + if (mask > 0.0f) { + BLI_linklist_prepend_arena( + bucketPixelNodes, + project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, + image_index, pixelScreenCo, wco, side, w), + arena + ); + } + } + + } +//#if 0 + else if (has_x_isect) { + /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ + break; + } +//#endif + } + + +#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ + /* no intersection for this entire row, after some intersection above means we can quit now */ + if (has_x_isect == 0 && has_isect) { + break; + } +#endif + } + } + } while (side--); + + + +#ifndef PROJ_DEBUG_NOSEAMBLEED + if (ps->seam_bleed_px > 0.0f) { + int face_seam_flag; + + if (ps->thread_tot > 1) + BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + + face_seam_flag = ps->faceSeamFlags[face_index]; + + /* are any of our edges un-initialized? */ + if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_NOSEAM1)) == 0 || + (face_seam_flag & (PROJ_FACE_SEAM2 | PROJ_FACE_NOSEAM2)) == 0 || + (face_seam_flag & (PROJ_FACE_SEAM3 | PROJ_FACE_NOSEAM3)) == 0 || + (face_seam_flag & (PROJ_FACE_SEAM4 | PROJ_FACE_NOSEAM4)) == 0) + { + project_face_seams_init(ps, face_index, mf->v4); + face_seam_flag = ps->faceSeamFlags[face_index]; + //printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4); + } + + if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) { + + if (ps->thread_tot > 1) + BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + + } + else { + /* we have a seam - deal with it! */ + + /* Now create new UV's for the seam face */ + float (*outset_uv)[2] = ps->faceSeamUVs[face_index]; + float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */ + + float *vCoSS[4]; /* vertex screenspace coords */ + + float bucket_clip_edges[2][2]; /* store the screenspace coords of the face, clipped by the bucket's screen aligned rectangle */ + float edge_verts_inset_clip[2][3]; + int fidx1, fidx2; /* face edge pairs - loop throuh these ((0,1), (1,2), (2,3), (3,0)) or ((0,1), (1,2), (2,0)) for a tri */ + + float seam_subsection[4][2]; + float fac1, fac2, ftot; + + + if (outset_uv[0][0] == FLT_MAX) /* first time initialize */ + uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4); + + /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ + if (ps->thread_tot > 1) + BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ + + vCoSS[0] = ps->screenCoords[mf->v1]; + vCoSS[1] = ps->screenCoords[mf->v2]; + vCoSS[2] = ps->screenCoords[mf->v3]; + if (mf->v4) + vCoSS[3] = ps->screenCoords[mf->v4]; + + /* PROJ_FACE_SCALE_SEAM must be slightly less then 1.0f */ + if (is_ortho) { + if (mf->v4) scale_quad(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); + else scale_tri(insetCos, vCoSS, PROJ_FACE_SCALE_SEAM); + } + else { + if (mf->v4) scale_quad(insetCos, vCo, PROJ_FACE_SCALE_SEAM); + else scale_tri(insetCos, vCo, PROJ_FACE_SCALE_SEAM); + } + + side = 0; /* for triangles this wont need to change */ + + for (fidx1 = 0; fidx1 < (mf->v4 ? 4 : 3); fidx1++) { + if (mf->v4) fidx2 = (fidx1 == 3) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */ + else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */ + + if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */ + line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])) + { + + ftot = len_v2v2(vCoSS[fidx1], vCoSS[fidx2]); /* screenspace edge length */ + + if (ftot > 0.0f) { /* avoid div by zero */ + if (mf->v4) { + if (fidx1 == 2 || fidx2 == 2) side = 1; + else side = 0; + } + + fac1 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[0]) / ftot; + fac2 = len_v2v2(vCoSS[fidx1], bucket_clip_edges[1]) / ftot; + + interp_v2_v2v2(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1); + interp_v2_v2v2(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2); + + interp_v2_v2v2(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2); + interp_v2_v2v2(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1); + + /* if the bucket_clip_edges values Z values was kept we could avoid this + * Inset needs to be added so occlusion tests wont hit adjacent faces */ + interp_v3_v3v3(edge_verts_inset_clip[0], insetCos[fidx1], insetCos[fidx2], fac1); + interp_v3_v3v3(edge_verts_inset_clip[1], insetCos[fidx1], insetCos[fidx2], fac2); + + + if (pixel_bounds_uv(seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3], &bounds_px, ibuf->x, ibuf->y, 1)) { + /* bounds between the seam rect and the uvspace bucket pixels */ + + has_isect = 0; + for (y = bounds_px.ymin; y < bounds_px.ymax; y++) { + // uv[1] = (((float)y) + 0.5f) / (float)ibuf->y; + uv[1] = (float)y / ibuf_yf; /* use offset uvs instead */ + + has_x_isect = 0; + for (x = bounds_px.xmin; x < bounds_px.xmax; x++) { + //uv[0] = (((float)x) + 0.5f) / (float)ibuf->x; + uv[0] = (float)x / ibuf_xf; /* use offset uvs instead */ + + /* test we're inside uvspace bucket and triangle bounds */ + if (isect_point_quad_v2(uv, seam_subsection[0], seam_subsection[1], seam_subsection[2], seam_subsection[3])) { + float fac; + + /* We need to find the closest point along the face edge, + * getting the screen_px_from_*** wont work because our actual location + * is not relevant, since we are outside the face, Use VecLerpf to find + * our location on the side of the face's UV */ +#if 0 + if (is_ortho) screen_px_from_ortho(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); + else screen_px_from_persp(ps, uv, v1co, v2co, v3co, uv1co, uv2co, uv3co, pixelScreenCo); +#endif + + /* Since this is a seam we need to work out where on the line this pixel is */ + //fac = line_point_factor_v2(uv, uv_seam_quad[0], uv_seam_quad[1]); + + fac = line_point_factor_v2(uv, seam_subsection[0], seam_subsection[1]); + if (fac < 0.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[0]); } + else if (fac > 1.0f) { copy_v3_v3(pixelScreenCo, edge_verts_inset_clip[1]); } + else { interp_v3_v3v3(pixelScreenCo, edge_verts_inset_clip[0], edge_verts_inset_clip[1], fac); } + + if (!is_ortho) { + pixelScreenCo[3] = 1.0f; + mul_m4_v4((float(*)[4])ps->projectMat, pixelScreenCo); /* cast because of const */ + pixelScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * pixelScreenCo[0] / pixelScreenCo[3]; + pixelScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * pixelScreenCo[1] / pixelScreenCo[3]; + pixelScreenCo[2] = pixelScreenCo[2] / pixelScreenCo[3]; /* Use the depth for bucket point occlusion */ + } + + if ((ps->do_occlude == FALSE) || + !project_bucket_point_occluded(ps, bucketFaceNodes, face_index, pixelScreenCo)) + { + /* Only bother calculating the weights if we intersect */ + if (ps->do_mask_normal || ps->dm_mtface_clone) { +#if 1 + /* get the UV on the line since we want to copy the pixels from there for bleeding */ + float uv_close[2]; + float uv_fac = closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]); + if (uv_fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]); + else if (uv_fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]); + + if (side) { + barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w); + } + else { + barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w); + } +#else /* this is buggy with quads, don't use for now */ + + /* Cheat, we know where we are along the edge so work out the weights from that */ + uv_fac = fac1 + (uv_fac * (fac2 - fac1)); + + w[0] = w[1] = w[2] = 0.0; + if (side) { + w[fidx1 ? fidx1 - 1 : 0] = 1.0f - uv_fac; + w[fidx2 ? fidx2 - 1 : 0] = uv_fac; + } + else { + w[fidx1] = 1.0f - uv_fac; + w[fidx2] = uv_fac; + } +#endif + } + + /* a pity we need to get the worldspace pixel location here */ + if (do_clip || do_3d_mapping) { + if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w); + else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w); + + if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) { + continue; /* Watch out that no code below this needs to run */ + } + } + + mask = project_paint_uvpixel_mask(ps, face_index, side, w); + + if (mask > 0.0f) { + BLI_linklist_prepend_arena( + bucketPixelNodes, + project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w), + arena + ); + } + + } + } + else if (has_x_isect) { + /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ + break; + } + } + +#if 0 /* TODO - investigate why this dosnt work sometimes! it should! */ + /* no intersection for this entire row, after some intersection above means we can quit now */ + if (has_x_isect == 0 && has_isect) { + break; + } +#endif + } + } + } + } + } + } + } +#endif // PROJ_DEBUG_NOSEAMBLEED +} + + +/* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */ +static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2]) +{ + /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */ + /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */ + bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */ + bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f); + + bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f); + bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f); + + /* in case the rect is outside the mesh 2d bounds */ + CLAMP(bucketMin[0], 0, ps->buckets_x); + CLAMP(bucketMin[1], 0, ps->buckets_y); + + CLAMP(bucketMax[0], 0, ps->buckets_x); + CLAMP(bucketMax[1], 0, ps->buckets_y); +} + +/* set bucket_bounds to a screen space-aligned floating point bound-box */ +static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, const int bucket_y, rctf *bucket_bounds) +{ + bucket_bounds->xmin = ps->screenMin[0] + ((bucket_x) * (ps->screen_width / ps->buckets_x)); /* left */ + bucket_bounds->xmax = ps->screenMin[0] + ((bucket_x + 1) * (ps->screen_width / ps->buckets_x)); /* right */ + + bucket_bounds->ymin = ps->screenMin[1] + ((bucket_y) * (ps->screen_height / ps->buckets_y)); /* bottom */ + bucket_bounds->ymax = ps->screenMin[1] + ((bucket_y + 1) * (ps->screen_height / ps->buckets_y)); /* top */ +} + +/* Fill this bucket with pixels from the faces that intersect it. + * + * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */ +static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds) +{ + LinkNode *node; + int face_index, image_index = 0; + ImBuf *ibuf = NULL; + Image *tpage_last = NULL, *tpage; + Image *ima = NULL; + + if (ps->image_tot == 1) { + /* Simple loop, no context switching */ + ibuf = ps->projImages[0].ibuf; + ima = ps->projImages[0].ima; + + for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { + project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + } + } + else { + + /* More complicated loop, switch between images */ + for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { + face_index = GET_INT_FROM_POINTER(node->link); + + /* Image context switching */ + tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); + if (tpage_last != tpage) { + tpage_last = tpage; + + for (image_index = 0; image_index < ps->image_tot; image_index++) { + if (ps->projImages[image_index].ima == tpage_last) { + ibuf = ps->projImages[image_index].ibuf; + ima = ps->projImages[image_index].ima; + break; + } + } + } + /* context switching done */ + + project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + } + } + + ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; +} + + +/* We want to know if a bucket and a face overlap in screen-space + * + * Note, if this ever returns false positives its not that bad, since a face in the bounding area will have its pixels + * calculated when it might not be needed later, (at the moment at least) + * obviously it shouldn't have bugs though */ + +static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf) +{ + /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */ + rctf bucket_bounds; + float p1[2], p2[2], p3[2], p4[2]; + float *v, *v1, *v2, *v3, *v4 = NULL; + int fidx; + + project_bucket_bounds(ps, bucket_x, bucket_y, &bucket_bounds); + + /* Is one of the faces verts in the bucket bounds? */ + + fidx = mf->v4 ? 3 : 2; + do { + v = ps->screenCoords[(*(&mf->v1 + fidx))]; + if (BLI_rctf_isect_pt_v(&bucket_bounds, v)) { + return 1; + } + } while (fidx--); + + v1 = ps->screenCoords[mf->v1]; + v2 = ps->screenCoords[mf->v2]; + v3 = ps->screenCoords[mf->v3]; + if (mf->v4) { + v4 = ps->screenCoords[mf->v4]; + } + + p1[0] = bucket_bounds.xmin; p1[1] = bucket_bounds.ymin; + p2[0] = bucket_bounds.xmin; p2[1] = bucket_bounds.ymax; + p3[0] = bucket_bounds.xmax; p3[1] = bucket_bounds.ymax; + p4[0] = bucket_bounds.xmax; p4[1] = bucket_bounds.ymin; + + if (mf->v4) { + if (isect_point_quad_v2(p1, v1, v2, v3, v4) || + isect_point_quad_v2(p2, v1, v2, v3, v4) || + isect_point_quad_v2(p3, v1, v2, v3, v4) || + isect_point_quad_v2(p4, v1, v2, v3, v4) || + + /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ + (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3) || isect_line_line_v2(p1, p2, v3, v4)) || + (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3) || isect_line_line_v2(p2, p3, v3, v4)) || + (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3) || isect_line_line_v2(p3, p4, v3, v4)) || + (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3) || isect_line_line_v2(p4, p1, v3, v4))) + { + return 1; + } + } + else { + if (isect_point_tri_v2(p1, v1, v2, v3) || + isect_point_tri_v2(p2, v1, v2, v3) || + isect_point_tri_v2(p3, v1, v2, v3) || + isect_point_tri_v2(p4, v1, v2, v3) || + /* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */ + (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) || + (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) || + (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) || + (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3))) + { + return 1; + } + } + + return 0; +} + +/* Add faces to the bucket but don't initialize its pixels + * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */ +static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index) +{ + float min[2], max[2], *vCoSS; + int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */ + int fidx, bucket_x, bucket_y; + int has_x_isect = -1, has_isect = 0; /* for early loop exit */ + MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */ + + INIT_MINMAX2(min, max); + + fidx = mf->v4 ? 3 : 2; + do { + vCoSS = ps->screenCoords[*(&mf->v1 + fidx)]; + minmax_v2v2_v2(min, max, vCoSS); + } while (fidx--); + + project_paint_bucket_bounds(ps, min, max, bucketMin, bucketMax); + + for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) { + has_x_isect = 0; + for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) { + if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) { + int bucket_index = bucket_x + (bucket_y * ps->buckets_x); + BLI_linklist_prepend_arena( + &ps->bucketFaces[bucket_index], + SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */ + arena + ); + + has_x_isect = has_isect = 1; + } + else if (has_x_isect) { + /* assuming the face is not a bow-tie - we know we cant intersect again on the X */ + break; + } + } + + /* no intersection for this entire row, after some intersection above means we can quit now */ + if (has_x_isect == 0 && has_isect) { + break; + } + } + +#ifndef PROJ_DEBUG_NOSEAMBLEED + if (ps->seam_bleed_px > 0.0f) { + if (!mf->v4) { + ps->faceSeamFlags[face_index] |= PROJ_FACE_NOSEAM4; /* so this wont show up as an untagged edge */ + } + **ps->faceSeamUVs[face_index] = FLT_MAX; /* set as uninitialized */ + } +#endif +} + +/* run once per stroke before projection painting */ +static void project_paint_begin(ProjPaintState *ps) +{ + /* Viewport vars */ + float mat[3][3]; + + float no[3]; + + float *projScreenCo; /* Note, we could have 4D vectors are only needed for */ + float projMargin; + + /* Image Vars - keep track of images we have used */ + LinkNode *image_LinkList = NULL; + LinkNode *node; + + ProjPaintImage *projIma; + Image *tpage_last = NULL, *tpage; + + /* Face vars */ + MFace *mf; + MTFace *tf; + + int a, i; /* generic looping vars */ + int image_index = -1, face_index; + MVert *mv; + + MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ + + const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + + /* ---- end defines ---- */ + + if (ps->source == PROJ_SRC_VIEW) + ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ + + /* paint onto the derived mesh */ + + /* Workaround for subsurf selection, try the display mesh first */ + if (ps->source == PROJ_SRC_IMAGE_CAM) { + /* using render mesh, assume only camera was rendered from */ + ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); + ps->dm_release = TRUE; + } + else if (ps->ob->derivedFinal && CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE)) { + ps->dm = ps->ob->derivedFinal; + ps->dm_release = FALSE; + } + else { + ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); + ps->dm_release = TRUE; + } + + if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) { + + if (ps->dm_release) + ps->dm->release(ps->dm); + + ps->dm = NULL; + return; + } + + ps->dm_mvert = ps->dm->getVertArray(ps->dm); + ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); + ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); + + ps->dm_totvert = ps->dm->getNumVerts(ps->dm); + ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); + + /* use clone mtface? */ + + + /* Note, use the original mesh for getting the clone and mask layer index + * this avoids re-generating the derived mesh just to get the new index */ + if (ps->do_layer_clone) { + //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE); + int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); + if (layer_num != -1) + ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); + + if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) { + ps->do_layer_clone = FALSE; + ps->dm_mtface_clone = NULL; + printf("ACK!\n"); + } + } + + if (ps->do_layer_stencil) { + //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE); + int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->fdata, CD_MTFACE); + if (layer_num != -1) + ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); + + if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) { + ps->do_layer_stencil = FALSE; + ps->dm_mtface_stencil = NULL; + } + } + + /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ + if (ps->dm->type != DM_TYPE_CDDM) { + ps->dm_mvert = MEM_dupallocN(ps->dm_mvert); + ps->dm_mface = MEM_dupallocN(ps->dm_mface); + /* looks like these are ok for now.*/ +#if 0 + ps->dm_mtface = MEM_dupallocN(ps->dm_mtface); + ps->dm_mtface_clone = MEM_dupallocN(ps->dm_mtface_clone); + ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil); +#endif + } + + ps->viewDir[0] = 0.0f; + ps->viewDir[1] = 0.0f; + ps->viewDir[2] = 1.0f; + + { + float viewmat[4][4]; + float viewinv[4][4]; + + invert_m4_m4(ps->ob->imat, ps->ob->obmat); + + if (ps->source == PROJ_SRC_VIEW) { + /* normal drawing */ + ps->winx = ps->ar->winx; + ps->winy = ps->ar->winy; + + copy_m4_m4(viewmat, ps->rv3d->viewmat); + copy_m4_m4(viewinv, ps->rv3d->viewinv); + + ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat); + + ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); + } + else { + /* re-projection */ + float winmat[4][4]; + float vmat[4][4]; + + ps->winx = ps->reproject_ibuf->x; + ps->winy = ps->reproject_ibuf->y; + + if (ps->source == PROJ_SRC_IMAGE_VIEW) { + /* image stores camera data, tricky */ + IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0); + IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); + + float *array = (float *)IDP_Array(view_data); + + /* use image array, written when creating image */ + memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float); + memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float); + ps->clipsta = array[0]; + ps->clipend = array[1]; + ps->is_ortho = array[2] ? 1 : 0; + + invert_m4_m4(viewinv, viewmat); + } + else if (ps->source == PROJ_SRC_IMAGE_CAM) { + Object *cam_ob = ps->scene->camera; + CameraParams params; + + /* viewmat & viewinv */ + copy_m4_m4(viewinv, cam_ob->obmat); + normalize_m4(viewinv); + invert_m4_m4(viewmat, viewinv); + + /* window matrix, clipping and ortho */ + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, cam_ob); + BKE_camera_params_compute_viewplane(¶ms, ps->winx, ps->winy, 1.0f, 1.0f); + BKE_camera_params_compute_matrix(¶ms); + + copy_m4_m4(winmat, params.winmat); + ps->clipsta = params.clipsta; + ps->clipend = params.clipend; + ps->is_ortho = params.is_ortho; + } + + /* same as #ED_view3d_ob_project_mat_get */ + mult_m4_m4m4(vmat, viewmat, ps->ob->obmat); + mult_m4_m4m4(ps->projectMat, winmat, vmat); + } + + + /* viewDir - object relative */ + invert_m4_m4(ps->ob->imat, ps->ob->obmat); + copy_m3_m4(mat, viewinv); + mul_m3_v3(mat, ps->viewDir); + copy_m3_m4(mat, ps->ob->imat); + mul_m3_v3(mat, ps->viewDir); + normalize_v3(ps->viewDir); + + /* viewPos - object relative */ + copy_v3_v3(ps->viewPos, viewinv[3]); + copy_m3_m4(mat, ps->ob->imat); + mul_m3_v3(mat, ps->viewPos); + add_v3_v3(ps->viewPos, ps->ob->imat[3]); + } + + /* calculate vert screen coords + * run this early so we can calculate the x/y resolution of our bucket rect */ + INIT_MINMAX2(ps->screenMin, ps->screenMax); + + ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts"); + projScreenCo = *ps->screenCoords; + + if (ps->is_ortho) { + for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) { + mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co); + + /* screen space, not clamped */ + projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0]; + projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1]; + minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo); + } + } + else { + for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) { + copy_v3_v3(projScreenCo, mv->co); + projScreenCo[3] = 1.0f; + + mul_m4_v4(ps->projectMat, projScreenCo); + + if (projScreenCo[3] > ps->clipsta) { + /* screen space, not clamped */ + projScreenCo[0] = (float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projScreenCo[0] / projScreenCo[3]; + projScreenCo[1] = (float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projScreenCo[1] / projScreenCo[3]; + projScreenCo[2] = projScreenCo[2] / projScreenCo[3]; /* Use the depth for bucket point occlusion */ + minmax_v2v2_v2(ps->screenMin, ps->screenMax, projScreenCo); + } + else { + /* TODO - deal with cases where 1 side of a face goes behind the view ? + * + * After some research this is actually very tricky, only option is to + * clip the derived mesh before painting, which is a Pain */ + projScreenCo[0] = FLT_MAX; + } + } + } + + /* If this border is not added we get artifacts for faces that + * have a parallel edge and at the bounds of the the 2D projected verts eg + * - a single screen aligned quad */ + projMargin = (ps->screenMax[0] - ps->screenMin[0]) * 0.000001f; + ps->screenMax[0] += projMargin; + ps->screenMin[0] -= projMargin; + projMargin = (ps->screenMax[1] - ps->screenMin[1]) * 0.000001f; + ps->screenMax[1] += projMargin; + ps->screenMin[1] -= projMargin; + + if (ps->source == PROJ_SRC_VIEW) { +#ifdef PROJ_DEBUG_WINCLIP + CLAMP(ps->screenMin[0], (float)(-diameter), (float)(ps->winx + diameter)); + CLAMP(ps->screenMax[0], (float)(-diameter), (float)(ps->winx + diameter)); + + CLAMP(ps->screenMin[1], (float)(-diameter), (float)(ps->winy + diameter)); + CLAMP(ps->screenMax[1], (float)(-diameter), (float)(ps->winy + diameter)); +#endif + } + else { /* re-projection, use bounds */ + ps->screenMin[0] = 0; + ps->screenMax[0] = (float)(ps->winx); + + ps->screenMin[1] = 0; + ps->screenMax[1] = (float)(ps->winy); + } + + /* only for convenience */ + ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; + ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; + + ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); + ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); + + /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ + + /* really high values could cause problems since it has to allocate a few + * (ps->buckets_x*ps->buckets_y) sized arrays */ + CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); + CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); + + ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect"); + ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); + + ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); +#ifndef PROJ_DEBUG_NOSEAMBLEED + if (ps->seam_bleed_px > 0.0f) { + ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces"); + ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags"); + ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs"); + } +#endif + + /* Thread stuff + * + * very small brushes run a lot slower multithreaded since the advantage with + * threads is being able to fill in multiple buckets at once. + * Only use threads for bigger brushes. */ + + if (ps->scene->r.mode & R_FIXED_THREADS) { + ps->thread_tot = ps->scene->r.threads; + } + else { + ps->thread_tot = BLI_system_thread_count(); + } + for (a = 0; a < ps->thread_tot; a++) { + ps->arena_mt[a] = BLI_memarena_new(1 << 16, "project paint arena"); + } + + arena = ps->arena_mt[0]; + + if (ps->do_backfacecull && ps->do_mask_normal) { + float viewDirPersp[3]; + + ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags"); + + for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) { + normal_short_to_float_v3(no, mv->no); + + if (ps->is_ortho) { + if (angle_normalized_v3v3(ps->viewDir, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ + ps->vertFlags[a] |= PROJ_VERT_CULL; + } + } + else { + sub_v3_v3v3(viewDirPersp, ps->viewPos, mv->co); + normalize_v3(viewDirPersp); + if (angle_normalized_v3v3(viewDirPersp, no) >= ps->normal_angle) { /* 1 vert of this face is towards us */ + ps->vertFlags[a] |= PROJ_VERT_CULL; + } + } + } + } + + + for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { + +#ifndef PROJ_DEBUG_NOSEAMBLEED + /* add face user if we have bleed enabled, set the UV seam flags later */ + /* annoying but we need to add all faces even ones we never use elsewhere */ + if (ps->seam_bleed_px > 0.0f) { + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena); + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena); + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena); + if (mf->v4) { + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena); + } + } +#endif + + tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); + + if (tpage && ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) == 0 || mf->flag & ME_FACE_SEL)) { + + float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; + + v1coSS = ps->screenCoords[mf->v1]; + v2coSS = ps->screenCoords[mf->v2]; + v3coSS = ps->screenCoords[mf->v3]; + if (mf->v4) { + v4coSS = ps->screenCoords[mf->v4]; + } + + + if (!ps->is_ortho) { + if (v1coSS[0] == FLT_MAX || + v2coSS[0] == FLT_MAX || + v3coSS[0] == FLT_MAX || + (mf->v4 && v4coSS[0] == FLT_MAX)) + { + continue; + } + } + +#ifdef PROJ_DEBUG_WINCLIP + /* ignore faces outside the view */ + if ( + (v1coSS[0] < ps->screenMin[0] && + v2coSS[0] < ps->screenMin[0] && + v3coSS[0] < ps->screenMin[0] && + (mf->v4 && v4coSS[0] < ps->screenMin[0])) || + + (v1coSS[0] > ps->screenMax[0] && + v2coSS[0] > ps->screenMax[0] && + v3coSS[0] > ps->screenMax[0] && + (mf->v4 && v4coSS[0] > ps->screenMax[0])) || + + (v1coSS[1] < ps->screenMin[1] && + v2coSS[1] < ps->screenMin[1] && + v3coSS[1] < ps->screenMin[1] && + (mf->v4 && v4coSS[1] < ps->screenMin[1])) || + + (v1coSS[1] > ps->screenMax[1] && + v2coSS[1] > ps->screenMax[1] && + v3coSS[1] > ps->screenMax[1] && + (mf->v4 && v4coSS[1] > ps->screenMax[1])) + ) + { + continue; + } + +#endif //PROJ_DEBUG_WINCLIP + + + if (ps->do_backfacecull) { + if (ps->do_mask_normal) { + /* Since we are interpolating the normals of faces, we want to make + * sure all the verts are pointing away from the view, + * not just the face */ + if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) && + (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) && + (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) && + (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL) + ) + { + continue; + } + } + else { + if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) { + continue; + } + + } + } + + if (tpage_last != tpage) { + + image_index = BLI_linklist_index(image_LinkList, tpage); + + if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */ + BLI_linklist_append(&image_LinkList, tpage); + image_index = ps->image_tot; + ps->image_tot++; + } + + tpage_last = tpage; + } + + if (image_index != -1) { + /* Initialize the faces screen pixels */ + /* Add this to a list to initialize later */ + project_paint_delayed_face_init(ps, mf, face_index); + } + } + } + + /* build an array of images we use*/ + projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot); + + for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) { + projIma->ima = node->link; + projIma->touch = 0; + projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); + projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + } + + /* we have built the array, discard the linked list */ + BLI_linklist_free(image_LinkList, NULL); +} + +static void paint_proj_begin_clone(ProjPaintState *ps, const int mouse[2]) +{ + /* setup clone offset */ + if (ps->tool == PAINT_TOOL_CLONE) { + float projCo[4]; + copy_v3_v3(projCo, give_cursor(ps->scene, ps->v3d)); + mul_m4_v3(ps->ob->imat, projCo); + + projCo[3] = 1.0f; + mul_m4_v4(ps->projectMat, projCo); + ps->cloneOffset[0] = mouse[0] - ((float)(ps->winx / 2.0f) + (ps->winx / 2.0f) * projCo[0] / projCo[3]); + ps->cloneOffset[1] = mouse[1] - ((float)(ps->winy / 2.0f) + (ps->winy / 2.0f) * projCo[1] / projCo[3]); + } +} + +static void project_paint_end(ProjPaintState *ps) +{ + int a; + ProjPaintImage *projIma; + + /* build undo data from original pixel colors */ + if (U.uiflag & USER_GLOBALUNDO) { + ProjPixel *projPixel; + ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; + LinkNode *pixel_node; + void *tilerect; + MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */ + + int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */ + int bucket_index; + int tile_index; + int x_round, y_round; + int x_tile, y_tile; + int is_float = -1; + + /* context */ + ProjPaintImage *last_projIma; + int last_image_index = -1; + int last_tile_width = 0; + + for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) { + int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); + last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size); + memset(last_projIma->undoRect, 0, size); + last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; + } + + for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { + /* loop through all pixels */ + for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) { + + /* ok we have a pixel, was it modified? */ + projPixel = (ProjPixel *)pixel_node->link; + + if (last_image_index != projPixel->image_index) { + /* set the context */ + last_image_index = projPixel->image_index; + last_projIma = ps->projImages + last_image_index; + last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x); + is_float = last_projIma->ibuf->rect_float ? 1 : 0; + } + + + if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) || + (is_float == 1 && + (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] || + projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] || + projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] || + projPixel->origColor.f[3] != projPixel->pixel.f_pt[3])) + ) + { + + x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS; + y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS; + + x_round = x_tile * IMAPAINT_TILE_SIZE; + y_round = y_tile * IMAPAINT_TILE_SIZE; + + tile_index = x_tile + y_tile * last_tile_width; + + if (last_projIma->undoRect[tile_index] == NULL) { + /* add the undo tile from the modified image, then write the original colors back into it */ + tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile); + } + else { + tilerect = last_projIma->undoRect[tile_index]; + } + + /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color + * because allocating the tiles along the way slows down painting */ + + if (is_float) { + float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4; + copy_v4_v4(rgba_fp, projPixel->origColor.f); + } + else { + ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint; + } + } + } + } + + if (tmpibuf) IMB_freeImBuf(tmpibuf); + if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); + } + /* done calculating undo data */ + + /* dereference used image buffers */ + for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { + BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL); + } + + BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL); + + MEM_freeN(ps->screenCoords); + MEM_freeN(ps->bucketRect); + MEM_freeN(ps->bucketFaces); + MEM_freeN(ps->bucketFlags); + +#ifndef PROJ_DEBUG_NOSEAMBLEED + if (ps->seam_bleed_px > 0.0f) { + MEM_freeN(ps->vertFaces); + MEM_freeN(ps->faceSeamFlags); + MEM_freeN(ps->faceSeamUVs); + } +#endif + + if (ps->vertFlags) MEM_freeN(ps->vertFlags); + + for (a = 0; a < ps->thread_tot; a++) { + BLI_memarena_free(ps->arena_mt[a]); + } + + /* copy for subsurf/multires, so throw away */ + if (ps->dm->type != DM_TYPE_CDDM) { + if (ps->dm_mvert) MEM_freeN(ps->dm_mvert); + if (ps->dm_mface) MEM_freeN(ps->dm_mface); + /* looks like these don't need copying */ +#if 0 + if (ps->dm_mtface) MEM_freeN(ps->dm_mtface); + if (ps->dm_mtface_clone) MEM_freeN(ps->dm_mtface_clone); + if (ps->dm_mtface_stencil) MEM_freeN(ps->dm_mtface_stencil); +#endif + } + + if (ps->dm_release) + ps->dm->release(ps->dm); +} + +/* 1 = an undo, -1 is a redo. */ +static void partial_redraw_array_init(ImagePaintPartialRedraw *pr) +{ + int tot = PROJ_BOUNDBOX_SQUARED; + while (tot--) { + pr->x1 = 10000000; + pr->y1 = 10000000; + + pr->x2 = -1; + pr->y2 = -1; + + pr->enabled = 1; + + pr++; + } +} + + +static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot) +{ + int touch = 0; + while (tot--) { + pr->x1 = min_ii(pr->x1, pr_other->x1); + pr->y1 = min_ii(pr->y1, pr_other->y1); + + pr->x2 = max_ii(pr->x2, pr_other->x2); + pr->y2 = max_ii(pr->y2, pr_other->y2); + + if (pr->x2 != -1) + touch = 1; + + pr++; pr_other++; + } + + return touch; +} + +/* Loop over all images on this mesh and update any we have touched */ +static int project_image_refresh_tagged(ProjPaintState *ps) +{ + ImagePaintPartialRedraw *pr; + ProjPaintImage *projIma; + int a, i; + int redraw = 0; + + + for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { + if (projIma->touch) { + /* look over each bound cell */ + for (i = 0; i < PROJ_BOUNDBOX_SQUARED; i++) { + pr = &(projIma->partRedrawRect[i]); + if (pr->x2 != -1) { /* TODO - use 'enabled' ? */ + set_imapaintpartial(pr); + imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true); + redraw = 1; + } + } + + projIma->touch = 0; /* clear for reuse */ + } + } + + return redraw; +} + +/* run this per painting onto each mouse location */ +static int project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) +{ + if (ps->source == PROJ_SRC_VIEW) { + float min_brush[2], max_brush[2]; + const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush); + + /* so we don't have a bucket bounds that is way too small to paint into */ + // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ + + min_brush[0] = mval_f[0] - radius; + min_brush[1] = mval_f[1] - radius; + + max_brush[0] = mval_f[0] + radius; + max_brush[1] = mval_f[1] + radius; + + /* offset to make this a valid bucket index */ + project_paint_bucket_bounds(ps, min_brush, max_brush, ps->bucketMin, ps->bucketMax); + + /* mouse outside the model areas? */ + if (ps->bucketMin[0] == ps->bucketMax[0] || ps->bucketMin[1] == ps->bucketMax[1]) { + return 0; + } + + ps->context_bucket_x = ps->bucketMin[0]; + ps->context_bucket_y = ps->bucketMin[1]; + } + else { /* reproject: PROJ_SRC_* */ + ps->bucketMin[0] = 0; + ps->bucketMin[1] = 0; + + ps->bucketMax[0] = ps->buckets_x; + ps->bucketMax[1] = ps->buckets_y; + + ps->context_bucket_x = 0; + ps->context_bucket_y = 0; + } + return 1; +} + + +static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2]) +{ + const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + + if (ps->thread_tot > 1) + BLI_lock_thread(LOCK_CUSTOM1); + + //printf("%d %d\n", ps->context_bucket_x, ps->context_bucket_y); + + for (; ps->context_bucket_y < ps->bucketMax[1]; ps->context_bucket_y++) { + for (; ps->context_bucket_x < ps->bucketMax[0]; ps->context_bucket_x++) { + + /* use bucket_bounds for project_bucket_isect_circle and project_bucket_init*/ + project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds); + + if ((ps->source != PROJ_SRC_VIEW) || + project_bucket_isect_circle(mval, (float)(diameter * diameter), bucket_bounds)) + { + *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x); + ps->context_bucket_x++; + + if (ps->thread_tot > 1) + BLI_unlock_thread(LOCK_CUSTOM1); + + return 1; + } + } + ps->context_bucket_x = ps->bucketMin[0]; + } + + if (ps->thread_tot > 1) + BLI_unlock_thread(LOCK_CUSTOM1); + return 0; +} + +/* Each thread gets one of these, also used as an argument to pass to project_paint_op */ +typedef struct ProjectHandle { + /* args */ + ProjPaintState *ps; + float prevmval[2]; + float mval[2]; + + /* annoying but we need to have image bounds per thread, then merge into ps->projectPartialRedraws */ + ProjPaintImage *projImages; /* array of partial redraws */ + + /* thread settings */ + int thread_index; + + struct ImagePool *pool; +} ProjectHandle; + +static void blend_color_mix(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac) +{ + /* this and other blending modes previously used >>8 instead of /255. both + * are not equivalent (>>8 is /256), and the former results in rounding + * errors that can turn colors black fast after repeated blending */ + const int mfac = 255 - fac; + + cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255; + cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255; + cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255; + cp[3] = (mfac * cp1[3] + fac * cp2[3]) / 255; +} + +static void blend_color_mix_float(float cp[4], const float cp1[4], const float cp2[4], const float fac) +{ + const float mfac = 1.0f - fac; + cp[0] = mfac * cp1[0] + fac * cp2[0]; + cp[1] = mfac * cp1[1] + fac * cp2[1]; + cp[2] = mfac * cp1[2] + fac * cp2[2]; + cp[3] = mfac * cp1[3] + fac * cp2[3]; +} + +static void blend_color_mix_accum(unsigned char cp[4], const unsigned char cp1[4], const unsigned char cp2[4], const int fac) +{ + /* this and other blending modes previously used >>8 instead of /255. both + * are not equivalent (>>8 is /256), and the former results in rounding + * errors that can turn colors black fast after repeated blending */ + const int mfac = 255 - fac; + const int alpha = cp1[3] + ((fac * cp2[3]) / 255); + + cp[0] = (mfac * cp1[0] + fac * cp2[0]) / 255; + cp[1] = (mfac * cp1[1] + fac * cp2[1]) / 255; + cp[2] = (mfac * cp1[2] + fac * cp2[2]) / 255; + cp[3] = alpha > 255 ? 255 : alpha; +} +static void blend_color_mix_accum_float(float cp[4], const float cp1[4], const unsigned char cp2[4], const float fac) +{ + const float mfac = 1.0f - fac; + const float alpha = cp1[3] + (fac * (cp2[3] / 255.0f)); + + cp[0] = (mfac * cp1[0] + (fac * (cp2[0] / 255.0f))); + cp[1] = (mfac * cp1[1] + (fac * (cp2[1] / 255.0f))); + cp[2] = (mfac * cp1[2] + (fac * (cp2[2] / 255.0f))); + cp[3] = alpha > 1.0f ? 1.0f : alpha; +} + + +static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) +{ + if (ps->do_masking && mask < 1.0f) { + projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * 255), ps->blend); + blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255)); + } + else { + *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, ((ProjPixelClone *)projPixel)->clonepx.uint, (int)(alpha * mask * 255), ps->blend); + } +} + +static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) +{ + if (ps->do_masking && mask < 1.0f) { + IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend); + blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); + } + else { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f, alpha * mask, ps->blend); + } +} + +/* do_projectpaint_smear* + * + * note, mask is used to modify the alpha here, this is not correct since it allows + * accumulation of color greater then 'projPixel->mask' however in the case of smear its not + * really that important to be correct as it is with clone and painting + */ +static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, + MemArena *smearArena, LinkNode **smearPixels, const float co[2]) +{ + unsigned char rgba_ub[4]; + + if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) + return; + /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ + blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * mask * 255)); + BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); +} + +static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, + MemArena *smearArena, LinkNode **smearPixels_f, const float co[2]) +{ + float rgba[4]; + + if (project_paint_PickColor(ps, co, rgba, NULL, 1) == 0) + return; + + /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ + blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha * mask); + BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); +} + +/* do_projectpaint_soften for float & byte + */ +static float inv_pow2(float f) +{ + f = 1.0f - f; + f = f * f; + return 1.0f - f; +} + +static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, + MemArena *softenArena, LinkNode **softenPixels) +{ + unsigned int accum_tot = 0; + unsigned int i; + + float *rgba = projPixel->newColor.f; + + /* sigh, alpha values tend to need to be a _lot_ stronger with blur */ + mask = inv_pow2(mask); + alpha = inv_pow2(alpha); + + /* rather then painting, accumulate surrounding colors */ + zero_v4(rgba); + + for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { + float co_ofs[2]; + float rgba_tmp[4]; + sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) { + add_v4_v4(rgba, rgba_tmp); + accum_tot++; + } + } + + if (LIKELY(accum_tot != 0)) { + mul_v4_fl(rgba, 1.0f / (float)accum_tot); + blend_color_mix_float(rgba, projPixel->pixel.f_pt, rgba, alpha); + if (mask < 1.0f) blend_color_mix_float(rgba, projPixel->origColor.f, rgba, mask); + BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); + } +} + +static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, + MemArena *softenArena, LinkNode **softenPixels) +{ + unsigned int accum_tot = 0; + unsigned int i; + + float rgba[4]; /* convert to byte after */ + + /* sigh, alpha values tend to need to be a _lot_ stronger with blur */ + mask = inv_pow2(mask); + alpha = inv_pow2(alpha); + + /* rather then painting, accumulate surrounding colors */ + zero_v4(rgba); + + for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { + float co_ofs[2]; + float rgba_tmp[4]; + sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, TRUE)) { + add_v4_v4(rgba, rgba_tmp); + accum_tot++; + } + } + + if (LIKELY(accum_tot != 0)) { + unsigned char *rgba_ub = projPixel->newColor.ch; + + mul_v4_fl(rgba, 1.0f / (float)accum_tot); + IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_ub, rgba); + + blend_color_mix(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha * 255)); + if (mask != 1.0f) blend_color_mix(rgba_ub, projPixel->origColor.ch, rgba_ub, (int)(mask * 255)); + BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); + } +} + +BLI_INLINE void rgba_float_to_uchar__mul_v3(unsigned char rgba_ub[4], const float rgba[4], const float rgb[3]) +{ + rgba_ub[0] = f_to_char(rgba[0] * rgb[0]); + rgba_ub[1] = f_to_char(rgba[1] * rgb[1]); + rgba_ub[2] = f_to_char(rgba[2] * rgb[2]); + rgba_ub[3] = f_to_char(rgba[3]); +} + +static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgba[4], float alpha, float mask) +{ + unsigned char rgba_ub[4]; + + if (ps->is_texbrush) { + rgba_float_to_uchar__mul_v3(rgba_ub, rgba, ps->brush->rgb); + } + else { + IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb); + rgba_ub[3] = 255; + } + + if (ps->do_masking && mask < 1.0f) { + projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, *((unsigned int *)rgba_ub), (int)(alpha * 255), ps->blend); + blend_color_mix(projPixel->pixel.ch_pt, projPixel->origColor.ch, projPixel->newColor.ch, (int)(mask * 255)); + } + else { + *projPixel->pixel.uint_pt = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha * mask * 255), ps->blend); + } +} + +static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, float rgba[4], float alpha, float mask) +{ + if (ps->is_texbrush) { + /* rgba already holds a texture result here from higher level function */ + float rgba_br[3]; + srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb); + mul_v3_v3(rgba, rgba_br); + } + else { + srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb); + rgba[3] = 1.0; + } + + if (ps->do_masking && mask < 1.0f) { + IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, rgba, alpha, ps->blend); + blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, projPixel->newColor.f, mask); + } + else { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, alpha * mask, ps->blend); + } +} + + + +/* run this for single and multithreaded painting */ +static void *do_projectpaint_thread(void *ph_v) +{ + /* First unpack args from the struct */ + ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; + ProjPaintImage *projImages = ((ProjectHandle *)ph_v)->projImages; + const float *lastpos = ((ProjectHandle *)ph_v)->prevmval; + const float *pos = ((ProjectHandle *)ph_v)->mval; + const int thread_index = ((ProjectHandle *)ph_v)->thread_index; + struct ImagePool *pool = ((ProjectHandle *)ph_v)->pool; + /* Done with args from ProjectHandle */ + + LinkNode *node; + ProjPixel *projPixel; + Brush *brush = ps->brush; + + int last_index = -1; + ProjPaintImage *last_projIma = NULL; + ImagePaintPartialRedraw *last_partial_redraw_cell; + + float rgba[4], alpha, dist_nosqrt, dist; + + float falloff; + int bucket_index; + int is_floatbuf = 0; + const short tool = ps->tool; + rctf bucket_bounds; + + /* for smear only */ + float pos_ofs[2] = {0}; + float co[2]; + float mask = 1.0f; /* airbrush wont use mask */ + unsigned short mask_short; + const float radius = (float)BKE_brush_size_get(ps->scene, brush); + const float radius_squared = radius * radius; /* avoid a square root with every dist comparison */ + + short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA; + + LinkNode *smearPixels = NULL; + LinkNode *smearPixels_f = NULL; + MemArena *smearArena = NULL; /* mem arena for this brush projection only */ + + LinkNode *softenPixels = NULL; + LinkNode *softenPixels_f = NULL; + MemArena *softenArena = NULL; /* mem arena for this brush projection only */ + + if (tool == PAINT_TOOL_SMEAR) { + pos_ofs[0] = pos[0] - lastpos[0]; + pos_ofs[1] = pos[1] - lastpos[1]; + + smearArena = BLI_memarena_new(1 << 16, "paint smear arena"); + } + else if (tool == PAINT_TOOL_SOFTEN) { + softenArena = BLI_memarena_new(1 << 16, "paint soften arena"); + } + + /* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */ + + while (project_bucket_iter_next(ps, &bucket_index, &bucket_bounds, pos)) { + + /* Check this bucket and its faces are initialized */ + if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) { + /* No pixels initialized */ + project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds); + } + + if (ps->source != PROJ_SRC_VIEW) { + + /* Re-Projection, simple, no brushes! */ + + for (node = ps->bucketRect[bucket_index]; node; node = node->next) { + projPixel = (ProjPixel *)node->link; + + /* copy of code below */ + if (last_index != projPixel->image_index) { + last_index = projPixel->image_index; + last_projIma = projImages + last_index; + + last_projIma->touch = 1; + is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; + } + /* end copy */ + + if (is_floatbuf) { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + mask = ((float)projPixel->mask) / 65535.0f; + blend_color_mix_accum_float(projPixel->pixel.f_pt, projPixel->origColor.f, + projPixel->newColor.ch, (mask * (projPixel->newColor.ch[3] / 255.0f))); + } + } + else { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + mask = ((float)projPixel->mask) / 65535.0f; + blend_color_mix_accum(projPixel->pixel.ch_pt, projPixel->origColor.ch, + projPixel->newColor.ch, (int)(mask * projPixel->newColor.ch[3])); + } + } + } + } + else { + /* Normal brush painting */ + + for (node = ps->bucketRect[bucket_index]; node; node = node->next) { + + projPixel = (ProjPixel *)node->link; + + dist_nosqrt = len_squared_v2v2(projPixel->projCoSS, pos); + + /*if (dist < radius) {*/ /* correct but uses a sqrtf */ + if (dist_nosqrt <= radius_squared) { + float samplecos[3]; + dist = sqrtf(dist_nosqrt); + + falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius); + + if (ps->is_texbrush) { + MTex *mtex = &brush->mtex; + /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */ + if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { + copy_v3_v3(samplecos, projPixel->worldCoSS); + } + else { + copy_v2_v2(samplecos, projPixel->projCoSS); + samplecos[2] = 0.0f; + } + } + + if (falloff > 0.0f) { + if (ps->is_texbrush) { + /* note, for clone and smear, we only use the alpha, could be a special function */ + BKE_brush_sample_tex_3D(ps->scene, brush, samplecos, rgba, thread_index, pool); + alpha = rgba[3]; + } + else { + alpha = 1.0f; + } + + if (!ps->do_masking) { + /* for an aurbrush there is no real mask, so just multiply the alpha by it */ + alpha *= falloff * BKE_brush_alpha_get(ps->scene, brush); + mask = ((float)projPixel->mask) / 65535.0f; + } + else { + /* This brush dosnt accumulate so add some curve to the brushes falloff */ + falloff = 1.0f - falloff; + falloff = 1.0f - (falloff * falloff); + + mask_short = (unsigned short)(projPixel->mask * (BKE_brush_alpha_get(ps->scene, brush) * falloff)); + if (mask_short > projPixel->mask_max) { + mask = ((float)mask_short) / 65535.0f; + projPixel->mask_max = mask_short; + } + else { + /*mask = ((float)projPixel->mask_max)/65535.0f;*/ + + /* Go onto the next pixel */ + continue; + } + } + + if (alpha > 0.0f) { + + /* copy of code above */ + if (last_index != projPixel->image_index) { + last_index = projPixel->image_index; + last_projIma = projImages + last_index; + + last_projIma->touch = 1; + is_floatbuf = last_projIma->ibuf->rect_float ? 1 : 0; + } + /* end copy */ + + last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; + last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); + last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); + + last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1); + last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1); + + + switch (tool) { + case PAINT_TOOL_CLONE: + if (is_floatbuf) { + if (((ProjPixelClone *)projPixel)->clonepx.f[3]) { + do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */ + } + } + else { + if (((ProjPixelClone *)projPixel)->clonepx.ch[3]) { + do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isn't used for cloning, only alpha */ + } + } + break; + case PAINT_TOOL_SMEAR: + sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs); + + if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co); + else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co); + break; + case PAINT_TOOL_SOFTEN: + if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, alpha, mask, softenArena, &softenPixels_f); + else do_projectpaint_soften(ps, projPixel, alpha, mask, softenArena, &softenPixels); + break; + default: + if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask); + else do_projectpaint_draw(ps, projPixel, rgba, alpha, mask); + break; + } + } + + if (lock_alpha) { + if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3]; + else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3]; + } + + /* done painting */ + } + } + } + } + } + + + if (tool == PAINT_TOOL_SMEAR) { + + for (node = smearPixels; node; node = node->next) { /* this wont run for a float image */ + projPixel = node->link; + *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint; + } + + for (node = smearPixels_f; node; node = node->next) { + projPixel = node->link; + copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f); + } + + BLI_memarena_free(smearArena); + } + else if (tool == PAINT_TOOL_SOFTEN) { + + for (node = softenPixels; node; node = node->next) { /* this wont run for a float image */ + projPixel = node->link; + *projPixel->pixel.uint_pt = projPixel->newColor.uint; + } + + for (node = softenPixels_f; node; node = node->next) { + projPixel = node->link; + copy_v4_v4(projPixel->pixel.f_pt, projPixel->newColor.f); + } + + BLI_memarena_free(softenArena); + } + + return NULL; +} + +static int project_paint_op(void *state, const float lastpos[2], const float pos[2]) +{ + /* First unpack args from the struct */ + ProjPaintState *ps = (ProjPaintState *)state; + int touch_any = 0; + + ProjectHandle handles[BLENDER_MAX_THREADS]; + ListBase threads; + int a, i; + + struct ImagePool *pool; + + if (!project_bucket_iter_init(ps, pos)) { + return 0; + } + + if (ps->thread_tot > 1) + BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot); + + pool = BKE_image_pool_new(); + + /* get the threads running */ + for (a = 0; a < ps->thread_tot; a++) { + + /* set defaults in handles */ + //memset(&handles[a], 0, sizeof(BakeShade)); + + handles[a].ps = ps; + copy_v2_v2(handles[a].mval, pos); + copy_v2_v2(handles[a].prevmval, lastpos); + + /* thread specific */ + handles[a].thread_index = a; + + handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); + + memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage)); + + /* image bounds */ + for (i = 0; i < ps->image_tot; i++) { + handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + } + + handles[a].pool = pool; + + if (ps->thread_tot > 1) + BLI_insert_thread(&threads, &handles[a]); + } + + if (ps->thread_tot > 1) /* wait for everything to be done */ + BLI_end_threads(&threads); + else + do_projectpaint_thread(&handles[0]); + + + BKE_image_pool_free(pool); + + /* move threaded bounds back into ps->projectPartialRedraws */ + for (i = 0; i < ps->image_tot; i++) { + int touch = 0; + for (a = 0; a < ps->thread_tot; a++) { + touch |= partial_redraw_array_merge(ps->projImages[i].partRedrawRect, handles[a].projImages[i].partRedrawRect, PROJ_BOUNDBOX_SQUARED); + } + + if (touch) { + ps->projImages[i].touch = 1; + touch_any = 1; + } + } + + return touch_any; +} + + +int paint_proj_stroke(bContext *C, void *pps, const int prevmval_i[2], const int mval_i[2]) +{ + ProjPaintState *ps = pps; + int a, redraw; + float pos[2], prev_pos[2]; + + pos[0] = (float)(mval_i[0]); + pos[1] = (float)(mval_i[1]); + + prev_pos[0] = (float)(prevmval_i[0]); + prev_pos[1] = (float)(prevmval_i[1]); + + /* clone gets special treatment here to avoid going through image initialization */ + if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) { + Scene *scene = ps->scene; + View3D *v3d = ps->v3d; + float *cursor = give_cursor(scene, v3d); + + view3d_operator_needs_opengl(C); + + if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor)) + return 0; + + ED_region_tag_redraw(ps->ar); + + return 0; + } + + for (a = 0; a < ps->image_tot; a++) + partial_redraw_array_init(ps->projImages[a].partRedrawRect); + + redraw = project_paint_op(ps, prev_pos, pos) ? 1 : 0; + + if (project_image_refresh_tagged(ps)) + return redraw; + + return 0; +} + + +/* initialize project paint settings from context */ +static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int mode) +{ + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; + + /* brush */ + ps->mode = mode; + ps->brush = paint_brush(&settings->imapaint.paint); + if (ps->brush) { + Brush *brush = ps->brush; + ps->tool = brush->imagepaint_tool; + ps->blend = brush->blend; + + /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */ + ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW || + brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) ? false : true; + ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? 1 : 0; + } + else { + /* brush may be NULL*/ + ps->do_masking = false; + ps->is_texbrush = false; + } + + /* sizeof(ProjPixel), since we alloc this a _lot_ */ + ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool); + BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel)); + + /* these can be NULL */ + ps->v3d = CTX_wm_view3d(C); + ps->rv3d = CTX_wm_region_view3d(C); + ps->ar = CTX_wm_region(C); + + ps->scene = scene; + ps->ob = ob; /* allow override of active object */ + + /* setup projection painting data */ + ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; + ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; + ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1; + ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */ + + if (ps->tool == PAINT_TOOL_CLONE) + ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE); + + ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0; + ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0; + + +#ifndef PROJ_DEBUG_NOSEAMBLEED + ps->seam_bleed_px = settings->imapaint.seam_bleed; /* pixel num to bleed */ +#endif + + if (ps->do_mask_normal) { + ps->normal_angle_inner = settings->imapaint.normal_angle; + ps->normal_angle = (ps->normal_angle_inner + 90.0f) * 0.5f; + } + else { + ps->normal_angle_inner = ps->normal_angle = settings->imapaint.normal_angle; + } + + ps->normal_angle_inner *= (float)(M_PI_2 / 90); + ps->normal_angle *= (float)(M_PI_2 / 90); + ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner; + + if (ps->normal_angle_range <= 0.0f) + ps->do_mask_normal = FALSE; /* no need to do blending */ + + return; +} + +void *paint_proj_new_stroke(bContext *C, Object *ob, const int mouse[2], int mode) +{ + ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState"); + project_state_init(C, ob, ps, mode); + + if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) { + view3d_operator_needs_opengl(C); + return ps; + } + + /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ + curvemapping_initialize(ps->brush->curve); + + paint_brush_init_tex(ps->brush); + + ps->source = PROJ_SRC_VIEW; + + if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) { + MEM_freeN(ps); + return NULL; + } + + ps->orig_brush_size = BKE_brush_size_get(ps->scene, ps->brush); + + /* Don't allow brush size below 2 */ + if (BKE_brush_size_get(ps->scene, ps->brush) < 2) + BKE_brush_size_set(ps->scene, ps->brush, 2); + + /* allocate and initialize spatial data structures */ + project_paint_begin(ps); + + if (ps->dm == NULL) { + MEM_freeN(ps); + return NULL; + } + + paint_proj_begin_clone(ps, mouse); + + return ps; +} + +void paint_proj_stroke_done(void *pps) +{ + ProjPaintState *ps = pps; + if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) { + MEM_freeN(ps); + return; + } + BKE_brush_size_set(ps->scene, ps->brush, ps->orig_brush_size); + + paint_brush_exit_tex(ps->brush); + + project_paint_end(ps); + MEM_freeN(ps); +} +/* use project paint to re-apply an image */ +static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) +{ + Image *image = BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image")); + Scene *scene = CTX_data_scene(C); + ProjPaintState ps = {NULL}; + int orig_brush_size; + IDProperty *idgroup; + IDProperty *view_data = NULL; + + project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL); + + if (ps.ob == NULL || ps.ob->type != OB_MESH) { + BKE_report(op->reports, RPT_ERROR, "No active mesh object"); + return OPERATOR_CANCELLED; + } + + if (image == NULL) { + BKE_report(op->reports, RPT_ERROR, "Image could not be found"); + return OPERATOR_CANCELLED; + } + + ps.reproject_image = image; + ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + + if (ps.reproject_ibuf == NULL || ps.reproject_ibuf->rect == NULL) { + BKE_report(op->reports, RPT_ERROR, "Image data could not be found"); + return OPERATOR_CANCELLED; + } + + idgroup = IDP_GetProperties(&image->id, 0); + + if (idgroup) { + view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY); + + /* type check to make sure its ok */ + if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) { + BKE_report(op->reports, RPT_ERROR, "Image project data invalid"); + return OPERATOR_CANCELLED; + } + } + + if (view_data) { + /* image has stored view projection info */ + ps.source = PROJ_SRC_IMAGE_VIEW; + } + else { + ps.source = PROJ_SRC_IMAGE_CAM; + + if (scene->camera == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active camera set"); + return OPERATOR_CANCELLED; + } + } + + /* override */ + ps.is_texbrush = 0; + ps.do_masking = false; + orig_brush_size = BKE_brush_size_get(scene, ps.brush); + BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */ + + ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */ + + scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; + + undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, + image_undo_restore, image_undo_free); + + /* allocate and initialize spatial data structures */ + project_paint_begin(&ps); + + if (ps.dm == NULL) { + BKE_brush_size_set(scene, ps.brush, orig_brush_size); + return OPERATOR_CANCELLED; + } + else { + float pos[2] = {0.0, 0.0}; + float lastpos[2] = {0.0, 0.0}; + int a; + + for (a = 0; a < ps.image_tot; a++) + partial_redraw_array_init(ps.projImages[a].partRedrawRect); + + project_paint_op(&ps, lastpos, pos); + + project_image_refresh_tagged(&ps); + + for (a = 0; a < ps.image_tot; a++) { + GPU_free_image(ps.projImages[a].ima); + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ps.projImages[a].ima); + } + } + + project_paint_end(&ps); + + scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + BKE_brush_size_set(scene, ps.brush, orig_brush_size); + + return OPERATOR_FINISHED; +} + +void PAINT_OT_project_image(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Project Image"; + ot->idname = "PAINT_OT_project_image"; + ot->description = "Project an edited render from the active camera back onto the object"; + + /* api callbacks */ + ot->invoke = WM_enum_search_invoke; + ot->exec = texture_paint_camera_project_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + prop = RNA_def_enum(ot->srna, "image", DummyRNA_NULL_items, 0, "Image", ""); + RNA_def_enum_funcs(prop, RNA_image_itemf); + ot->prop = prop; +} + +static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) +{ + Image *image; + ImBuf *ibuf; + char filename[FILE_MAX]; + + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; + int w = settings->imapaint.screen_grab_size[0]; + int h = settings->imapaint.screen_grab_size[1]; + int maxsize; + char err_out[256] = "unknown"; + + RNA_string_get(op->ptr, "filepath", filename); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); + + if (w > maxsize) w = maxsize; + if (h > maxsize) h = maxsize; + + ibuf = ED_view3d_draw_offscreen_imbuf(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, FALSE, R_ALPHAPREMUL, err_out); + if (!ibuf) { + /* Mostly happens when OpenGL offscreen buffer was failed to create, */ + /* but could be other reasons. Should be handled in the future. nazgul */ + BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer: %s", err_out); + return OPERATOR_CANCELLED; + } + + image = BKE_image_add_from_imbuf(ibuf); + + if (image) { + /* now for the trickyness. store the view projection here! + * re-projection will reuse this */ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + IDPropertyTemplate val; + IDProperty *idgroup = IDP_GetProperties(&image->id, 1); + IDProperty *view_data; + bool is_ortho; + float *array; + + val.array.len = PROJ_VIEW_DATA_SIZE; + val.array.type = IDP_FLOAT; + view_data = IDP_New(IDP_ARRAY, &val, PROJ_VIEW_DATA_ID); + + array = (float *)IDP_Array(view_data); + memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float); + memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float); + is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true); + array[2] = is_ortho ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */ + + IDP_AddToGroup(idgroup, view_data); + + rename_id(&image->id, "image_view"); + } + + return OPERATOR_FINISHED; +} + +void PAINT_OT_image_from_view(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Image from View"; + ot->idname = "PAINT_OT_image_from_view"; + ot->description = "Make an image from the current 3D view for re-projection"; + + /* api callbacks */ + ot->exec = texture_paint_image_from_view_exec; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER; + + RNA_def_string_file_name(ot->srna, "filepath", "", FILE_MAX, "File Path", "Name of the file"); +} diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index e7c3ddd071b..a15795dc2da 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -50,6 +50,8 @@ struct ViewContext; struct wmEvent; struct wmOperator; struct wmOperatorType; +struct ImagePaintState; +enum PaintMode; /* paint_stroke.c */ typedef int (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]); @@ -62,11 +64,14 @@ struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeUpdateStep update_step, StrokeDone done, int event_type); void paint_stroke_data_free(struct wmOperator *op); -bool paint_space_stroke_enabled(struct Brush *br); -bool paint_supports_dynamic_size(struct Brush *br); +bool paint_space_stroke_enabled(struct Brush *br, enum PaintMode mode); +bool paint_supports_dynamic_size(struct Brush *br, enum PaintMode mode); +bool paint_supports_dynamic_tex_coords(struct Brush *br, enum PaintMode mode); +bool paint_supports_smooth_stroke(struct Brush *br, enum PaintMode mode); +bool paint_supports_jitter(enum PaintMode mode); struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf); -int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); +int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); int paint_stroke_exec(struct bContext *C, struct wmOperator *op); int paint_stroke_cancel(struct bContext *C, struct wmOperator *op); struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); @@ -103,16 +108,46 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot); unsigned int vpaint_get_current_col(struct VPaint *vp); /* paint_image.c */ +typedef struct ImagePaintPartialRedraw { + int x1, y1, x2, y2; /* XXX, could use 'rcti' */ + int enabled; +} ImagePaintPartialRedraw; + +#define IMAPAINT_TILE_BITS 6 +#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS) +#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) + +#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f) + int image_texture_paint_poll(struct bContext *C); +void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile); +void image_undo_restore(struct bContext *C, struct ListBase *lb); +void image_undo_free(struct ListBase *lb); +void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint); +struct ImagePaintPartialRedraw *get_imapaintpartial(void); +void set_imapaintpartial(struct ImagePaintPartialRedraw * ippr); +void imapaint_clear_partial_redraw(void); +void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h); +int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); +void *paint_2d_new_stroke(struct bContext *, struct wmOperator *); +void paint_2d_redraw(const bContext *C, void *ps, int final); +void paint_2d_stroke_done(void *ps); +int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser); +void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const int mouse[2], int mode); +int paint_proj_stroke(struct bContext *C, void *ps, const int prevmval_i[2], const int mval_i[2]); +void paint_proj_stroke_done(void *ps); +void paint_brush_init_tex(struct Brush *brush); +void paint_brush_exit_tex(struct Brush *brush); -void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_grab_clone(struct wmOperatorType *ot); void PAINT_OT_sample_color(struct wmOperatorType *ot); -void PAINT_OT_clone_cursor_set(struct wmOperatorType *ot); void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_project_image(struct wmOperatorType *ot); void PAINT_OT_image_from_view(struct wmOperatorType *ot); +/* new texture painting */ +void PAINT_OT_image_paint(struct wmOperatorType *ot); + /* uv sculpting */ int uv_sculpt_poll(struct bContext *C); @@ -144,6 +179,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[ float paint_get_tex_pixel(struct Brush *br, float u, float v, struct ImagePool *pool); int imapaint_pick_face(struct ViewContext *vc, const int mval[2], unsigned int *index, unsigned int totface); void imapaint_pick_uv(struct Scene *scene, struct Object *ob, unsigned int faceindex, const int xy[2], float uv[2]); +void brush_drawcursor_texpaint_uvsculpt(struct bContext *C, int x, int y, void *customdata); void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y); void BRUSH_OT_curve_preset(struct wmOperatorType *ot); @@ -155,6 +191,7 @@ void PAINT_OT_face_select_hide(struct wmOperatorType *ot); void PAINT_OT_face_select_reveal(struct wmOperatorType *ot); void PAINT_OT_vert_select_all(struct wmOperatorType *ot); +void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot); int vert_paint_poll(struct bContext *C); int mask_paint_poll(struct bContext *C); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index dffb8c39bf2..e0b3905b30f 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -38,6 +38,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BLI_utildefines.h" #include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_context.h" diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 7385c2f0cf1..120d0a3b10a 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -467,7 +467,6 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_image_paint); WM_operatortype_append(PAINT_OT_sample_color); WM_operatortype_append(PAINT_OT_grab_clone); - WM_operatortype_append(PAINT_OT_clone_cursor_set); WM_operatortype_append(PAINT_OT_project_image); WM_operatortype_append(PAINT_OT_image_from_view); @@ -485,6 +484,7 @@ void ED_operatortypes_paint(void) /* vertex selection */ WM_operatortype_append(PAINT_OT_vert_select_all); + WM_operatortype_append(PAINT_OT_vert_select_ungrouped); /* vertex */ WM_operatortype_append(PAINT_OT_vertex_paint_toggle); @@ -533,7 +533,7 @@ static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path typedef enum { RC_COLOR = 1, RC_ROTATION = 2, - RC_ZOOM = 4, + RC_ZOOM = 4 } RCFlags; static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path, @@ -707,11 +707,17 @@ void ED_keymap_paint(wmKeyConfig *keyconf) ed_keymap_paint_brush_switch(keymap, "vertex_paint"); ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size"); - ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR); + ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR | RC_ROTATION); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */ RNA_string_set(kmi->ptr, "data_path", "vertex_paint_object.data.use_paint_mask"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.use_smooth_stroke"); + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random"); + /* Weight Paint mode */ keymap = WM_keymap_find(keyconf, "Weight Paint", 0, 0); keymap->poll = weight_paint_mode_poll; @@ -741,7 +747,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "PAINT_OT_weight_from_bones", WKEY, KM_PRESS, 0, 0); - + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.weight_paint.brush.use_smooth_stroke"); + /*Weight paint's Vertex Selection Mode */ keymap = WM_keymap_find(keyconf, "Weight Paint Vertex Selection", 0, 0); keymap->poll = vert_paint_poll; @@ -759,18 +767,24 @@ void ED_keymap_paint(wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Image Paint", 0, 0); keymap->poll = image_texture_paint_poll; - WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL); + RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT); WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "PAINT_OT_clone_cursor_set", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); ed_keymap_paint_brush_switch(keymap, "image_paint"); ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size"); - ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM); + ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */ RNA_string_set(kmi->ptr, "data_path", "image_paint_object.data.use_paint_mask"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.use_smooth_stroke"); + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random"); + /* face-mask mode */ keymap = WM_keymap_find(keyconf, "Face Mask", 0, 0); keymap->poll = facemask_paint_poll; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 5d9313485d2..8c5552f48bc 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -35,6 +35,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_rand.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -91,6 +92,12 @@ typedef struct PaintStroke { /* event that started stroke, for modal() return */ int event_type; + bool brush_init; + float initial_mouse[2]; + float cached_pressure; + + float zoom_2d; + StrokeGetLocation get_location; StrokeTestStart test_start; StrokeUpdateStep update_step; @@ -104,23 +111,21 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata Brush *brush = paint_brush(paint); PaintStroke *stroke = customdata; - glColor4ubv(paint->paint_cursor_col); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { - ARegion *ar = CTX_wm_region(C); - sdrawline(x, y, (int)stroke->last_mouse_position[0] - ar->winrct.xmin, - (int)stroke->last_mouse_position[1] - ar->winrct.ymin); + glColor4ubv(paint->paint_cursor_col); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + sdrawline(x, y, (int)stroke->last_mouse_position[0], + (int)stroke->last_mouse_position[1]); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); } - - glDisable(GL_BLEND); - glDisable(GL_LINE_SMOOTH); } /* if this is a tablet event, return tablet pressure and set *pen_flip * to 1 if the eraser tool is being used, 0 otherwise */ -static float event_tablet_data(wmEvent *event, int *pen_flip) +static float event_tablet_data(const wmEvent *event, int *pen_flip) { int erasor = 0; float pressure = 1; @@ -138,11 +143,105 @@ static float event_tablet_data(wmEvent *event, int *pen_flip) return pressure; } + +/* Initialize the stroke cache variants from operator properties */ +static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, + struct PaintStroke *stroke, + const float mouse[2], float pressure) +{ + Scene *scene = CTX_data_scene(C); + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + /* XXX: Use pressure value from first brush step for brushes which don't + * support strokes (grab, thumb). They depends on initial state and + * brush coord/pressure/etc. + * It's more an events design issue, which doesn't split coordinate/pressure/angle + * changing events. We should avoid this after events system re-design */ + if (paint_supports_dynamic_size(brush, mode) || !stroke->brush_init) { + copy_v2_v2(stroke->initial_mouse, mouse); + copy_v2_v2(ups->tex_mouse, mouse); + stroke->cached_pressure = pressure; + } + + /* Truly temporary data that isn't stored in properties */ + + ups->draw_pressure = TRUE; + ups->pressure_value = stroke->cached_pressure; + + ups->pixel_radius = BKE_brush_size_get(scene, brush); + + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) { + ups->pixel_radius *= stroke->cached_pressure; + } + + if (!(brush->flag & BRUSH_ANCHORED || + ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, + SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) + { + copy_v2_v2(ups->tex_mouse, mouse); + + if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) && + (brush->flag & BRUSH_RANDOM_ROTATION) && + !(brush->flag & BRUSH_RAKE)) + { + ups->brush_rotation = 2.0f * (float)M_PI * BLI_frand(); + } + } + + if (brush->flag & BRUSH_ANCHORED) { + bool hit = false; + float halfway[2]; + + const float dx = mouse[0] - stroke->initial_mouse[0]; + const float dy = mouse[1] - stroke->initial_mouse[1]; + + ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy); + + ups->brush_rotation = atan2(dx, dy) + M_PI; + + if (brush->flag & BRUSH_EDGE_TO_EDGE) { + float out[3]; + + halfway[0] = dx * 0.5f + stroke->initial_mouse[0]; + halfway[1] = dy * 0.5f + stroke->initial_mouse[1]; + + if (stroke->get_location) { + if (stroke->get_location(C, out, halfway)) { + hit = true; + } + } + else { + hit = true; + } + } + if (hit) { + copy_v2_v2(ups->anchored_initial_mouse, halfway); + copy_v2_v2(ups->tex_mouse, halfway); + ups->anchored_size /= 2.0f; + ups->pixel_radius /= 2.0f; + } + else + copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse); + + ups->draw_anchored = 1; + } + else if (brush->flag & BRUSH_RAKE) { + if (!stroke->brush_init) + copy_v2_v2(ups->last_rake, mouse); + else + paint_calculate_rake_rotation(ups, mouse); + } + + stroke->brush_init = TRUE; +} + + /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ -static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, const float mouse_in[2]) +static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const wmEvent *event, const float mouse_in[2]) { Scene *scene = CTX_data_scene(C); Paint *paint = paint_get_active_from_context(C); + PaintMode mode = paintmode_get_active_from_context(C); Brush *brush = paint_brush(paint); PaintStroke *stroke = op->customdata; float mouse_out[2]; @@ -154,19 +253,45 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev /* see if tablet affects event */ pressure = event_tablet_data(event, &pen_flip); +/* the following code is adapted from texture paint. It may not be needed but leaving here + * just in case for reference (code in texpaint removed as part of refactoring). + * It's strange that only texpaint had these guards. */ +#if 0 + /* special exception here for too high pressure values on first touch in + * windows for some tablets, then we just skip first touch .. */ + if (tablet && (pressure >= 0.99f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush))) + return; + + /* This can be removed once fixed properly in + * BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user) + * at zero pressure we should do nothing 1/2^12 is 0.0002 which is the sensitivity of the most sensitive pen tablet available */ + if (tablet && (pressure < 0.0002f) && ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) || BKE_brush_use_alpha_pressure(scene, pop->s.brush) || BKE_brush_use_size_pressure(scene, pop->s.brush))) + return; +#endif + + /* copy last position -before- jittering, or space fill code + * will create too many dabs */ + copy_v2_v2(stroke->last_mouse_position, mouse_in); + + paint_brush_update(C, brush, mode, stroke, mouse_in, pressure); + /* TODO: as sculpt and other paint modes are unified, this * separation will go away */ - if (stroke->vc.obact->sculpt) { + if (paint_supports_jitter(mode)) { float delta[2]; + float factor = stroke->zoom_2d; + + if (brush->flag & BRUSH_JITTER_PRESSURE) + factor *= pressure; BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out); /* XXX: meh, this is round about because * BKE_brush_jitter_pos isn't written in the best way to * be reused here */ - if (brush->flag & BRUSH_JITTER_PRESSURE) { + if (factor != 1.0f) { sub_v2_v2v2(delta, mouse_out, mouse_in); - mul_v2_fl(delta, pressure); + mul_v2_fl(delta, factor); add_v2_v2v2(mouse_out, mouse_in, delta); } } @@ -188,34 +313,25 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev RNA_boolean_set(&itemptr, "pen_flip", pen_flip); RNA_float_set(&itemptr, "pressure", pressure); - copy_v2_v2(stroke->last_mouse_position, mouse_out); - stroke->update_step(C, stroke, &itemptr); } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], - const PaintSample *sample) + const PaintSample *sample, PaintMode mode) { output[0] = sample->mouse[0]; output[1] = sample->mouse[1]; - if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) && - !ELEM4(stroke->brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK) && - !(stroke->brush->flag & BRUSH_ANCHORED) && - !(stroke->brush->flag & BRUSH_RESTORE_MESH)) - { + if (paint_supports_smooth_stroke(stroke->brush, mode)) { + float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; float dx = stroke->last_mouse_position[0] - sample->mouse[0]; float dy = stroke->last_mouse_position[1] - sample->mouse[1]; /* If the mouse is moving within the radius of the last move, * don't update the mouse position. This allows sharp turns. */ - if (dx * dx + dy * dy < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius) + if (dx * dx + dy * dy < radius * radius) return 0; output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u; @@ -227,12 +343,14 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], /* For brushes with stroke spacing enabled, moves mouse in steps * towards the final mouse location. */ -static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2]) +static int paint_space_stroke(bContext *C, wmOperator *op, const wmEvent *event, const float final_mouse[2]) { PaintStroke *stroke = op->customdata; + PaintMode mode = paintmode_get_active_from_context(C); + int cnt = 0; - if (paint_space_stroke_enabled(stroke->brush)) { + if (paint_space_stroke_enabled(stroke->brush, mode)) { float mouse[2]; float vec[2]; float length, scale; @@ -246,17 +364,28 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const const Scene *scene = CTX_data_scene(C); int steps; int i; - float pressure = 1.0f; + float size_pressure = 1.0f; + float pressure = event_tablet_data(event, NULL); /* XXX mysterious :) what has 'use size' do with this here... if you don't check for it, pressure fails */ if (BKE_brush_use_size_pressure(scene, stroke->brush)) - pressure = event_tablet_data(event, NULL); + size_pressure = pressure; - if (pressure > FLT_EPSILON) { + if (size_pressure > FLT_EPSILON) { /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel * causing very high step sizes, hanging blender [#32381] */ - const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * pressure); - scale = (size_clamp * stroke->brush->spacing / 50.0f) / length; + const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure); + float spacing = stroke->brush->spacing; + + /* stroke system is used for 2d paint too, so we need to account for + * the fact that brush can be scaled there. */ + + if (stroke->brush->flag & BRUSH_SPACING_PRESSURE) + spacing = max_ff(1.0f, spacing * (1.5f - pressure)); + + spacing *= stroke->zoom_2d; + + scale = (size_clamp * spacing / 50.0f) / length; if (scale > FLT_EPSILON) { mul_v2_fl(vec, scale); @@ -286,7 +415,8 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->brush = paint_brush(paint_get_active_from_context(C)); view3d_set_viewcontext(C, &stroke->vc); - view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats); + if (stroke->vc.v3d) + view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats); stroke->get_location = get_location; stroke->test_start = test_start; @@ -324,16 +454,77 @@ static void stroke_done(struct bContext *C, struct wmOperator *op) } /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */ -bool paint_space_stroke_enabled(Brush *br) +bool paint_space_stroke_enabled(Brush *br, PaintMode mode) +{ + return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode); +} + +/* return true if the brush size can change during paint (normally used for pressure) */ +bool paint_supports_dynamic_size(Brush *br, PaintMode mode) { - return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br); + if (br->flag & BRUSH_ANCHORED) + return false; + + switch (mode) { + case PAINT_SCULPT: + if (ELEM4(br->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK)) + { + return false; + } + default: + ; + } + return true; +} + +bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) +{ + if (!(br->flag & BRUSH_SMOOTH_STROKE) || + (br->flag & BRUSH_ANCHORED) || + (br->flag & BRUSH_RESTORE_MESH)) + { + return false; + } + + switch (mode) { + case PAINT_SCULPT: + if (ELEM4(br->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK)) + { + return false; + } + default: + ; + } + return true; } /* return true if the brush size can change during paint (normally used for pressure) */ -bool paint_supports_dynamic_size(Brush *br) +bool paint_supports_dynamic_tex_coords(Brush *br, PaintMode mode) { - return !(br->flag & BRUSH_ANCHORED) && - !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK); + if (br->flag & BRUSH_ANCHORED) + return false; + + switch (mode) { + case PAINT_SCULPT: + if (ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK)) + return false; + default: + ; + } + return true; +} + +bool paint_supports_jitter(PaintMode mode) +{ + return ELEM3(mode, PAINT_SCULPT, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); } #define PAINT_STROKE_MODAL_CANCEL 1 @@ -400,17 +591,22 @@ static void paint_stroke_sample_average(const PaintStroke *stroke, /*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/ } -int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { Paint *p = paint_get_active_from_context(C); + PaintMode mode = paintmode_get_active_from_context(C); PaintStroke *stroke = op->customdata; PaintSample sample_average; float mouse[2]; int first = 0; + float zoomx, zoomy; - paint_stroke_add_sample(p, stroke, event->x, event->y); + paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1]); paint_stroke_sample_average(stroke, &sample_average); + get_imapaint_zoom(C, &zoomx, &zoomy); + stroke->zoom_2d = max_ff(zoomx, zoomy); + /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously! * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it * since the 2D deltas are zero -- code in this file needs to be updated to use the @@ -452,8 +648,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) (event->type == TIMER && (event->customdata == stroke->timer)) ) { if (stroke->stroke_started) { - if (paint_smooth_stroke(stroke, mouse, &sample_average)) { - if (paint_space_stroke_enabled(stroke->brush)) { + if (paint_smooth_stroke(stroke, mouse, &sample_average, mode)) { + if (paint_space_stroke_enabled(stroke->brush, mode)) { if (!paint_space_stroke(C, op, event, mouse)) { //ED_region_tag_redraw(ar); } @@ -472,7 +668,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) * instead of waiting till we have moved the space distance */ if (first && stroke->stroke_started && - paint_space_stroke_enabled(stroke->brush) && + paint_space_stroke_enabled(stroke->brush, mode) && !(stroke->brush->flag & BRUSH_ANCHORED) && !(stroke->brush->flag & BRUSH_SMOOTH_STROKE)) { diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index dc3f310b405..5e88c7b5730 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -47,6 +47,7 @@ #include "BKE_context.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "RNA_access.h" #include "RNA_define.h" @@ -160,12 +161,12 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], Object *ob = vc->obact; float delta[3], scale, loc[3]; const float mval_f[2] = {pixel_radius, 0.0f}; + float zfac; mul_v3_m4v3(loc, ob->obmat, center); - initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); - - ED_view3d_win_to_delta(vc->ar, mval_f, delta); + zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL); + ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac); scale = fabsf(mat4_to_scale(ob->obmat)); scale = (scale == 0.0f) ? 1.0f : scale; @@ -414,7 +415,7 @@ void PAINT_OT_face_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int mode = RNA_boolean_get(op->ptr, "extend") ? 1 : 0; paintface_select_linked(C, CTX_data_active_object(C), event->mval, mode); @@ -484,6 +485,39 @@ void PAINT_OT_vert_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } + +static int vert_select_ungrouped_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + + if ((ob->defbase.first == NULL) || (me->dvert == NULL)) { + BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object"); + return OPERATOR_CANCELLED; + } + + paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), TRUE); + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; +} + +void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Ungrouped"; + ot->idname = "PAINT_OT_vert_select_ungrouped"; + ot->description = "Select vertices without a group"; + + /* api callbacks */ + ot->exec = vert_select_ungrouped_exec; + ot->poll = vert_paint_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); +} + static int face_select_hide_exec(bContext *C, wmOperator *op) { const int unselected = RNA_boolean_get(op->ptr, "unselected"); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 0277e1e11dc..2bdcda1430d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -43,6 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_math_color.h" #include "BLI_memarena.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -854,36 +855,46 @@ static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x } /* whats _dl mean? */ -static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float co[3], - const float mval[2], const float brush_size_pressure) +static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co[3], + const float mval[2], const float brush_size_pressure, float rgba[4]) { - float vertco[2]; + float co_ss[2]; /* screenspace */ if (ED_view3d_project_float_object(vc->ar, - co, vertco, + co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { float delta[2]; float dist_squared; - sub_v2_v2v2(delta, mval, vertco); + sub_v2_v2v2(delta, mval, co_ss); dist_squared = dot_v2v2(delta, delta); /* len squared */ if (dist_squared <= brush_size_pressure * brush_size_pressure) { Brush *brush = paint_brush(&vp->paint); const float dist = sqrtf(dist_squared); + if (brush->mtex.tex && rgba) { + if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { + BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL); + } + else { + const float co_ss_3d[3] = {co_ss[0], co_ss[1], 0.0f}; /* we need a 3rd empty value */ + BKE_brush_sample_tex_3D(vc->scene, brush, co_ss_3d, rgba, 0, NULL); + } + } return BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); } } - + if (rgba) + zero_v4(rgba); return 0.0f; } -static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc, +static float calc_vp_alpha_col_dl(VPaint *vp, ViewContext *vc, float vpimat[3][3], const DMCoNo *v_co_no, const float mval[2], - const float brush_size_pressure, const float brush_alpha_pressure) + const float brush_size_pressure, const float brush_alpha_pressure, float rgba[4]) { - float strength = calc_vp_strength_dl(vp, vc, v_co_no->co, mval, brush_size_pressure); + float strength = calc_vp_strength_col_dl(vp, vc, v_co_no->co, mval, brush_size_pressure, rgba); if (strength > 0.0f) { float alpha = brush_alpha_pressure * strength; @@ -1015,7 +1026,7 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev, /* sets wp->weight to the closest weight value to vertex */ /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ -static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; Mesh *me; @@ -1467,7 +1478,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, MDeformWeight *ndw; MDeformWeight *odw; - float changed_sum = 0.0f; + // float changed_sum = 0.0f; // UNUSED char *change_status; @@ -1496,7 +1507,7 @@ static void enforce_locks(MDeformVert *odv, MDeformVert *ndv, } else if (ndw->weight != odw->weight) { /* changed groups are handled here */ totchange += ndw->weight - odw->weight; - changed_sum += ndw->weight; + // changed_sum += ndw->weight; // UNUSED change_status[i] = 2; /* was altered already */ total_changed++; } /* unchanged, unlocked bone groups are handled here */ @@ -2239,11 +2250,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); RNA_float_get_array(itemptr, "mouse", mval); - mval[0] -= vc->ar->winrct.xmin; - mval[1] -= vc->ar->winrct.ymin; - - - /* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */ wpi.defbase_tot = wpd->defbase_tot; @@ -2312,7 +2318,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P #define WP_BLUR_ACCUM(v_idx_var) \ { \ const unsigned int vidx = v_idx_var; \ - const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); \ + const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \ if (fac > 0.0f) { \ MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \ paintweight += dw ? (dw->weight * fac) : 0.0f; \ @@ -2382,8 +2388,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P { \ unsigned int vidx = v_idx_var; \ if (me->dvert[vidx].flag) { \ - alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ - mval, brush_size_pressure, brush_alpha_pressure); \ + alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ + mval, brush_size_pressure, brush_alpha_pressure, NULL); \ if (alpha) { \ do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ } \ @@ -2480,7 +2486,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) } -static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; @@ -2667,6 +2673,8 @@ typedef struct VPaintData { /* mpoly -> mface mapping */ MemArena *polyfacemap_arena; ListBase *polyfacemap; + + bool is_texbrush; } VPaintData; static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me) @@ -2703,6 +2711,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl ToolSettings *ts = CTX_data_tool_settings(C); struct PaintStroke *stroke = op->customdata; VPaint *vp = ts->vpaint; + Brush *brush = paint_brush(&vp->paint); struct VPaintData *vpd; Object *ob = CTX_data_active_object(C); Mesh *me; @@ -2732,6 +2741,8 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const fl vpd->indexar = get_indexarray(me); vpd->paintcol = vpaint_get_current_col(vp); + vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && + brush->mtex.tex; /* are we painting onto a modified mesh?, * if not we can skip face map trickyness */ @@ -2808,12 +2819,24 @@ static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Mesh *me, ml = me->mloop + mpoly->loopstart; for (i = 0; i < mpoly->totloop; i++, ml++) { - alpha = calc_vp_alpha_dl(vp, vc, vpd->vpimat, + float rgba[4]; + unsigned int paintcol; + alpha = calc_vp_alpha_col_dl(vp, vc, vpd->vpimat, &vpd->vertexcosnos[ml->v], mval, - brush_size_pressure, brush_alpha_pressure); + brush_size_pressure, brush_alpha_pressure, rgba); + + if (vpd->is_texbrush) { + float rgba_br[3]; + rgb_uchar_to_float(rgba_br, (const unsigned char *)&vpd->paintcol); + mul_v3_v3(rgba_br, rgba); + rgb_float_to_uchar((unsigned char *)&paintcol, rgba_br); + } + else + paintcol = vpd->paintcol; + if (alpha > 0.0f) { const int alpha_i = (int)(alpha * 255.0f); - lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i); + lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], paintcol, alpha_i, brush_alpha_pressure_i); } } @@ -2872,10 +2895,6 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* load projection matrix */ mult_m4_m4m4(mat, vc->rv3d->persmat, ob->obmat); - mval[0] -= vc->ar->winrct.xmin; - mval[1] -= vc->ar->winrct.ymin; - - /* which faces are involved */ if (vp->flag & VP_AREA) { totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); @@ -2959,7 +2978,7 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) MEM_freeN(vpd); } -static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; @@ -3165,7 +3184,7 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], } } -static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *event) +static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event) { int ret = WM_gesture_straightline_modal(C, op, event); @@ -3273,7 +3292,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int ret; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 90e7645032b..376622e95a6 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -43,6 +43,8 @@ #include "BLI_threads.h" #include "BLI_rand.h" +#include "BLF_translation.h" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_types.h" @@ -243,7 +245,6 @@ typedef struct StrokeCache { float pressure; float mouse[2]; float bstrength; - float tex_mouse[2]; /* The rest is temporary storage that isn't saved as a property */ @@ -257,8 +258,8 @@ typedef struct StrokeCache { Brush *brush; float (*face_norms)[3]; /* Copy of the mesh faces' normals */ - float special_rotation; /* Texture rotation (radians) for anchored and rake modes */ - int pixel_radius, previous_pixel_radius; + + float special_rotation; float grab_delta[3], grab_delta_symmetry[3]; float old_grab_location[3], orig_grab_location[3]; @@ -282,8 +283,8 @@ typedef struct StrokeCache { int radial_symmetry_pass; float symm_rot_mat[4][4]; float symm_rot_mat_inv[4][4]; - float last_rake[2]; /* Last location of updating rake rotation */ int original; + float anchored_location[3]; float vertex_rotation; @@ -316,8 +317,8 @@ typedef struct { /* Initialize a SculptOrigVertData for accessing original vertex data; * handles BMesh, mesh, and multires */ static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, - Object *ob, - SculptUndoNode *unode) + Object *ob, + SculptUndoNode *unode) { SculptSession *ss = ob->sculpt; BMesh *bm = ss->bm; @@ -338,19 +339,18 @@ static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, /* Initialize a SculptOrigVertData for accessing original vertex data; * handles BMesh, mesh, and multires */ static void sculpt_orig_vert_data_init(SculptOrigVertData *data, - Object *ob, - PBVHNode *node) + Object *ob, + PBVHNode *node) { SculptUndoNode *unode; unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS); sculpt_orig_vert_data_unode_init(data, ob, unode); - } /* Update a SculptOrigVertData for a particular vertex from the PBVH * iterator */ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, - PBVHVertexIter *iter) + PBVHVertexIter *iter) { if (orig_data->unode->type == SCULPT_UNDO_COORDS) { if (orig_data->coords) { @@ -387,30 +387,30 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, Others, like smooth, are better without. Same goes for alt- key smoothing. */ static int sculpt_stroke_dynamic_topology(const SculptSession *ss, - const Brush *brush) + const Brush *brush) { return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) && - (!ss->cache || (!ss->cache->alt_smooth)) && - - /* Requires mesh restore, which doesn't work with - * dynamic-topology */ - !(brush->flag & BRUSH_ANCHORED) && - !(brush->flag & BRUSH_RESTORE_MESH) && + (!ss->cache || (!ss->cache->alt_smooth)) && - (!ELEM6(brush->sculpt_tool, - /* These brushes, as currently coded, cannot - * support dynamic topology */ - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER, + /* Requires mesh restore, which doesn't work with + * dynamic-topology */ + !(brush->flag & BRUSH_ANCHORED) && + !(brush->flag & BRUSH_RESTORE_MESH) && + + (!ELEM6(brush->sculpt_tool, + /* These brushes, as currently coded, cannot + * support dynamic topology */ + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER, - /* These brushes could handle dynamic topology, - * but user feedback indicates it's better not - * to */ - SCULPT_TOOL_SMOOTH, - SCULPT_TOOL_MASK))); + /* These brushes could handle dynamic topology, + * but user feedback indicates it's better not + * to */ + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_MASK))); } /*** paint mesh ***/ @@ -439,7 +439,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) for (n = 0; n < totnode; n++) { SculptUndoNode *unode; SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ? - SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); + SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); if (ss->bm) { unode = sculpt_undo_push_node(ob, nodes[n], type); @@ -545,13 +545,32 @@ typedef struct SculptBrushTest { float radius_squared; float location[3]; float dist; + + /* View3d clipping - only set rv3d for clipping */ + RegionView3D *clip_rv3d; } SculptBrushTest; static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { + RegionView3D *rv3d = ss->cache->vc->rv3d; + test->radius_squared = ss->cache->radius_squared; copy_v3_v3(test->location, ss->cache->location); test->dist = 0.0f; /* just for initialize */ + + + if (rv3d->rflag & RV3D_CLIPPING) { + test->clip_rv3d = rv3d; + } + else { + test->clip_rv3d = NULL; + } +} + +BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3]) +{ + RegionView3D *rv3d = test->clip_rv3d; + return (rv3d && (ED_view3d_clipping_test(rv3d, co, true))); } static int sculpt_brush_test(SculptBrushTest *test, const float co[3]) @@ -559,6 +578,9 @@ static int sculpt_brush_test(SculptBrushTest *test, const float co[3]) float distsq = len_squared_v3v3(co, test->location); if (distsq <= test->radius_squared) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } test->dist = sqrt(distsq); return 1; } @@ -572,6 +594,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) float distsq = len_squared_v3v3(co, test->location); if (distsq <= test->radius_squared) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } test->dist = distsq; return 1; } @@ -582,6 +607,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3]) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } return len_squared_v3v3(co, test->location) <= test->radius_squared; } @@ -590,6 +618,10 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca float side = M_SQRT1_2; float local_co[3]; + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } + mul_v3_m4v3(local_co, local, co); local_co[0] = fabs(local_co[0]); @@ -890,25 +922,22 @@ static float tex_strength(SculptSession *ss, Brush *br, const float fno[3], const float mask) { + const Scene *scene = ss->cache->vc->scene; MTex *mtex = &br->mtex; float avg = 1; + float rgba[4]; if (!mtex->tex) { avg = 1; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { - float jnk; - /* Get strength by feeding the vertex * location directly into a texture */ - externtex(mtex, point, &avg, - &jnk, &jnk, &jnk, &jnk, 0, ss->tex_pool); + avg = BKE_brush_sample_tex_3D(scene, br, point, rgba, 0, ss->tex_pool); } else if (ss->texcache) { - float rotation = -mtex->rot; float symm_point[3], point_2d[2]; float x = 0.0f, y = 0.0f; /* Quite warnings */ - float radius = 1.0f; /* Quite warnings */ /* if the active area is being applied for symmetry, flip it * across the symmetry axis and rotate it back to the original @@ -922,77 +951,33 @@ static float tex_strength(SculptSession *ss, Brush *br, ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat); - if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { - /* keep coordinates relative to mouse */ - - rotation += ss->cache->special_rotation; - - point_2d[0] -= ss->cache->tex_mouse[0]; - point_2d[1] -= ss->cache->tex_mouse[1]; - - /* use pressure adjusted size for fixed mode */ - radius = ss->cache->pixel_radius; - - x = point_2d[0] + ss->cache->vc->ar->winrct.xmin; - y = point_2d[1] + ss->cache->vc->ar->winrct.ymin; - } - else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { - /* leave the coordinates relative to the screen */ - - /* use unadjusted size for tiled mode */ - radius = BKE_brush_size_get(ss->cache->vc->scene, br); - - x = point_2d[0]; - y = point_2d[1]; - } - else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { + /* still no symmetry supported for other paint modes. + * Sculpt does it DIY */ + if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { /* Similar to fixed mode, but projects from brush angle * rather than view direction */ - /* Rotation is handled by the brush_local_mat */ - rotation = 0; - mul_m4_v3(ss->cache->brush_local_mat, symm_point); x = symm_point[0]; y = symm_point[1]; - } - if (mtex->brush_map_mode != MTEX_MAP_MODE_AREA) { - x /= ss->cache->vc->ar->winx; - y /= ss->cache->vc->ar->winy; + x *= br->mtex.size[0]; + y *= br->mtex.size[1]; - if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { - x -= 0.5f; - y -= 0.5f; - } - - x *= ss->cache->vc->ar->winx / radius; - y *= ss->cache->vc->ar->winy / radius; - } + x += br->mtex.ofs[0]; + y += br->mtex.ofs[1]; - /* it is probably worth optimizing for those cases where - * the texture is not rotated by skipping the calls to - * atan2, sqrtf, sin, and cos. */ - if (rotation > 0.001f || rotation < -0.001f) { - const float angle = atan2f(y, x) + rotation; - const float flen = sqrtf(x * x + y * y); + avg = paint_get_tex_pixel(br, x, y, ss->tex_pool); - x = flen * cosf(angle); - y = flen * sinf(angle); + avg += br->texture_sample_bias; + } + else { + const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; + avg = BKE_brush_sample_tex_3D(scene, br, point_3d, rgba, 0, ss->tex_pool); } - - x *= br->mtex.size[0]; - y *= br->mtex.size[1]; - - x += br->mtex.ofs[0]; - y += br->mtex.ofs[1]; - - avg = paint_get_tex_pixel(br, x, y, ss->tex_pool); } - avg += br->texture_sample_bias; - /* Falloff curve */ avg *= BKE_brush_curve_strength(br, len, ss->cache->radius); @@ -1203,11 +1188,12 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3]) { Object *ob = vc->obact; float loc[3], mval_f[2] = {0.0f, 1.0f}; + float zfac; mul_v3_m4v3(loc, ob->imat, center); - initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); + zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL); - ED_view3d_win_to_delta(vc->ar, mval_f, y); + ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac); normalize_v3(y); add_v3_v3(y, ob->loc); @@ -3173,8 +3159,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) if (use_orco) { if (ss->bm) { copy_v3_v3(val, - BM_log_original_vert_co(ss->bm_log, - vd.bm_vert)); + BM_log_original_vert_co(ss->bm_log, + vd.bm_vert)); } else copy_v3_v3(val, orco[vd.i]); @@ -3342,7 +3328,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) } static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, - BrushActionFunc action) + BrushActionFunc action) { Brush *brush = paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3480,7 +3466,9 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, } } } - else free_sculptsession_deformMats(ss); + else { + free_sculptsession_deformMats(ss); + } /* if pbvh is deformed, key block is already applied to it */ if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) { @@ -3673,27 +3661,28 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio Brush *brush = paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); + float rot[3][3], scale[3], loc[3]; int i; int mode; ss->cache = cache; /* Set scaling adjustment */ - ss->cache->scale[0] = 1.0f / ob->size[0]; - ss->cache->scale[1] = 1.0f / ob->size[1]; - ss->cache->scale[2] = 1.0f / ob->size[2]; + cache->scale[0] = 1.0f / ob->size[0]; + cache->scale[1] = 1.0f / ob->size[1]; + cache->scale[2] = 1.0f / ob->size[2]; - ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; + cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; - ss->cache->flag = 0; + cache->flag = 0; sculpt_init_mirror_clipping(ob, ss); /* Initial mouse location */ if (mouse) - copy_v2_v2(ss->cache->initial_mouse, mouse); + copy_v2_v2(cache->initial_mouse, mouse); else - zero_v2(ss->cache->initial_mouse); + zero_v2(cache->initial_mouse); mode = RNA_enum_get(op->ptr, "mode"); cache->invert = mode == BRUSH_STROKE_INVERT; @@ -3705,7 +3694,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio else brush->flag &= ~BRUSH_INVERTED; /* Alt-Smooth */ - if (ss->cache->alt_smooth) { + if (cache->alt_smooth) { if (brush->sculpt_tool == SCULPT_TOOL_MASK) { cache->saved_mask_brush_tool = brush->mask_tool; brush->mask_tool = BRUSH_MASK_SMOOTH; @@ -3726,7 +3715,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio } copy_v2_v2(cache->mouse, cache->initial_mouse); - copy_v2_v2(cache->tex_mouse, cache->initial_mouse); + copy_v2_v2(ups->tex_mouse, cache->initial_mouse); /* Truly temporary data that isn't stored in properties */ @@ -3737,7 +3726,12 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); + mat4_to_loc_rot_size(loc, rot, scale, ob->obmat); + /* transposing an orthonormal matrix inverts */ + transpose_m3(rot); ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); + /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */ + mul_m3_v3(rot, cache->true_view_normal); /* Initialize layer brush displacements and persistent coords */ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { /* not supported yet for multires or dynamic topology */ @@ -3748,7 +3742,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy"); - if (ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert); + if (ss->deform_cos) { + memcpy(ss->layer_co, ss->deform_cos, ss->totvert); + } else { for (i = 0; i < ss->totvert; ++i) { copy_v3_v3(ss->layer_co[i], ss->mvert[i].co); @@ -3779,8 +3775,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio } } - cache->special_rotation = (brush->flag & BRUSH_RAKE) ? ups->last_angle : 0; - cache->first_time = 1; cache->vertex_rotation = 0; @@ -3793,8 +3787,8 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; float mouse[2] = { - cache->mouse[0] - cache->vc->ar->winrct.xmin, - cache->mouse[1] - cache->vc->ar->winrct.ymin + cache->mouse[0], + cache->mouse[1] }; int tool = brush->sculpt_tool; @@ -3814,8 +3808,6 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* compute 3d coordinate at same z from original location + mouse */ mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); - initgrabz(cache->vc->rv3d, loc[0], loc[1], loc[2]); - ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location); /* compute delta to move verts by */ @@ -3853,9 +3845,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru copy_v3_v3(cache->old_grab_location, grab_location); if (tool == SCULPT_TOOL_GRAB) - copy_v3_v3(ups->anchored_location, cache->true_location); + copy_v3_v3(cache->anchored_location, cache->true_location); else if (tool == SCULPT_TOOL_THUMB) - copy_v3_v3(ups->anchored_location, cache->orig_grab_location); + copy_v3_v3(cache->anchored_location, cache->orig_grab_location); if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) { /* location stays the same for finding vertices in brush radius */ @@ -3863,7 +3855,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru ups->draw_anchored = 1; copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); - ups->anchored_size = cache->pixel_radius; + ups->anchored_size = ups->pixel_radius; } } } @@ -3898,18 +3890,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, * brush coord/pressure/etc. * It's more an events design issue, which doesn't split coordinate/pressure/angle * changing events. We should avoid this after events system re-design */ - if (paint_supports_dynamic_size(brush) || cache->first_time) { + if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) { cache->pressure = RNA_float_get(ptr, "pressure"); } /* Truly temporary data that isn't stored in properties */ - - ups->draw_pressure = 1; - ups->pressure_value = cache->pressure; - - cache->previous_pixel_radius = cache->pixel_radius; - cache->pixel_radius = BKE_brush_size_get(scene, brush); - if (cache->first_time) { if (!BKE_brush_use_locked_size(scene, brush)) { cache->initial_radius = paint_calc_object_space_radius(cache->vc, @@ -3922,8 +3907,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, } } - if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush)) { - cache->pixel_radius *= cache->pressure; + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) { cache->radius = cache->initial_radius * cache->pressure; } else { @@ -3932,77 +3916,25 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, cache->radius_squared = cache->radius * cache->radius; - if (!(brush->flag & BRUSH_ANCHORED || - ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, - SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) - { - copy_v2_v2(cache->tex_mouse, cache->mouse); - - if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) && - (brush->flag & BRUSH_RANDOM_ROTATION) && - !(brush->flag & BRUSH_RAKE)) - { - cache->special_rotation = 2.0f * (float)M_PI * BLI_frand(); - } - } - if (brush->flag & BRUSH_ANCHORED) { - int hit = 0; - - const float dx = cache->mouse[0] - cache->initial_mouse[0]; - const float dy = cache->mouse[1] - cache->initial_mouse[1]; - - ups->anchored_size = cache->pixel_radius = sqrt(dx * dx + dy * dy); - - cache->special_rotation = atan2(dx, dy) + M_PI; - if (brush->flag & BRUSH_EDGE_TO_EDGE) { float halfway[2]; float out[3]; - - halfway[0] = dx * 0.5f + cache->initial_mouse[0]; - halfway[1] = dy * 0.5f + cache->initial_mouse[1]; + halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]); + halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]); if (sculpt_stroke_get_location(C, out, halfway)) { - copy_v3_v3(ups->anchored_location, out); - copy_v2_v2(ups->anchored_initial_mouse, halfway); - copy_v2_v2(cache->tex_mouse, halfway); - copy_v3_v3(cache->true_location, ups->anchored_location); - ups->anchored_size /= 2.0f; - cache->pixel_radius /= 2.0f; - hit = 1; + copy_v3_v3(cache->anchored_location, out); + copy_v3_v3(cache->true_location, cache->anchored_location); } } - if (!hit) - copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); - cache->radius = paint_calc_object_space_radius(paint_stroke_view_context(stroke), cache->true_location, - cache->pixel_radius); + ups->pixel_radius); cache->radius_squared = cache->radius * cache->radius; - copy_v3_v3(ups->anchored_location, cache->true_location); - - ups->draw_anchored = 1; - } - else if (brush->flag & BRUSH_RAKE) { - const float u = 0.5f; - const float v = 1 - u; - const float r = 20; - - const float dx = cache->last_rake[0] - cache->mouse[0]; - const float dy = cache->last_rake[1] - cache->mouse[1]; - - if (cache->first_time) { - copy_v2_v2(cache->last_rake, cache->mouse); - } - else if (dx * dx + dy * dy >= r * r) { - cache->special_rotation = atan2(dx, dy); - - cache->last_rake[0] = u * cache->last_rake[0] + v * cache->mouse[0]; - cache->last_rake[1] = u * cache->last_rake[1] + v * cache->mouse[1]; - } + copy_v3_v3(cache->anchored_location, cache->true_location); } sculpt_update_brush_delta(ups, ob, brush); @@ -4015,14 +3947,14 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, ups->draw_anchored = 1; copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); - copy_v3_v3(ups->anchored_location, cache->true_location); - ups->anchored_size = cache->pixel_radius; + copy_v3_v3(cache->anchored_location, cache->true_location); + ups->anchored_size = ups->pixel_radius; } - ups->special_rotation = cache->special_rotation; + cache->special_rotation = ups->brush_rotation; } -/* Returns true iff any of the smoothing modes are active (currently +/* Returns true if any of the smoothing modes are active (currently * one of smooth brush, autosmooth, mask smooth, or shift-key * smooth) */ static int sculpt_any_smooth_mode(const Brush *brush, @@ -4098,7 +4030,6 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) StrokeCache *cache; float ray_start[3], ray_end[3], ray_normal[3], dist; float obimat[4][4]; - float mval[2]; SculptRaycastData srd; view3d_set_viewcontext(C, &vc); @@ -4109,11 +4040,8 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) sculpt_stroke_modifiers_check(C, ob); - mval[0] = mouse[0] - vc.ar->winrct.xmin; - mval[1] = mouse[1] - vc.ar->winrct.ymin; - /* TODO: what if the segment is totally clipped? (return == 0) */ - ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mval, ray_start, ray_end); + ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mouse, ray_start, ray_end); invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); @@ -4279,6 +4207,7 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; @@ -4289,9 +4218,9 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P sculpt_restore_mesh(sd, ob); BKE_pbvh_bmesh_detail_size_set(ss->pbvh, - (ss->cache->radius / - (float)ss->cache->pixel_radius) * - (float)sd->detail_size); + (ss->cache->radius / + (float)ups->pixel_radius) * + (float)sd->detail_size); if (sculpt_stroke_dynamic_topology(ss, brush)) { do_symmetrical_brush_actions(sd, ob, sculpt_topology_update); @@ -4335,7 +4264,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str /* reset values used to draw brush after completing the stroke */ ups->draw_anchored = 0; ups->draw_pressure = 0; - ups->special_rotation = 0; /* Finished */ if (ss->cache) { @@ -4390,7 +4318,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_brush_exit_tex(sd); } -static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { struct PaintStroke *stroke; int ignore_background_click; @@ -4407,8 +4335,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even op->customdata = stroke; /* For tablet rotation */ - ignore_background_click = RNA_boolean_get(op->ptr, - "ignore_background_click"); + ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) { paint_stroke_data_free(op); @@ -4487,8 +4414,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* properties */ - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, - "Stroke", ""); + RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Sculpt Stroke Mode", @@ -4570,7 +4496,7 @@ void sculpt_dynamic_topology_enable(bContext *C) sculpt_pbvh_clear(ob); ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & - SCULPT_DYNTOPO_SMOOTH_SHADING); + SCULPT_DYNTOPO_SMOOTH_SHADING); /* Create triangles-only BMesh */ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); @@ -4596,7 +4522,7 @@ void sculpt_dynamic_topology_enable(bContext *C) * If 'unode' is given, the BMesh's data is copied out to the unode * before the BMesh is deleted so that it can be restored from */ void sculpt_dynamic_topology_disable(bContext *C, - SculptUndoNode *unode) + SculptUndoNode *unode) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; @@ -4619,13 +4545,13 @@ void sculpt_dynamic_topology_disable(bContext *C, me->totedge = unode->bm_enter_totedge; me->totface = 0; CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH, - CD_DUPLICATE, unode->bm_enter_totvert); + CD_DUPLICATE, unode->bm_enter_totvert); CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH, - CD_DUPLICATE, unode->bm_enter_totedge); + CD_DUPLICATE, unode->bm_enter_totedge); CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH, - CD_DUPLICATE, unode->bm_enter_totloop); + CD_DUPLICATE, unode->bm_enter_totloop); CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH, - CD_DUPLICATE, unode->bm_enter_totpoly); + CD_DUPLICATE, unode->bm_enter_totpoly); mesh_update_customdata_pointers(me, FALSE); } @@ -4665,28 +4591,23 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o return OPERATOR_FINISHED; } -static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, - wmEvent *UNUSED(event)) +static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; SculptSession *ss = ob->sculpt; - const char *msg = "Dynamic-topology sculpting will not preserve" - "vertex colors, UVs, or other customdata"; + const char *msg = TIP_("Dynamic-topology sculpting will not preserve vertex colors, UVs, or other customdata"); if (!ss->bm) { int i; for (i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, - CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, - CD_ORIGINDEX) && + if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && (CustomData_has_layer(&me->vdata, i) || CustomData_has_layer(&me->edata, i) || CustomData_has_layer(&me->fdata, i))) { - /* The mesh has customdata that will be lost, let the - * user confirm this is OK */ + /* The mesh has customdata that will be lost, let the user confirm this is OK */ return WM_operator_confirm_message(C, op, msg); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index fa1bdd6ca82..82a07c9e3be 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -62,9 +62,6 @@ int sculpt_poll(struct bContext *C); void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_pmap, int need_mask); -/* Deformed mesh sculpt */ -void free_sculptsession_deformMats(struct SculptSession *ss); - /* Stroke */ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 406756f4197..2cc09ea2aa9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -131,7 +131,9 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo vertCos = BKE_key_convert_to_vertcos(ob, ss->kb); for (i = 0; i < unode->totvert; i++) { - if (ss->modifiers_active) sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]); + if (ss->modifiers_active) { + sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]); + } else { if (unode->orig_co) swap_v3_v3(vertCos[index[i]], unode->orig_co[i]); else swap_v3_v3(vertCos[index[i]], unode->co[i]); @@ -149,7 +151,9 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo } else { for (i = 0; i < unode->totvert; i++) { - if (ss->modifiers_active) sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); + if (ss->modifiers_active) { + sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co); + } else { if (unode->orig_co) swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]); else swap_v3_v3(mvert[index[i]].co, unode->co[i]); @@ -263,8 +267,8 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode } static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, - Object *ob, - SculptSession *ss) + Object *ob, + SculptSession *ss) { if (unode->applied) { BM_log_undo(ss->bm, ss->bm_log); @@ -282,7 +286,7 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, /* Create empty sculpt BMesh and enable logging */ static void sculpt_undo_bmesh_enable(Object *ob, - SculptUndoNode *unode) + SculptUndoNode *unode) { SculptSession *ss = ob->sculpt; Mesh *me = ob->data; @@ -296,13 +300,13 @@ static void sculpt_undo_bmesh_enable(Object *ob, /* Restore the BMLog using saved entries */ ss->bm_log = BM_log_from_existing_entries_create(ss->bm, - unode->bm_entry); + unode->bm_entry); } static void sculpt_undo_bmesh_restore_begin(bContext *C, - SculptUndoNode *unode, - Object *ob, - SculptSession *ss) + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) { if (unode->applied) { sculpt_dynamic_topology_disable(C, unode); @@ -319,9 +323,9 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C, } static void sculpt_undo_bmesh_restore_end(bContext *C, - SculptUndoNode *unode, - Object *ob, - SculptSession *ss) + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) { if (unode->applied) { sculpt_undo_bmesh_enable(ob, unode); @@ -343,9 +347,9 @@ static void sculpt_undo_bmesh_restore_end(bContext *C, * Returns TRUE if this was a dynamic-topology undo step, otherwise * returns FALSE to indicate the non-dyntopo code should run. */ static int sculpt_undo_bmesh_restore(bContext *C, - SculptUndoNode *unode, - Object *ob, - SculptSession *ss) + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) { switch (unode->type) { case SCULPT_UNDO_DYNTOPO_BEGIN: @@ -375,7 +379,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) DerivedMesh *dm; SculptSession *ss = ob->sculpt; SculptUndoNode *unode; - MultiresModifierData *mmd; int update = FALSE, rebuild = FALSE; int need_mask = FALSE; @@ -446,7 +449,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL); - if ((mmd = sculpt_multires_active(scene, ob))) { + if (sculpt_multires_active(scene, ob)) { if (rebuild) multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); else @@ -563,7 +566,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, if (node) { BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, - &maxgrid, &gridsize, NULL, NULL); + &maxgrid, &gridsize, NULL, NULL); unode->totvert = totvert; } @@ -673,8 +676,8 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode) } static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, - PBVHNode *node, - SculptUndoType type) + PBVHNode *node, + SculptUndoType type) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); SculptUndoNode *unode = lb->first; @@ -701,13 +704,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, * (converting polys to triangles) that the BMLog can't * fully restore from */ CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH, - CD_DUPLICATE, me->totvert); + CD_DUPLICATE, me->totvert); CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH, - CD_DUPLICATE, me->totedge); + CD_DUPLICATE, me->totedge); CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH, - CD_DUPLICATE, me->totloop); + CD_DUPLICATE, me->totloop); CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH, - CD_DUPLICATE, me->totpoly); + CD_DUPLICATE, me->totpoly); unode->bm_enter_totvert = me->totvert; unode->bm_enter_totedge = me->totedge; unode->bm_enter_totloop = me->totloop; @@ -756,9 +759,9 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, BLI_lock_thread(LOCK_CUSTOM1); if (ss->bm || - ELEM(type, - SCULPT_UNDO_DYNTOPO_BEGIN, - SCULPT_UNDO_DYNTOPO_END)) + ELEM(type, + SCULPT_UNDO_DYNTOPO_BEGIN, + SCULPT_UNDO_DYNTOPO_END)) { /* Dynamic topology stores only one undo node per stroke, * regardless of the number of PBVH nodes modified */ diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 0bcccd9479c..7cdfb6d22b2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -144,6 +144,69 @@ typedef struct UvSculptData { char invert; } UvSculptData; + +static Brush *uv_sculpt_brush(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + ToolSettings *settings = scene->toolsettings; + + if (!settings->uvsculpt) + return NULL; + return paint_brush(&settings->uvsculpt->paint); +} + + +static int uv_sculpt_brush_poll(bContext *C) +{ + BMEditMesh *em; + int ret; + Object *obedit = CTX_data_edit_object(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *toolsettings = scene->toolsettings; + + if (!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH) + return 0; + + em = BMEdit_FromObject(obedit); + ret = EDBM_mtexpoly_check(em); + + if (ret && sima) { + ARegion *ar = CTX_wm_region(C); + if ((toolsettings->use_uv_sculpt) && ar->regiontype == RGN_TYPE_WINDOW) + return 1; + } + + return 0; +} + + +void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings) +{ + if (settings->use_uv_sculpt) { + if (!settings->uvsculpt) { + settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint"); + settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB; + settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS; + settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN; + } + + BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); + + WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, + brush_drawcursor_texpaint_uvsculpt, NULL); + } + else { + if (settings->uvsculpt) + settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH; + } +} + +int uv_sculpt_poll(bContext *C) +{ + return uv_sculpt_brush_poll(C); +} + /*********** Improved Laplacian Relaxation Operator ************************/ /* original code by Raul Fernandez Hernandez "farsthary" * * adapted to uv smoothing by Antony Riakiatakis * @@ -294,7 +357,7 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *scul } -static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, Object *obedit) +static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit) { float co[2], radius, radius_root; Scene *scene = CTX_data_scene(C); @@ -464,7 +527,7 @@ static int uv_edge_compare(const void *a, const void *b) } -static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent *event) +static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -649,7 +712,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent return NULL; } /* fill the edges with data */ - for (i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) { + for (i = 0; BLI_ghashIterator_notDone(ghi); BLI_ghashIterator_step(ghi)) { data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi)); } data->totalUvEdges = BLI_ghash_size(edgeHash); @@ -731,7 +794,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent return op->customdata; } -static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { UvSculptData *data; Object *obedit = CTX_data_edit_object(C); @@ -754,7 +817,7 @@ static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) } -static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { UvSculptData *data = (UvSculptData *)op->customdata; Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index eb138bfeeef..d25fd00514c 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -160,7 +160,7 @@ static int sound_open_exec(bContext *UNUSED(C), wmOperator *op) #endif -static int sound_open_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sound_open_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (RNA_struct_property_is_set(op->ptr, "filepath")) return sound_open_exec(C, op); @@ -439,7 +439,7 @@ static int sound_mixdown_check(bContext *UNUSED(C), wmOperator *op) #endif // WITH_AUDASPACE -static int sound_mixdown_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (RNA_struct_property_is_set(op->ptr, "filepath")) return sound_mixdown_exec(C, op); @@ -747,7 +747,7 @@ static int sound_unpack_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sound_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Editing *ed = CTX_data_scene(C)->ed; bSound *sound; diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 7e99e6c065d..803e7b71c77 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -742,7 +742,7 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { actkeys_duplicate_exec(C, op); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 964a6a20c37..b6d2d31f0ad 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -872,7 +872,7 @@ static int actkeys_select_leftright_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; short leftright = RNA_enum_get(op->ptr, "mode"); @@ -1223,7 +1223,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ } /* handle clicking */ -static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; /* ARegion *ar; */ /* UNUSED */ @@ -1264,16 +1264,17 @@ void ACTION_OT_clickselect(wmOperatorType *ot) ot->idname = "ACTION_OT_clickselect"; ot->description = "Select keyframes by clicking on them"; - /* api callbacks - absolutely no exec() this yet... */ + /* callbacks */ ot->invoke = actkeys_clickselect_invoke; ot->poll = ED_operator_action_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "column", 0, "Column Select", ""); // ALTKEY RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 8b6682ff1c9..dcc61cfa544 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -35,10 +35,10 @@ #include "DNA_userdef_types.h" +#include "BLI_utildefines.h" #include "BLI_fileops.h" #include "BLI_path_util.h" #include "BLI_string.h" -#include "BLI_utildefines.h" #include "BLF_translation.h" @@ -62,7 +62,7 @@ /********************** toolbox operator *********************/ -static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { bScreen *sc = CTX_wm_screen(C); SpaceButs *sbuts = CTX_wm_space_buts(C); @@ -113,7 +113,6 @@ static int file_browse_exec(bContext *C, wmOperator *op) /* add slash for directories, important for some properties */ if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) { - char name[FILE_MAX]; int is_relative = RNA_boolean_get(op->ptr, "relative_path"); id = fbo->ptr.id.data; @@ -132,8 +131,10 @@ static int file_browse_exec(bContext *C, wmOperator *op) } BLI_add_slash(str); } - else - BLI_splitdirstring(str, name); + else { + char * const lslash = (char *)BLI_last_slash(str); + if (lslash) lslash[1] = '\0'; + } } RNA_property_string_set(&fbo->ptr, fbo->prop, str); @@ -164,7 +165,7 @@ static int file_browse_cancel(bContext *UNUSED(C), wmOperator *op) return OPERATOR_CANCELLED; } -static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) { PointerRNA ptr; PropertyRNA *prop; @@ -189,7 +190,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, wmEvent *event) PointerRNA props_ptr; if (event->alt) { - char *lslash = BLI_last_slash(str); + char *lslash = (char *)BLI_last_slash(str); if (lslash) *lslash = '\0'; } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 16d194d0929..1643921e4dd 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -404,7 +404,7 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C) } /* create button */ - BLI_snprintf(name, UI_MAX_NAME_STR, "%s", user->name); + BLI_strncpy(name, user->name, UI_MAX_NAME_STR); if (user->icon) { but = uiDefIconTextMenuBut(block, template_texture_user_menu, NULL, diff --git a/source/blender/editors/space_clip/SConscript b/source/blender/editors/space_clip/SConscript index c65a076186f..840a3b49f2b 100644 --- a/source/blender/editors/space_clip/SConscript +++ b/source/blender/editors/space_clip/SConscript @@ -34,5 +34,8 @@ incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): + incs += ' ' + env['BF_PTHREADS_INC'] env.BlenderLib ( 'bf_editors_space_clip', sources, Split(incs), defs, libtype=['core'], priority=[95] ) diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c index 09f6271b6ef..e5cd7247c43 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_ops.c +++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c @@ -59,12 +59,11 @@ #include "clip_intern.h" // own include -#if 0 -static int ED_space_clip_dopesheet_poll(bContext *C) +static int space_clip_dopesheet_poll(bContext *C) { - SpaceClip *sc = CTX_wm_space_clip(C); + if (ED_space_clip_tracking_poll(C)) { + SpaceClip *sc = CTX_wm_space_clip(C); - if (sc && sc->clip) { if (sc->view == SC_VIEW_DOPESHEET) { ARegion *ar = CTX_wm_region(C); @@ -74,7 +73,6 @@ static int ED_space_clip_dopesheet_poll(bContext *C) return FALSE; } -#endif /********************** select channel operator *********************/ @@ -129,7 +127,7 @@ static int dopesheet_select_channel_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int dopesheet_select_channel_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int dopesheet_select_channel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float location[2]; @@ -161,3 +159,54 @@ void CLIP_OT_dopesheet_select_channel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection rather than clearing the existing selection"); } + +/********************** View All operator *********************/ + +static int dopesheet_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + View2D *v2d = &ar->v2d; + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; + MovieTrackingDopesheetChannel *channel; + int frame_min = INT_MAX, frame_max = INT_MIN; + + for (channel = dopesheet->channels.first; channel; channel = channel->next) { + frame_min = min_ii(frame_min, channel->segments[0]); + frame_max = max_ii(frame_max, channel->segments[channel->tot_segment]); + } + + if (frame_min < frame_max) { + float extra; + + v2d->cur.xmin = frame_min; + v2d->cur.xmax = frame_max; + + /* we need an extra "buffer" factor on either side so that the endpoints are visible */ + extra = 0.01f * BLI_rctf_size_x(&v2d->cur); + v2d->cur.xmin -= extra; + v2d->cur.xmax += extra; + + ED_region_tag_redraw(ar); + } + + + return OPERATOR_FINISHED; +} + +void CLIP_OT_dopesheet_view_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View All"; + ot->description = "Reset viewable area to show full keyframe range"; + ot->idname = "CLIP_OT_dopesheet_view_all"; + + /* api callbacks */ + ot->exec = dopesheet_view_all_exec; + ot->poll = space_clip_dopesheet_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 56f2998b047..58626c79363 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -944,7 +944,7 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra if (state[0]) BLI_snprintf(str, sizeof(str), "%s: %s", track->name, state); else - BLI_snprintf(str, sizeof(str), "%s", track->name); + BLI_strncpy(str, track->name, sizeof(str)); BLF_position(fontid, pos[0], pos[1], 0.0f); BLF_draw(fontid, str, sizeof(str)); diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index fa235bd2997..edc6ac1ecf7 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -276,7 +276,7 @@ static int select_exec(bContext *C, wmOperator *op) return mouse_select(C, co, extend); } -static int select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float co[2]; diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 432032e9dbf..cd7da4229d2 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -67,6 +67,7 @@ void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *ar); /* clip_dopesheet_ops.c */ void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot); +void CLIP_OT_dopesheet_view_all(struct wmOperatorType *ot); /* clip_draw.c */ void clip_draw_main(const struct bContext *C, struct SpaceClip *sc, struct ARegion *ar); @@ -133,7 +134,7 @@ void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scen void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene); /* tracking_ops.c */ -struct MovieTrackingTrack *tracking_marker_check_slide(struct bContext *C, struct wmEvent *event, +struct MovieTrackingTrack *tracking_marker_check_slide(struct bContext *C, const struct wmEvent *event, int *area_r, int *action_r, int *corner_r); void CLIP_OT_add_marker(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index dfb69be6f18..914eb9526a8 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -30,16 +30,26 @@ */ #include <errno.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifndef WIN32 +# include <unistd.h> +#else +# include <io.h> +#endif #include "MEM_guardedalloc.h" #include "DNA_userdef_types.h" #include "DNA_scene_types.h" /* min/max frames */ -#include "BLI_path_util.h" #include "BLI_utildefines.h" +#include "BLI_fileops.h" +#include "BLI_path_util.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_threads.h" #include "BLF_translation.h" @@ -113,7 +123,7 @@ static void sclip_zoom_set_factor(const bContext *C, float zoomfac, float locati sclip_zoom_set(C, sc->zoom * zoomfac, location); } -static void sclip_zoom_set_factor_exec(bContext *C, wmEvent *event, float factor) +static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float factor) { ARegion *ar = CTX_wm_region(C); @@ -230,7 +240,7 @@ static int open_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceClip *sc = CTX_wm_space_clip(C); char path[FILE_MAX]; @@ -318,7 +328,7 @@ typedef struct ViewPanData { float *vec; } ViewPanData; -static void view_pan_init(bContext *C, wmOperator *op, wmEvent *event) +static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ViewPanData *vpd; @@ -377,7 +387,7 @@ static int view_pan_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type == MOUSEPAN) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -399,7 +409,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) } } -static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) +static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ViewPanData *vpd = op->customdata; @@ -471,7 +481,7 @@ typedef struct ViewZoomData { float location[2]; } ViewZoomData; -static void view_zoom_init(bContext *C, wmOperator *op, wmEvent *event) +static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -514,7 +524,7 @@ static int view_zoom_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { float delta, factor; @@ -538,7 +548,7 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) } } -static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewZoomData *vpd = op->customdata; float delta, factor; @@ -611,7 +621,7 @@ static int view_zoom_in_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -654,7 +664,7 @@ static int view_zoom_out_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -844,7 +854,7 @@ static int change_frame_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int frame_from_event(bContext *C, wmEvent *event) +static int frame_from_event(bContext *C, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); @@ -866,7 +876,7 @@ static int frame_from_event(bContext *C, wmEvent *event) return framenr; } -static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -885,7 +895,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) +static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case ESCKEY: @@ -971,46 +981,39 @@ static int proxy_bitflag_to_array(int size_flag, int build_sizes[4], int undisto return build_count; } -/* only this runs inside thread */ -static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress) +/* simple case for movies -- handle frame-by-frame, do threading within single frame */ +static void do_movie_proxy(void *pjv, int *UNUSED(build_sizes), int UNUSED(build_count), + int *build_undistort_sizes, int build_undistort_count, + short *stop, short *do_update, float *progress) { ProxyJob *pj = pjv; Scene *scene = pj->scene; MovieClip *clip = pj->clip; struct MovieDistortion *distortion = NULL; - short size_flag; int cfra, sfra = SFRA, efra = EFRA; - int build_sizes[4], build_count = 0; - int build_undistort_sizes[4], build_undistort_count = 0; - size_flag = clip->proxy.build_size_flag; - - build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0); - build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1); - - if (clip->source == MCLIP_SRC_MOVIE) { - if (pj->index_context) - IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress); + if (pj->index_context) + IMB_anim_index_rebuild(pj->index_context, stop, do_update, progress); - if (!build_undistort_count) { - if (*stop) - pj->stop = 1; + if (!build_undistort_count) { + if (*stop) + pj->stop = 1; - return; - } - else { - sfra = 1; - efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE); - } + return; } + else { + sfra = 1; + efra = IMB_anim_get_duration(clip->anim, IMB_TC_NONE); + } + + if (build_undistort_count) { + int threads = BLI_system_thread_count(); - if (build_undistort_count) distortion = BKE_tracking_distortion_new(); + BKE_tracking_distortion_set_threads(distortion, threads); + } for (cfra = sfra; cfra <= efra; cfra++) { - if (clip->source != MCLIP_SRC_MOVIE) - BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, NULL, cfra, build_sizes, build_count, 0); - BKE_movieclip_build_proxy_frame(clip, pj->clip_flag, distortion, cfra, build_undistort_sizes, build_undistort_count, 1); @@ -1028,6 +1031,193 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog pj->stop = 1; } +/* ***** + * special case for sequences -- handle different frames in different threads, + * loading from disk happens in critical section, decoding frame happens from + * thread for maximal speed + */ + +typedef struct ProxyQueue { + int cfra; + int sfra; + int efra; + SpinLock spin; + + short *stop; + short *do_update; + float *progress; +} ProxyQueue; + +typedef struct ProxyThread { + MovieClip *clip; + ProxyQueue *queue; + + struct MovieDistortion *distortion; + + int *build_sizes, build_count; + int *build_undistort_sizes, build_undistort_count; +} ProxyThread; + +static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip, size_t *size_r, int *cfra_r) +{ + unsigned char *mem = NULL; + + BLI_spin_lock(&queue->spin); + if (!*queue->stop && queue->cfra <= queue->efra) { + char name[FILE_MAX]; + size_t size; + int file; + + BKE_movieclip_filename_for_frame(clip, queue->cfra, name); + + file = open(name, O_BINARY | O_RDONLY, 0); + if (file < 0) { + BLI_spin_unlock(&queue->spin); + return NULL; + } + + size = BLI_file_descriptor_size(file); + if (size < 1) { + close(file); + BLI_spin_unlock(&queue->spin); + return NULL; + } + + mem = MEM_mallocN(size, "movieclip proxy memory file"); + + if (read(file, mem, size) != size) { + close(file); + BLI_spin_unlock(&queue->spin); + MEM_freeN(mem); + return NULL; + } + + *size_r = size; + *cfra_r = queue->cfra; + + queue->cfra++; + close(file); + + *queue->do_update = 1; + *queue->progress = (float)(queue->cfra - queue->sfra) / (queue->efra - queue->sfra); + } + BLI_spin_unlock(&queue->spin); + + return mem; +} + +static void *do_proxy_thread(void *data_v) +{ + ProxyThread *data = (ProxyThread *) data_v; + unsigned char *mem; + size_t size; + int cfra; + + while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) { + ImBuf *ibuf; + + ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame"); + + BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra, + data->build_sizes, data->build_count, FALSE); + + BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra, + data->build_undistort_sizes, data->build_undistort_count, TRUE); + + IMB_freeImBuf(ibuf); + + MEM_freeN(mem); + } + + return NULL; +} + +static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count, + int *build_undistort_sizes, int build_undistort_count, + short *stop, short *do_update, float *progress) +{ + ProxyJob *pj = pjv; + MovieClip *clip = pj->clip; + Scene *scene = pj->scene; + int sfra = SFRA, efra = EFRA; + ProxyThread *handles; + ListBase threads; + int i, tot_thread = BLI_system_thread_count(); + ProxyQueue queue; + + BLI_spin_init(&queue.spin); + + queue.cfra = sfra; + queue.sfra = sfra; + queue.efra = efra; + queue.stop = stop; + queue.do_update = do_update; + queue.progress = progress; + + handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles"); + + if (tot_thread > 1) + BLI_init_threads(&threads, do_proxy_thread, tot_thread); + + for (i = 0; i < tot_thread; i++) { + ProxyThread *handle = &handles[i]; + + handle->clip = clip; + handle->queue = &queue; + + handle->build_count = build_count; + handle->build_sizes = build_sizes; + + handle->build_undistort_count = build_undistort_count; + handle->build_undistort_sizes = build_undistort_sizes; + + if (build_undistort_count) + handle->distortion = BKE_tracking_distortion_new(); + + if (tot_thread > 1) + BLI_insert_thread(&threads, handle); + } + + if (tot_thread > 1) + BLI_end_threads(&threads); + else + do_proxy_thread(handles); + + MEM_freeN(handles); + + if (build_undistort_count) { + for (i = 0; i < tot_thread; i++) { + ProxyThread *handle = &handles[i]; + + BKE_tracking_distortion_free(handle->distortion); + } + } +} + +static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress) +{ + ProxyJob *pj = pjv; + MovieClip *clip = pj->clip; + + short size_flag; + int build_sizes[4], build_count = 0; + int build_undistort_sizes[4], build_undistort_count = 0; + + size_flag = clip->proxy.build_size_flag; + + build_count = proxy_bitflag_to_array(size_flag, build_sizes, 0); + build_undistort_count = proxy_bitflag_to_array(size_flag, build_undistort_sizes, 1); + + if (clip->source == MCLIP_SRC_MOVIE) { + do_movie_proxy(pjv, build_sizes, build_count, build_undistort_sizes, + build_undistort_count, stop, do_update, progress); + } + else { + do_sequence_proxy(pjv, build_sizes, build_count, build_undistort_sizes, + build_undistort_count, stop, do_update, progress); + } +} + static void proxy_endjob(void *pjv) { ProxyJob *pj = pjv; @@ -1134,7 +1324,7 @@ void CLIP_OT_mode_set(wmOperatorType *ot) * that explains the negative signs in the code below */ -static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int clip_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { if (event->type != NDOF_MOTION) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index 7543988b5aa..10175d07300 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -33,8 +33,6 @@ #include "DNA_windowmanager_types.h" -#include "RNA_access.h" - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -45,12 +43,14 @@ #include "BKE_context.h" #include "BKE_screen.h" -#include "ED_screen.h" -#include "ED_util.h" +#include "RNA_access.h" #include "WM_types.h" #include "WM_api.h" +#include "ED_screen.h" +#include "ED_util.h" + #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index f0c0e7b72fd..4f9757a6640 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -534,6 +534,7 @@ static void clip_operatortypes(void) /* ** clip_dopesheet_ops.c ** */ WM_operatortype_append(CLIP_OT_dopesheet_select_channel); + WM_operatortype_append(CLIP_OT_dopesheet_view_all); } static void clip_keymap(struct wmKeyConfig *keyconf) @@ -768,6 +769,8 @@ static void clip_keymap(struct wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", ACTIONMOUSE, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "extend", TRUE); /* toggle */ + + WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", HOMEKEY, KM_PRESS, 0, 0); } const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL}; @@ -796,7 +799,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul } /* dropboxes */ -static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ @@ -1191,6 +1194,9 @@ static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_find(wm->defaultconf, "Clip Graph Editor", SPACE_CLIP, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + keymap = WM_keymap_find(wm->defaultconf, "Clip Dopesheet Editor", SPACE_CLIP, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } static void graph_area_draw(const bContext *C, ARegion *ar) diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index ac7ebd9ddac..a51315d9a16 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -124,7 +124,7 @@ static int add_marker_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int add_marker_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int add_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -282,7 +282,7 @@ static void slide_marker_tilt_slider(MovieTrackingMarker *marker, float slider[2 } static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track, - MovieTrackingMarker *marker, wmEvent *event, + MovieTrackingMarker *marker, const wmEvent *event, int area, int corner, int action, int width, int height) { SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data"); @@ -524,7 +524,7 @@ static void show_cursor(bContext *C) WM_cursor_set(win, CURSOR_STD); } -MovieTrackingTrack *tracking_marker_check_slide(bContext *C, wmEvent *event, int *area_r, int *action_r, int *corner_r) +MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *event, int *area_r, int *action_r, int *corner_r) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -623,7 +623,7 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, wmEvent *event, int return NULL; } -static void *slide_marker_customdata(bContext *C, wmEvent *event) +static void *slide_marker_customdata(bContext *C, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -652,7 +652,7 @@ static void *slide_marker_customdata(bContext *C, wmEvent *event) return customdata; } -static int slide_marker_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SlideMarkerData *slidedata = slide_marker_customdata(C, event); @@ -703,7 +703,7 @@ static void free_slide_data(SlideMarkerData *data) MEM_freeN(data); } -static int slide_marker_modal(bContext *C, wmOperator *op, wmEvent *event) +static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -1228,7 +1228,7 @@ static int track_markers_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { TrackMarkersJob *tmj; ScrArea *sa = CTX_wm_area(C); @@ -1286,7 +1286,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve return OPERATOR_RUNNING_MODAL; } -static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { /* no running tracking, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) @@ -1457,7 +1457,7 @@ static int solve_camera_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SolveCameraJob *scj; ScrArea *sa = CTX_wm_area(C); @@ -1507,7 +1507,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even return OPERATOR_RUNNING_MODAL; } -static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { /* no running solver, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) @@ -2334,7 +2334,7 @@ static int set_scale_exec(bContext *C, wmOperator *op) return do_set_scale(C, op, 0); } -static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int set_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -2390,7 +2390,7 @@ static int set_solution_scale_exec(bContext *C, wmOperator *op) return do_set_scale(C, op, 1); } -static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int set_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -3258,7 +3258,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op) next = track->next; if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) { - int ok = 1; + bool ok; ok = (is_track_clean(track, frames, action == TRACKING_CLEAN_DELETE_SEGMENT)) && (error == 0.0f || (track->flag & TRACK_HAS_BUNDLE) == 0 || track->error < error); @@ -3295,7 +3295,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int clean_tracks_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int clean_tracks_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index bec50130230..b03209173d8 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -268,6 +268,17 @@ static int mouse_select(bContext *C, float co[2], int extend) return OPERATOR_FINISHED; } +static int select_poll(bContext *C) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + + if (sc) { + return sc->clip && sc->view == SC_VIEW_CLIP; + } + + return FALSE; +} + static int select_exec(bContext *C, wmOperator *op) { float co[2]; @@ -279,7 +290,7 @@ static int select_exec(bContext *C, wmOperator *op) return mouse_select(C, co, extend); } -static int select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceClip *sc = CTX_wm_space_clip(C); ARegion *ar = CTX_wm_region(C); @@ -317,8 +328,7 @@ void CLIP_OT_select(wmOperatorType *ot) /* api callbacks */ ot->exec = select_exec; ot->invoke = select_invoke; - //ot->poll = ED_space_clip_tracking_poll; // so mask view can Ctrl+RMB markers - ot->poll = ED_space_clip_view_clip_poll; + ot->poll = select_poll; /* flags */ ot->flag = OPTYPE_UNDO; diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 73747239255..cb191d0b15e 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -150,6 +150,26 @@ static int console_textview_line_get(struct TextViewContext *tvc, const char **l return 1; } +static void console_cursor_wrap_offset(const char *str, int width, int *row, int *column, const char *end) +{ + int col; + + for (; *str; str += BLI_str_utf8_size_safe(str)) { + col = BLI_str_utf8_char_width_safe(str); + + if (*column + col > width) { + (*row)++; + *column = 0; + } + + if (end && str >= end) + break; + + *column += col; + } + return; +} + static int console_textview_line_color(struct TextViewContext *tvc, unsigned char fg[3], unsigned char UNUSED(bg[3])) { ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter; @@ -158,24 +178,18 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha if (tvc->iter_index == 0) { const SpaceConsole *sc = (SpaceConsole *)tvc->arg1; const ConsoleLine *cl = (ConsoleLine *)sc->history.last; - const int prompt_len = BLI_strlen_utf8(sc->prompt); - const int cursor_loc = BLI_strnlen_utf8(cl->line, cl->cursor) + prompt_len; - const int line_len = BLI_strlen_utf8(cl->line) + prompt_len; + int offl = 0, offc = 0; int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN}; int pen[2]; xy[1] += tvc->lheight / 6; - /* account for wrapping */ - if (line_len < tvc->console_width) { - /* simple case, no wrapping */ - pen[0] = tvc->cwidth * cursor_loc; - pen[1] = -2; - } - else { - /* wrap */ - pen[0] = tvc->cwidth * (cursor_loc % tvc->console_width); - pen[1] = -2 + (((line_len / tvc->console_width) - (cursor_loc / tvc->console_width)) * tvc->lheight); - } + console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL); + console_cursor_wrap_offset(cl->line, tvc->console_width, &offl, &offc, cl->line + cl->cursor); + pen[0] = tvc->cwidth * offc; + pen[1] = -2 - tvc->lheight * offl; + + console_cursor_wrap_offset(cl->line + cl->cursor, tvc->console_width, &offl, &offc, NULL); + pen[1] += tvc->lheight * offl; /* cursor */ UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg); diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index 1242d123a41..b735dee5bdf 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -390,7 +390,7 @@ static int console_insert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int console_insert_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int console_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) { // if (!RNA_struct_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */ if (!RNA_string_length(op->ptr, "text")) { @@ -1042,7 +1042,7 @@ static void console_cursor_set_to_pos(SpaceConsole *sc, ARegion *ar, SetConsoleC } } -static void console_modal_select_apply(bContext *C, wmOperator *op, wmEvent *event) +static void console_modal_select_apply(bContext *C, wmOperator *op, const wmEvent *event) { SpaceConsole *sc = CTX_wm_space_console(C); ARegion *ar = CTX_wm_region(C); @@ -1080,7 +1080,7 @@ static void console_cursor_set_exit(bContext *UNUSED(C), wmOperator *op) MEM_freeN(scu); } -static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int console_modal_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceConsole *sc = CTX_wm_space_console(C); // ARegion *ar = CTX_wm_region(C); @@ -1101,7 +1101,7 @@ static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *eve return OPERATOR_RUNNING_MODAL; } -static int console_modal_select(bContext *C, wmOperator *op, wmEvent *event) +static int console_modal_select(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index eed269ff70f..4243ae4e2df 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -160,7 +160,7 @@ static void console_main_area_init(wmWindowManager *wm, ARegion *ar) /* ************* dropboxes ************* */ -static int id_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int id_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { // SpaceConsole *sc = CTX_wm_space_console(C); if (drag->type == WM_DRAG_ID) @@ -179,7 +179,7 @@ static void id_drop_copy(wmDrag *drag, wmDropBox *drop) MEM_freeN(text); } -static int path_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { // SpaceConsole *sc = CTX_wm_space_console(C); if (drag->type == WM_DRAG_PATH) diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index afe32ec0b85..5b6b8656072 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -35,6 +35,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_dynstr.h" +#include "BLI_fileops_types.h" #ifdef WIN32 # include "BLI_winstuff.h" @@ -55,6 +56,7 @@ #include "MEM_guardedalloc.h" #include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" #include "RNA_access.h" @@ -374,7 +376,7 @@ static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int /* the image */ glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_UNSIGNED_BYTE, imb->rect, scale, scale); + glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale); /* border */ if (dropshadow) { @@ -396,6 +398,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) char newname[FILE_MAX + 12]; char orgname[FILE_MAX + 12]; char filename[FILE_MAX + 12]; + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); ARegion *ar = CTX_wm_region(C); @@ -407,7 +410,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) if (!BLI_exists(newname)) { BLI_rename(orgname, newname); /* to make sure we show what is on disk */ - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); } ED_region_tag_redraw(ar); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 79a578a86d1..f705831c715 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -30,6 +30,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_fileops_types.h" #include "BKE_context.h" #include "BKE_screen.h" @@ -227,7 +228,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select, return retval; } -static int file_border_select_modal(bContext *C, wmOperator *op, wmEvent *event) +static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -310,7 +311,7 @@ void FILE_OT_select_border(wmOperatorType *ot) WM_operator_properties_gesture_border(ot, 1); } -static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -584,7 +585,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) return (params->active_file != origfile); } -static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -611,12 +612,13 @@ void FILE_OT_highlight(struct wmOperatorType *ot) int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused)) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); wmOperator *op = sfile->op; sfile->op = NULL; - WM_event_fileselect_event(C, op, EVT_FILESELECT_CANCEL); + WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL); return OPERATOR_FINISHED; } @@ -779,6 +781,7 @@ int file_draw_check_exists(SpaceFile *sfile) /* sends events now, so things get handled on windowqueue level */ int file_exec(bContext *C, wmOperator *exec_op) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); char filepath[FILE_MAX]; @@ -810,7 +813,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_make_file_string(G.main->name, filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE); fsmenu_write_file(fsmenu_get(), filepath); - WM_event_fileselect_event(C, op, EVT_FILESELECT_EXEC); + WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC); } @@ -870,10 +873,11 @@ void FILE_OT_parent(struct wmOperatorType *ot) static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); struct FSMenu *fsmenu = fsmenu_get(); - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); /* refresh system directory menu */ fsmenu_refresh_system_category(fsmenu); @@ -949,7 +953,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) /* only meant for timer usage */ -static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -1087,6 +1091,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) char path[FILE_MAX]; int generate_name = 1; + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); if (!sfile->params) { @@ -1125,7 +1130,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) sfile->scroll_offset = 0; /* reload dir to make sure we're seeing what's in the directory */ - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return OPERATOR_FINISHED; @@ -1189,7 +1194,7 @@ static void file_expand_directory(bContext *C) } } -static int file_directory_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int file_directory_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -1227,7 +1232,6 @@ int file_directory_exec(bContext *C, wmOperator *UNUSED(unused)) } BLI_cleanup_dir(G.main->name, sfile->params->dir); - BLI_add_slash(sfile->params->dir); file_change_dir(C, 1); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1291,11 +1295,12 @@ void FILE_OT_refresh(struct wmOperatorType *ot) static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused)) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { sfile->params->flag ^= FILE_HIDE_DOT; - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1477,14 +1482,15 @@ static int file_delete_poll(bContext *C) int file_delete_exec(bContext *C, wmOperator *UNUSED(op)) { char str[FILE_MAX]; + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); struct direntry *file; file = filelist_file(sfile->files, sfile->params->active_file); BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relname); - BLI_delete(str, 0, 0); - ED_fileselect_clear(C, sfile); + BLI_delete(str, false, false); + ED_fileselect_clear(wm, sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 142eb2214a1..f1e707f8802 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -48,6 +48,7 @@ #include "BLI_linklist.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_fileops_types.h" #ifdef WIN32 # include "BLI_winstuff.h" @@ -545,8 +546,6 @@ FileList *filelist_new(short type) void filelist_free(struct FileList *filelist) { - int i; - if (!filelist) { printf("Attempting to delete empty filelist.\n"); return; @@ -557,23 +556,8 @@ void filelist_free(struct FileList *filelist) filelist->fidx = NULL; } - for (i = 0; i < filelist->numfiles; ++i) { - if (filelist->filelist[i].image) { - IMB_freeImBuf(filelist->filelist[i].image); - } - filelist->filelist[i].image = NULL; - if (filelist->filelist[i].relname) - MEM_freeN(filelist->filelist[i].relname); - if (filelist->filelist[i].path) - MEM_freeN(filelist->filelist[i].path); - filelist->filelist[i].relname = NULL; - if (filelist->filelist[i].string) - MEM_freeN(filelist->filelist[i].string); - filelist->filelist[i].string = NULL; - } - + BLI_free_filelist(filelist->filelist, filelist->numfiles); filelist->numfiles = 0; - free(filelist->filelist); filelist->filelist = NULL; filelist->filter = 0; filelist->filter_glob[0] = '\0'; @@ -874,18 +858,14 @@ static void filelist_setfiletypes(struct FileList *filelist) static void filelist_read_dir(struct FileList *filelist) { - char wdir[FILE_MAX] = ""; if (!filelist) return; filelist->fidx = NULL; filelist->filelist = NULL; - BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ - BLI_cleanup_dir(G.main->name, filelist->dir); filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist)); - if (!chdir(wdir)) {} /* fix warning about not checking return value */ filelist_setfiletypes(filelist); filelist_filter(filelist); } @@ -1033,7 +1013,7 @@ static int groupname_to_code(const char *group) char *lslash; BLI_strncpy(buf, group, sizeof(buf)); - lslash = BLI_last_slash(buf); + lslash = (char *)BLI_last_slash(buf); if (lslash) lslash[0] = '\0'; @@ -1364,7 +1344,7 @@ static void thumbnails_free(void *tjv) } -void thumbnails_start(struct FileList *filelist, const struct bContext *C) +void thumbnails_start(FileList *filelist, const bContext *C) { wmJob *wm_job; ThumbnailJob *tj; @@ -1376,7 +1356,7 @@ void thumbnails_start(struct FileList *filelist, const struct bContext *C) for (idx = 0; idx < filelist->numfiles; idx++) { if (!filelist->filelist[idx].image) { if ( (filelist->filelist[idx].flags & (IMAGEFILE | MOVIEFILE | BLENDERFILE | BLENDERFILE_BACKUP)) ) { - FileImage *limg = MEM_callocN(sizeof(struct FileImage), "loadimage"); + FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage"); BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX); limg->index = idx; limg->flags = filelist->filelist[idx].flags; @@ -1398,12 +1378,12 @@ void thumbnails_start(struct FileList *filelist, const struct bContext *C) WM_jobs_start(CTX_wm_manager(C), wm_job); } -void thumbnails_stop(struct FileList *filelist, const struct bContext *C) +void thumbnails_stop(wmWindowManager *wm, FileList *filelist) { - WM_jobs_kill(CTX_wm_manager(C), filelist, NULL); + WM_jobs_kill(wm, filelist, NULL); } -int thumbnails_running(struct FileList *filelist, const struct bContext *C) +int thumbnails_running(wmWindowManager *wm, FileList *filelist) { - return WM_jobs_test(CTX_wm_manager(C), filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL); + return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL); } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 32a31c51229..d093d427eae 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -37,15 +37,16 @@ extern "C" { #endif +struct BlendHandle; struct FileList; +struct FileSelection; struct FolderList; -struct direntry; -struct BlendHandle; -struct Scene; struct Main; -struct rcti; struct ReportList; -struct FileSelection; +struct Scene; +struct direntry; +struct rcti; +struct wmWindowManager; typedef enum FileSelType { FILE_SEL_REMOVE = 0, @@ -99,9 +100,9 @@ void folderlist_popdir(struct ListBase *folderlist, char *dir); void folderlist_pushdir(struct ListBase *folderlist, const char *dir); int folderlist_clear_next(struct SpaceFile *sfile); -void thumbnails_stop(struct FileList *filelist, const struct bContext *C); void thumbnails_start(struct FileList *filelist, const struct bContext *C); -int thumbnails_running(struct FileList *filelist, const struct bContext *C); +void thumbnails_stop(struct wmWindowManager *wm, struct FileList *filelist); +int thumbnails_running(struct wmWindowManager *wm, struct FileList *filelist); #ifdef __cplusplus } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 3c6f6358171..b8db7dc97b7 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -58,6 +58,7 @@ #include "BLI_linklist.h" #include "BLI_dynstr.h" #include "BLI_utildefines.h" +#include "BLI_fileops_types.h" #include "BKE_context.h" #include "BKE_global.h" @@ -577,13 +578,14 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) void file_change_dir(bContext *C, int checkdir) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); - if (checkdir && BLI_is_dir(sfile->params->dir) == 0) { + if (checkdir && !BLI_is_dir(sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } @@ -690,24 +692,24 @@ void autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v)) } } -void ED_fileselect_clear(struct bContext *C, struct SpaceFile *sfile) +void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile) { /* only NULL in rare cases - [#29734] */ if (sfile->files) { - thumbnails_stop(sfile->files, C); + thumbnails_stop(wm, sfile->files); filelist_freelib(sfile->files); filelist_free(sfile->files); } sfile->params->active_file = -1; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } -void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile) +void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile) { if (!sfile) return; if (sfile->op) { - WM_event_fileselect_event(C, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); + WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); sfile->op = NULL; } @@ -715,7 +717,7 @@ void ED_fileselect_exit(struct bContext *C, struct SpaceFile *sfile) folderlist_free(sfile->folders_next); if (sfile->files) { - ED_fileselect_clear(C, sfile); + ED_fileselect_clear(wm, sfile); MEM_freeN(sfile->files); sfile->files = NULL; } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 5f1f9a3ab22..04c68e5ea68 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -281,14 +281,14 @@ void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename) void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename) { - char line[256]; + char line[FILE_MAXDIR]; FSMenuCategory category = FS_CATEGORY_BOOKMARKS; FILE *fp; fp = BLI_fopen(filename, "r"); if (!fp) return; - while (fgets(line, 256, fp) != NULL) { /* read a line */ + while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */ if (strncmp(line, "[Bookmarks]", 11) == 0) { category = FS_CATEGORY_BOOKMARKS; } @@ -318,7 +318,7 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename) void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) { - char line[256]; + char line[FILE_MAXDIR]; #ifdef WIN32 /* Add the drive names to the listing */ { @@ -376,25 +376,25 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) * TODO : replace hardcoded paths with proper BLI_get_folder calls */ home = getenv("HOME"); if (read_bookmarks && home) { - BLI_snprintf(line, 256, "%s/", home); + BLI_snprintf(line, sizeof(line), "%s/", home); fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); - BLI_snprintf(line, 256, "%s/Desktop/", home); + BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } - BLI_snprintf(line, 256, "%s/Documents/", home); + BLI_snprintf(line, sizeof(line), "%s/Documents/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } - BLI_snprintf(line, 256, "%s/Pictures/", home); + BLI_snprintf(line, sizeof(line), "%s/Pictures/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } - BLI_snprintf(line, 256, "%s/Music/", home); + BLI_snprintf(line, sizeof(line), "%s/Music/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } - BLI_snprintf(line, 256, "%s/Movies/", home); + BLI_snprintf(line, sizeof(line), "%s/Movies/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } @@ -427,7 +427,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); - if (!CFStringGetCString(pathString, line, 256, kCFStringEncodingASCII)) + if (!CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII)) continue; fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, FS_INSERT_SORTED); @@ -480,7 +480,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle); - if (!CFStringGetCString(pathString, line, 256, kCFStringEncodingASCII)) + if (!CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII)) continue; fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); @@ -499,9 +499,9 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) const char *home = getenv("HOME"); if (read_bookmarks && home) { - BLI_snprintf(line, FILE_MAXDIR, "%s/", home); + BLI_snprintf(line, sizeof(line), "%s/", home); fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); - BLI_snprintf(line, FILE_MAXDIR, "%s/Desktop/", home); + BLI_snprintf(line, sizeof(line), "%s/Desktop/", home); if (BLI_exists(line)) { fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED); } @@ -527,7 +527,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) len = strlen(mnt->mnt_dir); if (len && mnt->mnt_dir[len - 1] != '/') { - BLI_snprintf(line, FILE_MAXDIR, "%s/", mnt->mnt_dir); + BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir); fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, FS_INSERT_SORTED); } else { diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 0a4b922bb38..698c355fad3 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -28,13 +28,9 @@ * \ingroup spfile */ - #include <string.h> #include <stdio.h> - -#include "RNA_access.h" - #include "MEM_guardedalloc.h" #include "BIF_gl.h" @@ -45,11 +41,17 @@ #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_utildefines.h" +#include "BLI_fileops_types.h" #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_global.h" +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + #include "ED_space_api.h" #include "ED_screen.h" #include "ED_fileselect.h" @@ -57,9 +59,6 @@ #include "IMB_imbuf_types.h" #include "IMB_thumbs.h" -#include "WM_api.h" -#include "WM_types.h" - #include "UI_resources.h" #include "UI_view2d.h" @@ -147,7 +146,7 @@ static void file_free(SpaceLink *sl) /* spacetype; init callback, area size changes, screen set, etc */ -static void file_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa) +static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) { SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; //printf("file_init\n"); @@ -158,6 +157,12 @@ static void file_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa) if (sfile->layout) sfile->layout->dirty = TRUE; } +static void file_exit(wmWindowManager *wm, ScrArea *sa) +{ + SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; + + ED_fileselect_exit(wm, sfile); +} static SpaceLink *file_duplicate(SpaceLink *sl) { @@ -187,6 +192,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) static void file_refresh(const bContext *C, ScrArea *UNUSED(sa)) { + wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); @@ -202,7 +208,7 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa)) filelist_setfilter_types(sfile->files, params->filter_glob); if (filelist_empty(sfile->files)) { - thumbnails_stop(sfile->files, C); + thumbnails_stop(wm, sfile->files); filelist_readdir(sfile->files); if (params->sort != FILE_SORT_NONE) { filelist_sort(sfile->files, params->sort); @@ -214,7 +220,7 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa)) } else { if (params->sort != FILE_SORT_NONE) { - thumbnails_stop(sfile->files, C); + thumbnails_stop(wm, sfile->files); filelist_sort(sfile->files, params->sort); if (params->display == FILE_IMGDISPLAY) { thumbnails_start(sfile->files, C); @@ -222,14 +228,14 @@ static void file_refresh(const bContext *C, ScrArea *UNUSED(sa)) } else { if (params->display == FILE_IMGDISPLAY) { - if (!thumbnails_running(sfile->files, C)) { + if (!thumbnails_running(wm, sfile->files)) { thumbnails_start(sfile->files, C); } } else { /* stop any running thumbnail jobs if we're not * displaying them - speedup for NFS */ - thumbnails_stop(sfile->files, C); + thumbnails_stop(wm, sfile->files); } filelist_filter(sfile->files); } @@ -577,6 +583,7 @@ void ED_spacetype_file(void) st->new = file_new; st->free = file_free; st->init = file_init; + st->exit = file_exit; st->duplicate = file_duplicate; st->refresh = file_refresh; st->listener = file_listener; @@ -629,7 +636,7 @@ void ED_spacetype_file(void) void ED_file_init(void) { - char *cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); fsmenu_read_system(fsmenu_get(), TRUE); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index b92430ce0e9..a51fef6c692 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -609,7 +609,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; ARegion *ar; @@ -625,8 +625,8 @@ static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, wmEvent *e ar = ac.ar; v2d = &ar->v2d; - mval[0] = (evt->x - ar->winrct.xmin); - mval[1] = (evt->y - ar->winrct.ymin); + mval[0] = (event->x - ar->winrct.xmin); + mval[1] = (event->y - ar->winrct.ymin); UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); @@ -835,7 +835,7 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { graphkeys_duplicate_exec(C, op); @@ -1190,7 +1190,7 @@ static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op) #endif //WITH_AUDASPACE -static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; @@ -2132,7 +2132,7 @@ void GRAPH_OT_smooth(wmOperatorType *ot) /* ******************** Add F-Modifier Operator *********************** */ /* present a special customised popup menu for this, with some filtering */ -static int graph_fmodifier_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int graph_fmodifier_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmOperatorType *ot = WM_operatortype_find("GRAPH_OT_fmodifier_add", 1); uiPopupMenu *pup; @@ -2196,8 +2196,9 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) /* add F-Modifier of specified type to active F-Curve, and make it the active one */ fcm = add_fmodifier(&fcu->modifiers, type); - if (fcm) + if (fcm) { set_active_fmodifier(&fcu->modifiers, fcm); + } else { BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)"); break; diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 54b417e740a..acb9e42d91b 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -109,7 +109,7 @@ static int graphview_cursor_exec(bContext *C, wmOperator *op) /* ... */ /* set the operator properties from the initial event */ -static void graphview_cursor_setprops(bContext *C, wmOperator *op, wmEvent *event) +static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float viewx, viewy; @@ -128,7 +128,7 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, wmEvent *even } /* Modal Operator init */ -static int graphview_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* Change to frame that mouse is over before adding modal handler, * as user could click on a single frame (jump to frame) as well as @@ -145,7 +145,7 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* Modal event handling of cursor changing */ -static int graphview_cursor_modal(bContext *C, wmOperator *op, wmEvent *event) +static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event) { /* execute the events */ switch (event->type) { diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 978b3224850..cbec3072c44 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -815,7 +815,7 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; short leftright = RNA_enum_get(op->ptr, "mode"); @@ -1297,7 +1297,7 @@ static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short /* ------------------- */ /* handle clicking */ -static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; short selectmode; @@ -1342,10 +1342,13 @@ void GRAPH_OT_clickselect(wmOperatorType *ot) ot->idname = "GRAPH_OT_clickselect"; ot->description = "Select keyframes by clicking on them"; - /* api callbacks */ + /* callbacks */ ot->invoke = graphkeys_clickselect_invoke; ot->poll = graphop_visible_keyframes_poll; + /* flags */ + ot->flag = OPTYPE_UNDO; + /* properties */ prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript index 6e7c5982d6e..68f747270a3 100644 --- a/source/blender/editors/space_image/SConscript +++ b/source/blender/editors/space_image/SConscript @@ -44,7 +44,7 @@ if env['WITH_BF_OPENJPEG']: if env['WITH_BF_TIFF']: defs.append('WITH_TIFF') if env['WITH_BF_CINEON']: - defs.append('WITH_CINEON') + defs.append('WITH_CINEON') if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 6237958e723..70001b59528 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -73,51 +73,55 @@ /* proto */ -static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str) +static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, char *str, size_t len) { - int ofs = 0; + size_t ofs = 0; str[0] = 0; - - if (ima == NULL) return; + if (ima == NULL) + return; if (ibuf == NULL) { - ofs += sprintf(str, IFACE_("Can't Load Image")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Can't Load Image"), len - ofs); } else { if (ima->source == IMA_SRC_MOVIE) { - ofs += sprintf(str, IFACE_("Movie")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs); if (ima->anim) - ofs += sprintf(str + ofs, IFACE_(" %d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN)); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"), + IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN)); + } + else { + ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs); } - else - ofs += sprintf(str, IFACE_("Image")); - ofs += sprintf(str + ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y); if (ibuf->rect_float) { if (ibuf->channels != 4) { - ofs += sprintf(str + ofs, IFACE_("%d float channel(s)"), ibuf->channels); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_("%d float channel(s)"), ibuf->channels); } else if (ibuf->planes == R_IMF_PLANES_RGBA) - ofs += sprintf(str + ofs, IFACE_(" RGBA float")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA float"), len - ofs); else - ofs += sprintf(str + ofs, IFACE_(" RGB float")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB float"), len - ofs); } else { if (ibuf->planes == R_IMF_PLANES_RGBA) - ofs += sprintf(str + ofs, IFACE_(" RGBA byte")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGBA byte"), len - ofs); else - ofs += sprintf(str + ofs, IFACE_(" RGB byte")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" RGB byte"), len - ofs); } if (ibuf->zbuf || ibuf->zbuf_float) - ofs += sprintf(str + ofs, IFACE_(" + Z")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs); if (ima->source == IMA_SRC_SEQUENCE) { - char *file = BLI_last_slash(ibuf->name); - if (file == NULL) file = ibuf->name; - else file++; - ofs += sprintf(str + ofs, ", %s", file); + const char *file = BLI_last_slash(ibuf->name); + if (file == NULL) + file = ibuf->name; + else + file++; + ofs += BLI_snprintf(str + ofs, len - ofs, ", %s", file); } } @@ -125,10 +129,8 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf, if (ima->source == IMA_SRC_SEQUENCE) { /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */ const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL); - ofs += sprintf(str + ofs, IFACE_(", Frame: %d"), framenr); + ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(", Frame: %d"), framenr); } - - (void)ofs; } /* gets active viewer user */ @@ -539,16 +541,17 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact) { +#define MAX_INFO_LEN 128 + PropertyRNA *prop; PointerRNA imaptr; RNAUpdateCb *cb; Image *ima; ImageUser *iuser; - ImBuf *ibuf; Scene *scene = CTX_data_scene(C); uiLayout *row, *split, *col; uiBlock *block; - char str[128]; + char str[MAX_INFO_LEN]; void *lock; @@ -591,8 +594,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL); if (ima->source == IMA_SRC_VIEWER) { - ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN); BKE_image_release_ibuf(ima, ibuf, lock); uiItemL(layout, ima->id.name + 2, ICON_NONE); @@ -661,8 +664,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } else if (ima->source != IMA_SRC_GENERATED) { if (compact == 0) { - ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN); BKE_image_release_ibuf(ima, ibuf, lock); uiItemL(layout, str, ICON_NONE); } @@ -750,6 +753,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } MEM_freeN(cb); + +#undef MAX_INFO_LEN } void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_management) diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index cae71885b87..e69ce56c9d9 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -491,6 +491,8 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, /* set zoom */ glPixelZoom(zoomx, zoomy); + glaDefine2DArea(&ar->winrct); + /* find window pixel coordinates of origin */ UI_view2d_to_region_no_clip(&ar->v2d, fx, fy, &x, &y); @@ -523,11 +525,7 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle); if (display_buffer) - glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer); -#if 0 - else - glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float); -#endif + glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer); IMB_display_buffer_release(cache_handle); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index b913b3528ac..54230d35312 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -162,7 +162,7 @@ static int space_image_file_exists_poll(bContext *C) if (BLI_exists(name) == FALSE) { CTX_wm_operator_poll_msg_set(C, "image file not found"); } - else if (BLI_file_is_writable(name) == FALSE) { + else if (!BLI_file_is_writable(name)) { CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); } else { @@ -238,7 +238,7 @@ typedef struct ViewPanData { int event_type; } ViewPanData; -static void image_view_pan_init(bContext *C, wmOperator *op, wmEvent *event) +static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); ViewPanData *vpd; @@ -293,7 +293,7 @@ static int image_view_pan_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type == MOUSEPAN) { SpaceImage *sima = CTX_wm_space_image(C); @@ -312,7 +312,7 @@ static int image_view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) } } -static int image_view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); ViewPanData *vpd = op->customdata; @@ -383,7 +383,7 @@ typedef struct ViewZoomData { ARegion *ar; } ViewZoomData; -static void image_view_zoom_init(bContext *C, wmOperator *op, wmEvent *event) +static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); ARegion *ar = CTX_wm_region(C); @@ -455,7 +455,7 @@ enum { VIEW_CONFIRM }; -static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { SpaceImage *sima = CTX_wm_space_image(C); @@ -525,7 +525,7 @@ static void image_zoom_apply(ViewZoomData *vpd, wmOperator *op, const int x, con ED_region_tag_redraw(vpd->ar); } -static int image_view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewZoomData *vpd = op->customdata; short event_code = VIEW_PASS; @@ -589,7 +589,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot) * that explains the negative signs in the code below */ -static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { if (event->type != NDOF_MOTION) return OPERATOR_CANCELLED; @@ -773,7 +773,7 @@ static int image_view_zoom_in_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float location[2]; @@ -815,7 +815,7 @@ static int image_view_zoom_out_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float location[2]; @@ -978,7 +978,7 @@ static int image_open_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */ char *path = U.textudir; @@ -1128,7 +1128,7 @@ static int image_replace_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_replace_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_replace_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceImage *sima = CTX_wm_space_image(C); @@ -1442,7 +1442,7 @@ static int image_save_as_check(bContext *UNUSED(C), wmOperator *op) return WM_operator_filesel_ensure_ext_imtype(op, imf); } -static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = ED_space_image(sima); @@ -1603,7 +1603,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) SpaceImage *sima = CTX_wm_space_image(C); ImBuf *ibuf; int tot = 0; - char di[FILE_MAX], fi[FILE_MAX]; + char di[FILE_MAX]; if (sima->image == NULL) return OPERATOR_CANCELLED; @@ -1632,10 +1632,8 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next) if (ibuf->userflags & IB_BITMAPDIRTY) break; - - BLI_strncpy(di, ibuf->name, FILE_MAX); - BLI_splitdirstring(di, fi); - + + BLI_split_dir_part(ibuf->name, di, sizeof(di)); BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di); for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next) { @@ -1775,7 +1773,7 @@ static int image_new_exec(bContext *C, wmOperator *op) /* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */ /* XXX Note: the WM_operator_props_dialog_popup() doesn't work for uiIDContextProperty(), image is not being that way */ -static int image_new_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y); @@ -1945,7 +1943,7 @@ static int image_pack_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_pack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_pack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Image *ima = CTX_data_edit_image(C); ImBuf *ibuf; @@ -2029,7 +2027,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Image *ima = CTX_data_edit_image(C); @@ -2145,7 +2143,7 @@ int ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], floa return ret; } -static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event) +static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); ARegion *ar = CTX_wm_region(C); @@ -2271,7 +2269,7 @@ static void image_sample_exit(bContext *C, wmOperator *op) MEM_freeN(info); } -static int image_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); ARegion *ar = CTX_wm_region(C); @@ -2292,7 +2290,7 @@ static int image_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int image_sample_modal(bContext *C, wmOperator *op, wmEvent *event) +static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: @@ -2378,7 +2376,7 @@ static int image_sample_line_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int image_sample_line_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); @@ -2533,7 +2531,7 @@ static int image_record_composite_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int image_record_composite_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int image_record_composite_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { RecordCompositeData *rcd; @@ -2550,7 +2548,7 @@ static int image_record_composite_invoke(bContext *C, wmOperator *op, wmEvent *U return OPERATOR_RUNNING_MODAL; } -static int image_record_composite_modal(bContext *C, wmOperator *op, wmEvent *event) +static int image_record_composite_modal(bContext *C, wmOperator *op, const wmEvent *event) { RecordCompositeData *rcd = op->customdata; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index d82a46e9578..761becdbf8e 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -337,7 +337,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) } /* dropboxes */ -static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 04f6a5152e6..c68473820e3 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -104,7 +104,7 @@ static int unpack_libraries_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int unpack_libraries_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int unpack_libraries_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return WM_operator_confirm_message(C, op, "Unpack Blender Libraries - creates directories, all new paths should work"); } @@ -137,7 +137,7 @@ static int pack_all_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int pack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); Image *ima; @@ -203,7 +203,7 @@ static int unpack_all_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); uiPopupMenu *pup; @@ -288,7 +288,7 @@ static int unpack_item_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int unpack_item_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int unpack_item_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -429,7 +429,7 @@ static int find_missing_files_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int find_missing_files_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int find_missing_files_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { /* XXX file open button text "Find Missing Files" */ WM_event_add_fileselect(C, op); @@ -469,7 +469,7 @@ void FILE_OT_find_missing_files(wmOperatorType *ot) #define ERROR_TIMEOUT 10.0f #define ERROR_COLOR_TIMEOUT 6.0f #define COLLAPSE_TIMEOUT 0.25f -static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { wmWindowManager *wm = CTX_wm_manager(C); ReportList *reports = CTX_wm_reports(C); diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 3050563e538..b096b8f3e2b 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -127,7 +127,7 @@ static int select_report_pick_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int select_report_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_report_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceInfo *sinfo = CTX_wm_space_info(C); ARegion *ar = CTX_wm_region(C); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 976769752f9..b2e9427c799 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -38,8 +38,9 @@ #include "DNA_meta_types.h" #include "DNA_scene_types.h" -#include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" #include "BLF_translation.h" @@ -58,6 +59,7 @@ #include "ED_armature.h" #include "ED_mesh.h" +#define MAX_INFO_LEN 512 typedef struct SceneStats { int totvert, totvertsel; @@ -68,7 +70,7 @@ typedef struct SceneStats { int totlamp, totlampsel; int tottri, totmesh; - char infostr[512]; + char infostr[MAX_INFO_LEN]; } SceneStats; static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) @@ -357,60 +359,70 @@ static void stats_update(Scene *scene) static void stats_string(Scene *scene) { +#define MAX_INFO_MEM_LEN 64 SceneStats *stats = scene->stats; Object *ob = (scene->basact) ? scene->basact->object : NULL; uintptr_t mem_in_use, mmap_in_use; - char memstr[64]; + char memstr[MAX_INFO_MEM_LEN]; char *s; + size_t ofs = 0; mem_in_use = MEM_get_memory_in_use(); mmap_in_use = MEM_get_mapped_memory_in_use(); /* get memory statistics */ - s = memstr + sprintf(memstr, IFACE_(" | Mem:%.2fM"), (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0); + s = memstr; + ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"), + (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0); if (mmap_in_use) - sprintf(s, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0); + BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0); s = stats->infostr; - - s += sprintf(s, "%s | ", versionstr); + ofs = 0; + + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr); if (scene->obedit) { if (BKE_keyblock_from_object(scene->obedit)) - s += sprintf(s, IFACE_("(Key) ")); + ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs); if (scene->obedit->type == OB_MESH) { - s += sprintf(s, IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"), - stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel, - stats->totface, stats->tottri); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, + IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"), + stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, + stats->totfacesel, stats->totface, stats->tottri); } else if (scene->obedit->type == OB_ARMATURE) { - s += sprintf(s, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, stats->totvert, stats->totbonesel, - stats->totbone); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, + stats->totvert, stats->totbonesel, stats->totbone); } else { - s += sprintf(s, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert); } - strcat(s, memstr); + ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); } else if (ob && (ob->mode & OB_MODE_POSE)) { - s += sprintf(s, IFACE_("Bones:%d/%d %s"), - stats->totbonesel, stats->totbone, memstr); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%d/%d %s"), + stats->totbonesel, stats->totbone, memstr); } else if (stats_is_object_dynamic_topology_sculpt(ob)) { - s += sprintf(s, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri); } else { - s += sprintf(s, IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), - stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, - stats->totlamp, memstr); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, + IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), stats->totvert, + stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, + stats->totlamp, memstr); } if (ob) - sprintf(s, " | %s", ob->id.name + 2); + BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", ob->id.name + 2); +#undef MAX_INFO_MEM_LEN } +#undef MAX_INFO_LEN + void ED_info_stats_clear(Scene *scene) { if (scene->stats) { diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 66f4904c340..e53cbdd04af 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -31,14 +31,19 @@ #include <limits.h> #include <assert.h> +#include "MEM_guardedalloc.h" + #include "BLF_api.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_string_utf8.h" #include "BIF_gl.h" #include "BIF_glutil.h" +#include "BKE_text.h" + #include "ED_datafiles.h" #include "textview.h" @@ -68,12 +73,12 @@ BLI_INLINE void console_step_sel(ConsoleDrawContext *cdc, const int step) cdc->sel[1] += step; } -static void console_draw_sel(const int sel[2], const int xy[2], const int str_len_draw, int cwidth, int lheight, - const unsigned char bg_sel[4]) +static void console_draw_sel(const char *str, const int sel[2], const int xy[2], const int str_len_draw, + int cwidth, int lheight, const unsigned char bg_sel[4]) { if (sel[0] <= str_len_draw && sel[1] >= 0) { - const int sta = max_ii(sel[0], 0); - const int end = min_ii(sel[1], str_len_draw); + const int sta = txt_utf8_offset_to_column(str, max_ii(sel[0], 0)); + const int end = txt_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw)); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -85,38 +90,72 @@ static void console_draw_sel(const int sel[2], const int xy[2], const int str_le } } +/* warning: allocated memory for 'offsets' must be freed by caller */ +static int console_wrap_offsets(const char *str, int len, int width, int *lines, int **offsets) +{ + int i, end; /* column */ + int j; /* mem */ + + *lines = 1; + + *offsets = MEM_callocN(sizeof(**offsets) * (len * BLI_UTF8_WIDTH_MAX / MAX2(1, width - (BLI_UTF8_WIDTH_MAX - 1)) + 1), + "console_wrap_offsets"); + (*offsets)[0] = 0; + + for (i = 0, end = width, j = 0; j < len && str[j]; j += BLI_str_utf8_size_safe(str + j)) { + int columns = BLI_str_utf8_char_width_safe(str + j); + + if (i + columns > end) { + (*offsets)[*lines] = j; + (*lines)++; + + end = i + width; + } + i += columns; + } + return j; /* return actual length */ +} + /* return 0 if the last line is off the screen * should be able to use this for any string type */ -static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const int str_len, +static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str_len, const unsigned char fg[3], const unsigned char bg[3], const unsigned char bg_sel[4]) { int rct_ofs = cdc->lheight / 4; - int tot_lines = (str_len / cdc->console_width) + 1; /* total number of lines for wrapping */ - int y_next = (str_len > cdc->console_width) ? cdc->xy[1] + cdc->lheight * tot_lines : cdc->xy[1] + cdc->lheight; + int tot_lines; /* total number of lines for wrapping */ + int *offsets; /* offsets of line beginnings for wrapping */ + int y_next; const int mono = blf_mono_font; + str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets); + y_next = cdc->xy[1] + cdc->lheight * tot_lines; + /* just advance the height */ if (cdc->draw == 0) { - if (cdc->pos_pick && (cdc->mval[1] != INT_MAX)) { - if (cdc->xy[1] <= cdc->mval[1]) { - if ((y_next >= cdc->mval[1])) { - int ofs = (int)floor(((float)cdc->mval[0] / (float)cdc->cwidth)); - - /* wrap */ - if (str_len > cdc->console_width) - ofs += cdc->console_width * ((int)((((float)(y_next - cdc->mval[1]) / - (float)(y_next - cdc->xy[1])) * tot_lines))); - - CLAMP(ofs, 0, str_len); - *cdc->pos_pick += str_len - ofs; + if (cdc->pos_pick && cdc->mval[1] != INT_MAX && cdc->xy[1] <= cdc->mval[1]) { + if (y_next >= cdc->mval[1]) { + int ofs = 0; + + /* wrap */ + if (tot_lines > 1) { + int iofs = (int)((float)(y_next - cdc->mval[1]) / cdc->lheight); + ofs += offsets[MIN2(iofs, tot_lines - 1)]; } - else - *cdc->pos_pick += str_len + 1; + + /* last part */ + ofs += txt_utf8_column_to_offset(str + ofs, + (int)floor((float)cdc->mval[0] / cdc->cwidth)); + + CLAMP(ofs, 0, str_len); + *cdc->pos_pick += str_len - ofs; } + else + *cdc->pos_pick += str_len + 1; } cdc->xy[1] = y_next; + MEM_freeN(offsets); return 1; } else if (y_next - cdc->lheight < cdc->ymin) { @@ -128,12 +167,15 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i console_step_sel(cdc, -(str_len + 1)); } + MEM_freeN(offsets); return 1; } if (tot_lines > 1) { /* wrap? */ - const int initial_offset = ((tot_lines - 1) * cdc->console_width); - const char *line_stride = str + initial_offset; /* advance to the last line and draw it first */ + const int initial_offset = offsets[tot_lines - 1]; + size_t len = str_len - initial_offset; + const char *s = str + initial_offset; + int i; int sel_orig[2]; copy_v2_v2_int(sel_orig, cdc->sel); @@ -151,36 +193,38 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i /* last part needs no clipping */ BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); - BLF_draw(mono, line_stride, str_len - initial_offset); + BLF_draw_mono(mono, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { console_step_sel(cdc, -initial_offset); // glColor4ub(255, 0, 0, 96); // debug - console_draw_sel(cdc->sel, cdc->xy, str_len % cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel); - console_step_sel(cdc, cdc->console_width); + console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel); glColor3ubv(fg); } cdc->xy[1] += cdc->lheight; - line_stride -= cdc->console_width; - - for (; line_stride >= str; line_stride -= cdc->console_width) { + for (i = tot_lines - 1; i > 0; i--) { + len = offsets[i] - offsets[i - 1]; + s = str + offsets[i - 1]; + BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); - BLF_draw(mono, line_stride, cdc->console_width); + BLF_draw_mono(mono, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { + console_step_sel(cdc, len); // glColor4ub(0, 255, 0, 96); // debug - console_draw_sel(cdc->sel, cdc->xy, cdc->console_width, cdc->cwidth, cdc->lheight, bg_sel); - console_step_sel(cdc, cdc->console_width); + console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel); glColor3ubv(fg); } cdc->xy[1] += cdc->lheight; /* check if were out of view bounds */ - if (cdc->xy[1] > cdc->ymax) + if (cdc->xy[1] > cdc->ymax) { + MEM_freeN(offsets); return 0; + } } copy_v2_v2_int(cdc->sel, sel_orig); @@ -196,7 +240,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i glColor3ubv(fg); BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); - BLF_draw(mono, str, str_len); + BLF_draw_mono(mono, str, str_len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { int isel[2]; @@ -205,16 +249,19 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, const i isel[1] = str_len - cdc->sel[0]; // glColor4ub(255, 255, 0, 96); // debug - console_draw_sel(isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel); + console_draw_sel(str, isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel); console_step_sel(cdc, -(str_len + 1)); } cdc->xy[1] += cdc->lheight; - if (cdc->xy[1] > cdc->ymax) + if (cdc->xy[1] > cdc->ymax) { + MEM_freeN(offsets); return 0; + } } + MEM_freeN(offsets); return 1; } diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index 2313885dbaf..5f2ecbf1b2b 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -122,7 +122,7 @@ static Object *edit_object_property_get(bContext *C, wmOperator *op) /* if ob_name is valid try to find the object with this name * otherwise gets the active object */ - if (BLI_strnlen(ob_name, MAX_NAME) > 0) + if (*ob_name) ob = BLI_findstring(&(CTX_data_main(C)->object), ob_name, offsetof(ID, name) + 2); else ob = ED_object_active_context(C); @@ -250,7 +250,7 @@ static int sensor_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sensor_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sensor_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_sensor_invoke_properties(C, op)) return sensor_remove_exec(C, op); @@ -295,12 +295,13 @@ static int sensor_add_exec(bContext *C, wmOperator *op) prop = RNA_struct_find_property(&sens_ptr, "type"); RNA_string_get(op->ptr, "name", name); - if (BLI_strnlen(name, MAX_NAME) < 1) { + if (*name) { + BLI_strncpy(sens->name, name, sizeof(sens->name)); + } + else { RNA_property_enum_name(C, &sens_ptr, prop, RNA_property_enum_get(&sens_ptr, prop), &sens_name); BLI_strncpy(sens->name, sens_name, sizeof(sens->name)); } - else - BLI_strncpy(sens->name, name, sizeof(sens->name)); make_unique_prop_names(C, sens->name); ob->scaflag |= OB_SHOWSENS; @@ -355,7 +356,7 @@ static int controller_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int controller_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int controller_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_controller_invoke_properties(C, op)) return controller_remove_exec(C, op); @@ -401,12 +402,13 @@ static int controller_add_exec(bContext *C, wmOperator *op) prop = RNA_struct_find_property(&cont_ptr, "type"); RNA_string_get(op->ptr, "name", name); - if (BLI_strnlen(name, MAX_NAME) < 1) { + if (*name) { + BLI_strncpy(cont->name, name, sizeof(cont->name)); + } + else { RNA_property_enum_name(C, &cont_ptr, prop, RNA_property_enum_get(&cont_ptr, prop), &cont_name); BLI_strncpy(cont->name, cont_name, sizeof(cont->name)); } - else - BLI_strncpy(cont->name, name, sizeof(cont->name)); make_unique_prop_names(C, cont->name); /* set the controller state mask from the current object state. @@ -473,7 +475,7 @@ static int actuator_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int actuator_remove_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int actuator_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_actuator_invoke_properties(C, op)) return actuator_remove_exec(C, op); @@ -518,12 +520,13 @@ static int actuator_add_exec(bContext *C, wmOperator *op) prop = RNA_struct_find_property(&act_ptr, "type"); RNA_string_get(op->ptr, "name", name); - if (BLI_strnlen(name, MAX_NAME) < 1) { + if (*name) { + BLI_strncpy(act->name, name, sizeof(act->name)); + } + else { RNA_property_enum_name(C, &act_ptr, prop, RNA_property_enum_get(&act_ptr, prop), &act_name); BLI_strncpy(act->name, act_name, sizeof(act->name)); } - else - BLI_strncpy(act->name, name, sizeof(act->name)); make_unique_prop_names(C, act->name); ob->scaflag |= OB_SHOWACT; @@ -583,7 +586,7 @@ static int sensor_move_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sensor_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sensor_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_sensor_invoke_properties(C, op)) { return sensor_move_exec(C, op); @@ -628,7 +631,7 @@ static int controller_move_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int controller_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int controller_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_controller_invoke_properties(C, op)) { return controller_move_exec(C, op); @@ -673,7 +676,7 @@ static int actuator_move_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int actuator_move_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int actuator_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (edit_actuator_invoke_properties(C, op)) { return actuator_move_exec(C, op); @@ -711,7 +714,7 @@ static int texface_convert_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int texface_convert_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int texface_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return texface_convert_exec(C, op); } diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 31c773e613e..b2cae8e5496 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -131,7 +131,6 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA case ANIMTYPE_SCENE: /* Top-Level Widgets doubling up as datablocks */ case ANIMTYPE_OBJECT: - case ANIMTYPE_FILLACTD: /* Action Expander */ case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ case ANIMTYPE_DSLAM: case ANIMTYPE_DSCAM: @@ -142,22 +141,34 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA case ANIMTYPE_DSPART: case ANIMTYPE_DSMBALL: case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: #ifdef WITH_FREESTYLE case ANIMTYPE_DSLINESTYLE: #endif case ANIMTYPE_DSSPK: { /* for these channels, we only do AnimData */ - if (ale->id && ale->adt) { - if (adt_ptr) { - /* AnimData pointer */ - RNA_pointer_create(ale->id, &RNA_AnimData, ale->adt, adt_ptr); - - /* set found status to -1, since setting to 1 would break the loop - * and potentially skip an active NLA-Track in some cases... - */ - found = -1; + if (ale->adt && adt_ptr) { + ID *id; + + if ((ale->data == NULL) || (ale->type == ANIMTYPE_OBJECT)) { + /* ale->data is not an ID block! */ + id = ale->id; } + else { + /* ale->data is always the proper ID block we need, but ale->id may not be (i.e. for textures) */ + id = (ID *)ale->data; + } + + /* AnimData pointer */ + RNA_pointer_create(id, &RNA_AnimData, ale->adt, adt_ptr); + + /* set found status to -1, since setting to 1 would break the loop + * and potentially skip an active NLA-Track in some cases... + */ + found = -1; } } break; @@ -250,6 +261,28 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) block = uiLayoutGetBlock(layout); uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL); + /* AnimData Source Properties ----------------------------------- */ + + /* icon + id-block name of block where AnimData came from to prevent + * accidentally changing the properties of the wrong action + */ + if (adt_ptr.id.data) { + ID *id = adt_ptr.id.data; + PointerRNA id_ptr; + + RNA_id_pointer_create(id, &id_ptr); + + /* ID-block name > AnimData */ + row = uiLayoutRow(layout, TRUE); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT); + + uiItemL(row, id->name + 2, RNA_struct_ui_icon(id_ptr.type)); /* id-block (src) */ + uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC); /* expander */ + uiItemL(row, IFACE_("Animation Data"), ICON_ANIM_DATA); /* animdata */ + + uiItemS(layout); + } + /* Active Action Properties ------------------------------------- */ /* action */ row = uiLayoutRow(layout, TRUE); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 97581cefc2b..6d091e3c7c4 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -48,6 +48,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_report.h" #include "ED_anim_api.h" #include "ED_keyframes_edit.h" @@ -140,7 +141,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor } else { Base *b; - + /* deselect all */ /* TODO: should this deselect all other types of channels too? */ for (b = sce->base.first; b; b = b->next) { @@ -268,6 +269,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor { AnimData *adt = BKE_animdata_from_id(ale->id); + /* button area... */ if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) { if (nlaedit_is_tweakmode_on(ac) == 0) { /* 'push-down' action - only usable when not in TweakMode */ @@ -283,6 +285,30 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor /* changes to NLA-Action occurred */ notifierFlags |= ND_NLA_ACTCHANGE; } + /* OR rest of name... */ + else { + /* NOTE: rest of NLA-Action name doubles for operating on the AnimData block + * - this is useful when there's no clear divider, and makes more sense in + * the case of users trying to use this to change actions + */ + + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); + adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if (adt->flag & ADT_UI_SELECTED) + adt->flag |= ADT_UI_ACTIVE; + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + } } break; @@ -301,7 +327,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor /* ------------------- */ /* handle clicking */ -static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; SpaceNla *snla; @@ -358,7 +384,7 @@ void NLA_OT_channels_click(wmOperatorType *ot) ot->poll = ED_operator_nla_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* props */ prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY @@ -371,24 +397,18 @@ void NLA_OT_channels_click(wmOperatorType *ot) /* ******************** Add Tracks Operator ***************************** */ /* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */ -static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op) +/* helper - add NLA Tracks alongside existing ones */ +static bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel) { - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; - AnimData *lastAdt = NULL; - short above_sel = RNA_boolean_get(op->ptr, "above_selected"); + bool added = false; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get a list of the AnimData blocks being shown in the NLA */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + /* get a list of the (selected) NLA Tracks being shown in the NLA */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* add tracks... */ for (ale = anim_data.first; ale; ale = ale->next) { @@ -402,11 +422,13 @@ static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op) if (above_sel) { /* just add a new one above this one */ add_nlatrack(adt, nlt); + added = true; } else if ((lastAdt == NULL) || (adt != lastAdt)) { /* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */ add_nlatrack(adt, NULL); lastAdt = adt; + added = true; } } } @@ -414,17 +436,80 @@ static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op) /* free temp data */ BLI_freelistN(&anim_data); - /* set notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + return added; +} + +/* helper - add NLA Tracks to empty (and selected) AnimData blocks */ +static bool nlaedit_add_tracks_empty(bAnimContext *ac) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool added = false; - /* done */ - return OPERATOR_FINISHED; + /* get a list of the selected AnimData blocks in the NLA */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* check if selected AnimData blocks are empty, and add tracks if so... */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ale->adt; + + /* sanity check */ + BLI_assert(adt->flag & ADT_UI_SELECTED); + + /* ensure it is empty */ + if (adt->nla_tracks.first == NULL) { + /* add new track to this AnimData block then */ + add_nlatrack(adt, NULL); + added = true; + } + } + + /* cleanup */ + BLI_freelistN(&anim_data); + + return added; +} + +/* ----- */ + +static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + bool above_sel = RNA_boolean_get(op->ptr, "above_selected"); + bool op_done = false; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* perform adding in two passes - existing first so that we don't double up for empty */ + op_done |= nlaedit_add_tracks_existing(&ac, above_sel); + op_done |= nlaedit_add_tracks_empty(&ac); + + /* done? */ + if (op_done) { + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; + } + else { + /* failed to add any tracks */ + BKE_report(op->reports, RPT_WARNING, + "Select an existing NLA Track or an empty action line first"); + + /* not done */ + return OPERATOR_CANCELLED; + } } void NLA_OT_tracks_add(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Track(s)"; + ot->name = "Add Tracks"; ot->idname = "NLA_OT_tracks_add"; ot->description = "Add NLA-Tracks above/after the selected tracks"; @@ -485,11 +570,11 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void NLA_OT_delete_tracks(wmOperatorType *ot) +void NLA_OT_tracks_delete(wmOperatorType *ot) { /* identifiers */ ot->name = "Delete Tracks"; - ot->idname = "NLA_OT_delete_tracks"; + ot->idname = "NLA_OT_tracks_delete"; ot->description = "Delete selected NLA-Tracks and the strips they contain"; /* api callbacks */ @@ -501,3 +586,59 @@ void NLA_OT_delete_tracks(wmOperatorType *ot) } /* *********************************************** */ +/* AnimData Related Operators */ + +/* ******************** Include Objects Operator ***************************** */ +/* Include selected objects in NLA Editor, by giving them AnimData blocks + * NOTE: This doesn't help for non-object AnimData, where we do not have any effective + * selection mechanism in place. Unfortunately, this means that non-object AnimData + * once again becomes a second-class citizen here. However, at least for the most + * common use case, we now have a nice shortcut again. + */ + +static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bAnimContext ac; + SpaceNla *snla; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* ensure that filters are set so that the effect will be immediately visible */ + snla = (SpaceNla *)ac.sl; + if (snla && snla->ads) { + snla->ads->filterflag &= ~ADS_FILTER_NLA_NOACT; + } + + /* operate on selected objects... */ + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + /* ensure that object has AnimData... that's all */ + BKE_id_add_animdata(&ob->id); + } + CTX_DATA_END; + + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +void NLA_OT_selected_objects_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Include Selected Objects"; + ot->idname = "NLA_OT_selected_objects_add"; + ot->description = "Make selected objects appear in NLA Editor by adding Animation Data"; + + /* api callbacks */ + ot->exec = nlaedit_objects_add_exec; + ot->poll = nlaop_poll_tweakmode_off; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index acfb4a51b14..56f2ec9ebe1 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -695,11 +695,8 @@ static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View special = ICON_ACTION; - if (act) - BLI_snprintf(name, sizeof(name), "%s", act->id.name + 2); - else - BLI_strncpy(name, "<No Action>", sizeof(name)); - + BLI_strncpy(name, act ? act->id.name + 2 : "<No Action>", sizeof(name)); + /* draw manually still */ do_draw = TRUE; } @@ -759,7 +756,6 @@ static void draw_nla_channel_list_gl(bAnimContext *ac, ListBase *anim_data, View glEnable(GL_BLEND); /* draw backing strip behind channel name */ - // FIXME: hardcoded colors!!! if (group == 5) { float color[4]; diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 484eb47fa8e..17d403789cf 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -200,7 +200,7 @@ static int nlaedit_disable_tweakmode_exec(bContext *C, wmOperator *op) for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ale->data; - /* try entering tweakmode if valid */ + /* to be sure, just exit tweakmode... */ BKE_nla_tweakmode_exit(adt); } @@ -891,7 +891,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } -static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { nlaedit_duplicate_exec(C, op); @@ -1627,7 +1627,7 @@ void NLA_OT_action_sync_length(wmOperatorType *ot) /* api callbacks */ ot->exec = nlaedit_sync_actlen_exec; - ot->poll = ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip... + ot->poll = nlaop_poll_tweakmode_off; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1801,7 +1801,7 @@ void NLA_OT_clear_scale(wmOperatorType *ot) /* defines for snap keyframes tool */ static EnumPropertyItem prop_nlaedit_snap_types[] = { - {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""}, + {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current Frame", ""}, {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry? {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry? {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""}, @@ -1947,7 +1947,7 @@ void NLA_OT_snap(wmOperatorType *ot) /* ******************** Add F-Modifier Operator *********************** */ /* present a special customised popup menu for this, with some filtering */ -static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -2021,8 +2021,9 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) /* add F-Modifier of specified type to selected, and make it the active one */ fcm = add_fmodifier(&strip->modifiers, type); - if (fcm) + if (fcm) { set_active_fmodifier(&strip->modifiers, fcm); + } else { BKE_reportf(op->reports, RPT_ERROR, "Modifier could not be added to (%s : %s) (see console for details)", @@ -2101,8 +2102,10 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); return OPERATOR_CANCELLED; } - else + else { + /* no updates needed - copy is non-destructive operation */ return OPERATOR_FINISHED; + } } void NLA_OT_fmodifier_copy(wmOperatorType *ot) @@ -2156,8 +2159,6 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op) /* successful or not? */ if (ok) { - /* set notifier that things have changed */ - /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 398d2d5f1f4..450b85738ad 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -125,7 +125,9 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot); void NLA_OT_channels_click(wmOperatorType *ot); void NLA_OT_tracks_add(wmOperatorType *ot); -void NLA_OT_delete_tracks(wmOperatorType *ot); +void NLA_OT_tracks_delete(wmOperatorType *ot); + +void NLA_OT_selected_objects_add(wmOperatorType *ot); /* **************************************** */ /* nla_ops.c */ diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 54ade829c0d..fb0f11ffd87 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -120,7 +120,9 @@ void nla_operatortypes(void) WM_operatortype_append(NLA_OT_channels_click); WM_operatortype_append(NLA_OT_tracks_add); - WM_operatortype_append(NLA_OT_delete_tracks); + WM_operatortype_append(NLA_OT_tracks_delete); + + WM_operatortype_append(NLA_OT_selected_objects_add); /* select */ WM_operatortype_append(NLA_OT_click_select); @@ -188,8 +190,8 @@ static void nla_keymap_channels(wmKeyMap *keymap) RNA_boolean_set(kmi->ptr, "above_selected", TRUE); /* delete tracks */ - WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", XKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", DELKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", DELKEY, KM_PRESS, 0, 0); } static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap) diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 97553b7aa56..3e414233add 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -451,7 +451,7 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; short leftright = RNA_enum_get(op->ptr, "mode"); @@ -613,7 +613,7 @@ static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], s /* ------------------- */ /* handle clicking */ -static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; /* Scene *scene; */ /* UNUSED */ @@ -660,7 +660,7 @@ void NLA_OT_click_select(wmOperatorType *ot) ot->poll = ED_operator_nla_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO; /* properties */ prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 8a2e03f2660..4a14d6ba6fd 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -687,14 +687,14 @@ static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket * static void draw_group_socket(const bContext *C, SpaceNode *snode, bNodeTree *ntree, bNode *gnode, bNodeSocket *sock, bNodeSocket *gsock, int index, int in_out) { - const float dpi_fac = 1.0f; + const float dpi_fac = UI_DPI_FAC; bNodeTree *ngroup = (bNodeTree *)gnode->id; bNodeSocketType *stype = ntreeGetSocketType(gsock ? gsock->type : sock->type); uiBut *bt; float offset; int draw_value; const float node_group_frame = NODE_GROUP_FRAME * dpi_fac; - const float socket_size = NODE_SOCKSIZE * dpi_fac; + const float socket_size = NODE_SOCKSIZE; const float arrowbutw = 0.8f * UI_UNIT_X; const short co_text_w = 72 * dpi_fac; const float co_margin = 6.0f * dpi_fac; @@ -799,12 +799,12 @@ static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bN uiLayout *layout; PointerRNA ptr; rctf rect = gnode->totr; - const float dpi_fac = 1.0f; + const float dpi_fac = UI_DPI_FAC; const float node_group_frame = NODE_GROUP_FRAME * dpi_fac; const float group_header = 26 * dpi_fac; int index; - + /* backdrop header */ glEnable(GL_BLEND); uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); @@ -1296,11 +1296,11 @@ static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), Poin uiItemR(row, ptr, "scale", 0, "", ICON_NONE); row = uiLayoutRow(layout, TRUE); - uiItemR(row, ptr, "use_min", 0, "Min", ICON_NONE); + uiItemR(row, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE); uiItemR(row, ptr, "min", 0, "", ICON_NONE); row = uiLayoutRow(layout, TRUE); - uiItemR(row, ptr, "use_max", 0, "Max", ICON_NONE); + uiItemR(row, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE); uiItemR(row, ptr, "max", 0, "", ICON_NONE); } @@ -3301,7 +3301,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPixelZoom(snode->zoom, snode->zoom); - glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer); + glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer); glPixelZoom(1.0f, 1.0f); glDisable(GL_BLEND); @@ -3309,7 +3309,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) else { glPixelZoom(snode->zoom, snode->zoom); - glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer); + glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, display_buffer); glPixelZoom(1.0f, 1.0f); } @@ -3320,6 +3320,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) /** @note draw selected info on backdrop */ if (snode->edittree) { bNode *node = snode->edittree->nodes.first; + rctf *viewer_border = &snode->edittree->viewer_border; while (node) { if (node->flag & NODE_SELECT) { if (node->typeinfo->uibackdropfunc) { @@ -3328,6 +3329,23 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) } node = node->next; } + + if ((snode->edittree->flag & NTREE_VIEWER_BORDER) && + viewer_border->xmin < viewer_border->xmax && + viewer_border->ymin < viewer_border->ymax) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + setlinestyle(3); + cpack(0x4040FF); + + glRectf(x + snode->zoom * viewer_border->xmin * ibuf->x, + y + snode->zoom * viewer_border->ymin * ibuf->y, + x + snode->zoom * viewer_border->xmax * ibuf->x, + y + snode->zoom * viewer_border->ymax * ibuf->y); + + setlinestyle(0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } } glMatrixMode(GL_PROJECTION); @@ -3340,57 +3358,6 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode) } } -#if 0 -/* note: needs to be userpref or opengl profile option */ -static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode) -{ - - draw_nodespace_grid(snode); - - if (snode->flag & SNODE_BACKDRAW) { - Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ibuf) { - int x, y; - float zoom = 1.0; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - glaDefine2DArea(&sa->winrct); - - if (ibuf->x > sa->winx || ibuf->y > sa->winy) { - float zoomx, zoomy; - zoomx = (float)sa->winx / ibuf->x; - zoomy = (float)sa->winy / ibuf->y; - zoom = min_ff(zoomx, zoomy); - } - - x = (sa->winx - zoom * ibuf->x) / 2 + snode->xof; - y = (sa->winy - zoom * ibuf->y) / 2 + snode->yof; - - glPixelZoom(zoom, zoom); - - glColor4f(1.0, 1.0, 1.0, 1.0); - if (ibuf->rect) - glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect); - else if (ibuf->channels == 4) - glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float); - - glPixelZoom(1.0, 1.0); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - BKE_image_release_ibuf(ima, ibuf, NULL); - } - } -} -#endif /* if v2d not NULL, it clips and returns 0 if not visible */ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol) diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index 4943bb45113..235d91ecd92 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -400,7 +400,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_add_file_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 34f7799d47c..d6a3a6a6a3f 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -629,7 +629,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */ glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect); + glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect); glDisable(GL_BLEND); glPixelZoom(1.0f, 1.0f); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index fb4e4f62e52..941bd783c39 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -73,6 +73,8 @@ #include "GPU_material.h" +#include "IMB_imbuf_types.h" + #include "node_intern.h" /* own include */ #define USE_ESC_COMPO @@ -835,7 +837,7 @@ typedef struct NodeSizeWidget { int directions; } NodeSizeWidget; -static void node_resize_init(bContext *C, wmOperator *op, wmEvent *UNUSED(event), bNode *node, int dir) +static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir) { SpaceNode *snode = CTX_wm_space_node(C); @@ -868,7 +870,7 @@ static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel)) op->customdata = NULL; } -static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) +static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -971,7 +973,7 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -1055,7 +1057,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) } /* return 0, nothing done */ -static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode * snode) +static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode *snode) { bNode *gnode; float mx = 0, my = 0; @@ -2138,7 +2140,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -2281,3 +2283,105 @@ void NODE_OT_shader_script_update(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************** Viewer border ******************/ + +static void viewer_border_corner_to_backdrop(SpaceNode *snode, ARegion *ar, int x, int y, + int backdrop_width, int backdrop_height, + float *fx, float *fy) +{ + float bufx, bufy; + + bufx = backdrop_width * snode->zoom; + bufy = backdrop_height * snode->zoom; + + *fx = (bufx > 0.0f ? ((float) x - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f); + *fy = (bufy > 0.0f ? ((float) y - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f); +} + +static int viewer_border_exec(bContext *C, wmOperator *op) +{ + Image *ima; + void *lock; + ImBuf *ibuf; + + ED_preview_kill_jobs(C); + + ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + ARegion *ar = CTX_wm_region(C); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *btree = snode->edittree; + rcti rect; + rctf rectf; + + /* get border from operator */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* convert border to unified space within backdrop image */ + viewer_border_corner_to_backdrop(snode, ar, rect.xmin, rect.ymin, ibuf->x, ibuf->y, + &rectf.xmin, &rectf.ymin); + + viewer_border_corner_to_backdrop(snode, ar, rect.xmax, rect.ymax, ibuf->x, ibuf->y, + &rectf.xmax, &rectf.ymax); + + /* clamp coordinates */ + rectf.xmin = max_ff(rectf.xmin, 0.0f); + rectf.ymin = max_ff(rectf.ymin, 0.0f); + rectf.xmax = min_ff(rectf.xmax, 1.0f); + rectf.ymax = min_ff(rectf.ymax, 1.0f); + + if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) { + btree->viewer_border = rectf; + + if (rectf.xmin == 0.0f && rectf.ymin == 0.0f && + rectf.xmax == 1.0f && rectf.ymax == 1.0f) + { + btree->flag &= ~NTREE_VIEWER_BORDER; + } + else { + if (ibuf->rect) + memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y); + + if (ibuf->rect_float) + memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float)); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + btree->flag |= NTREE_VIEWER_BORDER; + } + + snode_notify(C, snode); + WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL); + } + else { + btree->flag &= ~NTREE_VIEWER_BORDER; + } + } + + BKE_image_release_ibuf(ima, ibuf, lock); + + return OPERATOR_FINISHED; +} + +void NODE_OT_viewer_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Viewer Border"; + ot->description = "Set the boundaries for viewer operations"; + ot->idname = "NODE_OT_viewer_border"; + + /* api callbacks */ + ot->invoke = WM_border_select_invoke; + ot->exec = viewer_border_exec; + ot->modal = WM_border_select_modal; + ot->cancel = WM_border_select_cancel; + ot->poll = composite_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_border(ot, TRUE); +} diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 7b7b98f132c..6696284b169 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -133,7 +133,7 @@ static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int node_group_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceNode *snode = CTX_wm_space_node(C); bNode *gnode; @@ -789,7 +789,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE); uiLayout *layout = uiPupMenuLayout(pup); @@ -1146,7 +1146,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { SpaceNode *snode = CTX_wm_space_node(C); bNode *act = nodeGetActive(snode->edittree); diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index e8dd1cf1528..cbf7101a101 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -217,6 +217,8 @@ void NODE_OT_clipboard_paste(struct wmOperatorType *ot); void NODE_OT_shader_script_update(struct wmOperatorType *ot); +void NODE_OT_viewer_border(struct wmOperatorType *ot); + extern const char *node_context_dir[]; // XXXXXX diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 8adccd9e6c4..d16c6627d3f 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -120,6 +120,8 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_clipboard_paste); WM_operatortype_append(NODE_OT_shader_script_update); + + WM_operatortype_append(NODE_OT_viewer_border); } void ED_operatormacros_node(void) @@ -298,5 +300,7 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_clipboard_copy", CKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "NODE_OT_viewer_border", BKEY, KM_PRESS, KM_CTRL, 0); + transform_keymap_for_space(keyconf, keymap, SPACE_NODE); } diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 8d7eef22822..097e4f418e0 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -448,7 +448,7 @@ static int outside_group_rect(SpaceNode *snode) /* loop that adds a nodelink, called by function below */ /* in_out = starting socket */ -static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) +static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -702,7 +702,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) return nldrag; } -static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -840,7 +840,9 @@ static int cut_links_exec(bContext *C, wmOperator *op) if (i > 1) { int found = FALSE; bNodeLink *link, *next; - + + ED_preview_kill_jobs(C); + for (link = snode->edittree->links.first; link; link = next) { next = link->next; @@ -1181,7 +1183,7 @@ static int node_attach_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int node_attach_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_attach_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 7d2b80d50ba..c917b8ee756 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -429,7 +429,7 @@ static int node_select_exec(bContext *C, wmOperator *op) } } -static int node_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RNA_int_set(op->ptr, "mouse_x", event->mval[0]); RNA_int_set(op->ptr, "mouse_y", event->mval[1]); @@ -494,7 +494,7 @@ static int node_borderselect_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int node_border_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int tweak = RNA_boolean_get(op->ptr, "tweak"); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index a69e73c1489..a8e84e0a0e5 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -196,7 +196,7 @@ typedef struct NodeViewMove { int xmin, ymin, xmax, ymax; } NodeViewMove; -static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) +static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -231,7 +231,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -413,7 +413,7 @@ int ED_space_node_color_sample(SpaceNode *snode, ARegion *ar, int mval[2], float return ret; } -static void sample_apply(bContext *C, wmOperator *op, wmEvent *event) +static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -513,7 +513,7 @@ static void sample_exit(bContext *C, wmOperator *op) MEM_freeN(info); } -static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); @@ -534,7 +534,7 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int sample_modal(bContext *C, wmOperator *op, wmEvent *event) +static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 264bea5f871..75f28baf558 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -423,7 +423,7 @@ static void node_main_area_draw(const bContext *C, ARegion *ar) /* ************* dropboxes ************* */ -static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int node_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index cacbc6d6268..26a0d0a2fa8 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -41,6 +41,8 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_depsgraph.h" @@ -50,6 +52,7 @@ #include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_object.h" #include "ED_armature.h" #include "ED_object.h" @@ -129,11 +132,66 @@ static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int start /* ****************************************************** */ +static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag) +{ + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { + if (set_flag) { + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + ebone->flag |= flag; + } + else { + ebone->flag &= ~flag; + } + } + } +} + +static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bone_parent, int flag, bool set_flag) +{ + Bone *bone; + for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + if (set_flag) { + bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + bone->flag |= flag; + } + else { + bone->flag &= ~flag; + } + restrictbutton_recursive_bone(C, arm, bone, flag, set_flag); + } + +} + +static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag, + bool state, bool deselect) +{ + Main *bmain = CTX_data_main(C); + Object *ob; + for (ob = bmain->object.first; ob; ob = ob->id.next) { + if (BKE_object_is_child_recursive(ob_parent, ob)) { + if (state) { + ob->restrictflag |= flag; + if (deselect) { + ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); + } + } + else { + ob->restrictflag &= ~flag; + } + } + } +} + static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2) { Scene *scene = (Scene *)poin; Object *ob = (Object *)poin2; - + if (!common_restrict_check(C, ob)) return; /* deselect objects that are invisible */ @@ -142,6 +200,12 @@ static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2) * so have to do loop to find it. */ ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); } + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW, + (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true); + } + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } @@ -159,12 +223,25 @@ static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2) * so have to do loop to find it. */ ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT); } + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT, + (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true); + } + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } -static void restrictbutton_rend_cb(bContext *C, void *poin, void *UNUSED(poin2)) +static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2) { + Object *ob = (Object *)poin2; + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER, + (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false); + } + WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin); } @@ -182,19 +259,59 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); } -static void restrictbutton_bone_cb(bContext *C, void *UNUSED(poin), void *poin2) +static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2) { + bArmature *arm = (bArmature *)poin; Bone *bone = (Bone *)poin2; if (bone && (bone->flag & BONE_HIDDEN_P)) bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_bone(C, arm, bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); +} + +static void restrictbutton_bone_select_cb(bContext *C, void *poin, void *poin2) +{ + bArmature *arm = (bArmature *)poin; + Bone *bone = (Bone *)poin2; + if (bone && (bone->flag & BONE_UNSELECTABLE)) + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_bone(C, arm, bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0); + } + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } -static void restrictbutton_ebone_cb(bContext *C, void *UNUSED(poin), void *poin2) +static void restrictbutton_ebone_select_cb(bContext *C, void *UNUSED(poin), void *poin2) { EditBone *ebone = (EditBone *)poin2; - if (ebone && (ebone->flag & BONE_HIDDEN_A)) + + if (ebone->flag & BONE_UNSELECTABLE) { ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_ebone(C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); +} + +static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2) +{ + EditBone *ebone = (EditBone *)poin2; + if (ebone->flag & BONE_HIDDEN_A) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0); + } WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } @@ -238,7 +355,7 @@ static int group_select_flag(Group *gr) } void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) -{ +{ Scene *scene = (Scene *)poin; GroupObject *gob; Group *gr = (Group *)poin2; @@ -297,7 +414,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) TreeElement *te = outliner_find_tse(soops, tselem); if (tselem->type == 0) { - test_idbutton(tselem->id->name + 2); // library.c, unique name and alpha sort + test_idbutton(tselem->id->name); // library.c, unique name and alpha sort switch (GS(tselem->id->name)) { case ID_MA: @@ -332,7 +449,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object break; case TSE_NLA_ACTION: - test_idbutton(tselem->id->name + 2); + test_idbutton(tselem->id->name); break; case TSE_EBONE: { @@ -389,7 +506,8 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) Object *ob = (Object *)tselem->id; // id = object bActionGroup *grp = te->directdata; - BLI_uniquename(&ob->pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name)); + BLI_uniquename(&ob->pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), + sizeof(grp->name)); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); } break; @@ -422,17 +540,20 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, "hide", -1, 0, 0, -1, -1, NULL); + &ptr, "hide", -1, 0, 0, -1, -1, + TIP_("Restrict viewport visibility (Ctrl - Recursive)")); uiButSetFunc(bt, restrictbutton_view_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, "hide_select", -1, 0, 0, -1, -1, NULL); + &ptr, "hide_select", -1, 0, 0, -1, -1, + TIP_("Restrict viewport selection (Ctrl - Recursive)")); uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, "hide_render", -1, 0, 0, -1, -1, NULL); + &ptr, "hide_render", -1, 0, 0, -1, -1, + TIP_("Restrict rendering (Ctrl - Recursive)")); uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob); uiBlockSetEmboss(block, UI_EMBOSS); @@ -447,19 +568,19 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW); bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View")); uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT); bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View")); uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER); bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, "Restrict/Allow renderability"); + NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability")); uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr); uiBlockSetEmboss(block, UI_EMBOSS); @@ -469,8 +590,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - te->directdata, 0, 0, 0, 0, "Render this RenderLayer"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer")); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); uiBlockSetEmboss(block, UI_EMBOSS); @@ -483,8 +604,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - layflag, 0, 0, 0, 0, "Render this Pass"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass")); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); layflag++; /* is lay_xor */ @@ -492,8 +613,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT)) { bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - layflag, 0, 0, 0, 0, "Exclude this Pass from Combined"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined")); } uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); @@ -505,43 +626,49 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, + TIP_("Restrict/Allow visibility in the 3D View")); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability")); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); } else if (tselem->type == TSE_POSE_CHANNEL) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; + ob = (Object *)tselem->id; uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); - uiButSetFunc(bt, restrictbutton_bone_cb, NULL, bone); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, + TIP_("Restrict/Allow visibility in the 3D View")); + uiButSetFunc(bt, restrictbutton_bone_visibility_cb, ob->data, bone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); - uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, + TIP_("Restrict/Allow selection in the 3D View")); + uiButSetFunc(bt, restrictbutton_bone_select_cb, ob->data, bone); } else if (tselem->type == TSE_EBONE) { EditBone *ebone = (EditBone *)te->directdata; uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); - uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, ebone); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, + TIP_("Restrict/Allow visibility in the 3D View")); + uiButSetFunc(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, - &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); - uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, NULL); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, + UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, + TIP_("Restrict/Allow selection in the 3D View")); + uiButSetFunc(bt, restrictbutton_ebone_select_cb, NULL, ebone); } } @@ -571,7 +698,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) } static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb) -{ +{ TreeElement *te; TreeStoreElem *tselem; PointerRNA *ptr; @@ -586,14 +713,17 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa ptr = &te->rnaptr; prop = te->directdata; - if (!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem, soops))) ) - uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, UI_UNIT_Y - 1); + if (!(RNA_property_type(prop) == PROP_POINTER && (TSELEM_OPEN(tselem, soops)))) { + uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); + } } else if (tselem->type == TSE_RNA_ARRAY_ELEM) { ptr = &te->rnaptr; prop = te->directdata; - uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, UI_UNIT_Y - 1); + uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, (int)te->ys, OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); } } @@ -615,7 +745,7 @@ static void operator_search_cb(const struct bContext *UNUSED(C), void *UNUSED(ar { GHashIterator *iter = WM_operatortype_iter(); - for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) { wmOperatorType *ot = BLI_ghashIterator_getValue(iter); if (BLI_strcasestr(ot->idname, str)) { @@ -806,7 +936,8 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo /* pass */ } else { - uiDefBlockBut(block, operator_search_menu, kmi, "", xstart, (int)te->ys + 1, butw1, UI_UNIT_Y - 1, "Assign new Operator"); + uiDefBlockBut(block, operator_search_menu, kmi, "", xstart, (int)te->ys + 1, butw1, UI_UNIT_Y - 1, + TIP_("Assign new Operator")); } xstart += butw1 + 10; @@ -814,43 +945,58 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo kmi->maptype = keymap_menu_type(kmi->type); str = keymap_type_menu(); - but = uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->maptype, 0, 0, 0, 0, "Event type"); + but = uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->maptype, + 0, 0, 0, 0, TIP_("Event type")); uiButSetFunc(but, keymap_type_cb, kmi, NULL); xstart += butw2 + 5; /* edit actual event */ switch (kmi->maptype) { case OL_KM_KEYBOARD: - uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, "Key code"); + uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, + TIP_("Key code")); xstart += butw2 + 5; break; case OL_KM_MOUSE: str = keymap_mouse_menu(); - uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, 0, 0, 0, 0, "Mouse button"); + uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, + 0, 0, 0, 0, TIP_("Mouse button")); xstart += butw2 + 5; break; case OL_KM_TWEAK: str = keymap_tweak_menu(); - uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, 0, 0, 0, 0, "Tweak gesture"); + uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->type, + 0, 0, 0, 0, TIP_("Tweak gesture")); xstart += butw2 + 5; str = keymap_tweak_dir_menu(); - uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->val, 0, 0, 0, 0, "Tweak gesture direction"); + uiDefButS(block, MENU, 0, str, xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->val, + 0, 0, 0, 0, TIP_("Tweak gesture direction")); xstart += butw2 + 5; break; } /* modifiers */ - uiDefButS(block, OPTION, 0, "Shift", xstart, (int)te->ys + 1, butw3 + 5, UI_UNIT_Y - 1, &kmi->shift, 0, 0, 0, 0, "Modifier"); xstart += butw3 + 5; - uiDefButS(block, OPTION, 0, "Ctrl", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->ctrl, 0, 0, 0, 0, "Modifier"); xstart += butw3; - uiDefButS(block, OPTION, 0, "Alt", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->alt, 0, 0, 0, 0, "Modifier"); xstart += butw3; - uiDefButS(block, OPTION, 0, "OS", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->oskey, 0, 0, 0, 0, "Modifier"); xstart += butw3; - xstart += 5; - uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->keymodifier, "Key Modifier code"); + uiDefButS(block, OPTION, 0, IFACE_("Shift"), xstart, (int)te->ys + 1, butw3 + 5, UI_UNIT_Y - 1, + &kmi->shift, 0, 0, 0, 0, TIP_("Modifier")); + xstart += butw3 + 5; + uiDefButS(block, OPTION, 0, IFACE_("Ctrl"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->ctrl, + 0, 0, 0, 0, TIP_("Modifier")); + xstart += butw3; + uiDefButS(block, OPTION, 0, IFACE_("Alt"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->alt, + 0, 0, 0, 0, TIP_("Modifier")); + xstart += butw3; + uiDefButS(block, OPTION, 0, IFACE_("OS"), xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->oskey, + 0, 0, 0, 0, TIP_("Modifier")); + xstart += butw3 + 5; + uiDefKeyevtButS(block, 0, "", xstart, (int)te->ys + 1, butw3, UI_UNIT_Y - 1, &kmi->keymodifier, + TIP_("Key Modifier code")); xstart += butw3 + 5; /* rna property */ if (kmi->ptr && kmi->ptr->data) { - uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, NULL, 0, 0, 0, 0, ""); xstart += butw2; + uiDefBut(block, LABEL, 0, IFACE_("(RNA property)"), xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, + NULL, 0, 0, 0, 0, ""); + xstart += butw2; } (void)xstart; @@ -878,7 +1024,8 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Spa /* If we add support to rename Sequence. * need change this. */ - if (tselem->type == TSE_POSE_BASE) continue; // prevent crash when trying to rename 'pose' entry of armature + // prevent crash when trying to rename 'pose' entry of armature + if (tselem->type == TSE_POSE_BASE) continue; if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name); else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name); @@ -891,7 +1038,8 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Spa spx = te->xs + 2 * UI_UNIT_X - 4; if (spx + dx + 10 > ar->v2d.cur.xmax) dx = ar->v2d.cur.xmax - spx - 10; - bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, (int)te->ys, dx + 10, UI_UNIT_Y - 1, (void *)te->name, 1.0, (float)len, 0, 0, ""); + bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, (int)te->ys, dx + 10, UI_UNIT_Y - 1, (void *)te->name, + 1.0, (float)len, 0, 0, ""); uiButSetRenameFunc(bt, namebutton_cb, tselem); /* returns false if button got removed */ @@ -924,7 +1072,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) glDisable(GL_BLEND); } else { - uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : ""); + uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL, + 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : ""); if (arg->id) uiButSetDragID(but, arg->id); @@ -932,7 +1081,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) } -static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, float alpha) +static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, + float alpha) { struct DrawIconArg arg; float aspect; @@ -1217,7 +1367,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto } } -static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level, int xmax, int *offsx, int ys) +static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level, + int xmax, int *offsx, int ys) { TreeElement *te; TreeStoreElem *tselem; @@ -1236,12 +1387,20 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa /* active blocks get white circle */ if (tselem->type == 0) { - if (te->idcode == ID_OB) active = (OBACT == (Object *)tselem->id); - else if (scene->obedit && scene->obedit->data == tselem->id) active = 1; // XXX use context? - else active = tree_element_active(C, scene, soops, te, 0); + if (te->idcode == ID_OB) { + active = (OBACT == (Object *)tselem->id); + } + else if (scene->obedit && scene->obedit->data == tselem->id) { + active = 1; // XXX use context? + } + else { + active = tree_element_active(C, scene, soops, te, 0); + } } - else active = tree_element_type_active(NULL, scene, soops, te, tselem, 0); - + else { + active = tree_element_type_active(NULL, scene, soops, te, tselem, 0, false); + } + if (active) { float ufac = UI_UNIT_X / 20.0f; @@ -1286,7 +1445,8 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i } -static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement *te, int startx, int *starty) +static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, + TreeElement *te, int startx, int *starty) { TreeElement *ten; TreeStoreElem *tselem; @@ -1377,7 +1537,7 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene } } else { - if (tree_element_type_active(NULL, scene, soops, te, tselem, 0) ) active = 2; + if (tree_element_type_active(NULL, scene, soops, te, tselem, 0, false) ) active = 2; glColor4ub(220, 220, 255, alpha); } @@ -1685,15 +1845,17 @@ void draw_outliner(const bContext *C) sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX); /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ - if (soops->outlinevis == SO_KEYMAP) - sizex = sizex_rna + OL_RNA_COL_SIZEX * 3 + 50; // XXX this is only really a quick hack to make this wide enough... + if (soops->outlinevis == SO_KEYMAP) + // XXX this is only really a quick hack to make this wide enough... + sizex = sizex_rna + OL_RNA_COL_SIZEX * 3 + 50; else sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; } else { /* width must take into account restriction columns (if visible) so that entries will still be visible */ //outliner_width(soops, &soops->tree, &sizex); - outliner_rna_width(soops, &soops->tree, &sizex, 0); // XXX should use outliner_width instead when te->xend will be set correctly... + // XXX should use outliner_width instead when te->xend will be set correctly... + outliner_rna_width(soops, &soops->tree, &sizex, 0); /* constant offset for restriction columns */ // XXX this isn't that great yet... diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 9a1b3628196..1e67e099508 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -146,7 +146,7 @@ static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement } /* event can enterkey, then it opens/closes */ -static int outliner_item_openclose(bContext *C, wmOperator *op, wmEvent *event) +static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -222,12 +222,12 @@ static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, T if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); - /* name and first icon */ - if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) { - + /* click on name */ + if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) { do_item_rename(ar, te, tselem, reports); + return 1; } - return 1; + return 0; } for (te = te->subtree.first; te; te = te->next) { @@ -236,20 +236,24 @@ static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, T return 0; } -static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te; float fmval[2]; + bool change = false; UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval + 1); for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_rename(C, ar, soops, te, fmval)) break; + if (do_outliner_item_rename(C, ar, soops, te, fmval)) { + change = true; + break; + } } - return OPERATOR_FINISHED; + return change ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH; } @@ -890,9 +894,13 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase else tselem->flag |= TSE_CLOSED; } } - else tselem->flag |= TSE_CLOSED; - - if (TSELEM_OPEN(tselem, soops)) tree_element_show_hierarchy(scene, soops, &te->subtree); + else { + tselem->flag |= TSE_CLOSED; + } + + if (TSELEM_OPEN(tselem, soops)) { + tree_element_show_hierarchy(scene, soops, &te->subtree); + } } } @@ -1440,7 +1448,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op) } /* Used for drag and drop parenting */ -TreeElement *outliner_dropzone_parent(bContext *C, wmEvent *event, TreeElement *te, float *fmval) +TreeElement *outliner_dropzone_parent(bContext *C, const wmEvent *event, TreeElement *te, const float fmval[2]) { SpaceOops *soops = CTX_wm_space_outliner(C); TreeStoreElem *tselem = TREESTORE(te); @@ -1469,7 +1477,7 @@ TreeElement *outliner_dropzone_parent(bContext *C, wmEvent *event, TreeElement * return NULL; } -static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *par = NULL; Object *ob = NULL; @@ -1643,7 +1651,7 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); } -int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te, float *fmval) +int outliner_dropzone_parent_clear(bContext *C, const wmEvent *event, TreeElement *te, const float fmval[2]) { SpaceOops *soops = CTX_wm_space_outliner(C); TreeStoreElem *tselem = TREESTORE(te); @@ -1681,7 +1689,7 @@ int outliner_dropzone_parent_clear(bContext *C, wmEvent *event, TreeElement *te, return 0; } -static int parent_clear_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); Scene *scene = NULL; @@ -1730,7 +1738,7 @@ void OUTLINER_OT_parent_clear(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", ""); } -TreeElement *outliner_dropzone_scene(bContext *C, wmEvent *UNUSED(event), TreeElement *te, float *fmval) +TreeElement *outliner_dropzone_scene(bContext *C, const wmEvent *UNUSED(event), TreeElement *te, const float fmval[2]) { SpaceOops *soops = CTX_wm_space_outliner(C); TreeStoreElem *tselem = TREESTORE(te); @@ -1746,7 +1754,7 @@ TreeElement *outliner_dropzone_scene(bContext *C, wmEvent *UNUSED(event), TreeEl return NULL; } -static int scene_drop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = NULL; Object *ob = NULL; @@ -1822,7 +1830,7 @@ void OUTLINER_OT_scene_drop(wmOperatorType *ot) RNA_def_string(ot->srna, "scene", "Scene", MAX_ID_NAME, "Scene", "Target Scene"); } -static int material_drop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Material *ma = NULL; Object *ob = NULL; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 63452de18d0..a918357ced2 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -165,8 +165,9 @@ void draw_outliner(const struct bContext *C); void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag); /* outliner_select.c -------------------------------------------- */ -int tree_element_type_active(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set); +int tree_element_type_active(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive); int tree_element_active(struct bContext *C, struct Scene *scene, SpaceOops *soops, TreeElement *te, int set); +int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive); /* outliner_edit.c ---------------------------------------------- */ @@ -189,9 +190,9 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); -TreeElement *outliner_dropzone_parent(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval); -int outliner_dropzone_parent_clear(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval); -TreeElement *outliner_dropzone_scene(struct bContext *C, struct wmEvent *event, struct TreeElement *te, float *fmval); +TreeElement *outliner_dropzone_parent(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]); +int outliner_dropzone_parent_clear(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]); +TreeElement *outliner_dropzone_scene(struct bContext *C, const struct wmEvent *event, struct TreeElement *te, const float fmval[2]); /* ...................................................... */ void OUTLINER_OT_item_activate(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 1dd043409a5..b9e3942a7ce 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -30,12 +30,12 @@ #include "DNA_space_types.h" -#include "WM_api.h" -#include "WM_types.h" +#include "BLI_utildefines.h" #include "RNA_access.h" -#include "BLI_utildefines.h" +#include "WM_api.h" +#include "WM_types.h" #include "outliner_intern.h" @@ -88,10 +88,22 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0); + RNA_boolean_set(kmi->ptr, "recursive", FALSE); RNA_boolean_set(kmi->ptr, "extend", FALSE); + kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "recursive", FALSE); + RNA_boolean_set(kmi->ptr, "extend", TRUE); + + kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "recursive", TRUE); + RNA_boolean_set(kmi->ptr, "extend", FALSE); + + kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "recursive", TRUE); RNA_boolean_set(kmi->ptr, "extend", TRUE); + WM_keymap_add_item(keymap, "OUTLINER_OT_select_border", BKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index fa337ba7af1..6fcfb457615 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -47,8 +47,11 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_main.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_armature.h" #include "ED_armature.h" #include "ED_object.h" @@ -140,7 +143,50 @@ static int tree_element_active_renderlayer(bContext *C, TreeElement *te, TreeSto return 0; } -static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te, int set) +/** + * Select object tree: + * CTRL+LMB: Select/Deselect object and all cildren + * CTRL+SHIFT+LMB: Add/Remove object and all children + */ +static void do_outliner_object_select_recursive(Scene *scene, Object *ob_parent, bool select) +{ + Base *base; + + for (base = FIRSTBASE; base; base = base->next) { + Object *ob = base->object; + if ((((ob->restrictflag & OB_RESTRICT_VIEW) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) { + ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); + } + } +} + +static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select) +{ + Bone *bone; + for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + if (select && PBONE_SELECTABLE(arm, bone)) + bone->flag |= BONE_SELECTED; + else + bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + do_outliner_bone_select_recursive(arm, bone, select); + } +} + +static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select) +{ + EditBone *ebone; + for (ebone = ebone_parent->next; ebone; ebone = ebone->next) { + if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { + if (select && EBONE_SELECTABLE(arm, ebone)) + ebone->flag |= BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL; + else + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } + } +} + +static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops *soops, + TreeElement *te, int set, bool recursive) { TreeStoreElem *tselem = TREESTORE(te); Scene *sce; @@ -148,7 +194,9 @@ static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops Object *ob = NULL; /* if id is not object, we search back */ - if (te->idcode == ID_OB) ob = (Object *)tselem->id; + if (te->idcode == ID_OB) { + ob = (Object *)tselem->id; + } else { ob = (Object *)outliner_search_back(soops, te, ID_OB); if (ob == OBACT) return 0; @@ -176,6 +224,12 @@ static int tree_element_set_active_object(bContext *C, Scene *scene, SpaceOops BKE_scene_base_deselect_all(scene); ED_base_object_select(base, BA_SELECT); } + + if (recursive) { + /* Recursive select/deselect for Object hierarchies */ + do_outliner_object_select_recursive(scene, ob, (ob->flag & SELECT) != 0); + } + if (C) { ED_base_object_activate(C, base); /* adds notifier */ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -312,7 +366,9 @@ static int tree_element_active_lamp(bContext *UNUSED(C), Scene *scene, SpaceOops if (set) { // XXX extern_set_butspace(F5KEY, 0); } - else return 1; + else { + return 1; + } return 0; } @@ -395,7 +451,7 @@ static int tree_element_active_posegroup(bContext *C, Scene *scene, TreeElement return 0; } -static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set) +static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive) { Object *ob = (Object *)tselem->id; bArmature *arm = ob->data; @@ -404,9 +460,13 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen if (set) { if (!(pchan->bone->flag & BONE_HIDDEN_P)) { - if (set == 2) ED_pose_deselectall(ob, 2); // 2 = clear active tag - else ED_pose_deselectall(ob, 0); // 0 = deselect - + if (set != 2) { + bPoseChannel *pchannel; + /* single select forces all other bones to get unselected */ + for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next) + pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } + if (set == 2 && (pchan->bone->flag & BONE_SELECTED)) { pchan->bone->flag &= ~BONE_SELECTED; } @@ -414,7 +474,12 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen pchan->bone->flag |= BONE_SELECTED; arm->act_bone = pchan->bone; } - + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_bone_select_recursive(arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0); + } + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); } @@ -427,7 +492,7 @@ static int tree_element_active_posechannel(bContext *C, Scene *scene, TreeElemen return 0; } -static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set) +static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, int set, bool recursive) { bArmature *arm = (bArmature *)tselem->id; Bone *bone = te->directdata; @@ -436,8 +501,12 @@ static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, if (!(bone->flag & BONE_HIDDEN_P)) { Object *ob = OBACT; if (ob) { - if (set == 2) ED_pose_deselectall(ob, 2); // 2 is clear active tag - else ED_pose_deselectall(ob, 0); + if (set != 2) { + bPoseChannel *pchannel; + /* single select forces all other bones to get unselected */ + for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next) + pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } } if (set == 2 && (bone->flag & BONE_SELECTED)) { @@ -447,6 +516,12 @@ static int tree_element_active_bone(bContext *C, Scene *scene, TreeElement *te, bone->flag |= BONE_SELECTED; arm->act_bone = bone; } + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0); + } + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); } @@ -479,35 +554,42 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, scene->obedit); } -static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set) +static int tree_element_active_ebone(bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), int set, bool recursive) { bArmature *arm = scene->obedit->data; EditBone *ebone = te->directdata; - - if (set == 1) { - if (!(ebone->flag & BONE_HIDDEN_A)) { - ED_armature_deselect_all(scene->obedit, 0); // deselect - tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); - return 1; - } - } - else if (set == 2) { - if (!(ebone->flag & BONE_HIDDEN_A)) { - if (!(ebone->flag & BONE_SELECTED)) { + int status = 0; + if (set) { + if (set == 1) { + if (!(ebone->flag & BONE_HIDDEN_A)) { + ED_armature_deselect_all(scene->obedit, 0); // deselect tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); - return 1; + status = 1; } - else { - /* entirely selected, so de-select */ - tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE); - return 0; + } + else if (set == 2) { + if (!(ebone->flag & BONE_HIDDEN_A)) { + if (!(ebone->flag & BONE_SELECTED)) { + tree_element_active_ebone__sel(C, scene, arm, ebone, TRUE); + status = 1; + } + else { + /* entirely selected, so de-select */ + tree_element_active_ebone__sel(C, scene, arm, ebone, FALSE); + status = 0; + } } } + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0); + } } else if (ebone->flag & BONE_SELECTED) { - return 1; + status = 1; } - return 0; + return status; } static int tree_element_active_modifier(bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, int set) @@ -675,19 +757,19 @@ int tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement /* generic call for non-id data to make/check active in UI */ /* Context can be NULL when set==0 */ int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, - TreeElement *te, TreeStoreElem *tselem, int set) + TreeElement *te, TreeStoreElem *tselem, int set, bool recursive) { switch (tselem->type) { case TSE_DEFGROUP: return tree_element_active_defgroup(C, scene, te, tselem, set); case TSE_BONE: - return tree_element_active_bone(C, scene, te, tselem, set); + return tree_element_active_bone(C, scene, te, tselem, set, recursive); case TSE_EBONE: - return tree_element_active_ebone(C, scene, te, tselem, set); + return tree_element_active_ebone(C, scene, te, tselem, set, recursive); case TSE_MODIFIER: return tree_element_active_modifier(C, te, tselem, set); case TSE_LINKED_OB: - if (set) tree_element_set_active_object(C, scene, soops, te, set); + if (set) tree_element_set_active_object(C, scene, soops, te, set, FALSE); else if (tselem->id == (ID *)OBACT) return 1; break; case TSE_LINKED_PSYS: @@ -695,7 +777,7 @@ int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, case TSE_POSE_BASE: return tree_element_active_pose(C, scene, te, tselem, set); case TSE_POSE_CHANNEL: - return tree_element_active_posechannel(C, scene, te, tselem, set); + return tree_element_active_posechannel(C, scene, te, tselem, set, recursive); case TSE_CONSTRAINT: return tree_element_active_constraint(C, te, tselem, set); case TSE_R_LAYER: @@ -716,7 +798,7 @@ int tree_element_type_active(bContext *C, Scene *scene, SpaceOops *soops, /* ================================================ */ static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, int extend, const float mval[2]) + TreeElement *te, bool extend, bool recursive, const float mval[2]) { if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { @@ -748,7 +830,9 @@ static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Spa /* always makes active object */ if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP) - tree_element_set_active_object(C, scene, soops, te, 1 + (extend != 0 && tselem->type == 0)); + tree_element_set_active_object(C, scene, soops, te, + 1 + (extend != 0 && tselem->type == 0), + recursive && tselem->type == 0 ); if (tselem->type == 0) { // the lib blocks /* editmode? */ @@ -791,31 +875,31 @@ static int do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Spa else { // rest of types tree_element_active(C, scene, soops, te, 1); } - + + } + else { + tree_element_type_active(C, scene, soops, te, tselem, 1 + (extend != 0), recursive); } - else tree_element_type_active(C, scene, soops, te, tselem, 1 + (extend != 0)); return 1; } } for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, mval)) return 1; + if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) return 1; } return 0; } -/* event can enterkey, then it opens/closes */ -static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event) +int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te; float fmval[2]; - int extend = RNA_boolean_get(op->ptr, "extend"); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], fmval, fmval + 1); + UI_view2d_region_to_view(&ar->v2d, x, y, fmval, fmval + 1); if (!ELEM3(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF, SO_KEYMAP) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && @@ -825,7 +909,7 @@ static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event) } for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_activate(C, scene, ar, soops, te, extend, fmval)) break; + if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break; } if (te) { @@ -855,6 +939,16 @@ static int outliner_item_activate(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_FINISHED; } +/* event can enterkey, then it opens/closes */ +static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event) +{ + bool extend = RNA_boolean_get(op->ptr, "extend"); + bool recursive = RNA_boolean_get(op->ptr, "recursive"); + int x = event->mval[0]; + int y = event->mval[1]; + return outliner_item_do_activate(C, x, y, extend, recursive); +} + void OUTLINER_OT_item_activate(wmOperatorType *ot) { ot->name = "Activate Item"; @@ -865,7 +959,8 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; - RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection for activation"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation"); + RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children"); } /* ****************************************************** */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index cd04c8c6bd1..258f0338d1e 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -75,6 +75,7 @@ #include "outliner_intern.h" + /* ****************************************************** */ /* ************ SELECTION OPERATIONS ********* */ @@ -190,8 +191,10 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle World *wrld = (World *)tsep->id; mtex = wrld->mtex; } - else return; - + else { + return; + } + for (a = 0; a < MAX_MTEX; a++) { if (a == te->index && mtex[a]) { if (mtex[a]->tex) { @@ -264,6 +267,17 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, } } +static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem)) +{ + /* From where do i get the x,y coordinate of the mouse event ? */ + wmWindow *win = CTX_wm_window(C); + int x = win->eventstate->mval[0]; + int y = win->eventstate->mval[1]; + outliner_item_do_activate(C, x, y, true, true); +} + + static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) { @@ -300,7 +314,7 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t if (tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) { /* if the ID type has no special local function, * just clear the lib */ - if (id_make_local(tselem->id, FALSE) == FALSE) { + if (id_make_local(tselem->id, false) == false) { Main *bmain = CTX_data_main(C); id_clear_lib_data(bmain, tselem->id); } @@ -526,9 +540,9 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void Sequence *seq = (Sequence *)te->directdata; if (event == 1) { Scene *scene = (Scene *)scene_ptr; - Editing *ed = BKE_sequencer_editing_get(scene, FALSE); + Editing *ed = BKE_sequencer_editing_get(scene, false); if (BLI_findindex(ed->seqbasep, seq) != -1) { - ED_sequencer_select_sequence_single(scene, seq, TRUE); + ED_sequencer_select_sequence_single(scene, seq, true); } } @@ -569,15 +583,29 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li /* **************************************** */ +enum { + OL_OP_ENDMARKER = 0, + OL_OP_SELECT, + OL_OP_DESELECT, + OL_OP_SELECT_HIERARCHY, + OL_OP_DELETE, + OL_OP_LOCALIZED, /* disabled, see below */ + OL_OP_TOGVIS, + OL_OP_TOGSEL, + OL_OP_TOGREN, + OL_OP_RENAME +}; + static EnumPropertyItem prop_object_op_types[] = { - {1, "SELECT", 0, "Select", ""}, - {2, "DESELECT", 0, "Deselect", ""}, - {4, "DELETE", 0, "Delete", ""}, - {6, "TOGVIS", 0, "Toggle Visible", ""}, - {7, "TOGSEL", 0, "Toggle Selectable", ""}, - {8, "TOGREN", 0, "Toggle Renderable", ""}, - {9, "RENAME", 0, "Rename", ""}, - {0, NULL, 0, NULL, NULL} + {OL_OP_SELECT, "SELECT", 0, "Select", ""}, + {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, + {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, + {OL_OP_DELETE, "DELETE", 0, "Delete", ""}, + {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, + {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, + {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, + {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, + {OL_OP_ENDMARKER, NULL, 0, NULL, NULL} }; static int outliner_object_operation_exec(bContext *C, wmOperator *op) @@ -594,7 +622,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) event = RNA_enum_get(op->ptr, "type"); - if (event == 1) { + if (event == OL_OP_SELECT) { Scene *sce = scene; // to be able to delete, scenes are set... outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb); if (scene != sce) { @@ -604,12 +632,21 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Select Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - else if (event == 2) { + else if (event == OL_OP_SELECT_HIERARCHY) { + Scene *sce = scene; // to be able to delete, scenes are set... + outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb); + if (scene != sce) { + ED_screen_set_scene(C, CTX_wm_screen(C), sce); + } + str = "Select Object Hierarchy"; + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + else if (event == OL_OP_DESELECT) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb); str = "Deselect Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - else if (event == 4) { + else if (event == OL_OP_DELETE) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb); /* XXX: tree management normally happens from draw_outliner(), but when @@ -623,26 +660,26 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Delete Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } - else if (event == 5) { /* disabled, see above enum (ton) */ + else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; } - else if (event == 6) { + else if (event == OL_OP_TOGVIS) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); str = "Toggle Visibility"; WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); } - else if (event == 7) { + else if (event == OL_OP_TOGSEL) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); str = "Toggle Selectability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - else if (event == 8) { + else if (event == OL_OP_TOGREN) { outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); str = "Toggle Renderability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); } - else if (event == 9) { + else if (event == OL_OP_RENAME) { outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb); str = "Rename Object"; } @@ -1229,7 +1266,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, wmEvent *event, const float mval[2]) + TreeElement *te, const wmEvent *event, const float mval[2]) { ReportList *reports = CTX_wm_reports(C); // XXX... @@ -1259,7 +1296,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); } else if (idlevel) { - if (idlevel == -1 || datalevel) BKE_report(reports, RPT_WARNING, "Mixed selection"); + if (idlevel == -1 || datalevel) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + } else { if (idlevel == ID_GR) WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); @@ -1268,7 +1307,9 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S } } else if (datalevel) { - if (datalevel == -1) BKE_report(reports, RPT_WARNING, "Mixed selection"); + if (datalevel == -1) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + } else { if (datalevel == TSE_ANIM_DATA) WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL); @@ -1295,7 +1336,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S } -static int outliner_operation(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f723fbedc7b..19bc1db2b5d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -64,6 +64,8 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLF_translation.h" + #include "BKE_fcurve.h" #include "BKE_main.h" #include "BKE_library.h" @@ -322,7 +324,7 @@ static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, Sc * in order to not overflow short tselem->nr */ te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED)); - te->name = "Combined"; + te->name = IFACE_("Combined"); te->directdata = &srl->passflag; /* save cpu cycles, but we add the first to invoke an open/close triangle */ @@ -331,71 +333,71 @@ static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, Sc return; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z)); - te->name = "Z"; + te->name = IFACE_("Z"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR)); - te->name = "Vector"; + te->name = IFACE_("Vector"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL)); - te->name = "Normal"; + te->name = IFACE_("Normal"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV)); - te->name = "UV"; + te->name = IFACE_("UV"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST)); - te->name = "Mist"; + te->name = IFACE_("Mist"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB)); - te->name = "Index Object"; + te->name = IFACE_("Index Object"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA)); - te->name = "Index Material"; + te->name = IFACE_("Index Material"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA)); - te->name = "Color"; + te->name = IFACE_("Color"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE)); - te->name = "Diffuse"; + te->name = IFACE_("Diffuse"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC)); - te->name = "Specular"; + te->name = IFACE_("Specular"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW)); - te->name = "Shadow"; + te->name = IFACE_("Shadow"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO)); - te->name = "AO"; + te->name = IFACE_("AO"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT)); - te->name = "Reflection"; + te->name = IFACE_("Reflection"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT)); - te->name = "Refraction"; + te->name = IFACE_("Refraction"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT)); - te->name = "Indirect"; + te->name = IFACE_("Indirect"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT)); - te->name = "Environment"; + te->name = IFACE_("Environment"); te->directdata = &srl->passflag; te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT)); - te->name = "Emit"; + te->name = IFACE_("Emit"); te->directdata = &srl->passflag; } @@ -407,7 +409,7 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); int a; - tenla->name = "RenderLayers"; + tenla->name = IFACE_("RenderLayers"); for (a = 0, srl = sce->r.layers.first; srl; srl = srl->next, a++) { TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a); tenlay->name = srl->name; @@ -449,7 +451,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *ten; TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0); - tenla->name = "Pose"; + tenla->name = IFACE_("Pose"); /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) { @@ -468,7 +470,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); //char *str; - tenla1->name = "Constraints"; + tenla1->name = IFACE_("Constraints"); for (con = pchan->constraints.first; con; con = con->next, const_index++) { ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); #if 0 /* disabled as it needs to be reworked for recoded constraints system */ @@ -508,7 +510,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0); int a = 0; - tenla->name = "Bone Groups"; + tenla->name = IFACE_("Bone Groups"); for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) { ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a); ten->name = agrp->name; @@ -527,7 +529,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0); //char *str; - tenla->name = "Constraints"; + tenla->name = IFACE_("Constraints"); for (con = ob->constraints.first, a = 0; con; con = con->next, a++) { ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a); #if 0 /* disabled due to constraints system targets recode... code here needs review */ @@ -547,7 +549,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); int index; - temod->name = "Modifiers"; + temod->name = IFACE_("Modifiers"); for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) { TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index); te->name = md->name; @@ -582,7 +584,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree TreeElement *ten; TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); - tenla->name = "Vertex Groups"; + tenla->name = IFACE_("Vertex Groups"); for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) { ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a); ten->name = defgroup->name; @@ -856,7 +858,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i AnimData *adt = (AnimData *)iat->adt; /* this element's info */ - te->name = "Animation"; + te->name = IFACE_("Animation"); te->directdata = adt; /* Action */ @@ -868,7 +870,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i ID *lastadded = NULL; FCurve *fcu; - ted->name = "Drivers"; + ted->name = IFACE_("Drivers"); for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { if (fcu->driver && fcu->driver->variables.first) { @@ -897,7 +899,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i NlaTrack *nlt; int a = 0; - tenla->name = "NLA Tracks"; + tenla->name = IFACE_("NLA Tracks"); for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); @@ -951,7 +953,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i if (strip->dir) te->name = strip->dir; else - te->name = "Strip None"; + te->name = IFACE_("Strip None"); te->directdata = strip; } else if (type == TSE_SEQUENCE_DUP) { @@ -970,7 +972,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i /* we do lazy build, for speed and to avoid infinite recusion */ if (ptr->data == NULL) { - te->name = "(empty)"; + te->name = IFACE_("(empty)"); } else if (type == TSE_RNA_STRUCT) { /* struct */ @@ -1096,7 +1098,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i ten->directdata = kmi; if (kmi->propvalue) { - ten->name = "Modal map, not yet"; + ten->name = IFACE_("Modal map, not yet"); } else { WM_operator_py_idname(opname, ot->idname); @@ -1257,19 +1259,23 @@ static int treesort_obtype_alpha(const void *v1, const void *v2) const tTreeSort *x1 = v1, *x2 = v2; /* first put objects last (hierarchy) */ - if (x1->idcode == ID_OB && x2->idcode != ID_OB) return 1; - else if (x2->idcode == ID_OB && x1->idcode != ID_OB) return -1; + if (x1->idcode == ID_OB && x2->idcode != ID_OB) { + return 1; + } + else if (x2->idcode == ID_OB && x1->idcode != ID_OB) { + return -1; + } else { /* 2nd we check ob type */ if (x1->idcode == ID_OB && x2->idcode == ID_OB) { - if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1; + if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1; else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1; else return 0; } else { int comp = strcmp(x1->name, x2->name); - if (comp > 0) return 1; + if (comp > 0) return 1; else if (comp < 0) return -1; return 0; } @@ -1502,7 +1508,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) /* current file first - mainvar provides tselem with unique pointer - not used */ ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0); - ten->name = "Current File"; + ten->name = IFACE_("Current File"); tselem = TREESTORE(ten); if (!tselem->used) diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 4bf88376b74..3849aaf78c1 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -90,7 +90,7 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_dropbox_handler(&ar->handlers, lb); } -static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -135,7 +135,7 @@ static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop) RNA_string_set(drop->ptr, "child", id->name + 2); } -static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -176,7 +176,7 @@ static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop) RNA_enum_set(drop->ptr, "type", 0); } -static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -205,7 +205,7 @@ static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop) RNA_string_set(drop->ptr, "object", id->name + 2); } -static int outliner_material_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -316,6 +316,10 @@ static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn) /* all modifier actions now */ ED_region_tag_redraw(ar); break; + default: + /* Trigger update for NC_OBJECT itself */ + ED_region_tag_redraw(ar); + break; } break; case NC_GROUP: diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 78a76532487..571779a7524 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -294,7 +294,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) } -static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!ED_operator_sequencer_active(C)) { BKE_report(op->reports, RPT_ERROR, "Sequencer area not active"); @@ -392,7 +392,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!ED_operator_sequencer_active(C)) { BKE_report(op->reports, RPT_ERROR, "Sequencer area not active"); @@ -489,7 +489,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!ED_operator_sequencer_active(C)) { BKE_report(op->reports, RPT_ERROR, "Sequencer area not active"); @@ -602,7 +602,7 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) } -static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!ED_operator_sequencer_active(C)) { @@ -657,7 +657,7 @@ static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op) return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip); } -static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!ED_operator_sequencer_active(C)) { @@ -769,7 +769,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!ED_operator_sequencer_active(C)) { @@ -921,7 +921,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) /* add color */ -static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { short is_type_set = RNA_struct_property_is_set(op->ptr, "type"); int type = -1; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 396878cbfeb..7ebe04f666b 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -813,7 +813,9 @@ static void UNUSED_FUNCTION(set_special_seq_update) (int val) if (val) { // XXX special_seq_update = find_nearest_seq(&x); } - else special_seq_update = NULL; + else { + special_seq_update = NULL; + } } ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 7be2d51a3c0..f0ed8d4107d 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -520,7 +520,7 @@ int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequen return 0; } if ((seq != activeseq) && (seq != seq2)) { - if (seq2 == NULL) seq2 = seq; + if (seq2 == NULL) seq2 = seq; else if (seq1 == NULL) seq1 = seq; else if (seq3 == NULL) seq3 = seq; else { @@ -889,7 +889,7 @@ static int insert_gap(Scene *scene, int gap, int cfra) return done; } -static void UNUSED_FUNCTION(touch_seq_files) (Scene * scene) +static void UNUSED_FUNCTION(touch_seq_files) (Scene *scene) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, FALSE); @@ -946,7 +946,7 @@ static void set_filter_seq(Scene *scene) } #endif -static void UNUSED_FUNCTION(seq_remap_paths) (Scene * scene) +static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene) { Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); Editing *ed = BKE_sequencer_editing_get(scene, FALSE); @@ -988,7 +988,7 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene * scene) } -static void UNUSED_FUNCTION(no_gaps) (Scene * scene) +static void UNUSED_FUNCTION(no_gaps) (Scene *scene) { Editing *ed = BKE_sequencer_editing_get(scene, FALSE); int cfra, first = 0, done; @@ -1121,7 +1121,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sequencer_snap_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); @@ -1546,7 +1546,7 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op) } -static int sequencer_cut_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); @@ -1695,7 +1695,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int sequencer_delete_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); @@ -3105,7 +3105,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int sequencer_change_path_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); Sequence *seq = BKE_sequencer_active_get(scene); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 0d1ecb76d0e..3269e772be6 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -162,7 +162,7 @@ void select_surround_from_last(Scene *scene) } #endif -void ED_sequencer_select_sequence_single(Scene * scene, Sequence * seq, int deselect_all) +void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all) { Editing *ed = BKE_sequencer_editing_get(scene, FALSE); @@ -315,7 +315,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = CTX_data_scene(C); @@ -552,8 +552,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot) } - - /* run recursively to select linked */ static int select_more_less_seq__internal(Scene *scene, int sel, int linked) { @@ -670,7 +668,7 @@ void SEQUENCER_OT_select_less(wmOperatorType *ot) /* select pick linked operator (uses the mouse) */ -static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 92b17393114..7dcd3a70870 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -85,7 +85,7 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info) } } -static void sample_apply(bContext *C, wmOperator *op, wmEvent *event) +static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -168,7 +168,7 @@ static void sample_exit(bContext *C, wmOperator *op) MEM_freeN(info); } -static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceSeq *sseq = CTX_wm_space_seq(C); @@ -189,7 +189,7 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int sample_modal(bContext *C, wmOperator *op, wmEvent *event) +static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 4c6b909882c..ffe89407715 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -373,7 +373,7 @@ static void sequencer_main_area_draw(const bContext *C, ARegion *ar) /* ************* dropboxes ************* */ -static int image_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); @@ -387,7 +387,7 @@ static int image_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) return 0; } -static int movie_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); @@ -400,7 +400,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) return 0; } -static int sound_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index ff9d1329721..110e0ab5bc4 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -458,7 +458,7 @@ static void text_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) /* ************* dropboxes ************* */ -static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_BLANK)) /* rule might not work? */ diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index 7c18b5c283a..838ffb948b1 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -220,7 +220,7 @@ static GHash *text_autocomplete_build(Text *text) TextFormatType *tft; tft = ED_text_format_get(text); - for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) { const char *s = BLI_ghashIterator_getValue(iter); texttool_suggest_add(s, tft->format_identifier(s)); } @@ -282,7 +282,7 @@ static void confirm_suggestion(Text *text) /* -- */ -static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceText *st = CTX_wm_space_text(C); Text *text = CTX_data_edit_text(C); @@ -313,7 +313,7 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED static int doc_scroll = 0; -static int text_autocomplete_modal(bContext *C, wmOperator *op, wmEvent *event) +static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); ScrArea *sa = CTX_wm_area(C); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index c264368e714..95fd7fce878 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -67,12 +67,14 @@ static void text_font_end(SpaceText *UNUSED(st)) { } -static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str) +static int text_font_draw(SpaceText *st, int x, int y, const char *str) { + int columns; + BLF_position(mono, x, y, 0); - BLF_draw(mono, str, BLF_DRAW_STR_DUMMY_MAX); + columns = BLF_draw_mono(mono, str, BLF_DRAW_STR_DUMMY_MAX, st->cwidth); - return BLF_width(mono, str); + return st->cwidth * columns; } static int text_font_draw_character(SpaceText *st, int x, int y, char c) @@ -85,10 +87,13 @@ static int text_font_draw_character(SpaceText *st, int x, int y, char c) static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c) { + int columns; + const size_t len = BLI_str_utf8_size_safe(c); BLF_position(mono, x, y, 0); - BLF_draw(mono, c, len); - return st->cwidth; + columns = BLF_draw_mono(mono, c, len, st->cwidth); + + return st->cwidth * columns; } #if 0 @@ -216,7 +221,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * } max = wrap_width(st, ar); - cursin = txt_utf8_offset_to_index(linein->line, cursin); + cursin = txt_utf8_offset_to_column(linein->line, cursin); while (linep) { start = 0; @@ -225,6 +230,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * *offc = 0; for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; + int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = linep->line[j]; @@ -238,7 +244,9 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * } while (chars--) { - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + if (chop && linep == linein && i >= cursin) { if (i == cursin) { (*offl)++; @@ -261,7 +269,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * if (linep == linein && i >= cursin) return; } - i++; + i += columns; } } if (linep == linein) break; @@ -286,9 +294,10 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi end = max; chop = 1; *offc = 0; - cursin = txt_utf8_offset_to_index(linein->line, cursin); + cursin = txt_utf8_offset_to_column(linein->line, cursin); for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size_safe(linein->line + j)) { + int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = linein->line[j]; @@ -301,7 +310,9 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi chars = 1; while (chars--) { - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + if (chop && i >= cursin) { if (i == cursin) { (*offl)++; @@ -324,7 +335,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi if (i >= cursin) return; } - i++; + i += columns; } } } @@ -337,24 +348,35 @@ int text_get_char_pos(SpaceText *st, const char *line, int cur) if (line[i] == '\t') a += st->tabnumber - a % st->tabnumber; else - a++; + a += BLI_str_utf8_char_width_safe(line + i); } return a; } -static const char *txt_utf8_get_nth(const char *str, int n) +static const char *txt_utf8_forward_columns(const char *str, int columns, int *padding) { - int pos = 0; - while (str[pos] && n--) { - pos += BLI_str_utf8_size_safe(str + pos); + int col; + const char *p = str; + while (*p) { + col = BLI_str_utf8_char_width(p); + if (columns - col < 0) + break; + columns -= col; + p += BLI_str_utf8_size_safe(p); + if (columns == 0) + break; } - return str + pos; + if (padding) + *padding = *p ? columns : 0; + return p; } static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip) { FlattenString fs; - int basex, i, a, start, end, max, lines; /* view */ + int basex, lines; + int i, wrap, end, max, columns, padding; /* column */ + int a, fstart, fpos; /* utf8 chars */ int mi, ma, mstart, mend; /* mem */ char fmt_prev = 0xff; @@ -365,41 +387,46 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w basex = x; lines = 1; - start = 0; mstart = 0; - end = max; mend = txt_utf8_get_nth(str, max) - str; + fpos = fstart = 0; mstart = 0; + mend = txt_utf8_forward_columns(str, max, &padding) - str; + end = wrap = max - padding; - for (i = 0, mi = 0; str[mi]; i++, mi += BLI_str_utf8_size_safe(str + mi)) { - if (i - start >= max) { + for (i = 0, mi = 0; str[mi]; i += columns, mi += BLI_str_utf8_size_safe(str + mi)) { + columns = BLI_str_utf8_char_width_safe(str + mi); + if (i + columns > end) { /* skip hidden part of line */ if (skip) { skip--; - start = end; mstart = mend; - end += max; mend = txt_utf8_get_nth(str + mend, max) - str; + fstart = fpos; mstart = mend; + mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; + end = (wrap += max - padding); continue; } /* Draw the visible portion of text on the overshot line */ - for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) { + for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (st->showsyntax && format) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } x += text_font_draw_character_utf8(st, x, y, str + ma); + fpos++; } y -= st->lheight_dpi + TXT_LINE_SPACING; x = basex; lines++; - start = end; mstart = mend; - end += max; mend = txt_utf8_get_nth(str + mend, max) - str; + fstart = fpos; mstart = mend; + mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; + end = (wrap += max - padding); if (y <= 0) break; } else if (str[mi] == ' ' || str[mi] == '-') { - end = i + 1; mend = mi + 1; + wrap = i + 1; mend = mi + 1; } } /* Draw the remaining text */ - for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { + for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { if (st->showsyntax && format) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } @@ -412,53 +439,55 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w return lines; } -static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, const char *format) +static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format) { FlattenString fs; - int *acc, r = 0; - const char *in; + int columns, size, n, w = 0, padding, amount = 0; + const char *in = NULL; - int w = flatten_string(st, &fs, str); - if (w < cshift) { - flatten_string_free(&fs); - return 0; /* String is shorter than shift */ - } - - in = txt_utf8_get_nth(fs.buf, cshift); - acc = fs.accum + cshift; - w = w - cshift; + for (n = flatten_string(st, &fs, str), str = fs.buf; n > 0; n--) { + columns = BLI_str_utf8_char_width_safe(str); + size = BLI_str_utf8_size_safe(str); - if (draw) { - int amount = maxwidth ? MIN2(w, maxwidth) : w; - - if (st->showsyntax && format) { - int a, str_shift = 0; - char fmt_prev = 0xff; - format = format + cshift; - - for (a = 0; a < amount; a++) { - if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); - x += text_font_draw_character_utf8(st, x, y, in + str_shift); - str_shift += BLI_str_utf8_size_safe(in + str_shift); + if (!in) { + if (w >= cshift) { + padding = w - cshift; + in = str; } + else if (format) + format++; } - else { - text_font_draw(st, x, y, in); + if (in) { + if (maxwidth && w + columns > cshift + maxwidth) + break; + amount++; + } + + w += columns; + str += size; + } + if (!in) { + flatten_string_free(&fs); + return; /* String is shorter than shift or ends with a padding */ + } + + x += st->cwidth * padding; + + if (st->showsyntax && format) { + int a, str_shift = 0; + char fmt_prev = 0xff; + + for (a = 0; a < amount; a++) { + if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); + x += text_font_draw_character_utf8(st, x, y, in + str_shift); + str_shift += BLI_str_utf8_size_safe(in + str_shift); } } else { - while (w-- && *acc++ < maxwidth) - r += st->cwidth; + text_font_draw(st, x, y, in); } flatten_string_free(&fs); - - if (cshift && r == 0) - return 0; - else if (st->showlinenrs) - return r + TXT_OFFSET + TEXTXLOC; - else - return r + TXT_OFFSET; } /************************ cache utilities *****************************/ @@ -672,25 +701,29 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str) start = 0; end = max; for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size_safe(str + j)) { + int columns = BLI_str_utf8_char_width_safe(str + j); /* = 1 for tab */ + /* Mimic replacement of tabs */ ch = str[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; } - else chars = 1; + else { + chars = 1; + } while (chars--) { - if (i - start >= max) { + if (i + columns - start > max) { lines++; - start = end; + start = MIN2(end, i); end += max; } else if (ch == ' ' || ch == '-') { end = i + 1; } - i++; + i += columns; } } @@ -712,7 +745,9 @@ int text_get_span_wrap(SpaceText *st, ARegion *ar, TextLine *from, TextLine *to) return ret; } - else return txt_get_span(from, to); + else { + return txt_get_span(from, to); + } } int text_get_total_lines(SpaceText *st, ARegion *ar) @@ -927,7 +962,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) buf[i] = '\0'; if (lines >= 0) { y -= st->lheight_dpi; - text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL); + text_draw(st, buf, 0, 0, x + 4, y - 3, NULL); } i = 0; br = DOC_WIDTH; lines++; } @@ -936,7 +971,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) buf[br] = '\0'; if (lines >= 0) { y -= st->lheight_dpi; - text_draw(st, buf, 0, 0, 1, x + 4, y - 3, NULL); + text_draw(st, buf, 0, 0, x + 4, y - 3, NULL); } p -= i - br - 1; /* Rewind pointer to last break */ i = 0; br = DOC_WIDTH; lines++; @@ -955,9 +990,9 @@ static void draw_documentation(SpaceText *st, ARegion *ar) static void draw_suggestion_list(SpaceText *st, ARegion *ar) { SuggItem *item, *first, *last, *sel; - TextLine *tmp; - char str[SUGG_LIST_WIDTH + 1]; - int w, boxw = 0, boxh, i, l, x, y, *top; + char str[SUGG_LIST_WIDTH * BLI_UTF8_MAX + 1]; + int offl, offc, vcurl, vcurc; + int w, boxw = 0, boxh, i, x, y, *top; const int lheight = st->lheight_dpi + TXT_LINE_SPACING; const int margin_x = 2; @@ -973,24 +1008,24 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) sel = texttool_suggest_selected(); top = texttool_suggest_top(); - /* Count the visible lines to the cursor */ - for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; - if (l < 0) return; - - if (st->showlinenrs) { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4; - } - else { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; - } + wrap_offset(st, ar, st->text->curl, st->text->curc, &offl, &offc); + vcurl = txt_get_span(st->text->lines.first, st->text->curl) - st->top + offl; + vcurc = text_get_char_pos(st, st->text->curl->line, st->text->curc) - st->left + offc; + + x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; + x += vcurc * st->cwidth - 4; + y = ar->winy - (vcurl + 1) * lheight - 2; + /* offset back so the start of the text lines up with the suggestions, * not essential but makes suggestions easier to follow */ x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc)); - y = ar->winy - lheight * l - 2; boxw = SUGG_LIST_WIDTH * st->cwidth + 20; boxh = SUGG_LIST_SIZE * lheight + 8; + if (x + boxw > ar->winx) + x = MAX2(0, ar->winx - boxw); + /* not needed but stands out nicer */ uiDrawBoxShadow(220, x, y - boxh, x + boxw, y); @@ -1003,12 +1038,13 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ; for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) { + int len = txt_utf8_forward_columns(item->name, SUGG_LIST_WIDTH, NULL) - item->name; y -= lheight; - BLI_strncpy(str, item->name, SUGG_LIST_WIDTH); + BLI_strncpy(str, item->name, len + 1); - w = BLF_width(mono, str); + w = st->cwidth * text_get_char_pos(st, str, len); if (item == sel) { UI_ThemeColor(TH_SHADE2); @@ -1016,7 +1052,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) } format_draw_color(item->type); - text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL); + text_draw(st, str, 0, 0, x + margin_x, y - 1, NULL); if (item == last) break; } @@ -1378,7 +1414,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) } else { /* draw unwrapped text */ - text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, 1, x, y, tmp->format); + text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format); y -= st->lheight_dpi + TXT_LINE_SPACING; } @@ -1435,8 +1471,6 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa) winx = ar->winx; break; } - - winx -= TXT_SCROLL_WIDTH; text_update_character_width(st); @@ -1454,10 +1488,11 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa) st->left = 0; } else { - x = text_draw(st, text->sell->line, st->left, text->selc, 0, 0, 0, NULL); + x = st->cwidth * (text_get_char_pos(st, text->sell->line, text->selc) - st->left); + winx -= TXT_OFFSET + (st->showlinenrs ? TEXTXLOC : 0) + TXT_SCROLL_WIDTH; - if (x == 0 || x > winx) - st->left = text->curc - 0.5 * winx / st->cwidth; + if (x <= 0 || x > winx) + st->left += (x - winx / 2) / st->cwidth; } if (st->top < 0) st->top = 0; diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c index 3c7897200ed..b29c6420d60 100644 --- a/source/blender/editors/space_text/text_format.c +++ b/source/blender/editors/space_text/text_format.c @@ -144,7 +144,7 @@ int text_check_format_len(TextLine *line, unsigned int len) * Fill the string with formatting constant, * advancing \a str_p and \a fmt_p * - * \param len length in bytes + * \param len length in bytes of \a fmt_p to fill. */ void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len) { diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c index 6c72e043930..f74d1cf8e8b 100644 --- a/source/blender/editors/space_text/text_format_lua.c +++ b/source/blender/editors/space_text/text_format_lua.c @@ -237,7 +237,7 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const int do_n } /* Single line comment */ else if (*str == '-' && *(str + 1) == '-') { - text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf)); + text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format)); } else if (*str == '"' || *str == '\'') { /* Strings */ diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c index 7d493eb1f62..c95929a720f 100644 --- a/source/blender/editors/space_text/text_format_osl.c +++ b/source/blender/editors/space_text/text_format_osl.c @@ -141,10 +141,10 @@ static int txtfmt_osl_find_specialvar(const char *string) int i, len; /* OSL shader types */ - if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len; - else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len; + if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -252,7 +252,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const int do_n /* Deal with comments first */ if (*str == '/' && *(str + 1) == '/') { /* fill the remaining line */ - text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf)); + text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format)); } /* C-Style (multi-line) comments */ else if (*str == '/' && *(str + 1) == '*') { diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 902d60dcb3e..9562d57041f 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -233,7 +233,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const int do_ne /* Deal with comments first */ if (*str == '#') { /* fill the remaining line */ - text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(str - fs.buf)); + text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format)); } else if (*str == '"' || *str == '\'') { /* Strings */ diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index b45961bff11..cdbb3e7c600 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -72,7 +72,7 @@ /************************ poll ***************************/ -BLI_INLINE int text_pixel_x_to_index(SpaceText *st, const int x) +BLI_INLINE int text_pixel_x_to_column(SpaceText *st, const int x) { /* add half the char width so mouse cursor selection is inbetween letters */ return (x + (st->cwidth / 2)) / st->cwidth; @@ -278,7 +278,7 @@ static int text_open_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int text_open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Text *text = CTX_data_edit_text(C); char *path = (text && text->name) ? text->name : G.main->name; @@ -539,7 +539,7 @@ static int text_save_as_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int text_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Text *text = CTX_data_edit_text(C); char *str; @@ -1011,7 +1011,7 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(st, 0); // double check tabs/spaces before splitting the line - curts = setcurr_tab_spaces(text, space); + curts = txt_setcurr_tab_spaces(text, space); txt_split_curline(text); for (a = 0; a < curts; a++) { @@ -1407,25 +1407,31 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) { int chars; + int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */ + /* Mimic replacement of tabs */ ch = linein->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; } - else chars = 1; + else { + chars = 1; + } while (chars--) { - if (rell == 0 && i - start == relc) { + if (rell == 0 && i - start <= relc && i + columns - start > relc) { /* current position could be wrapped to next line */ /* this should be checked when end of current line would be reached */ selc = j; found = 1; } - else if (i - end == relc) { + else if (i - end <= relc && i + columns - end > relc) { curs = j; } - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + if (found) { /* exact cursor position was found, check if it's */ /* still on needed line (hasn't been wrapped) */ @@ -1441,7 +1447,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int chop = 1; rell--; - if (rell == 0 && i - start >= relc) { + if (rell == 0 && i + columns - start > relc) { selc = curs; loop = 0; break; @@ -1458,7 +1464,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int break; } - if (rell == 0 && i - start >= relc) { + if (rell == 0 && i + columns - start > relc) { selc = curs; loop = 0; break; @@ -1467,7 +1473,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int endj = j; chop = 0; } - i++; + i += columns; } } @@ -1585,20 +1591,26 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel) for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) { int chars; + int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */ + /* Mimic replacement of tabs */ ch = (*linep)->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; } - else chars = 1; + else { + chars = 1; + } while (chars--) { - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + *charp = endj; if (j >= oldc) { - if (ch == '\0') *charp = txt_utf8_index_to_offset((*linep)->line, start); + if (ch == '\0') *charp = txt_utf8_column_to_offset((*linep)->line, start); loop = 0; break; } @@ -1611,7 +1623,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel) } else if (ch == ' ' || ch == '-' || ch == '\0') { if (j >= oldc) { - *charp = txt_utf8_index_to_offset((*linep)->line, start); + *charp = txt_utf8_column_to_offset((*linep)->line, start); loop = 0; break; } @@ -1620,7 +1632,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel) endj = j + 1; chop = 0; } - i++; + i += columns; } } @@ -1651,16 +1663,22 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel) for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) { int chars; + int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */ + /* Mimic replacement of tabs */ ch = (*linep)->line[j]; if (ch == '\t') { chars = st->tabnumber - i % st->tabnumber; ch = ' '; } - else chars = 1; + else { + chars = 1; + } while (chars--) { - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + if (chop) endj = BLI_str_prev_char_utf8((*linep)->line + j) - (*linep)->line; if (endj >= oldc) { @@ -1684,7 +1702,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel) endj = j; chop = 0; } - i++; + i += columns; } } @@ -1716,7 +1734,9 @@ static void txt_wrap_move_up(SpaceText *st, ARegion *ar, short sel) visible_lines = text_get_visible_lines(st, ar, (*linep)->line); *charp = text_get_cursor_rel(st, ar, *linep, visible_lines - 1, col); } - else *charp = 0; + else { + *charp = 0; + } } if (!sel) txt_pop_sel(text); @@ -1745,7 +1765,9 @@ static void txt_wrap_move_down(SpaceText *st, ARegion *ar, short sel) *linep = (*linep)->next; *charp = text_get_cursor_rel(st, ar, *linep, 0, col); } - else *charp = (*linep)->len; + else { + *charp = (*linep)->len; + } } if (!sel) txt_pop_sel(text); @@ -1927,7 +1949,7 @@ static int text_jump_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int text_jump_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y); @@ -2085,7 +2107,7 @@ static int text_scroll_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void text_scroll_apply(bContext *C, wmOperator *op, wmEvent *event) +static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); ARegion *ar = CTX_wm_region(C); @@ -2142,7 +2164,7 @@ static void scroll_exit(bContext *C, wmOperator *op) MEM_freeN(op->customdata); } -static int text_scroll_modal(bContext *C, wmOperator *op, wmEvent *event) +static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event) { TextScroll *tsc = op->customdata; SpaceText *st = CTX_wm_space_text(C); @@ -2182,7 +2204,7 @@ static int text_scroll_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int text_scroll_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); TextScroll *tsc; @@ -2259,7 +2281,7 @@ static int text_region_scroll_poll(bContext *C) return 1; } -static int text_scroll_bar_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); ARegion *ar = CTX_wm_region(C); @@ -2342,7 +2364,7 @@ typedef struct SetSelection { short old[2]; } SetSelection; -static int flatten_len(SpaceText *st, const char *str) +static int flatten_width(SpaceText *st, const char *str) { int i, total = 0; @@ -2350,20 +2372,30 @@ static int flatten_len(SpaceText *st, const char *str) if (str[i] == '\t') { total += st->tabnumber - total % st->tabnumber; } - else total++; + else { + total += BLI_str_utf8_char_width_safe(str + i); + } } return total; } -static int flatten_index_to_offset(SpaceText *st, const char *str, int index) +static int flatten_column_to_offset(SpaceText *st, const char *str, int index) { - int i, j; - for (i = 0, j = 0; i < index; j += BLI_str_utf8_size_safe(str + j)) + int i = 0, j = 0, col; + + while (*(str + j)) { if (str[j] == '\t') - i += st->tabnumber - i % st->tabnumber; + col = st->tabnumber - i % st->tabnumber; else - i++; + col = BLI_str_utf8_char_width_safe(str + j); + + if (i + col > index) + break; + + i += col; + j += BLI_str_utf8_size_safe(str + j); + } return j; } @@ -2390,7 +2422,7 @@ static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y) static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, int y, int sel) { Text *text = st->text; - int max = wrap_width(st, ar); /* view */ + int max = wrap_width(st, ar); /* column */ int charp = -1; /* mem */ int loop = 1, found = 0; /* flags */ char ch; @@ -2399,12 +2431,13 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in TextLine *linep = get_first_visible_line(st, ar, &y); while (loop && linep) { - int i = 0, start = 0, end = max; /* view */ + int i = 0, start = 0, end = max; /* column */ int j = 0, curs = 0, endj = 0; /* mem */ int chop = 1; /* flags */ for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; + int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */ /* Mimic replacement of tabs */ ch = linep->line[j]; @@ -2412,7 +2445,9 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in chars = st->tabnumber - i % st->tabnumber; ch = ' '; } - else chars = 1; + else { + chars = 1; + } while (chars--) { /* Gone too far, go back to last wrap point */ @@ -2422,17 +2457,19 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in break; /* Exactly at the cursor */ } - else if (y == 0 && i - start == x) { + else if (y == 0 && i - start <= x && i + columns - start > x) { /* current position could be wrapped to next line */ /* this should be checked when end of current line would be reached */ charp = curs = j; found = 1; /* Prepare curs for next wrap */ } - else if (i - end == x) { + else if (i - end <= x && i + columns - end > x) { curs = j; } - if (i - start >= max) { + if (i + columns - start > max) { + end = MIN2(end, i); + if (found) { /* exact cursor position was found, check if it's */ /* still on needed line (hasn't been wrapped) */ @@ -2449,7 +2486,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in y--; chop = 1; - if (y == 0 && i - start >= x) { + if (y == 0 && i + columns - start > x) { charp = curs; loop = 0; break; @@ -2461,7 +2498,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in break; } - if (y == 0 && i - start >= x) { + if (y == 0 && i + columns - start > x) { charp = curs; loop = 0; break; @@ -2470,7 +2507,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in endj = j; chop = 0; } - i++; + i += columns; } if (ch == '\0') break; @@ -2509,7 +2546,7 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int else x -= TXT_OFFSET; if (x < 0) x = 0; - x = text_pixel_x_to_index(st, x) + st->left; + x = text_pixel_x_to_column(st, x) + st->left; if (st->wordwrap) { text_cursor_set_to_pos_wrapped(st, ar, x, y, sel); @@ -2532,14 +2569,14 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int } - w = flatten_len(st, (*linep)->line); - if (x < w) *charp = flatten_index_to_offset(st, (*linep)->line, x); + w = flatten_width(st, (*linep)->line); + if (x < w) *charp = flatten_column_to_offset(st, (*linep)->line, x); else *charp = (*linep)->len; } if (!sel) txt_pop_sel(text); } -static void text_cursor_set_apply(bContext *C, wmOperator *op, wmEvent *event) +static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); ARegion *ar = CTX_wm_region(C); @@ -2594,7 +2631,7 @@ static void text_cursor_set_exit(bContext *C, wmOperator *op) MEM_freeN(ssel); } -static int text_set_selection_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int text_set_selection_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); SetSelection *ssel; @@ -2619,7 +2656,7 @@ static int text_set_selection_invoke(bContext *C, wmOperator *op, wmEvent *event return OPERATOR_RUNNING_MODAL; } -static int text_set_selection_modal(bContext *C, wmOperator *op, wmEvent *event) +static int text_set_selection_modal(bContext *C, wmOperator *op, const wmEvent *event) { switch (event->type) { case LEFTMOUSE: @@ -2675,7 +2712,7 @@ static int text_cursor_set_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH; } -static int text_cursor_set_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); @@ -2707,7 +2744,7 @@ void TEXT_OT_cursor_set(wmOperatorType *ot) /******************* line number operator **********************/ -static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { SpaceText *st = CTX_wm_space_text(C); Text *text = CTX_data_edit_text(C); @@ -2797,7 +2834,7 @@ static int text_insert_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int text_insert_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int ret; @@ -3100,7 +3137,7 @@ static int text_resolve_conflict_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Text *text = CTX_data_edit_text(C); uiPopupMenu *pup; diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 462619a7e8b..a04371a5ed9 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC view3d_iterators.c view3d_ops.c view3d_project.c + view3d_ruler.c view3d_select.c view3d_snap.c view3d_toolbar.c diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 2cef10e1981..9000ccbf324 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -428,7 +428,9 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, int has_mcol, int return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */ } else if (!has_mcol) { - if (tface) glColor3f(1.0, 1.0, 1.0); + if (tface) { + glColor3f(1.0, 1.0, 1.0); + } else { if (ma) { float col[3]; @@ -437,7 +439,9 @@ static DMDrawOption draw_tface__set_draw_legacy(MTFace *tface, int has_mcol, int glColor3fv(col); } - else glColor3f(1.0, 1.0, 1.0); + else { + glColor3f(1.0, 1.0, 1.0); + } } return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */ } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 158b75c494a..743b53ce16c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -615,7 +615,7 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char glColor4fv(ob->col); /* Draw the Image on the screen */ - glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, ibuf->rect); + glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); glPixelTransferf(GL_ALPHA_SCALE, 1.0f); glDisable(GL_BLEND); @@ -812,17 +812,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, floa } for (vos = strings->first; vos; vos = vos->next) { - /* too slow, reading opengl info while drawing is very bad, - * better to see if we can use the zbuffer while in pixel space - campbell */ -#if 0 - if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) { - gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz); - glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - - if (uz > depth) - continue; - } -#endif if (vos->sco[0] != IS_CLIPPED) { const char *str = (char *)(vos + 1); @@ -3862,7 +3851,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas if (v3d->flag2 & V3D_BACKFACE_CULLING) { /* not all displists use same in/out normal direction convention */ glEnable(GL_CULL_FACE); - glCullFace((base->object->type == OB_MBALL) ? GL_BACK : GL_FRONT); + glCullFace((base->object->type == OB_MBALL || base->object->derivedFinal) ? GL_BACK : GL_FRONT); } retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); @@ -3968,7 +3957,9 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix if (draw_as == PART_DRAW_AXIS) { copy_v3_v3(vec2, state->co); } - else sub_v3_v3v3(vec2, state->co, vec); + else { + sub_v3_v3v3(vec2, state->co, vec); + } add_v3_v3(vec, state->co); copy_v3_v3(pdd->vd, vec); pdd->vd += 3; @@ -3980,7 +3971,9 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix if (draw_as == PART_DRAW_AXIS) { copy_v3_v3(vec2, state->co); } - else sub_v3_v3v3(vec2, state->co, vec); + else { + sub_v3_v3v3(vec2, state->co, vec); + } add_v3_v3(vec, state->co); @@ -6055,8 +6048,10 @@ static void drawtexspace(Object *ob) copy_v3_v3(size, mb->size); copy_v3_v3(loc, mb->loc); } - else return; - + else { + return; + } + vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = loc[0] - size[0]; vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = loc[0] + size[0]; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 57755231240..d332fb9f8b3 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -48,10 +48,12 @@ #include "BKE_object.h" #include "BKE_screen.h" +#include "ED_render.h" #include "ED_space_api.h" #include "ED_screen.h" #include "ED_object.h" +#include "GPU_extensions.h" #include "GPU_material.h" #include "BIF_gl.h" @@ -350,7 +352,7 @@ static void view3d_free(SpaceLink *sl) /* spacetype; init callback */ -static void view3d_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa)) +static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa)) { } @@ -469,7 +471,22 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) } -static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static void view3d_main_area_exit(wmWindowManager *UNUSED(wm), ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->render_engine) { + RE_engine_free(rv3d->render_engine); + rv3d->render_engine = NULL; + } + + if (rv3d->gpuoffscreen) { + GPU_offscreen_free(rv3d->gpuoffscreen); + rv3d->gpuoffscreen = NULL; + } +} + +static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; @@ -479,7 +496,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSE return 0; } -static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; @@ -489,7 +506,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UN return 0; } -static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; @@ -499,7 +516,7 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS return 0; } -static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { ID *id = (ID *)drag->poin; @@ -513,7 +530,7 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS return 0; } -static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { if (event->ctrl) return false; @@ -524,7 +541,7 @@ static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) return 0; } -static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { Base *base = ED_view3d_give_base_under_cursor(C, event->mval); @@ -535,7 +552,7 @@ static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) return 0; } -static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) +static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { Base *base = ED_view3d_give_base_under_cursor(C, event->mval); @@ -615,6 +632,10 @@ static void view3d_main_area_free(ARegion *ar) if (rv3d->sms) { MEM_freeN(rv3d->sms); } + if (rv3d->gpuoffscreen) { + GPU_offscreen_free(rv3d->gpuoffscreen); + } + MEM_freeN(rv3d); ar->regiondata = NULL; } @@ -633,6 +654,7 @@ static void *view3d_main_area_duplicate(void *poin) new->clipbb = MEM_dupallocN(rv3d->clipbb); new->depths = NULL; + new->gpuoffscreen = NULL; new->ri = NULL; new->render_engine = NULL; new->gpd = NULL; @@ -1216,6 +1238,7 @@ void ED_spacetype_view3d(void) art->keymapflag = ED_KEYMAP_GPENCIL; art->draw = view3d_main_area_draw; art->init = view3d_main_area_init; + art->exit = view3d_main_area_exit; art->free = view3d_main_area_free; art->duplicate = view3d_main_area_duplicate; art->listener = view3d_main_area_listener; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 4aaa3332252..8fdc9416513 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -219,15 +219,12 @@ void ED_view3d_clipping_enable(void) } } -static int view3d_clipping_test(const float vec[3], float clip[6][4]) +static int view3d_clipping_test(const float co[3], float clip[6][4]) { - float view[3]; - copy_v3_v3(view, vec); - - if (0.0f < clip[0][3] + dot_v3v3(view, clip[0])) - if (0.0f < clip[1][3] + dot_v3v3(view, clip[1])) - if (0.0f < clip[2][3] + dot_v3v3(view, clip[2])) - if (0.0f < clip[3][3] + dot_v3v3(view, clip[3])) + if (0.0f < clip[0][3] + dot_v3v3(co, clip[0])) + if (0.0f < clip[1][3] + dot_v3v3(co, clip[1])) + if (0.0f < clip[2][3] + dot_v3v3(co, clip[2])) + if (0.0f < clip[3][3] + dot_v3v3(co, clip[3])) return 0; return 1; @@ -235,9 +232,9 @@ static int view3d_clipping_test(const float vec[3], float clip[6][4]) /* for 'local' ED_view3d_clipping_local must run first * then all comparisons can be done in localspace */ -int ED_view3d_clipping_test(RegionView3D *rv3d, const float vec[3], const int is_local) +int ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local) { - return view3d_clipping_test(vec, is_local ? rv3d->clip_local : rv3d->clip); + return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); } /* ********* end custom clipping *********** */ @@ -971,7 +968,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) } static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, - rctf *viewborder_r, short no_shift, short no_zoom) + rctf *r_viewborder, const bool no_shift, const bool no_zoom) { CameraParams params; rctf rect_view, rect_camera; @@ -995,25 +992,25 @@ static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionV rect_camera = params.viewplane; /* get camera border within viewport */ - viewborder_r->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx; - viewborder_r->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx; - viewborder_r->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy; - viewborder_r->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy; + r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx; + r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx; + r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy; + r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy; } -void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float size_r[2]) +void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2]) { rctf viewborder; view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, TRUE, TRUE); - size_r[0] = BLI_rctf_size_x(&viewborder); - size_r[1] = BLI_rctf_size_y(&viewborder); + r_size[0] = BLI_rctf_size_x(&viewborder); + r_size[1] = BLI_rctf_size_y(&viewborder); } void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, - rctf *viewborder_r, short no_shift) + rctf *viewborder_r, const bool no_shift) { - view3d_camera_border(scene, ar, v3d, rv3d, viewborder_r, no_shift, FALSE); + view3d_camera_border(scene, ar, v3d, rv3d, viewborder_r, no_shift, false); } static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac) @@ -1316,11 +1313,6 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) { /* do nothing */ } - else if ((base && (base->object->mode & OB_MODE_TEXTURE_PAINT)) && - scene->toolsettings && (scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE)) - { - /* do nothing */ - } else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT)) { @@ -1356,7 +1348,35 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) if (multisample_enabled) glDisable(GL_MULTISAMPLE_ARB); - glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) { + /* for multisample we use an offscreen FBO. multisample drawing can fail + * with color coded selection drawing, and reading back depths from such + * a buffer can also cause a few seconds freeze on OS X / NVidia. */ + int w = BLI_rcti_size_x(&ar->winrct); + int h = BLI_rcti_size_y(&ar->winrct); + char error[256]; + + if (rv3d->gpuoffscreen) { + if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || + GPU_offscreen_height(rv3d->gpuoffscreen) != h) + { + GPU_offscreen_free(rv3d->gpuoffscreen); + rv3d->gpuoffscreen = NULL; + } + } + + if (!rv3d->gpuoffscreen) { + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error); + + if (!rv3d->gpuoffscreen) + fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); + } + } + + if (rv3d->gpuoffscreen) + GPU_offscreen_bind(rv3d->gpuoffscreen); + else + glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); glClearColor(0.0, 0.0, 0.0, 0.0); if (v3d->zbuf) { @@ -1375,9 +1395,13 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) if (base && (base->lay & v3d->lay)) draw_object_backbufsel(scene, v3d, rv3d, base->object); + + if (rv3d->gpuoffscreen) + GPU_offscreen_unbind(rv3d->gpuoffscreen); + else + ar->swap = 0; /* mark invalid backbuf for wm draw */ v3d->flag &= ~V3D_INVALID_BACKBUF; - ar->swap = 0; /* mark invalid backbuf for wm draw */ G.f &= ~G_BACKBUFSEL; v3d->zbuf = FALSE; @@ -1394,6 +1418,21 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) } +void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->gpuoffscreen) { + GPU_offscreen_bind(rv3d->gpuoffscreen); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glReadPixels(x, y, w, h, format, type, data); + GPU_offscreen_unbind(rv3d->gpuoffscreen); + } + else { + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); + } +} + void view3d_validate_backbuf(ViewContext *vc) { if (vc->v3d->flag & V3D_INVALID_BACKBUF) @@ -1409,12 +1448,9 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y) return 0; } - x += vc->ar->winrct.xmin; - y += vc->ar->winrct.ymin; - view3d_validate_backbuf(vc); - glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); glReadBuffer(GL_BACK); if (ENDIAN_ORDER == B_ENDIAN) { @@ -1445,8 +1481,8 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax, view3d_validate_backbuf(vc); - glReadPixels(vc->ar->winrct.xmin + xminc, - vc->ar->winrct.ymin + yminc, + view3d_opengl_read_pixels(vc->ar, + xminc, yminc, (xmaxc - xminc + 1), (ymaxc - yminc + 1), GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); @@ -1573,7 +1609,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, float fac, asp, zoomx, zoomy; float x1, y1, x2, y2; - ImBuf *ibuf = NULL, *freeibuf; + ImBuf *ibuf = NULL, *freeibuf, *releaseibuf; Image *ima; MovieClip *clip; @@ -1583,6 +1619,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, continue; freeibuf = NULL; + releaseibuf = NULL; if (bgpic->source == V3D_BGPIC_IMAGE) { ima = bgpic->ima; if (ima == NULL) @@ -1593,7 +1630,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, } else { ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, NULL); - freeibuf = ibuf; + releaseibuf = ibuf; } image_aspect[0] = ima->aspx; @@ -1608,7 +1645,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, if (scene->camera) clip = BKE_object_movieclip_get(scene, scene->camera, 1); } - else clip = bgpic->clip; + else { + clip = bgpic->clip; + } if (clip == NULL) continue; @@ -1636,6 +1675,8 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ if (freeibuf) IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, NULL); continue; } @@ -1708,10 +1749,12 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, float tvec[3]; float sco[2]; const float mval_f[2] = {1.0f, 0.0f}; + const float co_zero[3] = {0}; + float zfac; /* calc window coord */ - initgrabz(rv3d, 0.0, 0.0, 0.0); - ED_view3d_win_to_delta(ar, mval_f, tvec); + zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); + ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ fac = 1.0f / fac; @@ -1731,6 +1774,8 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) { if (freeibuf) IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, NULL); continue; } @@ -1774,7 +1819,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, glPixelZoom(zoomx, zoomy); glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); - glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect); + glaDrawPixelsAuto(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); glPixelZoom(1.0, 1.0); glPixelTransferf(GL_ALPHA_SCALE, 1.0f); @@ -1789,9 +1834,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, glDepthMask(1); if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - if (freeibuf) { + if (freeibuf) IMB_freeImBuf(freeibuf); - } + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, NULL); } } } @@ -2102,7 +2148,7 @@ void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) } if (d->damaged) { - glReadPixels(ar->winrct.xmin + d->x, ar->winrct.ymin + d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + view3d_opengl_read_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); glGetDoublev(GL_DEPTH_RANGE, d->depth_range); d->damaged = FALSE; } @@ -2130,9 +2176,7 @@ void ED_view3d_depth_update(ARegion *ar) } if (d->damaged) { - glReadPixels(ar->winrct.xmin, ar->winrct.ymin, d->w, d->h, - GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - + view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); glGetDoublev(GL_DEPTH_RANGE, d->depth_range); d->damaged = 0; @@ -2999,7 +3043,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) #define VIEWGRAD_RES_Y 16 GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4]; - static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][2]; + static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3]; static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4]; static char buf_calculated = FALSE; @@ -3008,8 +3052,6 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings, &scene->display_settings); - glClear(GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -3029,6 +3071,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) /* -1..1 range */ grid_pos[x][y][0] = (xf - 0.5f) * 2.0f; grid_pos[x][y][1] = (yf - 0.5f) * 2.0f; + grid_pos[x][y][2] = 1.0; } } @@ -3082,15 +3125,22 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) } } + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, grid_pos); + glVertexPointer(3, GL_FLOAT, 0, grid_pos); glColorPointer(4, GL_UNSIGNED_BYTE, 0, grid_col); glDrawElements(GL_QUADS, (VIEWGRAD_RES_X - 1) * (VIEWGRAD_RES_Y - 1) * 4, GL_UNSIGNED_SHORT, indices); + glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + glDepthFunc(GL_LEQUAL); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); @@ -3112,9 +3162,6 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) } else { if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - /* only clear depth buffer here */ - glClear(GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -3122,17 +3169,22 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) glPushMatrix(); glLoadIdentity(); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); glShadeModel(GL_SMOOTH); glBegin(GL_QUADS); UI_ThemeColor(TH_LOW_GRAD); - glVertex2f(-1.0, -1.0); - glVertex2f(1.0, -1.0); + glVertex3f(-1.0, -1.0, 1.0); + glVertex3f(1.0, -1.0, 1.0); UI_ThemeColor(TH_HIGH_GRAD); - glVertex2f(1.0, 1.0); - glVertex2f(-1.0, 1.0); + glVertex3f(1.0, 1.0, 1.0); + glVertex3f(-1.0, 1.0, 1.0); glEnd(); glShadeModel(GL_FLAT); + glDepthFunc(GL_LEQUAL); + glDisable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); glPopMatrix(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 5f54f0dcfc8..8c8332075a2 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -368,6 +368,7 @@ typedef struct ViewOpsData { float reverse, dist0, camzoom0; float grid, far; short axis_snap; /* view rotate only */ + float zfac; /* use for orbit selection and auto-dist */ float ofs[3], dyn_ofs[3]; @@ -407,7 +408,7 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) } -static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event) +static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event) { static float lastofs[3] = {0, 0, 0}; RegionView3D *rv3d; @@ -504,7 +505,11 @@ static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event) calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec); - initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]); + { + float tvec[3]; + negate_v3_v3(tvec, rv3d->ofs); + vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + } vod->reverse = 1.0f; if (rv3d->persmat[2][1] < 0.0f) @@ -836,7 +841,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) ED_region_tag_redraw(vod->ar); } -static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event) +static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod = op->customdata; short event_code = VIEW_PASS; @@ -885,7 +890,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; RegionView3D *rv3d; @@ -1092,7 +1097,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D * -- zooming * -- panning in rotationally-locked views */ -static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type != NDOF_MOTION) @@ -1174,7 +1179,7 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) } -static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type != NDOF_MOTION) @@ -1272,7 +1277,7 @@ void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) /* -- "pan" navigation * -- zoom or dolly? */ -static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { if (event->type != NDOF_MOTION) return OPERATOR_CANCELLED; @@ -1366,7 +1371,7 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) /* * this is basically just the pan only code + the rotate only code crammed into one function that does both */ -static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; @@ -1508,7 +1513,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) mval_f[0] = x - vod->oldx; mval_f[1] = y - vod->oldy; - ED_view3d_win_to_delta(vod->ar, mval_f, dvec); + ED_view3d_win_to_delta(vod->ar, mval_f, dvec, vod->zfac); add_v3_v3(vod->rv3d->ofs, dvec); @@ -1525,7 +1530,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) } -static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) +static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod = op->customdata; @@ -1568,7 +1573,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; @@ -1665,15 +1670,16 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my) float tpos[3]; float mval_f[2]; float new_dist; + float zfac; negate_v3_v3(tpos, rv3d->ofs); - /* Project cursor position into 3D space */ - initgrabz(rv3d, tpos[0], tpos[1], tpos[2]); - mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f; mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f; - ED_view3d_win_to_delta(ar, mval_f, dvec); + + /* Project cursor position into 3D space */ + zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); /* Calculate view target position for dolly */ add_v3_v3v3(tvec, tpos, dvec); @@ -1788,7 +1794,7 @@ static void viewzoom_apply(ViewOpsData *vod, const int x, const int y, const sho } -static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event) +static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod = op->customdata; short event_code = VIEW_PASS; @@ -1933,7 +1939,7 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf) } /* viewdolly_invoke() copied this function, changes here may apply there */ -static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; @@ -2053,7 +2059,7 @@ static void viewdolly_apply(ViewOpsData *vod, int x, int y, const short zoom_inv } -static int viewdolly_modal(bContext *C, wmOperator *op, wmEvent *event) +static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod = op->customdata; short event_code = VIEW_PASS; @@ -2145,7 +2151,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) } /* copied from viewzoom_invoke(), changes here may apply there */ -static int viewdolly_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; @@ -2957,14 +2963,20 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) } else { float mval_f[2]; + float zfac; + /* We cant use the depth, fallback to the old way that dosnt set the center depth */ copy_v3_v3(new_ofs, rv3d->ofs); - initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]); + { + float tvec[3]; + negate_v3_v3(tvec, new_ofs); + zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL); + } mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f; mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f; - ED_view3d_win_to_delta(ar, mval_f, dvec); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); /* center the view to the center of the rectangle */ sub_v3_v3(new_ofs, dvec); } @@ -2997,7 +3009,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -3415,16 +3427,19 @@ static int viewpan_exec(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); float vec[3]; + const float co_zero[3] = {0.0f}; float mval_f[2] = {0.0f, 0.0f}; + float zfac; int pandir; pandir = RNA_enum_get(op->ptr, "type"); - initgrabz(rv3d, 0.0, 0.0, 0.0); - if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); } - else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); } - else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); } - else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); } + zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); + if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; } + else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; } + else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; } + else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; } + ED_view3d_win_to_delta(ar, mval_f, vec, zfac); add_v3_v3(rv3d->ofs, vec); if (rv3d->viewlock & RV3D_BOXVIEW) @@ -3506,7 +3521,7 @@ static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int background_image_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { View3D *v3d = CTX_wm_view3d(C); Image *ima = NULL; @@ -3661,7 +3676,7 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); ARegion *ar = CTX_wm_region(C); @@ -3713,15 +3728,16 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); float mval_fl[2]; - int flip; + float zfac; + bool flip; - flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); + zfac = ED_view3d_calc_zfac(rv3d, fp, &flip); /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ if (flip) { negate_v3_v3(fp, rv3d->ofs); /* re initialize, no need to check flip again */ - /* flip = */ initgrabz(rv3d, fp[0], fp[1], fp[2]); + zfac = ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ ); } if (ED_view3d_project_float_global(ar, fp, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { @@ -3736,17 +3752,17 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) if (depth_used == FALSE) { float dvec[3]; VECSUB2D(mval_fl, mval_fl, mval); - ED_view3d_win_to_delta(ar, mval_fl, dvec); + ED_view3d_win_to_delta(ar, mval_fl, dvec, zfac); sub_v3_v3(fp, dvec); } } else { - const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); - const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); + const float dx = ((float)(mval[0] - (ar->winx / 2))) * zfac / (ar->winx / 2); + const float dy = ((float)(mval[1] - (ar->winy / 2))) * zfac / (ar->winy / 2); const float fz = (rv3d->persmat[0][3] * fp[0] + rv3d->persmat[1][3] * fp[1] + rv3d->persmat[2][3] * fp[2] + - rv3d->persmat[3][3]) / rv3d->zfac; + rv3d->persmat[3][3]) / zfac; fp[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy + rv3d->persinv[2][0] * fz) - rv3d->ofs[0]; fp[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy + rv3d->persinv[2][1] * fz) - rv3d->ofs[1]; @@ -3755,7 +3771,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) } -static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -3794,7 +3810,7 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* ***************** manipulator op ******************* */ -static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); @@ -3830,7 +3846,7 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot) Transform_Properties(ot, P_CONSTRAINT); } -static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { View3D *v3d = CTX_wm_view3d(C); diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index c2e75a1c5d9..700027d62a2 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -272,7 +272,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), #define FLY_CANCEL 1 #define FLY_CONFIRM 2 -static int initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event) +static int initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); float upvec[3]; /* tmp */ @@ -486,7 +486,7 @@ static int flyEnd(bContext *C, FlyInfo *fly) return OPERATOR_CANCELLED; } -static void flyEvent(FlyInfo *fly, wmEvent *event) +static void flyEvent(FlyInfo *fly, const wmEvent *event) { if (event->type == TIMER && event->customdata == fly->timer) { fly->redraw = 1; @@ -1179,7 +1179,7 @@ static int flyApply_ndof(bContext *C, FlyInfo *fly) return OPERATOR_FINISHED; } -static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int fly_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); FlyInfo *fly; @@ -1214,7 +1214,7 @@ static int fly_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) +static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event) { int exit_code; short do_draw = FALSE; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index e078fa8eda1..430ed8698d7 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -28,7 +28,6 @@ * \ingroup spview3d */ - #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -37,8 +36,6 @@ #include "DNA_object_types.h" #include "DNA_mesh_types.h" -#include "RNA_access.h" - #include "MEM_guardedalloc.h" #include "BLI_math.h" @@ -57,18 +54,19 @@ #include "BKE_screen.h" #include "BKE_tessmesh.h" +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + #include "ED_mesh.h" #include "ED_util.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_types.h" -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_define.h" -#include "RNA_enum_types.h" - #include "UI_interface.h" #include "UI_resources.h" @@ -209,7 +207,7 @@ static int view3d_layers_exec(bContext *C, wmOperator *op) /* applies shift and alt, lazy coding or ok? :) */ /* the local per-keymap-entry keymap will solve it */ -static int view3d_layers_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view3d_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (event->ctrl || event->oskey) return OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index d4cfa9076a6..26ed8e1885c 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -108,6 +108,9 @@ float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]); void view3d_keymap(struct wmKeyConfig *keyconf); void VIEW3D_OT_fly(struct wmOperatorType *ot); +/* view3d_ruler.c */ +void VIEW3D_OT_ruler(struct wmOperatorType *ot); + /* drawanim.c */ void draw_motion_paths_init(View3D *v3d, struct ARegion *ar); void draw_motion_path_instance(Scene *scene, diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index bf1c5404c0e..e567ebda4b7 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -166,6 +166,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_localview); WM_operatortype_append(VIEW3D_OT_game_start); WM_operatortype_append(VIEW3D_OT_fly); + WM_operatortype_append(VIEW3D_OT_ruler); WM_operatortype_append(VIEW3D_OT_layers); WM_operatortype_append(VIEW3D_OT_copybuffer); WM_operatortype_append(VIEW3D_OT_pastebuffer); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index bc1656ff7c6..30a100283cc 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -73,7 +73,7 @@ void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r /** * \note use #ED_view3d_ob_project_mat_get to get projecting mat */ -void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3], float mat[4][4]) +void ED_view3d_project_float_v3_m4(const ARegion *ar, const float vec[3], float r_co[3], float mat[4][4]) { float vec4[4]; @@ -97,7 +97,7 @@ void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3 /* Clipping Projection Functions * ***************************** */ -eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) +eV3DProjStatus ED_view3d_project_base(const struct ARegion *ar, struct Base *base) { eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -113,8 +113,8 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) * - 'rv3d->perspmat', is_local == FALSE * - 'rv3d->persmatob', is_local == TRUE */ -static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, - float perspmat[4][4], const int is_local, /* normally hidden */ +static eV3DProjStatus ed_view3d_project__internal(const ARegion *ar, + float perspmat[4][4], const bool is_local, /* normally hidden */ const float co[3], float r_co[2], const eV3DProjTest flag) { float vec4[4]; @@ -171,7 +171,7 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, return V3D_PROJ_RET_OK; } -eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_short_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], short r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -190,7 +190,7 @@ eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], con return ret; } -eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_int_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], int r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -209,7 +209,7 @@ eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const return ret; } -eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], const int is_local, +eV3DProjStatus ED_view3d_project_float_ex(const ARegion *ar, float perspmat[4][4], const bool is_local, const float co[3], float r_co[2], const eV3DProjTest flag) { float tvec[2]; @@ -228,39 +228,39 @@ eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], con } /* --- short --- */ -eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_short_global(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_short_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_short_object(const ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } /* --- int --- */ -eV3DProjStatus ED_view3d_project_int_global(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_int_global(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_int_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_int_object(const ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); } /* --- float --- */ -eV3DProjStatus ED_view3d_project_float_global(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_float_global(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_float_ex(ar, rv3d->persmat, FALSE, co, r_co, flag); } /* object space, use ED_view3d_init_mats_rv3d before calling */ -eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) +eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag) { RegionView3D *rv3d = ar->regiondata; return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag); @@ -271,28 +271,30 @@ eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], fl /* More Generic Window/Ray/Vector projection functions * *************************************************** */ -/* odd function, need to document better */ -int initgrabz(RegionView3D *rv3d, float x, float y, float z) +/** + * Caculate a depth value from \a co, use with #ED_view3d_win_to_delta + */ +float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip) { - int flip = FALSE; - if (rv3d == NULL) return flip; - rv3d->zfac = rv3d->persmat[0][3] * x + rv3d->persmat[1][3] * y + rv3d->persmat[2][3] * z + rv3d->persmat[3][3]; - if (rv3d->zfac < 0.0f) - flip = TRUE; + float zfac = mul_project_m4_v3_zfac((float (*)[4])rv3d->persmat, co); + + if (r_flip) { + *r_flip = (zfac < 0.0f); + } + /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that - * (accounting for near zero values) - */ - if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f; + * (accounting for near zero values) */ + if (zfac < 1.e-6f && zfac > -1.e-6f) { + zfac = 1.0f; + } /* Negative zfac means x, y, z was behind the camera (in perspective). - * This gives flipped directions, so revert back to ok default case. - */ - /* NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok - * Aligorith, 2009Aug31 */ - //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f; - if (rv3d->zfac < 0.0f) rv3d->zfac = -rv3d->zfac; - - return flip; + * This gives flipped directions, so revert back to ok default case. */ + if (zfac < 0.0f) { + zfac = -zfac; + } + + return zfac; } /** @@ -306,7 +308,7 @@ int initgrabz(RegionView3D *rv3d, float x, float y, float z) * \param ray_start The world-space starting point of the segment. * \param ray_normal The normalized world-space direction of towards mval. */ -void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]) +void ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]) { float ray_end[3]; @@ -322,7 +324,7 @@ void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float r * \param coord The world-space location. * \param vec The resulting normalized vector. */ -void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3]) +void ED_view3d_global_to_vector(const RegionView3D *rv3d, const float coord[3], float vec[3]) { if (rv3d->is_persp) { float p1[4], p2[4]; @@ -331,11 +333,11 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float p1[3] = 1.0f; copy_v3_v3(p2, p1); p2[3] = 1.0f; - mul_m4_v4(rv3d->viewmat, p2); + mul_m4_v4((float (*)[4])rv3d->viewmat, p2); mul_v3_fl(p2, 2.0f); - mul_m4_v4(rv3d->viewinv, p2); + mul_m4_v4((float (*)[4])rv3d->viewinv, p2); sub_v3_v3v3(vec, p1, p2); } @@ -352,7 +354,7 @@ void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float * \param mval The area relative location (such as event->mval converted to floats). * \param out The resulting world-space location. */ -void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) +void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) { RegionView3D *rv3d = ar->regiondata; @@ -384,19 +386,19 @@ void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[ /** * Calculate a 3d difference vector from 2d window offset. - * note that initgrabz() must be called first to determine + * note that ED_view3d_calc_zfac() must be called first to determine * the depth used to calculate the delta. * \param ar The region (used for the window width and height). * \param mval The area relative 2d difference (such as event->mval[0] - other_x). * \param out The resulting world-space delta. */ -void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) +void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3], const float zfac) { RegionView3D *rv3d = ar->regiondata; float dx, dy; - dx = 2.0f * mval[0] * rv3d->zfac / ar->winx; - dy = 2.0f * mval[1] * rv3d->zfac / ar->winy; + dx = 2.0f * mval[0] * zfac / ar->winx; + dy = 2.0f * mval[1] * zfac / ar->winy; out[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy); out[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy); @@ -408,7 +410,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) * This direction vector starts and the view in the direction of the 2d window coordinates. * In orthographic view all window coordinates yield the same vector. * - * \note doesn't rely on initgrabz + * \note doesn't rely on ED_view3d_calc_zfac * for perspective view, get the vector direction to * the mouse cursor as a normalized vector. * @@ -416,7 +418,7 @@ void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) * \param mval The area relative 2d location (such as event->mval converted to floats). * \param out The resulting normalized world-space direction vector. */ -void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3]) +void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3]) { RegionView3D *rv3d = ar->regiondata; @@ -433,7 +435,7 @@ void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3]) normalize_v3(out); } -void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) +void ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) { RegionView3D *rv3d = ar->regiondata; @@ -472,7 +474,7 @@ void ED_view3d_win_to_segment(ARegion *ar, View3D *v3d, const float mval[2], flo * \param ray_end The world-space end point of the segment. * \return success, FALSE if the segment is totally clipped. */ -int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) +int ED_view3d_win_to_segment_clip(const ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) { RegionView3D *rv3d = ar->regiondata; ED_view3d_win_to_segment(ar, v3d, mval, ray_start, ray_end); @@ -503,12 +505,12 @@ int ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], /* Utility functions for projection * ******************************** */ -void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4]) +void ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, Object *ob, float pmat[4][4]) { float vmat[4][4]; - mult_m4_m4m4(vmat, rv3d->viewmat, ob->obmat); - mult_m4_m4m4(pmat, rv3d->winmat, vmat); + mult_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat); + mult_m4_m4m4(pmat, (float (*)[4])rv3d->winmat, vmat); } /** diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c new file mode 100644 index 00000000000..410d20a1dc0 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -0,0 +1,939 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_ruler.c + * \ingroup spview3d + */ + +/* defines VIEW3D_OT_ruler modal operator */ + +#include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" + +#include "BKE_context.h" +#include "BKE_unit.h" +#include "BKE_gpencil.h" + +#include "BIF_gl.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "BLF_api.h" +#include "BIF_glutil.h" + +#include "UI_resources.h" +#include "UI_interface.h" + +#include "view3d_intern.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/* Snapping (could be own function) */ +/* NOTE - this is not very nice use of transform snapping */ +#include "ED_transform.h" +#include "../transform/transform.h" + +static bool ED_view3d_snap_co(bContext *C, float r_co[3], const float co_ss[2], + bool use_vert, bool use_edge, bool use_face) +{ + TransInfo t = {0}; + int dist = 12; /* snap dist */ + float r_no_dummy[3]; + bool ret = false; + char backup_snap_mode; + Base *backup_baseact; + + t.scene = CTX_data_scene(C); + t.view = CTX_wm_view3d(C); + t.ar = CTX_wm_region(C); + t.obedit = CTX_data_edit_object(C); + + backup_snap_mode = t.scene->toolsettings->snap_mode; + backup_baseact = t.scene->basact; + t.scene->basact = NULL; + + /* try snap edge, then face if it fails */ + if (use_vert) { + t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX; + ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL); + } + if (use_edge && (ret == false)) { + t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE; + ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL); + } + if (use_face && (ret == false)) { + t.scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE; + ret = snapObjectsTransform(&t, co_ss, &dist, r_co, r_no_dummy, SNAP_ALL); + } + + t.scene->toolsettings->snap_mode = backup_snap_mode; + t.scene->basact = backup_baseact; + + return ret; +} +/* done snapping */ + + +/* -------------------------------------------------------------------- */ +/* Ruler Item (we can have many) */ +enum { + RULERITEM_USE_ANGLE = (1 << 0), /* use protractor */ + RULERITEM_USE_RAYCAST = (1 << 1) +}; + +enum { + RULERITEM_DIRECTION_IN = 0, + RULERITEM_DIRECTION_OUT +}; + +#define RULER_PICK_DIST 75.0f +#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST) + +typedef struct RulerItem { + struct RulerItem *next, *prev; + + /* worldspace coords, middle being optional */ + float co[3][3]; + + /* selected coord */ + char co_index; /* 0 -> 2*/ + + int flag; + int raycast_dir; /* RULER_DIRECTION_* */ +} RulerItem; + +enum { + RULER_STATE_NORMAL = 0, + RULER_STATE_DRAG +}; + + +/* -------------------------------------------------------------------- */ +/* Ruler Info (one per session) */ + +typedef struct RulerInfo { + ListBase items; + int item_active; + int flag; + int snap_flag; + int state; + + /* --- */ + ARegion *ar; + void *draw_handle_pixel; +} RulerInfo; + +/* -------------------------------------------------------------------- */ +/* local functions */ +static RulerItem *ruler_item_add(RulerInfo *ruler_info) +{ + RulerItem *ruler_item = MEM_callocN(sizeof(RulerItem), "RulerItem"); + BLI_addtail(&ruler_info->items, ruler_item); + return ruler_item; +} + +static void ruler_item_remove(RulerInfo *ruler_info, RulerItem *ruler_item) +{ + BLI_remlink(&ruler_info->items, ruler_item); + MEM_freeN(ruler_item); +} + +static RulerItem *ruler_item_active_get(RulerInfo *ruler_info) +{ + return BLI_findlink(&ruler_info->items, ruler_info->item_active); +} + +static void ruler_item_active_set(RulerInfo *ruler_info, RulerItem *ruler_item) +{ + ruler_info->item_active = BLI_findindex(&ruler_info->items, ruler_item); +} + +static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, + char *numstr, size_t numstr_size, int prec) +{ + const int do_split = unit->flag & USER_UNIT_OPT_SPLIT; + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + const float ruler_angle = angle_v3v3v3(ruler_item->co[0], + ruler_item->co[1], + ruler_item->co[2]); + + if (unit->system == USER_UNIT_NONE) { + BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle)); + } + else { + bUnit_AsString(numstr, numstr_size, + (double)ruler_angle, + prec, unit->system, B_UNIT_ROTATION, do_split, false); + } + } + else { + const float ruler_len = len_v3v3(ruler_item->co[0], + ruler_item->co[2]); + + if (unit->system == USER_UNIT_NONE) { + BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len); + } + else { + bUnit_AsString(numstr, numstr_size, + (double)(ruler_len * unit->scale_length), + prec, unit->system, B_UNIT_LENGTH, do_split, false); + } + } + +} + +static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], + RulerItem **r_ruler_item, int *r_co_index) +{ + ARegion *ar = ruler_info->ar; + RulerItem *ruler_item; + + float dist_best = RULER_PICK_DIST_SQ; + RulerItem *ruler_item_best = NULL; + int co_index_best = -1; + + for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { + float co_ss[3][2]; + float dist; + int j; + + /* should these be checked? - ok for now not to */ + for (j = 0; j < 3; j++) { + ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + } + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]), + dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2])); + if (dist < dist_best) { + dist_best = dist; + ruler_item_best = ruler_item; + + { + float dist_points[3] = {len_squared_v2v2(co_ss[0], mval), + len_squared_v2v2(co_ss[1], mval), + len_squared_v2v2(co_ss[2], mval)}; + if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { + co_index_best = min_axis_v3(dist_points); + } + else { + co_index_best = -1; + } + } + } + } + else { + dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]); + if (dist < dist_best) { + dist_best = dist; + ruler_item_best = ruler_item; + + { + float dist_points[2] = {len_squared_v2v2(co_ss[0], mval), + len_squared_v2v2(co_ss[2], mval)}; + if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { + co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; + } + else { + co_index_best = -1; + } + } + } + } + } + + if (ruler_item_best) { + *r_ruler_item = ruler_item_best; + *r_co_index = co_index_best; + return true; + } + else { + *r_ruler_item = NULL; + *r_co_index = -1; + return false; + } +} + +#define RULER_ID "RulerData3D" +static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) +{ + Scene *scene = CTX_data_scene(C); + bGPDlayer *gpl; + bGPDframe *gpf; + bGPDstroke *gps; + RulerItem *ruler_item; + const char *ruler_name = RULER_ID; + bool change = false; + + if (scene->gpd == NULL) { + scene->gpd = gpencil_data_addnew("GPencil"); + } + + gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + if (gpl == NULL) { + gpl = gpencil_layer_addnew(scene->gpd, ruler_name, false); + gpl->thickness = 1; + gpl->flag |= GP_LAYER_HIDE; + } + + gpf = gpencil_layer_getframe(gpl, CFRA, true); + free_gpencil_strokes(gpf); + + for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { + bGPDspoint *pt; + int j; + + /* allocate memory for a new stroke */ + gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + gps->totpoints = 3; + pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + for (j = 0; j < 3; j++) { + copy_v3_v3(&pt->x, ruler_item->co[j]); + pt->pressure = 1.0f; + pt++; + } + } + else { + gps->totpoints = 2; + pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + for (j = 0; j < 3; j += 2) { + copy_v3_v3(&pt->x, ruler_item->co[j]); + pt->pressure = 1.0f; + pt++; + } + } + gps->flag = GP_STROKE_3DSPACE; + BLI_addtail(&gpf->strokes, gps); + change = true; + } + + return change; +} + +static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info) +{ + Scene *scene = CTX_data_scene(C); + bool change = false; + + if (scene->gpd) { + bGPDlayer *gpl; + const char *ruler_name = RULER_ID; + gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + if (gpl) { + bGPDframe *gpf; + gpf = gpencil_layer_getframe(gpl, CFRA, false); + if (gpf) { + bGPDstroke *gps; + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt = gps->points; + int j; + if (gps->totpoints == 3) { + RulerItem *ruler_item = ruler_item_add(ruler_info); + for (j = 0; j < 3; j++) { + copy_v3_v3(ruler_item->co[j], &pt->x); + pt++; + } + ruler_item->flag |= RULERITEM_USE_ANGLE; + change = true; + } + else if (gps->totpoints == 2) { + RulerItem *ruler_item = ruler_item_add(ruler_info); + for (j = 0; j < 3; j += 2) { + copy_v3_v3(ruler_item->co[j], &pt->x); + pt++; + } + change = true; + } + } + } + } + } + + return change; +} + +/* -------------------------------------------------------------------- */ +/* local callbacks */ + +static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg) +{ + Scene *scene = CTX_data_scene(C); + UnitSettings *unit = &scene->unit; + RulerItem *ruler_item; + RulerInfo *ruler_info = arg; + RegionView3D *rv3d = ruler_info->ar->regiondata; +// ARegion *ar = ruler_info->ar; + const float cap_size = 4.0f; + const float bg_margin = 4.0f * U.pixelsize; + const float bg_radius = 4.0f * U.pixelsize; + const float arc_size = 64.0f * U.pixelsize; +#define ARC_STEPS 24 + const int arc_steps = ARC_STEPS; + int i; + //unsigned int color_act = 0x666600; + unsigned int color_act = 0xffffff; + unsigned int color_base = 0x0; + unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; + unsigned char color_text[3]; + unsigned char color_wire[3]; + + /* anti-aliased lines for more consistent appearance */ + glEnable(GL_LINE_SMOOTH); + + BLF_enable(blf_mono_font, BLF_ROTATION); + BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); + BLF_rotation(blf_mono_font, 0.0f); + + UI_GetThemeColor3ubv(TH_TEXT, color_text); + UI_GetThemeColor3ubv(TH_WIRE, color_wire); + + for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) { + const bool is_act = (i == ruler_info->item_active); + float dir_ruler[2]; + float co_ss[3][2]; + int j; + + /* should these be checked? - ok for now not to */ + for (j = 0; j < 3; j++) { + ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + } + + glEnable(GL_BLEND); + + cpack(is_act ? color_act : color_base); + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + glBegin(GL_LINE_STRIP); + for (j = 0; j < 3; j++) { + glVertex2fv(co_ss[j]); + } + glEnd(); + cpack(0xaaaaaa); + setlinestyle(3); + glBegin(GL_LINE_STRIP); + for (j = 0; j < 3; j++) { + glVertex2fv(co_ss[j]); + } + glEnd(); + setlinestyle(0); + + /* arc */ + { + float dir_tmp[3]; + float co_tmp[3]; + float arc_ss_coords[ARC_STEPS + 1][2]; + + float dir_a[3]; + float dir_b[3]; + float quat[4]; + float axis[3]; + float angle; + const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) * + min_fff(arc_size, + len_v2v2(co_ss[0], co_ss[1]) / 2.0f, + len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); + + sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); + sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); + normalize_v3(dir_a); + normalize_v3(dir_b); + + cross_v3_v3v3(axis, dir_a, dir_b); + angle = angle_normalized_v3v3(dir_a, dir_b); + + axis_angle_to_quat(quat, axis, angle / arc_steps); + + copy_v3_v3(dir_tmp, dir_a); + + glColor3ubv(color_wire); + + for (j = 0; j <= arc_steps; j++) { + madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); + ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP); + mul_qt_v3(quat, dir_tmp); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords); + glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1); + glDisableClientState(GL_VERTEX_ARRAY); + } + + /* text */ + { + char numstr[256]; + float numstr_size[2]; + float pos[2]; + const int prec = 2; /* XXX, todo, make optional */ + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + + BLF_width_and_height(blf_mono_font, numstr, &numstr_size[0], &numstr_size[1]); + + pos[0] = co_ss[1][0] + (cap_size * 2.0f); + pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); + + /* draw text (bg) */ + glColor4ubv(color_back); + uiSetRoundBox(UI_CNR_ALL); + uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, + pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], + bg_radius); + /* draw text */ + glColor3ubv(color_text); + BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); + BLF_rotation(blf_mono_font, 0.0f); + BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + } + + /* capping */ + { + float rot_90_vec_a[2]; + float rot_90_vec_b[2]; + float cap[2]; + + sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); + rot_90_vec_a[0] = -dir_ruler[1]; + rot_90_vec_a[1] = dir_ruler[0]; + normalize_v2(rot_90_vec_a); + + sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); + rot_90_vec_b[0] = -dir_ruler[1]; + rot_90_vec_b[1] = dir_ruler[0]; + normalize_v2(rot_90_vec_b); + + glEnable(GL_BLEND); + + glColor3ubv(color_wire); + + glBegin(GL_LINES); + + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + glVertex2fv(cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + glVertex2fv(cap); + + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + glVertex2fv(cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + glVertex2fv(cap); + + /* angle vertex */ + glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + glEnd(); + + glDisable(GL_BLEND); + } + } + else { + glBegin(GL_LINE_STRIP); + for (j = 0; j < 3; j += 2) { + glVertex2fv(co_ss[j]); + } + glEnd(); + cpack(0xaaaaaa); + setlinestyle(3); + glBegin(GL_LINE_STRIP); + for (j = 0; j < 3; j += 2) { + glVertex2fv(co_ss[j]); + } + glEnd(); + setlinestyle(0); + + sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); + + /* text */ + { + char numstr[256]; + float numstr_size[2]; + const int prec = 6; /* XXX, todo, make optional */ + float pos[2]; + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + + BLF_width_and_height(blf_mono_font, numstr, &numstr_size[0], &numstr_size[1]); + + mid_v2_v2v2(pos, co_ss[0], co_ss[2]); + + /* center text */ + pos[0] -= numstr_size[0] / 2.0f; + pos[1] -= numstr_size[1] / 2.0f; + + /* draw text (bg) */ + glColor4ubv(color_back); + uiSetRoundBox(UI_CNR_ALL); + uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, + pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], + bg_radius); + /* draw text */ + glColor3ubv(color_text); + BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); + BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + } + + /* capping */ + { + float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; + float cap[2]; + + normalize_v2(rot_90_vec); + + glEnable(GL_BLEND); + glColor3ubv(color_wire); + + glBegin(GL_LINES); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + glVertex2fv(cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + glVertex2fv(cap); + + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + glVertex2fv(cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + glVertex2fv(cap); + glEnd(); + + glDisable(GL_BLEND); + } + } + } + + glDisable(GL_LINE_SMOOTH); + + BLF_disable(blf_mono_font, BLF_ROTATION); + +#undef ARC_STEPS +} + +/* free, use for both cancel and finish */ +static void view3d_ruler_end(const struct bContext *UNUSED(C), RulerInfo *ruler_info) +{ + ED_region_draw_cb_exit(ruler_info->ar->type, ruler_info->draw_handle_pixel); +} + +static void view3d_ruler_free(RulerInfo *ruler_info) +{ + BLI_freelistN(&ruler_info->items); + MEM_freeN(ruler_info); +} + +static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], + const int xy[2]) +{ + view3d_get_view_aligned_coordinate(ruler_info->ar, r_co, xy, true); +} + +/* use for mousemove events */ +static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, const int mval[2], const bool do_snap) +{ + RulerItem *ruler_item = ruler_item_active_get(ruler_info); + + if (ruler_item) { + float *co = ruler_item->co[ruler_item->co_index]; + view3d_ruler_item_project(ruler_info, co, mval); + if (do_snap) { + const float mval_fl[2] = {UNPACK2(mval)}; + ED_view3d_snap_co(C, co, mval_fl, true, true, true); + } + return true; + } + else { + return false; + } +} + +static void view3d_ruler_header_update(ScrArea *sa) +{ + const char *text = "Ctrl+LMB: Add, " + "Del: Remove, " + "Ctrl+Drag: Snap, " + "Ctrl+C: Copy Value, " + "Enter: Store, " + "Esc: Cancel"; + + ED_area_headerprint(sa, text); +} + +/* -------------------------------------------------------------------- */ +/* Operator callbacks */ + +static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wmWindow *win = CTX_wm_window(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + RulerInfo *ruler_info; + + ruler_info = MEM_callocN(sizeof(RulerInfo), "RulerInfo"); + + if (view3d_ruler_from_gpencil(C, ruler_info)) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } + + op->customdata = ruler_info; + + ruler_info->ar = ar; + ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel, + ruler_info, REGION_DRAW_POST_PIXEL); + + view3d_ruler_header_update(sa); + + WM_cursor_modal(win, BC_CROSSCURSOR); + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int view3d_ruler_cancel(bContext *C, wmOperator *op) +{ + RulerInfo *ruler_info = op->customdata; + + view3d_ruler_end(C, ruler_info); + view3d_ruler_free(ruler_info); + op->customdata = NULL; + + return OPERATOR_CANCELLED; +} + +static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + bool do_draw = false; + int exit_code = OPERATOR_RUNNING_MODAL; + RulerInfo *ruler_info = op->customdata; + ARegion *ar = ruler_info->ar; + RegionView3D *rv3d = ar->regiondata; + + (void)C; + + switch (event->type) { + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + if (ruler_info->state == RULER_STATE_DRAG) { + /* rubber-band angle removal */ + RulerItem *ruler_item = ruler_item_active_get(ruler_info); + if (ruler_item && (ruler_item->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { + if (!BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { + ruler_item->flag &= ~RULERITEM_USE_ANGLE; + do_draw = true; + } + } + ruler_info->state = RULER_STATE_NORMAL; + } + } + else { + if (ruler_info->state == RULER_STATE_NORMAL) { + + if (event->ctrl || + /* weak - but user friendly */ + (ruler_info->items.first == NULL)) + { + /* Create new line */ + RulerItem *ruler_item; + /* check if we want to drag an existing point or add a new one */ + ruler_info->state = RULER_STATE_DRAG; + + ruler_item = ruler_item_add(ruler_info); + ruler_item_active_set(ruler_info, ruler_item); + + negate_v3_v3(ruler_item->co[0], rv3d->ofs); + view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval); + + /* snap the first point added, not essential but handy */ + { + ruler_item->co_index = 0; + view3d_ruler_item_mousemove(C, ruler_info, event->mval, true); + } + + copy_v3_v3(ruler_item->co[2], ruler_item->co[0]); + ruler_item->co_index = 2; + + do_draw = true; + } + else { + float mval_fl[2] = {UNPACK2(event->mval)}; + RulerItem *ruler_item_pick; + int co_index; + + /* select and drag */ + if (view3d_ruler_pick(ruler_info, mval_fl, &ruler_item_pick, &co_index)) { + if (co_index == -1) { + if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) { + /* Add Center Point */ + ruler_item_active_set(ruler_info, ruler_item_pick); + ruler_item_pick->flag |= RULERITEM_USE_ANGLE; + ruler_item_pick->co_index = 1; + ruler_info->state = RULER_STATE_DRAG; + + /* find the factor */ + { + float co_ss[2][2]; + float fac; + + ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP); + + fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); + CLAMP(fac, 0.0f, 1.0f); + + interp_v3_v3v3(ruler_item_pick->co[1], + ruler_item_pick->co[0], + ruler_item_pick->co[2], fac); + } + + /* update the new location */ + view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->ctrl != 0); + do_draw = true; + } + } + else { + ruler_item_active_set(ruler_info, ruler_item_pick); + ruler_item_pick->co_index = co_index; + ruler_info->state = RULER_STATE_DRAG; + do_draw = true; + } + } + else { + exit_code = OPERATOR_PASS_THROUGH; + } + + } + } + } + break; + case CKEY: + { + if (event->ctrl) { + RulerItem *ruler_item = ruler_item_active_get(ruler_info); + if (ruler_item) { + const int prec = 8; + char numstr[256]; + Scene *scene = CTX_data_scene(C); + UnitSettings *unit = &scene->unit; + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + WM_clipboard_text_set((void *) numstr, false); + } + } + } + case RIGHTCTRLKEY: + case LEFTCTRLKEY: + { + WM_event_add_mousemove(C); + break; + } + case MOUSEMOVE: + { + if (ruler_info->state == RULER_STATE_DRAG) { + if (view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->ctrl != 0)) { + do_draw = true; + } + } + break; + } + case ESCKEY: + { + do_draw = true; + exit_code = OPERATOR_CANCELLED; + break; + } + case RETKEY: + { + view3d_ruler_to_gpencil(C, ruler_info); + do_draw = true; + exit_code = OPERATOR_FINISHED; + break; + } + case DELKEY: + { + if (event->val == KM_PRESS) { + if (ruler_info->state == RULER_STATE_NORMAL) { + RulerItem *ruler_item = ruler_item_active_get(ruler_info); + if (ruler_item) { + ruler_item_remove(ruler_info, ruler_item); + ruler_info->item_active = -1; + do_draw = true; + } + } + } + break; + } + default: + exit_code = OPERATOR_PASS_THROUGH; + break; + + } + + if (do_draw) { + ScrArea *sa = CTX_wm_area(C); + + view3d_ruler_header_update(sa); + + /* all 3d views draw rulers */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } + + if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { + wmWindow *win = CTX_wm_window(C); + ScrArea *sa = CTX_wm_area(C); + + WM_cursor_restore(win); + + view3d_ruler_end(C, ruler_info); + view3d_ruler_free(ruler_info); + op->customdata = NULL; + + ED_area_headerprint(sa, NULL); + } + + return exit_code; +} + +void VIEW3D_OT_ruler(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "3D Ruler & Protractor"; + ot->description = "Interactive ruler"; + ot->idname = "VIEW3D_OT_ruler"; + + /* api callbacks */ + ot->invoke = view3d_ruler_invoke; + ot->cancel = view3d_ruler_cancel; + ot->modal = view3d_ruler_modal; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 24260898066..b441e48f59d 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -108,23 +108,23 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc) vc->obedit = CTX_data_edit_object(C); } -int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int mval[2], const short do_fallback) +/** + * Re-project \a fp so it stays on the same view-plane but is under \a mval (normally the cursor location). + */ +bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval[2], const bool do_fallback) { + RegionView3D *rv3d = ar->regiondata; float dvec[3]; int mval_cpy[2]; eV3DProjStatus ret; - mval_cpy[0] = mval[0]; - mval_cpy[1] = mval[1]; - - ret = ED_view3d_project_int_global(vc->ar, fp, mval_cpy, V3D_PROJ_TEST_NOP); - - initgrabz(vc->rv3d, fp[0], fp[1], fp[2]); + ret = ED_view3d_project_int_global(ar, fp, mval_cpy, V3D_PROJ_TEST_NOP); if (ret == V3D_PROJ_RET_OK) { const float mval_f[2] = {(float)(mval_cpy[0] - mval[0]), (float)(mval_cpy[1] - mval[1])}; - ED_view3d_win_to_delta(vc->ar, mval_f, dvec); + const float zfac = ED_view3d_calc_zfac(rv3d, fp, NULL); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); sub_v3_v3(fp, dvec); return TRUE; @@ -132,11 +132,11 @@ int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int m else { /* fallback to the view center */ if (do_fallback) { - negate_v3_v3(fp, vc->rv3d->ofs); - return view3d_get_view_aligned_coordinate(vc, fp, mval, FALSE); + negate_v3_v3(fp, rv3d->ofs); + return view3d_get_view_aligned_coordinate(ar, fp, mval, false); } else { - return FALSE; + return false; } } } @@ -177,10 +177,9 @@ static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, int select) { BMVert *eve; BMIter iter; - int index = bm_wireoffs; + unsigned int index = bm_wireoffs; - eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); - for (; eve; eve = BM_iter_step(&iter), index++) { + for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter), index++) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { if (EDBM_backbuf_check(index)) { BM_vert_select_set(em->bm, eve, select); @@ -209,7 +208,7 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, int select) { BMFace *efa; BMIter iter; - int index = 1; + unsigned int index = 1; efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); for (; efa; efa = BM_iter_step(&iter), index++) { @@ -226,11 +225,11 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, int select) static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, int select) { MVert *mv = me->mvert; - int a; + unsigned int index; if (mv) { - for (a = 1; a <= me->totvert; a++, mv++) { - if (EDBM_backbuf_check(a)) { + for (index = 1; index <= me->totvert; index++, mv++) { + if (EDBM_backbuf_check(index)) { if (!(mv->flag & ME_HIDE)) { mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT); } @@ -243,11 +242,11 @@ static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, int select) static void edbm_backbuf_check_and_select_tfaces(Mesh *me, int select) { MPoly *mpoly = me->mpoly; - int a; + unsigned int index; if (mpoly) { - for (a = 1; a <= me->totpoly; a++, mpoly++) { - if (EDBM_backbuf_check(a)) { + for (index = 1; index <= me->totpoly; index++, mpoly++) { + if (EDBM_backbuf_check(index)) { mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL); } } @@ -733,7 +732,7 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m MetaBall *mb = (MetaBall *)vc->obedit->data; if (extend == 0 && select) - BKE_mball_deselect_all(mb); + BKE_mball_deselect_all(mb); BLI_lasso_boundbox(&rect, mcords, moves); @@ -780,9 +779,6 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh } else { LassoSelectUserData data; - rcti rect; - - BLI_lasso_boundbox(&rect, mcords, moves); view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); @@ -1054,7 +1050,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */ - if (strcmp(name, base->object->id.name + 2) == 0) { + if (STREQ(name, base->object->id.name + 2)) { ED_base_object_activate(C, base); ED_base_object_select(base, BA_SELECT); changed = 1; @@ -2230,7 +2226,7 @@ static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], shor /* ****** Mouse Select ****** */ -static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index bb5b7aa6911..d3bf8a30792 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -156,7 +156,7 @@ static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), cons { GHashIterator *iter = WM_operatortype_iter(); - for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + for (; BLI_ghashIterator_notDone(iter); BLI_ghashIterator_step(iter)) { wmOperatorType *ot = BLI_ghashIterator_getValue(iter); if (BLI_strcasestr(ot->name, str)) { diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index fba1ce328ba..b2e10fa8457 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -294,7 +294,7 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera } /* only meant for timer usage */ -static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -667,22 +667,29 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d) } /* copies logic of get_view3d_viewplane(), keep in sync */ -int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) +bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend, + const bool use_ortho_factor) { CameraParams params; BKE_camera_params_init(¶ms); BKE_camera_params_from_view3d(¶ms, v3d, rv3d); - if (clipsta) *clipsta = params.clipsta; - if (clipend) *clipend = params.clipend; + if (use_ortho_factor && params.is_ortho) { + const float fac = 2.0f / (params.clipend - params.clipsta); + params.clipsta *= fac; + params.clipend *= fac; + } + + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; return params.is_ortho; } /* also exposed in previewrender.c */ -int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy, - rctf *viewplane, float *clipsta, float *clipend) +bool ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy, + rctf *r_viewplane, float *r_clipsta, float *r_clipend) { CameraParams params; @@ -690,9 +697,9 @@ int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy, BKE_camera_params_from_view3d(¶ms, v3d, rv3d); BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); - if (viewplane) *viewplane = params.viewplane; - if (clipsta) *clipsta = params.clipsta; - if (clipend) *clipend = params.clipend; + if (r_viewplane) *r_viewplane = params.viewplane; + if (r_clipsta) *r_clipsta = params.clipsta; + if (r_clipend) *r_clipend = params.clipend; return params.is_ortho; } @@ -791,7 +798,7 @@ static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short #define QUATSET(a, b, c, d, e) { a[0] = b; a[1] = c; a[2] = d; a[3] = e; } (void)0 -int ED_view3d_lock(RegionView3D *rv3d) +bool ED_view3d_lock(RegionView3D *rv3d) { switch (rv3d->view) { case RV3D_VIEW_BOTTOM: @@ -818,10 +825,10 @@ int ED_view3d_lock(RegionView3D *rv3d) QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /* don't set windows active in here, is used by renderwin too */ @@ -863,7 +870,9 @@ void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d) copy_v3_v3(vec, give_cursor(scene, v3d)); translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); } - else translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]); + else { + translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]); + } } } @@ -1558,11 +1567,7 @@ static void UNUSED_FUNCTION(view3d_align_axis_to_vector)(View3D *v3d, RegionView float ED_view3d_pixel_size(RegionView3D *rv3d, const float co[3]) { - return (rv3d->persmat[3][3] + ( - rv3d->persmat[0][3] * co[0] + - rv3d->persmat[1][3] * co[1] + - rv3d->persmat[2][3] * co[2]) - ) * rv3d->pixsize * U.pixelsize; + return mul_project_m4_v3_zfac(rv3d->persmat, co) * rv3d->pixsize * U.pixelsize; } float ED_view3d_radius_to_persp_dist(const float angle, const float radius) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index c8874d13cac..64e49abd761 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -98,6 +98,8 @@ #include "transform.h" +#define MAX_INFO_LEN 256 + static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); static int doEdgeSlide(TransInfo *t, float perc); static int doVertSlide(TransInfo *t, float perc); @@ -183,7 +185,7 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) { if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { const float mval_f[2] = {(float)dx, (float)dy}; - ED_view3d_win_to_delta(t->ar, mval_f, r_vec); + ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); } else if (t->spacetype == SPACE_IMAGE) { float aspx, aspy; @@ -864,7 +866,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } } -int transformEvent(TransInfo *t, wmEvent *event) +int transformEvent(TransInfo *t, const wmEvent *event) { float mati[3][3] = MAT3_UNITY; char cmode = constraintModeToChar(t); @@ -1298,7 +1300,9 @@ int transformEvent(TransInfo *t, wmEvent *event) if (t->flag & T_AUTOIK) { transform_autoik_update(t, 1); } - else view_editmove(event->type); + else { + view_editmove(event->type); + } t->redraw = 1; break; case PADMINUS: @@ -1313,7 +1317,9 @@ int transformEvent(TransInfo *t, wmEvent *event) if (t->flag & T_AUTOIK) { transform_autoik_update(t, -1); } - else view_editmove(event->type); + else { + view_editmove(event->type); + } t->redraw = 1; break; case LEFTALTKEY: @@ -1854,7 +1860,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } /* note: caller needs to free 't' on a 0 return */ -int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int mode) +int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode) { int options = 0; PropertyRNA *prop; @@ -2654,11 +2660,12 @@ void initWarp(TransInfo *t) mid_v3_v3v3(t->center, min, max); - if (max[0] == min[0]) max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */ + if (max[0] == min[0]) + max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */ t->val = (max[0] - min[0]) / 2.0f; /* t->val is X dimension projected boundbox */ } -int handleEventWarp(TransInfo *t, wmEvent *event) +int handleEventWarp(TransInfo *t, const wmEvent *event) { int status = 0; @@ -2681,7 +2688,7 @@ int Warp(TransInfo *t, const int UNUSED(mval[2])) float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3]; const float *curs; int i; - char str[50]; + char str[MAX_INFO_LEN]; curs = give_cursor(t->scene, t->view); /* @@ -2716,13 +2723,13 @@ int Warp(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Warp: %s"), c); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %s"), c); circumfac = DEG2RADF(circumfac); } else { /* default header print */ - sprintf(str, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac)); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac)); } t->values[0] = circumfac; @@ -2799,7 +2806,7 @@ void initShear(TransInfo *t) t->flag |= T_NO_CONSTRAINT; } -int handleEventShear(TransInfo *t, wmEvent *event) +int handleEventShear(TransInfo *t, const wmEvent *event) { int status = 0; @@ -2840,7 +2847,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2])) float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3]; float value; int i; - char str[50]; + char str[MAX_INFO_LEN]; copy_m3_m4(persmat, t->viewmat); invert_m3_m3(persinv, persmat); @@ -2857,11 +2864,11 @@ int Shear(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Shear: %s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext); } else { /* default header print */ - sprintf(str, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext); } t->values[0] = value; @@ -2937,10 +2944,11 @@ void initResize(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerResize(TransInfo *t, float vec[3], char *str) { char tvec[NUM_STR_REP_LEN * 3]; - char *spos = str; + size_t ofs = 0; if (hasNumInput(&t->num)) { outputNumInput(&(t->num), tvec); } @@ -2949,37 +2957,36 @@ static void headerResize(TransInfo *t, float vec[3], char *str) BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); } - + if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - spos += sprintf(spos, IFACE_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s%s %s"), + &tvec[0], t->con.text, t->proptext); break; case 1: - spos += sprintf(spos, IFACE_("Scale: %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s%s %s"), + &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext); break; case 2: - spos += sprintf(spos, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], + &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } } else { if (t->flag & T_2D_EDIT) { - spos += sprintf(spos, IFACE_("Scale X: %s Y: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s%s %s"), + &tvec[0], &tvec[NUM_STR_REP_LEN], t->con.text, t->proptext); } else { - spos += sprintf(spos, IFACE_("Scale X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Scale X: %s Y: %s Z: %s%s %s"), + &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } } - + if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) { - spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } - - (void)spos; } /* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */ @@ -3114,7 +3121,7 @@ int Resize(TransInfo *t, const int mval[2]) float size[3], mat[3][3]; float ratio; int i; - char str[200]; + char str[MAX_INFO_LEN]; /* for manipulator, center handle, the scaling can't be done relative to center */ if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) { @@ -3219,7 +3226,7 @@ int SkinResize(TransInfo *t, const int UNUSED(mval[2])) float size[3], mat[3][3]; float ratio; int i; - char str[200]; + char str[MAX_INFO_LEN]; ratio = t->values[0]; size[0] = size[1] = size[2] = ratio; @@ -3313,7 +3320,7 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2])) float vec[3]; float ratio, radius; int i; - char str[64]; + char str[MAX_INFO_LEN]; TransData *td = t->data; ratio = t->values[0]; @@ -3335,11 +3342,11 @@ int ToSphere(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("To Sphere: %s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext); } else { /* default header print */ - sprintf(str, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext); } @@ -3528,7 +3535,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle); + protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, + td->ext->irotAngle); } else { float eulmat[3][3]; @@ -3575,12 +3583,15 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself /* euler or quaternion? */ if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); - mat3_to_quat(quat, fmat); // Actual transform - - mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); - /* this function works on end result */ - protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); + /* can be called for texture space translate for example, then opt out */ + if (td->ext->quat) { + mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mat3_to_quat(quat, fmat); // Actual transform + + mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); + /* this function works on end result */ + protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); + } } else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { /* calculate effect based on quats */ @@ -3595,7 +3606,8 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat); /* this function works on end result */ - protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle); + protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, + td->ext->irotAngle); } else { float obmat[3][3]; @@ -3654,14 +3666,15 @@ static void applyRotation(TransInfo *t, float angle, float axis[3]) int Rotation(TransInfo *t, const int UNUSED(mval[2])) { - char str[128], *spos = str; - + char str[MAX_INFO_LEN]; + size_t ofs = 0; + float final; final = t->values[0]; - + snapGrid(t, &final); - + if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, t->axis, NULL); } @@ -3669,9 +3682,9 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2])) /* reset axis if constraint is not set */ copy_v3_v3(t->axis, t->axis_orig); } - + applySnapping(t, &final); - + if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; @@ -3679,19 +3692,19 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - spos += sprintf(spos, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); /* Clamp between -180 and 180 */ final = angle_wrap_rad(DEG2RADF(final)); } else { - spos += sprintf(spos, IFACE_("Rot: %.2f%s %s"), RAD2DEGF(final), t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %.2f%s %s"), + RAD2DEGF(final), t->con.text, t->proptext); } if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) { - spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } - (void)spos; t->values[0] = final; @@ -3756,7 +3769,8 @@ static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float a int Trackball(TransInfo *t, const int UNUSED(mval[2])) { - char str[128], *spos = str; + char str[MAX_INFO_LEN]; + size_t ofs = 0; float axis1[3], axis2[3]; float mat[3][3], totmat[3][3], smat[3][3]; float phi[2]; @@ -3778,19 +3792,20 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - spos += sprintf(spos, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"), + &c[0], &c[NUM_STR_REP_LEN], t->proptext); phi[0] = DEG2RADF(phi[0]); phi[1] = DEG2RADF(phi[1]); } else { - spos += sprintf(spos, IFACE_("Trackball: %.2f %.2f %s"), RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %.2f %.2f %s"), + RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext); } if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) { - spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } - (void)spos; vec_rot_to_mat3(smat, axis1, phi[0]); vec_rot_to_mat3(totmat, axis2, phi[1]); @@ -3854,9 +3869,10 @@ void initTranslation(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerTranslation(TransInfo *t, float vec[3], char *str) { - char *spos = str; + size_t ofs = 0; char tvec[NUM_STR_REP_LEN * 3]; char distvec[NUM_STR_REP_LEN]; char autoik[NUM_STR_REP_LEN]; @@ -3877,29 +3893,30 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str) int i, do_split = t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1 : 0; for (i = 0; i < 3; i++) { - bUnit_AsString(&tvec[i * NUM_STR_REP_LEN], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length, + bUnit_AsString(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1); } } else { - sprintf(&tvec[0], "%.4f", dvec[0]); - sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", dvec[1]); - sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", dvec[2]); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]); } } if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) - bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0); + bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system, + B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0); else if (dist > 1e10f || dist < -1e10f) /* prevent string buffer overflow */ - sprintf(distvec, "%.4e", dist); + BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist); else - sprintf(distvec, "%.4f", dist); + BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist); if (t->flag & T_AUTOIK) { short chainlen = t->settings->autoik_chainlen; if (chainlen) - sprintf(autoik, IFACE_("AutoIK-Len: %d"), chainlen); + BLI_snprintf(autoik, NUM_STR_REP_LEN, IFACE_("AutoIK-Len: %d"), chainlen); else autoik[0] = '\0'; } @@ -3909,32 +3926,34 @@ static void headerTranslation(TransInfo *t, float vec[3], char *str) if (t->con.mode & CON_APPLY) { switch (t->num.idx_max) { case 0: - spos += sprintf(spos, "D: %s (%s)%s %s %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s (%s)%s %s %s", + &tvec[0], distvec, t->con.text, t->proptext, autoik); break; case 1: - spos += sprintf(spos, "D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], - distvec, t->con.text, t->proptext, &autoik[0]); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s (%s)%s %s %s", + &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext, autoik); break; case 2: - spos += sprintf(spos, "D: %s D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "D: %s D: %s D: %s (%s)%s %s %s", + &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, + t->con.text, t->proptext, autoik); } } else { if (t->flag & T_2D_EDIT) { - spos += sprintf(spos, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], - distvec, t->con.text, t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s (%s)%s %s", + &tvec[0], &tvec[NUM_STR_REP_LEN], distvec, t->con.text, t->proptext); } else { - spos += sprintf(spos, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", + &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, + t->proptext, autoik); } } - + if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) { - spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size); } - (void)spos; } static void applyTranslation(TransInfo *t, float vec[3]) @@ -4006,7 +4025,7 @@ static void applyTranslation(TransInfo *t, float vec[3]) /* uses t->vec to store actual translation in */ int Translation(TransInfo *t, const int UNUSED(mval[2])) { - char str[250]; + char str[MAX_INFO_LEN]; if (t->con.mode & CON_APPLY) { float pvec[3] = {0.0f, 0.0f, 0.0f}; @@ -4082,8 +4101,8 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) { float distance; int i; - char str[128]; - char *str_p; + char str[MAX_INFO_LEN]; + size_t ofs = 0; TransData *td = t->data; distance = -t->values[0]; @@ -4093,31 +4112,30 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) applyNumInput(&t->num, &distance); /* header print for NumInput */ - str_p = str; - str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Shrink/Fatten:")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c); - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", c); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c); } else { /* default header print */ - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %.4f", distance); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %.4f", distance); } if (t->proptext[0]) { - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", t->proptext); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", t->proptext); } - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), ", ("); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, ", ("); { wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); if (kmi) { - str_p += WM_keymap_item_to_string(kmi, str_p, sizeof(str) - (str_p - str)); + ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs); } } - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_(" or Alt) Even Thickness %s"), - (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF")); + BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Even Thickness %s"), + (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF")); /* done with header string */ @@ -4173,7 +4191,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; int i; - char str[50]; + char str[MAX_INFO_LEN]; float final; @@ -4188,7 +4206,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Tilt: %s° %s"), &c[0], t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext); final = DEG2RADF(final); @@ -4196,7 +4214,7 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = final; } else { - sprintf(str, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -4247,7 +4265,7 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float ratio; int i; - char str[50]; + char str[MAX_INFO_LEN]; ratio = t->values[0]; @@ -4260,10 +4278,10 @@ int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Shrink/Fatten: %s"), c); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c); } else { - sprintf(str, IFACE_("Shrink/Fatten: %3f"), ratio); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %3f"), ratio); } for (i = 0; i < t->total; i++, td++) { @@ -4315,7 +4333,7 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) TransData *td; float ratio; int i, initial_feather = FALSE; - char str[50]; + char str[MAX_INFO_LEN]; ratio = t->values[0]; @@ -4328,10 +4346,10 @@ int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Feather Shrink/Fatten: %s"), c); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c); } else { - sprintf(str, IFACE_("Feather Shrink/Fatten: %3f"), ratio); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %3f"), ratio); } /* detect if no points have feather yet */ @@ -4401,7 +4419,7 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2])) float vec[3], axis[3]; float distance; int i; - char str[128]; + char str[MAX_INFO_LEN]; TransData *td = t->data; distance = t->values[0]; @@ -4416,11 +4434,11 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); } else { /* default header print */ - sprintf(str, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext); } t->values[0] = distance; @@ -4496,7 +4514,7 @@ void initBevel(TransInfo *t) } } -int handleEventBevel(TransInfo *t, wmEvent *event) +int handleEventBevel(TransInfo *t, const wmEvent *event) { if (event->val == KM_PRESS) { if (!G.editBMesh) return 0; @@ -4533,7 +4551,7 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2])) { float distance, d; int i; - char str[128]; + char str[MAX_INFO_LEN]; const char *mode; TransData *td = t->data; @@ -4552,11 +4570,11 @@ int Bevel(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode); } else { /* default header print */ - sprintf(str, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode); } if (distance < 0) distance = -distance; @@ -4602,7 +4620,7 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float weight; int i; - char str[50]; + char str[MAX_INFO_LEN]; weight = t->values[0]; @@ -4620,16 +4638,16 @@ int BevelWeight(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); if (weight >= 0.0f) - sprintf(str, IFACE_("Bevel Weight: +%s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext); else - sprintf(str, IFACE_("Bevel Weight: %s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %s %s"), c, t->proptext); } else { /* default header print */ if (weight >= 0.0f) - sprintf(str, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext); else - sprintf(str, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -4675,7 +4693,7 @@ int Crease(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float crease; int i; - char str[50]; + char str[MAX_INFO_LEN]; crease = t->values[0]; @@ -4693,16 +4711,16 @@ int Crease(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); if (crease >= 0.0f) - sprintf(str, IFACE_("Crease: +%s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext); else - sprintf(str, IFACE_("Crease: %s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %s %s"), c, t->proptext); } else { /* default header print */ if (crease >= 0.0f) - sprintf(str, IFACE_("Crease: +%.3f %s"), crease, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%.3f %s"), crease, t->proptext); else - sprintf(str, IFACE_("Crease: %.3f %s"), crease, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: %.3f %s"), crease, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -4746,6 +4764,7 @@ void initBoneSize(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerBoneSize(TransInfo *t, float vec[3], char *str) { char tvec[NUM_STR_REP_LEN * 3]; @@ -4753,22 +4772,22 @@ static void headerBoneSize(TransInfo *t, float vec[3], char *str) outputNumInput(&(t->num), tvec); } else { - sprintf(&tvec[0], "%.4f", vec[0]); - sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", vec[1]); - sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", vec[2]); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]); + BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]); } /* hmm... perhaps the y-axis values don't need to be shown? */ if (t->con.mode & CON_APPLY) { if (t->num.idx_max == 0) - sprintf(str, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext); else - sprintf(str, IFACE_("ScaleB: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB: %s : %s : %s%s %s"), + &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } else { - sprintf(str, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN], - &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleB X: %s Y: %s Z: %s%s %s"), + &tvec[0], &tvec[NUM_STR_REP_LEN], &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext); } } @@ -4798,7 +4817,7 @@ int BoneSize(TransInfo *t, const int mval[2]) float size[3], mat[3][3]; float ratio; int i; - char str[60]; + char str[MAX_INFO_LEN]; // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT /* for manipulator, center handle, the scaling can't be done relative to center */ @@ -4871,7 +4890,7 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) TransData *td = t->data; float ratio; int i; - char str[50]; + char str[MAX_INFO_LEN]; ratio = t->values[0]; @@ -4884,10 +4903,10 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) char c[NUM_STR_REP_LEN]; outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Envelope: %s"), c); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c); } else { - sprintf(str, IFACE_("Envelope: %3f"), ratio); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %3f"), ratio); } for (i = 0; i < t->total; i++, td++) { @@ -5604,7 +5623,8 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f); } else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->down)) { - f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f); + f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, + (uintptr_t)e_sel->l->radial_next->f); } } @@ -5613,7 +5633,8 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f); } else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->up)) { - f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f); + f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, + (uintptr_t)e_sel->l->radial_next->f); } } @@ -5746,7 +5767,7 @@ void initEdgeSlide(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } -int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event) +int handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event) { if (t->mode == TFM_EDGE_SLIDE) { EdgeSlideData *sld = t->customData; @@ -5929,12 +5950,15 @@ static int doEdgeSlide(TransInfo *t, float perc) int EdgeSlide(TransInfo *t, const int UNUSED(mval[2])) { - char str[128]; + char str[MAX_INFO_LEN]; float final; EdgeSlideData *sld = t->customData; bool flipped = sld->flipped_vtx; bool is_proportional = sld->is_proportional; + const char *on_str = IFACE_("ON"); + const char *off_str = IFACE_("OFF"); + final = t->values[0]; snapGrid(t, &final); @@ -5949,12 +5973,12 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"), - &c[0], !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF")); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"), + &c[0], !is_proportional ? on_str : off_str, flipped ? on_str : off_str); } else { - BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"), - final, !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF")); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"), + final, !is_proportional ? on_str : off_str, flipped ? on_str : off_str); } CLAMP(final, -1.0f, 1.0f); @@ -5962,10 +5986,11 @@ int EdgeSlide(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = final; /*do stuff here*/ - if (t->customData) + if (t->customData) { doEdgeSlide(t, final); + } else { - strcpy(str, IFACE_("Invalid Edge Selection")); + BLI_strncpy(str, IFACE_("Invalid Edge Selection"), MAX_INFO_LEN); t->state = TRANS_CANCEL; } @@ -6249,7 +6274,7 @@ void initVertSlide(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } -int handleEventVertSlide(struct TransInfo *t, struct wmEvent *event) +int handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event) { if (t->mode == TFM_VERT_SLIDE) { VertSlideData *sld = t->customData; @@ -6434,8 +6459,8 @@ static int doVertSlide(TransInfo *t, float perc) int VertSlide(TransInfo *t, const int UNUSED(mval[2])) { - char str[128]; - char *str_p; + char str[MAX_INFO_LEN]; + size_t ofs = 0; float final; VertSlideData *sld = t->customData; const bool flipped = sld->flipped_vtx; @@ -6443,6 +6468,9 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2])) const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num)); + const char *on_str = IFACE_("ON"); + const char *off_str = IFACE_("OFF"); + final = t->values[0]; snapGrid(t, &final); @@ -6453,25 +6481,21 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2])) } /* header string */ - str_p = str; - str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Vert Slide: ")); + ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; applyNumInput(&t->num, &final); outputNumInput(&(t->num), c); - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%s", &c[0]); + ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs); } else { - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%.4f ", final); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final); } - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(E)ven: %s, "), - !is_proportional ? IFACE_("ON") : IFACE_("OFF")); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), !is_proportional ? on_str : off_str); if (!is_proportional) { - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(F)lipped: %s, "), - flipped ? IFACE_("ON") : IFACE_("OFF")); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), flipped ? on_str : off_str); } - str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("Alt or (C)lamp: %s"), - is_clamp ? IFACE_("ON") : IFACE_("OFF")); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), is_clamp ? on_str : off_str); /* done with header string */ /*do stuff here*/ @@ -6479,7 +6503,7 @@ int VertSlide(TransInfo *t, const int UNUSED(mval[2])) doVertSlide(t, final); } else { - strcpy(str, IFACE_("Invalid Vert Selection")); + BLI_strncpy(str, IFACE_("Invalid Vert Selection"), MAX_INFO_LEN); t->state = TRANS_CANCEL; } @@ -6515,7 +6539,7 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; int i; - char str[50]; + char str[MAX_INFO_LEN]; float final; @@ -6530,12 +6554,12 @@ int BoneRoll(TransInfo *t, const int UNUSED(mval[2])) outputNumInput(&(t->num), c); - sprintf(str, IFACE_("Roll: %s"), &c[0]); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]); final = DEG2RADF(final); } else { - sprintf(str, IFACE_("Roll: %.2f"), RAD2DEGF(final)); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %.2f"), RAD2DEGF(final)); } /* set roll values */ @@ -6577,7 +6601,7 @@ int BakeTime(TransInfo *t, const int mval[2]) TransData *td = t->data; float time; int i; - char str[50]; + char str[MAX_INFO_LEN]; float fac = 0.1f; @@ -6601,16 +6625,16 @@ int BakeTime(TransInfo *t, const int mval[2]) outputNumInput(&(t->num), c); if (time >= 0.0f) - sprintf(str, IFACE_("Time: +%s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext); else - sprintf(str, IFACE_("Time: %s %s"), c, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %s %s"), c, t->proptext); } else { /* default header print */ if (time >= 0.0f) - sprintf(str, IFACE_("Time: +%.3f %s"), time, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%.3f %s"), time, t->proptext); else - sprintf(str, IFACE_("Time: %.3f %s"), time, t->proptext); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: %.3f %s"), time, t->proptext); } for (i = 0; i < t->total; i++, td++) { @@ -6652,7 +6676,7 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2])) TransData *td; float size[3], mat[3][3]; int i; - char str[200]; + char str[MAX_INFO_LEN]; /* * OPTIMIZATION: @@ -6670,7 +6694,7 @@ int Mirror(TransInfo *t, const int UNUSED(mval[2])) t->con.applySize(t, NULL, mat); } - sprintf(str, IFACE_("Mirror%s"), t->con.text); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Mirror%s"), t->con.text); for (i = 0, td = t->data; i < t->total; i++, td++) { if (td->flag & TD_NOACTION) @@ -6787,29 +6811,29 @@ void initSeqSlide(TransInfo *t) t->num.increment = t->snap[1]; } -static void headerSeqSlide(TransInfo *t, float val[2], char *str, size_t str_len) +/* We assume str is MAX_INFO_LEN long. */ +static void headerSeqSlide(TransInfo *t, float val[2], char *str) { char tvec[NUM_STR_REP_LEN * 3]; - char *str_p; + size_t ofs = 0; if (hasNumInput(&t->num)) { outputNumInput(&(t->num), tvec); } else { - sprintf(&tvec[0], "%.0f, %.0f", val[0], val[1]); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); } - str_p = str; - str_p += BLI_snprintf(str, str_len, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); { wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); if (kmi) { - str_p += WM_keymap_item_to_string(kmi, str_p, str_len - (str_p - str)); + ofs += WM_keymap_item_to_string(kmi, str + ofs, MAX_INFO_LEN - ofs); } } - str_p += BLI_snprintf(str_p, str_len - (str_p - str), IFACE_(" or Alt) Expand to fit %s"), - (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF")); + ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_(" or Alt) Expand to fit %s"), + (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF")); } static void applySeqSlide(TransInfo *t, float val[2]) @@ -6837,7 +6861,7 @@ static void applySeqSlide(TransInfo *t, float val[2]) int SeqSlide(TransInfo *t, const int UNUSED(mval[2])) { - char str[200]; + char str[MAX_INFO_LEN]; if (t->con.mode & CON_APPLY) { float pvec[3] = {0.0f, 0.0f, 0.0f}; @@ -6853,7 +6877,7 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = floor(t->values[0] + 0.5f); t->values[1] = floor(t->values[1] + 0.5f); - headerSeqSlide(t, t->values, str, sizeof(str)); + headerSeqSlide(t, t->values, str); applySeqSlide(t, t->values); recalcData(t); @@ -6953,7 +6977,11 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, TransData2D *td2d, #if 0 /* 'do_time' disabled for now */ const Scene *scene = t->scene; - const short do_time = 0; //getAnimEdit_DrawTime(t); // NOTE: this works, but may be confusing behavior given the option's label, hence disabled +#if 0 /* NOTE: this works, but may be confusing behavior given the option's label, hence disabled */ + const short do_time = getAnimEdit_DrawTime(t); +#else + const short do_time = 0; +#endif const double secf = FPS; #endif double val; @@ -7041,6 +7069,7 @@ void initTimeTranslate(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerTimeTranslate(TransInfo *t, char *str) { char tvec[NUM_STR_REP_LEN * 3]; @@ -7069,12 +7098,12 @@ static void headerTimeTranslate(TransInfo *t, char *str) } if (autosnap == SACTSNAP_FRAME) - sprintf(&tvec[0], "%d.00 (%.4f)", (int)val, val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%d.00 (%.4f)", (int)val, val); else - sprintf(&tvec[0], "%.4f", val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); } - sprintf(str, IFACE_("DeltaX: %s"), &tvec[0]); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("DeltaX: %s"), &tvec[0]); } static void applyTimeTranslate(TransInfo *t, float UNUSED(sval)) @@ -7138,7 +7167,7 @@ int TimeTranslate(TransInfo *t, const int mval[2]) { View2D *v2d = (View2D *)t->view; float cval[2], sval[2]; - char str[200]; + char str[MAX_INFO_LEN]; /* calculate translation amount from mouse movement - in 'time-grid space' */ UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); @@ -7196,6 +7225,7 @@ void initTimeSlide(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerTimeSlide(TransInfo *t, float sval, char *str) { char tvec[NUM_STR_REP_LEN * 3]; @@ -7212,10 +7242,10 @@ static void headerTimeSlide(TransInfo *t, float sval, char *str) val = 2.0f * (cval - sval) / (maxx - minx); CLAMP(val, -1.0f, 1.0f); - sprintf(&tvec[0], "%.4f", val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val); } - sprintf(str, IFACE_("TimeSlide: %s"), &tvec[0]); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("TimeSlide: %s"), &tvec[0]); } static void applyTimeSlide(TransInfo *t, float sval) @@ -7271,7 +7301,7 @@ int TimeSlide(TransInfo *t, const int mval[2]) float cval[2], sval[2]; float minx = *((float *)(t->customData)); float maxx = *((float *)(t->customData) + 1); - char str[200]; + char str[MAX_INFO_LEN]; /* calculate mouse co-ordinates */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); @@ -7338,6 +7368,7 @@ void initTimeScale(TransInfo *t) t->num.increment = t->snap[1]; } +/* We assume str is MAX_INFO_LEN long. */ static void headerTimeScale(TransInfo *t, char *str) { char tvec[NUM_STR_REP_LEN * 3]; @@ -7345,9 +7376,9 @@ static void headerTimeScale(TransInfo *t, char *str) if (hasNumInput(&t->num)) outputNumInput(&(t->num), tvec); else - sprintf(&tvec[0], "%.4f", t->values[0]); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]); - sprintf(str, IFACE_("ScaleX: %s"), &tvec[0]); + BLI_snprintf(str, MAX_INFO_LEN, IFACE_("ScaleX: %s"), &tvec[0]); } static void applyTimeScale(TransInfo *t) @@ -7392,7 +7423,7 @@ static void applyTimeScale(TransInfo *t) int TimeScale(TransInfo *t, const int UNUSED(mval[2])) { - char str[200]; + char str[MAX_INFO_LEN]; /* handle numeric-input stuff */ t->vec[0] = t->values[0]; @@ -7423,3 +7454,5 @@ bool checkUseLocalCenter_GraphEdit(TransInfo *t) { return ((t->around == V3D_LOCAL) && !ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)); } + +#undef MAX_INFO_LEN diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index dbf56f658ac..a551ef5008e 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -288,7 +288,7 @@ typedef struct TransInfo { float fac; /* factor for distance based transform */ int (*transform)(struct TransInfo *, const int *); /* transform function pointer */ - int (*handleEvent)(struct TransInfo *, struct wmEvent *); + int (*handleEvent)(struct TransInfo *, const struct wmEvent *); /* event handler function pointer RETURN 1 if redraw is needed */ int total; /* total number of transformed data */ TransData *data; /* transformed data (array) */ @@ -354,6 +354,7 @@ typedef struct TransInfo { struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ int mval[2]; /* current mouse position */ + float zfac; /* use for 3d view */ struct Object *obedit; void *draw_handle_apply; void *draw_handle_view; @@ -474,9 +475,9 @@ typedef struct TransInfo { #define POINT_INIT 4 #define MULTI_POINTS 8 -int initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, struct wmEvent *event, int mode); +int initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); -int transformEvent(TransInfo *t, struct wmEvent *event); +int transformEvent(TransInfo *t, const struct wmEvent *event); void transformApply(struct bContext *C, TransInfo *t); int transformEnd(struct bContext *C, TransInfo *t); @@ -491,11 +492,11 @@ void applyAspectRatio(TransInfo *t, float *vec); void removeAspectRatio(TransInfo *t, float *vec); void initWarp(TransInfo *t); -int handleEventWarp(TransInfo *t, struct wmEvent *event); +int handleEventWarp(TransInfo *t, const struct wmEvent *event); int Warp(TransInfo *t, const int mval[2]); void initShear(TransInfo *t); -int handleEventShear(TransInfo *t, struct wmEvent *event); +int handleEventShear(TransInfo *t, const struct wmEvent *event); int Shear(TransInfo *t, const int mval[2]); void initResize(TransInfo *t); @@ -532,7 +533,7 @@ void initPushPull(TransInfo *t); int PushPull(TransInfo *t, const int mval[2]); void initBevel(TransInfo *t); -int handleEventBevel(TransInfo *t, struct wmEvent *event); +int handleEventBevel(TransInfo *t, const struct wmEvent *event); int Bevel(TransInfo *t, const int mval[2]); void initBevelWeight(TransInfo *t); @@ -551,11 +552,11 @@ void initBoneRoll(TransInfo *t); int BoneRoll(TransInfo *t, const int mval[2]); void initEdgeSlide(TransInfo *t); -int handleEventEdgeSlide(TransInfo *t, struct wmEvent *event); +int handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event); int EdgeSlide(TransInfo *t, const int mval[2]); void initVertSlide(TransInfo *t); -int handleEventVertSlide(TransInfo *t, struct wmEvent *event); +int handleEventVertSlide(TransInfo *t, const struct wmEvent *event); int VertSlide(TransInfo *t, const int mval[2]); void initTimeTranslate(TransInfo *t); @@ -658,7 +659,7 @@ void initSnapping(struct TransInfo *t, struct wmOperator *op); void applyProject(TransInfo *t); void applySnapping(TransInfo *t, float *vec); void resetSnapping(TransInfo *t); -int handleSnapping(TransInfo *t, struct wmEvent *event); +int handleSnapping(TransInfo *t, const struct wmEvent *event); void drawSnapping(const struct bContext *C, TransInfo *t); int usingSnappingNormal(TransInfo *t); int validSnappingNormal(TransInfo *t); @@ -687,7 +688,7 @@ typedef enum { void initMouseInput(TransInfo *t, MouseInput *mi, const int center[2], const int mval[2]); void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode); -int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, struct wmEvent *event); +int handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event); void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]); void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]); @@ -695,7 +696,7 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val /*********************** Generics ********************************/ -int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, struct wmEvent *event); +int initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, const struct wmEvent *event); void postTrans (struct bContext *C, TransInfo *t); void resetTransRestrictions(TransInfo *t); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index c4d61472f18..f3026205ea2 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -29,19 +29,17 @@ * \ingroup edtransform */ - #include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h> #ifndef WIN32 -#include <unistd.h> +# include <unistd.h> #else -#include <io.h> +# include <io.h> #endif - #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -53,13 +51,13 @@ #include "BKE_context.h" -#include "ED_image.h" -#include "ED_view3d.h" - #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_string.h" +#include "ED_image.h" +#include "ED_view3d.h" + #include "BLF_translation.h" #include "UI_resources.h" @@ -867,11 +865,11 @@ static void setNearestAxis2d(TransInfo *t) /* no correction needed... just use whichever one is lower */ if (abs(t->mval[0] - t->con.imval[0]) < abs(t->mval[1] - t->con.imval[1]) ) { t->con.mode |= CON_AXIS1; - BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along Y axis")); + BLI_strncpy(t->con.text, IFACE_(" along Y axis"), sizeof(t->con.text)); } else { t->con.mode |= CON_AXIS0; - BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along X axis")); + BLI_strncpy(t->con.text, IFACE_(" along X axis"), sizeof(t->con.text)); } } @@ -892,9 +890,9 @@ static void setNearestAxis3d(TransInfo *t) * and to overflow the short integers. * The formula used is a bit stupid, just a simplification of the subtraction * of two 2D points 30 pixels apart (that's the last factor in the formula) after - * projecting them with window_to_3d_delta and then get the length of that vector. + * projecting them with ED_view3d_win_to_delta and then get the length of that vector. */ - zfac = t->persmat[0][3] * t->center[0] + t->persmat[1][3] * t->center[1] + t->persmat[2][3] * t->center[2] + t->persmat[3][3]; + zfac = mul_project_m4_v3_zfac(t->persmat, t->center); zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 57816e7546c..b8a39cae381 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -223,7 +223,9 @@ static void set_prop_dist(TransInfo *t, short with_dist) tob->rdist = dist; } } - else break; // by definition transdata has selected items in beginning + else { + break; /* by definition transdata has selected items in beginning */ + } } if (with_dist) { tob->dist = tob->rdist; @@ -1291,7 +1293,7 @@ static void calc_distanceCurveVerts(TransData *head, TransData *tail) } } else { - td->dist = MAXFLOAT; + td->dist = FLT_MAX; td->flag |= TD_NOTCONNECTED; } } @@ -2048,7 +2050,9 @@ static void createTransEditVerts(TransInfo *t) if (propmode & T_PROP_CONNECTED) dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears"); } - else t->total = countsel; + else { + t->total = countsel; + } tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)"); if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { @@ -2127,7 +2131,7 @@ static void createTransEditVerts(TransInfo *t) } else { tob->flag |= TD_NOTCONNECTED; - tob->dist = MAXFLOAT; + tob->dist = FLT_MAX; } } @@ -2363,7 +2367,7 @@ static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, f td->dist = 0.0; } else { - td->dist = MAXFLOAT; + td->dist = FLT_MAX; } unit_m3(td->mtx); unit_m3(td->smtx); @@ -3500,7 +3504,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, AnimData *adt, B td->dist = 0.0f; } else - td->dist = MAXFLOAT; + td->dist = FLT_MAX; if (ishandle) td->flag |= TD_NOTIMESNAP; @@ -3584,7 +3588,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) if (ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)) { /* for 'normal' pivots - just include anything that is selected. * this works a bit differently in translation modes */ - if (sel2) count++; + if (sel2) { + count++; + } else { if (sel1) count++; if (sel3) count++; @@ -6594,7 +6600,7 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } - else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) { + else if (ob && (ob->mode & (OB_MODE_ALL_PAINT))) { /* sculpt mode and project paint have own undo stack * transform ops redo clears sculpt/project undo stack. * diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index c2a331f5249..2a3b0bc8726 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1012,7 +1012,7 @@ void resetTransRestrictions(TransInfo *t) } /* the *op can be NULL */ -int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event) +int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { Scene *sce = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); @@ -1669,7 +1669,7 @@ void calculateCenter(TransInfo *t) projectIntView(t, axis, t->center2d); - /* rotate only needs correct 2d center, grab needs initgrabz() value */ + /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */ if (t->mode == TFM_TRANSLATION) { copy_v3_v3(t->center, axis); copy_v3_v3(t->con.center, t->center); @@ -1679,18 +1679,16 @@ void calculateCenter(TransInfo *t) } if (t->spacetype == SPACE_VIEW3D) { - /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */ + /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */ + float vec[3]; if (t->flag & (T_EDIT | T_POSE)) { Object *ob = t->obedit ? t->obedit : t->poseobj; - float vec[3]; - - copy_v3_v3(vec, t->center); - mul_m4_v3(ob->obmat, vec); - initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]); + mul_v3_m4v3(vec, ob->obmat, t->center); } else { - initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]); + copy_v3_v3(vec, t->center); } + t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, vec, NULL); } } diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 4e9a54692a5..4943a3a2fe7 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -393,7 +393,7 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp } } -int handleMouseInput(TransInfo *t, MouseInput *mi, wmEvent *event) +int handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event) { int redraw = TREDRAW_NOTHING; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 54fb567b8a2..bea1f9da057 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -856,7 +856,7 @@ static void axis_sort_v3(const float axis_values[3], int r_axis_order[3]) } else { if (v[1] < v[2]) { SWAP_AXIS(0, 1); } - else { SWAP_AXIS(0, 2); } + else { SWAP_AXIS(0, 2); } } if (v[2] < v[1]) { SWAP_AXIS(1, 2); } @@ -1293,7 +1293,9 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving, dz = 1.0; } - else dz = 1.0f - 4.0f * cusize; + else { + dz = 1.0f - 4.0f * cusize; + } if (moving) { float matt[4][4]; @@ -1739,8 +1741,12 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl dep = buffer[4 * a + 1]; val = buffer[4 * a + 3]; - if (val == MAN_TRANS_C) return MAN_TRANS_C; - else if (val == MAN_SCALE_C) return MAN_SCALE_C; + if (val == MAN_TRANS_C) { + return MAN_TRANS_C; + } + else if (val == MAN_SCALE_C) { + return MAN_SCALE_C; + } else { if (val & MAN_ROT_C) { if (minvalrot == 0 || dep < mindeprot) { @@ -1767,7 +1773,7 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl /* return 0; nothing happened */ -int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op) +int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -1855,8 +1861,15 @@ int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op) //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, FALSE); } else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */ - WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr); - //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, op->ptr, NULL, FALSE); + /* Do not pass op->ptr!!! trackball has no "constraint" properties! + * See [#34621], it's a miracle it did not cause more problems!!! */ + /* However, we need to copy the "release_confirm" property... */ + PointerRNA props_ptr; + WM_operator_properties_create(&props_ptr, "TRANSFORM_OT_trackball"); + RNA_boolean_set(&props_ptr, "release_confirm", RNA_boolean_get(op->ptr, "release_confirm")); + + WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, &props_ptr); + //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, NULL, NULL, FALSE); } else if (drawflags & MAN_ROT_C) { switch (drawflags) { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 0392c0f47a2..60b0c655691 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -24,16 +24,11 @@ * \ingroup edtransform */ - #include "MEM_guardedalloc.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - #include "BLI_math.h" #include "BLI_utildefines.h" @@ -44,6 +39,10 @@ #include "BKE_armature.h" #include "BKE_report.h" +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + #include "WM_api.h" #include "WM_types.h" @@ -166,7 +165,7 @@ static int select_orientation_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event)) +static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -213,7 +212,7 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int delete_orientation_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return delete_orientation_exec(C, op); } @@ -269,7 +268,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int create_orientation_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int create_orientation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return create_orientation_exec(C, op); } @@ -301,7 +300,7 @@ static void transformops_exit(bContext *C, wmOperator *op) G.moving = 0; } -static int transformops_data(bContext *C, wmOperator *op, wmEvent *event) +static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event) { int retval = 1; if (op->customdata == NULL) { @@ -335,7 +334,7 @@ static int transformops_data(bContext *C, wmOperator *op, wmEvent *event) return retval; /* return 0 on error */ } -static int transform_modal(bContext *C, wmOperator *op, wmEvent *event) +static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event) { int exit_code; @@ -402,7 +401,7 @@ static int transform_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int transform_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event) { if (!transformops_data(C, op, event)) { G.moving = 0; @@ -431,7 +430,6 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) /* Make this not hidden when there's a nice axis selection widget */ RNA_def_property_flag(prop, PROP_HIDDEN); RNA_def_property_ui_text(prop, "Axis", "The axis around which the transformation occurs"); - } if (flags & P_CONSTRAINT) { @@ -439,8 +437,6 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_property(ot->srna, "constraint_orientation", PROP_ENUM, PROP_NONE); RNA_def_property_ui_text(prop, "Orientation", "Transformation orientation"); RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf); - - } if (flags & P_MIRROR) { @@ -558,6 +554,8 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Trackball"; ot->description = "Trackball style rotation of selected items"; @@ -571,7 +569,9 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; - RNA_def_float_vector(ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); + /* Maybe we could use float_vector_xyz here too? */ + prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); + RNA_def_property_subtype(prop, PROP_ANGLE); Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP); } @@ -841,7 +841,7 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot) ot->cancel = transform_cancel; ot->poll = ED_operator_sequencer_active; - RNA_def_float_vector(ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); + RNA_def_float_vector_xyz(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); Transform_Properties(ot, P_SNAP); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index e507d062b0e..4fe36a15802 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -89,7 +89,7 @@ static TransformOrientation *findOrientationName(ListBase *lb, const char *name) return NULL; } -static int uniqueOrientationNameCheck(void *arg, const char *name) +static bool uniqueOrientationNameCheck(void *arg, const char *name) { return findOrientationName((ListBase *)arg, name) != NULL; } @@ -409,14 +409,16 @@ const char *BIF_menustringTransformOrientation(const bContext *C, const char *ti int i = V3D_MANIP_CUSTOM; char *str_menu, *p; const int elem_size = MAX_NAME + 4; + size_t str_menu_size; title = IFACE_(title); - str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + elem_size * BIF_countTransformOrientation(C), "UserTransSpace from matrix"); + str_menu_size = strlen(menu) + strlen(title) + 1 + (elem_size * BIF_countTransformOrientation(C)); + str_menu = MEM_callocN(str_menu_size, "UserTransSpace from matrix"); + p = str_menu; - - p += sprintf(str_menu, "%s", title); - p += sprintf(p, "%s", menu); + p += BLI_strncpy_rlen(p, title, str_menu_size); + p += BLI_strncpy_rlen(p, menu, str_menu_size - (p - str_menu)); for (ts = transform_spaces->first; ts; ts = ts->next) { p += sprintf(p, "|%s %%x%d", ts->name, i++); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 2efd35327c7..c92cd77449e 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -47,8 +47,6 @@ #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" -#include "RNA_access.h" - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -62,6 +60,10 @@ #include "BKE_tessmesh.h" #include "BKE_mesh.h" +#include "RNA_access.h" + +#include "WM_types.h" + #include "ED_armature.h" #include "ED_image.h" #include "ED_mesh.h" @@ -69,8 +71,6 @@ #include "ED_uvedit.h" #include "ED_view3d.h" -#include "WM_types.h" - #include "UI_resources.h" #include "UI_view2d.h" @@ -103,7 +103,7 @@ static float ResizeBetween(TransInfo *t, float p1[3], float p2[3]); /****************** IMPLEMENTATIONS *********************/ -static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode); +static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode); static NodeBorder snapNodeBorder(int snap_node_mode); #if 0 @@ -260,7 +260,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) } } -int handleSnapping(TransInfo *t, wmEvent *event) +int handleSnapping(TransInfo *t, const wmEvent *event) { int status = 0; @@ -807,7 +807,7 @@ static float ResizeBetween(TransInfo *t, float p1[3], float p2[3]) /********************** CALC **************************/ -static void UNUSED_FUNCTION(CalcSnapGrid) (TransInfo * t, float *UNUSED(vec)) +static void UNUSED_FUNCTION(CalcSnapGrid) (TransInfo *t, float *UNUSED(vec)) { snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS); } @@ -818,7 +818,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float loc[3]; float no[3]; float mval[2]; - int found = 0; + bool found = false; int dist = SNAP_MIN_DISTANCE; // Use a user defined value here mval[0] = t->mval[0]; @@ -901,7 +901,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) no[0] = 0.0; no[1] = 0.0; no[2] = 1.0; - found = 1; + found = true; } BLI_freelistN(&depth_peels); @@ -910,7 +910,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect); } - if (found == 1) { + if (found == true) { float tangent[3]; sub_v3_v3v3(tangent, loc, t->tsnap.snapPoint); @@ -1144,13 +1144,13 @@ static void TargetSnapClosest(TransInfo *t) } } -static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2], - float r_loc[3], float r_no[3], int *r_dist, float *r_depth) +static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2], + float r_loc[3], float r_no[3], int *r_dist, float *r_depth) { float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; int result; - int retval = 0; + bool retval = false; copy_v3_v3(ray_end, ray_normal_local); mul_v3_fl(ray_end, 2000); @@ -1206,7 +1206,7 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh float n1[3], n2[3]; *r_depth = new_depth; - retval = 1; + retval = true; sub_v3_v3v3(edge_loc, v1co, v2co); sub_v3_v3v3(vec, intersect, v2co); @@ -1231,11 +1231,11 @@ static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], sh return retval; } -static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2], - float r_loc[3], float r_no[3], int *r_dist, float *r_depth) +static bool snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval[2], + float r_loc[3], float r_no[3], int *r_dist, float *r_depth) { - int retval = 0; + bool retval = false; float dvec[3]; sub_v3_v3v3(dvec, vco, ray_start_local); @@ -1262,7 +1262,7 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4] if (new_dist <= *r_dist && new_depth < *r_depth) { *r_depth = new_depth; - retval = 1; + retval = true; copy_v3_v3(r_loc, location); @@ -1279,13 +1279,13 @@ static int snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4] return retval; } -static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float *UNUSED(r_no), int *r_dist, float *r_depth) +static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float *UNUSED(r_no), int *r_dist, float *r_depth) { float imat[4][4]; float ray_start_local[3], ray_normal_local[3]; - int retval = 0; + bool retval = false; invert_m4_m4(imat, obmat); @@ -1342,11 +1342,11 @@ static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm return retval; } -static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float r_no[3], int *r_dist, float *r_depth) +static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float r_no[3], int *r_dist, float *r_depth) { - int retval = 0; + bool retval = false; int totvert = dm->getNumVerts(dm); int totface = dm->getNumTessFaces(dm); @@ -1514,12 +1514,12 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh return retval; } -static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float r_no[3], int *r_dist, float *r_depth) +static bool snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float r_no[3], int *r_dist, float *r_depth) { ToolSettings *ts = scene->toolsettings; - int retval = 0; + bool retval = false; if (ob->type == OB_MESH) { BMEditMesh *em; @@ -1546,12 +1546,12 @@ static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, flo return retval; } -static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, const float mval[2], - int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) +static bool snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, const float mval[2], + int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) { Base *base; - float depth = FLT_MAX; - int retval = 0; + float depth = (FLT_MAX / 2.0f); /* use half of flt-max so we can scale up without an exception */ + bool retval = false; float ray_start[3], ray_normal[3]; ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal); @@ -1602,12 +1602,12 @@ static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, c return retval; } -int snapObjectsTransform(TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) +bool snapObjectsTransform(TransInfo *t, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) { return snapObjects(t->scene, t->view, t->ar, t->obedit, mval, r_dist, r_loc, r_no, mode); } -int snapObjectsContext(bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) +bool snapObjectsContext(bContext *C, const float mval[2], int *r_dist, float r_loc[3], float r_no[3], SnapMode mode) { ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -1667,11 +1667,11 @@ static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float n peel->flag = 0; } -static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]), - ListBase *depth_peels) +static bool peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float UNUSED(mval[2]), + ListBase *depth_peels) { - int retval = 0; + bool retval = false; int totvert = dm->getNumVerts(dm); int totface = dm->getNumTessFaces(dm); @@ -1776,10 +1776,11 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[4][4], return retval; } -static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase *depth_peels, const float mval[2], SnapMode mode) +static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, + ListBase *depth_peels, const float mval[2], SnapMode mode) { Base *base; - int retval = 0; + bool retval = false; float ray_start[3], ray_normal[3]; ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal); @@ -1798,7 +1799,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L if (dob->type == OB_MESH) { BMEditMesh *em; DerivedMesh *dm = NULL; - int val; + bool val; if (dob != obedit) { dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH); @@ -1822,7 +1823,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L } if (ob->type == OB_MESH) { - int val = 0; + bool val = false; if (ob != obedit && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT))) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); @@ -1850,12 +1851,12 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L return retval; } -int peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode) +bool peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode) { return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval, mode); } -int peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode) +bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode) { ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -1865,7 +1866,7 @@ int peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], /******************** NODES ***********************************/ -static int snapNodeTest(View2D *v2d, bNode *node, SnapMode mode) +static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode) { /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ return ((mode == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) || @@ -1887,12 +1888,12 @@ static NodeBorder snapNodeBorder(int snap_node_mode) return 0; } -static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2], - float r_loc[2], int *r_dist, char *r_node_border) +static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2], + float r_loc[2], int *r_dist, char *r_node_border) { View2D *v2d = &ar->v2d; NodeBorder border = snapNodeBorder(ts->snap_node_mode); - int retval = 0; + bool retval = false; rcti totr; int new_dist; @@ -1905,7 +1906,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo UI_view2d_region_to_view(v2d, totr.xmin, mval[1], &r_loc[0], &r_loc[1]); *r_dist = new_dist; *r_node_border = NODE_LEFT; - retval = 1; + retval = true; } } @@ -1915,7 +1916,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo UI_view2d_region_to_view(v2d, totr.xmax, mval[1], &r_loc[0], &r_loc[1]); *r_dist = new_dist; *r_node_border = NODE_RIGHT; - retval = 1; + retval = true; } } @@ -1925,7 +1926,7 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo UI_view2d_region_to_view(v2d, mval[0], totr.ymin, &r_loc[0], &r_loc[1]); *r_dist = new_dist; *r_node_border = NODE_BOTTOM; - retval = 1; + retval = true; } } @@ -1935,19 +1936,19 @@ static int snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNo UI_view2d_region_to_view(v2d, mval[0], totr.ymax, &r_loc[0], &r_loc[1]); *r_dist = new_dist; *r_node_border = NODE_TOP; - retval = 1; + retval = true; } } return retval; } -static int snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2], +static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode) { bNodeTree *ntree = snode->edittree; bNode *node; - int retval = 0; + bool retval = false; *r_node_border = 0; @@ -1959,12 +1960,12 @@ static int snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int return retval; } -int snapNodesTransform(TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode) +bool snapNodesTransform(TransInfo *t, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode) { return snapNodes(t->settings, t->sa->spacedata.first, t->ar, mval, r_dist, r_loc, r_node_border, mode); } -int snapNodesContext(bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode) +bool snapNodesContext(bContext *C, const int mval[2], int *r_dist, float r_loc[2], char *r_node_border, SnapMode mode) { Scene *scene = CTX_data_scene(C); return snapNodes(scene->toolsettings, CTX_wm_space_node(C), CTX_wm_region(C), mval, r_dist, r_loc, r_node_border, mode); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index f0f31b1e793..73062c57526 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -187,8 +187,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha if (G.relbase_valid) { char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; - BLI_strncpy(local_name, abs_name, sizeof(local_name)); - BLI_splitdirstring(local_name, fi); + BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (strcmp(abs_name, local_name) != 0) { switch (checkPackedFile(local_name, pf)) { diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index c8c26ed771d..7f4e05ddefa 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -246,7 +246,9 @@ void undo_editmode_step(bContext *C, int step) } else if (step == 1) { - if (curundo == NULL || curundo->prev == NULL) error("No more steps to undo"); + if (curundo == NULL || curundo->prev == NULL) { + error("No more steps to undo"); + } else { if (G.debug & G_DEBUG) printf("undo %s\n", curundo->name); curundo = curundo->prev; @@ -256,7 +258,9 @@ void undo_editmode_step(bContext *C, int step) else { /* curundo has to remain current situation! */ - if (curundo == NULL || curundo->next == NULL) error("No more steps to redo"); + if (curundo == NULL || curundo->next == NULL) { + error("No more steps to redo"); + } else { undo_restore(curundo->next, curundo->getdata(C), obedit->data); curundo = curundo->next; diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 0ec16ead35d..98a1b54c452 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -163,7 +163,7 @@ void applyNumInput(NumInput *n, float *vec) } } -char handleNumInput(NumInput *n, wmEvent *event) +char handleNumInput(NumInput *n, const wmEvent *event) { float Val = 0; short idx = n->idx, idx_max = n->idx_max; diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index ac2ee21d09d..fc603f7a593 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -475,7 +475,7 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem) } -static int undo_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { int undosys, totitem = 0; diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index ea7e17af086..ba4879b38ca 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -50,6 +50,7 @@ #include "BKE_tessmesh.h" #include "BLI_array.h" +#include "BLI_buffer.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -177,6 +178,9 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); + BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(vec2f, tf_uvorig_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + ED_space_image_get_uv_aspect(sima, &aspx, &aspy); switch (sima->dt_uvstretch) { @@ -186,8 +190,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { const int efa_len = efa->len; - float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len); - float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { @@ -229,8 +233,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { const int efa_len = efa->len; - float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len); - float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); area = BM_face_calc_area(efa) / totarea; @@ -268,6 +272,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe { float a; + BLI_buffer_declare_static(float, uvang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(float, ang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(vec3f, av_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(vec2f, auv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + col[3] = 0.5f; /* hard coded alpha, not that nice */ glShadeModel(GL_SMOOTH); @@ -277,12 +286,12 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe if (uvedit_face_visible_test(scene, ima, efa, tf)) { const int efa_len = efa->len; - float (*tf_uv)[2] = BLI_array_alloca(tf_uv, efa_len); - float (*tf_uvorig)[2] = BLI_array_alloca(tf_uvorig, efa_len); - float *uvang = BLI_array_alloca(uvang, efa_len); - float *ang = BLI_array_alloca(ang, efa_len); - float (*av)[3] = BLI_array_alloca(av, efa_len); /* use for 2d and 3d angle vectors */ - float (*auv)[2] = BLI_array_alloca(auv, efa_len); + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len); + float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len); + float *uvang = BLI_buffer_resize_data(&uvang_buf, float, efa_len); + float *ang = BLI_buffer_resize_data(&ang_buf, float, efa_len); + float (*av)[3] = (float (*)[3])BLI_buffer_resize_data(&av_buf, vec3f, efa_len); + float (*auv)[2] = (float (*)[2])BLI_buffer_resize_data(&auv_buf, vec2f, efa_len); int j; BM_elem_flag_enable(efa, BM_ELEM_TAG); @@ -329,11 +338,19 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe } } + BLI_buffer_free(&uvang_buf); + BLI_buffer_free(&ang_buf); + BLI_buffer_free(&av_buf); + BLI_buffer_free(&auv_buf); + glShadeModel(GL_FLAT); break; } } + + BLI_buffer_free(&tf_uv_buf); + BLI_buffer_free(&tf_uvorig_buf); } static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage) diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index fbb6250c05b..85375bcaf83 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -2236,7 +2236,7 @@ static int select_exec(bContext *C, wmOperator *op) return mouse_select(C, co, extend, loop); } -static int select_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float co[2]; @@ -2281,7 +2281,7 @@ static int select_loop_exec(bContext *C, wmOperator *op) return mouse_select(C, co, extend, loop); } -static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float co[2]; @@ -2314,7 +2314,7 @@ static void UV_OT_select_loop(wmOperatorType *ot) /* ******************** linked select operator **************** */ -static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick) +static int select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); @@ -2384,7 +2384,7 @@ static void UV_OT_select_linked(wmOperatorType *ot) "Extend", "Extend selection rather than clearing the existing selection"); } -static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { return select_linked_internal(C, op, event, 1); } @@ -3748,7 +3748,7 @@ static int set_2d_cursor_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); float location[2]; @@ -3799,7 +3799,7 @@ static int set_tile_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int set_tile_invoke(bContext *C, wmOperator *op, const wmEvent *event) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 5bb8105cd14..4c56a016176 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -41,6 +41,7 @@ #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" +#include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_math_vector.h" @@ -1748,7 +1749,7 @@ static int stitch_init(bContext *C, wmOperator *op) state->total_separate_edges = total_edges; /* fill the edges with data */ - for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) { + for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); BLI_ghashIterator_notDone(ghi); BLI_ghashIterator_step(ghi)) { edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi)); } @@ -1910,7 +1911,7 @@ static int stitch_init(bContext *C, wmOperator *op) return 1; } -static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *obedit = CTX_data_edit_object(C); if (!stitch_init(C, op)) @@ -2000,7 +2001,7 @@ static int stitch_exec(bContext *C, wmOperator *op) } } -static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *state) +static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, StitchState *state) { /* add uv under mouse to processed uv's */ float co[2]; @@ -2034,7 +2035,7 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState } } -static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event) +static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event) { StitchState *state; Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 4ddf4bd6a5c..9de43fc9d6b 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -654,7 +654,7 @@ static int minimize_stretch_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { MinStretch *ms; @@ -670,7 +670,7 @@ static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED( return OPERATOR_RUNNING_MODAL; } -static int minimize_stretch_modal(bContext *C, wmOperator *op, wmEvent *event) +static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event) { MinStretch *ms = op->customdata; |