From ea69d471c89a504a71b6906ed081057dafd196d0 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sun, 21 Aug 2016 23:59:18 +0200 Subject: Sculpting: Avoid calculating and chaching viewport matrices Really couldn't find where this was used. --- source/blender/editors/sculpt_paint/paint_stroke.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index d53d87db228..05270dbfa09 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -88,7 +88,6 @@ typedef struct PaintStroke { /* Cached values */ ViewContext vc; - bglMats mats; Brush *brush; UnifiedPaintSettings *ups; @@ -675,8 +674,6 @@ PaintStroke *paint_stroke_new(bContext *C, float zoomx, zoomy; view3d_set_viewcontext(C, &stroke->vc); - 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; -- cgit v1.2.3 From fe8b197269fda1b6747c022eb93b2781353008d5 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 23 Aug 2016 21:48:16 +0200 Subject: Fix T49150: make new 'operator categories' in search menu i18n-aware. --- source/blender/editors/interface/interface_regions.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index c621fcf493d..c507401b9a0 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1380,6 +1380,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4); /* widget itself */ + /* NOTE: i18n messages extracting tool does the same, please keep it in sync. */ { wmOperatorType *ot = data->items.pointers[a]; @@ -1400,7 +1401,8 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe } rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */ - ui_draw_menu_item(&data->fstyle, &rect_pre, text_pre, data->items.icons[a], state, false); + ui_draw_menu_item(&data->fstyle, &rect_pre, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre), + data->items.icons[a], state, false); ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep); } -- cgit v1.2.3 From 0ca4e3942427ad294428ba1b8db2cafe3bbdf5d6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 24 Aug 2016 14:17:26 +0200 Subject: Fix T49148: Blender Crash With B select on Skeleton Sketching --- source/blender/editors/space_view3d/view3d_select.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index a460d8900b4..3239d07553f 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1954,6 +1954,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool int index = buffer[(4 * a) + 3]; if (index != -1) { ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); + if ((index & 0xFFFF0000) == 0) { + continue; + } if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { if (index & BONESEL_TIP) { ebone->flag |= BONE_DONE; -- cgit v1.2.3 From adfd58aa49d6e7b5dbc0861848fc4ee91adad885 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 25 Aug 2016 13:48:23 +0200 Subject: Fix T48788: Diffuse color in BI Textured Solid mode is not updating properly in Sculpting mode Was caused by 6276726, so for the time being revert the optimization part of change. --- source/blender/editors/space_view3d/drawmesh.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 74a50497164..ecbfd5c7c85 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -1015,12 +1015,18 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d else { userData.me = NULL; - if ((ob->mode & OB_MODE_ALL_PAINT) == 0) { + /* if ((ob->mode & OB_MODE_ALL_PAINT) == 0) */ { /* Note: this isn't efficient and runs on every redraw, * its needed so material colors are used for vertex colors. * In the future we will likely remove 'texface' so, just avoid running this where possible, - * (when vertex paint or weight paint are used). */ + * (when vertex paint or weight paint are used). + * + * Note 2: We disable optimization for now since it causes T48788 + * and it is now too close to release to do something smarter. + * + * TODO(sergey): Find some real solution here. + */ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT)); } -- cgit v1.2.3 From 84cd13750390a38a5321259f354ef401f45a95a2 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 26 Aug 2016 16:04:15 +1200 Subject: GPencil: Select Grouped -> By Color Added a way to select all the currently visible strokes that use the same color as the selected stroke. This can be accessed via the Select Grouped (Shift-G) operator as an alternative to selecting by layer. --- source/blender/editors/gpencil/gpencil_select.c | 47 ++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 4cb966c6378..45dbde80284 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_lasso.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" @@ -253,6 +254,9 @@ typedef enum eGP_SelectGrouped { /* Select strokes in the same layer */ GP_SEL_SAME_LAYER = 0, + /* Select strokes with the same color */ + GP_SEL_SAME_COLOR = 1, + /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */ /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */ } eGP_SelectGrouped; @@ -302,6 +306,43 @@ static void gp_select_same_layer(bContext *C) CTX_DATA_END; } +/* Select all strokes with same colors as selected ones */ +static void gp_select_same_color(bContext *C) +{ + /* First, build set containing all the colors of selected strokes + * - We use the palette names, so that we can select all strokes with one + * (potentially missing) color, and remap them to something else + */ + GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); + + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + /* add instead of insert here, otherwise the uniqueness check gets skipped, + * and we get many duplicate entries... + */ + BLI_gset_add(selected_colors, gps->colorname); + } + } + CTX_DATA_END; + + /* Second, select any visible stroke that uses these colors */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (BLI_gset_haskey(selected_colors, gps->colorname)) { + /* select this stroke */ + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag |= GP_SPOINT_SELECT; + } + + gps->flag |= GP_STROKE_SELECT; + } + } + CTX_DATA_END; +} /* ----------------------------------- */ @@ -314,6 +355,9 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) case GP_SEL_SAME_LAYER: gp_select_same_layer(C); break; + case GP_SEL_SAME_COLOR: + gp_select_same_color(C); + break; default: BLI_assert(!"unhandled select grouped gpencil mode"); @@ -329,6 +373,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot) { static EnumPropertyItem prop_select_grouped_types[] = { {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"}, + {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"}, {0, NULL, 0, NULL, NULL} }; @@ -338,7 +383,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot) ot->description = "Select all strokes with similar characteristics"; /* callbacks */ - //ot->invoke = WM_menu_invoke; + ot->invoke = WM_menu_invoke; ot->exec = gpencil_select_grouped_exec; ot->poll = gpencil_select_poll; -- cgit v1.2.3 From 2ac75fe035458972ddf29cdbb33eb5af4ada2477 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 26 Aug 2016 16:07:25 +1200 Subject: Fix: Color of frame/selected object indicator in 3D View didn't indicate GPencil keyframes when there was no active object --- source/blender/editors/space_view3d/view3d_draw.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index d2a52de0e28..a01f5dbc640 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -951,9 +951,11 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) UI_ThemeColor(TH_TEXT_HI); } else { - /* no object */ - /* color is always white */ - UI_ThemeColor(TH_TEXT_HI); + /* no object */ + if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) + UI_ThemeColor(TH_TIME_GP_KEYFRAME); + else + UI_ThemeColor(TH_TEXT_HI); } if (markern) { -- cgit v1.2.3 From 274e1c4f1f4aaf32b86d2d66d58e8943279329a3 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 26 Aug 2016 16:25:39 +1200 Subject: Code Cleanup * Stroke editing functions should be in gpencil_edit.c not gpencil_data.c (the latter is only for handling "CRUD" operations on things like layers, brushes, and palettes) * Deduplicate the GP_STROKE_BUFFER_MAX define --- source/blender/editors/gpencil/gpencil_data.c | 428 ------------------------ source/blender/editors/gpencil/gpencil_edit.c | 424 +++++++++++++++++++++++ source/blender/editors/gpencil/gpencil_intern.h | 3 + source/blender/editors/gpencil/gpencil_paint.c | 3 - 4 files changed, 427 insertions(+), 431 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 2aa6d30c114..83dc0b679ee 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -75,9 +75,6 @@ #include "gpencil_intern.h" -/* maximum sizes of gp-session buffer */ -#define GP_STROKE_BUFFER_MAX 5000 - /* ************************************************ */ /* Datablock Operators */ @@ -965,431 +962,6 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot) ot->poll = gp_active_layer_poll; } -/* ******************* Apply layer thickness change to Strokes ************************** */ - -static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - - /* sanity checks */ - if (ELEM(NULL, gpd, gpl, gpl->frames.first)) - return OPERATOR_CANCELLED; - - /* loop all strokes */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - /* Apply thickness */ - gps->thickness = gps->thickness + gpl->thickness; - } - } - /* clear value */ - gpl->thickness = 0.0f; - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Apply Stroke Thickness"; - ot->idname = "GPENCIL_OT_stroke_apply_thickness"; - ot->description = "Apply the thickness change of the layer to its strokes"; - - /* api callbacks */ - ot->exec = gp_stroke_apply_thickness_exec; - ot->poll = gp_active_layer_poll; -} - -/* ******************* Close Strokes ************************** */ - -enum { - GP_STROKE_CYCLIC_CLOSE = 1, - GP_STROKE_CYCLIC_OPEN = 2, - GP_STROKE_CYCLIC_TOGGLE = 3 -}; - -static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - const int type = RNA_enum_get(op->ptr, "type"); - - /* sanity checks */ - if (ELEM(NULL, gpd)) - return OPERATOR_CANCELLED; - - /* loop all selected strokes */ - CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) - { - for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { - bGPDpalettecolor *palcolor = gps->palcolor; - - /* skip strokes that are not selected or invalid for current view */ - if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) - continue; - /* skip hidden or locked colors */ - if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED)) - continue; - - switch (type) { - case GP_STROKE_CYCLIC_CLOSE: - /* Close all (enable) */ - gps->flag |= GP_STROKE_CYCLIC; - break; - case GP_STROKE_CYCLIC_OPEN: - /* Open all (disable) */ - gps->flag &= ~GP_STROKE_CYCLIC; - break; - case GP_STROKE_CYCLIC_TOGGLE: - /* Just toggle flag... */ - gps->flag ^= GP_STROKE_CYCLIC; - break; - default: - BLI_assert(0); - break; - } - } - } - CTX_DATA_END; - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -/** - * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with - * option to force opened/closed strokes instead of just toggle behavior. - */ -void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) -{ - static EnumPropertyItem cyclic_type[] = { - {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""}, - {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""}, - {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Set Cyclical State"; - ot->idname = "GPENCIL_OT_stroke_cyclical_set"; - ot->description = "Close or open the selected stroke adding an edge from last to first point"; - - /* api callbacks */ - ot->exec = gp_stroke_cyclical_set_exec; - ot->poll = gp_active_layer_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", ""); -} - -/* ******************* Stroke join ************************** */ - -/* Helper: flip stroke */ -static void gpencil_flip_stroke(bGPDstroke *gps) -{ - bGPDspoint pt, *point, *point2; - int end = gps->totpoints - 1; - - for (int i = 0; i < gps->totpoints / 2; i++) { - /* save first point */ - point = &gps->points[i]; - pt.x = point->x; - pt.y = point->y; - pt.z = point->z; - pt.flag = point->flag; - pt.pressure = point->pressure; - pt.strength = point->strength; - pt.time = point->time; - - /* replace first point with last point */ - point2 = &gps->points[end]; - point->x = point2->x; - point->y = point2->y; - point->z = point2->z; - point->flag = point2->flag; - point->pressure = point2->pressure; - point->strength = point2->strength; - point->time = point2->time; - - /* replace last point with first saved before */ - point = &gps->points[end]; - point->x = pt.x; - point->y = pt.y; - point->z = pt.z; - point->flag = pt.flag; - point->pressure = pt.pressure; - point->strength = pt.strength; - point->time = pt.time; - - end--; - } -} - -/* Helper: copy point between strokes */ -static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3], - float pressure, float strength, float deltatime) -{ - bGPDspoint *newpoint; - - gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); - gps->totpoints++; - - newpoint = &gps->points[gps->totpoints - 1]; - newpoint->x = point->x * delta[0]; - newpoint->y = point->y * delta[1]; - newpoint->z = point->z * delta[2]; - newpoint->flag = point->flag; - newpoint->pressure = pressure; - newpoint->strength = strength; - newpoint->time = point->time + deltatime; -} - -/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */ -static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps) -{ - bGPDspoint point, *pt; - int i; - float delta[3] = {1.0f, 1.0f, 1.0f}; - float deltatime = 0.0f; - - /* sanity checks */ - if (ELEM(NULL, gps_a, gps_b)) - return; - - if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) - return; - - /* define start and end points of each stroke */ - float sa[3], sb[3], ea[3], eb[3]; - pt = &gps_a->points[0]; - copy_v3_v3(sa, &pt->x); - - pt = &gps_a->points[gps_a->totpoints - 1]; - copy_v3_v3(ea, &pt->x); - - pt = &gps_b->points[0]; - copy_v3_v3(sb, &pt->x); - - pt = &gps_b->points[gps_b->totpoints - 1]; - copy_v3_v3(eb, &pt->x); - - /* review if need flip stroke B */ - float ea_sb = len_squared_v3v3(ea, sb); - float ea_eb = len_squared_v3v3(ea, eb); - /* flip if distance to end point is shorter */ - if (ea_eb < ea_sb) { - gpencil_flip_stroke(gps_b); - } - - /* don't visibly link the first and last points? */ - if (leave_gaps) { - /* 1st: add one tail point to start invisible area */ - point = gps_a->points[gps_a->totpoints - 1]; - deltatime = point.time; - gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f); - - /* 2nd: add one head point to finish invisible area */ - point = gps_b->points[0]; - gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime); - } - - /* 3rd: add all points */ - for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { - /* check if still room in buffer */ - if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) { - gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime); - } - } -} - -static int gp_stroke_join_exec(bContext *C, wmOperator *op) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd); - bGPDstroke *gps, *gpsn; - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - - bGPDframe *gpf_a = NULL; - bGPDstroke *stroke_a = NULL; - bGPDstroke *stroke_b = NULL; - bGPDstroke *new_stroke = NULL; - - const int type = RNA_enum_get(op->ptr, "type"); - const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps"); - - /* sanity checks */ - if (ELEM(NULL, gpd)) - return OPERATOR_CANCELLED; - - if (activegpl->flag & GP_LAYER_LOCKED) - return OPERATOR_CANCELLED; - - BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY)); - - - /* read all selected strokes */ - bool first = false; - CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) - { - bGPDframe *gpf = gpl->actframe; - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; - if (gps->flag & GP_STROKE_SELECT) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } - /* to join strokes, cyclic must be disabled */ - gps->flag &= ~GP_STROKE_CYCLIC; - /* saves first frame and stroke */ - if (!first) { - first = true; - gpf_a = gpf; - stroke_a = gps; - } - else { - stroke_b = gps; - /* create a new stroke if was not created before (only created if something to join) */ - if (new_stroke == NULL) { - new_stroke = MEM_dupallocN(stroke_a); - new_stroke->points = MEM_dupallocN(stroke_a->points); - new_stroke->triangles = NULL; - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_CACHES; - /* if new, set current color */ - if (type == GP_STROKE_JOINCOPY) { - new_stroke->palcolor = palcolor; - BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname)); - new_stroke->flag |= GP_STROKE_RECALC_COLOR; - } - } - /* join new_stroke and stroke B. New stroke will contain all the previous data */ - gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps); - - /* if join only, delete old strokes */ - if (type == GP_STROKE_JOIN) { - if (stroke_a) { - BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke); - BLI_remlink(&gpf->strokes, stroke_a); - BKE_gpencil_free_stroke(stroke_a); - stroke_a = NULL; - } - if (stroke_b) { - BLI_remlink(&gpf->strokes, stroke_b); - BKE_gpencil_free_stroke(stroke_b); - stroke_b = NULL; - } - } - } - } - } - } - CTX_DATA_END; - /* add new stroke if was not added before */ - if (type == GP_STROKE_JOINCOPY) { - if (new_stroke) { - /* Add a new frame if needed */ - if (activegpl->actframe == NULL) - activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum); - - BLI_addtail(&activegpl->actframe->strokes, new_stroke); - } - } - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_stroke_join(wmOperatorType *ot) -{ - static EnumPropertyItem join_type[] = { - {GP_STROKE_JOIN, "JOIN", 0, "Join", ""}, - {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""}, - {0, NULL, 0, NULL, NULL} - }; - - /* identifiers */ - ot->name = "Join Strokes"; - ot->idname = "GPENCIL_OT_stroke_join"; - ot->description = "Join selected strokes (optionally as new stroke)"; - - /* api callbacks */ - ot->exec = gp_stroke_join_exec; - ot->poll = gp_active_layer_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", ""); - RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them"); -} - -/* ******************* Stroke flip ************************** */ - -static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - - /* sanity checks */ - if (ELEM(NULL, gpd)) - return OPERATOR_CANCELLED; - - /* read all selected strokes */ - CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) - { - bGPDframe *gpf = gpl->actframe; - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - if (gps->flag & GP_STROKE_SELECT) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } - /* flip stroke */ - gpencil_flip_stroke(gps); - } - } - } - CTX_DATA_END; - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_stroke_flip(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Flip Stroke"; - ot->idname = "GPENCIL_OT_stroke_flip"; - ot->description = "Change direction of the points of the selected strokes"; - - /* api callbacks */ - ot->exec = gp_stroke_flip_exec; - ot->poll = gp_active_layer_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - /* ************************************************ */ /* Drawing Brushes Operators */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index e58178bf2a7..f25e873fa58 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1455,5 +1455,429 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ******************* Apply layer thickness change to Strokes ************************** */ + +static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl, gpl->frames.first)) + return OPERATOR_CANCELLED; + + /* loop all strokes */ + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* Apply thickness */ + gps->thickness = gps->thickness + gpl->thickness; + } + } + /* clear value */ + gpl->thickness = 0.0f; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Apply Stroke Thickness"; + ot->idname = "GPENCIL_OT_stroke_apply_thickness"; + ot->description = "Apply the thickness change of the layer to its strokes"; + + /* api callbacks */ + ot->exec = gp_stroke_apply_thickness_exec; + ot->poll = gp_active_layer_poll; +} + +/* ******************* Close Strokes ************************** */ + +enum { + GP_STROKE_CYCLIC_CLOSE = 1, + GP_STROKE_CYCLIC_OPEN = 2, + GP_STROKE_CYCLIC_TOGGLE = 3 +}; + +static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + const int type = RNA_enum_get(op->ptr, "type"); + + /* sanity checks */ + if (ELEM(NULL, gpd)) + return OPERATOR_CANCELLED; + + /* loop all selected strokes */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { + bGPDpalettecolor *palcolor = gps->palcolor; + + /* skip strokes that are not selected or invalid for current view */ + if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) + continue; + /* skip hidden or locked colors */ + if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED)) + continue; + + switch (type) { + case GP_STROKE_CYCLIC_CLOSE: + /* Close all (enable) */ + gps->flag |= GP_STROKE_CYCLIC; + break; + case GP_STROKE_CYCLIC_OPEN: + /* Open all (disable) */ + gps->flag &= ~GP_STROKE_CYCLIC; + break; + case GP_STROKE_CYCLIC_TOGGLE: + /* Just toggle flag... */ + gps->flag ^= GP_STROKE_CYCLIC; + break; + default: + BLI_assert(0); + break; + } + } + } + CTX_DATA_END; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +/** + * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with + * option to force opened/closed strokes instead of just toggle behavior. + */ +void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) +{ + static EnumPropertyItem cyclic_type[] = { + {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""}, + {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""}, + {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Set Cyclical State"; + ot->idname = "GPENCIL_OT_stroke_cyclical_set"; + ot->description = "Close or open the selected stroke adding an edge from last to first point"; + + /* api callbacks */ + ot->exec = gp_stroke_cyclical_set_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", ""); +} + +/* ******************* Stroke join ************************** */ + +/* Helper: flip stroke */ +static void gpencil_flip_stroke(bGPDstroke *gps) +{ + bGPDspoint pt, *point, *point2; + int end = gps->totpoints - 1; + + for (int i = 0; i < gps->totpoints / 2; i++) { + /* save first point */ + point = &gps->points[i]; + pt.x = point->x; + pt.y = point->y; + pt.z = point->z; + pt.flag = point->flag; + pt.pressure = point->pressure; + pt.strength = point->strength; + pt.time = point->time; + + /* replace first point with last point */ + point2 = &gps->points[end]; + point->x = point2->x; + point->y = point2->y; + point->z = point2->z; + point->flag = point2->flag; + point->pressure = point2->pressure; + point->strength = point2->strength; + point->time = point2->time; + + /* replace last point with first saved before */ + point = &gps->points[end]; + point->x = pt.x; + point->y = pt.y; + point->z = pt.z; + point->flag = pt.flag; + point->pressure = pt.pressure; + point->strength = pt.strength; + point->time = pt.time; + + end--; + } +} + +/* Helper: copy point between strokes */ +static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3], + float pressure, float strength, float deltatime) +{ + bGPDspoint *newpoint; + + gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); + gps->totpoints++; + + newpoint = &gps->points[gps->totpoints - 1]; + newpoint->x = point->x * delta[0]; + newpoint->y = point->y * delta[1]; + newpoint->z = point->z * delta[2]; + newpoint->flag = point->flag; + newpoint->pressure = pressure; + newpoint->strength = strength; + newpoint->time = point->time + deltatime; +} + +/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */ +static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps) +{ + bGPDspoint point, *pt; + int i; + float delta[3] = {1.0f, 1.0f, 1.0f}; + float deltatime = 0.0f; + + /* sanity checks */ + if (ELEM(NULL, gps_a, gps_b)) + return; + + if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) + return; + + /* define start and end points of each stroke */ + float sa[3], sb[3], ea[3], eb[3]; + pt = &gps_a->points[0]; + copy_v3_v3(sa, &pt->x); + + pt = &gps_a->points[gps_a->totpoints - 1]; + copy_v3_v3(ea, &pt->x); + + pt = &gps_b->points[0]; + copy_v3_v3(sb, &pt->x); + + pt = &gps_b->points[gps_b->totpoints - 1]; + copy_v3_v3(eb, &pt->x); + + /* review if need flip stroke B */ + float ea_sb = len_squared_v3v3(ea, sb); + float ea_eb = len_squared_v3v3(ea, eb); + /* flip if distance to end point is shorter */ + if (ea_eb < ea_sb) { + gpencil_flip_stroke(gps_b); + } + + /* don't visibly link the first and last points? */ + if (leave_gaps) { + /* 1st: add one tail point to start invisible area */ + point = gps_a->points[gps_a->totpoints - 1]; + deltatime = point.time; + gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f); + + /* 2nd: add one head point to finish invisible area */ + point = gps_b->points[0]; + gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime); + } + + /* 3rd: add all points */ + for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { + /* check if still room in buffer */ + if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) { + gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime); + } + } +} + +static int gp_stroke_join_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd); + bGPDstroke *gps, *gpsn; + bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); + bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); + + bGPDframe *gpf_a = NULL; + bGPDstroke *stroke_a = NULL; + bGPDstroke *stroke_b = NULL; + bGPDstroke *new_stroke = NULL; + + const int type = RNA_enum_get(op->ptr, "type"); + const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps"); + + /* sanity checks */ + if (ELEM(NULL, gpd)) + return OPERATOR_CANCELLED; + + if (activegpl->flag & GP_LAYER_LOCKED) + return OPERATOR_CANCELLED; + + BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY)); + + + /* read all selected strokes */ + bool first = false; + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + continue; + } + /* to join strokes, cyclic must be disabled */ + gps->flag &= ~GP_STROKE_CYCLIC; + /* saves first frame and stroke */ + if (!first) { + first = true; + gpf_a = gpf; + stroke_a = gps; + } + else { + stroke_b = gps; + /* create a new stroke if was not created before (only created if something to join) */ + if (new_stroke == NULL) { + new_stroke = MEM_dupallocN(stroke_a); + new_stroke->points = MEM_dupallocN(stroke_a->points); + new_stroke->triangles = NULL; + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + /* if new, set current color */ + if (type == GP_STROKE_JOINCOPY) { + new_stroke->palcolor = palcolor; + BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname)); + new_stroke->flag |= GP_STROKE_RECALC_COLOR; + } + } + /* join new_stroke and stroke B. New stroke will contain all the previous data */ + gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps); + + /* if join only, delete old strokes */ + if (type == GP_STROKE_JOIN) { + if (stroke_a) { + BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke); + BLI_remlink(&gpf->strokes, stroke_a); + BKE_gpencil_free_stroke(stroke_a); + stroke_a = NULL; + } + if (stroke_b) { + BLI_remlink(&gpf->strokes, stroke_b); + BKE_gpencil_free_stroke(stroke_b); + stroke_b = NULL; + } + } + } + } + } + } + CTX_DATA_END; + /* add new stroke if was not added before */ + if (type == GP_STROKE_JOINCOPY) { + if (new_stroke) { + /* Add a new frame if needed */ + if (activegpl->actframe == NULL) + activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum); + + BLI_addtail(&activegpl->actframe->strokes, new_stroke); + } + } + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_join(wmOperatorType *ot) +{ + static EnumPropertyItem join_type[] = { + {GP_STROKE_JOIN, "JOIN", 0, "Join", ""}, + {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Join Strokes"; + ot->idname = "GPENCIL_OT_stroke_join"; + ot->description = "Join selected strokes (optionally as new stroke)"; + + /* api callbacks */ + ot->exec = gp_stroke_join_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", ""); + RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them"); +} + +/* ******************* Stroke flip ************************** */ + +static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + /* sanity checks */ + if (ELEM(NULL, gpd)) + return OPERATOR_CANCELLED; + + /* read all selected strokes */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *gpf = gpl->actframe; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + continue; + } + /* flip stroke */ + gpencil_flip_stroke(gps); + } + } + } + CTX_DATA_END; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_flip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flip Stroke"; + ot->idname = "GPENCIL_OT_stroke_flip"; + ot->description = "Change direction of the points of the selected strokes"; + + /* api callbacks */ + ot->exec = gp_stroke_flip_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} /* ************************************************ */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index f37fba4212d..5f7cef9a852 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -214,6 +214,9 @@ typedef enum eGPencil_PaintModes { GP_PAINTMODE_DRAW_POLY } eGPencil_PaintModes; +/* maximum sizes of gp-session buffer */ +#define GP_STROKE_BUFFER_MAX 5000 + /* stroke editing ----- */ void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index dacdc0cf777..70a4b2904ed 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -164,9 +164,6 @@ typedef struct tGPsdata { /* ------ */ -/* maximum sizes of gp-session buffer */ -#define GP_STROKE_BUFFER_MAX 5000 - /* Macros for accessing sensitivity thresholds... */ /* minimum number of pixels mouse should move before new point created */ #define MIN_MANHATTEN_PX (U.gp_manhattendist) -- cgit v1.2.3 From 2a6362255d8d0e1c5fd2c20495a76ceddaa8dbc8 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Sat, 27 Aug 2016 12:52:30 +0200 Subject: GPencil: Cleanup change color operator It is faster to assign the color to the pointer instead to force the new lookup in drawing function. --- source/blender/editors/gpencil/gpencil_data.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 83dc0b679ee..9560ab188a4 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -879,9 +879,9 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op)) continue; /* asign new color (only if different) */ - if (STREQ(gps->colorname, color->info) == false) { + if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) { BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname)); - gps->flag |= GP_STROKE_RECALC_COLOR; + gps->palcolor = color; } } } -- cgit v1.2.3 From 7bc9353957f495750445492dee8137321693de4e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 26 Aug 2016 19:54:16 +1200 Subject: Code Cleanup (Non-functional tweaks) General reshuffling of defines and spacing/brace usage for consistency. In particular: * When defining types, don't mix pointers and non-pointer types on same line to avoid confusion * As much as possible, have all defines at the top of each block instead of scattered haphazardly throughout the code --- source/blender/editors/gpencil/gpencil_edit.c | 211 +++++++++++++------------- 1 file changed, 106 insertions(+), 105 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f25e873fa58..3fe53e3d0ab 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1188,40 +1188,35 @@ static int gp_snap_poll(bContext *C) static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) { + bGPdata *gpd = ED_gpencil_data_get_active(C); RegionView3D *rv3d = CTX_wm_region_data(C); const float gridf = rv3d->gridview; - bGPdata *gpd = ED_gpencil_data_get_active(C); - float diff_mat[4][4]; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - + bGPDframe *gpf = gpl->actframe; + float diff_mat[4][4]; + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - } - - bGPDspoint *pt; - int i; - - // TOOD: if entire stroke is selected, offset entire stroke by same amount? - + + // TODO: if entire stroke is selected, offset entire stroke by same amount? for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - - /* only if point is selected.. */ + /* only if point is selected */ if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { pt->x = gridf * floorf(0.5f + pt->x / gridf); @@ -1232,19 +1227,17 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) /* apply parent transformations */ float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - + fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf); fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf); fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf); - + /* return data */ copy_v3_v3(&pt->x, fpt); gp_apply_parent_point(gpl, pt); } - } } - } } } @@ -1272,49 +1265,46 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) static int gp_snap_to_cursor(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - + const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d); - - bGPdata *gpd = ED_gpencil_data_get_active(C); - float diff_mat[4][4]; - + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - + bGPDframe *gpf = gpl->actframe; + float diff_mat[4][4]; + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - } - - bGPDspoint *pt; - int i; - /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + if (use_offset) { float offset[3]; - + /* compute offset from first point of stroke to cursor */ /* TODO: Allow using midpoint instead? */ sub_v3_v3v3(offset, cursor_global, &gps->points->x); - + /* apply offset to all points in the stroke */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { add_v3_v3(&pt->x, offset); @@ -1331,9 +1321,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) } } } - - } + } } @@ -1364,6 +1353,8 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -1375,36 +1366,31 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) INIT_MINMAX(min, max); /* calculate midpoints from selected points */ - bGPdata *gpd = ED_gpencil_data_get_active(C); - float diff_mat[4][4]; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - + bGPDframe *gpf = gpl->actframe; + float diff_mat[4][4]; + /* calculate difference matrix if parent object */ if (gpl->parent != NULL) { ED_gpencil_parent_location(gpl, diff_mat); } - - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(gpl, gps) == false) continue; - } - - bGPDspoint *pt; - int i; - /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { if (gpl->parent == NULL) { @@ -1415,14 +1401,14 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) /* apply parent transformations */ float fpt[3]; mul_v3_m4v3(fpt, diff_mat, &pt->x); - + add_v3_v3(centroid, fpt); minmax_v3v3_v3(min, max, fpt); } count++; } } - + } } } @@ -1455,7 +1441,7 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Apply layer thickness change to Strokes ************************** */ +/* ******************* Apply layer thickness change to strokes ************************** */ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1506,24 +1492,24 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); const int type = RNA_enum_get(op->ptr, "type"); - + /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - + /* loop all selected strokes */ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { bGPDpalettecolor *palcolor = gps->palcolor; - + /* skip strokes that are not selected or invalid for current view */ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) continue; /* skip hidden or locked colors */ if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED)) continue; - + switch (type) { case GP_STROKE_CYCLIC_CLOSE: /* Close all (enable) */ @@ -1544,10 +1530,10 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1563,19 +1549,20 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Set Cyclical State"; ot->idname = "GPENCIL_OT_stroke_cyclical_set"; ot->description = "Close or open the selected stroke adding an edge from last to first point"; - + /* api callbacks */ ot->exec = gp_stroke_cyclical_set_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", ""); } @@ -1584,10 +1571,12 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) /* Helper: flip stroke */ static void gpencil_flip_stroke(bGPDstroke *gps) { - bGPDspoint pt, *point, *point2; int end = gps->totpoints - 1; - + for (int i = 0; i < gps->totpoints / 2; i++) { + bGPDspoint *point, *point2; + bGPDspoint pt; + /* save first point */ point = &gps->points[i]; pt.x = point->x; @@ -1597,7 +1586,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) pt.pressure = point->pressure; pt.strength = point->strength; pt.time = point->time; - + /* replace first point with last point */ point2 = &gps->points[end]; point->x = point2->x; @@ -1607,7 +1596,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = point2->pressure; point->strength = point2->strength; point->time = point2->time; - + /* replace last point with first saved before */ point = &gps->points[end]; point->x = pt.x; @@ -1617,7 +1606,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = pt.pressure; point->strength = pt.strength; point->time = pt.time; - + end--; } } @@ -1627,10 +1616,10 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float float pressure, float strength, float deltatime) { bGPDspoint *newpoint; - + gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); gps->totpoints++; - + newpoint = &gps->points[gps->totpoints - 1]; newpoint->x = point->x * delta[0]; newpoint->y = point->y * delta[1]; @@ -1644,26 +1633,27 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float /* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps) { - bGPDspoint point, *pt; + bGPDspoint point; + bGPDspoint *pt; int i; float delta[3] = {1.0f, 1.0f, 1.0f}; float deltatime = 0.0f; - + /* sanity checks */ if (ELEM(NULL, gps_a, gps_b)) return; - + if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) return; - + /* define start and end points of each stroke */ float sa[3], sb[3], ea[3], eb[3]; pt = &gps_a->points[0]; copy_v3_v3(sa, &pt->x); - + pt = &gps_a->points[gps_a->totpoints - 1]; copy_v3_v3(ea, &pt->x); - + pt = &gps_b->points[0]; copy_v3_v3(sb, &pt->x); @@ -1677,14 +1667,14 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co if (ea_eb < ea_sb) { gpencil_flip_stroke(gps_b); } - + /* don't visibly link the first and last points? */ if (leave_gaps) { /* 1st: add one tail point to start invisible area */ point = gps_a->points[gps_a->totpoints - 1]; deltatime = point.time; gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f); - + /* 2nd: add one head point to finish invisible area */ point = gps_b->points[0]; gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime); @@ -1706,25 +1696,25 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) bGPDstroke *gps, *gpsn; bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - + bGPDframe *gpf_a = NULL; bGPDstroke *stroke_a = NULL; bGPDstroke *stroke_b = NULL; bGPDstroke *new_stroke = NULL; - + const int type = RNA_enum_get(op->ptr, "type"); const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps"); - + /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - + if (activegpl->flag & GP_LAYER_LOCKED) return OPERATOR_CANCELLED; - + BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY)); - - + + /* read all selected strokes */ bool first = false; CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) @@ -1741,8 +1731,10 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_color_use(gpl, gps) == false) { continue; } + /* to join strokes, cyclic must be disabled */ gps->flag &= ~GP_STROKE_CYCLIC; + /* saves first frame and stroke */ if (!first) { first = true; @@ -1751,6 +1743,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) } else { stroke_b = gps; + /* create a new stroke if was not created before (only created if something to join) */ if (new_stroke == NULL) { new_stroke = MEM_dupallocN(stroke_a); @@ -1758,6 +1751,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) new_stroke->triangles = NULL; new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; + /* if new, set current color */ if (type == GP_STROKE_JOINCOPY) { new_stroke->palcolor = palcolor; @@ -1765,9 +1759,10 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) new_stroke->flag |= GP_STROKE_RECALC_COLOR; } } + /* join new_stroke and stroke B. New stroke will contain all the previous data */ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps); - + /* if join only, delete old strokes */ if (type == GP_STROKE_JOIN) { if (stroke_a) { @@ -1787,20 +1782,21 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) } } CTX_DATA_END; + /* add new stroke if was not added before */ if (type == GP_STROKE_JOINCOPY) { if (new_stroke) { /* Add a new frame if needed */ if (activegpl->actframe == NULL) activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum); - + BLI_addtail(&activegpl->actframe->strokes, new_stroke); } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1811,19 +1807,20 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Join Strokes"; ot->idname = "GPENCIL_OT_stroke_join"; ot->description = "Join selected strokes (optionally as new stroke)"; - + /* api callbacks */ ot->exec = gp_stroke_join_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", ""); RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them"); } @@ -1842,6 +1839,9 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { bGPDframe *gpf = gpl->actframe; + if (gpf == NULL) + continue; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { if (gps->flag & GP_STROKE_SELECT) { /* skip strokes that are invalid for current view */ @@ -1852,16 +1852,17 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_color_use(gpl, gps) == false) { continue; } + /* flip stroke */ gpencil_flip_stroke(gps); } } } CTX_DATA_END; - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } @@ -1871,11 +1872,11 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) ot->name = "Flip Stroke"; ot->idname = "GPENCIL_OT_stroke_flip"; ot->description = "Change direction of the points of the selected strokes"; - + /* api callbacks */ ot->exec = gp_stroke_flip_exec; ot->poll = gp_active_layer_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -- cgit v1.2.3 From 116bab702e009ce8043b976b4a9c4afa4c7ff5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 28 Aug 2016 16:50:49 +0200 Subject: Fix T47639: OpenGL render with smoke and fire incorrect when using transparency. The issue is that we are rendering to a 0..1 clamped sRGB buffer with unpremultiplied alpha, where the correct thing to do would be to render to an unclamped linear premultiplied alpha buffer. Then we would just make fire purely emissive without affecting the alpha channel at all, but that doesn't work here. So for now, draw fire and smoke separately using different shaders and blend modes, like it used to before the smoke programs were rewritten (see rB0372b642). --- source/blender/editors/space_view3d/drawvolume.c | 193 ++++++++++++++--------- 1 file changed, 120 insertions(+), 73 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 8dbc2788744..06677ef4476 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -288,6 +288,108 @@ static int create_view_aligned_slices(VolumeSlicer *slicer, return num_points; } +static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, + bool use_fire, const float min[3], + const float ob_sizei[3], const float invsize[3]) +{ + int invsize_location = GPU_shader_get_uniform(shader, "invsize"); + int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); + int min_location = GPU_shader_get_uniform(shader, "min_location"); + + int soot_location; + int stepsize_location; + int densityscale_location; + int spec_location, flame_location; + int shadow_location, actcol_location; + + if (use_fire) { + spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); + flame_location = GPU_shader_get_uniform(shader, "flame_texture"); + } + else { + shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); + actcol_location = GPU_shader_get_uniform(shader, "active_color"); + soot_location = GPU_shader_get_uniform(shader, "soot_texture"); + stepsize_location = GPU_shader_get_uniform(shader, "step_size"); + densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); + } + + GPU_shader_bind(shader); + + if (use_fire) { + GPU_texture_bind(sds->tex_flame, 2); + GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); + + GPU_texture_bind(tex_spec, 3); + GPU_shader_uniform_texture(shader, spec_location, tex_spec); + } + else { + float density_scale = 10.0f; + + GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); + GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); + + GPU_texture_bind(sds->tex, 0); + GPU_shader_uniform_texture(shader, soot_location, sds->tex); + + GPU_texture_bind(sds->tex_shadow, 1); + GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); + + float active_color[3] = { 0.9, 0.9, 0.9 }; + if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) + mul_v3_v3(active_color, sds->active_color); + GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); + } + + GPU_shader_uniform_vector(shader, min_location, 3, 1, min); + GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); + GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); +} + +static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire) +{ + GPU_shader_unbind(); + + GPU_texture_unbind(sds->tex); + + if (use_fire) { + GPU_texture_unbind(sds->tex_flame); + GPU_texture_unbind(tex_spec); + GPU_texture_free(tex_spec); + } + else { + GPU_texture_unbind(sds->tex_shadow); + } +} + +static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer, + const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire) +{ + GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL; + + GLuint vertex_buffer; + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW); + + bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, NULL); + + glDrawArrays(GL_TRIANGLES, 0, num_points); + + glDisableClientState(GL_VERTEX_ARRAY); + + unbind_shader(sds, tex_spec, do_fire); + + /* cleanup */ + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDeleteBuffers(1, &vertex_buffer); +} + void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const float min[3], const float max[3], const float viewnormal[3]) @@ -299,14 +401,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; - GPUShader *shader = GPU_shader_get_builtin_shader( - (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); return; } + GPUShader *fire_shader = NULL; + if (use_fire) { + fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE); + + if (!fire_shader) { + fprintf(stderr, "Unable to create GLSL fire shader.\n"); + return; + } + } + const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), @@ -320,50 +431,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, TIMEIT_START(draw); #endif - /* setup smoke shader */ - - int soot_location = GPU_shader_get_uniform(shader, "soot_texture"); - int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); - int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); - int flame_location = GPU_shader_get_uniform(shader, "flame_texture"); - int actcol_location = GPU_shader_get_uniform(shader, "active_color"); - int stepsize_location = GPU_shader_get_uniform(shader, "step_size"); - int densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); - int invsize_location = GPU_shader_get_uniform(shader, "invsize"); - int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); - int min_location = GPU_shader_get_uniform(shader, "min_location"); - - GPU_shader_bind(shader); - - GPU_texture_bind(sds->tex, 0); - GPU_shader_uniform_texture(shader, soot_location, sds->tex); - - GPU_texture_bind(sds->tex_shadow, 1); - GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); - - GPUTexture *tex_spec = NULL; - - if (use_fire) { - GPU_texture_bind(sds->tex_flame, 2); - GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); - - tex_spec = create_flame_spectrum_texture(); - GPU_texture_bind(tex_spec, 3); - GPU_shader_uniform_texture(shader, spec_location, tex_spec); - } - - float active_color[3] = { 0.9, 0.9, 0.9 }; - float density_scale = 10.0f; - if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) - mul_v3_v3(active_color, sds->active_color); - - GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); - GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); - GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); - GPU_shader_uniform_vector(shader, min_location, 3, 1, min); - GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); - GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); - /* setup slicing information */ const int max_slices = 256; @@ -387,43 +454,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - GLuint vertex_buffer; - glGenBuffers(1, &vertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, NULL); - - glDrawArrays(GL_TRIANGLES, 0, num_points); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); - glDisableClientState(GL_VERTEX_ARRAY); + /* Draw fire separately (T47639). */ + if (use_fire) { + glBlendFunc(GL_ONE, GL_ONE); + draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); + } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif - /* cleanup */ - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &vertex_buffer); - - GPU_texture_unbind(sds->tex); - GPU_texture_unbind(sds->tex_shadow); - - if (use_fire) { - GPU_texture_unbind(sds->tex_flame); - GPU_texture_unbind(tex_spec); - GPU_texture_free(tex_spec); - } - MEM_freeN(slicer.verts); - GPU_shader_unbind(); - glDepthMask(gl_depth_write); if (!gl_blend) { -- cgit v1.2.3 From 71eaa28d0e9e774d19a1db6442a93d81b8d3d259 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 01:37:14 +1200 Subject: Code Cleanup: Just some fixes for whitespace/typos that I noticed while working on other stuff --- source/blender/editors/gpencil/gpencil_intern.h | 14 ++++++++++---- source/blender/editors/gpencil/gpencil_utils.c | 6 ++++-- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 5f7cef9a852..e8d007c6c19 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -183,7 +183,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints); /** * Add randomness to stroke * \param gps Stroke data -* \param brsuh Brush data +* \param brush Brush data */ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush); @@ -199,6 +199,7 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED( /* Enums of GP palettes */ EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free); + /* ***************************************************** */ /* Operator Defines */ @@ -303,10 +304,10 @@ void GPENCIL_OT_palette_add(struct wmOperatorType *ot); void GPENCIL_OT_palette_remove(struct wmOperatorType *ot); void GPENCIL_OT_palette_change(struct wmOperatorType *ot); void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot); + void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot); void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot); void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot); - void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot); void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot); void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot); @@ -321,7 +322,7 @@ void gpencil_undo_init(struct bGPdata *gpd); void gpencil_undo_push(struct bGPdata *gpd); void gpencil_undo_finish(void); -/******************************************************* */ +/* ****************************************************** */ /* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */ /* XXX - TODO: replace this with the modern bAnimListElem... */ @@ -343,7 +344,7 @@ typedef struct bActListElem { short ownertype; /* type of owner */ } bActListElem; -/******************************************************* */ +/* ****************************************************** */ /* FILTER ACTION DATA - METHODS/TYPES */ /* filtering flags - under what circumstances should a channel be added */ @@ -366,6 +367,9 @@ typedef enum ACTCONT_TYPES { ACTCONT_GPENCIL } ACTCONT_TYPES; +/* ****************************************************** */ +/* Stroke Iteration Utilities */ + /** * Iterate over all editable strokes in the current context, * stopping on each usable layer + stroke pair (i.e. gpl and gps) @@ -401,4 +405,6 @@ typedef enum ACTCONT_TYPES { CTX_DATA_END; \ } (void)0 +/* ****************************************************** */ + #endif /* __GPENCIL_INTERN_H__ */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index ed9a591dcbe..a61c83be54f 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -883,10 +883,12 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush) float normal[3]; cross_v3_v3v3(normal, v1, v2); normalize_v3(normal); + /* get orthogonal vector to plane to rotate random effect */ float ortho[3]; cross_v3_v3v3(ortho, v1, normal); normalize_v3(ortho); + /* Read all points and apply shift vector (first and last point not modified) */ for (int i = 1; i < gps->totpoints - 1; ++i) { bGPDspoint *pt = &gps->points[i]; @@ -955,8 +957,8 @@ bool ED_gpencil_stroke_minmax( } return changed; } -/* Dynamic Enums of GP Brushes */ +/* Dynamic Enums of GP Brushes */ EnumPropertyItem *ED_gpencil_brushes_enum_itemf( bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) @@ -990,8 +992,8 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf( return item; } -/* Dynamic Enums of GP Palettes */ +/* Dynamic Enums of GP Palettes */ EnumPropertyItem *ED_gpencil_palettes_enum_itemf( bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -- cgit v1.2.3 From 299bb019b5e5bf48098a85f510d3daaaa99f53d5 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 03:03:09 +1200 Subject: GPencil: "Reproject Strokes" operator A common problem encountered by artists was that they would accidentally move the 3D cursor while drawing, causing their strokes to end up in weird places in 3D space when viewing the drawing again from other perspectives. This operator helps fix up this mess by taking the selected strokes, projecting them to screenspace, and then back to 3D space again. As a result, it should be as if you had directly drawn the whole thing again, but from the current viewpoint instead. Unfortunately, if there was originally some depth information present (i.e. you already started reshaping the sketch in 3D), then that will get lost during this process. But so far, my tests indicate that this seems to work well enough. --- source/blender/editors/gpencil/gpencil_edit.c | 80 +++++++++++++++++++++++++ source/blender/editors/gpencil/gpencil_intern.h | 13 ++++ source/blender/editors/gpencil/gpencil_ops.c | 2 + source/blender/editors/gpencil/gpencil_utils.c | 57 ++++++++++++++++++ 4 files changed, 152 insertions(+) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3fe53e3d0ab..d9b6c8046cd 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -72,6 +72,7 @@ #include "ED_gpencil.h" #include "ED_object.h" +#include "ED_screen.h" #include "ED_view3d.h" #include "gpencil_intern.h" @@ -1881,4 +1882,83 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ***************** Reproject Strokes ********************** */ + +static int gp_strokes_reproject_poll(bContext *C) +{ + /* 2 Requirements: + * - 1) Editable GP data + * - 2) 3D View only (2D editors don't have projection issues) + */ + return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); +} + +static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + GP_SpaceConversion gsc = {NULL}; + + /* init space conversion stuff */ + gp_point_conversion_init(C, &gsc); + + /* Go through each editable + selected stroke, adjusting each of its points one by one... */ + GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) + { + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + float xy[2]; + + /* 3D to Screenspace */ + /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace + * coordinates, resulting in lost precision, which in turn causes stairstepping + * artifacts in the final points. + */ + if (gpl->parent == NULL) { + gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]); + } + else { + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); + } + + /* Project screenspace back to 3D space (from current perspective) + * so that all points have been treated the same way + */ + gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); + + /* Unapply parent corrections */ + if (gpl->parent) { + float inverse_diff_mat[4][4]; + invert_m4_m4(inverse_diff_mat, diff_mat); + mul_m4_v3(inverse_diff_mat, &pt->x); + } + } + } + } + GP_EDITABLE_STROKES_END; + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_reproject(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Reproject Strokes"; + ot->idname = "GPENCIL_OT_reproject"; + ot->description = "Reproject the selected strokes from the current viewpoint to get all points on the same plane again " + "(e.g. to fix problems from accidental 3D cursor movement, or viewport changes)"; + + /* callbacks */ + ot->exec = gp_strokes_reproject_exec; + ot->poll = gp_strokes_reproject_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ************************************************ */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index e8d007c6c19..4178d49d652 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -100,6 +100,18 @@ void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc); void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt, int *r_x, int *r_y); +/** + * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D) + * + * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints. + * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations. + * + * \param[out] r_x The screen-space x-coordinate of the point + * \param[out] r_y The screen-space y-coordinate of the point + */ +void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, + float *r_x, float *r_y); + /** * Convert point to parent space * @@ -250,6 +262,7 @@ void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot); void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot); void GPENCIL_OT_snap_cursor_to_center(struct wmOperatorType *ot); +void GPENCIL_OT_reproject(struct wmOperatorType *ot); /* stroke sculpting -- */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 50f4e795d70..ae1c5554521 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -375,6 +375,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_snap_to_cursor); WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected); + WM_operatortype_append(GPENCIL_OT_reproject); + WM_operatortype_append(GPENCIL_OT_brush_paint); /* Editing (Buttons) ------------ */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index a61c83be54f..564ba639983 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -628,6 +628,63 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, } } +/* Convert Grease Pencil points to screen-space values (as floats) + * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn + */ +void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, + float *r_x, float *r_y) +{ + ARegion *ar = gsc->ar; + View2D *v2d = gsc->v2d; + rctf *subrect = gsc->subrect; + float xyval[2]; + + /* sanity checks */ + BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D)); + BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D)); + + + if (gps->flag & GP_STROKE_3DSPACE) { + if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + *r_x = xyval[0]; + *r_y = xyval[1]; + } + else { + *r_x = 0.0f; + *r_y = 0.0f; + } + } + else if (gps->flag & GP_STROKE_2DSPACE) { + float vec[3] = {pt->x, pt->y, 0.0f}; + int t_x, t_y; + + mul_m4_v3(gsc->mat, vec); + UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y); + + if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) { + /* XXX: Or should we just always use the values as-is? */ + *r_x = 0.0f; + *r_y = 0.0f; + } + else { + *r_x = (float)t_x; + *r_y = (float)t_y; + } + } + else { + if (subrect == NULL) { + /* normal 3D view (or view space) */ + *r_x = (pt->x / 100.0f * ar->winx); + *r_y = (pt->y / 100.0f * ar->winy); + } + else { + /* camera view, use subrect */ + *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin; + *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin; + } + } +} + /** * Project screenspace coordinates to 3D-space * -- cgit v1.2.3 From 44524f751954598038f957403d4fdc9d814ff31c Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 13:50:53 +1200 Subject: Small optimisation: Only calculate the inverse_diff_mat once per stroke instead of for every point (Later this calculation should be moved into the iteration macro instead, since it only needs to be applied once per layer along with the diff_mat calculation) --- source/blender/editors/gpencil/gpencil_edit.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index d9b6c8046cd..d308d3ae5f1 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1907,7 +1907,15 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; + float inverse_diff_mat[4][4] = {0.0f}; + /* Compute inverse matrix for unapplying parenting once instead of doing per-point */ + /* TODO: add this bit to the iteration macro? */ + if (gpl->parent) { + invert_m4_m4(inverse_diff_mat, diff_mat); + } + + /* Adjust each point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { float xy[2]; @@ -1932,8 +1940,6 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) /* Unapply parent corrections */ if (gpl->parent) { - float inverse_diff_mat[4][4]; - invert_m4_m4(inverse_diff_mat, diff_mat); mul_m4_v3(inverse_diff_mat, &pt->x); } } -- cgit v1.2.3 From cea8f024eccae3860086aa2b1f65df28dbdf69db Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 16:27:23 +1200 Subject: Fix: GPencil Paste couldn't be used to paste strokes from one datablock to another This was because the poll callback was checking for the presence of an active layer. If you just create an empty datablock and try to paste, nothing would happen. However, this check was kindof redundant anyway, as the operator would add a layer for you if it didn't find one. --- source/blender/editors/gpencil/gpencil_edit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index d308d3ae5f1..a80600fb60c 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -432,10 +432,12 @@ void GPENCIL_OT_copy(wmOperatorType *ot) static int gp_strokes_paste_poll(bContext *C) { - /* 1) Must have GP layer to paste to... + /* 1) Must have GP datablock to paste to + * - We don't need to have an active layer though, as that can easily get added + * - If the active layer is locked, we can't paste there, but that should prompt a warning instead * 2) Copy buffer must at least have something (though it may be the wrong sort...) */ - return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf)); + return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf)); } enum { -- cgit v1.2.3 From f5ddcd4ce99b91e794b69bd1aad51055f4fdce2d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 29 Aug 2016 16:39:27 +1200 Subject: Code Cleanup: Fixes for some issues noticed during previous fix --- source/blender/editors/gpencil/gpencil_edit.c | 73 +++++++++++++-------------- 1 file changed, 36 insertions(+), 37 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index a80600fb60c..99f4ca221c3 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -440,10 +440,10 @@ static int gp_strokes_paste_poll(bContext *C) return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf)); } -enum { +typedef enum eGP_PasteMode { GP_COPY_ONLY = -1, GP_COPY_MERGE = 1 -}; +} eGP_PasteMode; static int gp_strokes_paste_exec(bContext *C, wmOperator *op) { @@ -451,9 +451,9 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */ bGPDframe *gpf; - - int type = RNA_enum_get(op->ptr, "type"); - + + eGP_PasteMode type = RNA_enum_get(op->ptr, "type"); + /* check for various error conditions */ if (gpd == NULL) { BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); @@ -510,39 +510,37 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - /* Ensure we have a frame to draw into - * NOTE: Since this is an op which creates strokes, - * we are obliged to add a new frame if one - * doesn't exist already - */ - - bGPDstroke *gps; - /* Copy each stroke into the layer */ - for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { - if (ED_gpencil_stroke_can_use(C, gps)) { - /* need to verify if layer exist nad frame */ - if (type != GP_COPY_MERGE) { - gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info)); - if (gpl == NULL) { - /* no layer - use active (only if layer deleted before paste) */ - gpl = CTX_data_active_gpencil_layer(C); - } - } - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); - if (gpf) { - bGPDstroke *new_stroke = MEM_dupallocN(gps); - new_stroke->tmp_layerinfo[0] = '\0'; - - new_stroke->points = MEM_dupallocN(gps->points); - - new_stroke->flag |= GP_STROKE_RECALC_CACHES; - new_stroke->triangles = NULL; - - new_stroke->next = new_stroke->prev = NULL; - BLI_addtail(&gpf->strokes, new_stroke); + for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { + if (ED_gpencil_stroke_can_use(C, gps)) { + /* Need to verify if layer exists */ + if (type != GP_COPY_MERGE) { + gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info)); + if (gpl == NULL) { + /* no layer - use active (only if layer deleted before paste) */ + gpl = CTX_data_active_gpencil_layer(C); } } + + /* Ensure we have a frame to draw into + * NOTE: Since this is an op which creates strokes, + * we are obliged to add a new frame if one + * doesn't exist already + */ + gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); + if (gpf) { + bGPDstroke *new_stroke = MEM_dupallocN(gps); + new_stroke->tmp_layerinfo[0] = '\0'; + + new_stroke->points = MEM_dupallocN(gps->points); + + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + new_stroke->triangles = NULL; + + new_stroke->next = new_stroke->prev = NULL; + BLI_addtail(&gpf->strokes, new_stroke); + } } + } /* updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); @@ -557,7 +555,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot) {GP_COPY_MERGE, "MERGE", 0, "Merge", ""}, {0, NULL, 0, NULL, NULL} }; - + /* identifiers */ ot->name = "Paste Strokes"; ot->idname = "GPENCIL_OT_paste"; @@ -569,7 +567,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", ""); } -- cgit v1.2.3 From 5af58faf799e3fd19ca9319f7ebef0654967bdc0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 29 Aug 2016 09:40:15 +0200 Subject: Fix compilation error caused by wrong array initialization We usually don't silence migh-be-uninitialized warning (which is the only thing which could explain setting matrix to all zeroes) so we can catch such errors when using tools like Valgrind. I don't get warning here and the initializer was wrong, so removing it. If it-s _REALLY_ needed please do a proper initialization. --- source/blender/editors/gpencil/gpencil_edit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 99f4ca221c3..9f700e8716c 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1894,7 +1894,7 @@ static int gp_strokes_reproject_poll(bContext *C) return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); } -static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) +static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); GP_SpaceConversion gsc = {NULL}; @@ -1908,7 +1908,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; - float inverse_diff_mat[4][4] = {0.0f}; + float inverse_diff_mat[4][4]; /* Compute inverse matrix for unapplying parenting once instead of doing per-point */ /* TODO: add this bit to the iteration macro? */ -- cgit v1.2.3 From cc2faa409fc8508fb0131bdc344651f2863957f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Mon, 29 Aug 2016 10:54:32 +0200 Subject: Fix T49172: mixdown sound op not exporting full length Thanks Flavio Perez for the fix. --- source/blender/editors/sound/sound_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 03f2e146b7d..ac3fc769ea1 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -348,10 +348,10 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) BLI_path_abs(filename, bmain->name); if (split) - result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS, + result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS, accuracy, filename, specs, container, codec, bitrate); else - result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS, + result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS, accuracy, filename, specs, container, codec, bitrate); if (result) { -- cgit v1.2.3 From 8f215d9b527681773bb1f02b57d00afc860d8122 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Mon, 29 Aug 2016 08:51:04 -0400 Subject: Fix for Bevel segments bug T49183; but doesn't fix whole report yet. --- source/blender/editors/mesh/editmesh_bevel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender/editors') diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 302ca407add..a81add7a86e 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -145,6 +145,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) opdata->em = em; opdata->is_modal = is_modal; opdata->value_mode = OFFSET_VALUE; + opdata->segments = (float) RNA_int_get(op->ptr, "segments"); pixels_per_inch = U.dpi * U.pixelsize; for (i = 0; i < NUM_VALUE_KINDS; i++) { -- cgit v1.2.3 From 2090ed164f674f9b3e29975e7d902eeacae3e55f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 29 Aug 2016 16:42:49 +0200 Subject: Cleanup/refactor spacefile's 'check dir' code. Was kinda split in two different places (one allowed to modify given path to always get a valid one, the other only checking for validity of given path), not nice - and broken in asset branch case. So rather extended a bit FileList->checkdirf to handle both cases (modifying and non-modifying path). --- source/blender/editors/space_file/file_intern.h | 1 - source/blender/editors/space_file/file_ops.c | 6 ++-- source/blender/editors/space_file/file_utils.c | 14 --------- source/blender/editors/space_file/filelist.c | 39 ++++++++++++++++++------- source/blender/editors/space_file/filelist.h | 1 + source/blender/editors/space_file/filesel.c | 2 +- 6 files changed, 34 insertions(+), 29 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index a55b18a2212..71e38f72a7a 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -128,7 +128,6 @@ void file_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); -bool file_is_dir(struct SpaceFile *sfile, const char *path); #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index c42ff120102..9f5e98d2431 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1894,7 +1894,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (!file_is_dir(sfile, sfile->params->dir)) { + if (!filelist_is_dir(sfile->files, sfile->params->dir)) { char tdir[FILE_MAX_LIBEXTRA]; char *group, *name; @@ -1920,7 +1920,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN BLI_cleanup_dir(G.main->name, sfile->params->dir); - if (file_is_dir(sfile, sfile->params->dir)) { + if (filelist_is_dir(sfile->files, sfile->params->dir)) { /* if directory exists, enter it immediately */ ED_file_change_dir(C); @@ -1993,7 +1993,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); /* if directory, open it and empty filename field */ - if (file_is_dir(sfile, filepath)) { + if (filelist_is_dir(sfile->files, filepath)) { BLI_cleanup_dir(G.main->name, filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index f19e301064d..c1caf5ae8ac 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -48,17 +48,3 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, ymax - layout->tile_h - layout->tile_border_y, ymax); } - -/* Cannot directly use BLI_is_dir in libloading context... */ -bool file_is_dir(struct SpaceFile *sfile, const char *path) -{ - if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX_LIBEXTRA]; - char *name; - if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) { - /* .blend file itself and group are considered as directories, not final datablock names. */ - return name ? false : true; - } - } - return BLI_is_dir(path); -} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index b6e4991bf52..14719322bf7 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -309,8 +309,9 @@ typedef struct FileList { struct BlendHandle *libfiledata; - /* Set given path as root directory, may change given string in place to a valid value. */ - void (*checkdirf)(struct FileList *, char *); + /* Set given path as root directory, if last bool is true may change given string in place to a valid value. + * Returns True if valid dir. */ + bool (*checkdirf)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); @@ -942,24 +943,37 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m /* ********** Main ********** */ -static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir) +static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) { - BLI_make_exist(r_dir); + if (do_change) { + BLI_make_exist(r_dir); + return true; + } + else { + return BLI_is_dir(r_dir); + } } -static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir) +static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change) { - char dir[FILE_MAX_LIBEXTRA]; - if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *name; + + const bool is_valid = (BLI_is_dir(r_dir) || + (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name)); + + if (do_change && !is_valid) { /* if not a valid library, we need it to be a valid directory! */ BLI_make_exist(r_dir); + return true; } + return is_valid; } -static void filelist_checkdir_main(struct FileList *filelist, char *r_dir) +static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change) { /* TODO */ - filelist_checkdir_lib(filelist, r_dir); + return filelist_checkdir_lib(filelist, r_dir, do_change); } static void filelist_entry_clear(FileDirEntry *entry) @@ -1378,6 +1392,11 @@ const char *filelist_dir(struct FileList *filelist) return filelist->filelist.root; } +bool filelist_is_dir(struct FileList *filelist, const char *path) +{ + return filelist->checkdirf(filelist, (char *)path, false); +} + /** * May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length. */ @@ -1386,7 +1405,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_cleanup_dir(G.main->name, r_dir); - filelist->checkdirf(filelist, r_dir); + BLI_assert(filelist->checkdirf(filelist, r_dir, true)); if (!STREQ(filelist->filelist.root, r_dir)) { BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root)); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index d70faab1d6a..f4304681780 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -86,6 +86,7 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_c void filelist_free(struct FileList *filelist); const char * filelist_dir(struct FileList *filelist); +bool filelist_is_dir(struct FileList *filelist, const char *path); void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 1a558d40560..7abe5ff5070 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -592,7 +592,7 @@ void ED_file_change_dir(bContext *C) sfile->params->filter_search[0] = '\0'; sfile->params->active_file = -1; - if (!file_is_dir(sfile, sfile->params->dir)) { + if (!filelist_is_dir(sfile->files, sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } -- cgit v1.2.3 From fa092da37700b15374db50803bd7afe2a407bb55 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Mon, 29 Aug 2016 21:55:02 +0200 Subject: GPencil: Replace strcpy by BLI_strncpy --- source/blender/editors/space_view3d/view3d_ruler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 67a40ae4180..3c13ab9d595 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -357,7 +357,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) gps->flag = GP_STROKE_3DSPACE; gps->thickness = 3; /* assign color to stroke */ - strcpy(gps->colorname, palcolor->info); + BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); gps->palcolor = palcolor; BLI_addtail(&gpf->strokes, gps); changed = true; -- cgit v1.2.3 From 5f14bc1b47f3949cb5929153fcbb1916dc6cc0a8 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Mon, 29 Aug 2016 22:17:57 +0200 Subject: GPencil: Fix segment fault when undo When undo in UV/Image editor and press ESC key, there was segment fault in Toolsettings because the reference was missing. Now the toolsetting is loaded from context and not from local operator data. --- source/blender/editors/gpencil/gpencil_paint.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 70a4b2904ed..cc45cbd82af 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2310,6 +2310,7 @@ static void gpencil_move_last_stroke_to_back(bContext *C) static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p = op->customdata; + ToolSettings *ts = CTX_data_tool_settings(C); int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */ /* if (event->type == NDOF_MOTION) @@ -2363,9 +2364,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* exit() ends the current stroke before cleaning up */ /* printf("\t\tGP - end of paint op + end of stroke\n"); */ /* if drawing polygon and enable on back, must move stroke */ - if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { - if (p->flags & GP_PAINTFLAG_STROKEADDED) { - gpencil_move_last_stroke_to_back(C); + if (ts) { + if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { + if (p->flags & GP_PAINTFLAG_STROKEADDED) { + gpencil_move_last_stroke_to_back(C); + } } } p->status = GP_STATUS_DONE; @@ -2425,9 +2428,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) else { /* printf("\t\tGP - end of stroke + op\n"); */ /* if drawing polygon and enable on back, must move stroke */ - if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { - if (p->flags & GP_PAINTFLAG_STROKEADDED) { - gpencil_move_last_stroke_to_back(C); + if (ts) { + if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { + if (p->flags & GP_PAINTFLAG_STROKEADDED) { + gpencil_move_last_stroke_to_back(C); + } } } p->status = GP_STATUS_DONE; @@ -2511,9 +2516,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * region (as above) */ /* if drawing polygon and enable on back, must move stroke */ - if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { - if (p->flags & GP_PAINTFLAG_STROKEADDED) { - gpencil_move_last_stroke_to_back(C); + if (ts) { + if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) { + if (p->flags & GP_PAINTFLAG_STROKEADDED) { + gpencil_move_last_stroke_to_back(C); + } } } p->status = GP_STATUS_DONE; -- cgit v1.2.3 From 3a0c0c1b5425cd5b050cb742357da57266c70463 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 30 Aug 2016 12:32:31 +0300 Subject: Fix node editor to display node group names in the bottom left corner. Currently it pointlessly repeats the material name there, separated by slashes. That obviously should display the nested group path instead. --- source/blender/editors/space_node/node_draw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index d9c51e427c8..ab40c55b59d 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1327,8 +1327,10 @@ void drawnodespace(const bContext *C, ARegion *ar) path = snode->treepath.last; /* update tree path name (drawn in the bottom left) */ - if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) { - BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name)); + ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id : snode->id; + + if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) { + BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name)); } /* current View2D center, will be set temporarily for parent node trees */ -- cgit v1.2.3 From bfd8da753d34881c6f1205938ce9e6e25e3bf4e8 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 31 Aug 2016 16:42:14 +0200 Subject: Fix T49210: Issue with User Count on Images in some shader nodetrees when rendering previews Our usercount handling was really... infuriating :| Here, localization (i.e. 'shalow' copy that should not touch to usercounts) was incrementing usercounts of the sole Textures IDs of lamps and worlds (on the weak and fallacious pretext that related BKE_free... functions would decrement those counts)... Seriously... So now, localize funcs do not increment any usercount anymore (since matching BKE_free... ones do not decrement any either), and we do not call anymore that stupid unlink when freeing temp localized copies of lamps/materials at end of preview generation. Note that we probably still have a lot to do to cleanup that copy/localize code, pretty sure we can dedpulicate a lot more. --- source/blender/editors/render/render_preview.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index b4f3426677a..ddbf59b2cf7 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -526,7 +526,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true); } } - + return sce; } @@ -863,8 +863,6 @@ static void shader_preview_free(void *customdata) /* get rid of copied world */ BLI_remlink(&pr_main->world, sp->worldcopy); - /* T32865 - we need to unlink the texture copies, unlike for materials */ - BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL, true); BKE_world_free(sp->worldcopy); properties = IDP_GetProperties((ID *)sp->worldcopy, false); @@ -881,7 +879,6 @@ static void shader_preview_free(void *customdata) /* get rid of copied lamp */ BLI_remlink(&pr_main->lamp, sp->lampcopy); - BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL, true); BKE_lamp_free(sp->lampcopy); properties = IDP_GetProperties((ID *)sp->lampcopy, false); -- cgit v1.2.3 From e240025276648218c19d3fb7dbd5af92253b7718 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 1 Sep 2016 16:25:42 +0200 Subject: Fix T49199: Combination of dialog + wm.open_mainfile causes crash Issue was that the wm.open_mainfile OP caused all handlers to be removed and since rB45592291 cancelled (which is correct in general), the menu that triggered the OP should not be cancelled though. Not sure if this is a nice fix or not, it's however the safest fix I found. A different fix would be to call UI_popup_block_close before WM_operator_call_ex (in dialog_exec_cb), but not sure how safe this is and want to further investigate if it makes other hacks/fixes redundant. There's still a crash with --debug-memory that confused the heck out of me (since I always have --debug-memory enabled), but I'll commit fix for that separately. --- source/blender/editors/include/UI_interface.h | 2 ++ source/blender/editors/interface/interface_handlers.c | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 1f053c806b0..49e5845e3ca 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -393,6 +393,8 @@ struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head); void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL(); int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2); +void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable); + /* Pie menus */ typedef struct uiPieMenu uiPieMenu; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index d05a80bed62..4972e16bf2e 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -9921,6 +9921,17 @@ static int ui_handle_menus_recursive( return retval; } +/** + * Allow setting menu return value from externals. E.g. WM might need to do this for exiting files correctly. + */ +void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable) +{ + uiPopupBlockHandle *menu = block->handle; + if (menu) { + menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval); + } +} + /* *************** UI event handlers **************** */ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata)) @@ -10163,7 +10174,11 @@ static void ui_popup_handler_remove(bContext *C, void *userdata) { uiPopupBlockHandle *menu = userdata; - if (menu->cancel_func) { + /* More correct would be to expect UI_RETURN_CANCEL here, but not wanting to + * cancel when removing handlers because of file exit is a rare exception. + * So instead of setting cancel flag for all menus before removing handlers, + * just explicitly flag menu with UI_RETURN_OK to avoid cancelling it. */ + if ((menu->menuretval & UI_RETURN_OK) == 0 && menu->cancel_func) { menu->cancel_func(C, menu->popup_arg); } -- cgit v1.2.3 From 8b2a4505209343cebb7012af7dc29aa03da18536 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 2 Sep 2016 08:37:57 +0200 Subject: Fix T49222: Image Save settings are overridden by the File Save Screen ones. There were two inconsistencies in how 'save image' op initiated its settings: * It would always use ImBuf->planes value. * It would always use Image views settings. Both of those settings should come from scene->r.im_format (as everything else) when saving render/compo result... --- source/blender/editors/space_image/image_ops.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index f9d76da9f87..1f591b5fb35 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1613,13 +1613,16 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, if (ima->source == IMA_SRC_GENERATED) { simopts->im_format.imtype = R_IMF_IMTYPE_PNG; simopts->im_format.compress = ibuf->foptions.quality; + simopts->im_format.planes = ibuf->planes; } else { BKE_imbuf_to_image_format(&simopts->im_format, ibuf); } - } - simopts->im_format.planes = ibuf->planes; + /* use the multiview image settings as the default */ + simopts->im_format.stereo3d_format = *ima->stereo3d_format; + simopts->im_format.views_format = ima->views_format; + } //simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */ @@ -1660,10 +1663,6 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, } } - /* use the multiview image settings as the default */ - simopts->im_format.stereo3d_format = *ima->stereo3d_format; - simopts->im_format.views_format = ima->views_format; - /* color management */ BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings); BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings); -- cgit v1.2.3 From 27c64e3f46395b1807ab211888b321de7e773918 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 3 Sep 2016 11:47:17 +0200 Subject: Fix T49229: ID user decrement error when deleting group instance twice. Another great example of inconsistency in usercount handling - dupli_group was considered as refcounted by readfile.c code (and hence by library_query.c one, which is based on it), but not by editor/BKE_object code, which never increased group's usercount when creating an instance of it etc. To be backported to 2.78. --- source/blender/editors/object/object_add.c | 2 +- source/blender/editors/object/object_edit.c | 2 +- source/blender/editors/object/object_relations.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index a8b0c28599d..9f91feee4c6 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -998,7 +998,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer); ob->dup_group = group; ob->transflag |= OB_DUPLIGROUP; - id_lib_extern(&group->id); + id_us_plus(&group->id); /* works without this except if you try render right after, see: 22027 */ DAG_relations_tag_update(bmain); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 3dc7d8ebd4b..111afcdc7a7 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -910,7 +910,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) base->object->dup_group = ob->dup_group; if (ob->dup_group) - id_lib_extern(&ob->dup_group->id); + id_us_plus(&ob->dup_group->id); } else if (event == 7) { /* mass */ base->object->mass = ob->mass; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 067a5ad2b49..82c6a14eb7f 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1609,7 +1609,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) case MAKE_LINKS_DUPLIGROUP: ob_dst->dup_group = ob_src->dup_group; if (ob_dst->dup_group) { - id_lib_extern(&ob_dst->dup_group->id); + id_us_plus(&ob_dst->dup_group->id); ob_dst->transflag |= OB_DUPLIGROUP; } break; -- cgit v1.2.3 From 6c0307f88854aada929359ff1eaad133e950188d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 3 Sep 2016 12:51:50 +0200 Subject: Fix T49228: Separate by material, materials dissappear after reload. Yet another mismatch where code would decrease usercount (of Material here) but never increase it again when re-assigning the datablock... --- source/blender/editors/mesh/editmesh_tools.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender/editors') diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 999d5b278ee..7e31deba2c7 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3121,8 +3121,10 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const BKE_material_resize_id(bmain, obdata, 1, true); ob->mat[0] = ma_ob; + id_us_plus((ID *)ma_ob); ob->matbits[0] = matbit; (*matarar)[0] = ma_obdata; + id_us_plus((ID *)ma_obdata); } else { BKE_material_clear_id(bmain, obdata, true); -- cgit v1.2.3